summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAndres Noetzli <andres.noetzli@gmail.com>2020-11-29 15:44:51 -0800
committerAndres Noetzli <andres.noetzli@gmail.com>2020-11-29 15:44:51 -0800
commit8f0b61ca58b4402f00d056ee50338808fdcf8385 (patch)
tree6f0ba5c55609fdd2c8895d22b99d4009ac8f339e /src
parent8a279c8f16170d22e8e64e9eadbec184a1ce2f11 (diff)
parent36af095242f2445fa5d3c2c1f3882159119d152a (diff)
Merge branch 'master' into fixClangWarnings
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt321
-rw-r--r--src/api/cvc4cpp.cpp2035
-rw-r--r--src/api/cvc4cpp.h506
-rw-r--r--src/api/cvc4cppkind.h205
-rw-r--r--src/api/python/CMakeLists.txt10
-rw-r--r--src/api/python/cvc4.pxd46
-rw-r--r--src/api/python/cvc4.pxi554
-rw-r--r--[-rwxr-xr-x]src/api/python/genkinds.py10
-rw-r--r--src/api/python/setup.py.in26
-rw-r--r--src/base/CMakeLists.txt10
-rw-r--r--src/base/GitInfo.cmake.in10
-rw-r--r--src/base/check.cpp2
-rw-r--r--src/base/check.h2
-rw-r--r--src/base/configuration.cpp52
-rw-r--r--src/base/configuration.h8
-rw-r--r--src/base/configuration_private.h18
-rw-r--r--src/base/exception.cpp2
-rw-r--r--src/base/exception.h2
-rw-r--r--src/base/git_versioninfo.cpp.in2
-rw-r--r--src/base/listener.cpp72
-rw-r--r--src/base/listener.h127
-rw-r--r--src/base/map_util.h2
-rw-r--r--src/base/modal_exception.h2
-rw-r--r--src/base/output.cpp2
-rw-r--r--src/base/output.h2
-rw-r--r--src/context/backtrackable.h2
-rw-r--r--src/context/cddense_set.h2
-rw-r--r--src/context/cdhashmap.h4
-rw-r--r--src/context/cdhashmap_forward.h2
-rw-r--r--src/context/cdhashset.h3
-rw-r--r--src/context/cdhashset_forward.h2
-rw-r--r--src/context/cdinsert_hashmap.h2
-rw-r--r--src/context/cdinsert_hashmap_forward.h2
-rw-r--r--src/context/cdlist.h4
-rw-r--r--src/context/cdlist_forward.h2
-rw-r--r--src/context/cdmaybe.h2
-rw-r--r--src/context/cdo.h2
-rw-r--r--src/context/cdqueue.h2
-rw-r--r--src/context/cdtrail_queue.h2
-rw-r--r--src/context/context.cpp2
-rw-r--r--src/context/context.h2
-rw-r--r--src/context/context_mm.cpp2
-rw-r--r--src/context/context_mm.h2
-rw-r--r--src/decision/decision_attributes.h2
-rw-r--r--src/decision/decision_engine.cpp2
-rw-r--r--src/decision/decision_engine.h2
-rw-r--r--src/decision/decision_strategy.h2
-rw-r--r--src/decision/justification_heuristic.cpp2
-rw-r--r--src/decision/justification_heuristic.h2
-rw-r--r--src/expr/CMakeLists.txt34
-rw-r--r--src/expr/array.h2
-rw-r--r--src/expr/array_store_all.cpp7
-rw-r--r--src/expr/array_store_all.h4
-rw-r--r--src/expr/ascription_type.cpp58
-rw-r--r--src/expr/ascription_type.h39
-rw-r--r--src/expr/attribute.cpp2
-rw-r--r--src/expr/attribute.h41
-rw-r--r--src/expr/attribute_internals.h3
-rw-r--r--src/expr/attribute_unique_id.h4
-rw-r--r--src/expr/buffered_proof_generator.cpp82
-rw-r--r--src/expr/buffered_proof_generator.h65
-rw-r--r--src/expr/datatype.cpp974
-rw-r--r--src/expr/datatype.h977
-rw-r--r--src/expr/datatype_index.cpp36
-rw-r--r--src/expr/datatype_index.h71
-rw-r--r--src/expr/dtype.cpp73
-rw-r--r--src/expr/dtype.h38
-rw-r--r--src/expr/dtype_cons.cpp131
-rw-r--r--src/expr/dtype_cons.h54
-rw-r--r--src/expr/dtype_selector.cpp12
-rw-r--r--src/expr/dtype_selector.h4
-rw-r--r--src/expr/emptybag.cpp65
-rw-r--r--src/expr/emptybag.h63
-rw-r--r--src/expr/emptyset.cpp4
-rw-r--r--src/expr/emptyset.h4
-rw-r--r--src/expr/expr_iomanip.cpp35
-rw-r--r--src/expr/expr_iomanip.h64
-rw-r--r--src/expr/expr_manager_scope.h2
-rw-r--r--src/expr/expr_manager_template.cpp223
-rw-r--r--src/expr/expr_manager_template.h105
-rw-r--r--src/expr/expr_template.cpp17
-rw-r--r--src/expr/expr_template.h18
-rw-r--r--src/expr/kind_map.h3
-rw-r--r--src/expr/kind_template.cpp5
-rw-r--r--src/expr/kind_template.h5
-rw-r--r--src/expr/lazy_proof.cpp98
-rw-r--r--src/expr/lazy_proof.h17
-rw-r--r--src/expr/lazy_proof_chain.cpp317
-rw-r--r--src/expr/lazy_proof_chain.h153
-rw-r--r--src/expr/match_trie.cpp2
-rw-r--r--src/expr/match_trie.h2
-rw-r--r--src/expr/metakind_template.cpp2
-rw-r--r--src/expr/metakind_template.h4
-rwxr-xr-xsrc/expr/mkexpr15
-rwxr-xr-xsrc/expr/mkkind26
-rwxr-xr-xsrc/expr/mkmetakind8
-rw-r--r--src/expr/node.cpp2
-rw-r--r--src/expr/node.h27
-rw-r--r--src/expr/node_algorithm.cpp52
-rw-r--r--src/expr/node_algorithm.h14
-rw-r--r--src/expr/node_builder.h3
-rw-r--r--src/expr/node_manager.cpp306
-rw-r--r--src/expr/node_manager.h254
-rw-r--r--src/expr/node_manager_attributes.h2
-rw-r--r--src/expr/node_self_iterator.h2
-rw-r--r--src/expr/node_traversal.cpp2
-rw-r--r--src/expr/node_traversal.h3
-rw-r--r--src/expr/node_trie.cpp2
-rw-r--r--src/expr/node_trie.h2
-rw-r--r--src/expr/node_value.cpp14
-rw-r--r--src/expr/node_value.h8
-rw-r--r--src/expr/node_visitor.h2
-rw-r--r--src/expr/proof.cpp19
-rw-r--r--src/expr/proof.h12
-rw-r--r--src/expr/proof_checker.cpp203
-rw-r--r--src/expr/proof_checker.h57
-rw-r--r--src/expr/proof_generator.cpp174
-rw-r--r--src/expr/proof_generator.h49
-rw-r--r--src/expr/proof_node.cpp8
-rw-r--r--src/expr/proof_node.h23
-rw-r--r--src/expr/proof_node_algorithm.cpp95
-rw-r--r--src/expr/proof_node_algorithm.h21
-rw-r--r--src/expr/proof_node_manager.cpp182
-rw-r--r--src/expr/proof_node_manager.h17
-rw-r--r--src/expr/proof_node_to_sexpr.cpp19
-rw-r--r--src/expr/proof_node_to_sexpr.h2
-rw-r--r--src/expr/proof_node_updater.cpp238
-rw-r--r--src/expr/proof_node_updater.h82
-rw-r--r--src/expr/proof_rule.cpp66
-rw-r--r--src/expr/proof_rule.h540
-rw-r--r--src/expr/proof_set.h75
-rw-r--r--src/expr/proof_step_buffer.cpp2
-rw-r--r--src/expr/proof_step_buffer.h2
-rw-r--r--src/expr/record.cpp2
-rw-r--r--src/expr/record.h2
-rw-r--r--src/expr/sequence.cpp4
-rw-r--r--src/expr/sequence.h4
-rw-r--r--src/expr/skolem_manager.cpp27
-rw-r--r--src/expr/skolem_manager.h19
-rw-r--r--src/expr/subs.cpp177
-rw-r--r--src/expr/subs.h85
-rw-r--r--src/expr/sygus_datatype.cpp21
-rw-r--r--src/expr/sygus_datatype.h8
-rw-r--r--src/expr/symbol_manager.cpp256
-rw-r--r--src/expr/symbol_manager.h140
-rw-r--r--src/expr/symbol_table.cpp366
-rw-r--r--src/expr/symbol_table.h38
-rw-r--r--src/expr/tconv_seq_proof_generator.cpp167
-rw-r--r--src/expr/tconv_seq_proof_generator.h119
-rw-r--r--src/expr/term_canonize.cpp2
-rw-r--r--src/expr/term_canonize.h2
-rw-r--r--src/expr/term_context.cpp135
-rw-r--r--src/expr/term_context.h168
-rw-r--r--src/expr/term_context_node.cpp76
-rw-r--r--src/expr/term_context_node.h79
-rw-r--r--src/expr/term_context_stack.cpp76
-rw-r--r--src/expr/term_context_stack.h73
-rw-r--r--src/expr/term_conversion_proof_generator.cpp454
-rw-r--r--src/expr/term_conversion_proof_generator.h109
-rw-r--r--src/expr/type.cpp29
-rw-r--r--src/expr/type.h18
-rw-r--r--src/expr/type_checker.h2
-rw-r--r--src/expr/type_checker_template.cpp10
-rw-r--r--src/expr/type_checker_util.h2
-rw-r--r--src/expr/type_matcher.cpp2
-rw-r--r--src/expr/type_matcher.h2
-rw-r--r--src/expr/type_node.cpp71
-rw-r--r--src/expr/type_node.h44
-rw-r--r--src/expr/type_properties_template.h12
-rw-r--r--src/expr/uninterpreted_constant.cpp4
-rw-r--r--src/expr/uninterpreted_constant.h4
-rw-r--r--src/expr/variable_type_map.h2
-rwxr-xr-xsrc/fix-install-headers.sh3
-rw-r--r--src/include/cvc4.h4
-rw-r--r--src/include/cvc4_private.h2
-rw-r--r--src/include/cvc4_private_library.h2
-rw-r--r--src/include/cvc4_public.h3
-rw-r--r--src/include/cvc4parser_private.h2
-rw-r--r--src/include/cvc4parser_public.h2
-rw-r--r--src/lib/clock_gettime.c2
-rw-r--r--src/lib/clock_gettime.h2
-rw-r--r--src/lib/ffs.c2
-rw-r--r--src/lib/ffs.h2
-rw-r--r--src/lib/replacements.h2
-rw-r--r--src/lib/strtok_r.c2
-rw-r--r--src/lib/strtok_r.h2
-rw-r--r--src/main/CMakeLists.txt26
-rw-r--r--src/main/command_executor.cpp59
-rw-r--r--src/main/command_executor.h39
-rw-r--r--src/main/driver_unified.cpp19
-rw-r--r--src/main/interactive_shell.cpp140
-rw-r--r--src/main/interactive_shell.h8
-rw-r--r--src/main/main.cpp3
-rw-r--r--src/main/main.h2
-rw-r--r--src/main/signal_handlers.cpp4
-rw-r--r--src/main/signal_handlers.h2
-rw-r--r--src/main/time_limit.cpp2
-rw-r--r--src/main/time_limit.h2
-rw-r--r--src/options/CMakeLists.txt11
-rw-r--r--src/options/arith_options.toml45
-rw-r--r--src/options/arrays_options.toml8
-rw-r--r--src/options/base_handlers.h2
-rw-r--r--src/options/base_options.toml1
-rw-r--r--src/options/bv_options.toml74
-rw-r--r--src/options/decision_weight.h2
-rw-r--r--src/options/didyoumean.cpp2
-rw-r--r--src/options/didyoumean.h2
-rw-r--r--src/options/didyoumean_test.cpp2
-rw-r--r--src/options/expr_options.toml12
-rw-r--r--src/options/language.cpp9
-rw-r--r--src/options/language.h2
-rw-r--r--[-rwxr-xr-x]src/options/mkoptions.py10
-rw-r--r--src/options/module_template.cpp2
-rw-r--r--src/options/module_template.h2
-rw-r--r--src/options/open_ostream.cpp2
-rw-r--r--src/options/open_ostream.h2
-rw-r--r--src/options/option_exception.cpp2
-rw-r--r--src/options/option_exception.h2
-rw-r--r--src/options/options.h154
-rw-r--r--src/options/options_handler.cpp69
-rw-r--r--src/options/options_handler.h11
-rw-r--r--src/options/options_holder_template.h2
-rw-r--r--src/options/options_listener.h37
-rw-r--r--src/options/options_public_functions.cpp12
-rw-r--r--src/options/options_template.cpp127
-rw-r--r--src/options/printer_modes.cpp2
-rw-r--r--src/options/printer_modes.h2
-rw-r--r--src/options/proof_options.toml35
-rw-r--r--src/options/quantifiers_options.toml79
-rw-r--r--src/options/set_language.cpp2
-rw-r--r--src/options/set_language.h2
-rw-r--r--src/options/smt_options.toml157
-rw-r--r--src/options/strings_options.toml25
-rw-r--r--src/options/theory_options.toml32
-rw-r--r--src/options/uf_options.toml9
-rw-r--r--src/parser/CMakeLists.txt12
-rw-r--r--src/parser/antlr_input.cpp33
-rw-r--r--src/parser/antlr_input.h2
-rw-r--r--src/parser/antlr_input_imports.cpp2
-rw-r--r--src/parser/antlr_line_buffered_input.cpp2
-rw-r--r--src/parser/antlr_line_buffered_input.h2
-rw-r--r--src/parser/antlr_tracing.h2
-rw-r--r--src/parser/bounded_token_buffer.cpp2
-rw-r--r--src/parser/bounded_token_buffer.h2
-rw-r--r--src/parser/bounded_token_factory.cpp2
-rw-r--r--src/parser/bounded_token_factory.h2
-rw-r--r--src/parser/cvc/Cvc.g110
-rw-r--r--src/parser/cvc/cvc.cpp3
-rw-r--r--src/parser/cvc/cvc.h6
-rw-r--r--src/parser/cvc/cvc_input.cpp2
-rw-r--r--src/parser/cvc/cvc_input.h2
-rw-r--r--src/parser/input.cpp3
-rw-r--r--src/parser/input.h2
-rw-r--r--src/parser/line_buffer.cpp2
-rw-r--r--src/parser/line_buffer.h2
-rw-r--r--src/parser/memory_mapped_input_buffer.cpp3
-rw-r--r--src/parser/memory_mapped_input_buffer.h2
-rw-r--r--src/parser/parse_op.cpp2
-rw-r--r--src/parser/parse_op.h2
-rw-r--r--src/parser/parser.cpp130
-rw-r--r--src/parser/parser.h117
-rw-r--r--src/parser/parser_builder.cpp28
-rw-r--r--src/parser/parser_builder.h19
-rw-r--r--src/parser/parser_exception.h2
-rw-r--r--src/parser/smt2/Smt2.g334
-rw-r--r--src/parser/smt2/smt2.cpp311
-rw-r--r--src/parser/smt2/smt2.h143
-rw-r--r--src/parser/smt2/smt2_input.cpp2
-rw-r--r--src/parser/smt2/smt2_input.h2
-rw-r--r--src/parser/smt2/sygus_input.cpp2
-rw-r--r--src/parser/smt2/sygus_input.h2
-rw-r--r--src/parser/tptp/Tptp.g53
-rw-r--r--src/parser/tptp/tptp.cpp32
-rw-r--r--src/parser/tptp/tptp.h6
-rw-r--r--src/parser/tptp/tptp_input.cpp2
-rw-r--r--src/parser/tptp/tptp_input.h2
-rw-r--r--src/preprocessing/assertion_pipeline.cpp158
-rw-r--r--src/preprocessing/assertion_pipeline.h74
-rw-r--r--src/preprocessing/passes/ackermann.cpp28
-rw-r--r--src/preprocessing/passes/ackermann.h2
-rw-r--r--src/preprocessing/passes/apply_substs.cpp9
-rw-r--r--src/preprocessing/passes/apply_substs.h2
-rw-r--r--src/preprocessing/passes/bool_to_bv.cpp2
-rw-r--r--src/preprocessing/passes/bool_to_bv.h2
-rw-r--r--src/preprocessing/passes/bv_abstraction.cpp2
-rw-r--r--src/preprocessing/passes/bv_abstraction.h2
-rw-r--r--src/preprocessing/passes/bv_eager_atoms.cpp2
-rw-r--r--src/preprocessing/passes/bv_eager_atoms.h2
-rw-r--r--src/preprocessing/passes/bv_gauss.cpp22
-rw-r--r--src/preprocessing/passes/bv_gauss.h2
-rw-r--r--src/preprocessing/passes/bv_intro_pow2.cpp2
-rw-r--r--src/preprocessing/passes/bv_intro_pow2.h2
-rw-r--r--src/preprocessing/passes/bv_to_bool.cpp2
-rw-r--r--src/preprocessing/passes/bv_to_bool.h2
-rw-r--r--src/preprocessing/passes/bv_to_int.cpp1388
-rw-r--r--src/preprocessing/passes/bv_to_int.h181
-rw-r--r--src/preprocessing/passes/extended_rewriter_pass.cpp2
-rw-r--r--src/preprocessing/passes/extended_rewriter_pass.h2
-rw-r--r--src/preprocessing/passes/fun_def_fmf.cpp464
-rw-r--r--src/preprocessing/passes/fun_def_fmf.h106
-rw-r--r--src/preprocessing/passes/global_negate.cpp5
-rw-r--r--src/preprocessing/passes/global_negate.h4
-rw-r--r--src/preprocessing/passes/ho_elim.cpp20
-rw-r--r--src/preprocessing/passes/ho_elim.h4
-rw-r--r--src/preprocessing/passes/int_to_bv.cpp4
-rw-r--r--src/preprocessing/passes/int_to_bv.h2
-rw-r--r--src/preprocessing/passes/ite_removal.cpp22
-rw-r--r--src/preprocessing/passes/ite_removal.h2
-rw-r--r--src/preprocessing/passes/ite_simp.cpp15
-rw-r--r--src/preprocessing/passes/ite_simp.h2
-rw-r--r--src/preprocessing/passes/miplib_trick.cpp30
-rw-r--r--src/preprocessing/passes/miplib_trick.h2
-rw-r--r--src/preprocessing/passes/nl_ext_purify.cpp17
-rw-r--r--src/preprocessing/passes/nl_ext_purify.h2
-rw-r--r--src/preprocessing/passes/non_clausal_simp.cpp334
-rw-r--r--src/preprocessing/passes/non_clausal_simp.h46
-rw-r--r--src/preprocessing/passes/pseudo_boolean_processor.cpp2
-rw-r--r--src/preprocessing/passes/pseudo_boolean_processor.h2
-rw-r--r--src/preprocessing/passes/quantifier_macros.cpp64
-rw-r--r--src/preprocessing/passes/quantifier_macros.h14
-rw-r--r--src/preprocessing/passes/quantifiers_preprocess.cpp9
-rw-r--r--src/preprocessing/passes/quantifiers_preprocess.h2
-rw-r--r--src/preprocessing/passes/real_to_int.cpp7
-rw-r--r--src/preprocessing/passes/real_to_int.h2
-rw-r--r--src/preprocessing/passes/rewrite.cpp2
-rw-r--r--src/preprocessing/passes/rewrite.h2
-rw-r--r--src/preprocessing/passes/sep_skolem_emp.cpp2
-rw-r--r--src/preprocessing/passes/sep_skolem_emp.h2
-rw-r--r--src/preprocessing/passes/sort_infer.cpp9
-rw-r--r--src/preprocessing/passes/sort_infer.h2
-rw-r--r--src/preprocessing/passes/static_learning.cpp4
-rw-r--r--src/preprocessing/passes/static_learning.h2
-rw-r--r--src/preprocessing/passes/sygus_inference.cpp29
-rw-r--r--src/preprocessing/passes/sygus_inference.h4
-rw-r--r--src/preprocessing/passes/synth_rew_rules.cpp26
-rw-r--r--src/preprocessing/passes/synth_rew_rules.h2
-rw-r--r--src/preprocessing/passes/theory_preprocess.cpp5
-rw-r--r--src/preprocessing/passes/theory_preprocess.h2
-rw-r--r--src/preprocessing/passes/unconstrained_simplifier.cpp21
-rw-r--r--src/preprocessing/passes/unconstrained_simplifier.h3
-rw-r--r--src/preprocessing/preprocessing_pass.cpp12
-rw-r--r--src/preprocessing/preprocessing_pass.h2
-rw-r--r--src/preprocessing/preprocessing_pass_context.cpp23
-rw-r--r--src/preprocessing/preprocessing_pass_context.h21
-rw-r--r--src/preprocessing/preprocessing_pass_registry.cpp4
-rw-r--r--src/preprocessing/preprocessing_pass_registry.h2
-rw-r--r--src/preprocessing/util/ite_utilities.cpp16
-rw-r--r--src/preprocessing/util/ite_utilities.h9
-rw-r--r--src/printer/ast/ast_printer.cpp312
-rw-r--r--src/printer/ast/ast_printer.h154
-rw-r--r--src/printer/cvc/cvc_printer.cpp679
-rw-r--r--src/printer/cvc/cvc_printer.h157
-rw-r--r--src/printer/dagification_visitor.cpp2
-rw-r--r--src/printer/dagification_visitor.h2
-rw-r--r--src/printer/let_binding.cpp210
-rw-r--r--src/printer/let_binding.h150
-rw-r--r--src/printer/printer.cpp321
-rw-r--r--src/printer/printer.h235
-rw-r--r--src/printer/smt2/smt2_printer.cpp1182
-rw-r--r--src/printer/smt2/smt2_printer.h236
-rw-r--r--src/printer/tptp/tptp_printer.cpp54
-rw-r--r--src/printer/tptp/tptp_printer.h34
-rw-r--r--src/proof/arith_proof.cpp1207
-rw-r--r--src/proof/arith_proof.h217
-rw-r--r--src/proof/arith_proof_recorder.cpp89
-rw-r--r--src/proof/arith_proof_recorder.h107
-rw-r--r--src/proof/array_proof.cpp1350
-rw-r--r--src/proof/array_proof.h121
-rw-r--r--src/proof/bitvector_proof.cpp792
-rw-r--r--src/proof/bitvector_proof.h280
-rw-r--r--src/proof/clausal_bitvector_proof.cpp412
-rw-r--r--src/proof/clausal_bitvector_proof.h189
-rw-r--r--src/proof/clause_id.h11
-rw-r--r--src/proof/cnf_proof.cpp867
-rw-r--r--src/proof/cnf_proof.h138
-rw-r--r--src/proof/dimacs.cpp120
-rw-r--r--src/proof/dimacs.h69
-rw-r--r--src/proof/drat/drat_proof.cpp291
-rw-r--r--src/proof/drat/drat_proof.h140
-rw-r--r--src/proof/er/er_proof.cpp399
-rw-r--r--src/proof/er/er_proof.h218
-rw-r--r--src/proof/lemma_proof.cpp254
-rw-r--r--src/proof/lemma_proof.h115
-rw-r--r--src/proof/lfsc_proof_printer.cpp217
-rw-r--r--src/proof/lfsc_proof_printer.h154
-rw-r--r--src/proof/lrat/lrat_proof.cpp343
-rw-r--r--src/proof/lrat/lrat_proof.h184
-rw-r--r--src/proof/proof.h70
-rw-r--r--src/proof/proof_manager.cpp1056
-rw-r--r--src/proof/proof_manager.h327
-rw-r--r--src/proof/proof_output_channel.cpp100
-rw-r--r--src/proof/proof_output_channel.h77
-rw-r--r--src/proof/proof_utils.cpp126
-rw-r--r--src/proof/proof_utils.h229
-rw-r--r--src/proof/resolution_bitvector_proof.cpp523
-rw-r--r--src/proof/resolution_bitvector_proof.h113
-rw-r--r--src/proof/sat_proof.h5
-rw-r--r--src/proof/sat_proof_implementation.h23
-rw-r--r--src/proof/simplify_boolean_node.cpp183
-rw-r--r--src/proof/simplify_boolean_node.h27
-rw-r--r--src/proof/skolemization_manager.cpp69
-rw-r--r--src/proof/skolemization_manager.h55
-rw-r--r--src/proof/theory_proof.cpp1750
-rw-r--r--src/proof/theory_proof.h510
-rw-r--r--src/proof/uf_proof.cpp759
-rw-r--r--src/proof/uf_proof.h106
-rw-r--r--src/proof/unsat_core.cpp23
-rw-r--r--src/proof/unsat_core.h77
-rw-r--r--src/prop/bv_sat_solver_notify.h2
-rw-r--r--src/prop/bvminisat/bvminisat.cpp36
-rw-r--r--src/prop/bvminisat/bvminisat.h11
-rw-r--r--src/prop/bvminisat/core/Solver.cc406
-rw-r--r--src/prop/bvminisat/core/Solver.h50
-rw-r--r--src/prop/bvminisat/core/SolverTypes.h49
-rw-r--r--src/prop/bvminisat/simp/SimpSolver.cc55
-rw-r--r--src/prop/bvminisat/simp/SimpSolver.h2
-rw-r--r--src/prop/cadical.cpp3
-rw-r--r--src/prop/cadical.h2
-rw-r--r--src/prop/cnf_stream.cpp428
-rw-r--r--src/prop/cnf_stream.h329
-rw-r--r--src/prop/cryptominisat.cpp47
-rw-r--r--src/prop/cryptominisat.h5
-rw-r--r--src/prop/kissat.cpp3
-rw-r--r--src/prop/kissat.h2
-rw-r--r--src/prop/minisat/core/Solver.cc316
-rw-r--r--src/prop/minisat/core/Solver.h12
-rw-r--r--src/prop/minisat/core/SolverTypes.h64
-rw-r--r--src/prop/minisat/minisat.cpp8
-rw-r--r--src/prop/minisat/minisat.h2
-rw-r--r--src/prop/minisat/simp/SimpSolver.cc98
-rw-r--r--src/prop/minisat/simp/SimpSolver.h2
-rw-r--r--src/prop/proof_cnf_stream.cpp981
-rw-r--r--src/prop/proof_cnf_stream.h174
-rw-r--r--src/prop/proof_post_processor.cpp108
-rw-r--r--src/prop/proof_post_processor.h112
-rw-r--r--src/prop/prop_engine.cpp41
-rw-r--r--src/prop/prop_engine.h21
-rw-r--r--src/prop/prop_proof_manager.cpp109
-rw-r--r--src/prop/prop_proof_manager.h95
-rw-r--r--src/prop/registrar.h2
-rw-r--r--src/prop/sat_proof_manager.cpp722
-rw-r--r--src/prop/sat_proof_manager.h587
-rw-r--r--src/prop/sat_solver.h16
-rw-r--r--src/prop/sat_solver_factory.cpp2
-rw-r--r--src/prop/sat_solver_factory.h2
-rw-r--r--src/prop/sat_solver_types.cpp2
-rw-r--r--src/prop/sat_solver_types.h2
-rw-r--r--src/prop/theory_proxy.cpp32
-rw-r--r--src/prop/theory_proxy.h8
-rw-r--r--src/smt/abduction_solver.cpp26
-rw-r--r--src/smt/abduction_solver.h4
-rw-r--r--src/smt/abstract_values.cpp55
-rw-r--r--src/smt/abstract_values.h80
-rw-r--r--src/smt/assertions.cpp243
-rw-r--r--src/smt/assertions.h177
-rw-r--r--src/smt/check_models.cpp272
-rw-r--r--src/smt/check_models.h52
-rw-r--r--src/smt/command.cpp1722
-rw-r--r--src/smt/command.h958
-rw-r--r--src/smt/command_list.cpp30
-rw-r--r--src/smt/command_list.h39
-rw-r--r--src/smt/defined_function.h4
-rw-r--r--src/smt/dump.cpp114
-rw-r--r--src/smt/dump.h26
-rw-r--r--src/smt/dump_manager.cpp145
-rw-r--r--src/smt/dump_manager.h108
-rw-r--r--src/smt/interpolation_solver.cpp137
-rw-r--r--src/smt/interpolation_solver.h86
-rw-r--r--src/smt/listeners.cpp112
-rw-r--r--src/smt/listeners.h80
-rw-r--r--src/smt/logic_exception.h2
-rw-r--r--src/smt/logic_request.cpp2
-rw-r--r--src/smt/logic_request.h2
-rw-r--r--src/smt/managed_ostreams.cpp2
-rw-r--r--src/smt/managed_ostreams.h16
-rw-r--r--src/smt/model.cpp47
-rw-r--r--src/smt/model.h104
-rw-r--r--src/smt/model_blocker.cpp29
-rw-r--r--src/smt/model_blocker.h8
-rw-r--r--src/smt/model_core_builder.cpp19
-rw-r--r--src/smt/model_core_builder.h8
-rw-r--r--src/smt/node_command.cpp178
-rw-r--r--src/smt/node_command.h152
-rw-r--r--src/smt/options_manager.cpp146
-rw-r--r--src/smt/options_manager.h80
-rw-r--r--src/smt/output_manager.cpp35
-rw-r--r--src/smt/output_manager.h57
-rw-r--r--src/smt/preprocess_proof_generator.cpp182
-rw-r--r--src/smt/preprocess_proof_generator.h80
-rw-r--r--src/smt/preprocessor.cpp165
-rw-r--r--src/smt/preprocessor.h145
-rw-r--r--src/smt/process_assertions.cpp157
-rw-r--r--src/smt/process_assertions.h29
-rw-r--r--src/smt/proof_manager.cpp151
-rw-r--r--src/smt/proof_manager.h103
-rw-r--r--src/smt/proof_post_processor.cpp812
-rw-r--r--src/smt/proof_post_processor.h228
-rw-r--r--src/smt/quant_elim_solver.cpp131
-rw-r--r--src/smt/quant_elim_solver.h93
-rw-r--r--src/smt/set_defaults.cpp279
-rw-r--r--src/smt/set_defaults.h4
-rw-r--r--src/smt/smt_engine.cpp3077
-rw-r--r--src/smt/smt_engine.h757
-rw-r--r--src/smt/smt_engine_scope.cpp5
-rw-r--r--src/smt/smt_engine_scope.h4
-rw-r--r--src/smt/smt_engine_state.cpp312
-rw-r--r--src/smt/smt_engine_state.h266
-rw-r--r--src/smt/smt_engine_stats.cpp15
-rw-r--r--src/smt/smt_engine_stats.h10
-rw-r--r--src/smt/smt_mode.cpp37
-rw-r--r--src/smt/smt_mode.h57
-rw-r--r--src/smt/smt_solver.cpp266
-rw-r--r--src/smt/smt_solver.h150
-rw-r--r--src/smt/smt_statistics_registry.cpp2
-rw-r--r--src/smt/smt_statistics_registry.h2
-rw-r--r--src/smt/sygus_solver.cpp410
-rw-r--r--src/smt/sygus_solver.h190
-rw-r--r--src/smt/term_formula_removal.cpp497
-rw-r--r--src/smt/term_formula_removal.h191
-rw-r--r--src/smt/update_ostream.h5
-rw-r--r--src/smt/witness_form.cpp182
-rw-r--r--src/smt/witness_form.h103
-rw-r--r--src/smt_util/boolean_simplification.cpp2
-rw-r--r--src/smt_util/boolean_simplification.h14
-rw-r--r--src/smt_util/nary_builder.cpp2
-rw-r--r--src/smt_util/nary_builder.h2
-rw-r--r--src/theory/CMakeLists.txt10
-rw-r--r--src/theory/arith/approx_simplex.cpp2
-rw-r--r--src/theory/arith/approx_simplex.h2
-rw-r--r--src/theory/arith/arith_ite_utils.cpp13
-rw-r--r--src/theory/arith/arith_ite_utils.h4
-rw-r--r--src/theory/arith/arith_lemma.cpp (renamed from src/theory/arith/theory_arith_private_forward.h)27
-rw-r--r--src/theory/arith/arith_lemma.h61
-rw-r--r--src/theory/arith/arith_msum.cpp2
-rw-r--r--src/theory/arith/arith_msum.h2
-rw-r--r--src/theory/arith/arith_preprocess.cpp68
-rw-r--r--src/theory/arith/arith_preprocess.h80
-rw-r--r--src/theory/arith/arith_rewriter.cpp148
-rw-r--r--src/theory/arith/arith_rewriter.h7
-rw-r--r--src/theory/arith/arith_state.cpp38
-rw-r--r--src/theory/arith/arith_state.h57
-rw-r--r--src/theory/arith/arith_static_learner.cpp2
-rw-r--r--src/theory/arith/arith_static_learner.h2
-rw-r--r--src/theory/arith/arith_utilities.cpp49
-rw-r--r--src/theory/arith/arith_utilities.h12
-rw-r--r--src/theory/arith/arithvar.cpp2
-rw-r--r--src/theory/arith/arithvar.h2
-rw-r--r--src/theory/arith/arithvar_node_map.h2
-rw-r--r--src/theory/arith/attempt_solution_simplex.cpp2
-rw-r--r--src/theory/arith/attempt_solution_simplex.h2
-rw-r--r--src/theory/arith/bound_counts.h4
-rw-r--r--src/theory/arith/bound_inference.cpp250
-rw-r--r--src/theory/arith/bound_inference.h118
-rw-r--r--src/theory/arith/callbacks.cpp40
-rw-r--r--src/theory/arith/callbacks.h13
-rw-r--r--src/theory/arith/congruence_manager.cpp374
-rw-r--r--src/theory/arith/congruence_manager.h153
-rw-r--r--src/theory/arith/constraint.cpp685
-rw-r--r--src/theory/arith/constraint.h161
-rw-r--r--src/theory/arith/constraint_forward.h2
-rw-r--r--src/theory/arith/cut_log.cpp2
-rw-r--r--src/theory/arith/cut_log.h2
-rw-r--r--src/theory/arith/delta_rational.cpp2
-rw-r--r--src/theory/arith/delta_rational.h2
-rw-r--r--src/theory/arith/dio_solver.cpp2
-rw-r--r--src/theory/arith/dio_solver.h2
-rw-r--r--src/theory/arith/dual_simplex.cpp2
-rw-r--r--src/theory/arith/dual_simplex.h2
-rw-r--r--src/theory/arith/error_set.cpp2
-rw-r--r--src/theory/arith/error_set.h2
-rw-r--r--src/theory/arith/fc_simplex.cpp2
-rw-r--r--src/theory/arith/fc_simplex.h4
-rw-r--r--src/theory/arith/infer_bounds.cpp4
-rw-r--r--src/theory/arith/infer_bounds.h4
-rw-r--r--src/theory/arith/inference_id.cpp60
-rw-r--r--src/theory/arith/inference_id.h (renamed from src/theory/arith/nl/inference.h)71
-rw-r--r--src/theory/arith/inference_manager.cpp159
-rw-r--r--src/theory/arith/inference_manager.h128
-rw-r--r--src/theory/arith/kinds20
-rw-r--r--src/theory/arith/linear_equality.cpp26
-rw-r--r--src/theory/arith/linear_equality.h2
-rw-r--r--src/theory/arith/matrix.cpp2
-rw-r--r--src/theory/arith/matrix.h2
-rw-r--r--src/theory/arith/nl/cad/cdcac.cpp495
-rw-r--r--src/theory/arith/nl/cad/cdcac.h196
-rw-r--r--src/theory/arith/nl/cad/cdcac_utils.cpp375
-rw-r--r--src/theory/arith/nl/cad/cdcac_utils.h113
-rw-r--r--src/theory/arith/nl/cad/constraints.cpp84
-rw-r--r--src/theory/arith/nl/cad/constraints.h99
-rw-r--r--src/theory/arith/nl/cad/projections.cpp104
-rw-r--r--src/theory/arith/nl/cad/projections.h69
-rw-r--r--src/theory/arith/nl/cad/variable_ordering.cpp137
-rw-r--r--src/theory/arith/nl/cad/variable_ordering.h74
-rw-r--r--src/theory/arith/nl/cad_solver.cpp195
-rw-r--r--src/theory/arith/nl/cad_solver.h102
-rw-r--r--src/theory/arith/nl/ext/constraint.cpp (renamed from src/theory/arith/nl/nl_constraint.cpp)6
-rw-r--r--src/theory/arith/nl/ext/constraint.h (renamed from src/theory/arith/nl/nl_constraint.h)10
-rw-r--r--src/theory/arith/nl/ext/ext_state.cpp95
-rw-r--r--src/theory/arith/nl/ext/ext_state.h67
-rw-r--r--src/theory/arith/nl/ext/factoring_check.cpp181
-rw-r--r--src/theory/arith/nl/ext/factoring_check.h68
-rw-r--r--src/theory/arith/nl/ext/monomial.cpp (renamed from src/theory/arith/nl/nl_monomial.cpp)6
-rw-r--r--src/theory/arith/nl/ext/monomial.h (renamed from src/theory/arith/nl/nl_monomial.h)8
-rw-r--r--src/theory/arith/nl/ext/monomial_bounds_check.cpp500
-rw-r--r--src/theory/arith/nl/ext/monomial_bounds_check.h90
-rw-r--r--src/theory/arith/nl/ext/monomial_check.cpp740
-rw-r--r--src/theory/arith/nl/ext/monomial_check.h196
-rw-r--r--src/theory/arith/nl/ext/split_zero_check.cpp54
-rw-r--r--src/theory/arith/nl/ext/split_zero_check.h53
-rw-r--r--src/theory/arith/nl/ext/tangent_plane_check.cpp148
-rw-r--r--src/theory/arith/nl/ext/tangent_plane_check.h69
-rw-r--r--src/theory/arith/nl/ext_theory_callback.cpp131
-rw-r--r--src/theory/arith/nl/ext_theory_callback.h86
-rw-r--r--src/theory/arith/nl/iand_solver.cpp45
-rw-r--r--src/theory/arith/nl/iand_solver.h26
-rw-r--r--src/theory/arith/nl/iand_table.cpp222
-rw-r--r--src/theory/arith/nl/iand_table.h136
-rw-r--r--src/theory/arith/nl/icp/candidate.cpp120
-rw-r--r--src/theory/arith/nl/icp/candidate.h85
-rw-r--r--src/theory/arith/nl/icp/contraction_origins.cpp120
-rw-r--r--src/theory/arith/nl/icp/contraction_origins.h104
-rw-r--r--src/theory/arith/nl/icp/icp_solver.cpp386
-rw-r--r--src/theory/arith/nl/icp/icp_solver.h156
-rw-r--r--src/theory/arith/nl/icp/intersection.cpp224
-rw-r--r--src/theory/arith/nl/icp/intersection.h79
-rw-r--r--src/theory/arith/nl/icp/interval.h65
-rw-r--r--src/theory/arith/nl/inference.cpp55
-rw-r--r--src/theory/arith/nl/nl_lemma_utils.cpp17
-rw-r--r--src/theory/arith/nl/nl_lemma_utils.h34
-rw-r--r--src/theory/arith/nl/nl_model.cpp202
-rw-r--r--src/theory/arith/nl/nl_model.h104
-rw-r--r--src/theory/arith/nl/nl_solver.cpp1592
-rw-r--r--src/theory/arith/nl/nl_solver.h370
-rw-r--r--src/theory/arith/nl/nonlinear_extension.cpp695
-rw-r--r--src/theory/arith/nl/nonlinear_extension.h186
-rw-r--r--src/theory/arith/nl/poly_conversion.cpp805
-rw-r--r--src/theory/arith/nl/poly_conversion.h167
-rw-r--r--src/theory/arith/nl/stats.cpp2
-rw-r--r--src/theory/arith/nl/stats.h8
-rw-r--r--src/theory/arith/nl/strategy.cpp176
-rw-r--r--src/theory/arith/nl/strategy.h179
-rw-r--r--src/theory/arith/nl/transcendental_solver.cpp60
-rw-r--r--src/theory/arith/nl/transcendental_solver.h29
-rw-r--r--src/theory/arith/normal_form.cpp60
-rw-r--r--src/theory/arith/normal_form.h27
-rw-r--r--src/theory/arith/operator_elim.cpp73
-rw-r--r--src/theory/arith/operator_elim.h73
-rw-r--r--src/theory/arith/partial_model.cpp2
-rw-r--r--src/theory/arith/partial_model.h2
-rw-r--r--src/theory/arith/proof_checker.cpp21
-rw-r--r--src/theory/arith/proof_checker.h4
-rw-r--r--src/theory/arith/proof_macros.h34
-rw-r--r--src/theory/arith/rewrites.cpp50
-rw-r--r--src/theory/arith/rewrites.h82
-rw-r--r--src/theory/arith/simplex.cpp2
-rw-r--r--src/theory/arith/simplex.h2
-rw-r--r--src/theory/arith/simplex_update.cpp2
-rw-r--r--src/theory/arith/simplex_update.h2
-rw-r--r--src/theory/arith/soi_simplex.cpp2
-rw-r--r--src/theory/arith/soi_simplex.h4
-rw-r--r--src/theory/arith/tableau.cpp2
-rw-r--r--src/theory/arith/tableau.h2
-rw-r--r--src/theory/arith/tableau_sizes.cpp2
-rw-r--r--src/theory/arith/tableau_sizes.h3
-rw-r--r--src/theory/arith/theory_arith.cpp240
-rw-r--r--src/theory/arith/theory_arith.h110
-rw-r--r--src/theory/arith/theory_arith_private.cpp662
-rw-r--r--src/theory/arith/theory_arith_private.h143
-rw-r--r--src/theory/arith/theory_arith_type_rules.h15
-rw-r--r--src/theory/arith/type_enumerator.h2
-rw-r--r--src/theory/arrays/array_info.cpp2
-rw-r--r--src/theory/arrays/array_info.h2
-rw-r--r--src/theory/arrays/array_proof_reconstruction.cpp199
-rw-r--r--src/theory/arrays/array_proof_reconstruction.h59
-rw-r--r--src/theory/arrays/inference_manager.cpp128
-rw-r--r--src/theory/arrays/inference_manager.h77
-rw-r--r--src/theory/arrays/kinds2
-rw-r--r--src/theory/arrays/proof_checker.cpp118
-rw-r--r--src/theory/arrays/proof_checker.h49
-rw-r--r--src/theory/arrays/skolem_cache.cpp87
-rw-r--r--src/theory/arrays/skolem_cache.h57
-rw-r--r--src/theory/arrays/static_fact_manager.cpp170
-rw-r--r--src/theory/arrays/static_fact_manager.h116
-rw-r--r--src/theory/arrays/theory_arrays.cpp1244
-rw-r--r--src/theory/arrays/theory_arrays.h131
-rw-r--r--src/theory/arrays/theory_arrays_rewriter.cpp2
-rw-r--r--src/theory/arrays/theory_arrays_rewriter.h4
-rw-r--r--src/theory/arrays/theory_arrays_type_rules.h4
-rw-r--r--src/theory/arrays/type_enumerator.h2
-rw-r--r--src/theory/arrays/union_find.cpp2
-rw-r--r--src/theory/arrays/union_find.h2
-rw-r--r--src/theory/assertion.cpp2
-rw-r--r--src/theory/assertion.h2
-rw-r--r--src/theory/atom_requests.cpp2
-rw-r--r--src/theory/atom_requests.h2
-rw-r--r--src/theory/bags/bags_rewriter.cpp508
-rw-r--r--src/theory/bags/bags_rewriter.h224
-rw-r--r--src/theory/bags/bags_statistics.cpp35
-rw-r--r--src/theory/bags/bags_statistics.h45
-rw-r--r--src/theory/bags/inference_manager.cpp35
-rw-r--r--src/theory/bags/inference_manager.h57
-rw-r--r--src/theory/bags/kinds93
-rw-r--r--src/theory/bags/make_bag_op.cpp49
-rw-r--r--src/theory/bags/make_bag_op.h63
-rw-r--r--src/theory/bags/normal_form.cpp656
-rw-r--r--src/theory/bags/normal_form.h187
-rw-r--r--src/theory/bags/rewrites.cpp82
-rw-r--r--src/theory/bags/rewrites.h97
-rw-r--r--src/theory/bags/solver_state.cpp35
-rw-r--r--src/theory/bags/solver_state.h44
-rw-r--r--src/theory/bags/term_registry.cpp45
-rw-r--r--src/theory/bags/term_registry.h63
-rw-r--r--src/theory/bags/theory_bags.cpp143
-rw-r--r--src/theory/bags/theory_bags.h113
-rw-r--r--src/theory/bags/theory_bags_type_enumerator.cpp86
-rw-r--r--src/theory/bags/theory_bags_type_enumerator.h91
-rw-r--r--src/theory/bags/theory_bags_type_rules.h314
-rw-r--r--src/theory/booleans/circuit_propagator.cpp914
-rw-r--r--src/theory/booleans/circuit_propagator.h107
-rw-r--r--src/theory/booleans/proof_checker.cpp206
-rw-r--r--src/theory/booleans/proof_checker.h2
-rw-r--r--src/theory/booleans/proof_circuit_propagator.cpp587
-rw-r--r--src/theory/booleans/proof_circuit_propagator.h213
-rw-r--r--src/theory/booleans/theory_bool.cpp16
-rw-r--r--src/theory/booleans/theory_bool.h7
-rw-r--r--src/theory/booleans/theory_bool_rewriter.cpp4
-rw-r--r--src/theory/booleans/theory_bool_rewriter.h2
-rw-r--r--src/theory/booleans/theory_bool_type_rules.h2
-rw-r--r--src/theory/booleans/type_enumerator.h2
-rw-r--r--src/theory/builtin/proof_checker.cpp170
-rw-r--r--src/theory/builtin/proof_checker.h68
-rw-r--r--src/theory/builtin/theory_builtin.cpp4
-rw-r--r--src/theory/builtin/theory_builtin.h4
-rw-r--r--src/theory/builtin/theory_builtin_rewriter.cpp89
-rw-r--r--src/theory/builtin/theory_builtin_rewriter.h21
-rw-r--r--src/theory/builtin/theory_builtin_type_rules.cpp50
-rw-r--r--src/theory/builtin/theory_builtin_type_rules.h7
-rw-r--r--src/theory/builtin/type_enumerator.cpp2
-rw-r--r--src/theory/builtin/type_enumerator.h2
-rw-r--r--src/theory/bv/abstraction.cpp34
-rw-r--r--src/theory/bv/abstraction.h2
-rw-r--r--src/theory/bv/bitblast/aig_bitblaster.cpp7
-rw-r--r--src/theory/bv/bitblast/aig_bitblaster.h8
-rw-r--r--src/theory/bv/bitblast/bitblast_strategies_template.h2
-rw-r--r--src/theory/bv/bitblast/bitblast_utils.h2
-rw-r--r--src/theory/bv/bitblast/bitblaster.h23
-rw-r--r--src/theory/bv/bitblast/eager_bitblaster.cpp41
-rw-r--r--src/theory/bv/bitblast/eager_bitblaster.h10
-rw-r--r--src/theory/bv/bitblast/lazy_bitblaster.cpp72
-rw-r--r--src/theory/bv/bitblast/lazy_bitblaster.h21
-rw-r--r--src/theory/bv/bv_eager_solver.cpp16
-rw-r--r--src/theory/bv/bv_eager_solver.h11
-rw-r--r--src/theory/bv/bv_inequality_graph.cpp2
-rw-r--r--src/theory/bv/bv_inequality_graph.h2
-rw-r--r--src/theory/bv/bv_quick_check.cpp21
-rw-r--r--src/theory/bv/bv_quick_check.h142
-rw-r--r--src/theory/bv/bv_solver.h122
-rw-r--r--src/theory/bv/bv_solver_lazy.cpp830
-rw-r--r--src/theory/bv/bv_solver_lazy.h234
-rw-r--r--src/theory/bv/bv_solver_simple.cpp296
-rw-r--r--src/theory/bv/bv_solver_simple.h80
-rw-r--r--src/theory/bv/bv_subtheory.h28
-rw-r--r--src/theory/bv/bv_subtheory_algebraic.cpp55
-rw-r--r--src/theory/bv/bv_subtheory_algebraic.h154
-rw-r--r--src/theory/bv/bv_subtheory_bitblast.cpp24
-rw-r--r--src/theory/bv/bv_subtheory_bitblast.h27
-rw-r--r--src/theory/bv/bv_subtheory_core.cpp498
-rw-r--r--src/theory/bv/bv_subtheory_core.h122
-rw-r--r--src/theory/bv/bv_subtheory_inequality.cpp9
-rw-r--r--src/theory/bv/bv_subtheory_inequality.h46
-rw-r--r--src/theory/bv/slicer.cpp590
-rw-r--r--src/theory/bv/slicer.h211
-rw-r--r--src/theory/bv/theory_bv.cpp1022
-rw-r--r--src/theory/bv/theory_bv.h251
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules.h46
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_constant_evaluation.h2
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_core.h2
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_normalization.h2
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h231
-rw-r--r--src/theory/bv/theory_bv_rewrite_rules_simplification.h59
-rw-r--r--src/theory/bv/theory_bv_rewriter.cpp15
-rw-r--r--src/theory/bv/theory_bv_rewriter.h7
-rw-r--r--src/theory/bv/theory_bv_type_rules.h2
-rw-r--r--src/theory/bv/theory_bv_utils.cpp2
-rw-r--r--src/theory/bv/theory_bv_utils.h2
-rw-r--r--src/theory/bv/type_enumerator.h2
-rw-r--r--src/theory/care_graph.h2
-rw-r--r--src/theory/combination_care_graph.cpp100
-rw-r--r--src/theory/combination_care_graph.h52
-rw-r--r--src/theory/combination_engine.cpp127
-rw-r--r--src/theory/combination_engine.h145
-rw-r--r--src/theory/datatypes/datatypes_rewriter.cpp50
-rw-r--r--src/theory/datatypes/datatypes_rewriter.h2
-rw-r--r--src/theory/datatypes/infer_proof_cons.cpp275
-rw-r--r--src/theory/datatypes/infer_proof_cons.h99
-rw-r--r--src/theory/datatypes/inference.cpp105
-rw-r--r--src/theory/datatypes/inference.h123
-rw-r--r--src/theory/datatypes/inference_manager.cpp219
-rw-r--r--src/theory/datatypes/inference_manager.h131
-rw-r--r--src/theory/datatypes/kinds12
-rw-r--r--src/theory/datatypes/proof_checker.cpp135
-rw-r--r--src/theory/datatypes/proof_checker.h49
-rw-r--r--src/theory/datatypes/sygus_datatype_utils.cpp42
-rw-r--r--src/theory/datatypes/sygus_datatype_utils.h13
-rw-r--r--src/theory/datatypes/sygus_extension.cpp2
-rw-r--r--src/theory/datatypes/sygus_extension.h4
-rw-r--r--src/theory/datatypes/sygus_simple_sym.cpp2
-rw-r--r--src/theory/datatypes/sygus_simple_sym.h2
-rw-r--r--src/theory/datatypes/theory_datatypes.cpp959
-rw-r--r--src/theory/datatypes/theory_datatypes.h220
-rw-r--r--src/theory/datatypes/theory_datatypes_type_rules.h12
-rw-r--r--src/theory/datatypes/theory_datatypes_utils.cpp4
-rw-r--r--src/theory/datatypes/theory_datatypes_utils.h2
-rw-r--r--src/theory/datatypes/type_enumerator.cpp30
-rw-r--r--src/theory/datatypes/type_enumerator.h2
-rw-r--r--src/theory/decision_manager.cpp2
-rw-r--r--src/theory/decision_manager.h3
-rw-r--r--src/theory/decision_strategy.cpp2
-rw-r--r--src/theory/decision_strategy.h2
-rw-r--r--src/theory/eager_proof_generator.cpp39
-rw-r--r--src/theory/eager_proof_generator.h27
-rw-r--r--src/theory/ee_manager.cpp50
-rw-r--r--src/theory/ee_manager.h100
-rw-r--r--src/theory/ee_manager_distributed.cpp123
-rw-r--r--src/theory/ee_manager_distributed.h99
-rw-r--r--src/theory/ee_setup_info.h52
-rw-r--r--src/theory/engine_output_channel.cpp196
-rw-r--r--src/theory/engine_output_channel.h16
-rw-r--r--src/theory/evaluator.cpp32
-rw-r--r--src/theory/evaluator.h8
-rw-r--r--src/theory/example/ecdata.cpp103
-rw-r--r--src/theory/example/ecdata.h258
-rw-r--r--src/theory/example/theory_uf_tim.cpp327
-rw-r--r--src/theory/example/theory_uf_tim.h213
-rw-r--r--src/theory/ext_theory.cpp64
-rw-r--r--src/theory/ext_theory.h72
-rw-r--r--src/theory/fp/fp_converter.cpp121
-rw-r--r--src/theory/fp/fp_converter.h4
-rw-r--r--src/theory/fp/theory_fp.cpp302
-rw-r--r--src/theory/fp/theory_fp.h62
-rw-r--r--src/theory/fp/theory_fp_rewriter.cpp188
-rw-r--r--src/theory/fp/theory_fp_rewriter.h2
-rw-r--r--src/theory/fp/theory_fp_type_rules.h63
-rw-r--r--src/theory/fp/type_enumerator.h28
-rw-r--r--src/theory/inference_manager_buffered.cpp146
-rw-r--r--src/theory/inference_manager_buffered.h150
-rw-r--r--src/theory/interrupted.h2
-rw-r--r--src/theory/logic_info.cpp15
-rw-r--r--src/theory/logic_info.h2
-rwxr-xr-xsrc/theory/mkrewriter4
-rwxr-xr-xsrc/theory/mktheorytraits9
-rw-r--r--src/theory/model_manager.cpp228
-rw-r--r--src/theory/model_manager.h156
-rw-r--r--src/theory/model_manager_distributed.cpp116
-rw-r--r--src/theory/model_manager_distributed.h63
-rw-r--r--src/theory/output_channel.cpp114
-rw-r--r--src/theory/output_channel.h91
-rw-r--r--src/theory/quantifiers/alpha_equivalence.cpp32
-rw-r--r--src/theory/quantifiers/alpha_equivalence.h2
-rw-r--r--src/theory/quantifiers/anti_skolem.cpp2
-rw-r--r--src/theory/quantifiers/anti_skolem.h2
-rw-r--r--src/theory/quantifiers/bv_inverter.cpp2
-rw-r--r--src/theory/quantifiers/bv_inverter.h2
-rw-r--r--src/theory/quantifiers/bv_inverter_utils.cpp2
-rw-r--r--src/theory/quantifiers/bv_inverter_utils.h2
-rw-r--r--src/theory/quantifiers/candidate_rewrite_database.cpp42
-rw-r--r--src/theory/quantifiers/candidate_rewrite_database.h46
-rw-r--r--src/theory/quantifiers/candidate_rewrite_filter.cpp2
-rw-r--r--src/theory/quantifiers/candidate_rewrite_filter.h2
-rw-r--r--src/theory/quantifiers/cegqi/ceg_arith_instantiator.cpp2
-rw-r--r--src/theory/quantifiers/cegqi/ceg_arith_instantiator.h2
-rw-r--r--src/theory/quantifiers/cegqi/ceg_bv_instantiator.cpp2
-rw-r--r--src/theory/quantifiers/cegqi/ceg_bv_instantiator.h2
-rw-r--r--src/theory/quantifiers/cegqi/ceg_bv_instantiator_utils.cpp2
-rw-r--r--src/theory/quantifiers/cegqi/ceg_bv_instantiator_utils.h2
-rw-r--r--src/theory/quantifiers/cegqi/ceg_dt_instantiator.cpp2
-rw-r--r--src/theory/quantifiers/cegqi/ceg_dt_instantiator.h2
-rw-r--r--src/theory/quantifiers/cegqi/ceg_epr_instantiator.cpp2
-rw-r--r--src/theory/quantifiers/cegqi/ceg_epr_instantiator.h2
-rw-r--r--src/theory/quantifiers/cegqi/ceg_instantiator.cpp18
-rw-r--r--src/theory/quantifiers/cegqi/ceg_instantiator.h2
-rw-r--r--src/theory/quantifiers/cegqi/inst_strategy_cegqi.cpp303
-rw-r--r--src/theory/quantifiers/cegqi/inst_strategy_cegqi.h73
-rw-r--r--src/theory/quantifiers/cegqi/nested_qe.cpp155
-rw-r--r--src/theory/quantifiers/cegqi/nested_qe.h86
-rw-r--r--src/theory/quantifiers/cegqi/vts_term_cache.cpp2
-rw-r--r--src/theory/quantifiers/cegqi/vts_term_cache.h2
-rw-r--r--src/theory/quantifiers/conjecture_generator.cpp14
-rw-r--r--src/theory/quantifiers/conjecture_generator.h21
-rw-r--r--src/theory/quantifiers/dynamic_rewrite.cpp2
-rw-r--r--src/theory/quantifiers/dynamic_rewrite.h2
-rw-r--r--src/theory/quantifiers/ematching/candidate_generator.cpp2
-rw-r--r--src/theory/quantifiers/ematching/candidate_generator.h2
-rw-r--r--src/theory/quantifiers/ematching/ho_trigger.cpp2
-rw-r--r--src/theory/quantifiers/ematching/ho_trigger.h2
-rw-r--r--src/theory/quantifiers/ematching/inst_match_generator.cpp3
-rw-r--r--src/theory/quantifiers/ematching/inst_match_generator.h2
-rw-r--r--src/theory/quantifiers/ematching/inst_strategy_e_matching.cpp2
-rw-r--r--src/theory/quantifiers/ematching/inst_strategy_e_matching.h2
-rw-r--r--src/theory/quantifiers/ematching/instantiation_engine.cpp115
-rw-r--r--src/theory/quantifiers/ematching/instantiation_engine.h4
-rw-r--r--src/theory/quantifiers/ematching/trigger.cpp4
-rw-r--r--src/theory/quantifiers/ematching/trigger.h2
-rw-r--r--src/theory/quantifiers/equality_infer.cpp2
-rw-r--r--src/theory/quantifiers/equality_infer.h2
-rw-r--r--src/theory/quantifiers/equality_query.cpp4
-rw-r--r--src/theory/quantifiers/equality_query.h2
-rw-r--r--src/theory/quantifiers/expr_miner.cpp2
-rw-r--r--src/theory/quantifiers/expr_miner.h3
-rw-r--r--src/theory/quantifiers/expr_miner_manager.cpp8
-rw-r--r--src/theory/quantifiers/expr_miner_manager.h2
-rw-r--r--src/theory/quantifiers/extended_rewrite.cpp4
-rw-r--r--src/theory/quantifiers/extended_rewrite.h2
-rw-r--r--src/theory/quantifiers/first_order_model.cpp5
-rw-r--r--src/theory/quantifiers/first_order_model.h5
-rw-r--r--src/theory/quantifiers/fmf/bounded_integers.cpp6
-rw-r--r--src/theory/quantifiers/fmf/bounded_integers.h2
-rw-r--r--src/theory/quantifiers/fmf/full_model_check.cpp4
-rw-r--r--src/theory/quantifiers/fmf/full_model_check.h2
-rw-r--r--src/theory/quantifiers/fmf/model_builder.cpp3
-rw-r--r--src/theory/quantifiers/fmf/model_builder.h2
-rw-r--r--src/theory/quantifiers/fmf/model_engine.cpp35
-rw-r--r--src/theory/quantifiers/fmf/model_engine.h2
-rw-r--r--src/theory/quantifiers/fun_def_evaluator.cpp2
-rw-r--r--src/theory/quantifiers/fun_def_evaluator.h2
-rw-r--r--src/theory/quantifiers/fun_def_process.cpp340
-rw-r--r--src/theory/quantifiers/fun_def_process.h93
-rw-r--r--src/theory/quantifiers/inst_match.cpp2
-rw-r--r--src/theory/quantifiers/inst_match.h2
-rw-r--r--src/theory/quantifiers/inst_match_trie.cpp58
-rw-r--r--src/theory/quantifiers/inst_match_trie.h18
-rw-r--r--src/theory/quantifiers/inst_strategy_enumerative.cpp2
-rw-r--r--src/theory/quantifiers/inst_strategy_enumerative.h2
-rw-r--r--src/theory/quantifiers/instantiate.cpp211
-rw-r--r--src/theory/quantifiers/instantiate.h50
-rw-r--r--src/theory/quantifiers/lazy_trie.cpp2
-rw-r--r--src/theory/quantifiers/lazy_trie.h2
-rw-r--r--src/theory/quantifiers/proof_checker.cpp45
-rw-r--r--src/theory/quantifiers/proof_checker.h2
-rw-r--r--src/theory/quantifiers/quant_conflict_find.cpp2
-rw-r--r--src/theory/quantifiers/quant_conflict_find.h2
-rw-r--r--src/theory/quantifiers/quant_epr.cpp2
-rw-r--r--src/theory/quantifiers/quant_epr.h2
-rw-r--r--src/theory/quantifiers/quant_relevance.cpp2
-rw-r--r--src/theory/quantifiers/quant_relevance.h2
-rw-r--r--src/theory/quantifiers/quant_rep_bound_ext.cpp2
-rw-r--r--src/theory/quantifiers/quant_rep_bound_ext.h2
-rw-r--r--src/theory/quantifiers/quant_split.cpp2
-rw-r--r--src/theory/quantifiers/quant_split.h2
-rw-r--r--src/theory/quantifiers/quant_util.cpp4
-rw-r--r--src/theory/quantifiers/quant_util.h2
-rw-r--r--src/theory/quantifiers/quantifiers_attributes.cpp35
-rw-r--r--src/theory/quantifiers/quantifiers_attributes.h41
-rw-r--r--src/theory/quantifiers/quantifiers_modules.cpp113
-rw-r--r--src/theory/quantifiers/quantifiers_modules.h93
-rw-r--r--src/theory/quantifiers/quantifiers_rewriter.cpp14
-rw-r--r--src/theory/quantifiers/quantifiers_rewriter.h7
-rw-r--r--src/theory/quantifiers/quantifiers_state.cpp30
-rw-r--r--src/theory/quantifiers/quantifiers_state.h40
-rw-r--r--src/theory/quantifiers/query_generator.cpp2
-rw-r--r--src/theory/quantifiers/query_generator.h2
-rw-r--r--src/theory/quantifiers/relevant_domain.cpp2
-rw-r--r--src/theory/quantifiers/relevant_domain.h2
-rw-r--r--src/theory/quantifiers/single_inv_partition.cpp2
-rw-r--r--src/theory/quantifiers/single_inv_partition.h2
-rw-r--r--src/theory/quantifiers/skolemize.cpp86
-rw-r--r--src/theory/quantifiers/skolemize.h26
-rw-r--r--src/theory/quantifiers/solution_filter.cpp4
-rw-r--r--src/theory/quantifiers/solution_filter.h2
-rw-r--r--src/theory/quantifiers/sygus/ce_guided_single_inv.cpp210
-rw-r--r--src/theory/quantifiers/sygus/ce_guided_single_inv.h45
-rw-r--r--src/theory/quantifiers/sygus/ce_guided_single_inv_sol.cpp4
-rw-r--r--src/theory/quantifiers/sygus/ce_guided_single_inv_sol.h3
-rw-r--r--src/theory/quantifiers/sygus/cegis.cpp2
-rw-r--r--src/theory/quantifiers/sygus/cegis.h2
-rw-r--r--src/theory/quantifiers/sygus/cegis_core_connective.cpp10
-rw-r--r--src/theory/quantifiers/sygus/cegis_core_connective.h2
-rw-r--r--src/theory/quantifiers/sygus/cegis_unif.cpp20
-rw-r--r--src/theory/quantifiers/sygus/cegis_unif.h2
-rw-r--r--src/theory/quantifiers/sygus/enum_stream_substitution.cpp2
-rw-r--r--src/theory/quantifiers/sygus/enum_stream_substitution.h2
-rw-r--r--src/theory/quantifiers/sygus/example_eval_cache.cpp2
-rw-r--r--src/theory/quantifiers/sygus/example_eval_cache.h2
-rw-r--r--src/theory/quantifiers/sygus/example_infer.cpp2
-rw-r--r--src/theory/quantifiers/sygus/example_infer.h2
-rw-r--r--src/theory/quantifiers/sygus/example_min_eval.cpp2
-rw-r--r--src/theory/quantifiers/sygus/example_min_eval.h2
-rw-r--r--src/theory/quantifiers/sygus/sygus_abduct.cpp3
-rw-r--r--src/theory/quantifiers/sygus/sygus_abduct.h2
-rw-r--r--src/theory/quantifiers/sygus/sygus_enumerator.cpp147
-rw-r--r--src/theory/quantifiers/sygus/sygus_enumerator.h41
-rw-r--r--src/theory/quantifiers/sygus/sygus_enumerator_basic.cpp2
-rw-r--r--src/theory/quantifiers/sygus/sygus_enumerator_basic.h2
-rw-r--r--src/theory/quantifiers/sygus/sygus_eval_unfold.cpp2
-rw-r--r--src/theory/quantifiers/sygus/sygus_eval_unfold.h2
-rw-r--r--src/theory/quantifiers/sygus/sygus_explain.cpp2
-rw-r--r--src/theory/quantifiers/sygus/sygus_explain.h2
-rw-r--r--src/theory/quantifiers/sygus/sygus_grammar_cons.cpp174
-rw-r--r--src/theory/quantifiers/sygus/sygus_grammar_cons.h27
-rw-r--r--src/theory/quantifiers/sygus/sygus_grammar_norm.cpp15
-rw-r--r--src/theory/quantifiers/sygus/sygus_grammar_norm.h7
-rw-r--r--src/theory/quantifiers/sygus/sygus_grammar_red.cpp2
-rw-r--r--src/theory/quantifiers/sygus/sygus_grammar_red.h3
-rw-r--r--src/theory/quantifiers/sygus/sygus_interpol.cpp311
-rw-r--r--src/theory/quantifiers/sygus/sygus_interpol.h96
-rw-r--r--src/theory/quantifiers/sygus/sygus_invariance.cpp2
-rw-r--r--src/theory/quantifiers/sygus/sygus_invariance.h2
-rw-r--r--src/theory/quantifiers/sygus/sygus_module.cpp2
-rw-r--r--src/theory/quantifiers/sygus/sygus_module.h2
-rw-r--r--src/theory/quantifiers/sygus/sygus_pbe.cpp3
-rw-r--r--src/theory/quantifiers/sygus/sygus_pbe.h2
-rw-r--r--src/theory/quantifiers/sygus/sygus_process_conj.cpp3
-rw-r--r--src/theory/quantifiers/sygus/sygus_process_conj.h2
-rw-r--r--src/theory/quantifiers/sygus/sygus_qe_preproc.cpp147
-rw-r--r--src/theory/quantifiers/sygus/sygus_qe_preproc.h60
-rw-r--r--src/theory/quantifiers/sygus/sygus_repair_const.cpp4
-rw-r--r--src/theory/quantifiers/sygus/sygus_repair_const.h4
-rw-r--r--src/theory/quantifiers/sygus/sygus_stats.cpp2
-rw-r--r--src/theory/quantifiers/sygus/sygus_stats.h2
-rw-r--r--src/theory/quantifiers/sygus/sygus_unif.cpp2
-rw-r--r--src/theory/quantifiers/sygus/sygus_unif.h2
-rw-r--r--src/theory/quantifiers/sygus/sygus_unif_io.cpp88
-rw-r--r--src/theory/quantifiers/sygus/sygus_unif_io.h2
-rw-r--r--src/theory/quantifiers/sygus/sygus_unif_rl.cpp2
-rw-r--r--src/theory/quantifiers/sygus/sygus_unif_rl.h2
-rw-r--r--src/theory/quantifiers/sygus/sygus_unif_strat.cpp2
-rw-r--r--src/theory/quantifiers/sygus/sygus_unif_strat.h2
-rw-r--r--src/theory/quantifiers/sygus/synth_conjecture.cpp312
-rw-r--r--src/theory/quantifiers/sygus/synth_conjecture.h68
-rw-r--r--src/theory/quantifiers/sygus/synth_engine.cpp175
-rw-r--r--src/theory/quantifiers/sygus/synth_engine.h7
-rw-r--r--src/theory/quantifiers/sygus/template_infer.cpp205
-rw-r--r--src/theory/quantifiers/sygus/template_infer.h76
-rw-r--r--src/theory/quantifiers/sygus/term_database_sygus.cpp9
-rw-r--r--src/theory/quantifiers/sygus/term_database_sygus.h2
-rw-r--r--src/theory/quantifiers/sygus/transition_inference.cpp2
-rw-r--r--src/theory/quantifiers/sygus/transition_inference.h2
-rw-r--r--src/theory/quantifiers/sygus/type_info.cpp2
-rw-r--r--src/theory/quantifiers/sygus/type_info.h2
-rw-r--r--src/theory/quantifiers/sygus/type_node_id_trie.cpp2
-rw-r--r--src/theory/quantifiers/sygus/type_node_id_trie.h2
-rw-r--r--src/theory/quantifiers/sygus_inst.cpp314
-rw-r--r--src/theory/quantifiers/sygus_inst.h31
-rw-r--r--src/theory/quantifiers/sygus_sampler.cpp2
-rw-r--r--src/theory/quantifiers/sygus_sampler.h2
-rw-r--r--src/theory/quantifiers/term_database.cpp79
-rw-r--r--src/theory/quantifiers/term_database.h2
-rw-r--r--src/theory/quantifiers/term_enumeration.cpp2
-rw-r--r--src/theory/quantifiers/term_enumeration.h2
-rw-r--r--src/theory/quantifiers/term_util.cpp3
-rw-r--r--src/theory/quantifiers/term_util.h2
-rw-r--r--src/theory/quantifiers/theory_quantifiers.cpp120
-rw-r--r--src/theory/quantifiers/theory_quantifiers.h32
-rw-r--r--src/theory/quantifiers/theory_quantifiers_type_rules.h2
-rw-r--r--src/theory/quantifiers_engine.cpp440
-rw-r--r--src/theory/quantifiers_engine.h236
-rw-r--r--src/theory/relevance_manager.cpp315
-rw-r--r--src/theory/relevance_manager.h154
-rw-r--r--src/theory/rep_set.cpp4
-rw-r--r--src/theory/rep_set.h4
-rw-r--r--src/theory/rewriter.cpp80
-rw-r--r--src/theory/rewriter.h18
-rw-r--r--src/theory/rewriter_attributes.h2
-rw-r--r--src/theory/rewriter_tables_template.h4
-rw-r--r--src/theory/sep/kinds2
-rw-r--r--src/theory/sep/theory_sep.cpp1523
-rw-r--r--src/theory/sep/theory_sep.h134
-rw-r--r--src/theory/sep/theory_sep_rewriter.cpp8
-rw-r--r--src/theory/sep/theory_sep_rewriter.h2
-rw-r--r--src/theory/sep/theory_sep_type_rules.h2
-rw-r--r--src/theory/sets/cardinality_extension.cpp111
-rw-r--r--src/theory/sets/cardinality_extension.h13
-rw-r--r--src/theory/sets/inference_manager.cpp93
-rw-r--r--src/theory/sets/inference_manager.h68
-rw-r--r--src/theory/sets/kinds46
-rw-r--r--src/theory/sets/normal_form.h115
-rw-r--r--src/theory/sets/rels_utils.h2
-rw-r--r--src/theory/sets/singleton_op.cpp50
-rw-r--r--src/theory/sets/singleton_op.h63
-rw-r--r--src/theory/sets/skolem_cache.cpp2
-rw-r--r--src/theory/sets/skolem_cache.h2
-rw-r--r--src/theory/sets/solver_state.cpp303
-rw-r--r--src/theory/sets/solver_state.h130
-rw-r--r--src/theory/sets/term_registry.cpp154
-rw-r--r--src/theory/sets/term_registry.h94
-rw-r--r--src/theory/sets/theory_sets.cpp125
-rw-r--r--src/theory/sets/theory_sets.h67
-rw-r--r--src/theory/sets/theory_sets_private.cpp810
-rw-r--r--src/theory/sets/theory_sets_private.h118
-rw-r--r--src/theory/sets/theory_sets_rels.cpp102
-rw-r--r--src/theory/sets/theory_sets_rels.h15
-rw-r--r--src/theory/sets/theory_sets_rewriter.cpp163
-rw-r--r--src/theory/sets/theory_sets_rewriter.h8
-rw-r--r--src/theory/sets/theory_sets_type_enumerator.cpp7
-rw-r--r--src/theory/sets/theory_sets_type_enumerator.h2
-rw-r--r--src/theory/sets/theory_sets_type_rules.h189
-rw-r--r--src/theory/shared_solver.cpp116
-rw-r--r--src/theory/shared_solver.h134
-rw-r--r--src/theory/shared_solver_distributed.cpp96
-rw-r--r--src/theory/shared_solver_distributed.h64
-rw-r--r--src/theory/shared_terms_database.cpp187
-rw-r--r--src/theory/shared_terms_database.h95
-rw-r--r--src/theory/smt_engine_subsolver.cpp12
-rw-r--r--src/theory/smt_engine_subsolver.h16
-rw-r--r--src/theory/sort_inference.cpp3
-rw-r--r--src/theory/sort_inference.h2
-rw-r--r--src/theory/strings/arith_entail.cpp10
-rw-r--r--src/theory/strings/arith_entail.h2
-rw-r--r--src/theory/strings/base_solver.cpp9
-rw-r--r--src/theory/strings/base_solver.h2
-rw-r--r--src/theory/strings/core_solver.cpp543
-rw-r--r--src/theory/strings/core_solver.h67
-rw-r--r--src/theory/strings/eqc_info.cpp2
-rw-r--r--src/theory/strings/eqc_info.h2
-rw-r--r--src/theory/strings/extf_solver.cpp115
-rw-r--r--src/theory/strings/extf_solver.h30
-rw-r--r--src/theory/strings/infer_info.cpp37
-rw-r--r--src/theory/strings/infer_info.h53
-rw-r--r--src/theory/strings/infer_proof_cons.cpp1016
-rw-r--r--src/theory/strings/infer_proof_cons.h135
-rw-r--r--src/theory/strings/inference_manager.cpp476
-rw-r--r--src/theory/strings/inference_manager.h178
-rw-r--r--src/theory/strings/kinds6
-rw-r--r--src/theory/strings/normal_form.cpp11
-rw-r--r--src/theory/strings/normal_form.h2
-rw-r--r--src/theory/strings/proof_checker.cpp509
-rw-r--r--src/theory/strings/proof_checker.h49
-rw-r--r--src/theory/strings/regexp_elim.cpp2
-rw-r--r--src/theory/strings/regexp_elim.h2
-rw-r--r--src/theory/strings/regexp_entail.cpp4
-rw-r--r--src/theory/strings/regexp_entail.h2
-rw-r--r--src/theory/strings/regexp_operation.cpp1161
-rw-r--r--src/theory/strings/regexp_operation.h90
-rw-r--r--src/theory/strings/regexp_solver.cpp85
-rw-r--r--src/theory/strings/regexp_solver.h8
-rw-r--r--src/theory/strings/rewrites.cpp5
-rw-r--r--src/theory/strings/rewrites.h7
-rw-r--r--src/theory/strings/sequences_rewriter.cpp126
-rw-r--r--src/theory/strings/sequences_rewriter.h11
-rw-r--r--src/theory/strings/sequences_stats.cpp11
-rw-r--r--src/theory/strings/sequences_stats.h11
-rw-r--r--src/theory/strings/skolem_cache.cpp2
-rw-r--r--src/theory/strings/skolem_cache.h9
-rw-r--r--src/theory/strings/solver_state.cpp119
-rw-r--r--src/theory/strings/solver_state.h75
-rw-r--r--src/theory/strings/strategy.cpp6
-rw-r--r--src/theory/strings/strategy.h4
-rw-r--r--src/theory/strings/strings_entail.cpp141
-rw-r--r--src/theory/strings/strings_entail.h14
-rw-r--r--src/theory/strings/strings_fmf.cpp2
-rw-r--r--src/theory/strings/strings_fmf.h2
-rw-r--r--src/theory/strings/strings_rewriter.cpp2
-rw-r--r--src/theory/strings/strings_rewriter.h2
-rw-r--r--src/theory/strings/term_registry.cpp113
-rw-r--r--src/theory/strings/term_registry.h30
-rw-r--r--src/theory/strings/theory_strings.cpp495
-rw-r--r--src/theory/strings/theory_strings.h112
-rw-r--r--src/theory/strings/theory_strings_preprocess.cpp121
-rw-r--r--src/theory/strings/theory_strings_preprocess.h10
-rw-r--r--src/theory/strings/theory_strings_type_rules.h28
-rw-r--r--src/theory/strings/theory_strings_utils.cpp4
-rw-r--r--src/theory/strings/theory_strings_utils.h2
-rw-r--r--src/theory/strings/type_enumerator.cpp4
-rw-r--r--src/theory/strings/type_enumerator.h2
-rw-r--r--src/theory/strings/word.cpp4
-rw-r--r--src/theory/strings/word.h2
-rw-r--r--src/theory/subs_minimize.cpp2
-rw-r--r--src/theory/subs_minimize.h2
-rw-r--r--src/theory/substitutions.cpp54
-rw-r--r--src/theory/substitutions.h36
-rw-r--r--src/theory/term_registration_visitor.cpp121
-rw-r--r--src/theory/term_registration_visitor.h40
-rw-r--r--src/theory/theory.cpp281
-rw-r--r--src/theory/theory.h491
-rw-r--r--src/theory/theory_engine.cpp1524
-rw-r--r--src/theory/theory_engine.h314
-rw-r--r--src/theory/theory_engine_proof_generator.cpp71
-rw-r--r--src/theory/theory_engine_proof_generator.h8
-rw-r--r--src/theory/theory_eq_notify.h82
-rw-r--r--src/theory/theory_id.cpp93
-rw-r--r--src/theory/theory_id.h53
-rw-r--r--src/theory/theory_inference.cpp65
-rw-r--r--src/theory/theory_inference.h119
-rw-r--r--src/theory/theory_inference_manager.cpp474
-rw-r--r--src/theory/theory_inference_manager.h430
-rw-r--r--src/theory/theory_model.cpp138
-rw-r--r--src/theory/theory_model.h74
-rw-r--r--src/theory/theory_model_builder.cpp42
-rw-r--r--src/theory/theory_model_builder.h30
-rw-r--r--src/theory/theory_preprocessor.cpp304
-rw-r--r--src/theory/theory_preprocessor.h87
-rw-r--r--src/theory/theory_proof_step_buffer.cpp143
-rw-r--r--src/theory/theory_proof_step_buffer.h36
-rw-r--r--src/theory/theory_registrar.h2
-rw-r--r--src/theory/theory_rewriter.cpp4
-rw-r--r--src/theory/theory_rewriter.h4
-rw-r--r--src/theory/theory_state.cpp141
-rw-r--r--src/theory/theory_state.h105
-rw-r--r--src/theory/theory_test_utils.h20
-rw-r--r--src/theory/theory_traits_template.h4
-rw-r--r--src/theory/trust_node.cpp23
-rw-r--r--src/theory/trust_node.h13
-rw-r--r--src/theory/trust_substitutions.cpp253
-rw-r--r--src/theory/trust_substitutions.h138
-rw-r--r--src/theory/type_enumerator.h2
-rw-r--r--src/theory/type_enumerator_template.cpp4
-rw-r--r--src/theory/type_set.cpp2
-rw-r--r--src/theory/type_set.h2
-rw-r--r--src/theory/uf/cardinality_extension.cpp899
-rw-r--r--src/theory/uf/cardinality_extension.h113
-rw-r--r--src/theory/uf/eq_proof.cpp1360
-rw-r--r--src/theory/uf/eq_proof.h64
-rw-r--r--src/theory/uf/equality_engine.cpp820
-rw-r--r--src/theory/uf/equality_engine.h319
-rw-r--r--src/theory/uf/equality_engine_iterator.cpp135
-rw-r--r--src/theory/uf/equality_engine_iterator.h84
-rw-r--r--src/theory/uf/equality_engine_notify.h120
-rw-r--r--src/theory/uf/equality_engine_types.h25
-rw-r--r--src/theory/uf/ho_extension.cpp35
-rw-r--r--src/theory/uf/ho_extension.h14
-rw-r--r--src/theory/uf/kinds2
-rw-r--r--src/theory/uf/proof_checker.cpp56
-rw-r--r--src/theory/uf/proof_checker.h2
-rw-r--r--src/theory/uf/proof_equality_engine.cpp548
-rw-r--r--src/theory/uf/proof_equality_engine.h299
-rw-r--r--src/theory/uf/symmetry_breaker.cpp2
-rw-r--r--src/theory/uf/symmetry_breaker.h2
-rw-r--r--src/theory/uf/theory_uf.cpp445
-rw-r--r--src/theory/uf/theory_uf.h183
-rw-r--r--src/theory/uf/theory_uf_model.cpp2
-rw-r--r--src/theory/uf/theory_uf_model.h2
-rw-r--r--src/theory/uf/theory_uf_rewriter.h3
-rw-r--r--src/theory/uf/theory_uf_type_rules.h2
-rw-r--r--src/theory/valuation.cpp52
-rw-r--r--src/theory/valuation.h35
-rw-r--r--src/util/CMakeLists.txt25
-rw-r--r--src/util/abstract_value.cpp2
-rw-r--r--src/util/abstract_value.h2
-rw-r--r--src/util/bin_heap.h2
-rw-r--r--src/util/bitvector.cpp20
-rw-r--r--src/util/bitvector.h21
-rw-r--r--src/util/bool.h2
-rw-r--r--src/util/cardinality.cpp2
-rw-r--r--src/util/cardinality.h2
-rw-r--r--src/util/dense_map.h2
-rw-r--r--src/util/divisible.cpp2
-rw-r--r--src/util/divisible.h2
-rw-r--r--src/util/floatingpoint.cpp1221
-rw-r--r--src/util/floatingpoint.h516
-rw-r--r--src/util/floatingpoint.h.in554
-rw-r--r--src/util/floatingpoint_literal_symfpu.cpp428
-rw-r--r--src/util/floatingpoint_literal_symfpu.h.in327
-rw-r--r--src/util/floatingpoint_size.cpp34
-rw-r--r--src/util/floatingpoint_size.h97
-rw-r--r--src/util/gmp_util.h9
-rw-r--r--src/util/hash.h3
-rw-r--r--src/util/iand.h7
-rw-r--r--src/util/index.cpp3
-rw-r--r--src/util/index.h4
-rw-r--r--src/util/integer.h.in2
-rw-r--r--src/util/integer_cln_imp.cpp518
-rw-r--r--src/util/integer_cln_imp.h493
-rw-r--r--src/util/integer_gmp_imp.cpp424
-rw-r--r--src/util/integer_gmp_imp.h468
-rw-r--r--src/util/maybe.h2
-rw-r--r--src/util/ostream_util.cpp2
-rw-r--r--src/util/ostream_util.h2
-rw-r--r--src/util/poly_util.cpp365
-rw-r--r--src/util/poly_util.h145
-rw-r--r--src/util/proof.h44
-rw-r--r--src/util/random.cpp2
-rw-r--r--src/util/random.h2
-rw-r--r--src/util/rational.h.in2
-rw-r--r--src/util/rational_cln_imp.cpp2
-rw-r--r--src/util/rational_cln_imp.h2
-rw-r--r--src/util/rational_gmp_imp.cpp2
-rw-r--r--src/util/rational_gmp_imp.h8
-rw-r--r--src/util/real_algebraic_number.h.in25
-rw-r--r--src/util/real_algebraic_number_poly_imp.cpp175
-rw-r--r--src/util/real_algebraic_number_poly_imp.h160
-rw-r--r--src/util/regexp.cpp2
-rw-r--r--src/util/regexp.h3
-rw-r--r--src/util/resource_manager.cpp376
-rw-r--r--src/util/resource_manager.h365
-rw-r--r--src/util/result.cpp2
-rw-r--r--src/util/result.h2
-rw-r--r--src/util/roundingmode.h50
-rw-r--r--src/util/safe_print.cpp2
-rw-r--r--src/util/safe_print.h9
-rw-r--r--src/util/sampler.cpp2
-rw-r--r--src/util/sampler.h2
-rw-r--r--src/util/sexpr.cpp2
-rw-r--r--src/util/sexpr.h2
-rw-r--r--src/util/smt2_quote_string.cpp2
-rw-r--r--src/util/smt2_quote_string.h2
-rw-r--r--src/util/statistics.cpp2
-rw-r--r--src/util/statistics.h2
-rw-r--r--src/util/statistics_registry.cpp2
-rw-r--r--src/util/statistics_registry.h4
-rw-r--r--src/util/string.cpp14
-rw-r--r--src/util/string.h7
-rw-r--r--src/util/tuple.h2
-rw-r--r--src/util/unsafe_interrupt_exception.h2
-rw-r--r--src/util/utility.cpp2
-rw-r--r--src/util/utility.h2
1305 files changed, 76143 insertions, 52822 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index a19580c00..366e72af0 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,3 +1,13 @@
+#####################
+## CMakeLists.txt
+## Top contributors (to current version):
+## Mathias Preiner, Andrew Reynolds, Gereon Kremer
+## This file is part of the CVC4 project.
+## Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+## in the top-level source directory and their institutional affiliations.
+## All rights reserved. See the file COPYING in the top-level source
+## directory for licensing information.
+##
#-----------------------------------------------------------------------------#
# Collect libcvc4 source files
@@ -58,6 +68,8 @@ libcvc4_add_sources(
preprocessing/passes/bv_to_int.h
preprocessing/passes/extended_rewriter_pass.cpp
preprocessing/passes/extended_rewriter_pass.h
+ preprocessing/passes/fun_def_fmf.cpp
+ preprocessing/passes/fun_def_fmf.h
preprocessing/passes/global_negate.cpp
preprocessing/passes/global_negate.h
preprocessing/passes/ho_elim.cpp
@@ -112,58 +124,24 @@ libcvc4_add_sources(
printer/cvc/cvc_printer.h
printer/dagification_visitor.cpp
printer/dagification_visitor.h
+ printer/let_binding.cpp
+ printer/let_binding.h
printer/printer.cpp
printer/printer.h
printer/smt2/smt2_printer.cpp
printer/smt2/smt2_printer.h
printer/tptp/tptp_printer.cpp
printer/tptp/tptp_printer.h
- proof/arith_proof.cpp
- proof/arith_proof.h
- proof/arith_proof_recorder.cpp
- proof/arith_proof_recorder.h
- proof/array_proof.cpp
- proof/array_proof.h
- proof/bitvector_proof.cpp
- proof/bitvector_proof.h
- proof/clausal_bitvector_proof.cpp
- proof/clausal_bitvector_proof.h
proof/clause_id.h
proof/cnf_proof.cpp
proof/cnf_proof.h
- proof/dimacs.cpp
- proof/dimacs.h
- proof/drat/drat_proof.cpp
- proof/drat/drat_proof.h
- proof/er/er_proof.cpp
- proof/er/er_proof.h
- proof/lemma_proof.cpp
- proof/lemma_proof.h
- proof/lfsc_proof_printer.cpp
- proof/lfsc_proof_printer.h
- proof/lrat/lrat_proof.cpp
- proof/lrat/lrat_proof.h
- proof/proof.h
proof/proof_manager.cpp
proof/proof_manager.h
- proof/proof_output_channel.cpp
- proof/proof_output_channel.h
- proof/proof_utils.cpp
- proof/proof_utils.h
- proof/resolution_bitvector_proof.cpp
- proof/resolution_bitvector_proof.h
proof/sat_proof.h
proof/sat_proof_implementation.h
- proof/simplify_boolean_node.cpp
- proof/simplify_boolean_node.h
- proof/skolemization_manager.cpp
- proof/skolemization_manager.h
- proof/theory_proof.cpp
- proof/theory_proof.h
- proof/uf_proof.cpp
- proof/uf_proof.h
proof/unsat_core.cpp
proof/unsat_core.h
+ prop/bv_sat_solver_notify.h
prop/bvminisat/bvminisat.cpp
prop/bvminisat/bvminisat.h
prop/bvminisat/core/Dimacs.h
@@ -190,6 +168,8 @@ libcvc4_add_sources(
prop/cryptominisat.h
prop/kissat.cpp
prop/kissat.h
+ prop/proof_cnf_stream.cpp
+ prop/proof_cnf_stream.h
prop/minisat/core/Dimacs.h
prop/minisat/core/Solver.cc
prop/minisat/core/Solver.h
@@ -208,29 +188,44 @@ libcvc4_add_sources(
prop/minisat/simp/SimpSolver.cc
prop/minisat/simp/SimpSolver.h
prop/minisat/utils/Options.h
+ prop/proof_post_processor.cpp
+ prop/proof_post_processor.h
prop/prop_engine.cpp
prop/prop_engine.h
+ prop/prop_proof_manager.cpp
+ prop/prop_proof_manager.h
prop/registrar.h
prop/sat_solver.h
+ prop/sat_proof_manager.cpp
+ prop/sat_proof_manager.h
prop/sat_solver_factory.cpp
prop/sat_solver_factory.h
- prop/bv_sat_solver_notify.h
prop/sat_solver_types.cpp
prop/sat_solver_types.h
prop/theory_proxy.cpp
prop/theory_proxy.h
smt/abduction_solver.cpp
smt/abduction_solver.h
+ smt/abstract_values.cpp
+ smt/abstract_values.h
+ smt/assertions.cpp
+ smt/assertions.h
+ smt/check_models.cpp
+ smt/check_models.h
smt/command.cpp
smt/command.h
- smt/command_list.cpp
- smt/command_list.h
smt/defined_function.h
smt/dump.cpp
smt/dump.h
+ smt/dump_manager.cpp
+ smt/dump_manager.h
+ smt/listeners.cpp
+ smt/listeners.h
smt/logic_exception.h
smt/logic_request.cpp
smt/logic_request.h
+ smt/interpolation_solver.cpp
+ smt/interpolation_solver.h
smt/managed_ostreams.cpp
smt/managed_ostreams.h
smt/model.cpp
@@ -239,23 +234,47 @@ libcvc4_add_sources(
smt/model_core_builder.h
smt/model_blocker.cpp
smt/model_blocker.h
+ smt/node_command.cpp
+ smt/node_command.h
+ smt/options_manager.cpp
+ smt/options_manager.h
+ smt/output_manager.cpp
+ smt/output_manager.h
+ smt/quant_elim_solver.cpp
+ smt/quant_elim_solver.h
+ smt/preprocessor.cpp
+ smt/preprocessor.h
smt/preprocess_proof_generator.cpp
smt/preprocess_proof_generator.h
smt/process_assertions.cpp
smt/process_assertions.h
+ smt/proof_manager.cpp
+ smt/proof_manager.h
+ smt/proof_post_processor.cpp
+ smt/proof_post_processor.h
smt/set_defaults.cpp
smt/set_defaults.h
smt/smt_engine.cpp
smt/smt_engine.h
smt/smt_engine_scope.cpp
smt/smt_engine_scope.h
+ smt/smt_engine_state.cpp
+ smt/smt_engine_state.h
smt/smt_engine_stats.cpp
smt/smt_engine_stats.h
+ smt/smt_mode.cpp
+ smt/smt_mode.h
+ smt/smt_solver.cpp
+ smt/smt_solver.h
smt/smt_statistics_registry.cpp
smt/smt_statistics_registry.h
+ smt/sygus_solver.cpp
+ smt/sygus_solver.h
smt/term_formula_removal.cpp
smt/term_formula_removal.h
smt/update_ostream.h
+ smt/witness_form.cpp
+ smt/witness_form.h
smt_util/boolean_simplification.cpp
smt_util/boolean_simplification.h
smt_util/nary_builder.cpp
@@ -264,10 +283,16 @@ libcvc4_add_sources(
theory/arith/approx_simplex.h
theory/arith/arith_ite_utils.cpp
theory/arith/arith_ite_utils.h
+ theory/arith/arith_lemma.cpp
+ theory/arith/arith_lemma.h
theory/arith/arith_msum.cpp
theory/arith/arith_msum.h
+ theory/arith/arith_preprocess.cpp
+ theory/arith/arith_preprocess.h
theory/arith/arith_rewriter.cpp
theory/arith/arith_rewriter.h
+ theory/arith/arith_state.cpp
+ theory/arith/arith_state.h
theory/arith/arith_static_learner.cpp
theory/arith/arith_static_learner.h
theory/arith/arith_utilities.cpp
@@ -277,6 +302,8 @@ libcvc4_add_sources(
theory/arith/attempt_solution_simplex.cpp
theory/arith/attempt_solution_simplex.h
theory/arith/bound_counts.h
+ theory/arith/bound_inference.cpp
+ theory/arith/bound_inference.h
theory/arith/callbacks.cpp
theory/arith/callbacks.h
theory/arith/congruence_manager.cpp
@@ -298,28 +325,68 @@ libcvc4_add_sources(
theory/arith/fc_simplex.h
theory/arith/infer_bounds.cpp
theory/arith/infer_bounds.h
+ theory/arith/inference_id.cpp
+ theory/arith/inference_id.h
+ theory/arith/inference_manager.cpp
+ theory/arith/inference_manager.h
theory/arith/linear_equality.cpp
theory/arith/linear_equality.h
theory/arith/matrix.cpp
theory/arith/matrix.h
+ theory/arith/nl/cad_solver.cpp
+ theory/arith/nl/cad_solver.h
+ theory/arith/nl/cad/cdcac.cpp
+ theory/arith/nl/cad/cdcac.h
+ theory/arith/nl/cad/cdcac_utils.cpp
+ theory/arith/nl/cad/cdcac_utils.h
+ theory/arith/nl/cad/constraints.cpp
+ theory/arith/nl/cad/constraints.h
+ theory/arith/nl/cad/projections.cpp
+ theory/arith/nl/cad/projections.h
+ theory/arith/nl/cad/variable_ordering.cpp
+ theory/arith/nl/cad/variable_ordering.h
+ theory/arith/nl/ext/constraint.cpp
+ theory/arith/nl/ext/constraint.h
+ theory/arith/nl/ext/factoring_check.cpp
+ theory/arith/nl/ext/factoring_check.h
+ theory/arith/nl/ext/monomial.cpp
+ theory/arith/nl/ext/monomial.h
+ theory/arith/nl/ext/monomial_bounds_check.cpp
+ theory/arith/nl/ext/monomial_bounds_check.h
+ theory/arith/nl/ext/monomial_check.cpp
+ theory/arith/nl/ext/monomial_check.h
+ theory/arith/nl/ext/ext_state.cpp
+ theory/arith/nl/ext/ext_state.h
+ theory/arith/nl/ext/split_zero_check.cpp
+ theory/arith/nl/ext/split_zero_check.h
+ theory/arith/nl/ext/tangent_plane_check.cpp
+ theory/arith/nl/ext/tangent_plane_check.h
+ theory/arith/nl/ext_theory_callback.cpp
+ theory/arith/nl/ext_theory_callback.h
theory/arith/nl/iand_solver.cpp
theory/arith/nl/iand_solver.h
- theory/arith/nl/inference.cpp
- theory/arith/nl/inference.h
- theory/arith/nl/nl_constraint.cpp
- theory/arith/nl/nl_constraint.h
+ theory/arith/nl/icp/candidate.cpp
+ theory/arith/nl/icp/candidate.h
+ theory/arith/nl/icp/contraction_origins.cpp
+ theory/arith/nl/icp/contraction_origins.h
+ theory/arith/nl/icp/icp_solver.cpp
+ theory/arith/nl/icp/icp_solver.h
+ theory/arith/nl/icp/intersection.cpp
+ theory/arith/nl/icp/intersection.h
+ theory/arith/nl/iand_table.cpp
+ theory/arith/nl/iand_table.h
theory/arith/nl/nl_lemma_utils.cpp
theory/arith/nl/nl_lemma_utils.h
theory/arith/nl/nl_model.cpp
theory/arith/nl/nl_model.h
- theory/arith/nl/nl_monomial.cpp
- theory/arith/nl/nl_monomial.h
- theory/arith/nl/nl_solver.cpp
- theory/arith/nl/nl_solver.h
theory/arith/nl/nonlinear_extension.cpp
theory/arith/nl/nonlinear_extension.h
+ theory/arith/nl/poly_conversion.cpp
+ theory/arith/nl/poly_conversion.h
theory/arith/nl/stats.cpp
theory/arith/nl/stats.h
+ theory/arith/nl/strategy.cpp
+ theory/arith/nl/strategy.h
theory/arith/nl/transcendental_solver.cpp
theory/arith/nl/transcendental_solver.h
theory/arith/normal_form.cpp
@@ -328,6 +395,11 @@ libcvc4_add_sources(
theory/arith/operator_elim.h
theory/arith/partial_model.cpp
theory/arith/partial_model.h
+ theory/arith/proof_checker.cpp
+ theory/arith/proof_checker.h
+ theory/arith/proof_macros.h
+ theory/arith/rewrites.cpp
+ theory/arith/rewrites.h
theory/arith/simplex.cpp
theory/arith/simplex.h
theory/arith/simplex_update.cpp
@@ -342,15 +414,16 @@ libcvc4_add_sources(
theory/arith/theory_arith.h
theory/arith/theory_arith_private.cpp
theory/arith/theory_arith_private.h
- theory/arith/theory_arith_private_forward.h
theory/arith/theory_arith_type_rules.h
theory/arith/type_enumerator.h
theory/arrays/array_info.cpp
theory/arrays/array_info.h
- theory/arrays/array_proof_reconstruction.cpp
- theory/arrays/array_proof_reconstruction.h
- theory/arrays/static_fact_manager.cpp
- theory/arrays/static_fact_manager.h
+ theory/arrays/inference_manager.cpp
+ theory/arrays/inference_manager.h
+ theory/arrays/proof_checker.cpp
+ theory/arrays/proof_checker.h
+ theory/arrays/skolem_cache.cpp
+ theory/arrays/skolem_cache.h
theory/arrays/theory_arrays.cpp
theory/arrays/theory_arrays.h
theory/arrays/theory_arrays_rewriter.cpp
@@ -363,8 +436,31 @@ libcvc4_add_sources(
theory/assertion.h
theory/atom_requests.cpp
theory/atom_requests.h
+ theory/bags/bags_rewriter.cpp
+ theory/bags/bags_rewriter.h
+ theory/bags/bags_statistics.cpp
+ theory/bags/bags_statistics.h
+ theory/bags/inference_manager.cpp
+ theory/bags/inference_manager.h
+ theory/bags/make_bag_op.cpp
+ theory/bags/make_bag_op.h
+ theory/bags/normal_form.cpp
+ theory/bags/normal_form.h
+ theory/bags/rewrites.cpp
+ theory/bags/rewrites.h
+ theory/bags/solver_state.cpp
+ theory/bags/solver_state.h
+ theory/bags/term_registry.cpp
+ theory/bags/term_registry.h
+ theory/bags/theory_bags.cpp
+ theory/bags/theory_bags.h
+ theory/bags/theory_bags_type_enumerator.cpp
+ theory/bags/theory_bags_type_enumerator.h
+ theory/bags/theory_bags_type_rules.h
theory/booleans/circuit_propagator.cpp
theory/booleans/circuit_propagator.h
+ theory/booleans/proof_circuit_propagator.cpp
+ theory/booleans/proof_circuit_propagator.h
theory/booleans/proof_checker.cpp
theory/booleans/proof_checker.h
theory/booleans/theory_bool.cpp
@@ -379,6 +475,7 @@ libcvc4_add_sources(
theory/builtin/theory_builtin.h
theory/builtin/theory_builtin_rewriter.cpp
theory/builtin/theory_builtin_rewriter.h
+ theory/builtin/theory_builtin_type_rules.cpp
theory/builtin/theory_builtin_type_rules.h
theory/builtin/type_enumerator.cpp
theory/builtin/type_enumerator.h
@@ -399,6 +496,11 @@ libcvc4_add_sources(
theory/bv/bv_inequality_graph.h
theory/bv/bv_quick_check.cpp
theory/bv/bv_quick_check.h
+ theory/bv/bv_solver.h
+ theory/bv/bv_solver_lazy.cpp
+ theory/bv/bv_solver_lazy.h
+ theory/bv/bv_solver_simple.cpp
+ theory/bv/bv_solver_simple.h
theory/bv/bv_subtheory.h
theory/bv/bv_subtheory_algebraic.cpp
theory/bv/bv_subtheory_algebraic.h
@@ -425,8 +527,20 @@ libcvc4_add_sources(
theory/bv/theory_bv_utils.h
theory/bv/type_enumerator.h
theory/care_graph.h
+ theory/combination_care_graph.cpp
+ theory/combination_care_graph.h
+ theory/combination_engine.cpp
+ theory/combination_engine.h
theory/datatypes/datatypes_rewriter.cpp
theory/datatypes/datatypes_rewriter.h
+ theory/datatypes/inference.cpp
+ theory/datatypes/inference.h
+ theory/datatypes/inference_manager.cpp
+ theory/datatypes/inference_manager.h
+ theory/datatypes/infer_proof_cons.cpp
+ theory/datatypes/infer_proof_cons.h
+ theory/datatypes/proof_checker.cpp
+ theory/datatypes/proof_checker.h
theory/datatypes/sygus_datatype_utils.cpp
theory/datatypes/sygus_datatype_utils.h
theory/datatypes/sygus_extension.cpp
@@ -446,6 +560,11 @@ libcvc4_add_sources(
theory/decision_strategy.h
theory/eager_proof_generator.cpp
theory/eager_proof_generator.h
+ theory/ee_manager.cpp
+ theory/ee_manager.h
+ theory/ee_manager_distributed.cpp
+ theory/ee_manager_distributed.h
+ theory/ee_setup_info.h
theory/engine_output_channel.cpp
theory/engine_output_channel.h
theory/evaluator.cpp
@@ -461,8 +580,15 @@ libcvc4_add_sources(
theory/fp/theory_fp_type_rules.h
theory/fp/type_enumerator.h
theory/interrupted.h
+ theory/inference_manager_buffered.cpp
+ theory/inference_manager_buffered.h
theory/logic_info.cpp
theory/logic_info.h
+ theory/model_manager.cpp
+ theory/model_manager.h
+ theory/model_manager_distributed.cpp
+ theory/model_manager_distributed.h
+ theory/output_channel.cpp
theory/output_channel.h
theory/quantifiers/alpha_equivalence.cpp
theory/quantifiers/alpha_equivalence.h
@@ -490,6 +616,8 @@ libcvc4_add_sources(
theory/quantifiers/cegqi/ceg_instantiator.h
theory/quantifiers/cegqi/inst_strategy_cegqi.cpp
theory/quantifiers/cegqi/inst_strategy_cegqi.h
+ theory/quantifiers/cegqi/nested_qe.cpp
+ theory/quantifiers/cegqi/nested_qe.h
theory/quantifiers/cegqi/vts_term_cache.cpp
theory/quantifiers/cegqi/vts_term_cache.h
theory/quantifiers/conjecture_generator.cpp
@@ -530,8 +658,6 @@ libcvc4_add_sources(
theory/quantifiers/fmf/model_engine.h
theory/quantifiers/fun_def_evaluator.cpp
theory/quantifiers/fun_def_evaluator.h
- theory/quantifiers/fun_def_process.cpp
- theory/quantifiers/fun_def_process.h
theory/quantifiers/inst_match.cpp
theory/quantifiers/inst_match.h
theory/quantifiers/inst_match_trie.cpp
@@ -560,8 +686,12 @@ libcvc4_add_sources(
theory/quantifiers/quant_util.h
theory/quantifiers/quantifiers_attributes.cpp
theory/quantifiers/quantifiers_attributes.h
+ theory/quantifiers/quantifiers_modules.cpp
+ theory/quantifiers/quantifiers_modules.h
theory/quantifiers/quantifiers_rewriter.cpp
theory/quantifiers/quantifiers_rewriter.h
+ theory/quantifiers/quantifiers_state.cpp
+ theory/quantifiers/quantifiers_state.h
theory/quantifiers/query_generator.cpp
theory/quantifiers/query_generator.h
theory/quantifiers/relevant_domain.cpp
@@ -620,6 +750,8 @@ libcvc4_add_sources(
theory/quantifiers/sygus/sygus_pbe.h
theory/quantifiers/sygus/sygus_process_conj.cpp
theory/quantifiers/sygus/sygus_process_conj.h
+ theory/quantifiers/sygus/sygus_qe_preproc.cpp
+ theory/quantifiers/sygus/sygus_qe_preproc.h
theory/quantifiers/sygus/sygus_repair_const.cpp
theory/quantifiers/sygus/sygus_repair_const.h
theory/quantifiers/sygus/sygus_stats.cpp
@@ -636,6 +768,8 @@ libcvc4_add_sources(
theory/quantifiers/sygus/synth_conjecture.h
theory/quantifiers/sygus/synth_engine.cpp
theory/quantifiers/sygus/synth_engine.h
+ theory/quantifiers/sygus/template_infer.cpp
+ theory/quantifiers/sygus/template_infer.h
theory/quantifiers/sygus/term_database_sygus.cpp
theory/quantifiers/sygus/term_database_sygus.h
theory/quantifiers/sygus/type_info.cpp
@@ -657,6 +791,8 @@ libcvc4_add_sources(
theory/quantifiers/theory_quantifiers_type_rules.h
theory/quantifiers_engine.cpp
theory/quantifiers_engine.h
+ theory/relevance_manager.cpp
+ theory/relevance_manager.h
theory/rep_set.cpp
theory/rep_set.h
theory/rewriter.cpp
@@ -673,10 +809,14 @@ libcvc4_add_sources(
theory/sets/inference_manager.h
theory/sets/normal_form.h
theory/sets/rels_utils.h
+ theory/sets/singleton_op.cpp
+ theory/sets/singleton_op.h
theory/sets/skolem_cache.cpp
theory/sets/skolem_cache.h
theory/sets/solver_state.cpp
theory/sets/solver_state.h
+ theory/sets/term_registry.cpp
+ theory/sets/term_registry.h
theory/sets/theory_sets.cpp
theory/sets/theory_sets.h
theory/sets/theory_sets_private.cpp
@@ -688,6 +828,10 @@ libcvc4_add_sources(
theory/sets/theory_sets_type_enumerator.cpp
theory/sets/theory_sets_type_enumerator.h
theory/sets/theory_sets_type_rules.h
+ theory/shared_solver.cpp
+ theory/shared_solver.h
+ theory/shared_solver_distributed.cpp
+ theory/shared_solver_distributed.h
theory/shared_terms_database.cpp
theory/shared_terms_database.h
theory/smt_engine_subsolver.cpp
@@ -706,10 +850,14 @@ libcvc4_add_sources(
theory/strings/eqc_info.h
theory/strings/infer_info.cpp
theory/strings/infer_info.h
+ theory/strings/infer_proof_cons.cpp
+ theory/strings/infer_proof_cons.h
theory/strings/inference_manager.cpp
theory/strings/inference_manager.h
theory/strings/normal_form.cpp
theory/strings/normal_form.h
+ theory/strings/proof_checker.cpp
+ theory/strings/proof_checker.h
theory/strings/regexp_elim.cpp
theory/strings/regexp_elim.h
theory/strings/regexp_entail.cpp
@@ -763,6 +911,11 @@ libcvc4_add_sources(
theory/theory_engine_proof_generator.h
theory/theory_id.cpp
theory/theory_id.h
+ theory/theory_eq_notify.h
+ theory/theory_inference.cpp
+ theory/theory_inference.h
+ theory/theory_inference_manager.cpp
+ theory/theory_inference_manager.h
theory/theory_model.cpp
theory/theory_model.h
theory/theory_model_builder.cpp
@@ -774,9 +927,13 @@ libcvc4_add_sources(
theory/theory_rewriter.cpp
theory/theory_rewriter.h
theory/theory_registrar.h
+ theory/theory_state.cpp
+ theory/theory_state.h
theory/theory_test_utils.h
theory/trust_node.cpp
theory/trust_node.h
+ theory/trust_substitutions.cpp
+ theory/trust_substitutions.h
theory/type_enumerator.h
theory/type_set.cpp
theory/type_set.h
@@ -784,11 +941,16 @@ libcvc4_add_sources(
theory/uf/cardinality_extension.h
theory/uf/equality_engine.cpp
theory/uf/equality_engine.h
+ theory/uf/equality_engine_iterator.cpp
+ theory/uf/equality_engine_iterator.h
+ theory/uf/equality_engine_notify.h
theory/uf/equality_engine_types.h
theory/uf/eq_proof.cpp
theory/uf/eq_proof.h
theory/uf/proof_checker.cpp
theory/uf/proof_checker.h
+ theory/uf/proof_equality_engine.cpp
+ theory/uf/proof_equality_engine.h
theory/uf/ho_extension.cpp
theory/uf/ho_extension.h
theory/uf/symmetry_breaker.cpp
@@ -822,6 +984,7 @@ set(KINDS_FILES
${PROJECT_SOURCE_DIR}/src/theory/datatypes/kinds
${PROJECT_SOURCE_DIR}/src/theory/sep/kinds
${PROJECT_SOURCE_DIR}/src/theory/sets/kinds
+ ${PROJECT_SOURCE_DIR}/src/theory/bags/kinds
${PROJECT_SOURCE_DIR}/src/theory/strings/kinds
${PROJECT_SOURCE_DIR}/src/theory/quantifiers/kinds)
@@ -831,7 +994,9 @@ set(KINDS_FILES
add_subdirectory(base)
add_subdirectory(expr)
add_subdirectory(options)
-add_subdirectory(parser)
+if (NOT BUILD_LIB_ONLY)
+ add_subdirectory(parser)
+endif()
add_subdirectory(theory)
add_subdirectory(util)
@@ -849,8 +1014,8 @@ target_include_directories(cvc4
install(TARGETS cvc4
EXPORT cvc4-targets
- LIBRARY DESTINATION ${LIBRARY_INSTALL_DIR}
- ARCHIVE DESTINATION ${LIBRARY_INSTALL_DIR})
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR})
set_target_properties(cvc4 PROPERTIES SOVERSION ${CVC4_SOVERSION})
target_compile_definitions(cvc4
@@ -898,6 +1063,10 @@ if(USE_LFSC)
target_link_libraries(cvc4 ${LFSC_LIBRARIES})
target_include_directories(cvc4 PRIVATE ${LFSC_INCLUDE_DIR})
endif()
+if(USE_POLY)
+ target_link_libraries(cvc4 ${POLY_LIBRARIES})
+ target_include_directories(cvc4 PRIVATE ${POLY_INCLUDE_DIR})
+endif()
if(USE_SYMFPU)
target_include_directories(cvc4
PUBLIC $<BUILD_INTERFACE:${SymFPU_INCLUDE_DIR}>)
@@ -919,7 +1088,9 @@ target_link_libraries(cvc4 ${RT_LIBRARIES})
# target_link_libraries(...) with object libraries for cmake versions <= 3.12.
# Thus, we can only visit main as soon as all dependencies for cvc4 are set up.
-add_subdirectory(main)
+if (NOT BUILD_LIB_ONLY)
+ add_subdirectory(main)
+endif()
#-----------------------------------------------------------------------------#
# Note:
@@ -934,36 +1105,36 @@ install(FILES
api/cvc4cpp.h
api/cvc4cppkind.h
DESTINATION
- ${INCLUDE_INSTALL_DIR}/cvc4/api)
+ ${CMAKE_INSTALL_INCLUDEDIR}/cvc4/api)
install(FILES
base/configuration.h
base/exception.h
base/listener.h
base/modal_exception.h
DESTINATION
- ${INCLUDE_INSTALL_DIR}/cvc4/base)
+ ${CMAKE_INSTALL_INCLUDEDIR}/cvc4/base)
install(FILES
context/cdhashmap_forward.h
context/cdhashset_forward.h
context/cdinsert_hashmap_forward.h
context/cdlist_forward.h
DESTINATION
- ${INCLUDE_INSTALL_DIR}/cvc4/context)
+ ${CMAKE_INSTALL_INCLUDEDIR}/cvc4/context)
install(FILES
include/cvc4.h
include/cvc4_public.h
include/cvc4parser_public.h
DESTINATION
- ${INCLUDE_INSTALL_DIR}/cvc4)
+ ${CMAKE_INSTALL_INCLUDEDIR}/cvc4)
install(FILES
expr/array.h
expr/array_store_all.h
expr/ascription_type.h
- expr/datatype.h
expr/emptyset.h
expr/expr_iomanip.h
expr/record.h
expr/sequence.h
+ expr/symbol_manager.h
expr/symbol_table.h
expr/type.h
expr/uninterpreted_constant.h
@@ -972,7 +1143,7 @@ install(FILES
${CMAKE_CURRENT_BINARY_DIR}/expr/kind.h
${CMAKE_CURRENT_BINARY_DIR}/expr/expr_manager.h
DESTINATION
- ${INCLUDE_INSTALL_DIR}/cvc4/expr)
+ ${CMAKE_INSTALL_INCLUDEDIR}/cvc4/expr)
install(FILES
options/language.h
options/option_exception.h
@@ -980,7 +1151,7 @@ install(FILES
options/printer_modes.h
options/set_language.h
DESTINATION
- ${INCLUDE_INSTALL_DIR}/cvc4/options)
+ ${CMAKE_INSTALL_INCLUDEDIR}/cvc4/options)
install(FILES
parser/input.h
parser/parser.h
@@ -988,25 +1159,25 @@ install(FILES
parser/parser_exception.h
parser/parse_op.h
DESTINATION
- ${INCLUDE_INSTALL_DIR}/cvc4/parser)
+ ${CMAKE_INSTALL_INCLUDEDIR}/cvc4/parser)
install(FILES
DESTINATION
- ${INCLUDE_INSTALL_DIR}/cvc4/printer)
+ ${CMAKE_INSTALL_INCLUDEDIR}/cvc4/printer)
install(FILES
proof/unsat_core.h
DESTINATION
- ${INCLUDE_INSTALL_DIR}/cvc4/proof)
+ ${CMAKE_INSTALL_INCLUDEDIR}/cvc4/proof)
install(FILES
smt/command.h
smt/logic_exception.h
smt/smt_engine.h
DESTINATION
- ${INCLUDE_INSTALL_DIR}/cvc4/smt)
+ ${CMAKE_INSTALL_INCLUDEDIR}/cvc4/smt)
install(FILES
theory/logic_info.h
theory/theory_id.h
DESTINATION
- ${INCLUDE_INSTALL_DIR}/cvc4/theory)
+ ${CMAKE_INSTALL_INCLUDEDIR}/cvc4/theory)
install(FILES
util/abstract_value.h
util/bitvector.h
@@ -1019,9 +1190,10 @@ install(FILES
util/integer_cln_imp.h
util/integer_gmp_imp.h
util/maybe.h
- util/proof.h
+ util/poly_util.h
util/rational_cln_imp.h
util/rational_gmp_imp.h
+ util/real_algebraic_number_poly_imp.h
util/regexp.h
util/resource_manager.h
util/result.h
@@ -1030,11 +1202,12 @@ install(FILES
util/string.h
util/tuple.h
util/unsafe_interrupt_exception.h
- ${CMAKE_CURRENT_BINARY_DIR}/util/floatingpoint.h
${CMAKE_CURRENT_BINARY_DIR}/util/integer.h
${CMAKE_CURRENT_BINARY_DIR}/util/rational.h
+ ${CMAKE_CURRENT_BINARY_DIR}/util/real_algebraic_number.h
+ ${CMAKE_CURRENT_BINARY_DIR}/util/floatingpoint_literal_symfpu.h
DESTINATION
- ${INCLUDE_INSTALL_DIR}/cvc4/util)
+ ${CMAKE_INSTALL_INCLUDEDIR}/cvc4/util)
# Fix include paths for all public headers.
# Note: This is a temporary fix until the new C++ API is in place.
diff --git a/src/api/cvc4cpp.cpp b/src/api/cvc4cpp.cpp
index fa995a00a..9b79b5c45 100644
--- a/src/api/cvc4cpp.cpp
+++ b/src/api/cvc4cpp.cpp
@@ -2,10 +2,10 @@
/*! \file cvc4cpp.cpp
** \verbatim
** Top contributors (to current version):
- ** Aina Niemetz, Makai Mann, Andrew Reynolds
+ ** Aina Niemetz, Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -34,23 +34,29 @@
#include "api/cvc4cpp.h"
#include <cstring>
+#include <regex>
#include <sstream>
#include "base/check.h"
#include "base/configuration.h"
+#include "expr/dtype.h"
#include "expr/expr.h"
#include "expr/expr_manager.h"
#include "expr/expr_manager_scope.h"
#include "expr/kind.h"
#include "expr/metakind.h"
+#include "expr/node.h"
#include "expr/node_manager.h"
#include "expr/sequence.h"
#include "expr/type.h"
+#include "expr/type_node.h"
#include "options/main_options.h"
#include "options/options.h"
#include "options/smt_options.h"
+#include "proof/unsat_core.h"
#include "smt/model.h"
#include "smt/smt_engine.h"
+#include "smt/smt_mode.h"
#include "theory/logic_info.h"
#include "theory/theory_model.h"
#include "util/random.h"
@@ -76,6 +82,7 @@ const static std::unordered_map<Kind, CVC4::Kind, KindHashFunction> s_kinds{
{DISTINCT, CVC4::Kind::DISTINCT},
{CONSTANT, CVC4::Kind::VARIABLE},
{VARIABLE, CVC4::Kind::BOUND_VARIABLE},
+ {SEXPR, CVC4::Kind::SEXPR},
{LAMBDA, CVC4::Kind::LAMBDA},
{WITNESS, CVC4::Kind::WITNESS},
/* Boolean ------------------------------------------------------------- */
@@ -250,6 +257,23 @@ const static std::unordered_map<Kind, CVC4::Kind, KindHashFunction> s_kinds{
{IDEN, CVC4::Kind::IDEN},
{COMPREHENSION, CVC4::Kind::COMPREHENSION},
{CHOOSE, CVC4::Kind::CHOOSE},
+ {IS_SINGLETON, CVC4::Kind::IS_SINGLETON},
+ /* Bags ---------------------------------------------------------------- */
+ {UNION_MAX, CVC4::Kind::UNION_MAX},
+ {UNION_DISJOINT, CVC4::Kind::UNION_DISJOINT},
+ {INTERSECTION_MIN, CVC4::Kind::INTERSECTION_MIN},
+ {DIFFERENCE_SUBTRACT, CVC4::Kind::DIFFERENCE_SUBTRACT},
+ {DIFFERENCE_REMOVE, CVC4::Kind::DIFFERENCE_REMOVE},
+ {SUBBAG, CVC4::Kind::SUBBAG},
+ {BAG_COUNT, CVC4::Kind::BAG_COUNT},
+ {DUPLICATE_REMOVAL, CVC4::Kind::DUPLICATE_REMOVAL},
+ {MK_BAG, CVC4::Kind::MK_BAG},
+ {EMPTYBAG, CVC4::Kind::EMPTYBAG},
+ {BAG_CARD, CVC4::Kind::BAG_CARD},
+ {BAG_CHOOSE, CVC4::Kind::BAG_CHOOSE},
+ {BAG_IS_SINGLETON, CVC4::Kind::BAG_IS_SINGLETON},
+ {BAG_FROM_SET, CVC4::Kind::BAG_FROM_SET},
+ {BAG_TO_SET, CVC4::Kind::BAG_TO_SET},
/* Strings ------------------------------------------------------------- */
{STRING_CONCAT, CVC4::Kind::STRING_CONCAT},
{STRING_IN_REGEXP, CVC4::Kind::STRING_IN_REGEXP},
@@ -305,6 +329,7 @@ const static std::unordered_map<Kind, CVC4::Kind, KindHashFunction> s_kinds{
{SEQ_SUFFIX, CVC4::Kind::STRING_SUFFIX},
{CONST_SEQUENCE, CVC4::Kind::CONST_SEQUENCE},
{SEQ_UNIT, CVC4::Kind::SEQ_UNIT},
+ {SEQ_NTH, CVC4::Kind::SEQ_NTH},
/* Quantifiers --------------------------------------------------------- */
{FORALL, CVC4::Kind::FORALL},
{EXISTS, CVC4::Kind::EXISTS},
@@ -538,6 +563,23 @@ const static std::unordered_map<CVC4::Kind, Kind, CVC4::kind::KindHashFunction>
{CVC4::Kind::IDEN, IDEN},
{CVC4::Kind::COMPREHENSION, COMPREHENSION},
{CVC4::Kind::CHOOSE, CHOOSE},
+ {CVC4::Kind::IS_SINGLETON, IS_SINGLETON},
+ /* Bags ------------------------------------------------------------ */
+ {CVC4::Kind::UNION_MAX, UNION_MAX},
+ {CVC4::Kind::UNION_DISJOINT, UNION_DISJOINT},
+ {CVC4::Kind::INTERSECTION_MIN, INTERSECTION_MIN},
+ {CVC4::Kind::DIFFERENCE_SUBTRACT, DIFFERENCE_SUBTRACT},
+ {CVC4::Kind::DIFFERENCE_REMOVE, DIFFERENCE_REMOVE},
+ {CVC4::Kind::SUBBAG, SUBBAG},
+ {CVC4::Kind::BAG_COUNT, BAG_COUNT},
+ {CVC4::Kind::DUPLICATE_REMOVAL, DUPLICATE_REMOVAL},
+ {CVC4::Kind::MK_BAG, MK_BAG},
+ {CVC4::Kind::EMPTYBAG, EMPTYBAG},
+ {CVC4::Kind::BAG_CARD, BAG_CARD},
+ {CVC4::Kind::BAG_CHOOSE, BAG_CHOOSE},
+ {CVC4::Kind::BAG_IS_SINGLETON, BAG_IS_SINGLETON},
+ {CVC4::Kind::BAG_FROM_SET, BAG_FROM_SET},
+ {CVC4::Kind::BAG_TO_SET, BAG_TO_SET},
/* Strings --------------------------------------------------------- */
{CVC4::Kind::STRING_CONCAT, STRING_CONCAT},
{CVC4::Kind::STRING_IN_REGEXP, STRING_IN_REGEXP},
@@ -574,12 +616,15 @@ const static std::unordered_map<CVC4::Kind, Kind, CVC4::kind::KindHashFunction>
{CVC4::Kind::REGEXP_OPT, REGEXP_OPT},
{CVC4::Kind::REGEXP_RANGE, REGEXP_RANGE},
{CVC4::Kind::REGEXP_REPEAT, REGEXP_REPEAT},
+ {CVC4::Kind::REGEXP_REPEAT_OP, REGEXP_REPEAT},
{CVC4::Kind::REGEXP_LOOP, REGEXP_LOOP},
+ {CVC4::Kind::REGEXP_LOOP_OP, REGEXP_LOOP},
{CVC4::Kind::REGEXP_EMPTY, REGEXP_EMPTY},
{CVC4::Kind::REGEXP_SIGMA, REGEXP_SIGMA},
{CVC4::Kind::REGEXP_COMPLEMENT, REGEXP_COMPLEMENT},
{CVC4::Kind::CONST_SEQUENCE, CONST_SEQUENCE},
{CVC4::Kind::SEQ_UNIT, SEQ_UNIT},
+ {CVC4::Kind::SEQ_NTH, SEQ_NTH},
/* Quantifiers ----------------------------------------------------- */
{CVC4::Kind::FORALL, FORALL},
{CVC4::Kind::EXISTS, EXISTS},
@@ -642,7 +687,15 @@ uint32_t minArity(Kind k)
{
Assert(isDefinedKind(k));
Assert(isDefinedIntKind(extToIntKind(k)));
- return CVC4::ExprManager::minArity(extToIntKind(k));
+ uint32_t min = CVC4::ExprManager::minArity(extToIntKind(k));
+
+ // At the API level, we treat functions/constructors/selectors/testers as
+ // normal terms instead of making them part of the operator
+ if (isApplyKind(extToIntKind(k)))
+ {
+ min++;
+ }
+ return min;
}
uint32_t maxArity(Kind k)
@@ -651,9 +704,8 @@ uint32_t maxArity(Kind k)
Assert(isDefinedIntKind(extToIntKind(k)));
uint32_t max = CVC4::ExprManager::maxArity(extToIntKind(k));
- // special cases for API level
- // higher-order logic perspective at API
- // functions/constructors/selectors/testers are terms
+ // At the API level, we treat functions/constructors/selectors/testers as
+ // normal terms instead of making them part of the operator
if (isApplyKind(extToIntKind(k))
&& max != std::numeric_limits<uint32_t>::max()) // be careful not to
// overflow
@@ -710,10 +762,35 @@ class CVC4ApiExceptionStream
std::stringstream d_stream;
};
+class CVC4ApiRecoverableExceptionStream
+{
+ public:
+ CVC4ApiRecoverableExceptionStream() {}
+ /* Note: This needs to be explicitly set to 'noexcept(false)' since it is
+ * a destructor that throws an exception and in C++11 all destructors
+ * default to noexcept(true) (else this triggers a call to std::terminate). */
+ ~CVC4ApiRecoverableExceptionStream() noexcept(false)
+ {
+ if (!std::uncaught_exception())
+ {
+ throw CVC4ApiRecoverableException(d_stream.str());
+ }
+ }
+
+ std::ostream& ostream() { return d_stream; }
+
+ private:
+ std::stringstream d_stream;
+};
+
#define CVC4_API_CHECK(cond) \
CVC4_PREDICT_TRUE(cond) \
? (void)0 : OstreamVoider() & CVC4ApiExceptionStream().ostream()
+#define CVC4_API_RECOVERABLE_CHECK(cond) \
+ CVC4_PREDICT_TRUE(cond) \
+ ? (void)0 : OstreamVoider() & CVC4ApiRecoverableExceptionStream().ostream()
+
#define CVC4_API_CHECK_NOT_NULL \
CVC4_API_CHECK(!isNullHelper()) \
<< "Invalid call to '" << __PRETTY_FUNCTION__ \
@@ -765,6 +842,10 @@ class CVC4ApiExceptionStream
{
#define CVC4_API_SOLVER_TRY_CATCH_END \
} \
+ catch (const CVC4::RecoverableModalException& e) \
+ { \
+ throw CVC4ApiRecoverableException(e.getMessage()); \
+ } \
catch (const CVC4::Exception& e) { throw CVC4ApiException(e.getMessage()); } \
catch (const std::invalid_argument& e) { throw CVC4ApiException(e.what()); }
@@ -865,13 +946,26 @@ std::ostream& operator<<(std::ostream& out, const Result& r)
/* -------------------------------------------------------------------------- */
Sort::Sort(const Solver* slv, const CVC4::Type& t)
- : d_solver(slv), d_type(new CVC4::Type(t))
+ : d_solver(slv), d_type(new CVC4::TypeNode(TypeNode::fromType(t)))
+{
+}
+Sort::Sort(const Solver* slv, const CVC4::TypeNode& t)
+ : d_solver(slv), d_type(new CVC4::TypeNode(t))
{
}
-Sort::Sort() : d_solver(nullptr), d_type(new CVC4::Type()) {}
+Sort::Sort() : d_solver(nullptr), d_type(new CVC4::TypeNode()) {}
-Sort::~Sort() {}
+Sort::~Sort()
+{
+ if (d_solver != nullptr)
+ {
+ // Ensure that the correct node manager is in scope when the node is
+ // destroyed.
+ NodeManagerScope scope(d_solver->getNodeManager());
+ d_type.reset();
+ }
+}
/* Helpers */
/* -------------------------------------------------------------------------- */
@@ -916,7 +1010,7 @@ bool Sort::isDatatype() const { return d_type->isDatatype(); }
bool Sort::isParametricDatatype() const
{
if (!d_type->isDatatype()) return false;
- return DatatypeType(*d_type).isParametric();
+ return d_type->isParametricDatatype();
}
bool Sort::isConstructor() const { return d_type->isConstructor(); }
@@ -935,6 +1029,8 @@ bool Sort::isArray() const { return d_type->isArray(); }
bool Sort::isSet() const { return d_type->isSet(); }
+bool Sort::isBag() const { return d_type->isBag(); }
+
bool Sort::isSequence() const { return d_type->isSequence(); }
bool Sort::isUninterpretedSort() const { return d_type->isSort(); }
@@ -954,52 +1050,91 @@ bool Sort::isComparableTo(Sort s) const
Datatype Sort::getDatatype() const
{
+ NodeManagerScope scope(d_solver->getNodeManager());
CVC4_API_CHECK(isDatatype()) << "Expected datatype sort.";
- return Datatype(d_solver, DatatypeType(*d_type).getDatatype());
+ return Datatype(d_solver, d_type->getDType());
}
Sort Sort::instantiate(const std::vector<Sort>& params) const
{
+ NodeManagerScope scope(d_solver->getNodeManager());
CVC4_API_CHECK(isParametricDatatype() || isSortConstructor())
<< "Expected parametric datatype or sort constructor sort.";
- std::vector<Type> tparams;
- for (const Sort& s : params)
- {
- tparams.push_back(*s.d_type.get());
- }
+ std::vector<CVC4::TypeNode> tparams = sortVectorToTypeNodes(params);
if (d_type->isDatatype())
{
- return Sort(d_solver, DatatypeType(*d_type).instantiate(tparams));
+ return Sort(d_solver, d_type->instantiateParametricDatatype(tparams));
}
Assert(d_type->isSortConstructor());
- return Sort(d_solver, SortConstructorType(*d_type).instantiate(tparams));
+ return Sort(d_solver, d_solver->getNodeManager()->mkSort(*d_type, tparams));
}
-std::string Sort::toString() const { return d_type->toString(); }
+std::string Sort::toString() const
+{
+ if (d_solver != nullptr)
+ {
+ NodeManagerScope scope(d_solver->getNodeManager());
+ return d_type->toString();
+ }
+ return d_type->toString();
+}
// !!! This is only temporarily available until the parser is fully migrated
// to the new API. !!!
-CVC4::Type Sort::getType(void) const { return *d_type; }
+CVC4::Type Sort::getType(void) const
+{
+ if (d_type->isNull()) return Type();
+ NodeManagerScope scope(d_solver->getNodeManager());
+ return d_type->toType();
+}
+const CVC4::TypeNode& Sort::getTypeNode(void) const { return *d_type; }
/* Constructor sort ------------------------------------------------------- */
size_t Sort::getConstructorArity() const
{
- CVC4_API_CHECK(isConstructor()) << "Not a function sort: " << (*this);
- return ConstructorType(*d_type).getArity();
+ CVC4_API_CHECK(isConstructor()) << "Not a constructor sort: " << (*this);
+ return d_type->getNumChildren() - 1;
}
std::vector<Sort> Sort::getConstructorDomainSorts() const
{
- CVC4_API_CHECK(isConstructor()) << "Not a function sort: " << (*this);
- std::vector<CVC4::Type> types = ConstructorType(*d_type).getArgTypes();
- return typeVectorToSorts(d_solver, types);
+ CVC4_API_CHECK(isConstructor()) << "Not a constructor sort: " << (*this);
+ return typeNodeVectorToSorts(d_solver, d_type->getArgTypes());
}
Sort Sort::getConstructorCodomainSort() const
{
- CVC4_API_CHECK(isConstructor()) << "Not a function sort: " << (*this);
- return Sort(d_solver, ConstructorType(*d_type).getRangeType());
+ CVC4_API_CHECK(isConstructor()) << "Not a constructor sort: " << (*this);
+ return Sort(d_solver, d_type->getConstructorRangeType());
+}
+
+/* Selector sort ------------------------------------------------------- */
+
+Sort Sort::getSelectorDomainSort() const
+{
+ CVC4_API_CHECK(isSelector()) << "Not a selector sort: " << (*this);
+ return Sort(d_solver, d_type->getSelectorDomainType());
+}
+
+Sort Sort::getSelectorCodomainSort() const
+{
+ CVC4_API_CHECK(isSelector()) << "Not a selector sort: " << (*this);
+ return Sort(d_solver, d_type->getSelectorRangeType());
+}
+
+/* Tester sort ------------------------------------------------------- */
+
+Sort Sort::getTesterDomainSort() const
+{
+ CVC4_API_CHECK(isTester()) << "Not a tester sort: " << (*this);
+ return Sort(d_solver, d_type->getTesterDomainType());
+}
+
+Sort Sort::getTesterCodomainSort() const
+{
+ CVC4_API_CHECK(isTester()) << "Not a tester sort: " << (*this);
+ return d_solver->getBooleanSort();
}
/* Function sort ------------------------------------------------------- */
@@ -1007,20 +1142,19 @@ Sort Sort::getConstructorCodomainSort() const
size_t Sort::getFunctionArity() const
{
CVC4_API_CHECK(isFunction()) << "Not a function sort: " << (*this);
- return FunctionType(*d_type).getArity();
+ return d_type->getNumChildren() - 1;
}
std::vector<Sort> Sort::getFunctionDomainSorts() const
{
CVC4_API_CHECK(isFunction()) << "Not a function sort: " << (*this);
- std::vector<CVC4::Type> types = FunctionType(*d_type).getArgTypes();
- return typeVectorToSorts(d_solver, types);
+ return typeNodeVectorToSorts(d_solver, d_type->getArgTypes());
}
Sort Sort::getFunctionCodomainSort() const
{
CVC4_API_CHECK(isFunction()) << "Not a function sort" << (*this);
- return Sort(d_solver, FunctionType(*d_type).getRangeType());
+ return Sort(d_solver, d_type->getRangeType());
}
/* Array sort ---------------------------------------------------------- */
@@ -1028,13 +1162,13 @@ Sort Sort::getFunctionCodomainSort() const
Sort Sort::getArrayIndexSort() const
{
CVC4_API_CHECK(isArray()) << "Not an array sort.";
- return Sort(d_solver, ArrayType(*d_type).getIndexType());
+ return Sort(d_solver, d_type->getArrayIndexType());
}
Sort Sort::getArrayElementSort() const
{
CVC4_API_CHECK(isArray()) << "Not an array sort.";
- return Sort(d_solver, ArrayType(*d_type).getConstituentType());
+ return Sort(d_solver, d_type->getArrayConstituentType());
}
/* Set sort ------------------------------------------------------------ */
@@ -1042,15 +1176,23 @@ Sort Sort::getArrayElementSort() const
Sort Sort::getSetElementSort() const
{
CVC4_API_CHECK(isSet()) << "Not a set sort.";
- return Sort(d_solver, SetType(*d_type).getElementType());
+ return Sort(d_solver, d_type->getSetElementType());
}
-/* Set sort ------------------------------------------------------------ */
+/* Bag sort ------------------------------------------------------------ */
+
+Sort Sort::getBagElementSort() const
+{
+ CVC4_API_CHECK(isBag()) << "Not a bag sort.";
+ return Sort(d_solver, d_type->getBagElementType());
+}
+
+/* Sequence sort ------------------------------------------------------- */
Sort Sort::getSequenceElementSort() const
{
CVC4_API_CHECK(isSequence()) << "Not a sequence sort.";
- return Sort(d_solver, SequenceType(*d_type).getElementType());
+ return Sort(d_solver, d_type->getSequenceElementType());
}
/* Uninterpreted sort -------------------------------------------------- */
@@ -1058,20 +1200,28 @@ Sort Sort::getSequenceElementSort() const
std::string Sort::getUninterpretedSortName() const
{
CVC4_API_CHECK(isUninterpretedSort()) << "Not an uninterpreted sort.";
- return SortType(*d_type).getName();
+ return d_type->getName();
}
bool Sort::isUninterpretedSortParameterized() const
{
CVC4_API_CHECK(isUninterpretedSort()) << "Not an uninterpreted sort.";
- return SortType(*d_type).isParameterized();
+ // This method is not implemented in the NodeManager, since whether a
+ // uninterpreted sort is parametrized is irrelevant for solving.
+ return d_type->getNumChildren() > 0;
}
std::vector<Sort> Sort::getUninterpretedSortParamSorts() const
{
CVC4_API_CHECK(isUninterpretedSort()) << "Not an uninterpreted sort.";
- std::vector<CVC4::Type> types = SortType(*d_type).getParamTypes();
- return typeVectorToSorts(d_solver, types);
+ // This method is not implemented in the NodeManager, since whether a
+ // uninterpreted sort is parametrized is irrelevant for solving.
+ std::vector<TypeNode> params;
+ for (size_t i = 0, nchildren = d_type->getNumChildren(); i < nchildren; i++)
+ {
+ params.push_back((*d_type)[i]);
+ }
+ return typeNodeVectorToSorts(d_solver, params);
}
/* Sort constructor sort ----------------------------------------------- */
@@ -1079,13 +1229,13 @@ std::vector<Sort> Sort::getUninterpretedSortParamSorts() const
std::string Sort::getSortConstructorName() const
{
CVC4_API_CHECK(isSortConstructor()) << "Not a sort constructor sort.";
- return SortConstructorType(*d_type).getName();
+ return d_type->getName();
}
size_t Sort::getSortConstructorArity() const
{
CVC4_API_CHECK(isSortConstructor()) << "Not a sort constructor sort.";
- return SortConstructorType(*d_type).getArity();
+ return d_type->getSortConstructorArity();
}
/* Bit-vector sort ----------------------------------------------------- */
@@ -1093,7 +1243,7 @@ size_t Sort::getSortConstructorArity() const
uint32_t Sort::getBVSize() const
{
CVC4_API_CHECK(isBitVector()) << "Not a bit-vector sort.";
- return BitVectorType(*d_type).getSize();
+ return d_type->getBitVectorSize();
}
/* Floating-point sort ------------------------------------------------- */
@@ -1101,13 +1251,13 @@ uint32_t Sort::getBVSize() const
uint32_t Sort::getFPExponentSize() const
{
CVC4_API_CHECK(isFloatingPoint()) << "Not a floating-point sort.";
- return FloatingPointType(*d_type).getExponentSize();
+ return d_type->getFloatingPointExponentSize();
}
uint32_t Sort::getFPSignificandSize() const
{
CVC4_API_CHECK(isFloatingPoint()) << "Not a floating-point sort.";
- return FloatingPointType(*d_type).getSignificandSize();
+ return d_type->getFloatingPointSignificandSize();
}
/* Datatype sort ------------------------------------------------------- */
@@ -1115,14 +1265,14 @@ uint32_t Sort::getFPSignificandSize() const
std::vector<Sort> Sort::getDatatypeParamSorts() const
{
CVC4_API_CHECK(isParametricDatatype()) << "Not a parametric datatype sort.";
- std::vector<CVC4::Type> types = DatatypeType(*d_type).getParamTypes();
- return typeVectorToSorts(d_solver, types);
+ std::vector<CVC4::TypeNode> typeNodes = d_type->getParamTypes();
+ return typeNodeVectorToSorts(d_solver, typeNodes);
}
size_t Sort::getDatatypeArity() const
{
CVC4_API_CHECK(isDatatype()) << "Not a datatype sort.";
- return DatatypeType(*d_type).getArity();
+ return d_type->getNumChildren() - 1;
}
/* Tuple sort ---------------------------------------------------------- */
@@ -1130,14 +1280,14 @@ size_t Sort::getDatatypeArity() const
size_t Sort::getTupleLength() const
{
CVC4_API_CHECK(isTuple()) << "Not a tuple sort.";
- return DatatypeType(*d_type).getTupleLength();
+ return d_type->getTupleLength();
}
std::vector<Sort> Sort::getTupleSorts() const
{
CVC4_API_CHECK(isTuple()) << "Not a tuple sort.";
- std::vector<CVC4::Type> types = DatatypeType(*d_type).getTupleTypes();
- return typeVectorToSorts(d_solver, types);
+ std::vector<CVC4::TypeNode> typeNodes = d_type->getTupleTypes();
+ return typeNodeVectorToSorts(d_solver, typeNodes);
}
/* --------------------------------------------------------------------- */
@@ -1150,26 +1300,40 @@ std::ostream& operator<<(std::ostream& out, const Sort& s)
size_t SortHashFunction::operator()(const Sort& s) const
{
- return TypeHashFunction()(*s.d_type);
+ return TypeNodeHashFunction()(*s.d_type);
}
/* -------------------------------------------------------------------------- */
/* Op */
/* -------------------------------------------------------------------------- */
-Op::Op() : d_solver(nullptr), d_kind(NULL_EXPR), d_expr(new CVC4::Expr()) {}
+Op::Op() : d_solver(nullptr), d_kind(NULL_EXPR), d_node(new CVC4::Node()) {}
Op::Op(const Solver* slv, const Kind k)
- : d_solver(slv), d_kind(k), d_expr(new CVC4::Expr())
+ : d_solver(slv), d_kind(k), d_node(new CVC4::Node())
{
}
Op::Op(const Solver* slv, const Kind k, const CVC4::Expr& e)
- : d_solver(slv), d_kind(k), d_expr(new CVC4::Expr(e))
+ : d_solver(slv), d_kind(k), d_node(new CVC4::Node(Node::fromExpr(e)))
{
}
-Op::~Op() {}
+Op::Op(const Solver* slv, const Kind k, const CVC4::Node& n)
+ : d_solver(slv), d_kind(k), d_node(new CVC4::Node(n))
+{
+}
+
+Op::~Op()
+{
+ if (d_solver != nullptr)
+ {
+ // Ensure that the correct node manager is in scope when the type node is
+ // destroyed.
+ NodeManagerScope scope(d_solver->getNodeManager());
+ d_node.reset();
+ }
+}
/* Helpers */
/* -------------------------------------------------------------------------- */
@@ -1179,23 +1343,23 @@ Op::~Op() {}
bool Op::isNullHelper() const
{
- return (d_expr->isNull() && (d_kind == NULL_EXPR));
+ return (d_node->isNull() && (d_kind == NULL_EXPR));
}
-bool Op::isIndexedHelper() const { return !d_expr->isNull(); }
+bool Op::isIndexedHelper() const { return !d_node->isNull(); }
/* Public methods */
bool Op::operator==(const Op& t) const
{
- if (d_expr->isNull() && t.d_expr->isNull())
+ if (d_node->isNull() && t.d_node->isNull())
{
return (d_kind == t.d_kind);
}
- else if (d_expr->isNull() || t.d_expr->isNull())
+ else if (d_node->isNull() || t.d_node->isNull())
{
return false;
}
- return (d_kind == t.d_kind) && (*d_expr == *t.d_expr);
+ return (d_kind == t.d_kind) && (*d_node == *t.d_node);
}
bool Op::operator!=(const Op& t) const { return !(*this == t); }
@@ -1214,22 +1378,22 @@ template <>
std::string Op::getIndices() const
{
CVC4_API_CHECK_NOT_NULL;
- CVC4_API_CHECK(!d_expr->isNull())
+ CVC4_API_CHECK(!d_node->isNull())
<< "Expecting a non-null internal expression. This Op is not indexed.";
std::string i;
- Kind k = intToExtKind(d_expr->getKind());
+ Kind k = intToExtKind(d_node->getKind());
if (k == DIVISIBLE)
{
// DIVISIBLE returns a string index to support
// arbitrary precision integers
- CVC4::Integer _int = d_expr->getConst<Divisible>().k;
+ CVC4::Integer _int = d_node->getConst<Divisible>().k;
i = _int.toString();
}
else if (k == RECORD_UPDATE)
{
- i = d_expr->getConst<RecordUpdate>().getField();
+ i = d_node->getConst<RecordUpdate>().getField();
}
else
{
@@ -1244,37 +1408,40 @@ template <>
uint32_t Op::getIndices() const
{
CVC4_API_CHECK_NOT_NULL;
- CVC4_API_CHECK(!d_expr->isNull())
+ CVC4_API_CHECK(!d_node->isNull())
<< "Expecting a non-null internal expression. This Op is not indexed.";
uint32_t i = 0;
- Kind k = intToExtKind(d_expr->getKind());
+ Kind k = intToExtKind(d_node->getKind());
switch (k)
{
case BITVECTOR_REPEAT:
- i = d_expr->getConst<BitVectorRepeat>().d_repeatAmount;
+ i = d_node->getConst<BitVectorRepeat>().d_repeatAmount;
break;
case BITVECTOR_ZERO_EXTEND:
- i = d_expr->getConst<BitVectorZeroExtend>().d_zeroExtendAmount;
+ i = d_node->getConst<BitVectorZeroExtend>().d_zeroExtendAmount;
break;
case BITVECTOR_SIGN_EXTEND:
- i = d_expr->getConst<BitVectorSignExtend>().d_signExtendAmount;
+ i = d_node->getConst<BitVectorSignExtend>().d_signExtendAmount;
break;
case BITVECTOR_ROTATE_LEFT:
- i = d_expr->getConst<BitVectorRotateLeft>().d_rotateLeftAmount;
+ i = d_node->getConst<BitVectorRotateLeft>().d_rotateLeftAmount;
break;
case BITVECTOR_ROTATE_RIGHT:
- i = d_expr->getConst<BitVectorRotateRight>().d_rotateRightAmount;
+ i = d_node->getConst<BitVectorRotateRight>().d_rotateRightAmount;
break;
- case INT_TO_BITVECTOR: i = d_expr->getConst<IntToBitVector>().d_size; break;
- case IAND: i = d_expr->getConst<IntAnd>().d_size; break;
+ case INT_TO_BITVECTOR: i = d_node->getConst<IntToBitVector>().d_size; break;
+ case IAND: i = d_node->getConst<IntAnd>().d_size; break;
case FLOATINGPOINT_TO_UBV:
- i = d_expr->getConst<FloatingPointToUBV>().bvs.d_size;
+ i = d_node->getConst<FloatingPointToUBV>().d_bv_size.d_size;
break;
case FLOATINGPOINT_TO_SBV:
- i = d_expr->getConst<FloatingPointToSBV>().bvs.d_size;
+ i = d_node->getConst<FloatingPointToSBV>().d_bv_size.d_size;
+ break;
+ case TUPLE_UPDATE: i = d_node->getConst<TupleUpdate>().getIndex(); break;
+ case REGEXP_REPEAT:
+ i = d_node->getConst<RegExpRepeat>().d_repeatAmount;
break;
- case TUPLE_UPDATE: i = d_expr->getConst<TupleUpdate>().getIndex(); break;
default:
CVC4ApiExceptionStream().ostream() << "Can't get uint32_t index from"
<< " kind " << kindToString(k);
@@ -1286,52 +1453,63 @@ template <>
std::pair<uint32_t, uint32_t> Op::getIndices() const
{
CVC4_API_CHECK_NOT_NULL;
- CVC4_API_CHECK(!d_expr->isNull())
+ CVC4_API_CHECK(!d_node->isNull())
<< "Expecting a non-null internal expression. This Op is not indexed.";
std::pair<uint32_t, uint32_t> indices;
- Kind k = intToExtKind(d_expr->getKind());
+ Kind k = intToExtKind(d_node->getKind());
// using if/else instead of case statement because want local variables
if (k == BITVECTOR_EXTRACT)
{
- CVC4::BitVectorExtract ext = d_expr->getConst<BitVectorExtract>();
+ CVC4::BitVectorExtract ext = d_node->getConst<BitVectorExtract>();
indices = std::make_pair(ext.d_high, ext.d_low);
}
else if (k == FLOATINGPOINT_TO_FP_IEEE_BITVECTOR)
{
CVC4::FloatingPointToFPIEEEBitVector ext =
- d_expr->getConst<FloatingPointToFPIEEEBitVector>();
- indices = std::make_pair(ext.t.exponent(), ext.t.significand());
+ d_node->getConst<FloatingPointToFPIEEEBitVector>();
+ indices = std::make_pair(ext.d_fp_size.exponentWidth(),
+ ext.d_fp_size.significandWidth());
}
else if (k == FLOATINGPOINT_TO_FP_FLOATINGPOINT)
{
CVC4::FloatingPointToFPFloatingPoint ext =
- d_expr->getConst<FloatingPointToFPFloatingPoint>();
- indices = std::make_pair(ext.t.exponent(), ext.t.significand());
+ d_node->getConst<FloatingPointToFPFloatingPoint>();
+ indices = std::make_pair(ext.d_fp_size.exponentWidth(),
+ ext.d_fp_size.significandWidth());
}
else if (k == FLOATINGPOINT_TO_FP_REAL)
{
- CVC4::FloatingPointToFPReal ext = d_expr->getConst<FloatingPointToFPReal>();
- indices = std::make_pair(ext.t.exponent(), ext.t.significand());
+ CVC4::FloatingPointToFPReal ext = d_node->getConst<FloatingPointToFPReal>();
+ indices = std::make_pair(ext.d_fp_size.exponentWidth(),
+ ext.d_fp_size.significandWidth());
}
else if (k == FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR)
{
CVC4::FloatingPointToFPSignedBitVector ext =
- d_expr->getConst<FloatingPointToFPSignedBitVector>();
- indices = std::make_pair(ext.t.exponent(), ext.t.significand());
+ d_node->getConst<FloatingPointToFPSignedBitVector>();
+ indices = std::make_pair(ext.d_fp_size.exponentWidth(),
+ ext.d_fp_size.significandWidth());
}
else if (k == FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR)
{
CVC4::FloatingPointToFPUnsignedBitVector ext =
- d_expr->getConst<FloatingPointToFPUnsignedBitVector>();
- indices = std::make_pair(ext.t.exponent(), ext.t.significand());
+ d_node->getConst<FloatingPointToFPUnsignedBitVector>();
+ indices = std::make_pair(ext.d_fp_size.exponentWidth(),
+ ext.d_fp_size.significandWidth());
}
else if (k == FLOATINGPOINT_TO_FP_GENERIC)
{
CVC4::FloatingPointToFPGeneric ext =
- d_expr->getConst<FloatingPointToFPGeneric>();
- indices = std::make_pair(ext.t.exponent(), ext.t.significand());
+ d_node->getConst<FloatingPointToFPGeneric>();
+ indices = std::make_pair(ext.d_fp_size.exponentWidth(),
+ ext.d_fp_size.significandWidth());
+ }
+ else if (k == REGEXP_LOOP)
+ {
+ CVC4::RegExpLoop ext = d_node->getConst<RegExpLoop>();
+ indices = std::make_pair(ext.d_loopMinOcc, ext.d_loopMaxOcc);
}
else
{
@@ -1344,21 +1522,31 @@ std::pair<uint32_t, uint32_t> Op::getIndices() const
std::string Op::toString() const
{
CVC4_API_CHECK_NOT_NULL;
- if (d_expr->isNull())
+ if (d_node->isNull())
{
return kindToString(d_kind);
}
else
{
- CVC4_API_CHECK(!d_expr->isNull())
+ CVC4_API_CHECK(!d_node->isNull())
<< "Expecting a non-null internal expression";
- return d_expr->toString();
+ if (d_solver != nullptr)
+ {
+ NodeManagerScope scope(d_solver->getNodeManager());
+ return d_node->toString();
+ }
+ return d_node->toString();
}
}
// !!! This is only temporarily available until the parser is fully migrated
// to the new API. !!!
-CVC4::Expr Op::getExpr(void) const { return *d_expr; }
+CVC4::Expr Op::getExpr(void) const
+{
+ if (d_node->isNull()) return Expr();
+ NodeManagerScope scope(d_solver->getNodeManager());
+ return d_node->toExpr();
+}
std::ostream& operator<<(std::ostream& out, const Op& t)
{
@@ -1370,7 +1558,7 @@ size_t OpHashFunction::operator()(const Op& t) const
{
if (t.isIndexedHelper())
{
- return ExprHashFunction()(*t.d_expr);
+ return ExprHashFunction()(t.d_node->toExpr());
}
else
{
@@ -1382,19 +1570,37 @@ size_t OpHashFunction::operator()(const Op& t) const
/* Term */
/* -------------------------------------------------------------------------- */
-Term::Term() : d_solver(nullptr), d_expr(new CVC4::Expr()) {}
+Term::Term() : d_solver(nullptr), d_node(new CVC4::Node()) {}
-Term::Term(const Solver* slv, const CVC4::Expr& e)
- : d_solver(slv), d_expr(new CVC4::Expr(e))
+Term::Term(const Solver* slv, const CVC4::Expr& e) : d_solver(slv)
{
+ // Ensure that we create the node in the correct node manager.
+ NodeManagerScope scope(d_solver->getNodeManager());
+ d_node.reset(new CVC4::Node(e));
}
-Term::~Term() {}
+Term::Term(const Solver* slv, const CVC4::Node& n) : d_solver(slv)
+{
+ // Ensure that we create the node in the correct node manager.
+ NodeManagerScope scope(d_solver->getNodeManager());
+ d_node.reset(new CVC4::Node(n));
+}
+
+Term::~Term()
+{
+ if (d_solver != nullptr)
+ {
+ // Ensure that the correct node manager is in scope when the node is
+ // destroyed.
+ NodeManagerScope scope(d_solver->getNodeManager());
+ d_node.reset();
+ }
+}
bool Term::isNullHelper() const
{
/* Split out to avoid nested API calls (problematic with API tracing). */
- return d_expr->isNull();
+ return d_node->isNull();
}
Kind Term::getKindHelper() const
@@ -1403,9 +1609,9 @@ Kind Term::getKindHelper() const
// (string) versions back to sequence. All operators where this is
// necessary are such that their first child is of sequence type, which
// we check here.
- if (getNumChildren() > 0 && (*this)[0].getSort().isSequence())
+ if (d_node->getNumChildren() > 0 && (*d_node)[0].getType().isSequence())
{
- switch (d_expr->getKind())
+ switch (d_node->getKind())
{
case CVC4::Kind::STRING_CONCAT: return SEQ_CONCAT;
case CVC4::Kind::STRING_LENGTH: return SEQ_LENGTH;
@@ -1424,56 +1630,78 @@ Kind Term::getKindHelper() const
break;
}
}
+ // Notice that kinds like APPLY_TYPE_ASCRIPTION will be converted to
+ // INTERNAL_KIND.
+ if(isCastedReal())
+ {
+ return CONST_RATIONAL;
+ }
+ return intToExtKind(d_node->getKind());
+}
- return intToExtKind(d_expr->getKind());
+bool Term::isCastedReal() const
+{
+ if(d_node->getKind() == kind::CAST_TO_REAL)
+ {
+ return (*d_node)[0].isConst() && (*d_node)[0].getType().isInteger();
+ }
+ return false;
}
-bool Term::operator==(const Term& t) const { return *d_expr == *t.d_expr; }
+bool Term::operator==(const Term& t) const { return *d_node == *t.d_node; }
-bool Term::operator!=(const Term& t) const { return *d_expr != *t.d_expr; }
+bool Term::operator!=(const Term& t) const { return *d_node != *t.d_node; }
-bool Term::operator<(const Term& t) const { return *d_expr < *t.d_expr; }
+bool Term::operator<(const Term& t) const { return *d_node < *t.d_node; }
-bool Term::operator>(const Term& t) const { return *d_expr > *t.d_expr; }
+bool Term::operator>(const Term& t) const { return *d_node > *t.d_node; }
-bool Term::operator<=(const Term& t) const { return *d_expr <= *t.d_expr; }
+bool Term::operator<=(const Term& t) const { return *d_node <= *t.d_node; }
-bool Term::operator>=(const Term& t) const { return *d_expr >= *t.d_expr; }
+bool Term::operator>=(const Term& t) const { return *d_node >= *t.d_node; }
size_t Term::getNumChildren() const
{
CVC4_API_CHECK_NOT_NULL;
// special case for apply kinds
- if (isApplyKind(d_expr->getKind()))
+ if (isApplyKind(d_node->getKind()))
+ {
+ return d_node->getNumChildren() + 1;
+ }
+ if(isCastedReal())
{
- return d_expr->getNumChildren() + 1;
+ return 0;
}
- return d_expr->getNumChildren();
+ return d_node->getNumChildren();
}
Term Term::operator[](size_t index) const
{
CVC4_API_CHECK_NOT_NULL;
+
+ // check the index within the number of children
+ CVC4_API_CHECK(index < getNumChildren()) << "index out of bound";
+
// special cases for apply kinds
- if (isApplyKind(d_expr->getKind()))
+ if (isApplyKind(d_node->getKind()))
{
- CVC4_API_CHECK(d_expr->hasOperator())
+ CVC4_API_CHECK(d_node->hasOperator())
<< "Expected apply kind to have operator when accessing child of Term";
if (index == 0)
{
// return the operator
- return Term(d_solver, d_expr->getOperator());
+ return Term(d_solver, d_node->getOperator().toExpr());
}
// otherwise we are looking up child at (index-1)
index--;
}
- return Term(d_solver, (*d_expr)[index]);
+ return Term(d_solver, (*d_node)[index].toExpr());
}
uint64_t Term::getId() const
{
CVC4_API_CHECK_NOT_NULL;
- return d_expr->getId();
+ return d_node->getId();
}
Kind Term::getKind() const
@@ -1485,7 +1713,8 @@ Kind Term::getKind() const
Sort Term::getSort() const
{
CVC4_API_CHECK_NOT_NULL;
- return Sort(d_solver, d_expr->getType());
+ NodeManagerScope scope(d_solver->getNodeManager());
+ return Sort(d_solver, d_node->getType());
}
Term Term::substitute(Term e, Term replacement) const
@@ -1497,7 +1726,8 @@ Term Term::substitute(Term e, Term replacement) const
<< "Expected non-null term as replacement in substitute";
CVC4_API_CHECK(e.getSort().isComparableTo(replacement.getSort()))
<< "Expecting terms of comparable sort in substitute";
- return Term(d_solver, d_expr->substitute(e.getExpr(), replacement.getExpr()));
+ return Term(d_solver,
+ d_node->substitute(TNode(*e.d_node), TNode(*replacement.d_node)));
}
Term Term::substitute(const std::vector<Term> es,
@@ -1515,21 +1745,26 @@ Term Term::substitute(const std::vector<Term> es,
CVC4_API_CHECK(es[i].getSort().isComparableTo(replacements[i].getSort()))
<< "Expecting terms of comparable sort in substitute";
}
+
+ std::vector<Node> nodes = termVectorToNodes(es);
+ std::vector<Node> nodeReplacements = termVectorToNodes(replacements);
return Term(d_solver,
- d_expr->substitute(termVectorToExprs(es),
- termVectorToExprs(replacements)));
+ d_node->substitute(nodes.begin(),
+ nodes.end(),
+ nodeReplacements.begin(),
+ nodeReplacements.end()));
}
bool Term::hasOp() const
{
CVC4_API_CHECK_NOT_NULL;
- return d_expr->hasOperator();
+ return d_node->hasOperator();
}
Op Term::getOp() const
{
CVC4_API_CHECK_NOT_NULL;
- CVC4_API_CHECK(d_expr->hasOperator())
+ CVC4_API_CHECK(d_node->hasOperator())
<< "Expecting Term to have an Op when calling getOp()";
// special cases for parameterized operators that are not indexed operators
@@ -1537,51 +1772,45 @@ Op Term::getOp() const
// indexed operators are stored in Ops
// whereas functions and datatype operators are terms, and the Op
// is one of the APPLY_* kinds
- if (isApplyKind(d_expr->getKind()))
+ if (isApplyKind(d_node->getKind()))
{
- return Op(d_solver, intToExtKind(d_expr->getKind()));
+ return Op(d_solver, intToExtKind(d_node->getKind()));
}
- else if (d_expr->isParameterized())
+ else if (d_node->getMetaKind() == kind::metakind::PARAMETERIZED)
{
// it's an indexed operator
// so we should return the indexed op
- CVC4::Expr op = d_expr->getOperator();
- return Op(d_solver, intToExtKind(d_expr->getKind()), op);
+ CVC4::Node op = d_node->getOperator();
+ return Op(d_solver, intToExtKind(d_node->getKind()), op);
}
// Notice this is the only case where getKindHelper is used, since the
- // cases above do have special cases for intToExtKind.
+ // cases above do not have special cases for intToExtKind.
return Op(d_solver, getKindHelper());
}
bool Term::isNull() const { return isNullHelper(); }
-bool Term::isConst() const
-{
- CVC4_API_CHECK_NOT_NULL;
- return d_expr->isConst();
-}
-
Term Term::getConstArrayBase() const
{
CVC4::ExprManagerScope exmgrs(*(d_solver->getExprManager()));
CVC4_API_CHECK_NOT_NULL;
// CONST_ARRAY kind maps to STORE_ALL internal kind
- CVC4_API_CHECK(d_expr->getKind() == CVC4::Kind::STORE_ALL)
+ CVC4_API_CHECK(d_node->getKind() == CVC4::Kind::STORE_ALL)
<< "Expecting a CONST_ARRAY Term when calling getConstArrayBase()";
- return Term(d_solver, d_expr->getConst<ArrayStoreAll>().getValue().toExpr());
+ return Term(d_solver, d_node->getConst<ArrayStoreAll>().getValue());
}
std::vector<Term> Term::getConstSequenceElements() const
{
CVC4_API_CHECK_NOT_NULL;
- CVC4_API_CHECK(d_expr->getKind() == CVC4::Kind::CONST_SEQUENCE)
+ CVC4_API_CHECK(d_node->getKind() == CVC4::Kind::CONST_SEQUENCE)
<< "Expecting a CONST_SEQUENCE Term when calling "
"getConstSequenceElements()";
- const std::vector<Node>& elems = d_expr->getConst<Sequence>().getVec();
+ const std::vector<Node>& elems = d_node->getConst<Sequence>().getVec();
std::vector<Term> terms;
for (const Node& t : elems)
{
- terms.push_back(Term(d_solver, t.toExpr()));
+ terms.push_back(Term(d_solver, t));
}
return terms;
}
@@ -1591,11 +1820,11 @@ Term Term::notTerm() const
CVC4_API_CHECK_NOT_NULL;
try
{
- Expr res = d_expr->notExpr();
+ Node res = d_node->notNode();
(void)res.getType(true); /* kick off type checking */
return Term(d_solver, res);
}
- catch (const CVC4::TypeCheckingException& e)
+ catch (const CVC4::TypeCheckingExceptionPrivate& e)
{
throw CVC4ApiException(e.getMessage());
}
@@ -1607,11 +1836,11 @@ Term Term::andTerm(const Term& t) const
CVC4_API_ARG_CHECK_NOT_NULL(t);
try
{
- Expr res = d_expr->andExpr(*t.d_expr);
+ Node res = d_node->andNode(*t.d_node);
(void)res.getType(true); /* kick off type checking */
return Term(d_solver, res);
}
- catch (const CVC4::TypeCheckingException& e)
+ catch (const CVC4::TypeCheckingExceptionPrivate& e)
{
throw CVC4ApiException(e.getMessage());
}
@@ -1623,11 +1852,11 @@ Term Term::orTerm(const Term& t) const
CVC4_API_ARG_CHECK_NOT_NULL(t);
try
{
- Expr res = d_expr->orExpr(*t.d_expr);
+ Node res = d_node->orNode(*t.d_node);
(void)res.getType(true); /* kick off type checking */
return Term(d_solver, res);
}
- catch (const CVC4::TypeCheckingException& e)
+ catch (const CVC4::TypeCheckingExceptionPrivate& e)
{
throw CVC4ApiException(e.getMessage());
}
@@ -1639,11 +1868,11 @@ Term Term::xorTerm(const Term& t) const
CVC4_API_ARG_CHECK_NOT_NULL(t);
try
{
- Expr res = d_expr->xorExpr(*t.d_expr);
+ Node res = d_node->xorNode(*t.d_node);
(void)res.getType(true); /* kick off type checking */
return Term(d_solver, res);
}
- catch (const CVC4::TypeCheckingException& e)
+ catch (const CVC4::TypeCheckingExceptionPrivate& e)
{
throw CVC4ApiException(e.getMessage());
}
@@ -1655,11 +1884,11 @@ Term Term::eqTerm(const Term& t) const
CVC4_API_ARG_CHECK_NOT_NULL(t);
try
{
- Expr res = d_expr->eqExpr(*t.d_expr);
+ Node res = d_node->eqNode(*t.d_node);
(void)res.getType(true); /* kick off type checking */
return Term(d_solver, res);
}
- catch (const CVC4::TypeCheckingException& e)
+ catch (const CVC4::TypeCheckingExceptionPrivate& e)
{
throw CVC4ApiException(e.getMessage());
}
@@ -1671,11 +1900,11 @@ Term Term::impTerm(const Term& t) const
CVC4_API_ARG_CHECK_NOT_NULL(t);
try
{
- Expr res = d_expr->impExpr(*t.d_expr);
+ Node res = d_node->impNode(*t.d_node);
(void)res.getType(true); /* kick off type checking */
return Term(d_solver, res);
}
- catch (const CVC4::TypeCheckingException& e)
+ catch (const CVC4::TypeCheckingExceptionPrivate& e)
{
throw CVC4ApiException(e.getMessage());
}
@@ -1688,37 +1917,45 @@ Term Term::iteTerm(const Term& then_t, const Term& else_t) const
CVC4_API_ARG_CHECK_NOT_NULL(else_t);
try
{
- Expr res = d_expr->iteExpr(*then_t.d_expr, *else_t.d_expr);
+ Node res = d_node->iteNode(*then_t.d_node, *else_t.d_node);
(void)res.getType(true); /* kick off type checking */
return Term(d_solver, res);
}
- catch (const CVC4::TypeCheckingException& e)
+ catch (const CVC4::TypeCheckingExceptionPrivate& e)
{
throw CVC4ApiException(e.getMessage());
}
}
-std::string Term::toString() const { return d_expr->toString(); }
+std::string Term::toString() const
+{
+ if (d_solver != nullptr)
+ {
+ NodeManagerScope scope(d_solver->getNodeManager());
+ return d_node->toString();
+ }
+ return d_node->toString();
+}
Term::const_iterator::const_iterator()
- : d_solver(nullptr), d_orig_expr(nullptr), d_pos(0)
+ : d_solver(nullptr), d_origNode(nullptr), d_pos(0)
{
}
Term::const_iterator::const_iterator(const Solver* slv,
- const std::shared_ptr<CVC4::Expr>& e,
+ const std::shared_ptr<CVC4::Node>& n,
uint32_t p)
- : d_solver(slv), d_orig_expr(e), d_pos(p)
+ : d_solver(slv), d_origNode(n), d_pos(p)
{
}
Term::const_iterator::const_iterator(const const_iterator& it)
- : d_solver(nullptr), d_orig_expr(nullptr)
+ : d_solver(nullptr), d_origNode(nullptr)
{
- if (it.d_orig_expr != nullptr)
+ if (it.d_origNode != nullptr)
{
d_solver = it.d_solver;
- d_orig_expr = it.d_orig_expr;
+ d_origNode = it.d_origNode;
d_pos = it.d_pos;
}
}
@@ -1726,18 +1963,18 @@ Term::const_iterator::const_iterator(const const_iterator& it)
Term::const_iterator& Term::const_iterator::operator=(const const_iterator& it)
{
d_solver = it.d_solver;
- d_orig_expr = it.d_orig_expr;
+ d_origNode = it.d_origNode;
d_pos = it.d_pos;
return *this;
}
bool Term::const_iterator::operator==(const const_iterator& it) const
{
- if (d_orig_expr == nullptr || it.d_orig_expr == nullptr)
+ if (d_origNode == nullptr || it.d_origNode == nullptr)
{
return false;
}
- return (d_solver == it.d_solver && *d_orig_expr == *it.d_orig_expr)
+ return (d_solver == it.d_solver && *d_origNode == *it.d_origNode)
&& (d_pos == it.d_pos);
}
@@ -1748,14 +1985,14 @@ bool Term::const_iterator::operator!=(const const_iterator& it) const
Term::const_iterator& Term::const_iterator::operator++()
{
- Assert(d_orig_expr != nullptr);
+ Assert(d_origNode != nullptr);
++d_pos;
return *this;
}
Term::const_iterator Term::const_iterator::operator++(int)
{
- Assert(d_orig_expr != nullptr);
+ Assert(d_origNode != nullptr);
const_iterator it = *this;
++d_pos;
return it;
@@ -1763,14 +2000,14 @@ Term::const_iterator Term::const_iterator::operator++(int)
Term Term::const_iterator::operator*() const
{
- Assert(d_orig_expr != nullptr);
+ Assert(d_origNode != nullptr);
// this term has an extra child (mismatch between API and internal structure)
// the extra child will be the first child
- bool extra_child = isApplyKind(d_orig_expr->getKind());
+ bool extra_child = isApplyKind(d_origNode->getKind());
if (!d_pos && extra_child)
{
- return Term(d_solver, d_orig_expr->getOperator());
+ return Term(d_solver, d_origNode->getOperator());
}
else
{
@@ -1781,35 +2018,47 @@ Term Term::const_iterator::operator*() const
--idx;
}
Assert(idx >= 0);
- return Term(d_solver, (*d_orig_expr)[idx]);
+ return Term(d_solver, (*d_origNode)[idx]);
}
}
Term::const_iterator Term::begin() const
{
- return Term::const_iterator(d_solver, d_expr, 0);
+ return Term::const_iterator(d_solver, d_node, 0);
}
Term::const_iterator Term::end() const
{
- int endpos = d_expr->getNumChildren();
+ int endpos = d_node->getNumChildren();
// special cases for APPLY_*
// the API differs from the internal structure
// the API takes a "higher-order" perspective and the applied
// function or datatype constructor/selector/tester is a Term
// which means it needs to be one of the children, even though
// internally it is not
- if (isApplyKind(d_expr->getKind()))
+ if (isApplyKind(d_node->getKind()))
{
// one more child if this is a UF application (count the UF as a child)
++endpos;
}
- return Term::const_iterator(d_solver, d_expr, endpos);
+ return Term::const_iterator(d_solver, d_node, endpos);
+}
+
+// !!! This is only temporarily available until the parser is fully migrated
+// to the new API. !!!
+CVC4::Expr Term::getExpr(void) const
+{
+ if (d_node->isNull())
+ {
+ return Expr();
+ }
+ NodeManagerScope scope(d_solver->getNodeManager());
+ return d_node->toExpr();
}
// !!! This is only temporarily available until the parser is fully migrated
// to the new API. !!!
-CVC4::Expr Term::getExpr(void) const { return *d_expr; }
+const CVC4::Node& Term::getNode(void) const { return *d_node; }
std::ostream& operator<<(std::ostream& out, const Term& t)
{
@@ -1855,7 +2104,7 @@ std::ostream& operator<<(
size_t TermHashFunction::operator()(const Term& t) const
{
- return ExprHashFunction()(*t.d_expr);
+ return NodeHashFunction()(*t.d_node);
}
/* -------------------------------------------------------------------------- */
@@ -1871,12 +2120,22 @@ DatatypeConstructorDecl::DatatypeConstructorDecl()
DatatypeConstructorDecl::DatatypeConstructorDecl(const Solver* slv,
const std::string& name)
- : d_solver(slv), d_ctor(new CVC4::DatatypeConstructor(name))
+ : d_solver(slv), d_ctor(new CVC4::DTypeConstructor(name))
{
}
+DatatypeConstructorDecl::~DatatypeConstructorDecl()
+{
+ if (d_ctor != nullptr)
+ {
+ // ensure proper node manager is in scope
+ NodeManagerScope scope(d_solver->getNodeManager());
+ d_ctor.reset();
+ }
+}
void DatatypeConstructorDecl::addSelector(const std::string& name, Sort sort)
{
+ NodeManagerScope scope(d_solver->getNodeManager());
CVC4_API_ARG_CHECK_EXPECTED(!sort.isNull(), sort)
<< "non-null range sort for selector";
d_ctor->addArg(name, *sort.d_type);
@@ -1884,7 +2143,8 @@ void DatatypeConstructorDecl::addSelector(const std::string& name, Sort sort)
void DatatypeConstructorDecl::addSelectorSelf(const std::string& name)
{
- d_ctor->addArg(name, DatatypeSelfType());
+ NodeManagerScope scope(d_solver->getNodeManager());
+ d_ctor->addArgSelf(name);
}
std::string DatatypeConstructorDecl::toString() const
@@ -1896,8 +2156,8 @@ std::string DatatypeConstructorDecl::toString() const
// !!! This is only temporarily available until the parser is fully migrated
// to the new API. !!!
-const CVC4::DatatypeConstructor&
-DatatypeConstructorDecl::getDatatypeConstructor(void) const
+const CVC4::DTypeConstructor& DatatypeConstructorDecl::getDatatypeConstructor(
+ void) const
{
return *d_ctor;
}
@@ -1923,8 +2183,7 @@ DatatypeDecl::DatatypeDecl() : d_solver(nullptr), d_dtype(nullptr) {}
DatatypeDecl::DatatypeDecl(const Solver* slv,
const std::string& name,
bool isCoDatatype)
- : d_solver(slv),
- d_dtype(new CVC4::Datatype(slv->getExprManager(), name, isCoDatatype))
+ : d_solver(slv), d_dtype(new CVC4::DType(name, isCoDatatype))
{
}
@@ -1933,10 +2192,8 @@ DatatypeDecl::DatatypeDecl(const Solver* slv,
Sort param,
bool isCoDatatype)
: d_solver(slv),
- d_dtype(new CVC4::Datatype(slv->getExprManager(),
- name,
- std::vector<Type>{*param.d_type},
- isCoDatatype))
+ d_dtype(new CVC4::DType(
+ name, std::vector<TypeNode>{*param.d_type}, isCoDatatype))
{
}
@@ -1946,23 +2203,28 @@ DatatypeDecl::DatatypeDecl(const Solver* slv,
bool isCoDatatype)
: d_solver(slv)
{
- std::vector<Type> tparams;
- for (const Sort& p : params)
- {
- tparams.push_back(*p.d_type);
- }
- d_dtype = std::shared_ptr<CVC4::Datatype>(
- new CVC4::Datatype(slv->getExprManager(), name, tparams, isCoDatatype));
+ std::vector<TypeNode> tparams = sortVectorToTypeNodes(params);
+ d_dtype = std::shared_ptr<CVC4::DType>(
+ new CVC4::DType(name, tparams, isCoDatatype));
}
bool DatatypeDecl::isNullHelper() const { return !d_dtype; }
-DatatypeDecl::~DatatypeDecl() {}
+DatatypeDecl::~DatatypeDecl()
+{
+ if (d_dtype != nullptr)
+ {
+ // ensure proper node manager is in scope
+ NodeManagerScope scope(d_solver->getNodeManager());
+ d_dtype.reset();
+ }
+}
void DatatypeDecl::addConstructor(const DatatypeConstructorDecl& ctor)
{
+ NodeManagerScope scope(d_solver->getNodeManager());
CVC4_API_CHECK_NOT_NULL;
- d_dtype->addConstructor(*ctor.d_ctor);
+ d_dtype->addConstructor(ctor.d_ctor);
}
size_t DatatypeDecl::getNumConstructors() const
@@ -1995,7 +2257,7 @@ bool DatatypeDecl::isNull() const { return isNullHelper(); }
// !!! This is only temporarily available until the parser is fully migrated
// to the new API. !!!
-CVC4::Datatype& DatatypeDecl::getDatatype(void) const { return *d_dtype; }
+CVC4::DType& DatatypeDecl::getDatatype(void) const { return *d_dtype; }
std::ostream& operator<<(std::ostream& out, const DatatypeDecl& dtdecl)
{
@@ -2008,13 +2270,21 @@ std::ostream& operator<<(std::ostream& out, const DatatypeDecl& dtdecl)
DatatypeSelector::DatatypeSelector() : d_solver(nullptr), d_stor(nullptr) {}
DatatypeSelector::DatatypeSelector(const Solver* slv,
- const CVC4::DatatypeConstructorArg& stor)
- : d_solver(slv), d_stor(new CVC4::DatatypeConstructorArg(stor))
+ const CVC4::DTypeSelector& stor)
+ : d_solver(slv), d_stor(new CVC4::DTypeSelector(stor))
{
CVC4_API_CHECK(d_stor->isResolved()) << "Expected resolved datatype selector";
}
-DatatypeSelector::~DatatypeSelector() {}
+DatatypeSelector::~DatatypeSelector()
+{
+ if (d_stor != nullptr)
+ {
+ // ensure proper node manager is in scope
+ NodeManagerScope scope(d_solver->getNodeManager());
+ d_stor.reset();
+ }
+}
std::string DatatypeSelector::getName() const { return d_stor->getName(); }
@@ -2038,8 +2308,7 @@ std::string DatatypeSelector::toString() const
// !!! This is only temporarily available until the parser is fully migrated
// to the new API. !!!
-CVC4::DatatypeConstructorArg DatatypeSelector::getDatatypeConstructorArg(
- void) const
+CVC4::DTypeSelector DatatypeSelector::getDatatypeConstructorArg(void) const
{
return *d_stor;
}
@@ -2057,14 +2326,22 @@ DatatypeConstructor::DatatypeConstructor() : d_solver(nullptr), d_ctor(nullptr)
}
DatatypeConstructor::DatatypeConstructor(const Solver* slv,
- const CVC4::DatatypeConstructor& ctor)
- : d_solver(slv), d_ctor(new CVC4::DatatypeConstructor(ctor))
+ const CVC4::DTypeConstructor& ctor)
+ : d_solver(slv), d_ctor(new CVC4::DTypeConstructor(ctor))
{
CVC4_API_CHECK(d_ctor->isResolved())
<< "Expected resolved datatype constructor";
}
-DatatypeConstructor::~DatatypeConstructor() {}
+DatatypeConstructor::~DatatypeConstructor()
+{
+ if (d_ctor != nullptr)
+ {
+ // ensure proper node manager is in scope
+ NodeManagerScope scope(d_solver->getNodeManager());
+ d_ctor.reset();
+ }
+}
std::string DatatypeConstructor::getName() const { return d_ctor->getName(); }
@@ -2074,6 +2351,30 @@ Term DatatypeConstructor::getConstructorTerm() const
return ctor;
}
+Term DatatypeConstructor::getSpecializedConstructorTerm(Sort retSort) const
+{
+ NodeManagerScope scope(d_solver->getNodeManager());
+ CVC4_API_CHECK(d_ctor->isResolved())
+ << "Expected resolved datatype constructor";
+ CVC4_API_CHECK(retSort.isDatatype())
+ << "Cannot get specialized constructor type for non-datatype type "
+ << retSort;
+ CVC4_API_SOLVER_TRY_CATCH_BEGIN;
+
+ NodeManager* nm = d_solver->getNodeManager();
+ Node ret =
+ nm->mkNode(kind::APPLY_TYPE_ASCRIPTION,
+ nm->mkConst(AscriptionType(
+ d_ctor->getSpecializedConstructorType(*retSort.d_type))),
+ d_ctor->getConstructor());
+ (void)ret.getType(true); /* kick off type checking */
+ // apply type ascription to the operator
+ Term sctor = api::Term(d_solver, ret);
+ return sctor;
+
+ CVC4_API_SOLVER_TRY_CATCH_END;
+}
+
Term DatatypeConstructor::getTesterTerm() const
{
Term tst = Term(d_solver, d_ctor->getTester());
@@ -2117,20 +2418,19 @@ DatatypeConstructor::const_iterator DatatypeConstructor::end() const
}
DatatypeConstructor::const_iterator::const_iterator(
- const Solver* slv, const CVC4::DatatypeConstructor& ctor, bool begin)
+ const Solver* slv, const CVC4::DTypeConstructor& ctor, bool begin)
{
d_solver = slv;
- d_int_stors = ctor.getArgs();
+ d_int_stors = &ctor.getArgs();
- const std::vector<CVC4::DatatypeConstructorArg>* sels =
- static_cast<const std::vector<CVC4::DatatypeConstructorArg>*>(
- d_int_stors);
- for (const auto& s : *sels)
+ const std::vector<std::shared_ptr<CVC4::DTypeSelector>>& sels =
+ ctor.getArgs();
+ for (const std::shared_ptr<CVC4::DTypeSelector>& s : sels)
{
/* Can not use emplace_back here since constructor is private. */
- d_stors.push_back(DatatypeSelector(d_solver, s));
+ d_stors.push_back(DatatypeSelector(d_solver, *s.get()));
}
- d_idx = begin ? 0 : sels->size();
+ d_idx = begin ? 0 : sels.size();
}
DatatypeConstructor::const_iterator::const_iterator()
@@ -2195,7 +2495,7 @@ std::string DatatypeConstructor::toString() const
// !!! This is only temporarily available until the parser is fully migrated
// to the new API. !!!
-const CVC4::DatatypeConstructor& DatatypeConstructor::getDatatypeConstructor(
+const CVC4::DTypeConstructor& DatatypeConstructor::getDatatypeConstructor(
void) const
{
return *d_ctor;
@@ -2215,8 +2515,18 @@ DatatypeSelector DatatypeConstructor::getSelectorForName(
break;
}
}
- CVC4_API_CHECK(foundSel) << "No selector " << name << " for constructor "
- << getName() << " exists";
+ if (!foundSel)
+ {
+ std::stringstream snames;
+ snames << "{ ";
+ for (size_t i = 0, ncons = getNumSelectors(); i < ncons; i++)
+ {
+ snames << (*d_ctor)[i].getName() << " ";
+ }
+ snames << "} ";
+ CVC4_API_CHECK(foundSel) << "No selector " << name << " for constructor "
+ << getName() << " exists among " << snames.str();
+ }
return DatatypeSelector(d_solver, (*d_ctor)[index]);
}
@@ -2228,15 +2538,23 @@ std::ostream& operator<<(std::ostream& out, const DatatypeConstructor& ctor)
/* Datatype ----------------------------------------------------------------- */
-Datatype::Datatype(const Solver* slv, const CVC4::Datatype& dtype)
- : d_solver(slv), d_dtype(new CVC4::Datatype(dtype))
+Datatype::Datatype(const Solver* slv, const CVC4::DType& dtype)
+ : d_solver(slv), d_dtype(new CVC4::DType(dtype))
{
CVC4_API_CHECK(d_dtype->isResolved()) << "Expected resolved datatype";
}
Datatype::Datatype() : d_solver(nullptr), d_dtype(nullptr) {}
-Datatype::~Datatype() {}
+Datatype::~Datatype()
+{
+ if (d_dtype != nullptr)
+ {
+ // ensure proper node manager is in scope
+ NodeManagerScope scope(d_solver->getNodeManager());
+ d_dtype.reset();
+ }
+}
DatatypeConstructor Datatype::operator[](size_t idx) const
{
@@ -2295,7 +2613,7 @@ Datatype::const_iterator Datatype::end() const
// !!! This is only temporarily available until the parser is fully migrated
// to the new API. !!!
-const CVC4::Datatype& Datatype::getDatatype(void) const { return *d_dtype; }
+const CVC4::DType& Datatype::getDatatype(void) const { return *d_dtype; }
DatatypeConstructor Datatype::getConstructorForName(
const std::string& name) const
@@ -2311,24 +2629,34 @@ DatatypeConstructor Datatype::getConstructorForName(
break;
}
}
- CVC4_API_CHECK(foundCons) << "No constructor " << name << " for datatype "
- << getName() << " exists";
+ if (!foundCons)
+ {
+ std::stringstream snames;
+ snames << "{ ";
+ for (size_t i = 0, ncons = getNumConstructors(); i < ncons; i++)
+ {
+ snames << (*d_dtype)[i].getName() << " ";
+ }
+ snames << "}";
+ CVC4_API_CHECK(foundCons) << "No constructor " << name << " for datatype "
+ << getName() << " exists, among " << snames.str();
+ }
return DatatypeConstructor(d_solver, (*d_dtype)[index]);
}
Datatype::const_iterator::const_iterator(const Solver* slv,
- const CVC4::Datatype& dtype,
+ const CVC4::DType& dtype,
bool begin)
- : d_solver(slv), d_int_ctors(dtype.getConstructors())
+ : d_solver(slv), d_int_ctors(&dtype.getConstructors())
{
- const std::vector<CVC4::DatatypeConstructor>* cons =
- static_cast<const std::vector<CVC4::DatatypeConstructor>*>(d_int_ctors);
- for (const auto& c : *cons)
+ const std::vector<std::shared_ptr<DTypeConstructor>>& cons =
+ dtype.getConstructors();
+ for (const std::shared_ptr<DTypeConstructor>& c : cons)
{
/* Can not use emplace_back here since constructor is private. */
- d_ctors.push_back(DatatypeConstructor(d_solver, c));
+ d_ctors.push_back(DatatypeConstructor(d_solver, *c.get()));
}
- d_idx = begin ? 0 : cons->size();
+ d_idx = begin ? 0 : cons.size();
}
Datatype::const_iterator::const_iterator()
@@ -2384,6 +2712,18 @@ bool Datatype::const_iterator::operator!=(
/* -------------------------------------------------------------------------- */
/* Grammar */
/* -------------------------------------------------------------------------- */
+
+Grammar::Grammar()
+ : d_solver(nullptr),
+ d_sygusVars(),
+ d_ntSyms(),
+ d_ntsToTerms(0),
+ d_allowConst(),
+ d_allowVars(),
+ d_isResolved(false)
+{
+}
+
Grammar::Grammar(const Solver* slv,
const std::vector<Term>& sygusVars,
const std::vector<Term>& ntSymbols)
@@ -2411,7 +2751,7 @@ void Grammar::addRule(Term ntSymbol, Term rule)
d_ntsToTerms.find(ntSymbol) != d_ntsToTerms.cend(), ntSymbol)
<< "ntSymbol to be one of the non-terminal symbols given in the "
"predeclaration";
- CVC4_API_CHECK(ntSymbol.d_expr->getType() == rule.d_expr->getType())
+ CVC4_API_CHECK(ntSymbol.d_node->getType() == rule.d_node->getType())
<< "Expected ntSymbol and rule to have the same sort";
d_ntsToTerms[ntSymbol].push_back(rule);
@@ -2432,7 +2772,7 @@ void Grammar::addRules(Term ntSymbol, std::vector<Term> rules)
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
!rules[i].isNull(), "parameter rule", rules[i], i)
<< "non-null term";
- CVC4_API_CHECK(ntSymbol.d_expr->getType() == rules[i].d_expr->getType())
+ CVC4_API_CHECK(ntSymbol.d_node->getType() == rules[i].d_node->getType())
<< "Expected ntSymbol and rule at index " << i
<< " to have the same sort";
}
@@ -2467,6 +2807,78 @@ void Grammar::addAnyVariable(Term ntSymbol)
d_allowVars.insert(ntSymbol);
}
+/**
+ * this function concatinates the outputs of calling f on each element between
+ * first and last, seperated by sep.
+ * @param first the beginning of the range
+ * @param last the end of the range
+ * @param f the function to call on each element in the range, its output must
+ * be overloaded for operator<<
+ * @param sep the string to add between successive calls to f
+ */
+template <typename Iterator, typename Function>
+std::string join(Iterator first, Iterator last, Function f, std::string sep)
+{
+ std::stringstream ss;
+ Iterator i = first;
+
+ if (i != last)
+ {
+ ss << f(*i);
+ ++i;
+ }
+
+ while (i != last)
+ {
+ ss << sep << f(*i);
+ ++i;
+ }
+
+ return ss.str();
+}
+
+std::string Grammar::toString() const
+{
+ std::stringstream ss;
+ ss << " (" // pre-declaration
+ << join(
+ d_ntSyms.cbegin(),
+ d_ntSyms.cend(),
+ [](const Term& t) {
+ std::stringstream s;
+ s << '(' << t << ' ' << t.getSort() << ')';
+ return s.str();
+ },
+ " ")
+ << ")\n (" // grouped rule listing
+ << join(
+ d_ntSyms.cbegin(),
+ d_ntSyms.cend(),
+ [this](const Term& t) {
+ bool allowConst = d_allowConst.find(t) != d_allowConst.cend(),
+ allowVars = d_allowVars.find(t) != d_allowVars.cend();
+ const std::vector<Term>& rules = d_ntsToTerms.at(t);
+ std::stringstream s;
+ s << '(' << t << ' ' << t.getSort() << " ("
+ << (allowConst ? "(Constant " + t.getSort().toString() + ")"
+ : "")
+ << (allowConst && allowVars ? " " : "")
+ << (allowVars ? "(Var " + t.getSort().toString() + ")" : "")
+ << ((allowConst || allowVars) && !rules.empty() ? " " : "")
+ << join(
+ rules.cbegin(),
+ rules.cend(),
+ [](const Term& rule) { return rule.toString(); },
+ " ")
+ << "))";
+ return s.str();
+ },
+ "\n ")
+ << ')';
+
+ return ss.str();
+}
+
Sort Grammar::resolve()
{
d_isResolved = true;
@@ -2487,11 +2899,11 @@ Sort Grammar::resolve()
// make the unresolved type, used for referencing the final version of
// the ntsymbol's datatype
ntsToUnres[ntsymbol] =
- Sort(d_solver, d_solver->getExprManager()->mkSort(ntsymbol.toString()));
+ Sort(d_solver, d_solver->getNodeManager()->mkSort(ntsymbol.toString()));
}
- std::vector<CVC4::Datatype> datatypes;
- std::set<Type> unresTypes;
+ std::vector<CVC4::DType> datatypes;
+ std::set<TypeNode> unresTypes;
datatypes.reserve(d_ntSyms.size());
@@ -2508,12 +2920,12 @@ Sort Grammar::resolve()
if (d_allowVars.find(ntSym) != d_allowVars.cend())
{
addSygusConstructorVariables(dtDecl,
- Sort(d_solver, ntSym.d_expr->getType()));
+ Sort(d_solver, ntSym.d_node->getType()));
}
bool aci = d_allowConst.find(ntSym) != d_allowConst.end();
- Type btt = ntSym.d_expr->getType();
- dtDecl.d_dtype->setSygus(btt, *bvl.d_expr, aci, false);
+ TypeNode btt = ntSym.d_node->getType();
+ dtDecl.d_dtype->setSygus(btt, *bvl.d_node, aci, false);
// We can be in a case where the only rule specified was (Variable T)
// and there are no variables of type T, in which case this is a bogus
@@ -2526,9 +2938,9 @@ Sort Grammar::resolve()
unresTypes.insert(*ntsToUnres[ntSym].d_type);
}
- std::vector<DatatypeType> datatypeTypes =
- d_solver->getExprManager()->mkMutualDatatypeTypes(
- datatypes, unresTypes, ExprManager::DATATYPE_FLAG_PLACEHOLDER);
+ std::vector<TypeNode> datatypeTypes =
+ d_solver->getNodeManager()->mkMutualDatatypeTypes(
+ datatypes, unresTypes, NodeManager::DATATYPE_FLAG_PLACEHOLDER);
// return is the first datatype
return Sort(d_solver, datatypeTypes[0]);
@@ -2558,12 +2970,13 @@ void Grammar::addSygusConstructorTerm(
d_solver->getExprManager()->mkExpr(
CVC4::kind::BOUND_VAR_LIST, termVectorToExprs(args)));
// its operator is a lambda
- op = Term(d_solver,
- d_solver->getExprManager()->mkExpr(CVC4::kind::LAMBDA,
- {*lbvl.d_expr, *op.d_expr}));
+ op = Term(
+ d_solver,
+ d_solver->getExprManager()->mkExpr(
+ CVC4::kind::LAMBDA, {lbvl.d_node->toExpr(), op.d_node->toExpr()}));
}
- dt.d_dtype->addSygusConstructor(
- *op.d_expr, ssCName.str(), sortVectorToTypes(cargs));
+ std::vector<TypeNode> cargst = sortVectorToTypeNodes(cargs);
+ dt.d_dtype->addSygusConstructor(*op.d_node, ssCName.str(), cargst);
}
Term Grammar::purifySygusGTerm(
@@ -2578,38 +2991,40 @@ Term Grammar::purifySygusGTerm(
{
Term ret =
Term(d_solver,
- d_solver->getExprManager()->mkBoundVar(term.d_expr->getType()));
+ d_solver->getNodeManager()->mkBoundVar(term.d_node->getType()));
args.push_back(ret);
cargs.push_back(itn->second);
return ret;
}
std::vector<Term> pchildren;
bool childChanged = false;
- for (unsigned i = 0, nchild = term.d_expr->getNumChildren(); i < nchild; i++)
+ for (unsigned i = 0, nchild = term.d_node->getNumChildren(); i < nchild; i++)
{
Term ptermc = purifySygusGTerm(
- Term(d_solver, (*term.d_expr)[i]), args, cargs, ntsToUnres);
+ Term(d_solver, (*term.d_node)[i]), args, cargs, ntsToUnres);
pchildren.push_back(ptermc);
- childChanged = childChanged || *ptermc.d_expr != (*term.d_expr)[i];
+ childChanged =
+ childChanged || ptermc.d_node->toExpr() != (term.d_node->toExpr())[i];
}
if (!childChanged)
{
return term;
}
- Expr nret;
+ Node nret;
- if (term.d_expr->isParameterized())
+ if (term.d_node->getMetaKind() == kind::metakind::PARAMETERIZED)
{
// it's an indexed operator so we should provide the op
- nret = d_solver->getExprManager()->mkExpr(term.d_expr->getKind(),
- term.d_expr->getOperator(),
- termVectorToExprs(pchildren));
+ NodeBuilder<> nb(term.d_node->getKind());
+ nb << term.d_node->getOperator();
+ nb.append(termVectorToNodes(pchildren));
+ nret = nb.constructNode();
}
else
{
- nret = d_solver->getExprManager()->mkExpr(term.d_expr->getKind(),
- termVectorToExprs(pchildren));
+ nret = d_solver->getNodeManager()->mkNode(term.d_node->getKind(),
+ termVectorToNodes(pchildren));
}
return Term(d_solver, nret);
@@ -2622,17 +3037,21 @@ void Grammar::addSygusConstructorVariables(DatatypeDecl& dt, Sort sort) const
for (unsigned i = 0, size = d_sygusVars.size(); i < size; i++)
{
Term v = d_sygusVars[i];
- if (v.d_expr->getType() == *sort.d_type)
+ if (v.d_node->getType() == *sort.d_type)
{
std::stringstream ss;
ss << v;
- std::vector<Sort> cargs;
- dt.d_dtype->addSygusConstructor(
- *v.d_expr, ss.str(), sortVectorToTypes(cargs));
+ std::vector<TypeNode> cargs;
+ dt.d_dtype->addSygusConstructor(*v.d_node, ss.str(), cargs);
}
}
}
+std::ostream& operator<<(std::ostream& out, const Grammar& g)
+{
+ return out << g.toString();
+}
+
/* -------------------------------------------------------------------------- */
/* Rounding Mode for Floating Points */
/* -------------------------------------------------------------------------- */
@@ -2641,24 +3060,24 @@ const static std::
unordered_map<RoundingMode, CVC4::RoundingMode, RoundingModeHashFunction>
s_rmodes{
{ROUND_NEAREST_TIES_TO_EVEN,
- CVC4::RoundingMode::roundNearestTiesToEven},
- {ROUND_TOWARD_POSITIVE, CVC4::RoundingMode::roundTowardPositive},
- {ROUND_TOWARD_NEGATIVE, CVC4::RoundingMode::roundTowardNegative},
- {ROUND_TOWARD_ZERO, CVC4::RoundingMode::roundTowardZero},
+ CVC4::RoundingMode::ROUND_NEAREST_TIES_TO_EVEN},
+ {ROUND_TOWARD_POSITIVE, CVC4::RoundingMode::ROUND_TOWARD_POSITIVE},
+ {ROUND_TOWARD_NEGATIVE, CVC4::RoundingMode::ROUND_TOWARD_POSITIVE},
+ {ROUND_TOWARD_ZERO, CVC4::RoundingMode::ROUND_TOWARD_ZERO},
{ROUND_NEAREST_TIES_TO_AWAY,
- CVC4::RoundingMode::roundNearestTiesToAway},
+ CVC4::RoundingMode::ROUND_NEAREST_TIES_TO_AWAY},
};
const static std::unordered_map<CVC4::RoundingMode,
RoundingMode,
CVC4::RoundingModeHashFunction>
s_rmodes_internal{
- {CVC4::RoundingMode::roundNearestTiesToEven,
+ {CVC4::RoundingMode::ROUND_NEAREST_TIES_TO_EVEN,
ROUND_NEAREST_TIES_TO_EVEN},
- {CVC4::RoundingMode::roundTowardPositive, ROUND_TOWARD_POSITIVE},
- {CVC4::RoundingMode::roundTowardNegative, ROUND_TOWARD_NEGATIVE},
- {CVC4::RoundingMode::roundTowardZero, ROUND_TOWARD_ZERO},
- {CVC4::RoundingMode::roundNearestTiesToAway,
+ {CVC4::RoundingMode::ROUND_TOWARD_POSITIVE, ROUND_TOWARD_POSITIVE},
+ {CVC4::RoundingMode::ROUND_TOWARD_POSITIVE, ROUND_TOWARD_NEGATIVE},
+ {CVC4::RoundingMode::ROUND_TOWARD_ZERO, ROUND_TOWARD_ZERO},
+ {CVC4::RoundingMode::ROUND_NEAREST_TIES_TO_AWAY,
ROUND_NEAREST_TIES_TO_AWAY},
};
@@ -2691,23 +3110,28 @@ Solver::~Solver() {}
template <typename T>
Term Solver::mkValHelper(T t) const
{
- Expr res = d_exprMgr->mkConst(t);
+ NodeManagerScope scope(getNodeManager());
+ Node res = getNodeManager()->mkConst(t);
(void)res.getType(true); /* kick off type checking */
return Term(this, res);
}
Term Solver::mkRealFromStrHelper(const std::string& s) const
{
- /* CLN and GMP handle this case differently, CLN interprets it as 0, GMP
- * throws an std::invalid_argument exception. For consistency, we treat it
- * as invalid. */
- CVC4_API_ARG_CHECK_EXPECTED(s != ".", s)
- << "a string representing an integer, real or rational value.";
-
- CVC4::Rational r = s.find('/') != std::string::npos
- ? CVC4::Rational(s)
- : CVC4::Rational::fromDecimal(s);
- return mkValHelper<CVC4::Rational>(r);
+ try
+ {
+ CVC4::Rational r = s.find('/') != std::string::npos
+ ? CVC4::Rational(s)
+ : CVC4::Rational::fromDecimal(s);
+ return mkValHelper<CVC4::Rational>(r);
+ }
+ catch (const std::invalid_argument& e)
+ {
+ std::stringstream message;
+ message << "Cannot construct Real or Int from string argument '" << s << "'"
+ << std::endl;
+ throw std::invalid_argument(message.str());
+ }
}
Term Solver::mkBVFromIntHelper(uint32_t size, uint64_t val) const
@@ -2760,15 +3184,28 @@ Term Solver::mkCharFromStrHelper(const std::string& s) const
CVC4_API_CHECK(s.find_first_not_of("0123456789abcdefABCDEF", 0)
== std::string::npos
&& s.size() <= 5 && s.size() > 0)
- << "Unexpected string for hexidecimal character " << s;
+ << "Unexpected string for hexadecimal character " << s;
uint32_t val = static_cast<uint32_t>(std::stoul(s, 0, 16));
CVC4_API_CHECK(val < String::num_codes())
- << "Not a valid code point for hexidecimal character " << s;
+ << "Not a valid code point for hexadecimal character " << s;
std::vector<unsigned> cpts;
cpts.push_back(val);
return mkValHelper<CVC4::String>(CVC4::String(cpts));
}
+Term Solver::getValueHelper(Term term) const
+{
+ Node value = d_smtEngine->getValue(*term.d_node);
+ Term res = Term(this, value);
+ // May need to wrap in real cast so that user know this is a real.
+ TypeNode tn = (*term.d_node).getType();
+ if (!tn.isInteger() && value.getType().isInteger())
+ {
+ return ensureRealSort(res);
+ }
+ return res;
+}
+
Term Solver::mkTermFromKind(Kind kind) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
@@ -2796,6 +3233,7 @@ Term Solver::mkTermFromKind(Kind kind) const
Term Solver::mkTermHelper(Kind kind, const std::vector<Term>& children) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
for (size_t i = 0, size = children.size(); i < size; ++i)
{
@@ -2816,7 +3254,7 @@ Term Solver::mkTermHelper(Kind kind, const std::vector<Term>& children) const
if (echildren.size() > 2)
{
if (kind == INTS_DIVISION || kind == XOR || kind == MINUS
- || kind == DIVISION || kind == BITVECTOR_XNOR || kind == HO_APPLY)
+ || kind == DIVISION || kind == HO_APPLY || kind == REGEXP_DIFF)
{
// left-associative, but CVC4 internally only supports 2 args
res = d_exprMgr->mkLeftAssociative(k, echildren);
@@ -2854,7 +3292,23 @@ Term Solver::mkTermHelper(Kind kind, const std::vector<Term>& children) const
{
// default case, same as above
checkMkTerm(kind, children.size());
- res = d_exprMgr->mkExpr(k, echildren);
+ if (kind == api::SINGLETON)
+ {
+ // the type of the term is the same as the type of the internal node
+ // see Term::getSort()
+ TypeNode type = children[0].d_node->getType();
+ // Internally NodeManager::mkSingleton needs a type argument
+ // to construct a singleton, since there is no difference between
+ // integers and reals (both are Rationals).
+ // At the API, mkReal and mkInteger are different and therefore the
+ // element type can be used safely here.
+ Node singleton = getNodeManager()->mkSingleton(type, *children[0].d_node);
+ res = Term(this, singleton).getExpr();
+ }
+ else
+ {
+ res = d_exprMgr->mkExpr(k, echildren);
+ }
}
(void)res.getType(true); /* kick off type checking */
@@ -2863,12 +3317,13 @@ Term Solver::mkTermHelper(Kind kind, const std::vector<Term>& children) const
}
std::vector<Sort> Solver::mkDatatypeSortsInternal(
- std::vector<DatatypeDecl>& dtypedecls,
- std::set<Sort>& unresolvedSorts) const
+ const std::vector<DatatypeDecl>& dtypedecls,
+ const std::set<Sort>& unresolvedSorts) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- std::vector<CVC4::Datatype> datatypes;
+ std::vector<CVC4::DType> datatypes;
for (size_t i = 0, ndts = dtypedecls.size(); i < ndts; ++i)
{
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(this == dtypedecls[i].d_solver,
@@ -2887,14 +3342,11 @@ std::vector<Sort> Solver::mkDatatypeSortsInternal(
{
CVC4_API_SOLVER_CHECK_SORT(sort);
}
- std::set<Type> utypes = sortSetToTypes(unresolvedSorts);
- std::vector<CVC4::DatatypeType> dtypes =
- d_exprMgr->mkMutualDatatypeTypes(datatypes, utypes);
- std::vector<Sort> retTypes;
- for (CVC4::DatatypeType t : dtypes)
- {
- retTypes.push_back(Sort(this, t));
- }
+
+ std::set<TypeNode> utypes = sortSetToTypeNodes(unresolvedSorts);
+ std::vector<CVC4::TypeNode> dtypes =
+ getNodeManager()->mkMutualDatatypeTypes(datatypes, utypes);
+ std::vector<Sort> retTypes = typeNodeVectorToSorts(this, dtypes);
return retTypes;
CVC4_API_SOLVER_TRY_CATCH_END;
@@ -2910,7 +3362,7 @@ std::vector<Type> Solver::sortVectorToTypes(
for (const Sort& s : sorts)
{
CVC4_API_SOLVER_CHECK_SORT(s);
- res.push_back(*s.d_type);
+ res.push_back(s.d_type->toType());
}
return res;
}
@@ -2922,7 +3374,7 @@ std::vector<Expr> Solver::termVectorToExprs(
for (const Term& t : terms)
{
CVC4_API_SOLVER_CHECK_TERM(t);
- res.push_back(*t.d_expr);
+ res.push_back(t.d_node->toExpr());
}
return res;
}
@@ -2949,55 +3401,71 @@ void Solver::checkMkTerm(Kind kind, uint32_t nchildren) const
<< " children (the one under construction has " << nchildren << ")";
}
+/* Solver Configuration */
+/* -------------------------------------------------------------------------- */
+
+bool Solver::supportsFloatingPoint() const
+{
+ return Configuration::isBuiltWithSymFPU();
+}
+
/* Sorts Handling */
/* -------------------------------------------------------------------------- */
Sort Solver::getNullSort(void) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return Sort(this, Type());
+ return Sort(this, TypeNode());
CVC4_API_SOLVER_TRY_CATCH_END;
}
Sort Solver::getBooleanSort(void) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return Sort(this, d_exprMgr->booleanType());
+ return Sort(this, getNodeManager()->booleanType());
CVC4_API_SOLVER_TRY_CATCH_END;
}
Sort Solver::getIntegerSort(void) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return Sort(this, d_exprMgr->integerType());
+ return Sort(this, getNodeManager()->integerType());
CVC4_API_SOLVER_TRY_CATCH_END;
}
Sort Solver::getRealSort(void) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return Sort(this, d_exprMgr->realType());
+ return Sort(this, getNodeManager()->realType());
CVC4_API_SOLVER_TRY_CATCH_END;
}
Sort Solver::getRegExpSort(void) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return Sort(this, d_exprMgr->regExpType());
+ return Sort(this, getNodeManager()->regExpType());
CVC4_API_SOLVER_TRY_CATCH_END;
}
Sort Solver::getStringSort(void) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return Sort(this, d_exprMgr->stringType());
+ return Sort(this, getNodeManager()->stringType());
CVC4_API_SOLVER_TRY_CATCH_END;
}
-Sort Solver::getRoundingmodeSort(void) const
+Sort Solver::getRoundingModeSort(void) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return Sort(this, d_exprMgr->roundingModeType());
+ CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
+ << "Expected CVC4 to be compiled with SymFPU support";
+ return Sort(this, getNodeManager()->roundingModeType());
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -3005,6 +3473,7 @@ Sort Solver::getRoundingmodeSort(void) const
Sort Solver::mkArraySort(Sort indexSort, Sort elemSort) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_ARG_CHECK_EXPECTED(!indexSort.isNull(), indexSort)
<< "non-null index sort";
@@ -3013,42 +3482,47 @@ Sort Solver::mkArraySort(Sort indexSort, Sort elemSort) const
CVC4_API_SOLVER_CHECK_SORT(indexSort);
CVC4_API_SOLVER_CHECK_SORT(elemSort);
- return Sort(this,
- d_exprMgr->mkArrayType(*indexSort.d_type, *elemSort.d_type));
+ return Sort(
+ this, getNodeManager()->mkArrayType(*indexSort.d_type, *elemSort.d_type));
CVC4_API_SOLVER_TRY_CATCH_END;
}
Sort Solver::mkBitVectorSort(uint32_t size) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_ARG_CHECK_EXPECTED(size > 0, size) << "size > 0";
- return Sort(this, d_exprMgr->mkBitVectorType(size));
+ return Sort(this, getNodeManager()->mkBitVectorType(size));
CVC4_API_SOLVER_TRY_CATCH_END;
}
Sort Solver::mkFloatingPointSort(uint32_t exp, uint32_t sig) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
+ CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
+ << "Expected CVC4 to be compiled with SymFPU support";
CVC4_API_ARG_CHECK_EXPECTED(exp > 0, exp) << "exponent size > 0";
CVC4_API_ARG_CHECK_EXPECTED(sig > 0, sig) << "significand size > 0";
- return Sort(this, d_exprMgr->mkFloatingPointType(exp, sig));
+ return Sort(this, getNodeManager()->mkFloatingPointType(exp, sig));
CVC4_API_SOLVER_TRY_CATCH_END;
}
Sort Solver::mkDatatypeSort(DatatypeDecl dtypedecl) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_CHECK(this == dtypedecl.d_solver)
<< "Given datatype declaration is not associated with this solver";
CVC4_API_ARG_CHECK_EXPECTED(dtypedecl.getNumConstructors() > 0, dtypedecl)
<< "a datatype declaration with at least one constructor";
- return Sort(this, d_exprMgr->mkDatatypeType(*dtypedecl.d_dtype));
+ return Sort(this, getNodeManager()->mkDatatypeType(*dtypedecl.d_dtype));
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -3056,18 +3530,24 @@ Sort Solver::mkDatatypeSort(DatatypeDecl dtypedecl) const
std::vector<Sort> Solver::mkDatatypeSorts(
std::vector<DatatypeDecl>& dtypedecls) const
{
+ CVC4_API_SOLVER_TRY_CATCH_BEGIN;
std::set<Sort> unresolvedSorts;
return mkDatatypeSortsInternal(dtypedecls, unresolvedSorts);
+ CVC4_API_SOLVER_TRY_CATCH_END;
}
-std::vector<Sort> Solver::mkDatatypeSorts(std::vector<DatatypeDecl>& dtypedecls,
- std::set<Sort>& unresolvedSorts) const
+std::vector<Sort> Solver::mkDatatypeSorts(
+ const std::vector<DatatypeDecl>& dtypedecls,
+ const std::set<Sort>& unresolvedSorts) const
{
+ CVC4_API_SOLVER_TRY_CATCH_BEGIN;
return mkDatatypeSortsInternal(dtypedecls, unresolvedSorts);
+ CVC4_API_SOLVER_TRY_CATCH_END;
}
Sort Solver::mkFunctionSort(Sort domain, Sort codomain) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_ARG_CHECK_EXPECTED(!codomain.isNull(), codomain)
<< "non-null codomain sort";
@@ -3079,14 +3559,15 @@ Sort Solver::mkFunctionSort(Sort domain, Sort codomain) const
<< "first-class sort as codomain sort for function sort";
Assert(!codomain.isFunction()); /* A function sort is not first-class. */
- return Sort(this,
- d_exprMgr->mkFunctionType(*domain.d_type, *codomain.d_type));
+ return Sort(
+ this, getNodeManager()->mkFunctionType(*domain.d_type, *codomain.d_type));
CVC4_API_SOLVER_TRY_CATCH_END;
}
Sort Solver::mkFunctionSort(const std::vector<Sort>& sorts, Sort codomain) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_ARG_SIZE_CHECK_EXPECTED(sorts.size() >= 1, sorts)
<< "at least one parameter sort for function sort";
@@ -3109,22 +3590,26 @@ Sort Solver::mkFunctionSort(const std::vector<Sort>& sorts, Sort codomain) const
<< "first-class sort as codomain sort for function sort";
Assert(!codomain.isFunction()); /* A function sort is not first-class. */
- std::vector<Type> argTypes = sortVectorToTypes(sorts);
- return Sort(this, d_exprMgr->mkFunctionType(argTypes, *codomain.d_type));
+ std::vector<TypeNode> argTypes = sortVectorToTypeNodes(sorts);
+ return Sort(this,
+ getNodeManager()->mkFunctionType(argTypes, *codomain.d_type));
CVC4_API_SOLVER_TRY_CATCH_END;
}
Sort Solver::mkParamSort(const std::string& symbol) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return Sort(this,
- d_exprMgr->mkSort(symbol, ExprManager::SORT_FLAG_PLACEHOLDER));
+ return Sort(
+ this,
+ getNodeManager()->mkSort(symbol, ExprManager::SORT_FLAG_PLACEHOLDER));
CVC4_API_SOLVER_TRY_CATCH_END;
}
Sort Solver::mkPredicateSort(const std::vector<Sort>& sorts) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_ARG_SIZE_CHECK_EXPECTED(sorts.size() >= 1, sorts)
<< "at least one parameter sort for predicate sort";
@@ -3140,9 +3625,9 @@ Sort Solver::mkPredicateSort(const std::vector<Sort>& sorts) const
sorts[i].isFirstClass(), "parameter sort", sorts[i], i)
<< "first-class sort as parameter sort for predicate sort";
}
- std::vector<Type> types = sortVectorToTypes(sorts);
+ std::vector<TypeNode> types = sortVectorToTypeNodes(sorts);
- return Sort(this, d_exprMgr->mkPredicateType(types));
+ return Sort(this, getNodeManager()->mkPredicateType(types));
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -3150,6 +3635,7 @@ Sort Solver::mkPredicateSort(const std::vector<Sort>& sorts) const
Sort Solver::mkRecordSort(
const std::vector<std::pair<std::string, Sort>>& fields) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
std::vector<std::pair<std::string, Type>> f;
size_t i = 0;
@@ -3162,58 +3648,76 @@ Sort Solver::mkRecordSort(
this == p.second.d_solver, "parameter sort", p.second, i)
<< "sort associated to this solver object";
i += 1;
- f.emplace_back(p.first, *p.second.d_type);
+ f.emplace_back(p.first, p.second.d_type->toType());
}
- return Sort(this, d_exprMgr->mkRecordType(Record(f)));
+ return Sort(this, getNodeManager()->mkRecordType(Record(f)));
CVC4_API_SOLVER_TRY_CATCH_END;
}
Sort Solver::mkSetSort(Sort elemSort) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_ARG_CHECK_EXPECTED(!elemSort.isNull(), elemSort)
<< "non-null element sort";
CVC4_API_SOLVER_CHECK_SORT(elemSort);
- return Sort(this, d_exprMgr->mkSetType(*elemSort.d_type));
+ return Sort(this, getNodeManager()->mkSetType(*elemSort.d_type));
+
+ CVC4_API_SOLVER_TRY_CATCH_END;
+}
+
+Sort Solver::mkBagSort(Sort elemSort) const
+{
+ NodeManagerScope scope(getNodeManager());
+ CVC4_API_SOLVER_TRY_CATCH_BEGIN;
+ CVC4_API_ARG_CHECK_EXPECTED(!elemSort.isNull(), elemSort)
+ << "non-null element sort";
+ CVC4_API_SOLVER_CHECK_SORT(elemSort);
+
+ return Sort(this, getNodeManager()->mkBagType(*elemSort.d_type));
CVC4_API_SOLVER_TRY_CATCH_END;
}
Sort Solver::mkSequenceSort(Sort elemSort) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_ARG_CHECK_EXPECTED(!elemSort.isNull(), elemSort)
<< "non-null element sort";
CVC4_API_SOLVER_CHECK_SORT(elemSort);
- return Sort(this, d_exprMgr->mkSequenceType(*elemSort.d_type));
+ return Sort(this, getNodeManager()->mkSequenceType(*elemSort.d_type));
CVC4_API_SOLVER_TRY_CATCH_END;
}
Sort Solver::mkUninterpretedSort(const std::string& symbol) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return Sort(this, d_exprMgr->mkSort(symbol));
+ return Sort(this, getNodeManager()->mkSort(symbol));
CVC4_API_SOLVER_TRY_CATCH_END;
}
Sort Solver::mkSortConstructorSort(const std::string& symbol,
size_t arity) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_ARG_CHECK_EXPECTED(arity > 0, arity) << "an arity > 0";
- return Sort(this, d_exprMgr->mkSortConstructor(symbol, arity));
+ return Sort(this, getNodeManager()->mkSortConstructor(symbol, arity));
CVC4_API_SOLVER_TRY_CATCH_END;
}
Sort Solver::mkTupleSort(const std::vector<Sort>& sorts) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
for (size_t i = 0, size = sorts.size(); i < size; ++i)
{
@@ -3227,9 +3731,8 @@ Sort Solver::mkTupleSort(const std::vector<Sort>& sorts) const
!sorts[i].isFunctionLike(), "parameter sort", sorts[i], i)
<< "non-function-like sort as parameter sort for tuple sort";
}
- std::vector<Type> types = sortVectorToTypes(sorts);
-
- return Sort(this, d_exprMgr->mkTupleType(types));
+ std::vector<TypeNode> typeNodes = sortVectorToTypeNodes(sorts);
+ return Sort(this, getNodeManager()->mkTupleType(typeNodes));
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -3270,76 +3773,66 @@ Term Solver::mkPi() const
CVC4_API_SOLVER_TRY_CATCH_END;
}
-Term Solver::mkReal(const char* s) const
-{
- CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- CVC4_API_ARG_CHECK_NOT_NULLPTR(s);
-
- return mkRealFromStrHelper(std::string(s));
-
- CVC4_API_SOLVER_TRY_CATCH_END;
-}
-
-Term Solver::mkReal(const std::string& s) const
+Term Solver::mkInteger(const std::string& s) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return mkRealFromStrHelper(s);
+ CVC4_API_ARG_CHECK_EXPECTED(std::regex_match(s, std::regex("-?\\d+")), s)
+ << " an integer ";
+ Term integer = mkRealFromStrHelper(s);
+ CVC4_API_ARG_CHECK_EXPECTED(integer.getSort() == getIntegerSort(), s)
+ << " an integer";
+ return integer;
CVC4_API_SOLVER_TRY_CATCH_END;
}
-Term Solver::mkReal(int32_t val) const
+Term Solver::mkInteger(int64_t val) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return mkValHelper<CVC4::Rational>(CVC4::Rational(val));
+ Term integer = mkValHelper<CVC4::Rational>(CVC4::Rational(val));
+ Assert(integer.getSort() == getIntegerSort());
+ return integer;
CVC4_API_SOLVER_TRY_CATCH_END;
}
-Term Solver::mkReal(int64_t val) const
-{
- CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return mkValHelper<CVC4::Rational>(CVC4::Rational(val));
- CVC4_API_SOLVER_TRY_CATCH_END;
-}
-
-Term Solver::mkReal(uint32_t val) const
+Term Solver::mkReal(const std::string& s) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return mkValHelper<CVC4::Rational>(CVC4::Rational(val));
+ /* CLN and GMP handle this case differently, CLN interprets it as 0, GMP
+ * throws an std::invalid_argument exception. For consistency, we treat it
+ * as invalid. */
+ CVC4_API_ARG_CHECK_EXPECTED(s != ".", s)
+ << "a string representing a real or rational value.";
+ Term rational = mkRealFromStrHelper(s);
+ return ensureRealSort(rational);
CVC4_API_SOLVER_TRY_CATCH_END;
}
-Term Solver::mkReal(uint64_t val) const
+Term Solver::ensureRealSort(const Term t) const
{
- CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return mkValHelper<CVC4::Rational>(CVC4::Rational(val));
- CVC4_API_SOLVER_TRY_CATCH_END;
+ CVC4_API_ARG_CHECK_EXPECTED(
+ t.getSort() == getIntegerSort() || t.getSort() == getRealSort(),
+ " an integer or real term");
+ if (t.getSort() == getIntegerSort())
+ {
+ Node n = getNodeManager()->mkNode(kind::CAST_TO_REAL, *t.d_node);
+ return Term(this, n);
+ }
+ return t;
}
-Term Solver::mkReal(int32_t num, int32_t den) const
+Term Solver::mkReal(int64_t val) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return mkValHelper<CVC4::Rational>(CVC4::Rational(num, den));
+ Term rational = mkValHelper<CVC4::Rational>(CVC4::Rational(val));
+ return ensureRealSort(rational);
CVC4_API_SOLVER_TRY_CATCH_END;
}
Term Solver::mkReal(int64_t num, int64_t den) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return mkValHelper<CVC4::Rational>(CVC4::Rational(num, den));
- CVC4_API_SOLVER_TRY_CATCH_END;
-}
-
-Term Solver::mkReal(uint32_t num, uint32_t den) const
-{
- CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return mkValHelper<CVC4::Rational>(CVC4::Rational(num, den));
- CVC4_API_SOLVER_TRY_CATCH_END;
-}
-
-Term Solver::mkReal(uint64_t num, uint64_t den) const
-{
- CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return mkValHelper<CVC4::Rational>(CVC4::Rational(num, den));
+ Term rational = mkValHelper<CVC4::Rational>(CVC4::Rational(num, den));
+ return ensureRealSort(rational);
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -3375,29 +3868,36 @@ Term Solver::mkEmptySet(Sort s) const
CVC4_API_ARG_CHECK_EXPECTED(s.isNull() || this == s.d_solver, s)
<< "set sort associated to this solver object";
- return mkValHelper<CVC4::EmptySet>(
- CVC4::EmptySet(TypeNode::fromType(*s.d_type)));
+ return mkValHelper<CVC4::EmptySet>(CVC4::EmptySet(*s.d_type));
CVC4_API_SOLVER_TRY_CATCH_END;
}
-Term Solver::mkSepNil(Sort sort) const
+Term Solver::mkEmptyBag(Sort s) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- CVC4_API_ARG_CHECK_EXPECTED(!sort.isNull(), sort) << "non-null sort";
- CVC4_API_SOLVER_CHECK_SORT(sort);
+ CVC4_API_ARG_CHECK_EXPECTED(s.isNull() || s.isBag(), s)
+ << "null sort or bag sort";
- Expr res = d_exprMgr->mkNullaryOperator(*sort.d_type, CVC4::kind::SEP_NIL);
- (void)res.getType(true); /* kick off type checking */
- return Term(this, res);
+ CVC4_API_ARG_CHECK_EXPECTED(s.isNull() || this == s.d_solver, s)
+ << "bag sort associated to this solver object";
+
+ return mkValHelper<CVC4::EmptyBag>(CVC4::EmptyBag(*s.d_type));
CVC4_API_SOLVER_TRY_CATCH_END;
}
-Term Solver::mkString(const char* s, bool useEscSequences) const
+Term Solver::mkSepNil(Sort sort) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- return mkValHelper<CVC4::String>(CVC4::String(s, useEscSequences));
+ CVC4_API_ARG_CHECK_EXPECTED(!sort.isNull(), sort) << "non-null sort";
+ CVC4_API_SOLVER_CHECK_SORT(sort);
+
+ Node res =
+ getNodeManager()->mkNullaryOperator(*sort.d_type, CVC4::kind::SEP_NIL);
+ (void)res.getType(true); /* kick off type checking */
+ return Term(this, res);
+
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -3429,14 +3929,6 @@ Term Solver::mkChar(const std::string& s) const
CVC4_API_SOLVER_TRY_CATCH_END;
}
-Term Solver::mkChar(const char* s) const
-{
- CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- CVC4_API_ARG_CHECK_NOT_NULLPTR(s);
- return mkCharFromStrHelper(std::string(s));
- CVC4_API_SOLVER_TRY_CATCH_END;
-}
-
Term Solver::mkEmptySequence(Sort sort) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
@@ -3444,8 +3936,7 @@ Term Solver::mkEmptySequence(Sort sort) const
CVC4_API_SOLVER_CHECK_SORT(sort);
std::vector<Node> seq;
- Expr res =
- d_exprMgr->mkConst(Sequence(TypeNode::fromType(*sort.d_type), seq));
+ Expr res = d_exprMgr->mkConst(Sequence(*sort.d_type, seq));
return Term(this, res);
CVC4_API_SOLVER_TRY_CATCH_END;
@@ -3457,8 +3948,8 @@ Term Solver::mkUniverseSet(Sort sort) const
CVC4_API_ARG_CHECK_EXPECTED(!sort.isNull(), sort) << "non-null sort";
CVC4_API_SOLVER_CHECK_SORT(sort);
- Expr res =
- d_exprMgr->mkNullaryOperator(*sort.d_type, CVC4::kind::UNIVERSE_SET);
+ Node res = getNodeManager()->mkNullaryOperator(*sort.d_type,
+ CVC4::kind::UNIVERSE_SET);
// TODO(#2771): Reenable?
// (void)res->getType(true); /* kick off type checking */
return Term(this, res);
@@ -3473,16 +3964,6 @@ Term Solver::mkBitVector(uint32_t size, uint64_t val) const
CVC4_API_SOLVER_TRY_CATCH_END;
}
-Term Solver::mkBitVector(const char* s, uint32_t base) const
-{
- CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- CVC4_API_ARG_CHECK_NOT_NULLPTR(s);
-
- return mkBVFromStrHelper(std::string(s), base);
-
- CVC4_API_SOLVER_TRY_CATCH_END;
-}
-
Term Solver::mkBitVector(const std::string& s, uint32_t base) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
@@ -3490,15 +3971,9 @@ Term Solver::mkBitVector(const std::string& s, uint32_t base) const
CVC4_API_SOLVER_TRY_CATCH_END;
}
-Term Solver::mkBitVector(uint32_t size, const char* s, uint32_t base) const
-{
- CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- CVC4_API_ARG_CHECK_NOT_NULLPTR(s);
- return mkBVFromStrHelper(size, s, base);
- CVC4_API_SOLVER_TRY_CATCH_END;
-}
-
-Term Solver::mkBitVector(uint32_t size, std::string& s, uint32_t base) const
+Term Solver::mkBitVector(uint32_t size,
+ const std::string& s,
+ uint32_t base) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
return mkBVFromStrHelper(size, s, base);
@@ -3514,10 +3989,17 @@ Term Solver::mkConstArray(Sort sort, Term val) const
CVC4_API_SOLVER_CHECK_SORT(sort);
CVC4_API_SOLVER_CHECK_TERM(val);
CVC4_API_CHECK(sort.isArray()) << "Not an array sort.";
- CVC4_API_CHECK(sort.getArrayElementSort().isComparableTo(val.getSort()))
+ CVC4_API_CHECK(val.getSort().isSubsortOf(sort.getArrayElementSort()))
<< "Value does not match element sort.";
- Term res = mkValHelper<CVC4::ArrayStoreAll>(CVC4::ArrayStoreAll(
- TypeNode::fromType(*sort.d_type), Node::fromExpr(*val.d_expr)));
+ // handle the special case of (CAST_TO_REAL n) where n is an integer
+ Node n = *val.d_node;
+ if (val.isCastedReal())
+ {
+ // this is safe because the constant array stores its type
+ n = n[0];
+ }
+ Term res = mkValHelper<CVC4::ArrayStoreAll>(
+ CVC4::ArrayStoreAll(*sort.d_type, n));
return res;
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -3585,6 +4067,8 @@ Term Solver::mkNegZero(uint32_t exp, uint32_t sig) const
Term Solver::mkRoundingMode(RoundingMode rm) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
+ CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
+ << "Expected CVC4 to be compiled with SymFPU support";
return mkValHelper<CVC4::RoundingMode>(s_rmodes.at(rm));
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -3596,7 +4080,7 @@ Term Solver::mkUninterpretedConst(Sort sort, int32_t index) const
CVC4_API_SOLVER_CHECK_SORT(sort);
return mkValHelper<CVC4::UninterpretedConstant>(
- CVC4::UninterpretedConstant(TypeNode::fromType(*sort.d_type), index));
+ CVC4::UninterpretedConstant(*sort.d_type, index));
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -3609,7 +4093,7 @@ Term Solver::mkAbstractValue(const std::string& index) const
CVC4::Integer idx(index, 10);
CVC4_API_ARG_CHECK_EXPECTED(idx > 0, index)
<< "a string representing an integer > 0";
- return Term(this, d_exprMgr->mkConst(CVC4::AbstractValue(idx)));
+ return Term(this, getNodeManager()->mkConst(CVC4::AbstractValue(idx)));
// do not call getType(), for abstract values, type can not be computed
// until it is substituted away
CVC4_API_SOLVER_TRY_CATCH_END;
@@ -3620,7 +4104,8 @@ Term Solver::mkAbstractValue(uint64_t index) const
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_ARG_CHECK_EXPECTED(index > 0, index) << "an integer > 0";
- return Term(this, d_exprMgr->mkConst(CVC4::AbstractValue(Integer(index))));
+ return Term(this,
+ getNodeManager()->mkConst(CVC4::AbstractValue(Integer(index))));
// do not call getType(), for abstract values, type can not be computed
// until it is substituted away
CVC4_API_SOLVER_TRY_CATCH_END;
@@ -3639,11 +4124,11 @@ Term Solver::mkFloatingPoint(uint32_t exp, uint32_t sig, Term val) const
CVC4_API_ARG_CHECK_EXPECTED(!val.isNull(), val) << "non-null term";
CVC4_API_SOLVER_CHECK_TERM(val);
CVC4_API_ARG_CHECK_EXPECTED(
- val.getSort().isBitVector() && val.d_expr->isConst(), val)
+ val.getSort().isBitVector() && val.d_node->isConst(), val)
<< "bit-vector constant";
return mkValHelper<CVC4::FloatingPoint>(
- CVC4::FloatingPoint(exp, sig, val.d_expr->getConst<BitVector>()));
+ CVC4::FloatingPoint(exp, sig, val.d_node->getConst<BitVector>()));
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -3653,12 +4138,26 @@ Term Solver::mkFloatingPoint(uint32_t exp, uint32_t sig, Term val) const
Term Solver::mkConst(Sort sort, const std::string& symbol) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_ARG_CHECK_EXPECTED(!sort.isNull(), sort) << "non-null sort";
CVC4_API_SOLVER_CHECK_SORT(sort);
- Expr res = symbol.empty() ? d_exprMgr->mkVar(*sort.d_type)
- : d_exprMgr->mkVar(symbol, *sort.d_type);
+ Expr res = d_exprMgr->mkVar(symbol, sort.d_type->toType());
+ (void)res.getType(true); /* kick off type checking */
+ return Term(this, res);
+
+ CVC4_API_SOLVER_TRY_CATCH_END;
+}
+
+Term Solver::mkConst(Sort sort) const
+{
+ NodeManagerScope scope(getNodeManager());
+ CVC4_API_SOLVER_TRY_CATCH_BEGIN;
+ CVC4_API_ARG_CHECK_EXPECTED(!sort.isNull(), sort) << "non-null sort";
+ CVC4_API_SOLVER_CHECK_SORT(sort);
+
+ Expr res = d_exprMgr->mkVar(sort.d_type->toType());
(void)res.getType(true); /* kick off type checking */
return Term(this, res);
@@ -3674,8 +4173,9 @@ Term Solver::mkVar(Sort sort, const std::string& symbol) const
CVC4_API_ARG_CHECK_EXPECTED(!sort.isNull(), sort) << "non-null sort";
CVC4_API_SOLVER_CHECK_SORT(sort);
- Expr res = symbol.empty() ? d_exprMgr->mkBoundVar(*sort.d_type)
- : d_exprMgr->mkBoundVar(symbol, *sort.d_type);
+ Expr res = symbol.empty()
+ ? d_exprMgr->mkBoundVar(sort.d_type->toType())
+ : d_exprMgr->mkBoundVar(symbol, sort.d_type->toType());
(void)res.getType(true); /* kick off type checking */
return Term(this, res);
@@ -3688,6 +4188,7 @@ Term Solver::mkVar(Sort sort, const std::string& symbol) const
DatatypeConstructorDecl Solver::mkDatatypeConstructorDecl(
const std::string& name)
{
+ NodeManagerScope scope(getNodeManager());
return DatatypeConstructorDecl(this, name);
}
@@ -3696,6 +4197,7 @@ DatatypeConstructorDecl Solver::mkDatatypeConstructorDecl(
DatatypeDecl Solver::mkDatatypeDecl(const std::string& name, bool isCoDatatype)
{
+ NodeManagerScope scope(getNodeManager());
return DatatypeDecl(this, name, isCoDatatype);
}
@@ -3703,6 +4205,7 @@ DatatypeDecl Solver::mkDatatypeDecl(const std::string& name,
Sort param,
bool isCoDatatype)
{
+ NodeManagerScope scope(getNodeManager());
return DatatypeDecl(this, name, param, isCoDatatype);
}
@@ -3710,6 +4213,7 @@ DatatypeDecl Solver::mkDatatypeDecl(const std::string& name,
const std::vector<Sort>& params,
bool isCoDatatype)
{
+ NodeManagerScope scope(getNodeManager());
return DatatypeDecl(this, name, params, isCoDatatype);
}
@@ -3725,33 +4229,12 @@ Term Solver::mkTerm(Kind kind) const
Term Solver::mkTerm(Kind kind, Term child) const
{
- CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- CVC4_API_ARG_CHECK_EXPECTED(!child.isNull(), child) << "non-null term";
- CVC4_API_SOLVER_CHECK_TERM(child);
- checkMkTerm(kind, 1);
-
- Expr res = d_exprMgr->mkExpr(extToIntKind(kind), *child.d_expr);
- (void)res.getType(true); /* kick off type checking */
- return Term(this, res);
-
- CVC4_API_SOLVER_TRY_CATCH_END;
+ return mkTermHelper(kind, std::vector<Term>{child});
}
Term Solver::mkTerm(Kind kind, Term child1, Term child2) const
{
- CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- CVC4_API_ARG_CHECK_EXPECTED(!child1.isNull(), child1) << "non-null term";
- CVC4_API_ARG_CHECK_EXPECTED(!child2.isNull(), child2) << "non-null term";
- CVC4_API_SOLVER_CHECK_TERM(child1);
- CVC4_API_SOLVER_CHECK_TERM(child2);
- checkMkTerm(kind, 2);
-
- Expr res =
- d_exprMgr->mkExpr(extToIntKind(kind), *child1.d_expr, *child2.d_expr);
- (void)res.getType(true); /* kick off type checking */
- return Term(this, res);
-
- CVC4_API_SOLVER_TRY_CATCH_END;
+ return mkTermHelper(kind, std::vector<Term>{child1, child2});
}
Term Solver::mkTerm(Kind kind, Term child1, Term child2, Term child3) const
@@ -3767,21 +4250,20 @@ Term Solver::mkTerm(Kind kind, const std::vector<Term>& children) const
Term Solver::mkTerm(Op op) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_SOLVER_CHECK_OP(op);
+ checkMkTerm(op.d_kind, 0);
- Term res;
- if (op.isIndexedHelper())
+ if (!op.isIndexedHelper())
{
- const CVC4::Kind int_kind = extToIntKind(op.d_kind);
- res = Term(this, d_exprMgr->mkExpr(int_kind, *op.d_expr));
- }
- else
- {
- res = mkTermFromKind(op.d_kind);
+ return mkTermFromKind(op.d_kind);
}
- (void)res.d_expr->getType(true); /* kick off type checking */
+ const CVC4::Kind int_kind = extToIntKind(op.d_kind);
+ Term res = Term(this, getNodeManager()->mkNode(int_kind, *op.d_node));
+
+ (void)res.d_node->getType(true); /* kick off type checking */
return res;
CVC4_API_SOLVER_TRY_CATCH_END;
@@ -3789,88 +4271,35 @@ Term Solver::mkTerm(Op op) const
Term Solver::mkTerm(Op op, Term child) const
{
- CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- CVC4_API_SOLVER_CHECK_OP(op);
- CVC4_API_ARG_CHECK_EXPECTED(!child.isNull(), child) << "non-null term";
- CVC4_API_SOLVER_CHECK_TERM(child);
-
- const CVC4::Kind int_kind = extToIntKind(op.d_kind);
- Expr res;
- if (op.isIndexedHelper())
- {
- res = d_exprMgr->mkExpr(int_kind, *op.d_expr, *child.d_expr);
- }
- else
- {
- res = d_exprMgr->mkExpr(int_kind, *child.d_expr);
- }
-
- (void)res.getType(true); /* kick off type checking */
- return Term(this, res);
-
- CVC4_API_SOLVER_TRY_CATCH_END;
+ return mkTermHelper(op, std::vector<Term>{child});
}
Term Solver::mkTerm(Op op, Term child1, Term child2) const
{
- CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- CVC4_API_SOLVER_CHECK_OP(op);
- CVC4_API_ARG_CHECK_EXPECTED(!child1.isNull(), child1) << "non-null term";
- CVC4_API_ARG_CHECK_EXPECTED(!child2.isNull(), child2) << "non-null term";
- CVC4_API_SOLVER_CHECK_TERM(child1);
- CVC4_API_SOLVER_CHECK_TERM(child2);
-
- const CVC4::Kind int_kind = extToIntKind(op.d_kind);
- Expr res;
- if (op.isIndexedHelper())
- {
- res =
- d_exprMgr->mkExpr(int_kind, *op.d_expr, *child1.d_expr, *child2.d_expr);
- }
- else
- {
- res = d_exprMgr->mkExpr(int_kind, *child1.d_expr, *child2.d_expr);
- }
-
- (void)res.getType(true); /* kick off type checking */
- return Term(this, res);
- CVC4_API_SOLVER_TRY_CATCH_END;
+ return mkTermHelper(op, std::vector<Term>{child1, child2});
}
Term Solver::mkTerm(Op op, Term child1, Term child2, Term child3) const
{
- CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- CVC4_API_SOLVER_CHECK_OP(op);
- CVC4_API_ARG_CHECK_EXPECTED(!child1.isNull(), child1) << "non-null term";
- CVC4_API_ARG_CHECK_EXPECTED(!child2.isNull(), child2) << "non-null term";
- CVC4_API_ARG_CHECK_EXPECTED(!child3.isNull(), child3) << "non-null term";
- CVC4_API_SOLVER_CHECK_TERM(child1);
- CVC4_API_SOLVER_CHECK_TERM(child2);
- CVC4_API_SOLVER_CHECK_TERM(child3);
-
- const CVC4::Kind int_kind = extToIntKind(op.d_kind);
- Expr res;
- if (op.isIndexedHelper())
- {
- res = d_exprMgr->mkExpr(
- int_kind, *op.d_expr, *child1.d_expr, *child2.d_expr, *child3.d_expr);
- }
- else
- {
- res = d_exprMgr->mkExpr(
- int_kind, *child1.d_expr, *child2.d_expr, *child3.d_expr);
- }
-
- (void)res.getType(true); /* kick off type checking */
- return Term(this, res);
-
- CVC4_API_SOLVER_TRY_CATCH_END;
+ return mkTermHelper(op, std::vector<Term>{child1, child2, child3});
}
Term Solver::mkTerm(Op op, const std::vector<Term>& children) const
{
+ return mkTermHelper(op, children);
+}
+
+Term Solver::mkTermHelper(const Op& op, const std::vector<Term>& children) const
+{
+ if (!op.isIndexedHelper())
+ {
+ return mkTermHelper(op.d_kind, children);
+ }
+
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_SOLVER_CHECK_OP(op);
+ checkMkTerm(op.d_kind, children.size());
for (size_t i = 0, size = children.size(); i < size; ++i)
{
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
@@ -3882,16 +4311,12 @@ Term Solver::mkTerm(Op op, const std::vector<Term>& children) const
}
const CVC4::Kind int_kind = extToIntKind(op.d_kind);
- std::vector<Expr> echildren = termVectorToExprs(children);
- Expr res;
- if (op.isIndexedHelper())
- {
- res = d_exprMgr->mkExpr(int_kind, *op.d_expr, echildren);
- }
- else
- {
- res = d_exprMgr->mkExpr(int_kind, echildren);
- }
+ std::vector<Node> echildren = termVectorToNodes(children);
+
+ NodeBuilder<> nb(int_kind);
+ nb << *op.d_node;
+ nb.append(echildren);
+ Node res = nb.constructNode();
(void)res.getType(true); /* kick off type checking */
return Term(this, res);
@@ -3902,10 +4327,11 @@ Term Solver::mkTerm(Op op, const std::vector<Term>& children) const
Term Solver::mkTuple(const std::vector<Sort>& sorts,
const std::vector<Term>& terms) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_CHECK(sorts.size() == terms.size())
<< "Expected the same number of sorts and elements";
- std::vector<CVC4::Expr> args;
+ std::vector<CVC4::Node> args;
for (size_t i = 0, size = sorts.size(); i < size; i++)
{
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
@@ -3914,14 +4340,15 @@ Term Solver::mkTuple(const std::vector<Sort>& sorts,
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
this == sorts[i].d_solver, "child sort", sorts[i], i)
<< "child sort associated to this solver object";
- args.push_back(*(ensureTermSort(terms[i], sorts[i])).d_expr);
+ args.push_back(*(ensureTermSort(terms[i], sorts[i])).d_node);
}
Sort s = mkTupleSort(sorts);
Datatype dt = s.getDatatype();
- Expr res = d_exprMgr->mkExpr(extToIntKind(APPLY_CONSTRUCTOR),
- *dt[0].getConstructorTerm().d_expr,
- args);
+ NodeBuilder<> nb(extToIntKind(APPLY_CONSTRUCTOR));
+ nb << *dt[0].getConstructorTerm().d_node;
+ nb.append(args);
+ Node res = nb.constructNode();
(void)res.getType(true); /* kick off type checking */
return Term(this, res);
@@ -3949,10 +4376,9 @@ Op Solver::mkOp(Kind kind, const std::string& arg) const
Op res;
if (kind == RECORD_UPDATE)
{
- res = Op(
- this,
- kind,
- *mkValHelper<CVC4::RecordUpdate>(CVC4::RecordUpdate(arg)).d_expr.get());
+ res = Op(this,
+ kind,
+ *mkValHelper<CVC4::RecordUpdate>(CVC4::RecordUpdate(arg)).d_node);
}
else
{
@@ -3964,7 +4390,7 @@ Op Solver::mkOp(Kind kind, const std::string& arg) const
res = Op(this,
kind,
*mkValHelper<CVC4::Divisible>(CVC4::Divisible(CVC4::Integer(arg)))
- .d_expr.get());
+ .d_node);
}
return res;
@@ -3980,81 +4406,78 @@ Op Solver::mkOp(Kind kind, uint32_t arg) const
switch (kind)
{
case DIVISIBLE:
- res =
- Op(this,
- kind,
- *mkValHelper<CVC4::Divisible>(CVC4::Divisible(arg)).d_expr.get());
+ res = Op(this,
+ kind,
+ *mkValHelper<CVC4::Divisible>(CVC4::Divisible(arg)).d_node);
break;
case BITVECTOR_REPEAT:
res = Op(this,
kind,
- *mkValHelper<CVC4::BitVectorRepeat>(CVC4::BitVectorRepeat(arg))
- .d_expr.get());
+ mkValHelper<CVC4::BitVectorRepeat>(CVC4::BitVectorRepeat(arg))
+ .d_node->toExpr());
break;
case BITVECTOR_ZERO_EXTEND:
res = Op(this,
kind,
*mkValHelper<CVC4::BitVectorZeroExtend>(
CVC4::BitVectorZeroExtend(arg))
- .d_expr.get());
+ .d_node);
break;
case BITVECTOR_SIGN_EXTEND:
res = Op(this,
kind,
*mkValHelper<CVC4::BitVectorSignExtend>(
CVC4::BitVectorSignExtend(arg))
- .d_expr.get());
+ .d_node);
break;
case BITVECTOR_ROTATE_LEFT:
res = Op(this,
kind,
*mkValHelper<CVC4::BitVectorRotateLeft>(
CVC4::BitVectorRotateLeft(arg))
- .d_expr.get());
+ .d_node);
break;
case BITVECTOR_ROTATE_RIGHT:
res = Op(this,
kind,
*mkValHelper<CVC4::BitVectorRotateRight>(
CVC4::BitVectorRotateRight(arg))
- .d_expr.get());
+ .d_node);
break;
case INT_TO_BITVECTOR:
- res = Op(this,
- kind,
- *mkValHelper<CVC4::IntToBitVector>(CVC4::IntToBitVector(arg))
- .d_expr.get());
+ res = Op(
+ this,
+ kind,
+ *mkValHelper<CVC4::IntToBitVector>(CVC4::IntToBitVector(arg)).d_node);
break;
case IAND:
- res = Op(this,
- kind,
- *mkValHelper<CVC4::IntAnd>(CVC4::IntAnd(arg)).d_expr.get());
+ res =
+ Op(this, kind, *mkValHelper<CVC4::IntAnd>(CVC4::IntAnd(arg)).d_node);
break;
case FLOATINGPOINT_TO_UBV:
res = Op(
this,
kind,
*mkValHelper<CVC4::FloatingPointToUBV>(CVC4::FloatingPointToUBV(arg))
- .d_expr.get());
+ .d_node);
break;
case FLOATINGPOINT_TO_SBV:
res = Op(
this,
kind,
*mkValHelper<CVC4::FloatingPointToSBV>(CVC4::FloatingPointToSBV(arg))
- .d_expr.get());
+ .d_node);
break;
case TUPLE_UPDATE:
- res = Op(
- this,
- kind,
- *mkValHelper<CVC4::TupleUpdate>(CVC4::TupleUpdate(arg)).d_expr.get());
- break;
- case REGEXP_REPEAT:
res = Op(this,
kind,
- *mkValHelper<CVC4::RegExpRepeat>(CVC4::RegExpRepeat(arg))
- .d_expr.get());
+ *mkValHelper<CVC4::TupleUpdate>(CVC4::TupleUpdate(arg)).d_node);
+ break;
+ case REGEXP_REPEAT:
+ res =
+ Op(this,
+ kind,
+ *mkValHelper<CVC4::RegExpRepeat>(CVC4::RegExpRepeat(arg)).d_node);
break;
default:
CVC4_API_KIND_CHECK_EXPECTED(false, kind)
@@ -4079,55 +4502,55 @@ Op Solver::mkOp(Kind kind, uint32_t arg1, uint32_t arg2) const
kind,
*mkValHelper<CVC4::BitVectorExtract>(
CVC4::BitVectorExtract(arg1, arg2))
- .d_expr.get());
+ .d_node);
break;
case FLOATINGPOINT_TO_FP_IEEE_BITVECTOR:
res = Op(this,
kind,
*mkValHelper<CVC4::FloatingPointToFPIEEEBitVector>(
CVC4::FloatingPointToFPIEEEBitVector(arg1, arg2))
- .d_expr.get());
+ .d_node);
break;
case FLOATINGPOINT_TO_FP_FLOATINGPOINT:
res = Op(this,
kind,
*mkValHelper<CVC4::FloatingPointToFPFloatingPoint>(
CVC4::FloatingPointToFPFloatingPoint(arg1, arg2))
- .d_expr.get());
+ .d_node);
break;
case FLOATINGPOINT_TO_FP_REAL:
res = Op(this,
kind,
*mkValHelper<CVC4::FloatingPointToFPReal>(
CVC4::FloatingPointToFPReal(arg1, arg2))
- .d_expr.get());
+ .d_node);
break;
case FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR:
res = Op(this,
kind,
*mkValHelper<CVC4::FloatingPointToFPSignedBitVector>(
CVC4::FloatingPointToFPSignedBitVector(arg1, arg2))
- .d_expr.get());
+ .d_node);
break;
case FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR:
res = Op(this,
kind,
*mkValHelper<CVC4::FloatingPointToFPUnsignedBitVector>(
CVC4::FloatingPointToFPUnsignedBitVector(arg1, arg2))
- .d_expr.get());
+ .d_node);
break;
case FLOATINGPOINT_TO_FP_GENERIC:
res = Op(this,
kind,
*mkValHelper<CVC4::FloatingPointToFPGeneric>(
CVC4::FloatingPointToFPGeneric(arg1, arg2))
- .d_expr.get());
+ .d_node);
break;
case REGEXP_LOOP:
- res = Op(this,
- kind,
- *mkValHelper<CVC4::RegExpLoop>(CVC4::RegExpLoop(arg1, arg2))
- .d_expr.get());
+ res = Op(
+ this,
+ kind,
+ *mkValHelper<CVC4::RegExpLoop>(CVC4::RegExpLoop(arg1, arg2)).d_node);
break;
default:
CVC4_API_KIND_CHECK_EXPECTED(false, kind)
@@ -4145,10 +4568,11 @@ Op Solver::mkOp(Kind kind, uint32_t arg1, uint32_t arg2) const
Term Solver::simplify(const Term& term)
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
+ CVC4::ExprManagerScope exmgrs(*(d_exprMgr.get()));
CVC4_API_ARG_CHECK_NOT_NULL(term);
CVC4_API_SOLVER_CHECK_TERM(term);
- return Term(this, d_smtEngine->simplify(*term.d_expr));
+ return Term(this, d_smtEngine->simplify(term.d_node->toExpr()));
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -4164,7 +4588,7 @@ Result Solver::checkEntailed(Term term) const
CVC4_API_ARG_CHECK_NOT_NULL(term);
CVC4_API_SOLVER_CHECK_TERM(term);
- CVC4::Result r = d_smtEngine->checkEntailed(*term.d_expr);
+ CVC4::Result r = d_smtEngine->checkEntailed(*term.d_node);
return Result(r);
CVC4_API_SOLVER_TRY_CATCH_END;
@@ -4184,7 +4608,7 @@ Result Solver::checkEntailed(const std::vector<Term>& terms) const
CVC4_API_ARG_CHECK_NOT_NULL(term);
}
- std::vector<Expr> exprs = termVectorToExprs(terms);
+ std::vector<Node> exprs = termVectorToNodes(terms);
CVC4::Result r = d_smtEngine->checkEntailed(exprs);
return Result(r);
@@ -4202,7 +4626,7 @@ void Solver::assertFormula(Term term) const
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_SOLVER_CHECK_TERM(term);
CVC4_API_ARG_CHECK_NOT_NULL(term);
- d_smtEngine->assertFormula(Node::fromExpr(*term.d_expr));
+ d_smtEngine->assertFormula(*term.d_node);
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -4234,7 +4658,7 @@ Result Solver::checkSatAssuming(Term assumption) const
<< "Cannot make multiple queries unless incremental solving is enabled "
"(try --incremental)";
CVC4_API_SOLVER_CHECK_TERM(assumption);
- CVC4::Result r = d_smtEngine->checkSat(*assumption.d_expr);
+ CVC4::Result r = d_smtEngine->checkSat(*assumption.d_node);
return Result(r);
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -4255,7 +4679,7 @@ Result Solver::checkSatAssuming(const std::vector<Term>& assumptions) const
CVC4_API_SOLVER_CHECK_TERM(term);
CVC4_API_ARG_CHECK_NOT_NULL(term);
}
- std::vector<Expr> eassumptions = termVectorToExprs(assumptions);
+ std::vector<Node> eassumptions = termVectorToNodes(assumptions);
CVC4::Result r = d_smtEngine->checkSat(eassumptions);
return Result(r);
CVC4_API_SOLVER_TRY_CATCH_END;
@@ -4281,7 +4705,7 @@ Sort Solver::declareDatatype(
<< "datatype constructor declaration associated to this solver object";
dtdecl.addConstructor(ctors[i]);
}
- return Sort(this, d_exprMgr->mkDatatypeType(*dtdecl.d_dtype));
+ return Sort(this, getNodeManager()->mkDatatypeType(*dtdecl.d_dtype));
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -4306,13 +4730,13 @@ Term Solver::declareFun(const std::string& symbol,
<< "first-class sort as function codomain sort";
CVC4_API_SOLVER_CHECK_SORT(sort);
Assert(!sort.isFunction()); /* A function sort is not first-class. */
- Type type = *sort.d_type;
+ TypeNode type = *sort.d_type;
if (!sorts.empty())
{
- std::vector<Type> types = sortVectorToTypes(sorts);
- type = d_exprMgr->mkFunctionType(types, type);
+ std::vector<TypeNode> types = sortVectorToTypeNodes(sorts);
+ type = getNodeManager()->mkFunctionType(types, type);
}
- return Term(this, d_exprMgr->mkVar(symbol, type));
+ return Term(this, d_exprMgr->mkVar(symbol, type.toType()));
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -4322,8 +4746,11 @@ Term Solver::declareFun(const std::string& symbol,
Sort Solver::declareSort(const std::string& symbol, uint32_t arity) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- if (arity == 0) return Sort(this, d_exprMgr->mkSort(symbol));
- return Sort(this, d_exprMgr->mkSortConstructor(symbol, arity));
+ if (arity == 0)
+ {
+ return Sort(this, getNodeManager()->mkSort(symbol));
+ }
+ return Sort(this, getNodeManager()->mkSortConstructor(symbol, arity));
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -4339,19 +4766,19 @@ Term Solver::defineFun(const std::string& symbol,
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_ARG_CHECK_EXPECTED(sort.isFirstClass(), sort)
<< "first-class sort as codomain sort for function sort";
- std::vector<Type> domain_types;
+ std::vector<TypeNode> domain_types;
for (size_t i = 0, size = bound_vars.size(); i < size; ++i)
{
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
this == bound_vars[i].d_solver, "bound variable", bound_vars[i], i)
<< "bound variable associated to this solver object";
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
- bound_vars[i].d_expr->getKind() == CVC4::Kind::BOUND_VARIABLE,
+ bound_vars[i].d_node->getKind() == CVC4::Kind::BOUND_VARIABLE,
"bound variable",
bound_vars[i],
i)
<< "a bound variable";
- CVC4::Type t = bound_vars[i].d_expr->getType();
+ CVC4::TypeNode t = bound_vars[i].d_node->getType();
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
t.isFirstClass(), "sort of parameter", bound_vars[i], i)
<< "first-class sort of parameter of defined function";
@@ -4361,14 +4788,15 @@ Term Solver::defineFun(const std::string& symbol,
CVC4_API_CHECK(sort == term.getSort())
<< "Invalid sort of function body '" << term << "', expected '" << sort
<< "'";
- Type type = *sort.d_type;
+ NodeManager* nm = getNodeManager();
+ TypeNode type = *sort.d_type;
if (!domain_types.empty())
{
- type = d_exprMgr->mkFunctionType(domain_types, type);
+ type = nm->mkFunctionType(domain_types, type);
}
- Expr fun = d_exprMgr->mkVar(symbol, type);
- std::vector<Expr> ebound_vars = termVectorToExprs(bound_vars);
- d_smtEngine->defineFunction(fun, ebound_vars, *term.d_expr, global);
+ Node fun = Node::fromExpr(d_exprMgr->mkVar(symbol, type.toType()));
+ std::vector<Node> ebound_vars = termVectorToNodes(bound_vars);
+ d_smtEngine->defineFunction(fun, ebound_vars, *term.d_node, global);
return Term(this, fun);
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -4392,7 +4820,7 @@ Term Solver::defineFun(Term fun,
this == bound_vars[i].d_solver, "bound variable", bound_vars[i], i)
<< "bound variable associated to this solver object";
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
- bound_vars[i].d_expr->getKind() == CVC4::Kind::BOUND_VARIABLE,
+ bound_vars[i].d_node->getKind() == CVC4::Kind::BOUND_VARIABLE,
"bound variable",
bound_vars[i],
i)
@@ -4417,8 +4845,8 @@ Term Solver::defineFun(Term fun,
CVC4_API_SOLVER_CHECK_TERM(term);
- std::vector<Expr> ebound_vars = termVectorToExprs(bound_vars);
- d_smtEngine->defineFunction(*fun.d_expr, ebound_vars, *term.d_expr, global);
+ std::vector<Node> ebound_vars = termVectorToNodes(bound_vars);
+ d_smtEngine->defineFunction(*fun.d_node, ebound_vars, *term.d_node, global);
return fun;
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -4432,6 +4860,7 @@ Term Solver::defineFunRec(const std::string& symbol,
Term term,
bool global) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_CHECK(d_smtEngine->getUserLogicInfo().isQuantified())
@@ -4444,19 +4873,19 @@ Term Solver::defineFunRec(const std::string& symbol,
CVC4_API_ARG_CHECK_EXPECTED(sort.isFirstClass(), sort)
<< "first-class sort as function codomain sort";
Assert(!sort.isFunction()); /* A function sort is not first-class. */
- std::vector<Type> domain_types;
+ std::vector<TypeNode> domain_types;
for (size_t i = 0, size = bound_vars.size(); i < size; ++i)
{
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
this == bound_vars[i].d_solver, "bound variable", bound_vars[i], i)
<< "bound variable associated to this solver object";
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
- bound_vars[i].d_expr->getKind() == CVC4::Kind::BOUND_VARIABLE,
+ bound_vars[i].d_node->getKind() == CVC4::Kind::BOUND_VARIABLE,
"bound variable",
bound_vars[i],
i)
<< "a bound variable";
- CVC4::Type t = bound_vars[i].d_expr->getType();
+ CVC4::TypeNode t = bound_vars[i].d_node->getType();
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
t.isFirstClass(), "sort of parameter", bound_vars[i], i)
<< "first-class sort of parameter of defined function";
@@ -4467,14 +4896,16 @@ Term Solver::defineFunRec(const std::string& symbol,
<< "Invalid sort of function body '" << term << "', expected '" << sort
<< "'";
CVC4_API_SOLVER_CHECK_TERM(term);
- Type type = *sort.d_type;
+ NodeManager* nm = getNodeManager();
+ TypeNode type = *sort.d_type;
if (!domain_types.empty())
{
- type = d_exprMgr->mkFunctionType(domain_types, type);
+ type = nm->mkFunctionType(domain_types, type);
}
- Expr fun = d_exprMgr->mkVar(symbol, type);
- std::vector<Expr> ebound_vars = termVectorToExprs(bound_vars);
- d_smtEngine->defineFunctionRec(fun, ebound_vars, *term.d_expr, global);
+ Node fun = Node::fromExpr(d_exprMgr->mkVar(symbol, type.toType()));
+ std::vector<Node> ebound_vars = termVectorToNodes(bound_vars);
+ d_smtEngine->defineFunctionRec(
+ fun, ebound_vars, term.d_node->toExpr(), global);
return Term(this, fun);
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -4484,6 +4915,7 @@ Term Solver::defineFunRec(Term fun,
Term term,
bool global) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_CHECK(d_smtEngine->getUserLogicInfo().isQuantified())
@@ -4505,7 +4937,7 @@ Term Solver::defineFunRec(Term fun,
this == bound_vars[i].d_solver, "bound variable", bound_vars[i], i)
<< "bound variable associated to this solver object";
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
- bound_vars[i].d_expr->getKind() == CVC4::Kind::BOUND_VARIABLE,
+ bound_vars[i].d_node->getKind() == CVC4::Kind::BOUND_VARIABLE,
"bound variable",
bound_vars[i],
i)
@@ -4529,9 +4961,9 @@ Term Solver::defineFunRec(Term fun,
}
CVC4_API_SOLVER_CHECK_TERM(term);
- std::vector<Expr> ebound_vars = termVectorToExprs(bound_vars);
+ std::vector<Node> ebound_vars = termVectorToNodes(bound_vars);
d_smtEngine->defineFunctionRec(
- *fun.d_expr, ebound_vars, *term.d_expr, global);
+ *fun.d_node, ebound_vars, *term.d_node, global);
return fun;
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -4544,6 +4976,7 @@ void Solver::defineFunsRec(const std::vector<Term>& funs,
const std::vector<Term>& terms,
bool global) const
{
+ NodeManagerScope scope(getNodeManager());
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_CHECK(d_smtEngine->getUserLogicInfo().isQuantified())
@@ -4581,7 +5014,7 @@ void Solver::defineFunsRec(const std::vector<Term>& funs,
this == bvars[k].d_solver, "bound variable", bvars[k], k)
<< "bound variable associated to this solver object";
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
- bvars[k].d_expr->getKind() == CVC4::Kind::BOUND_VARIABLE,
+ bvars[k].d_node->getKind() == CVC4::Kind::BOUND_VARIABLE,
"bound variable",
bvars[k],
k)
@@ -4606,13 +5039,13 @@ void Solver::defineFunsRec(const std::vector<Term>& funs,
<< "function or nullary symbol";
}
}
- std::vector<Expr> efuns = termVectorToExprs(funs);
- std::vector<std::vector<Expr>> ebound_vars;
+ std::vector<Node> efuns = termVectorToNodes(funs);
+ std::vector<std::vector<Node>> ebound_vars;
for (const auto& v : bound_vars)
{
- ebound_vars.push_back(termVectorToExprs(v));
+ ebound_vars.push_back(termVectorToNodes(v));
}
- std::vector<Expr> exprs = termVectorToExprs(terms);
+ std::vector<Node> exprs = termVectorToNodes(terms);
d_smtEngine->defineFunctionsRec(efuns, ebound_vars, exprs, global);
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -4631,12 +5064,12 @@ void Solver::echo(std::ostream& out, const std::string& str) const
std::vector<Term> Solver::getAssertions(void) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- std::vector<Expr> assertions = d_smtEngine->getAssertions();
+ std::vector<Node> assertions = d_smtEngine->getAssertions();
/* Can not use
* return std::vector<Term>(assertions.begin(), assertions.end());
* here since constructor is private */
std::vector<Term> res;
- for (const Expr& e : assertions)
+ for (const Node& e : assertions)
{
res.push_back(Term(this, e));
}
@@ -4645,26 +5078,6 @@ std::vector<Term> Solver::getAssertions(void) const
}
/**
- * ( get-assignment )
- */
-std::vector<std::pair<Term, Term>> Solver::getAssignment(void) const
-{
- CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- CVC4::ExprManagerScope exmgrs(*(d_exprMgr.get()));
- CVC4_API_CHECK(d_smtEngine->getOptions()[options::produceAssignments])
- << "Cannot get assignment unless assignment generation is enabled "
- "(try --produce-assignments)";
- std::vector<std::pair<Expr, Expr>> assignment = d_smtEngine->getAssignment();
- std::vector<std::pair<Term, Term>> res;
- for (const auto& p : assignment)
- {
- res.emplace_back(Term(this, p.first), Term(this, p.second));
- }
- return res;
- CVC4_API_SOLVER_TRY_CATCH_END;
-}
-
-/**
* ( get-info <info_flag> )
*/
std::string Solver::getInfo(const std::string& flag) const
@@ -4701,18 +5114,17 @@ std::vector<Term> Solver::getUnsatAssumptions(void) const
CVC4_API_CHECK(d_smtEngine->getOptions()[options::unsatAssumptions])
<< "Cannot get unsat assumptions unless explicitly enabled "
"(try --produce-unsat-assumptions)";
- CVC4_API_CHECK(d_smtEngine->getSmtMode()
- == SmtEngine::SmtMode::SMT_MODE_UNSAT)
+ CVC4_API_CHECK(d_smtEngine->getSmtMode() == SmtMode::UNSAT)
<< "Cannot get unsat assumptions unless in unsat mode.";
- std::vector<Expr> uassumptions = d_smtEngine->getUnsatAssumptions();
+ std::vector<Node> uassumptions = d_smtEngine->getUnsatAssumptions();
/* Can not use
* return std::vector<Term>(uassumptions.begin(), uassumptions.end());
* here since constructor is private */
std::vector<Term> res;
- for (const Expr& e : uassumptions)
+ for (const Node& e : uassumptions)
{
- res.push_back(Term(this, e));
+ res.push_back(Term(this, e.toExpr()));
}
return res;
CVC4_API_SOLVER_TRY_CATCH_END;
@@ -4728,15 +5140,14 @@ std::vector<Term> Solver::getUnsatCore(void) const
CVC4_API_CHECK(d_smtEngine->getOptions()[options::unsatCores])
<< "Cannot get unsat core unless explicitly enabled "
"(try --produce-unsat-cores)";
- CVC4_API_CHECK(d_smtEngine->getSmtMode()
- == SmtEngine::SmtMode::SMT_MODE_UNSAT)
+ CVC4_API_RECOVERABLE_CHECK(d_smtEngine->getSmtMode() == SmtMode::UNSAT)
<< "Cannot get unsat core unless in unsat mode.";
UnsatCore core = d_smtEngine->getUnsatCore();
/* Can not use
* return std::vector<Term>(core.begin(), core.end());
* here since constructor is private */
std::vector<Term> res;
- for (const Expr& e : core)
+ for (const Node& e : core)
{
res.push_back(Term(this, e));
}
@@ -4751,7 +5162,7 @@ Term Solver::getValue(Term term) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_SOLVER_CHECK_TERM(term);
- return Term(this, d_smtEngine->getValue(*term.d_expr));
+ return getValueHelper(term);
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -4762,12 +5173,11 @@ std::vector<Term> Solver::getValue(const std::vector<Term>& terms) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4::ExprManagerScope exmgrs(*(d_exprMgr.get()));
- CVC4_API_CHECK(d_smtEngine->getOptions()[options::produceModels])
+ CVC4_API_RECOVERABLE_CHECK(d_smtEngine->getOptions()[options::produceModels])
<< "Cannot get value unless model generation is enabled "
"(try --produce-models)";
- CVC4_API_CHECK(d_smtEngine->getSmtMode()
- != SmtEngine::SmtMode::SMT_MODE_UNSAT)
- << "Cannot get value when in unsat mode.";
+ CVC4_API_RECOVERABLE_CHECK(d_smtEngine->isSmtModeSat())
+ << "Cannot get value unless after a SAT or unknown response.";
std::vector<Term> res;
for (size_t i = 0, n = terms.size(); i < n; ++i)
{
@@ -4775,12 +5185,45 @@ std::vector<Term> Solver::getValue(const std::vector<Term>& terms) const
this == terms[i].d_solver, "term", terms[i], i)
<< "term associated to this solver object";
/* Can not use emplace_back here since constructor is private. */
- res.push_back(Term(this, d_smtEngine->getValue(*terms[i].d_expr)));
+ res.push_back(getValueHelper(terms[i]));
}
return res;
CVC4_API_SOLVER_TRY_CATCH_END;
}
+Term Solver::getQuantifierElimination(api::Term q) const
+{
+ CVC4_API_SOLVER_TRY_CATCH_BEGIN;
+ CVC4_API_ARG_CHECK_NOT_NULL(q);
+ CVC4_API_SOLVER_CHECK_TERM(q);
+ CVC4::ExprManagerScope exmgrs(*(d_exprMgr.get()));
+ return Term(this,
+ d_smtEngine->getQuantifierElimination(q.getNode(), true, true));
+ CVC4_API_SOLVER_TRY_CATCH_END;
+}
+
+Term Solver::getQuantifierEliminationDisjunct(api::Term q) const
+{
+ CVC4_API_SOLVER_TRY_CATCH_BEGIN;
+ CVC4_API_ARG_CHECK_NOT_NULL(q);
+ CVC4_API_SOLVER_CHECK_TERM(q);
+ CVC4::ExprManagerScope exmgrs(*(d_exprMgr.get()));
+ return Term(
+ this, d_smtEngine->getQuantifierElimination(q.getNode(), false, true));
+ CVC4_API_SOLVER_TRY_CATCH_END;
+}
+
+void Solver::declareSeparationHeap(api::Sort locSort, api::Sort dataSort) const
+{
+ CVC4_API_SOLVER_TRY_CATCH_BEGIN;
+ CVC4_API_CHECK(
+ d_smtEngine->getLogicInfo().isTheoryEnabled(theory::THEORY_SEP))
+ << "Cannot obtain separation logic expressions if not using the "
+ "separation logic theory.";
+ d_smtEngine->declareSepHeap(locSort.getTypeNode(), dataSort.getTypeNode());
+ CVC4_API_SOLVER_TRY_CATCH_END;
+}
+
Term Solver::getSeparationHeap() const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
@@ -4792,16 +5235,8 @@ Term Solver::getSeparationHeap() const
CVC4_API_CHECK(d_smtEngine->getOptions()[options::produceModels])
<< "Cannot get separation heap term unless model generation is enabled "
"(try --produce-models)";
- CVC4_API_CHECK(d_smtEngine->getSmtMode()
- != SmtEngine::SmtMode::SMT_MODE_UNSAT)
- << "Cannot get separtion heap term when in unsat mode.";
-
- theory::TheoryModel* m =
- d_smtEngine->getAvailableModel("get separation logic heap and nil");
- Expr heap, nil;
- bool hasHeapModel = m->getHeapModel(heap, nil);
- CVC4_API_CHECK(hasHeapModel)
- << "Failed to obtain heap term from theory model.";
+ CVC4_API_RECOVERABLE_CHECK(d_smtEngine->isSmtModeSat())
+ << "Can only get separtion heap term after sat or unknown response.";
return Term(this, d_smtEngine->getSepHeapExpr());
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -4817,17 +5252,9 @@ Term Solver::getSeparationNilTerm() const
CVC4_API_CHECK(d_smtEngine->getOptions()[options::produceModels])
<< "Cannot get separation nil term unless model generation is enabled "
"(try --produce-models)";
- CVC4_API_CHECK(d_smtEngine->getSmtMode()
- != SmtEngine::SmtMode::SMT_MODE_UNSAT)
- << "Cannot get separtion nil term when in unsat mode.";
-
- theory::TheoryModel* m =
- d_smtEngine->getAvailableModel("get separation logic heap and nil");
- Expr heap, nil;
- bool hasHeapModel = m->getHeapModel(heap, nil);
- CVC4_API_CHECK(hasHeapModel)
- << "Failed to obtain nil term from theory model.";
- return Term(this, nil);
+ CVC4_API_RECOVERABLE_CHECK(d_smtEngine->isSmtModeSat())
+ << "Can only get separtion nil term after sat or unknown response.";
+ return Term(this, d_smtEngine->getSepNilExpr());
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -4854,39 +5281,103 @@ void Solver::pop(uint32_t nscopes) const
bool Solver::getInterpolant(Term conj, Term& output) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- Expr result;
- bool success = d_smtEngine->getInterpol(*conj.d_expr, result);
- if (success) {
- output = Term(output.d_solver, result);
+ CVC4::ExprManagerScope exmgrs(*(d_exprMgr.get()));
+ Node result;
+ bool success = d_smtEngine->getInterpol(*conj.d_node, result);
+ if (success)
+ {
+ output = Term(this, result);
+ }
+ return success;
+ CVC4_API_SOLVER_TRY_CATCH_END;
+}
+
+bool Solver::getInterpolant(Term conj, Grammar& g, Term& output) const
+{
+ CVC4_API_SOLVER_TRY_CATCH_BEGIN;
+ CVC4::ExprManagerScope exmgrs(*(d_exprMgr.get()));
+ Node result;
+ bool success =
+ d_smtEngine->getInterpol(*conj.d_node, *g.resolve().d_type, result);
+ if (success)
+ {
+ output = Term(this, result);
+ }
+ return success;
+ CVC4_API_SOLVER_TRY_CATCH_END;
+}
+
+bool Solver::getAbduct(Term conj, Term& output) const
+{
+ CVC4_API_SOLVER_TRY_CATCH_BEGIN;
+ CVC4::ExprManagerScope exmgrs(*(d_exprMgr.get()));
+ Node result;
+ bool success = d_smtEngine->getAbduct(*conj.d_node, result);
+ if (success)
+ {
+ output = Term(this, result);
}
return success;
CVC4_API_SOLVER_TRY_CATCH_END;
}
-bool Solver::getInterpolant(Term conj, const Type& gtype, Term& output) const
+bool Solver::getAbduct(Term conj, Grammar& g, Term& output) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
- Expr result;
- bool success = d_smtEngine->getInterpol(*conj.d_expr, gtype, result);
+ CVC4::ExprManagerScope exmgrs(*(d_exprMgr.get()));
+ Node result;
+ bool success =
+ d_smtEngine->getAbduct(*conj.d_node, *g.resolve().d_type, result);
if (success)
{
- output = Term(output.d_solver, result);
+ output = Term(this, result);
}
return success;
CVC4_API_SOLVER_TRY_CATCH_END;
}
-void Solver::printModel(std::ostream& out) const
+void Solver::blockModel() const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4::ExprManagerScope exmgrs(*(d_exprMgr.get()));
CVC4_API_CHECK(d_smtEngine->getOptions()[options::produceModels])
<< "Cannot get value unless model generation is enabled "
"(try --produce-models)";
- CVC4_API_CHECK(d_smtEngine->getSmtMode()
- != SmtEngine::SmtMode::SMT_MODE_UNSAT)
- << "Cannot get value when in unsat mode.";
- out << *d_smtEngine->getModel();
+ CVC4_API_RECOVERABLE_CHECK(d_smtEngine->isSmtModeSat())
+ << "Can only block model after sat or unknown response.";
+ d_smtEngine->blockModel();
+ CVC4_API_SOLVER_TRY_CATCH_END;
+}
+
+void Solver::blockModelValues(const std::vector<Term>& terms) const
+{
+ CVC4_API_SOLVER_TRY_CATCH_BEGIN;
+ CVC4_API_CHECK(d_smtEngine->getOptions()[options::produceModels])
+ << "Cannot get value unless model generation is enabled "
+ "(try --produce-models)";
+ CVC4_API_RECOVERABLE_CHECK(d_smtEngine->isSmtModeSat())
+ << "Can only block model values after sat or unknown response.";
+ CVC4_API_ARG_SIZE_CHECK_EXPECTED(!terms.empty(), terms)
+ << "a non-empty set of terms";
+ for (size_t i = 0, tsize = terms.size(); i < tsize; ++i)
+ {
+ CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
+ !terms[i].isNull(), "term", terms[i], i)
+ << "a non-null term";
+ CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
+ this == terms[i].d_solver, "term", terms[i], i)
+ << "a term associated to this solver object";
+ }
+ CVC4::ExprManagerScope exmgrs(*(d_exprMgr.get()));
+ d_smtEngine->blockModelValues(termVectorToNodes(terms));
+ CVC4_API_SOLVER_TRY_CATCH_END;
+}
+
+void Solver::printInstantiations(std::ostream& out) const
+{
+ CVC4_API_SOLVER_TRY_CATCH_BEGIN;
+ CVC4::ExprManagerScope exmgrs(*(d_exprMgr.get()));
+ d_smtEngine->printInstantiations(out);
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -4995,7 +5486,7 @@ Term Solver::ensureTermSort(const Term& term, const Sort& sort) const
// in the theory.
res = Term(this,
d_exprMgr->mkExpr(extToIntKind(DIVISION),
- *res.d_expr,
+ res.d_node->toExpr(),
d_exprMgr->mkConst(CVC4::Rational(1))));
}
Assert(res.getSort() == sort);
@@ -5008,7 +5499,7 @@ Term Solver::mkSygusVar(Sort sort, const std::string& symbol) const
CVC4_API_ARG_CHECK_NOT_NULL(sort);
CVC4_API_SOLVER_CHECK_SORT(sort);
- Expr res = d_exprMgr->mkBoundVar(symbol, *sort.d_type);
+ Node res = getNodeManager()->mkBoundVar(symbol, *sort.d_type);
(void)res.getType(true); /* kick off type checking */
d_smtEngine->declareSygusVar(symbol, res, *sort.d_type);
@@ -5023,7 +5514,7 @@ Grammar Solver::mkSygusGrammar(const std::vector<Term>& boundVars,
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_ARG_SIZE_CHECK_EXPECTED(!ntSymbols.empty(), ntSymbols)
- << "non-empty vector";
+ << "a non-empty vector";
for (size_t i = 0, n = boundVars.size(); i < n; ++i)
{
@@ -5031,30 +5522,30 @@ Grammar Solver::mkSygusGrammar(const std::vector<Term>& boundVars,
this == boundVars[i].d_solver, "bound variable", boundVars[i], i)
<< "bound variable associated to this solver object";
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
- boundVars[i].d_expr->getKind() == CVC4::Kind::BOUND_VARIABLE,
+ !boundVars[i].isNull(), "bound variable", boundVars[i], i)
+ << "a non-null term";
+ CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
+ boundVars[i].d_node->getKind() == CVC4::Kind::BOUND_VARIABLE,
"bound variable",
boundVars[i],
i)
<< "a bound variable";
- CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
- !boundVars[i].isNull(), "parameter term", boundVars[i], i)
- << "non-null term";
}
for (size_t i = 0, n = ntSymbols.size(); i < n; ++i)
{
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
- this == ntSymbols[i].d_solver, "term", ntSymbols[i], i)
+ this == ntSymbols[i].d_solver, "non-terminal", ntSymbols[i], i)
<< "term associated to this solver object";
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
- ntSymbols[i].d_expr->getKind() == CVC4::Kind::BOUND_VARIABLE,
- "bound variable",
+ !ntSymbols[i].isNull(), "non-terminal", ntSymbols[i], i)
+ << "a non-null term";
+ CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
+ ntSymbols[i].d_node->getKind() == CVC4::Kind::BOUND_VARIABLE,
+ "non-terminal",
ntSymbols[i],
i)
<< "a bound variable";
- CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
- !ntSymbols[i].isNull(), "parameter term", ntSymbols[i], i)
- << "non-null term";
}
return Grammar(this, boundVars, ntSymbols);
@@ -5080,7 +5571,7 @@ Term Solver::synthInv(const std::string& symbol,
const std::vector<Term>& boundVars) const
{
return synthFunHelper(
- symbol, boundVars, Sort(this, d_exprMgr->booleanType()), true);
+ symbol, boundVars, Sort(this, getNodeManager()->booleanType()), true);
}
Term Solver::synthInv(const std::string& symbol,
@@ -5088,7 +5579,7 @@ Term Solver::synthInv(const std::string& symbol,
Grammar& g) const
{
return synthFunHelper(
- symbol, boundVars, Sort(this, d_exprMgr->booleanType()), true, &g);
+ symbol, boundVars, Sort(this, getNodeManager()->booleanType()), true, &g);
}
Term Solver::synthFunHelper(const std::string& symbol,
@@ -5100,47 +5591,43 @@ Term Solver::synthFunHelper(const std::string& symbol,
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
CVC4_API_ARG_CHECK_NOT_NULL(sort);
- CVC4_API_ARG_CHECK_EXPECTED(sort.d_type->isFirstClass(), sort)
- << "first-class sort as codomain sort for function sort";
-
- std::vector<Type> varTypes;
+ std::vector<TypeNode> varTypes;
for (size_t i = 0, n = boundVars.size(); i < n; ++i)
{
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
this == boundVars[i].d_solver, "bound variable", boundVars[i], i)
<< "bound variable associated to this solver object";
CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
- boundVars[i].d_expr->getKind() == CVC4::Kind::BOUND_VARIABLE,
+ !boundVars[i].isNull(), "bound variable", boundVars[i], i)
+ << "a non-null term";
+ CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
+ boundVars[i].d_node->getKind() == CVC4::Kind::BOUND_VARIABLE,
"bound variable",
boundVars[i],
i)
<< "a bound variable";
- CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
- !boundVars[i].isNull(), "parameter term", boundVars[i], i)
- << "non-null term";
- varTypes.push_back(boundVars[i].d_expr->getType());
+ varTypes.push_back(boundVars[i].d_node->getType());
}
CVC4_API_SOLVER_CHECK_SORT(sort);
if (g != nullptr)
{
- CVC4_API_CHECK(g->d_ntSyms[0].d_expr->getType() == *sort.d_type)
+ CVC4_API_CHECK(g->d_ntSyms[0].d_node->getType() == *sort.d_type)
<< "Invalid Start symbol for Grammar g, Expected Start's sort to be "
- << *sort.d_type;
+ << *sort.d_type << " but found " << g->d_ntSyms[0].d_node->getType();
}
- Type funType = varTypes.empty()
- ? *sort.d_type
- : d_exprMgr->mkFunctionType(varTypes, *sort.d_type);
+ TypeNode funType = varTypes.empty() ? *sort.d_type
+ : getNodeManager()->mkFunctionType(
+ varTypes, *sort.d_type);
- Expr fun = d_exprMgr->mkBoundVar(symbol, funType);
+ Node fun = getNodeManager()->mkBoundVar(symbol, funType);
(void)fun.getType(true); /* kick off type checking */
- d_smtEngine->declareSynthFun(symbol,
- fun,
- g == nullptr ? funType : *g->resolve().d_type,
- isInv,
- termVectorToExprs(boundVars));
+ std::vector<Node> bvns = termVectorToNodes(boundVars);
+
+ d_smtEngine->declareSynthFun(
+ symbol, fun, g == nullptr ? funType : *g->resolve().d_type, isInv, bvns);
return Term(this, fun);
@@ -5150,13 +5637,14 @@ Term Solver::synthFunHelper(const std::string& symbol,
void Solver::addSygusConstraint(Term term) const
{
CVC4_API_SOLVER_TRY_CATCH_BEGIN;
+ NodeManagerScope scope(getNodeManager());
CVC4_API_ARG_CHECK_NOT_NULL(term);
CVC4_API_SOLVER_CHECK_TERM(term);
CVC4_API_ARG_CHECK_EXPECTED(
- term.d_expr->getType() == d_exprMgr->booleanType(), term)
+ term.d_node->getType() == getNodeManager()->booleanType(), term)
<< "boolean term";
- d_smtEngine->assertSygusConstraint(*term.d_expr);
+ d_smtEngine->assertSygusConstraint(*term.d_node);
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -5175,24 +5663,24 @@ void Solver::addSygusInvConstraint(Term inv,
CVC4_API_ARG_CHECK_NOT_NULL(post);
CVC4_API_SOLVER_CHECK_TERM(post);
- CVC4_API_ARG_CHECK_EXPECTED(inv.d_expr->getType().isFunction(), inv)
+ CVC4_API_ARG_CHECK_EXPECTED(inv.d_node->getType().isFunction(), inv)
<< "a function";
- FunctionType invType = inv.d_expr->getType();
+ TypeNode invType = inv.d_node->getType();
CVC4_API_ARG_CHECK_EXPECTED(invType.getRangeType().isBoolean(), inv)
<< "boolean range";
- CVC4_API_CHECK(pre.d_expr->getType() == invType)
+ CVC4_API_CHECK(pre.d_node->getType() == invType)
<< "Expected inv and pre to have the same sort";
- CVC4_API_CHECK(post.d_expr->getType() == invType)
+ CVC4_API_CHECK(post.d_node->getType() == invType)
<< "Expected inv and post to have the same sort";
- const std::vector<Type>& invArgTypes = invType.getArgTypes();
+ const std::vector<TypeNode>& invArgTypes = invType.getArgTypes();
- std::vector<Type> expectedTypes;
- expectedTypes.reserve(2 * invType.getArity() + 1);
+ std::vector<TypeNode> expectedTypes;
+ expectedTypes.reserve(2 * invArgTypes.size() + 1);
for (size_t i = 0, n = invArgTypes.size(); i < 2 * n; i += 2)
{
@@ -5201,13 +5689,13 @@ void Solver::addSygusInvConstraint(Term inv,
}
expectedTypes.push_back(invType.getRangeType());
- FunctionType expectedTransType = d_exprMgr->mkFunctionType(expectedTypes);
+ TypeNode expectedTransType = getNodeManager()->mkFunctionType(expectedTypes);
- CVC4_API_CHECK(trans.d_expr->getType() == expectedTransType)
+ CVC4_API_CHECK(trans.d_node->getType() == expectedTransType)
<< "Expected trans's sort to be " << invType;
d_smtEngine->assertSygusInvConstraint(
- *inv.d_expr, *pre.d_expr, *trans.d_expr, *post.d_expr);
+ *inv.d_node, *pre.d_node, *trans.d_node, *post.d_node);
CVC4_API_SOLVER_TRY_CATCH_END;
}
@@ -5224,12 +5712,12 @@ Term Solver::getSynthSolution(Term term) const
CVC4_API_ARG_CHECK_NOT_NULL(term);
CVC4_API_SOLVER_CHECK_TERM(term);
- std::map<CVC4::Expr, CVC4::Expr> map;
+ std::map<CVC4::Node, CVC4::Node> map;
CVC4_API_CHECK(d_smtEngine->getSynthSolutions(map))
- << "The solver is not in a state immediately preceeded by a "
+ << "The solver is not in a state immediately preceded by a "
"successful call to checkSynth";
- std::map<CVC4::Expr, CVC4::Expr>::const_iterator it = map.find(*term.d_expr);
+ std::map<CVC4::Node, CVC4::Node>::const_iterator it = map.find(*term.d_node);
CVC4_API_CHECK(it != map.cend()) << "Synth solution not found for given term";
@@ -5253,9 +5741,9 @@ std::vector<Term> Solver::getSynthSolutions(
<< "non-null term";
}
- std::map<CVC4::Expr, CVC4::Expr> map;
+ std::map<CVC4::Node, CVC4::Node> map;
CVC4_API_CHECK(d_smtEngine->getSynthSolutions(map))
- << "The solver is not in a state immediately preceeded by a "
+ << "The solver is not in a state immediately preceded by a "
"successful call to checkSynth";
std::vector<Term> synthSolution;
@@ -5263,8 +5751,8 @@ std::vector<Term> Solver::getSynthSolutions(
for (size_t i = 0, n = terms.size(); i < n; ++i)
{
- std::map<CVC4::Expr, CVC4::Expr>::const_iterator it =
- map.find(*terms[i].d_expr);
+ std::map<CVC4::Node, CVC4::Node>::const_iterator it =
+ map.find(*terms[i].d_node);
CVC4_API_CHECK(it != map.cend())
<< "Synth solution not found for term at index " << i;
@@ -5293,6 +5781,15 @@ ExprManager* Solver::getExprManager(void) const { return d_exprMgr.get(); }
* !!! This is only temporarily available until the parser is fully migrated to
* the new API. !!!
*/
+NodeManager* Solver::getNodeManager(void) const
+{
+ return d_exprMgr->getNodeManager();
+}
+
+/**
+ * !!! This is only temporarily available until the parser is fully migrated to
+ * the new API. !!!
+ */
SmtEngine* Solver::getSmtEngine(void) const { return d_smtEngine.get(); }
/**
@@ -5315,22 +5812,42 @@ std::vector<Expr> termVectorToExprs(const std::vector<Term>& terms)
return exprs;
}
+std::vector<Node> termVectorToNodes(const std::vector<Term>& terms)
+{
+ std::vector<Node> res;
+ for (const Term& t : terms)
+ {
+ res.push_back(t.getNode());
+ }
+ return res;
+}
+
std::vector<Type> sortVectorToTypes(const std::vector<Sort>& sorts)
{
std::vector<Type> types;
for (size_t i = 0, ssize = sorts.size(); i < ssize; i++)
{
- types.push_back(sorts[i].getType());
+ types.push_back(sorts[i].getTypeNode().toType());
}
return types;
}
-std::set<Type> sortSetToTypes(const std::set<Sort>& sorts)
+std::vector<TypeNode> sortVectorToTypeNodes(const std::vector<Sort>& sorts)
{
- std::set<Type> types;
+ std::vector<TypeNode> typeNodes;
+ for (const Sort& sort : sorts)
+ {
+ typeNodes.push_back(sort.getTypeNode());
+ }
+ return typeNodes;
+}
+
+std::set<TypeNode> sortSetToTypeNodes(const std::set<Sort>& sorts)
+{
+ std::set<TypeNode> types;
for (const Sort& s : sorts)
{
- types.insert(s.getType());
+ types.insert(s.getTypeNode());
}
return types;
}
@@ -5352,6 +5869,16 @@ std::vector<Sort> typeVectorToSorts(const Solver* slv,
std::vector<Sort> sorts;
for (size_t i = 0, tsize = types.size(); i < tsize; i++)
{
+ sorts.push_back(Sort(slv, TypeNode::fromType(types[i])));
+ }
+ return sorts;
+}
+std::vector<Sort> typeNodeVectorToSorts(const Solver* slv,
+ const std::vector<TypeNode>& types)
+{
+ std::vector<Sort> sorts;
+ for (size_t i = 0, tsize = types.size(); i < tsize; i++)
+ {
sorts.push_back(Sort(slv, types[i]));
}
return sorts;
diff --git a/src/api/cvc4cpp.h b/src/api/cvc4cpp.h
index 91db4dd58..eb55e4007 100644
--- a/src/api/cvc4cpp.h
+++ b/src/api/cvc4cpp.h
@@ -5,7 +5,7 @@
** Aina Niemetz, Andrew Reynolds, Abdalrhman Mohamed
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -36,13 +36,21 @@
namespace CVC4 {
+template <bool ref_count>
+class NodeTemplate;
+typedef NodeTemplate<true> Node;
class Expr;
-class Datatype;
-class DatatypeConstructor;
-class DatatypeConstructorArg;
+class DType;
+class DTypeConstructor;
+class DTypeSelector;
class ExprManager;
+class GetAbductCommand;
+class GetInterpolCommand;
+class NodeManager;
class SmtEngine;
+class SynthFunCommand;
class Type;
+class TypeNode;
class Options;
class Random;
class Result;
@@ -67,6 +75,16 @@ class CVC4_PUBLIC CVC4ApiException : public std::exception
std::string d_msg;
};
+class CVC4_PUBLIC CVC4ApiRecoverableException : public CVC4ApiException
+{
+ public:
+ CVC4ApiRecoverableException(const std::string& str) : CVC4ApiException(str) {}
+ CVC4ApiRecoverableException(const std::stringstream& stream)
+ : CVC4ApiException(stream.str())
+ {
+ }
+};
+
/* -------------------------------------------------------------------------- */
/* Result */
/* -------------------------------------------------------------------------- */
@@ -188,6 +206,7 @@ class Datatype;
*/
class CVC4_PUBLIC Sort
{
+ friend class DatatypeConstructor;
friend class DatatypeConstructorDecl;
friend class DatatypeDecl;
friend class Op;
@@ -206,6 +225,7 @@ class CVC4_PUBLIC Sort
* @return the Sort
*/
Sort(const Solver* slv, const CVC4::Type& t);
+ Sort(const Solver* slv, const CVC4::TypeNode& t);
/**
* Constructor.
@@ -380,6 +400,12 @@ class CVC4_PUBLIC Sort
bool isSet() const;
/**
+ * Is this a Bag sort?
+ * @return true if the sort is a Bag sort
+ */
+ bool isBag() const;
+
+ /**
* Is this a Sequence sort?
* @return true if the sort is a Sequence sort
*/
@@ -464,6 +490,7 @@ class CVC4_PUBLIC Sort
// !!! This is only temporarily available until the parser is fully migrated
// to the new API. !!!
CVC4::Type getType(void) const;
+ const CVC4::TypeNode& getTypeNode(void) const;
/* Constructor sort ------------------------------------------------------- */
@@ -482,6 +509,30 @@ class CVC4_PUBLIC Sort
*/
Sort getConstructorCodomainSort() const;
+ /* Selector sort ------------------------------------------------------- */
+
+ /**
+ * @return the domain sort of a selector sort
+ */
+ Sort getSelectorDomainSort() const;
+
+ /**
+ * @return the codomain sort of a selector sort
+ */
+ Sort getSelectorCodomainSort() const;
+
+ /* Tester sort ------------------------------------------------------- */
+
+ /**
+ * @return the domain sort of a tester sort
+ */
+ Sort getTesterDomainSort() const;
+
+ /**
+ * @return the codomain sort of a tester sort, which is the Boolean sort
+ */
+ Sort getTesterCodomainSort() const;
+
/* Function sort ------------------------------------------------------- */
/**
@@ -518,6 +569,13 @@ class CVC4_PUBLIC Sort
*/
Sort getSetElementSort() const;
+ /* Bag sort ------------------------------------------------------------ */
+
+ /**
+ * @return the element sort of a bag sort
+ */
+ Sort getBagElementSort() const;
+
/* Sequence sort ------------------------------------------------------- */
/**
@@ -615,7 +673,7 @@ class CVC4_PUBLIC Sort
* memory allocation (CVC4::Type is already ref counted, so this could be
* a unique_ptr instead).
*/
- std::shared_ptr<CVC4::Type> d_type;
+ std::shared_ptr<CVC4::TypeNode> d_type;
};
/**
@@ -674,6 +732,17 @@ class CVC4_PUBLIC Op
*/
Op(const Solver* slv, const Kind k, const CVC4::Expr& e);
+ // !!! This constructor is only temporarily public until the parser is fully
+ // migrated to the new API. !!!
+ /**
+ * Constructor.
+ * @param slv the associated solver object
+ * @param k the kind of this Op
+ * @param n the internal node that is to be wrapped by this term
+ * @return the Term
+ */
+ Op(const Solver* slv, const Kind k, const CVC4::Node& n);
+
/**
* Destructor.
*/
@@ -763,7 +832,7 @@ class CVC4_PUBLIC Op
* memory allocation (CVC4::Expr is already ref counted, so this could be
* a unique_ptr instead).
*/
- std::shared_ptr<CVC4::Expr> d_expr;
+ std::shared_ptr<CVC4::Node> d_node;
};
/* -------------------------------------------------------------------------- */
@@ -792,6 +861,16 @@ class CVC4_PUBLIC Term
*/
Term(const Solver* slv, const CVC4::Expr& e);
+ // !!! This constructor is only temporarily public until the parser is fully
+ // migrated to the new API. !!!
+ /**
+ * Constructor.
+ * @param slv the associated solver object
+ * @param n the internal node that is to be wrapped by this term
+ * @return the Term
+ */
+ Term(const Solver* slv, const CVC4::Node& n);
+
/**
* Constructor.
*/
@@ -906,13 +985,6 @@ class CVC4_PUBLIC Term
bool isNull() const;
/**
- * Check if this is a Term representing a constant.
- *
- * @return true if a constant Term
- */
- bool isConst() const;
-
- /**
* Return the base (element stored at all indices) of a constant array
* throws an exception if the kind is not CONST_ARRAY
* @return the base value
@@ -1003,7 +1075,7 @@ class CVC4_PUBLIC Term
* @param p the position of the iterator (e.g. which child it's on)
*/
const_iterator(const Solver* slv,
- const std::shared_ptr<CVC4::Expr>& e,
+ const std::shared_ptr<CVC4::Node>& e,
uint32_t p);
/**
@@ -1055,8 +1127,8 @@ class CVC4_PUBLIC Term
* The associated solver object.
*/
const Solver* d_solver;
- /* The original expression to be iterated over */
- std::shared_ptr<CVC4::Expr> d_orig_expr;
+ /* The original node to be iterated over */
+ std::shared_ptr<CVC4::Node> d_origNode;
/* Keeps track of the iteration position */
uint32_t d_pos;
};
@@ -1075,6 +1147,10 @@ class CVC4_PUBLIC Term
// to the new API. !!!
CVC4::Expr getExpr(void) const;
+ // !!! This is only temporarily available until the parser is fully migrated
+ // to the new API. !!!
+ const CVC4::Node& getNode(void) const;
+
protected:
/**
* The associated solver object.
@@ -1096,12 +1172,17 @@ class CVC4_PUBLIC Term
Kind getKindHelper() const;
/**
+ * returns true if the current term is a constant integer that is casted into
+ * real using the operator CAST_TO_REAL, and returns false otherwise
+ */
+ bool isCastedReal() const;
+ /**
* The internal expression wrapped by this term.
* This is a shared_ptr rather than a unique_ptr to avoid overhead due to
* memory allocation (CVC4::Expr is already ref counted, so this could be
* a unique_ptr instead).
*/
- std::shared_ptr<CVC4::Expr> d_expr;
+ std::shared_ptr<CVC4::Node> d_node;
};
/**
@@ -1210,6 +1291,11 @@ class CVC4_PUBLIC DatatypeConstructorDecl
DatatypeConstructorDecl();
/**
+ * Destructor.
+ */
+ ~DatatypeConstructorDecl();
+
+ /**
* Add datatype selector declaration.
* @param name the name of the datatype selector declaration to add
* @param sort the range sort of the datatype selector declaration to add
@@ -1228,7 +1314,7 @@ class CVC4_PUBLIC DatatypeConstructorDecl
// !!! This is only temporarily available until the parser is fully migrated
// to the new API. !!!
- const CVC4::DatatypeConstructor& getDatatypeConstructor(void) const;
+ const CVC4::DTypeConstructor& getDatatypeConstructor(void) const;
private:
/**
@@ -1248,9 +1334,9 @@ class CVC4_PUBLIC DatatypeConstructorDecl
* The internal (intermediate) datatype constructor wrapped by this
* datatype constructor declaration.
* This is a shared_ptr rather than a unique_ptr since
- * CVC4::DatatypeConstructor is not ref counted.
+ * CVC4::DTypeConstructor is not ref counted.
*/
- std::shared_ptr<CVC4::DatatypeConstructor> d_ctor;
+ std::shared_ptr<CVC4::DTypeConstructor> d_ctor;
};
class Solver;
@@ -1301,7 +1387,7 @@ class CVC4_PUBLIC DatatypeDecl
// !!! This is only temporarily available until the parser is fully migrated
// to the new API. !!!
- CVC4::Datatype& getDatatype(void) const;
+ CVC4::DType& getDatatype(void) const;
private:
/**
@@ -1354,10 +1440,10 @@ class CVC4_PUBLIC DatatypeDecl
/* The internal (intermediate) datatype wrapped by this datatype
* declaration
- * This is a shared_ptr rather than a unique_ptr since CVC4::Datatype is
+ * This is a shared_ptr rather than a unique_ptr since CVC4::DType is
* not ref counted.
*/
- std::shared_ptr<CVC4::Datatype> d_dtype;
+ std::shared_ptr<CVC4::DType> d_dtype;
};
/**
@@ -1382,7 +1468,7 @@ class CVC4_PUBLIC DatatypeSelector
* @param stor the internal datatype selector to be wrapped
* @return the DatatypeSelector
*/
- DatatypeSelector(const Solver* slv, const CVC4::DatatypeConstructorArg& stor);
+ DatatypeSelector(const Solver* slv, const CVC4::DTypeSelector& stor);
/**
* Destructor.
@@ -1408,7 +1494,7 @@ class CVC4_PUBLIC DatatypeSelector
// !!! This is only temporarily available until the parser is fully migrated
// to the new API. !!!
- CVC4::DatatypeConstructorArg getDatatypeConstructorArg(void) const;
+ CVC4::DTypeSelector getDatatypeConstructorArg(void) const;
private:
/**
@@ -1418,10 +1504,10 @@ class CVC4_PUBLIC DatatypeSelector
/**
* The internal datatype selector wrapped by this datatype selector.
- * This is a shared_ptr rather than a unique_ptr since CVC4::Datatype is
+ * This is a shared_ptr rather than a unique_ptr since CVC4::DType is
* not ref counted.
*/
- std::shared_ptr<CVC4::DatatypeConstructorArg> d_stor;
+ std::shared_ptr<CVC4::DTypeSelector> d_stor;
};
/**
@@ -1445,7 +1531,7 @@ class CVC4_PUBLIC DatatypeConstructor
* @param ctor the internal datatype constructor to be wrapped
* @return the DatatypeConstructor
*/
- DatatypeConstructor(const Solver* slv, const CVC4::DatatypeConstructor& ctor);
+ DatatypeConstructor(const Solver* slv, const CVC4::DTypeConstructor& ctor);
/**
* Destructor.
@@ -1462,6 +1548,31 @@ class CVC4_PUBLIC DatatypeConstructor
Term getConstructorTerm() const;
/**
+ * Get the constructor operator of this datatype constructor whose return
+ * type is retSort. This method is intended to be used on constructors of
+ * parametric datatypes and can be seen as returning the constructor
+ * term that has been explicitly cast to the given sort.
+ *
+ * This method is required for constructors of parametric datatypes whose
+ * return type cannot be determined by type inference. For example, given:
+ * (declare-datatype List (par (T) ((nil) (cons (head T) (tail (List T))))))
+ * The type of nil terms need to be provided by the user. In SMT version 2.6,
+ * this is done via the syntax for qualified identifiers:
+ * (as nil (List Int))
+ * This method is equivalent of applying the above, where this
+ * DatatypeConstructor is the one corresponding to nil, and retSort is
+ * (List Int).
+ *
+ * Furthermore note that the returned constructor term t is an operator,
+ * while Solver::mkTerm(APPLY_CONSTRUCTOR, t) is used to construct the above
+ * (nullary) application of nil.
+ *
+ * @param retSort the desired return sort of the constructor
+ * @return the constructor term
+ */
+ Term getSpecializedConstructorTerm(Sort retSort) const;
+
+ /**
* Get the tester operator of this datatype constructor.
* @return the tester operator
*/
@@ -1563,7 +1674,7 @@ class CVC4_PUBLIC DatatypeConstructor
* @param true if this is a begin() iterator
*/
const_iterator(const Solver* slv,
- const CVC4::DatatypeConstructor& ctor,
+ const CVC4::DTypeConstructor& ctor,
bool begin);
/**
@@ -1595,7 +1706,7 @@ class CVC4_PUBLIC DatatypeConstructor
// !!! This is only temporarily available until the parser is fully migrated
// to the new API. !!!
- const CVC4::DatatypeConstructor& getDatatypeConstructor(void) const;
+ const CVC4::DTypeConstructor& getDatatypeConstructor(void) const;
private:
/**
@@ -1612,10 +1723,10 @@ class CVC4_PUBLIC DatatypeConstructor
/**
* The internal datatype constructor wrapped by this datatype constructor.
- * This is a shared_ptr rather than a unique_ptr since CVC4::Datatype is
+ * This is a shared_ptr rather than a unique_ptr since CVC4::DType is
* not ref counted.
*/
- std::shared_ptr<CVC4::DatatypeConstructor> d_ctor;
+ std::shared_ptr<CVC4::DTypeConstructor> d_ctor;
};
/*
@@ -1634,7 +1745,7 @@ class CVC4_PUBLIC Datatype
* @param dtype the internal datatype to be wrapped
* @return the Datatype
*/
- Datatype(const Solver* slv, const CVC4::Datatype& dtype);
+ Datatype(const Solver* slv, const CVC4::DType& dtype);
// Nullary constructor for Cython
Datatype();
@@ -1778,7 +1889,7 @@ class CVC4_PUBLIC Datatype
* @param dtype the internal datatype to iterate over
* @param true if this is a begin() iterator
*/
- const_iterator(const Solver* slv, const CVC4::Datatype& dtype, bool begin);
+ const_iterator(const Solver* slv, const CVC4::DType& dtype, bool begin);
/**
* The associated solver object.
@@ -1809,7 +1920,7 @@ class CVC4_PUBLIC Datatype
// !!! This is only temporarily available until the parser is fully migrated
// to the new API. !!!
- const CVC4::Datatype& getDatatype(void) const;
+ const CVC4::DType& getDatatype(void) const;
private:
/**
@@ -1826,10 +1937,10 @@ class CVC4_PUBLIC Datatype
/**
* The internal datatype wrapped by this datatype.
- * This is a shared_ptr rather than a unique_ptr since CVC4::Datatype is
+ * This is a shared_ptr rather than a unique_ptr since CVC4::DType is
* not ref counted.
*/
- std::shared_ptr<CVC4::Datatype> d_dtype;
+ std::shared_ptr<CVC4::DType> d_dtype;
};
/**
@@ -1895,6 +2006,9 @@ std::ostream& operator<<(std::ostream& out,
*/
class CVC4_PUBLIC Grammar
{
+ friend class CVC4::GetAbductCommand;
+ friend class CVC4::GetInterpolCommand;
+ friend class CVC4::SynthFunCommand;
friend class Solver;
public:
@@ -1906,6 +2020,13 @@ class CVC4_PUBLIC Grammar
void addRule(Term ntSymbol, Term rule);
/**
+ * Add <rules> to the set of rules corresponding to <ntSymbol>.
+ * @param ntSymbol the non-terminal to which the rules are added
+ * @param rule the rules to add
+ */
+ void addRules(Term ntSymbol, std::vector<Term> rules);
+
+ /**
* Allow <ntSymbol> to be an arbitrary constant.
* @param ntSymbol the non-terminal allowed to be any constant
*/
@@ -1919,11 +2040,14 @@ class CVC4_PUBLIC Grammar
void addAnyVariable(Term ntSymbol);
/**
- * Add <rules> to the set of rules corresponding to <ntSymbol>.
- * @param ntSymbol the non-terminal to which the rules are added
- * @param rule the rules to add
+ * @return a string representation of this grammar.
*/
- void addRules(Term ntSymbol, std::vector<Term> rules);
+ std::string toString() const;
+
+ /**
+ * Nullary constructor. Needed for the Cython API.
+ */
+ Grammar();
private:
/**
@@ -2013,6 +2137,14 @@ class CVC4_PUBLIC Grammar
bool d_isResolved;
};
+/**
+ * Serialize a grammar to given stream.
+ * @param out the output stream
+ * @param g the grammar to be serialized to the given output stream
+ * @return the output stream
+ */
+std::ostream& operator<<(std::ostream& out, const Grammar& g) CVC4_PUBLIC;
+
/* -------------------------------------------------------------------------- */
/* Rounding Mode for Floating Points */
/* -------------------------------------------------------------------------- */
@@ -2070,6 +2202,12 @@ class CVC4_PUBLIC Solver
Solver& operator=(const Solver&) = delete;
/* .................................................................... */
+ /* Solver Configuration */
+ /* .................................................................... */
+
+ bool supportsFloatingPoint() const;
+
+ /* .................................................................... */
/* Sorts Handling */
/* .................................................................... */
@@ -2101,7 +2239,7 @@ class CVC4_PUBLIC Solver
/**
* @return sort RoundingMode
*/
- Sort getRoundingmodeSort() const;
+ Sort getRoundingModeSort() const;
/**
* @return sort String
@@ -2165,8 +2303,9 @@ class CVC4_PUBLIC Solver
* @param unresolvedSorts the list of unresolved sorts
* @return the datatype sorts
*/
- std::vector<Sort> mkDatatypeSorts(std::vector<DatatypeDecl>& dtypedecls,
- std::set<Sort>& unresolvedSorts) const;
+ std::vector<Sort> mkDatatypeSorts(
+ const std::vector<DatatypeDecl>& dtypedecls,
+ const std::set<Sort>& unresolvedSorts) const;
/**
* Create function sort.
@@ -2214,6 +2353,13 @@ class CVC4_PUBLIC Solver
Sort mkSetSort(Sort elemSort) const;
/**
+ * Create a bag sort.
+ * @param elemSort the sort of the bag elements
+ * @return the bag sort
+ */
+ Sort mkBagSort(Sort elemSort) const;
+
+ /**
* Create a sequence sort.
* @param elemSort the sort of the sequence elements
* @return the sequence sort
@@ -2329,8 +2475,7 @@ class CVC4_PUBLIC Solver
/**
* Create n-ary term of given kind from a given operator.
* Create operators with mkOp().
- * @param kind the kind of the term
- * @param the operator
+ * @param op the operator
* @children the children of the term
* @return the Term
*/
@@ -2435,20 +2580,26 @@ class CVC4_PUBLIC Solver
* @return a constant representing Pi
*/
Term mkPi() const;
-
/**
- * Create a real constant from a string.
+ * Create an integer constant from a string.
* @param s the string representation of the constant, may represent an
- * integer (e.g., "123") or real constant (e.g., "12.34" or "12/34").
- * @return a constant of sort Real or Integer (if 's' represents an integer)
+ * integer (e.g., "123").
+ * @return a constant of sort Integer assuming 's' represents an integer)
+ */
+ Term mkInteger(const std::string& s) const;
+
+ /**
+ * Create an integer constant from a c++ int.
+ * @param val the value of the constant
+ * @return a constant of sort Integer
*/
- Term mkReal(const char* s) const;
+ Term mkInteger(int64_t val) const;
/**
* Create a real constant from a string.
* @param s the string representation of the constant, may represent an
* integer (e.g., "123") or real constant (e.g., "12.34" or "12/34").
- * @return a constant of sort Real or Integer (if 's' represents an integer)
+ * @return a constant of sort Real
*/
Term mkReal(const std::string& s) const;
@@ -2457,62 +2608,17 @@ class CVC4_PUBLIC Solver
* @param val the value of the constant
* @return a constant of sort Integer
*/
- Term mkReal(int32_t val) const;
-
- /**
- * Create a real constant from an integer.
- * @param val the value of the constant
- * @return a constant of sort Integer
- */
Term mkReal(int64_t val) const;
/**
- * Create a real constant from an unsigned integer.
- * @param val the value of the constant
- * @return a constant of sort Integer
- */
- Term mkReal(uint32_t val) const;
-
- /**
- * Create a real constant from an unsigned integer.
- * @param val the value of the constant
- * @return a constant of sort Integer
- */
- Term mkReal(uint64_t val) const;
-
- /**
* Create a real constant from a rational.
* @param num the value of the numerator
* @param den the value of the denominator
- * @return a constant of sort Real or Integer (if 'num' is divisible by 'den')
- */
- Term mkReal(int32_t num, int32_t den) const;
-
- /**
- * Create a real constant from a rational.
- * @param num the value of the numerator
- * @param den the value of the denominator
- * @return a constant of sort Real or Integer (if 'num' is divisible by 'den')
+ * @return a constant of sort Real
*/
Term mkReal(int64_t num, int64_t den) const;
/**
- * Create a real constant from a rational.
- * @param num the value of the numerator
- * @param den the value of the denominator
- * @return a constant of sort Real or Integer (if 'num' is divisible by 'den')
- */
- Term mkReal(uint32_t num, uint32_t den) const;
-
- /**
- * Create a real constant from a rational.
- * @param num the value of the numerator
- * @param den the value of the denominator
- * @return a constant of sort Real or Integer (if 'num' is divisible by 'den')
- */
- Term mkReal(uint64_t num, uint64_t den) const;
-
- /**
* Create a regular expression empty term.
* @return the empty term
*/
@@ -2532,6 +2638,13 @@ class CVC4_PUBLIC Solver
Term mkEmptySet(Sort s) const;
/**
+ * Create a constant representing an empty bag of the given sort.
+ * @param s the sort of the bag elements.
+ * @return the empty bag constant
+ */
+ Term mkEmptyBag(Sort s) const;
+
+ /**
* Create a separation logic nil term.
* @param sort the sort of the nil term
* @return the separation logic nil term
@@ -2545,15 +2658,6 @@ class CVC4_PUBLIC Solver
* be converted to the corresponding character
* @return the String constant
*/
- Term mkString(const char* s, bool useEscSequences = false) const;
-
- /**
- * Create a String constant.
- * @param s the string this constant represents
- * @param useEscSequences determines whether escape sequences in \p s should
- * be converted to the corresponding character
- * @return the String constant
- */
Term mkString(const std::string& s, bool useEscSequences = false) const;
/**
@@ -2578,13 +2682,6 @@ class CVC4_PUBLIC Solver
Term mkChar(const std::string& s) const;
/**
- * Create a character constant from a given string.
- * @param s the string denoting the code point of the character (in base 16)
- * @return the character constant
- */
- Term mkChar(const char* s) const;
-
- /**
* Create an empty sequence of the given element sort.
* @param sort The element sort of the sequence.
* @return the empty sequence with given element sort.
@@ -2607,14 +2704,6 @@ class CVC4_PUBLIC Solver
Term mkBitVector(uint32_t size, uint64_t val = 0) const;
/**
- * Create a bit-vector constant from a given string.
- * @param s the string representation of the constant
- * @param base the base of the string representation (2, 10, or 16)
- * @return the bit-vector constant
- */
- Term mkBitVector(const char* s, uint32_t base = 2) const;
-
- /**
* Create a bit-vector constant from a given string of base 2, 10 or 16.
*
* The size of resulting bit-vector is
@@ -2632,23 +2721,12 @@ class CVC4_PUBLIC Solver
/**
* Create a bit-vector constant of a given bit-width from a given string of
* base 2, 10 or 16.
- *
- * @param size the bit-width of the constant
- * @param s the string representation of the constant
- * @param base the base of the string representation (2, 10, or 16)
- * @return the bit-vector constant
- */
- Term mkBitVector(uint32_t size, const char* s, uint32_t base) const;
-
- /**
- * Create a bit-vector constant of a given bit-width from a given string of
- * base 2, 10 or 16.
* @param size the bit-width of the constant
* @param s the string representation of the constant
* @param base the base of the string representation (2, 10, or 16)
* @return the bit-vector constant
*/
- Term mkBitVector(uint32_t size, std::string& s, uint32_t base) const;
+ Term mkBitVector(uint32_t size, const std::string& s, uint32_t base) const;
/**
* Create a constant array with the provided constant value stored at every
@@ -2751,10 +2829,19 @@ class CVC4_PUBLIC Solver
* @param symbol the name of the constant
* @return the first-order constant
*/
- Term mkConst(Sort sort, const std::string& symbol = std::string()) const;
+ Term mkConst(Sort sort, const std::string& symbol) const;
+ /**
+ * Create (first-order) constant (0-arity function symbol), with a default
+ * symbol name.
+ *
+ * @param sort the sort of the constant
+ * @return the first-order constant
+ */
+ Term mkConst(Sort sort) const;
/**
- * Create (bound) variable.
+ * Create a bound variable to be used in a binder (i.e. a quantifier, a
+ * lambda, or a witness binder).
* @param sort the sort of the variable
* @param symbol the name of the variable
* @return the variable
@@ -2991,14 +3078,6 @@ class CVC4_PUBLIC Solver
std::vector<Term> getAssertions() const;
/**
- * Get the assignment of asserted formulas.
- * SMT-LIB: ( get-assignment )
- * Requires to enable option 'produce-assignments'.
- * @return a list of formula-assignment pairs
- */
- std::vector<std::pair<Term, Term>> getAssignment() const;
-
- /**
* Get info from the solver.
* SMT-LIB: ( get-info <info_flag> )
* @return the info
@@ -3045,6 +3124,57 @@ class CVC4_PUBLIC Solver
std::vector<Term> getValue(const std::vector<Term>& terms) const;
/**
+ * Do quantifier elimination.
+ * SMT-LIB: ( get-qe <q> )
+ * Requires a logic that supports quantifier elimination. Currently, the only
+ * logics supported by quantifier elimination is LRA and LIA.
+ * @param q a quantified formula of the form:
+ * Q x1...xn. P( x1...xn, y1...yn )
+ * where P( x1...xn, y1...yn ) is a quantifier-free formula
+ * @return a formula ret such that, given the current set of formulas A
+ * asserted to this solver:
+ * - ( A ^ q ) and ( A ^ ret ) are equivalent
+ * - ret is quantifier-free formula containing only free variables in
+ * y1...yn.
+ */
+ Term getQuantifierElimination(api::Term q) const;
+
+ /**
+ * Do partial quantifier elimination, which can be used for incrementally
+ * computing the result of a quantifier elimination.
+ * SMT-LIB: ( get-qe-disjunct <q> )
+ * Requires a logic that supports quantifier elimination. Currently, the only
+ * logics supported by quantifier elimination is LRA and LIA.
+ * @param q a quantified formula of the form:
+ * Q x1...xn. P( x1...xn, y1...yn )
+ * where P( x1...xn, y1...yn ) is a quantifier-free formula
+ * @return a formula ret such that, given the current set of formulas A
+ * asserted to this solver:
+ * - (A ^ q) => (A ^ ret) if Q is forall or (A ^ ret) => (A ^ q) if Q is
+ * exists,
+ * - ret is quantifier-free formula containing only free variables in
+ * y1...yn,
+ * - If Q is exists, let A^Q_n be the formula
+ * A ^ ~ret^Q_1 ^ ... ^ ~ret^Q_n
+ * where for each i=1,...n, formula ret^Q_i is the result of calling
+ * getQuantifierEliminationDisjunct for q with the set of assertions
+ * A^Q_{i-1}. Similarly, if Q is forall, then let A^Q_n be
+ * A ^ ret^Q_1 ^ ... ^ ret^Q_n
+ * where ret^Q_i is the same as above. In either case, we have
+ * that ret^Q_j will eventually be true or false, for some finite j.
+ */
+ Term getQuantifierEliminationDisjunct(api::Term q) const;
+
+ /**
+ * When using separation logic, this sets the location sort and the
+ * datatype sort to the given ones. This method should be invoked exactly
+ * once, before any separation logic constraints are provided.
+ * @param locSort The location sort of the heap
+ * @param dataSort The data sort of the heap
+ */
+ void declareSeparationHeap(api::Sort locSort, api::Sort dataSort) const;
+
+ /**
* When using separation logic, obtain the term for the heap.
* @return The term for the heap
*/
@@ -3065,7 +3195,7 @@ class CVC4_PUBLIC Solver
/**
* Get an interpolant
- * SMT-LIB: ( get-interpol <term> )
+ * SMT-LIB: ( get-interpol <conj> )
* Requires to enable option 'produce-interpols'.
* @param conj the conjecture term
* @param output a Term I such that A->I and I->B are valid, where A is the
@@ -3076,22 +3206,64 @@ class CVC4_PUBLIC Solver
/**
* Get an interpolant
- * SMT-LIB: ( get-interpol <term> )
+ * SMT-LIB: ( get-interpol <conj> <g> )
* Requires to enable option 'produce-interpols'.
* @param conj the conjecture term
- * @param gtype the grammar for the interpolant I
+ * @param g the grammar for the interpolant I
* @param output a Term I such that A->I and I->B are valid, where A is the
* current set of assertions and B is given in the input by conj.
* @return true if it gets I successfully, false otherwise.
*/
- bool getInterpolant(Term conj, const Type& gtype, Term& output) const;
+ bool getInterpolant(Term conj, Grammar& g, Term& output) const;
/**
- * Print the model of a satisfiable query to the given output stream.
- * Requires to enable option 'produce-models'.
+ * Get an abduct.
+ * SMT-LIB: ( get-abduct <conj> )
+ * Requires enabling option 'produce-abducts'
+ * @param conj the conjecture term
+ * @param output a term C such that A^C is satisfiable, and A^~B^C is
+ * unsatisfiable, where A is the current set of assertions and B is
+ * given in the input by conj
+ * @return true if it gets C successfully, false otherwise
+ */
+ bool getAbduct(Term conj, Term& output) const;
+
+ /**
+ * Get an abduct.
+ * SMT-LIB: ( get-abduct <conj> <g> )
+ * Requires enabling option 'produce-abducts'
+ * @param conj the conjecture term
+ * @param g the grammar for the abduct C
+ * @param output a term C such that A^C is satisfiable, and A^~B^C is
+ * unsatisfiable, where A is the current set of assertions and B is
+ * given in the input by conj
+ * @return true if it gets C successfully, false otherwise
+ */
+ bool getAbduct(Term conj, Grammar& g, Term& output) const;
+
+ /**
+ * Block the current model. Can be called only if immediately preceded by a
+ * SAT or INVALID query.
+ * SMT-LIB: ( block-model )
+ * Requires enabling 'produce-models' option and setting 'block-models' option
+ * to a mode other than "none".
+ */
+ void blockModel() const;
+
+ /**
+ * Block the current model values of (at least) the values in terms. Can be
+ * called only if immediately preceded by a SAT or NOT_ENTAILED query.
+ * SMT-LIB: ( block-model-values ( <terms>+ ) )
+ * Requires enabling 'produce-models' option and setting 'block-models' option
+ * to a mode other than "none".
+ */
+ void blockModelValues(const std::vector<Term>& terms) const;
+
+ /**
+ * Print all instantiations made by the quantifiers module.
* @param out the output stream
*/
- void printModel(std::ostream& out) const;
+ void printInstantiations(std::ostream& out) const;
/**
* Push (a) level(s) to the assertion stack.
@@ -3148,7 +3320,9 @@ class CVC4_PUBLIC Solver
Term mkSygusVar(Sort sort, const std::string& symbol = std::string()) const;
/**
- * Create a Sygus grammar.
+ * Create a Sygus grammar. The first non-terminal is treated as the starting
+ * non-terminal, so the order of non-terminals matters.
+ *
* @param boundVars the parameters to corresponding synth-fun/synth-inv
* @param ntSymbols the pre-declaration of the non-terminal symbols
* @return the grammar
@@ -3261,6 +3435,10 @@ class CVC4_PUBLIC Solver
// !!! This is only temporarily available until the parser is fully migrated
// to the new API. !!!
+ NodeManager* getNodeManager(void) const;
+
+ // !!! This is only temporarily available until the parser is fully migrated
+ // to the new API. !!!
SmtEngine* getSmtEngine(void) const;
// !!! This is only temporarily available until options are refactored at
@@ -3294,14 +3472,16 @@ class CVC4_PUBLIC Solver
Term mkTermFromKind(Kind kind) const;
/* Helper for mkChar functions that take a string as argument. */
Term mkCharFromStrHelper(const std::string& s) const;
+ /** Get value helper, which accounts for subtyping */
+ Term getValueHelper(Term term) const;
/**
* Helper function that ensures that a given term is of sort real (as opposed
* to being of sort integer).
- * @param term a term of sort integer or real
+ * @param t a term of sort integer or real
* @return a term of sort real
*/
- Term ensureRealSort(Term expr) const;
+ Term ensureRealSort(Term t) const;
/**
* Create n-ary term of given kind. This handles the cases of left/right
@@ -3314,14 +3494,22 @@ class CVC4_PUBLIC Solver
Term mkTermHelper(Kind kind, const std::vector<Term>& children) const;
/**
+ * Create n-ary term of given kind from a given operator.
+ * @param op the operator
+ * @param children the children of the term
+ * @return the Term
+ */
+ Term mkTermHelper(const Op& op, const std::vector<Term>& children) const;
+
+ /**
* Create a vector of datatype sorts, using unresolved sorts.
* @param dtypedecls the datatype declarations from which the sort is created
* @param unresolvedSorts the list of unresolved sorts
* @return the datatype sorts
*/
std::vector<Sort> mkDatatypeSortsInternal(
- std::vector<DatatypeDecl>& dtypedecls,
- std::set<Sort>& unresolvedSorts) const;
+ const std::vector<DatatypeDecl>& dtypedecls,
+ const std::set<Sort>& unresolvedSorts) const;
/**
* Synthesize n-ary function following specified syntactic constraints.
@@ -3350,12 +3538,16 @@ class CVC4_PUBLIC Solver
// !!! Only temporarily public until the parser is fully migrated to the
// new API. !!!
std::vector<Expr> termVectorToExprs(const std::vector<Term>& terms);
+std::vector<Node> termVectorToNodes(const std::vector<Term>& terms);
std::vector<Type> sortVectorToTypes(const std::vector<Sort>& sorts);
-std::set<Type> sortSetToTypes(const std::set<Sort>& sorts);
+std::vector<TypeNode> sortVectorToTypeNodes(const std::vector<Sort>& sorts);
+std::set<TypeNode> sortSetToTypeNodes(const std::set<Sort>& sorts);
std::vector<Term> exprVectorToTerms(const Solver* slv,
const std::vector<Expr>& terms);
std::vector<Sort> typeVectorToSorts(const Solver* slv,
const std::vector<Type>& sorts);
+std::vector<Sort> typeNodeVectorToSorts(const Solver* slv,
+ const std::vector<TypeNode>& types);
} // namespace api
diff --git a/src/api/cvc4cppkind.h b/src/api/cvc4cppkind.h
index 9e1ce3ecf..0bd4117dc 100644
--- a/src/api/cvc4cppkind.h
+++ b/src/api/cvc4cppkind.h
@@ -5,7 +5,7 @@
** Aina Niemetz, Andrew Reynolds, Makai Mann
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -120,9 +120,18 @@ enum CVC4_PUBLIC Kind : int32_t
#if 0
/* Skolem variable (internal only) */
SKOLEM,
- /* Symbolic expression (any arity) */
- SEXPR,
#endif
+ /*
+ * Symbolic expression.
+ * Parameters: n > 0
+ * -[1]..[n]: terms
+ * Create with:
+ * mkTerm(Kind kind, Term child)
+ * mkTerm(Kind kind, Term child1, Term child2)
+ * mkTerm(Kind kind, Term child1, Term child2, Term child3)
+ * mkTerm(Kind kind, const std::vector<Term>& children)
+ */
+ SEXPR,
/**
* Lambda expression.
* Parameters: 2
@@ -761,6 +770,12 @@ enum CVC4_PUBLIC Kind : int32_t
BITVECTOR_NEG,
/**
* Unsigned division of two bit-vectors, truncating towards 0.
+ *
+ * Note: The semantics of this operator depends on `bv-div-zero-const`
+ * (default is true). Depending on the setting, a division by zero is
+ * treated as all ones (default, corresponds to SMT-LIB >=2.6) or an
+ * uninterpreted value (corresponds to SMT-LIB <2.6).
+ *
* Parameters: 2
* -[1]..[2]: Terms of bit-vector sort (sorts must match)
* Create with:
@@ -770,6 +785,12 @@ enum CVC4_PUBLIC Kind : int32_t
BITVECTOR_UDIV,
/**
* Unsigned remainder from truncating division of two bit-vectors.
+ *
+ * Note: The semantics of this operator depends on `bv-div-zero-const`
+ * (default is true). Depending on the setting, if the modulus is zero, the
+ * result is either the dividend (default, corresponds to SMT-LIB >=2.6) or
+ * an uninterpreted value (corresponds to SMT-LIB <2.6).
+ *
* Parameters: 2
* -[1]..[2]: Terms of bit-vector sort (sorts must match)
* Create with:
@@ -779,6 +800,13 @@ enum CVC4_PUBLIC Kind : int32_t
BITVECTOR_UREM,
/**
* Two's complement signed division of two bit-vectors.
+ *
+ * Note: The semantics of this operator depends on `bv-div-zero-const`
+ * (default is true). By default, the function returns all ones if the
+ * dividend is positive and one if the dividend is negative (corresponds to
+ * SMT-LIB >=2.6). If the option is disabled, a division by zero is treated
+ * as an uninterpreted value (corresponds to SMT-LIB <2.6).
+ *
* Parameters: 2
* -[1]..[2]: Terms of bit-vector sort (sorts must match)
* Create with:
@@ -789,6 +817,12 @@ enum CVC4_PUBLIC Kind : int32_t
/**
* Two's complement signed remainder of two bit-vectors
* (sign follows dividend).
+ *
+ * Note: The semantics of this operator depends on `bv-div-zero-const`
+ * (default is true, corresponds to SMT-LIB >=2.6). Depending on the setting,
+ * if the modulus is zero, the result is either the dividend (default) or an
+ * uninterpreted value (corresponds to SMT-LIB <2.6).
+ *
* Parameters: 2
* -[1]..[2]: Terms of bit-vector sort (sorts must match)
* Create with:
@@ -799,6 +833,12 @@ enum CVC4_PUBLIC Kind : int32_t
/**
* Two's complement signed remainder
* (sign follows divisor).
+ *
+ * Note: The semantics of this operator depends on `bv-div-zero-const`
+ * (default is on). Depending on the setting, if the modulus is zero, the
+ * result is either the dividend (default, corresponds to SMT-LIB >=2.6) or
+ * an uninterpreted value (corresponds to SMT-LIB <2.6).
+ *
* Parameters: 2
* -[1]..[2]: Terms of bit-vector sort (sorts must match)
* Create with:
@@ -1801,7 +1841,8 @@ enum CVC4_PUBLIC Kind : int32_t
*/
MEMBER,
/**
- * The set of the single element given as a parameter.
+ * Construct a singleton set from an element given as a parameter.
+ * The returned set has same type of the element.
* Parameters: 1
* -[1]: Single element
* Create with:
@@ -1925,6 +1966,151 @@ enum CVC4_PUBLIC Kind : int32_t
* mkTerm(Kind kind, Term child)
*/
CHOOSE,
+ /**
+ * Set is_singleton predicate.
+ * Parameters: 1
+ * -[1]: Term of set sort, is [1] a singleton set?
+ * Create with:
+ * mkTerm(Kind kind, Term child)
+ */
+ IS_SINGLETON,
+ /* Bags ------------------------------------------------------------------ */
+ /**
+ * Empty bag constant.
+ * Parameters: 1
+ * -[1]: Sort of the bag elements
+ * Create with:
+ * mkEmptyBag(Sort sort)
+ */
+ EMPTYBAG,
+ /**
+ * Bag max union.
+ * Parameters: 2
+ * -[1]..[2]: Terms of bag sort
+ * Create with:
+ * mkTerm(Kind kind, Term child1, Term child2)
+ * mkTerm(Kind kind, const std::vector<Term>& children)
+ */
+ UNION_MAX,
+ /**
+ * Bag disjoint union (sum).
+ * Parameters: 2
+ * -[1]..[2]: Terms of bag sort
+ * Create with:
+ * mkTerm(Kind kind, Term child1, Term child2)
+ * mkTerm(Kind kind, const std::vector<Term>& children)
+ */
+ UNION_DISJOINT,
+ /**
+ * Bag intersection (min).
+ * Parameters: 2
+ * -[1]..[2]: Terms of bag sort
+ * Create with:
+ * mkTerm(Kind kind, Term child1, Term child2)
+ * mkTerm(Kind kind, const std::vector<Term>& children)
+ */
+ INTERSECTION_MIN,
+ /**
+ * Bag difference subtract (subtracts multiplicities of the second from the
+ * first).
+ * Parameters: 2
+ * -[1]..[2]: Terms of bag sort
+ * Create with:
+ * mkTerm(Kind kind, Term child1, Term child2)
+ * mkTerm(Kind kind, const std::vector<Term>& children)
+ */
+ DIFFERENCE_SUBTRACT,
+ /**
+ * Bag difference 2 (removes shared elements in the two bags).
+ * Parameters: 2
+ * -[1]..[2]: Terms of bag sort
+ * Create with:
+ * mkTerm(Kind kind, Term child1, Term child2)
+ * mkTerm(Kind kind, const std::vector<Term>& children)
+ */
+ DIFFERENCE_REMOVE,
+ /**
+ * Inclusion predicate for bags
+ * (multiplicities of the first bag <= multiplicities of the second bag).
+ * Parameters: 2
+ * -[1]..[2]: Terms of bag sort
+ * Create with:
+ * mkTerm(Kind kind, Term child1, Term child2)
+ * mkTerm(Kind kind, const std::vector<Term>& children)
+ */
+ SUBBAG,
+ /**
+ * Element multiplicity in a bag
+ * Parameters: 2
+ * -[1]..[2]: Terms of bag sort (Bag E), [1] an element of sort E
+ * Create with:
+ * mkTerm(Kind kind, Term child1, Term child2)
+ * mkTerm(Kind kind, const std::vector<Term>& children)
+ */
+ BAG_COUNT,
+ /**
+ * Eliminate duplicates in a given bag. The returned bag contains exactly the
+ * same elements in the given bag, but with multiplicity one.
+ * Parameters: 1
+ * -[1]: a term of bag sort
+ * Create with:
+ * mkTerm(Kind kind, Term child)
+ * mkTerm(Kind kind, const std::vector<Term>& children)
+ */
+ DUPLICATE_REMOVAL,
+ /**
+ * The bag of the single element given as a parameter.
+ * Parameters: 1
+ * -[1]: Single element
+ * Create with:
+ * mkTerm(Kind kind, Term child)
+ */
+ MK_BAG,
+ /**
+ * Bag cardinality.
+ * Parameters: 1
+ * -[1]: Bag to determine the cardinality of
+ * Create with:
+ * mkTerm(Kind kind, Term child)
+ */
+ BAG_CARD,
+ /**
+ * Returns an element from a given bag.
+ * If a bag A = {(x,n)} where n is the multiplicity, then the term (choose A)
+ * is equivalent to the term x.
+ * If the bag is empty, then (choose A) is an arbitrary value.
+ * If the bag contains distinct elements, then (choose A) will
+ * deterministically return an element in A.
+ * Parameters: 1
+ * -[1]: Term of bag sort
+ * Create with:
+ * mkTerm(Kind kind, Term child)
+ */
+ BAG_CHOOSE,
+ /**
+ * Bag is_singleton predicate (single element with multiplicity exactly one).
+ * Parameters: 1
+ * -[1]: Term of bag sort, is [1] a singleton bag?
+ * Create with:
+ * mkTerm(Kind kind, Term child)
+ */
+ BAG_IS_SINGLETON,
+ /**
+ * Bag.from_set converts a set to a bag.
+ * Parameters: 1
+ * -[1]: Term of set sort
+ * Create with:
+ * mkTerm(Kind kind, Term child)
+ */
+ BAG_FROM_SET,
+ /**
+ * Bag.to_set converts a bag to a set.
+ * Parameters: 1
+ * -[1]: Term of bag sort
+ * Create with:
+ * mkTerm(Kind kind, Term child)
+ */
+ BAG_TO_SET,
/* Strings --------------------------------------------------------------- */
@@ -2510,6 +2696,15 @@ enum CVC4_PUBLIC Kind : int32_t
* mkTerm(Kind kind, Term child1)
*/
SEQ_UNIT,
+ /**
+ * Sequence nth, corresponding to the nth element of a sequence.
+ * Parameters: 2
+ * -[1] Sequence term.
+ * -[2] Integer term.
+ * Create with:
+ * mkTerm(Kind kind, Term child1, Term child2)
+ */
+ SEQ_NTH,
/* Quantifiers ----------------------------------------------------------- */
@@ -2616,6 +2811,8 @@ enum CVC4_PUBLIC Kind : int32_t
SELECTOR_TYPE,
/* set type, takes as parameter the type of the elements */
SET_TYPE,
+ /* bag type, takes as parameter the type of the elements */
+ BAG_TYPE,
/* sort tag */
SORT_TAG,
/* specifies types of user-declared 'uninterpreted' sorts */
diff --git a/src/api/python/CMakeLists.txt b/src/api/python/CMakeLists.txt
index 1998954e5..dde29110f 100644
--- a/src/api/python/CMakeLists.txt
+++ b/src/api/python/CMakeLists.txt
@@ -1,3 +1,13 @@
+#####################
+## CMakeLists.txt
+## Top contributors (to current version):
+## Makai Mann
+## This file is part of the CVC4 project.
+## Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+## in the top-level source directory and their institutional affiliations.
+## All rights reserved. See the file COPYING in the top-level source
+## directory for licensing information.
+##
if(POLICY CMP0057)
# For cmake >= 3.3 this policy changed the behavior of IN_LIST
# if the policy exists, we use the NEW behavior
diff --git a/src/api/python/cvc4.pxd b/src/api/python/cvc4.pxd
index 940922052..19e7eb092 100644
--- a/src/api/python/cvc4.pxd
+++ b/src/api/python/cvc4.pxd
@@ -1,6 +1,7 @@
# import dereference and increment operators
from cython.operator cimport dereference as deref, preincrement as inc
from libc.stdint cimport int32_t, int64_t, uint32_t, uint64_t
+from libcpp.set cimport set
from libcpp.string cimport string
from libcpp.vector cimport vector
from libcpp.pair cimport pair
@@ -27,6 +28,12 @@ cdef extern from "api/cvc4cpp.h" namespace "CVC4::api":
Term getConstructorTerm(const string& name) except +
size_t getNumConstructors() except +
bint isParametric() except +
+ bint isCodatatype() except +
+ bint isTuple() except +
+ bint isRecord() except +
+ bint isFinite() except +
+ bint isWellFounded() except +
+ bint hasNestedRecursion() except +
string toString() except +
cppclass const_iterator:
const_iterator() except +
@@ -116,22 +123,26 @@ cdef extern from "api/cvc4cpp.h" namespace "CVC4::api":
cdef cppclass Solver:
Solver(Options*) except +
+ bint supportsFloatingPoint() except +
Sort getBooleanSort() except +
Sort getIntegerSort() except +
Sort getRealSort() except +
Sort getRegExpSort() except +
- Sort getRoundingmodeSort() except +
+ Sort getRoundingModeSort() except +
Sort getStringSort() except +
Sort mkArraySort(Sort indexSort, Sort elemSort) except +
Sort mkBitVectorSort(uint32_t size) except +
Sort mkFloatingPointSort(uint32_t exp, uint32_t sig) except +
Sort mkDatatypeSort(DatatypeDecl dtypedecl) except +
+ vector[Sort] mkDatatypeSorts(const vector[DatatypeDecl]& dtypedecls,
+ const set[Sort]& unresolvedSorts) except +
Sort mkFunctionSort(Sort domain, Sort codomain) except +
Sort mkFunctionSort(const vector[Sort]& sorts, Sort codomain) except +
Sort mkParamSort(const string& symbol) except +
Sort mkPredicateSort(const vector[Sort]& sorts) except +
Sort mkRecordSort(const vector[pair[string, Sort]]& fields) except +
Sort mkSetSort(Sort elemSort) except +
+ Sort mkSequenceSort(Sort elemSort) except +
Sort mkUninterpretedSort(const string& symbol) except +
Sort mkSortConstructorSort(const string& symbol, size_t arity) except +
Sort mkTupleSort(const vector[Sort]& sorts) except +
@@ -142,10 +153,27 @@ cdef extern from "api/cvc4cpp.h" namespace "CVC4::api":
Op mkOp(Kind kind, const string& arg) except +
Op mkOp(Kind kind, uint32_t arg) except +
Op mkOp(Kind kind, uint32_t arg1, uint32_t arg2) except +
+ # Sygus related functions
+ Grammar mkSygusGrammar(const vector[Term]& boundVars, const vector[Term]& ntSymbols) except +
+ Term mkSygusVar(Sort sort, const string& symbol) except +
+ Term mkSygusVar(Sort sort) except +
+ void addSygusConstraint(Term term) except +
+ void addSygusInvConstraint(Term inv_f, Term pre_f, Term trans_f, Term post_f) except +
+ Term synthFun(const string& symbol, const vector[Term]& bound_vars, Sort sort) except +
+ Term synthFun(const string& symbol, const vector[Term]& bound_vars, Sort sort, Grammar grammar) except +
+ Result checkSynth() except +
+ Term getSynthSolution(Term t) except +
+ vector[Term] getSynthSolutions(const vector[Term]& terms) except +
+ Term synthInv(const string& symbol, const vector[Term]& bound_vars) except +
+ Term synthInv(const string& symbol, const vector[Term]& bound_vars, Grammar grammar) except +
+ void printSynthSolution(ostream& out) except +
+ # End of sygus related functions
+
Term mkTrue() except +
Term mkFalse() except +
Term mkBoolean(bint val) except +
Term mkPi() except +
+ Term mkInteger(const string& s) except +
Term mkReal(const string& s) except +
Term mkRegexpEmpty() except +
Term mkRegexpSigma() except +
@@ -153,6 +181,7 @@ cdef extern from "api/cvc4cpp.h" namespace "CVC4::api":
Term mkSepNil(Sort sort) except +
Term mkString(const string& s) except +
Term mkString(const vector[unsigned]& s) except +
+ Term mkEmptySequence(Sort sort) except +
Term mkUniverseSet(Sort sort) except +
Term mkBitVector(uint32_t size) except +
Term mkBitVector(uint32_t size, uint64_t val) except +
@@ -200,17 +229,16 @@ cdef extern from "api/cvc4cpp.h" namespace "CVC4::api":
Term defineFunsRec(vector[Term]& funs, vector[vector[Term]]& bound_vars,
vector[Term]& terms, bint glbl) except +
vector[Term] getAssertions() except +
- vector[pair[Term, Term]] getAssignment() except +
string getInfo(const string& flag) except +
string getOption(string& option) except +
vector[Term] getUnsatAssumptions() except +
vector[Term] getUnsatCore() except +
Term getValue(Term term) except +
vector[Term] getValue(const vector[Term]& terms) except +
+ void declareSeparationHeap(Sort locSort, Sort dataSort) except +
Term getSeparationHeap() except +
Term getSeparationNilTerm() except +
void pop(uint32_t nscopes) except +
- void printModel(ostream& out)
void push(uint32_t nscopes) except +
void reset() except +
void resetAssertions() except +
@@ -218,6 +246,13 @@ cdef extern from "api/cvc4cpp.h" namespace "CVC4::api":
void setLogic(const string& logic) except +
void setOption(const string& option, const string& value) except +
+ cdef cppclass Grammar:
+ Grammar() except +
+ Grammar(Solver* solver, vector[Term] boundVars, vector[Term] ntSymbols) except +
+ void addRule(Term ntSymbol, Term rule) except +
+ void addAnyConstant(Term ntSymbol) except +
+ void addAnyVariable(Term ntSymbol) except +
+ void addRules(Term ntSymbol, vector[Term] rules) except +
cdef cppclass Sort:
Sort() except +
@@ -246,6 +281,7 @@ cdef extern from "api/cvc4cpp.h" namespace "CVC4::api":
bint isRecord() except +
bint isArray() except +
bint isSet() except +
+ bint isSequence() except +
bint isUninterpretedSort() except +
bint isSortConstructor() except +
bint isFirstClass() except +
@@ -263,6 +299,7 @@ cdef extern from "api/cvc4cpp.h" namespace "CVC4::api":
Sort getArrayIndexSort() except +
Sort getArrayElementSort() except +
Sort getSetElementSort() except +
+ Sort getSequenceElementSort() except +
string getUninterpretedSortName() except +
bint isUninterpretedSortParameterized() except +
vector[Sort] getUninterpretedSortParamSorts() except +
@@ -285,14 +322,15 @@ cdef extern from "api/cvc4cpp.h" namespace "CVC4::api":
Term()
bint operator==(const Term&) except +
bint operator!=(const Term&) except +
+ Term operator[](size_t idx) except +
Kind getKind() except +
Sort getSort() except +
Term substitute(const vector[Term] es, const vector[Term] & reps) except +
bint hasOp() except +
Op getOp() except +
bint isNull() except +
- bint isConst() except +
Term getConstArrayBase() except +
+ vector[Term] getConstSequenceElements() except +
Term notTerm() except +
Term andTerm(const Term& t) except +
Term orTerm(const Term& t) except +
diff --git a/src/api/python/cvc4.pxi b/src/api/python/cvc4.pxi
index 01660e206..c44fc08af 100644
--- a/src/api/python/cvc4.pxi
+++ b/src/api/python/cvc4.pxi
@@ -1,8 +1,11 @@
+from collections import defaultdict
+from fractions import Fraction
import sys
from libc.stdint cimport int32_t, int64_t, uint32_t, uint64_t
from libcpp.pair cimport pair
+from libcpp.set cimport set
from libcpp.string cimport string
from libcpp.vector cimport vector
@@ -17,10 +20,12 @@ from cvc4 cimport RoundingMode as c_RoundingMode
from cvc4 cimport Op as c_Op
from cvc4 cimport OpHashFunction as c_OpHashFunction
from cvc4 cimport Solver as c_Solver
+from cvc4 cimport Grammar as c_Grammar
from cvc4 cimport Sort as c_Sort
from cvc4 cimport SortHashFunction as c_SortHashFunction
from cvc4 cimport ROUND_NEAREST_TIES_TO_EVEN, ROUND_TOWARD_POSITIVE
-from cvc4 cimport ROUND_TOWARD_ZERO, ROUND_NEAREST_TIES_TO_AWAY
+from cvc4 cimport ROUND_TOWARD_NEGATIVE, ROUND_TOWARD_ZERO
+from cvc4 cimport ROUND_NEAREST_TIES_TO_AWAY
from cvc4 cimport Term as c_Term
from cvc4 cimport TermHashFunction as c_TermHashFunction
@@ -53,6 +58,22 @@ def expand_list_arg(num_req_args=0):
### always use c++ default arguments
#### only use default args of None at python level
+# References and pointers
+# The Solver object holds a pointer to a c_Solver.
+# This is because the assignment operator is deleted in the C++ API for solvers.
+# Cython has a limitation where you can't stack allocate objects
+# that have constructors with arguments:
+# https://groups.google.com/forum/#!topic/cython-users/fuKd-nQLpBs.
+# To get around that you can either have a nullary constructor and assignment
+# or, use a pointer (which is what we chose).
+# An additional complication of this is that to free up resources, you must
+# know when to delete the object.
+# Python will not follow the same scoping rules as in C++, so it must be
+# able to reference count. To do this correctly, the solver must be a
+# reference in the Python class for any class that keeps a pointer to
+# the solver in C++ (to ensure the solver is not deleted before something
+# that depends on it).
+
## Objects for hashing
cdef c_OpHashFunction cophash = c_OpHashFunction()
@@ -62,26 +83,27 @@ cdef c_TermHashFunction ctermhash = c_TermHashFunction()
cdef class Datatype:
cdef c_Datatype cd
- def __cinit__(self):
- pass
+ cdef Solver solver
+ def __cinit__(self, Solver solver):
+ self.solver = solver
def __getitem__(self, index):
- cdef DatatypeConstructor dc = DatatypeConstructor()
+ cdef DatatypeConstructor dc = DatatypeConstructor(self.solver)
if isinstance(index, int) and index >= 0:
dc.cdc = self.cd[(<int?> index)]
elif isinstance(index, str):
- dc.cdc = self.cd[(<const string &> name.encode())]
+ dc.cdc = self.cd[(<const string &> index.encode())]
else:
raise ValueError("Expecting a non-negative integer or string")
return dc
def getConstructor(self, str name):
- cdef DatatypeConstructor dc = DatatypeConstructor()
+ cdef DatatypeConstructor dc = DatatypeConstructor(self.solver)
dc.cdc = self.cd.getConstructor(name.encode())
return dc
def getConstructorTerm(self, str name):
- cdef Term term = Term()
+ cdef Term term = Term(self.solver)
term.cterm = self.cd.getConstructorTerm(name.encode())
return term
@@ -91,6 +113,24 @@ cdef class Datatype:
def isParametric(self):
return self.cd.isParametric()
+ def isCodatatype(self):
+ return self.cd.isCodatatype()
+
+ def isTuple(self):
+ return self.cd.isTuple()
+
+ def isRecord(self):
+ return self.cd.isRecord()
+
+ def isFinite(self):
+ return self.cd.isFinite()
+
+ def isWellFounded(self):
+ return self.cd.isWellFounded()
+
+ def hasNestedRecursion(self):
+ return self.cd.hasNestedRecursion()
+
def __str__(self):
return self.cd.toString().decode()
@@ -99,18 +139,20 @@ cdef class Datatype:
def __iter__(self):
for ci in self.cd:
- dc = DatatypeConstructor()
+ dc = DatatypeConstructor(self.solver)
dc.cdc = ci
yield dc
cdef class DatatypeConstructor:
cdef c_DatatypeConstructor cdc
- def __cinit__(self):
+ cdef Solver solver
+ def __cinit__(self, Solver solver):
self.cdc = c_DatatypeConstructor()
+ self.solver = solver
def __getitem__(self, index):
- cdef DatatypeSelector ds = DatatypeSelector()
+ cdef DatatypeSelector ds = DatatypeSelector(self.solver)
if isinstance(index, int) and index >= 0:
ds.cds = self.cdc[(<int?> index)]
elif isinstance(index, str):
@@ -123,12 +165,12 @@ cdef class DatatypeConstructor:
return self.cdc.getName().decode()
def getConstructorTerm(self):
- cdef Term term = Term()
+ cdef Term term = Term(self.solver)
term.cterm = self.cdc.getConstructorTerm()
return term
def getTesterTerm(self):
- cdef Term term = Term()
+ cdef Term term = Term(self.solver)
term.cterm = self.cdc.getTesterTerm()
return term
@@ -136,12 +178,12 @@ cdef class DatatypeConstructor:
return self.cdc.getNumSelectors()
def getSelector(self, str name):
- cdef DatatypeSelector ds = DatatypeSelector()
+ cdef DatatypeSelector ds = DatatypeSelector(self.solver)
ds.cds = self.cdc.getSelector(name.encode())
return ds
def getSelectorTerm(self, str name):
- cdef Term term = Term()
+ cdef Term term = Term(self.solver)
term.cterm = self.cdc.getSelectorTerm(name.encode())
return term
@@ -153,16 +195,17 @@ cdef class DatatypeConstructor:
def __iter__(self):
for ci in self.cdc:
- ds = DatatypeSelector()
+ ds = DatatypeSelector(self.solver)
ds.cds = ci
yield ds
cdef class DatatypeConstructorDecl:
cdef c_DatatypeConstructorDecl cddc
+ cdef Solver solver
- def __cinit__(self):
- pass
+ def __cinit__(self, Solver solver):
+ self.solver = solver
def addSelector(self, str name, Sort sort):
self.cddc.addSelector(name.encode(), sort.csort)
@@ -179,8 +222,9 @@ cdef class DatatypeConstructorDecl:
cdef class DatatypeDecl:
cdef c_DatatypeDecl cdd
- def __cinit__(self):
- pass
+ cdef Solver solver
+ def __cinit__(self, Solver solver):
+ self.solver = solver
def addConstructor(self, DatatypeConstructorDecl ctor):
self.cdd.addConstructor(ctor.cddc)
@@ -200,19 +244,21 @@ cdef class DatatypeDecl:
cdef class DatatypeSelector:
cdef c_DatatypeSelector cds
- def __cinit__(self):
+ cdef Solver solver
+ def __cinit__(self, Solver solver):
self.cds = c_DatatypeSelector()
+ self.solver = solver
def getName(self):
return self.cds.getName().decode()
def getSelectorTerm(self):
- cdef Term term = Term()
+ cdef Term term = Term(self.solver)
term.cterm = self.cds.getSelectorTerm()
return term
def getRangeSort(self):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self.solver)
sort.csort = self.cds.getRangeSort()
return sort
@@ -225,8 +271,10 @@ cdef class DatatypeSelector:
cdef class Op:
cdef c_Op cop
- def __cinit__(self):
+ cdef Solver solver
+ def __cinit__(self, Solver solver):
self.cop = c_Op()
+ self.solver = solver
def __eq__(self, Op other):
return self.cop == other.cop
@@ -271,6 +319,27 @@ cdef class Op:
return indices
+cdef class Grammar:
+ cdef c_Grammar cgrammar
+ cdef Solver solver
+ def __cinit__(self, Solver solver):
+ self.solver = solver
+ self.cgrammar = c_Grammar()
+
+ def addRule(self, Term ntSymbol, Term rule):
+ self.cgrammar.addRule(ntSymbol.cterm, rule.cterm)
+
+ def addAnyConstant(self, Term ntSymbol):
+ self.cgrammar.addAnyConstant(ntSymbol.cterm)
+
+ def addAnyVariable(self, Term ntSymbol):
+ self.cgrammar.addAnyVariable(ntSymbol.cterm)
+
+ def addRules(self, Term ntSymbol, rules):
+ cdef vector[c_Term] crules
+ for r in rules:
+ crules.push_back((<Term?> r).cterm)
+ self.cgrammar.addRules(ntSymbol.cterm, crules)
cdef class Result:
cdef c_Result cr
@@ -345,59 +414,85 @@ cdef class Solver:
def __cinit__(self):
self.csolver = new c_Solver(NULL)
+ def __dealloc__(self):
+ del self.csolver
+
+ def supportsFloatingPoint(self):
+ return self.csolver.supportsFloatingPoint()
+
def getBooleanSort(self):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
sort.csort = self.csolver.getBooleanSort()
return sort
def getIntegerSort(self):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
sort.csort = self.csolver.getIntegerSort()
return sort
def getRealSort(self):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
sort.csort = self.csolver.getRealSort()
return sort
def getRegExpSort(self):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
sort.csort = self.csolver.getRegExpSort()
return sort
- def getRoundingmodeSort(self):
- cdef Sort sort = Sort()
- sort.csort = self.csolver.getRoundingmodeSort()
+ def getRoundingModeSort(self):
+ cdef Sort sort = Sort(self)
+ sort.csort = self.csolver.getRoundingModeSort()
return sort
def getStringSort(self):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
sort.csort = self.csolver.getStringSort()
return sort
def mkArraySort(self, Sort indexSort, Sort elemSort):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
sort.csort = self.csolver.mkArraySort(indexSort.csort, elemSort.csort)
return sort
def mkBitVectorSort(self, uint32_t size):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
sort.csort = self.csolver.mkBitVectorSort(size)
return sort
def mkFloatingPointSort(self, uint32_t exp, uint32_t sig):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
sort.csort = self.csolver.mkFloatingPointSort(exp, sig)
return sort
def mkDatatypeSort(self, DatatypeDecl dtypedecl):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
sort.csort = self.csolver.mkDatatypeSort(dtypedecl.cdd)
return sort
+ def mkDatatypeSorts(self, list dtypedecls, unresolvedSorts):
+ sorts = []
+
+ cdef vector[c_DatatypeDecl] decls
+ for decl in dtypedecls:
+ decls.push_back((<DatatypeDecl?> decl).cdd)
+
+ cdef set[c_Sort] usorts
+ for usort in unresolvedSorts:
+ usorts.insert((<Sort?> usort).csort)
+
+ csorts = self.csolver.mkDatatypeSorts(
+ <const vector[c_DatatypeDecl]&> decls, <const set[c_Sort]&> usorts)
+ for csort in csorts:
+ sort = Sort(self)
+ sort.csort = csort
+ sorts.append(sort)
+
+ return sorts
+
def mkFunctionSort(self, sorts, Sort codomain):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
# populate a vector with dereferenced c_Sorts
cdef vector[c_Sort] v
@@ -413,7 +508,7 @@ cdef class Solver:
return sort
def mkParamSort(self, symbolname):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
sort.csort = self.csolver.mkParamSort(symbolname.encode())
return sort
@@ -426,7 +521,7 @@ cdef class Solver:
where sorts can also be comma-separated arguments of
type Sort
'''
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
cdef vector[c_Sort] v
for s in sorts:
v.push_back((<Sort?> s).csort)
@@ -442,7 +537,7 @@ cdef class Solver:
where fields can also be comma-separated arguments of
type Tuple[str, Sort]
'''
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
cdef vector[pair[string, c_Sort]] v
cdef pair[string, c_Sort] p
for f in fields:
@@ -455,17 +550,22 @@ cdef class Solver:
return sort
def mkSetSort(self, Sort elemSort):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
sort.csort = self.csolver.mkSetSort(elemSort.csort)
return sort
+ def mkSequenceSort(self, Sort elemSort):
+ cdef Sort sort = Sort(self)
+ sort.csort = self.csolver.mkSequenceSort(elemSort.csort)
+ return sort
+
def mkUninterpretedSort(self, str name):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
sort.csort = self.csolver.mkUninterpretedSort(name.encode())
return sort
def mkSortConstructorSort(self, str symbol, size_t arity):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
sort.csort =self.csolver.mkSortConstructorSort(symbol.encode(), arity)
return sort
@@ -478,7 +578,7 @@ cdef class Solver:
where sorts can also be comma-separated arguments of
type Sort
'''
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
cdef vector[c_Sort] v
for s in sorts:
v.push_back((<Sort?> s).csort)
@@ -495,7 +595,7 @@ cdef class Solver:
where List[Term] can also be comma-separated arguments
'''
- cdef Term term = Term()
+ cdef Term term = Term(self)
cdef vector[c_Term] v
op = kind_or_op
@@ -519,7 +619,7 @@ cdef class Solver:
Op mkOp(Kind kind, uint32_t arg)
Op mkOp(Kind kind, uint32_t arg0, uint32_t arg1)
'''
- cdef Op op = Op()
+ cdef Op op = Op(self)
if arg0 is None:
op.cop = self.csolver.mkOp(k.k)
@@ -545,27 +645,33 @@ cdef class Solver:
return op
def mkTrue(self):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkTrue()
return term
def mkFalse(self):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkFalse()
return term
def mkBoolean(self, bint val):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkBoolean(val)
return term
def mkPi(self):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkPi()
return term
+ def mkInteger(self, val):
+ cdef Term term = Term(self)
+ integer = int(val)
+ term.cterm = self.csolver.mkInteger("{}".format(integer).encode())
+ return term
+
def mkReal(self, val, den=None):
- cdef Term term = Term()
+ cdef Term term = Term(self)
if den is None:
term.cterm = self.csolver.mkReal(str(val).encode())
else:
@@ -577,30 +683,33 @@ cdef class Solver:
return term
def mkRegexpEmpty(self):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkRegexpEmpty()
return term
def mkRegexpSigma(self):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkRegexpSigma()
return term
def mkEmptySet(self, Sort s):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkEmptySet(s.csort)
return term
+
def mkSepNil(self, Sort sort):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkSepNil(sort.csort)
return term
def mkString(self, str_or_vec):
- cdef Term term = Term()
+ cdef Term term = Term(self)
cdef vector[unsigned] v
if isinstance(str_or_vec, str):
- term.cterm = self.csolver.mkString(<string &> str_or_vec.encode())
+ for u in str_or_vec:
+ v.push_back(<unsigned> ord(u))
+ term.cterm = self.csolver.mkString(<const vector[unsigned]&> v)
elif isinstance(str_or_vec, list):
for u in str_or_vec:
if not isinstance(u, int):
@@ -613,13 +722,18 @@ cdef class Solver:
" but got: {}".format(str_or_vec))
return term
+ def mkEmptySequence(self, Sort sort):
+ cdef Term term = Term(self)
+ term.cterm = self.csolver.mkEmptySequence(sort.csort)
+ return term
+
def mkUniverseSet(self, Sort sort):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkUniverseSet(sort.csort)
return term
def mkBitVector(self, size_or_str, val = None):
- cdef Term term = Term()
+ cdef Term term = Term(self)
if isinstance(size_or_str, int):
if val is None:
term.cterm = self.csolver.mkBitVector(<int> size_or_str)
@@ -640,47 +754,47 @@ cdef class Solver:
return term
def mkConstArray(self, Sort sort, Term val):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkConstArray(sort.csort, val.cterm)
return term
def mkPosInf(self, int exp, int sig):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkPosInf(exp, sig)
return term
def mkNegInf(self, int exp, int sig):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkNegInf(exp, sig)
return term
def mkNaN(self, int exp, int sig):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkNaN(exp, sig)
return term
def mkPosZero(self, int exp, int sig):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkPosZero(exp, sig)
return term
def mkNegZero(self, int exp, int sig):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkNegZero(exp, sig)
return term
def mkRoundingMode(self, RoundingMode rm):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkRoundingMode(<c_RoundingMode> rm.crm)
return term
def mkUninterpretedConst(self, Sort sort, int index):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkUninterpretedConst(sort.csort, index)
return term
def mkAbstractValue(self, index):
- cdef Term term = Term()
+ cdef Term term = Term(self)
try:
term.cterm = self.csolver.mkAbstractValue(str(index).encode())
except:
@@ -689,12 +803,12 @@ cdef class Solver:
return term
def mkFloatingPoint(self, int exp, int sig, Term val):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.mkFloatingPoint(exp, sig, val.cterm)
return term
def mkConst(self, Sort sort, symbol=None):
- cdef Term term = Term()
+ cdef Term term = Term(self)
if symbol is None:
term.cterm = self.csolver.mkConst(sort.csort)
else:
@@ -703,7 +817,7 @@ cdef class Solver:
return term
def mkVar(self, Sort sort, symbol=None):
- cdef Term term = Term()
+ cdef Term term = Term(self)
if symbol is None:
term.cterm = self.csolver.mkVar(sort.csort)
else:
@@ -712,12 +826,12 @@ cdef class Solver:
return term
def mkDatatypeConstructorDecl(self, str name):
- cdef DatatypeConstructorDecl ddc = DatatypeConstructorDecl()
+ cdef DatatypeConstructorDecl ddc = DatatypeConstructorDecl(self)
ddc.cddc = self.csolver.mkDatatypeConstructorDecl(name.encode())
return ddc
def mkDatatypeDecl(self, str name, sorts_or_bool=None, isCoDatatype=None):
- cdef DatatypeDecl dd = DatatypeDecl()
+ cdef DatatypeDecl dd = DatatypeDecl(self)
cdef vector[c_Sort] v
# argument cases
@@ -761,7 +875,7 @@ cdef class Solver:
return dd
def simplify(self, Term t):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.simplify(t.cterm)
return term
@@ -773,6 +887,63 @@ cdef class Solver:
r.cr = self.csolver.checkSat()
return r
+ def mkSygusGrammar(self, boundVars, ntSymbols):
+ cdef Grammar grammar = Grammar(self)
+ cdef vector[c_Term] bvc
+ cdef vector[c_Term] ntc
+ for bv in boundVars:
+ bvc.push_back((<Term?> bv).cterm)
+ for nt in ntSymbols:
+ ntc.push_back((<Term?> nt).cterm)
+ grammar.cgrammar = self.csolver.mkSygusGrammar(<const vector[c_Term]&> bvc, <const vector[c_Term]&> ntc)
+ return grammar
+
+ def mkSygusVar(self, Sort sort, str symbol=""):
+ cdef Term term = Term(self)
+ term.cterm = self.csolver.mkSygusVar(sort.csort, symbol.encode())
+ return term
+
+ def addSygusConstraint(self, Term t):
+ self.csolver.addSygusConstraint(t.cterm)
+
+ def addSygusInvConstraint(self, Term inv_f, Term pre_f, Term trans_f, Term post_f):
+ self.csolver.addSygusInvConstraint(inv_f.cterm, pre_f.cterm, trans_f.cterm, post_f.cterm)
+
+ def synthFun(self, str symbol, bound_vars, Sort sort, Grammar grammar=None):
+ cdef Term term = Term(self)
+ cdef vector[c_Term] v
+ for bv in bound_vars:
+ v.push_back((<Term?> bv).cterm)
+ if grammar is None:
+ term.cterm = self.csolver.synthFun(symbol.encode(), <const vector[c_Term]&> v, sort.csort)
+ else:
+ term.cterm = self.csolver.synthFun(symbol.encode(), <const vector[c_Term]&> v, sort.csort, grammar.cgrammar)
+ return term
+
+ def checkSynth(self):
+ cdef Result r = Result()
+ r.cr = self.csolver.checkSynth()
+ return r
+
+ def getSynthSolution(self, Term term):
+ cdef Term t = Term(self)
+ t.cterm = self.csolver.getSynthSolution(term.cterm)
+ return t
+
+ def synthInv(self, symbol, bound_vars, Grammar grammar=None):
+ cdef Term term = Term(self)
+ cdef vector[c_Term] v
+ for bv in bound_vars:
+ v.push_back((<Term?> bv).cterm)
+ if grammar is None:
+ term.cterm = self.csolver.synthInv(symbol.encode(), <const vector[c_Term]&> v)
+ else:
+ term.cterm = self.csolver.synthInv(symbol.encode(), <const vector[c_Term]&> v, grammar.cgrammar)
+ return term
+
+ def printSynthSolution(self):
+ self.csolver.printSynthSolution(cout)
+
@expand_list_arg(num_req_args=0)
def checkSatAssuming(self, *assumptions):
'''
@@ -816,7 +987,7 @@ cdef class Solver:
where ctors can also be comma-separated arguments of
type DatatypeConstructorDecl
'''
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
cdef vector[c_DatatypeConstructorDecl] v
for c in ctors:
@@ -825,7 +996,7 @@ cdef class Solver:
return sort
def declareFun(self, str symbol, list sorts, Sort sort):
- cdef Term term = Term()
+ cdef Term term = Term(self)
cdef vector[c_Sort] v
for s in sorts:
v.push_back((<Sort?> s).csort)
@@ -835,7 +1006,7 @@ cdef class Solver:
return term
def declareSort(self, str symbol, int arity):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self)
sort.csort = self.csolver.declareSort(symbol.encode(), arity)
return sort
@@ -847,7 +1018,7 @@ cdef class Solver:
Term defineFun(Term fun, List[Term] bound_vars,
Term term, bool glbl)
'''
- cdef Term term = Term()
+ cdef Term term = Term(self)
cdef vector[c_Term] v
for bv in bound_vars:
v.push_back((<Term?> bv).cterm)
@@ -874,7 +1045,7 @@ cdef class Solver:
Term defineFunRec(Term fun, List[Term] bound_vars,
Term term, bool glbl)
'''
- cdef Term term = Term()
+ cdef Term term = Term(self)
cdef vector[c_Term] v
for bv in bound_vars:
v.push_back((<Term?> bv).cterm)
@@ -914,24 +1085,11 @@ cdef class Solver:
def getAssertions(self):
assertions = []
for a in self.csolver.getAssertions():
- term = Term()
+ term = Term(self)
term.cterm = a
assertions.append(term)
return assertions
- def getAssignment(self):
- '''
- Gives the assignment of *named* formulas as a dictionary.
- '''
- assignments = {}
- for a in self.csolver.getAssignment():
- varterm = Term()
- valterm = Term()
- varterm.cterm = a.first
- valterm.cterm = a.second
- assignments[varterm] = valterm
- return assignments
-
def getInfo(self, str flag):
return self.csolver.getInfo(flag.encode())
@@ -941,7 +1099,7 @@ cdef class Solver:
def getUnsatAssumptions(self):
assumptions = []
for a in self.csolver.getUnsatAssumptions():
- term = Term()
+ term = Term(self)
term.cterm = a
assumptions.append(term)
return assumptions
@@ -949,32 +1107,32 @@ cdef class Solver:
def getUnsatCore(self):
core = []
for a in self.csolver.getUnsatCore():
- term = Term()
+ term = Term(self)
term.cterm = a
core.append(term)
return core
def getValue(self, Term t):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.getValue(t.cterm)
return term
def getSeparationHeap(self):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.getSeparationHeap()
return term
+ def declareSeparationHeap(self, Sort locType, Sort dataType):
+ self.csolver.declareSeparationHeap(locType.csort, dataType.csort)
+
def getSeparationNilTerm(self):
- cdef Term term = Term()
+ cdef Term term = Term(self)
term.cterm = self.csolver.getSeparationNilTerm()
return term
def pop(self, nscopes=1):
self.csolver.pop(nscopes)
- def printModel(self):
- self.csolver.printModel(cout)
-
def push(self, nscopes=1):
self.csolver.push(nscopes)
@@ -993,9 +1151,10 @@ cdef class Solver:
cdef class Sort:
cdef c_Sort csort
- def __cinit__(self):
+ cdef Solver solver
+ def __cinit__(self, Solver solver):
# csort always set by Solver
- pass
+ self.solver = solver
def __eq__(self, Sort other):
return self.csort == other.csort
@@ -1081,6 +1240,9 @@ cdef class Sort:
def isSet(self):
return self.csort.isSet()
+ def isSequence(self):
+ return self.csort.isSequence()
+
def isUninterpretedSort(self):
return self.csort.isUninterpretedSort()
@@ -1100,12 +1262,12 @@ cdef class Sort:
return self.csort.isComparableTo(sort.csort)
def getDatatype(self):
- cdef Datatype d = Datatype()
+ cdef Datatype d = Datatype(self.solver)
d.cd = self.csort.getDatatype()
return d
def instantiate(self, params):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self.solver)
cdef vector[c_Sort] v
for s in params:
v.push_back((<Sort?> s).csort)
@@ -1118,13 +1280,13 @@ cdef class Sort:
def getConstructorDomainSorts(self):
domain_sorts = []
for s in self.csort.getConstructorDomainSorts():
- sort = Sort()
+ sort = Sort(self.solver)
sort.csort = s
domain_sorts.append(sort)
return domain_sorts
def getConstructorCodomainSort(self):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self.solver)
sort.csort = self.csort.getConstructorCodomainSort()
return sort
@@ -1134,31 +1296,36 @@ cdef class Sort:
def getFunctionDomainSorts(self):
domain_sorts = []
for s in self.csort.getFunctionDomainSorts():
- sort = Sort()
+ sort = Sort(self.solver)
sort.csort = s
domain_sorts.append(sort)
return domain_sorts
def getFunctionCodomainSort(self):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self.solver)
sort.csort = self.csort.getFunctionCodomainSort()
return sort
def getArrayIndexSort(self):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self.solver)
sort.csort = self.csort.getArrayIndexSort()
return sort
def getArrayElementSort(self):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self.solver)
sort.csort = self.csort.getArrayElementSort()
return sort
def getSetElementSort(self):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self.solver)
sort.csort = self.csort.getSetElementSort()
return sort
+ def getSequenceElementSort(self):
+ cdef Sort sort = Sort(self.solver)
+ sort.csort = self.csort.getSequenceElementSort()
+ return sort
+
def getUninterpretedSortName(self):
return self.csort.getUninterpretedSortName().decode()
@@ -1168,7 +1335,7 @@ cdef class Sort:
def getUninterpretedSortParamSorts(self):
param_sorts = []
for s in self.csort.getUninterpretedSortParamSorts():
- sort = Sort()
+ sort = Sort(self.solver)
sort.csort = s
param_sorts.append(sort)
return param_sorts
@@ -1191,7 +1358,7 @@ cdef class Sort:
def getDatatypeParamSorts(self):
param_sorts = []
for s in self.csort.getDatatypeParamSorts():
- sort = Sort()
+ sort = Sort(self.solver)
sort.csort = s
param_sorts.append(sort)
return param_sorts
@@ -1205,7 +1372,7 @@ cdef class Sort:
def getTupleSorts(self):
tuple_sorts = []
for s in self.csort.getTupleSorts():
- sort = Sort()
+ sort = Sort(self.solver)
sort.csort = s
tuple_sorts.append(sort)
return tuple_sorts
@@ -1213,9 +1380,10 @@ cdef class Sort:
cdef class Term:
cdef c_Term cterm
- def __cinit__(self):
+ cdef Solver solver
+ def __cinit__(self, Solver solver):
# cterm always set in the Solver object
- pass
+ self.solver = solver
def __eq__(self, Term other):
return self.cterm == other.cterm
@@ -1223,6 +1391,14 @@ cdef class Term:
def __ne__(self, Term other):
return self.cterm != other.cterm
+ def __getitem__(self, int index):
+ cdef Term term = Term(self.solver)
+ if index >= 0:
+ term.cterm = self.cterm[index]
+ else:
+ raise ValueError("Expecting a non-negative integer or string")
+ return term
+
def __str__(self):
return self.cterm.toString().decode()
@@ -1231,7 +1407,7 @@ cdef class Term:
def __iter__(self):
for ci in self.cterm:
- term = Term()
+ term = Term(self.solver)
term.cterm = ci
yield term
@@ -1242,14 +1418,14 @@ cdef class Term:
return kind(<int> self.cterm.getKind())
def getSort(self):
- cdef Sort sort = Sort()
+ cdef Sort sort = Sort(self.solver)
sort.csort = self.cterm.getSort()
return sort
def substitute(self, list es, list replacements):
cdef vector[c_Term] ces
cdef vector[c_Term] creplacements
- cdef Term term = Term()
+ cdef Term term = Term(self.solver)
if len(es) != len(replacements):
raise RuntimeError("Expecting list inputs to substitute to "
@@ -1267,61 +1443,177 @@ cdef class Term:
return self.cterm.hasOp()
def getOp(self):
- cdef Op op = Op()
+ cdef Op op = Op(self.solver)
op.cop = self.cterm.getOp()
return op
def isNull(self):
return self.cterm.isNull()
- def isConst(self):
- return self.cterm.isConst()
-
def getConstArrayBase(self):
- cdef Term term = Term()
+ cdef Term term = Term(self.solver)
term.cterm = self.cterm.getConstArrayBase()
return term
+ def getConstSequenceElements(self):
+ elems = []
+ for e in self.cterm.getConstSequenceElements():
+ term = Term(self.solver)
+ term.cterm = e
+ elems.append(term)
+ return elems
+
def notTerm(self):
- cdef Term term = Term()
+ cdef Term term = Term(self.solver)
term.cterm = self.cterm.notTerm()
return term
def andTerm(self, Term t):
- cdef Term term = Term()
+ cdef Term term = Term(self.solver)
term.cterm = self.cterm.andTerm((<Term> t).cterm)
return term
def orTerm(self, Term t):
- cdef Term term = Term()
+ cdef Term term = Term(self.solver)
term.cterm = self.cterm.orTerm(t.cterm)
return term
def xorTerm(self, Term t):
- cdef Term term = Term()
+ cdef Term term = Term(self.solver)
term.cterm = self.cterm.xorTerm(t.cterm)
return term
def eqTerm(self, Term t):
- cdef Term term = Term()
+ cdef Term term = Term(self.solver)
term.cterm = self.cterm.eqTerm(t.cterm)
return term
def impTerm(self, Term t):
- cdef Term term = Term()
+ cdef Term term = Term(self.solver)
term.cterm = self.cterm.impTerm(t.cterm)
return term
def iteTerm(self, Term then_t, Term else_t):
- cdef Term term = Term()
+ cdef Term term = Term(self.solver)
term.cterm = self.cterm.iteTerm(then_t.cterm, else_t.cterm)
return term
+ def toPythonObj(self):
+ '''
+ Converts a constant value Term to a Python object.
+
+ Currently supports:
+ Boolean -- returns a Python bool
+ Int -- returns a Python int
+ Real -- returns a Python Fraction
+ BV -- returns a Python int (treats BV as unsigned)
+ Array -- returns a Python dict mapping indices to values
+ -- the constant base is returned as the default value
+ String -- returns a Python Unicode string
+ '''
+
+ string_repr = self.cterm.toString().decode()
+ assert string_repr
+ sort = self.getSort()
+ res = None
+ if sort.isBoolean():
+ if string_repr == "true":
+ res = True
+ else:
+ assert string_repr == "false"
+ res = False
+ elif sort.isInteger():
+ updated_string_repr = string_repr.strip('()').replace(' ', '')
+ try:
+ res = int(updated_string_repr)
+ except:
+ raise ValueError("Failed to convert"
+ " {} to an int".format(string_repr))
+ elif sort.isReal():
+ updated_string_repr = string_repr
+ try:
+ # expecting format (/ a b)
+ # note: a or b could be negated: (- a)
+ splits = [s.strip('()/')
+ for s in updated_string_repr.strip('()/') \
+ .replace('(- ', '(-').split()]
+ assert len(splits) == 2
+ num = int(splits[0])
+ den = int(splits[1])
+ res = Fraction(num, den)
+ except:
+ raise ValueError("Failed to convert "
+ "{} to a Fraction".format(string_repr))
+
+ elif sort.isBitVector():
+ # expecting format #b<bits>
+ assert string_repr[:2] == "#b"
+ python_bin_repr = "0" + string_repr[1:]
+ try:
+ res = int(python_bin_repr, 2)
+ except:
+ raise ValueError("Failed to convert bitvector "
+ "{} to an int".format(string_repr))
+ elif sort.isArray():
+ keys = []
+ values = []
+ base_value = None
+ to_visit = [self]
+ # Array models are represented as a series of store operations
+ # on a constant array
+ while to_visit:
+ t = to_visit.pop()
+ if t.getKind() == kinds.Store:
+ # save the mappings
+ keys.append(t[1].toPythonObj())
+ values.append(t[2].toPythonObj())
+ to_visit.append(t[0])
+ else:
+ assert t.getKind() == kinds.ConstArray
+ base_value = t.getConstArrayBase().toPythonObj()
+
+ assert len(keys) == len(values)
+ assert base_value is not None
+
+ # put everything in a dictionary with the constant
+ # base as the result for any index not included in the stores
+ res = defaultdict(lambda : base_value)
+ for k, v in zip(keys, values):
+ res[k] = v
+ elif sort.isString():
+ # Strip leading and trailing double quotes and replace double
+ # double quotes by single quotes
+ string_repr = string_repr[1:-1].replace('""', '"')
+
+ # Convert escape sequences
+ res = ''
+ escape_prefix = '\\u{'
+ i = 0
+ while True:
+ prev_i = i
+ i = string_repr.find(escape_prefix, i)
+ if i == -1:
+ res += string_repr[prev_i:]
+ break
+
+ res += string_repr[prev_i:i]
+ val = string_repr[i + len(escape_prefix):string_repr.find('}', i)]
+ res += chr(int(val, 16))
+ i += len(escape_prefix) + len(val) + 1
+ else:
+ raise ValueError("Cannot convert term {}"
+ " of sort {} to Python object".format(string_repr,
+ sort))
+
+ assert res is not None
+ return res
+
# Generate rounding modes
cdef __rounding_modes = {
<int> ROUND_NEAREST_TIES_TO_EVEN: "RoundNearestTiesToEven",
<int> ROUND_TOWARD_POSITIVE: "RoundTowardPositive",
+ <int> ROUND_TOWARD_NEGATIVE: "RoundTowardNegative",
<int> ROUND_TOWARD_ZERO: "RoundTowardZero",
<int> ROUND_NEAREST_TIES_TO_AWAY: "RoundNearestTiesToAway"
}
diff --git a/src/api/python/genkinds.py b/src/api/python/genkinds.py
index 77b168dea..6f54657a8 100755..100644
--- a/src/api/python/genkinds.py
+++ b/src/api/python/genkinds.py
@@ -1,4 +1,14 @@
#!/usr/bin/env python
+#####################
+## genkinds.py
+## Top contributors (to current version):
+## Makai Mann
+## This file is part of the CVC4 project.
+## Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+## in the top-level source directory and their institutional affiliations.
+## All rights reserved. See the file COPYING in the top-level source
+## directory for licensing information.
+##
"""
This script reads CVC4/src/api/cvc4cppkind.h and generates
.pxd and .pxi files which declare all the CVC4 kinds and
diff --git a/src/api/python/setup.py.in b/src/api/python/setup.py.in
index 079aa468e..0138da034 100644
--- a/src/api/python/setup.py.in
+++ b/src/api/python/setup.py.in
@@ -1,12 +1,22 @@
#!/usr/bin/env python
-
-# This script is automatically configured with cmake when CVC4
-# is built with --python-bindings. It is called during make
-# install to automatically install the python bindings using
-# distutils.
-# If it is called from a python virtualenv, the bindings are
-# installed in the virtualenv, otherwise, it respects the
-# configured install prefix using the setup.py --prefix option
+#####################
+## setup.py.in
+## Top contributors (to current version):
+## Makai Mann
+## This file is part of the CVC4 project.
+## Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+## in the top-level source directory and their institutional affiliations.
+## All rights reserved. See the file COPYING in the top-level source
+## directory for licensing information.
+##
+## This script is automatically configured with cmake when CVC4
+## is built with --python-bindings. It is called during make
+## install to automatically install the python bindings using
+## distutils.
+## If it is called from a python virtualenv, the bindings are
+## installed in the virtualenv, otherwise, it respects the
+## configured install prefix using the setup.py --prefix option
+##
from distutils.core import setup
from distutils.command.clean import clean
diff --git a/src/base/CMakeLists.txt b/src/base/CMakeLists.txt
index a34716fea..e28bd78cc 100644
--- a/src/base/CMakeLists.txt
+++ b/src/base/CMakeLists.txt
@@ -1,3 +1,13 @@
+#####################
+## CMakeLists.txt
+## Top contributors (to current version):
+## Mathias Preiner, Andrew V. Jones, Aina Niemetz
+## This file is part of the CVC4 project.
+## Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+## in the top-level source directory and their institutional affiliations.
+## All rights reserved. See the file COPYING in the top-level source
+## directory for licensing information.
+##
#-----------------------------------------------------------------------------#
# Extract info from Git for git_versioninfo.cpp
# Note: GitInfo.cmake generates git_versioninfo.cpp.
diff --git a/src/base/GitInfo.cmake.in b/src/base/GitInfo.cmake.in
index 2d02095dd..abcb64249 100644
--- a/src/base/GitInfo.cmake.in
+++ b/src/base/GitInfo.cmake.in
@@ -1,3 +1,13 @@
+#####################
+## GitInfo.cmake.in
+## Top contributors (to current version):
+## Aina Niemetz, Mathias Preiner
+## This file is part of the CVC4 project.
+## Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+## in the top-level source directory and their institutional affiliations.
+## All rights reserved. See the file COPYING in the top-level source
+## directory for licensing information.
+##
set(GIT_BUILD "false")
set(GIT_IS_DIRTY "false")
set(GIT_SHA1 "")
diff --git a/src/base/check.cpp b/src/base/check.cpp
index b81e7b457..d1fbc28b4 100644
--- a/src/base/check.cpp
+++ b/src/base/check.cpp
@@ -5,7 +5,7 @@
** Mathias Preiner, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/base/check.h b/src/base/check.h
index 614a844fd..c7a6b24aa 100644
--- a/src/base/check.h
+++ b/src/base/check.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Tim King, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/base/configuration.cpp b/src/base/configuration.cpp
index 5fcc5170b..98c323626 100644
--- a/src/base/configuration.cpp
+++ b/src/base/configuration.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Aina Niemetz, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -88,6 +88,15 @@ bool Configuration::isCompetitionBuild() {
return IS_COMPETITION_BUILD;
}
+bool Configuration::isStaticBuild()
+{
+#if defined(CVC4_STATIC_BUILD)
+ return true;
+#else
+ return false;
+#endif
+}
+
string Configuration::getPackageName() {
return CVC4_PACKAGE_NAME;
}
@@ -139,7 +148,8 @@ std::string Configuration::copyright() {
|| Configuration::isBuiltWithCadical()
|| Configuration::isBuiltWithCryptominisat()
|| Configuration::isBuiltWithKissat()
- || Configuration::isBuiltWithSymFPU())
+ || Configuration::isBuiltWithSymFPU()
+ || Configuration::isBuiltWithEditline())
{
ss << "This version of CVC4 is linked against the following non-(L)GPL'ed\n"
<< "third party libraries.\n\n";
@@ -177,9 +187,15 @@ std::string Configuration::copyright() {
<< " See https://github.com/martin-cs/symfpu/tree/CVC4 for copyright "
<< "information.\n\n";
}
+ if (Configuration::isBuiltWithEditline())
+ {
+ ss << " Editline Library\n"
+ << " See https://thrysoee.dk/editline\n"
+ << " for copyright information.\n\n";
+ }
}
- if (Configuration::isBuiltWithGmp())
+ if (Configuration::isBuiltWithGmp() || Configuration::isBuiltWithPoly())
{
ss << "This version of CVC4 is linked against the following third party\n"
<< "libraries covered by the LGPLv3 license.\n"
@@ -188,11 +204,23 @@ std::string Configuration::copyright() {
ss << " GMP - Gnu Multi Precision Arithmetic Library\n"
<< " See http://gmplib.org for copyright information.\n\n";
}
+ if (Configuration::isBuiltWithPoly())
+ {
+ ss << " LibPoly polynomial library\n"
+ << " See https://github.com/SRI-CSL/libpoly for copyright and\n"
+ << " licensing information.\n\n";
+ }
+ if (Configuration::isStaticBuild())
+ {
+ ss << "CVC4 is statically linked against these libraries. To recompile\n"
+ "this version of CVC4 with different versions of these libraries\n"
+ "follow the instructions on "
+ "https://github.com/CVC4/CVC4/blob/master/INSTALL.md\n\n";
+ }
}
if (Configuration::isBuiltWithCln()
- || Configuration::isBuiltWithGlpk ()
- || Configuration::isBuiltWithReadline()) {
+ || Configuration::isBuiltWithGlpk ()) {
ss << "This version of CVC4 is linked against the following third party\n"
<< "libraries covered by the GPLv3 license.\n"
<< "See licenses/gpl-3.0.txt for more information.\n\n";
@@ -206,11 +234,6 @@ std::string Configuration::copyright() {
<< " See http://github.com/timothy-king/glpk-cut-log for copyright"
<< "information\n\n";
}
- if (Configuration::isBuiltWithReadline()) {
- ss << " GNU Readline\n"
- << " See http://cnswww.cns.cwru.edu/php/chet/readline/rltop.html\n"
- << " for copyright information.\n\n";
- }
}
ss << "See the file COPYING (distributed with the source code, and with\n"
@@ -261,14 +284,17 @@ bool Configuration::isBuiltWithKissat() { return IS_KISSAT_BUILD; }
bool Configuration::isBuiltWithDrat2Er() { return IS_DRAT2ER_BUILD; }
-bool Configuration::isBuiltWithReadline() {
- return IS_READLINE_BUILD;
-}
+bool Configuration::isBuiltWithEditline() { return IS_EDITLINE_BUILD; }
bool Configuration::isBuiltWithLfsc() {
return IS_LFSC_BUILD;
}
+bool Configuration::isBuiltWithPoly()
+{
+ return IS_POLY_BUILD;
+}
+
bool Configuration::isBuiltWithSymFPU() { return IS_SYMFPU_BUILD; }
unsigned Configuration::getNumDebugTags() {
diff --git a/src/base/configuration.h b/src/base/configuration.h
index de060fa00..b91ce5e20 100644
--- a/src/base/configuration.h
+++ b/src/base/configuration.h
@@ -5,7 +5,7 @@
** Morgan Deters, Francois Bobot, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -69,6 +69,8 @@ public:
static bool isCompetitionBuild();
+ static bool isStaticBuild();
+
static std::string getPackageName();
static std::string getVersionString();
@@ -103,10 +105,12 @@ public:
static bool isBuiltWithDrat2Er();
- static bool isBuiltWithReadline();
+ static bool isBuiltWithEditline();
static bool isBuiltWithLfsc();
+ static bool isBuiltWithPoly();
+
static bool isBuiltWithSymFPU();
/* Return the number of debug tags */
diff --git a/src/base/configuration_private.h b/src/base/configuration_private.h
index 9c58e7898..1df78fa22 100644
--- a/src/base/configuration_private.h
+++ b/src/base/configuration_private.h
@@ -5,7 +5,7 @@
** Christopher L. Conway, Andres Noetzli, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -138,11 +138,17 @@ namespace CVC4 {
#define IS_LFSC_BUILD false
#endif /* CVC4_USE_LFSC */
-#if HAVE_LIBREADLINE
-# define IS_READLINE_BUILD true
-#else /* HAVE_LIBREADLINE */
-# define IS_READLINE_BUILD false
-#endif /* HAVE_LIBREADLINE */
+#if CVC4_USE_POLY
+#define IS_POLY_BUILD true
+#else /* CVC4_USE_POLY */
+#define IS_POLY_BUILD false
+#endif /* CVC4_USE_POLY */
+
+#if HAVE_LIBEDITLINE
+#define IS_EDITLINE_BUILD true
+#else /* HAVE_LIBEDITLINE */
+#define IS_EDITLINE_BUILD false
+#endif /* HAVE_LIBEDITLINE */
#ifdef CVC4_USE_SYMFPU
#define IS_SYMFPU_BUILD true
diff --git a/src/base/exception.cpp b/src/base/exception.cpp
index 5e9135021..2a8dc8d10 100644
--- a/src/base/exception.cpp
+++ b/src/base/exception.cpp
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/base/exception.h b/src/base/exception.h
index afd5731e9..1d49d94cc 100644
--- a/src/base/exception.h
+++ b/src/base/exception.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/base/git_versioninfo.cpp.in b/src/base/git_versioninfo.cpp.in
index 478ea1f9c..e2ea31916 100644
--- a/src/base/git_versioninfo.cpp.in
+++ b/src/base/git_versioninfo.cpp.in
@@ -5,7 +5,7 @@
** Aina Niemetz, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/base/listener.cpp b/src/base/listener.cpp
index 63617f978..72f9ee086 100644
--- a/src/base/listener.cpp
+++ b/src/base/listener.cpp
@@ -5,7 +5,7 @@
** Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,75 +25,5 @@ namespace CVC4 {
Listener::Listener(){}
Listener::~Listener(){}
-ListenerCollection::ListenerCollection() : d_listeners() {}
-ListenerCollection::~ListenerCollection() { Assert(empty()); }
-
-ListenerCollection::iterator ListenerCollection::addListener(Listener* listener)
-{
- return d_listeners.insert(d_listeners.end(), listener);
-}
-
-void ListenerCollection::removeListener(iterator position) {
- d_listeners.erase(position);
-}
-
-void ListenerCollection::notify() {
- for(iterator i = d_listeners.begin(), iend = d_listeners.end(); i != iend;
- ++i)
- {
- Listener* listener = *i;
- listener->notify();
- }
-}
-
-bool ListenerCollection::empty() const { return d_listeners.empty(); }
-
-
-ListenerCollection::Registration::Registration(
- ListenerCollection* collection, Listener* listener)
- : d_listener(listener)
- , d_position()
- , d_collection(collection)
-{
- d_position = d_collection->addListener(d_listener);
-}
-
-ListenerCollection::Registration::~Registration() {
- d_collection->removeListener(d_position);
- delete d_listener;
-}
-
- ListenerCollection::Registration* ListenerCollection::registerListener(
- Listener* listener)
-{
- return new Registration(this, listener);
-}
-
-
-ListenerRegistrationList::ListenerRegistrationList()
- : d_registrations()
-{}
-
-ListenerRegistrationList::~ListenerRegistrationList() {
- clear();
-}
-
-void ListenerRegistrationList::add(
- ListenerCollection::Registration* registration)
-{
- d_registrations.push_back(registration);
-}
-
-void ListenerRegistrationList::clear(){
- typedef std::list<ListenerCollection::Registration*>::iterator iterator;
- for(iterator i = d_registrations.begin(), iend = d_registrations.end();
- i != iend; ++i)
- {
- ListenerCollection::Registration* current = *i;
- delete current;
- }
- d_registrations.clear();
-}
-
}/* CVC4 namespace */
diff --git a/src/base/listener.h b/src/base/listener.h
index e131d0420..15256ab01 100644
--- a/src/base/listener.h
+++ b/src/base/listener.h
@@ -2,20 +2,17 @@
/*! \file listener.h
** \verbatim
** Top contributors (to current version):
- ** Tim King, Andres Noetzli, Mathias Preiner
+ ** Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
** \brief Utility classes for listeners and collections of listeners.
**
** Utilities for the development of a Listener interface class. This class
- ** provides a single notification that must be overwritten. This file also
- ** provides a utility class for a collection of listeners and an RAII style
- ** Registration class for managing the relationship between Listeners
- ** and the collection.
+ ** provides a single notification that must be overwritten.
**/
#include "cvc4_public.h"
@@ -41,124 +38,6 @@ public:
virtual void notify() = 0;
};
-/**
- * ListenerCollection is a list of Listener instances.
- * One can add and remove Listeners.
- *
- * ListenerCollection does not own the memory of the Listeners.
- * As a sanity check, it asserted that all of its listeners
- * have been removed.
- */
-class CVC4_PUBLIC ListenerCollection {
-public:
- typedef std::list<Listener*> ListenerList;
- typedef ListenerList::iterator iterator;
-
- /** Creates an empty listener collection. */
- ListenerCollection();
-
- /**
- * Destroys an iterator collection.
- * If assertions are on, this throws an AssertionException if the collection
- * is not empty().
- */
- ~ListenerCollection();
-
- /**
- * This adds a listener to the current collection and returns
- * an iterator to the listener in the collection.
- * The user of the collection must call removeListener() using
- * this iterator.
- * The collection does not take over the memory for the listener.
- */
- iterator addListener(Listener* listener);
-
- /**
- * Remove an listener using the iterator distributed when adding the
- * listener.
- */
- void removeListener(iterator position);
-
- /** Calls notify() on all listeners in the collection. */
- void notify();
-
- /** Returns true if the collection contains no listeners. */
- bool empty() const;
-
- /**
- * Registration is an RAII utility function for using Listener
- * with ListenerCollection.
- *
- * On construction, the Registration takes a ListenerCollection,
- * collection,
- * and a Listener*, listener. It takes over the memory for listener. It then
- * adds listener to collection. On destruction it removes listener and calls
- * delete on listener.
- *
- * Because of this usage, a Registration must be destroyed before the
- * ListenerCollection it is attached to.
- */
- class CVC4_PUBLIC Registration {
- public:
- Registration(ListenerCollection* collection, Listener* listener);
- ~Registration();
-
- private:
- Listener* d_listener;
- ListenerCollection::iterator d_position;
- ListenerCollection* d_collection;
- };/* class CVC4::ListenerCollection::Registration */
-
-
- /**
- * Returns a new Registration given a Listener that is attached to this
- * ListenerCollection. Management of the memory is handed to the user of
- * this function. To remove the listener, call the destructor for the
- * Registration.
- */
- Registration* registerListener(Listener* listener);
-
-private:
-
- /**
- * Disabling the copy-constructor.
- * The user of the class must be know to remove listeners on the collection.
- * Allowing copies will only cause confusion.
- */
- ListenerCollection(const ListenerCollection& copy) = delete;
-
- /**
- * Disabling the assignment operator.
- * The user of the class must be know to remove listeners on the collection.
- * Allowing copies will only cause confusion.
- */
- ListenerCollection& operator=(const ListenerCollection& copy) = delete;
-
- /** A list of the listeners in the collection.*/
- ListenerList d_listeners;
-};/* class CVC4::ListenerCollection */
-
-/**
- * A list of ListenerCollection::Registration* pointers.
- *
- * This list assumes it has control over all of the memory of the registrations.
- */
-class ListenerRegistrationList {
- public:
- ListenerRegistrationList();
- ~ListenerRegistrationList();
-
- void add(ListenerCollection::Registration* registration);
- void clear();
-
- private:
- /** Disallow copying.*/
- ListenerRegistrationList(const ListenerRegistrationList&) = delete;
- /** Disallow assignment.*/
- ListenerRegistrationList operator=(const ListenerRegistrationList&) = delete;
- std::list<ListenerCollection::Registration*> d_registrations;
-};/* class CVC4::ListenerRegistrationList */
-
}/* CVC4 namespace */
#endif /* CVC4__LISTENER_H */
diff --git a/src/base/map_util.h b/src/base/map_util.h
index 5c2bd5820..77267df69 100644
--- a/src/base/map_util.h
+++ b/src/base/map_util.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/base/modal_exception.h b/src/base/modal_exception.h
index 76fe5c841..ec4303940 100644
--- a/src/base/modal_exception.h
+++ b/src/base/modal_exception.h
@@ -5,7 +5,7 @@
** Morgan Deters, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/base/output.cpp b/src/base/output.cpp
index d6a45a3b2..4940d07d9 100644
--- a/src/base/output.cpp
+++ b/src/base/output.cpp
@@ -5,7 +5,7 @@
** Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/base/output.h b/src/base/output.h
index c1e2dafad..e23f62783 100644
--- a/src/base/output.h
+++ b/src/base/output.h
@@ -5,7 +5,7 @@
** Morgan Deters, Andres Noetzli, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/context/backtrackable.h b/src/context/backtrackable.h
index 78d73106d..29a5bb187 100644
--- a/src/context/backtrackable.h
+++ b/src/context/backtrackable.h
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/context/cddense_set.h b/src/context/cddense_set.h
index d9e52c29b..a59a32592 100644
--- a/src/context/cddense_set.h
+++ b/src/context/cddense_set.h
@@ -5,7 +5,7 @@
** Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/context/cdhashmap.h b/src/context/cdhashmap.h
index c98b0f7f0..07e928161 100644
--- a/src/context/cdhashmap.h
+++ b/src/context/cdhashmap.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -82,7 +82,6 @@
#ifndef CVC4__CONTEXT__CDHASHMAP_H
#define CVC4__CONTEXT__CDHASHMAP_H
-#include <cstddef>
#include <functional>
#include <iterator>
#include <unordered_map>
@@ -418,6 +417,7 @@ public:
// Dereference operators.
const value_type& operator*() const { return d_it->getValue(); }
+ const value_type* operator->() const { return &d_it->getValue(); }
// Prefix increment
iterator& operator++()
diff --git a/src/context/cdhashmap_forward.h b/src/context/cdhashmap_forward.h
index 6a30c3f3e..de9c61921 100644
--- a/src/context/cdhashmap_forward.h
+++ b/src/context/cdhashmap_forward.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/context/cdhashset.h b/src/context/cdhashset.h
index 9259eb388..c8dcc7888 100644
--- a/src/context/cdhashset.h
+++ b/src/context/cdhashset.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -115,6 +115,7 @@ public:
V operator*() const {
return d_val;
}
+ V* operator->() const { return &d_val; }
};/* class CDSet<>::iterator::Proxy */
// Actual postfix increment: returns Proxy with the old value.
diff --git a/src/context/cdhashset_forward.h b/src/context/cdhashset_forward.h
index d7a43d459..24caceadf 100644
--- a/src/context/cdhashset_forward.h
+++ b/src/context/cdhashset_forward.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Tim King, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/context/cdinsert_hashmap.h b/src/context/cdinsert_hashmap.h
index 2e55f53d1..168789f99 100644
--- a/src/context/cdinsert_hashmap.h
+++ b/src/context/cdinsert_hashmap.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/context/cdinsert_hashmap_forward.h b/src/context/cdinsert_hashmap_forward.h
index fca2b5234..ca316f33f 100644
--- a/src/context/cdinsert_hashmap_forward.h
+++ b/src/context/cdinsert_hashmap_forward.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/context/cdlist.h b/src/context/cdlist.h
index e6b822dfd..cb5e552ac 100644
--- a/src/context/cdlist.h
+++ b/src/context/cdlist.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Clark Barrett
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -357,6 +357,8 @@ public:
return *d_it;
}
+ inline const T* operator->() const { return d_it; }
+
/** Prefix increment */
const_iterator& operator++() {
++d_it;
diff --git a/src/context/cdlist_forward.h b/src/context/cdlist_forward.h
index febf9c839..1caeea985 100644
--- a/src/context/cdlist_forward.h
+++ b/src/context/cdlist_forward.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/context/cdmaybe.h b/src/context/cdmaybe.h
index 6b516e84d..2cc90858b 100644
--- a/src/context/cdmaybe.h
+++ b/src/context/cdmaybe.h
@@ -5,7 +5,7 @@
** Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/context/cdo.h b/src/context/cdo.h
index a3241c7e5..c5f7ec7f6 100644
--- a/src/context/cdo.h
+++ b/src/context/cdo.h
@@ -5,7 +5,7 @@
** Morgan Deters, Clark Barrett, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/context/cdqueue.h b/src/context/cdqueue.h
index 54e553120..b28fcc3d3 100644
--- a/src/context/cdqueue.h
+++ b/src/context/cdqueue.h
@@ -5,7 +5,7 @@
** Tim King, Francois Bobot, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/context/cdtrail_queue.h b/src/context/cdtrail_queue.h
index bc8ff8da0..04150a3d7 100644
--- a/src/context/cdtrail_queue.h
+++ b/src/context/cdtrail_queue.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/context/context.cpp b/src/context/context.cpp
index 3c60316a7..19be126f8 100644
--- a/src/context/context.cpp
+++ b/src/context/context.cpp
@@ -5,7 +5,7 @@
** Clark Barrett, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/context/context.h b/src/context/context.h
index a5c96c44e..15b4307b9 100644
--- a/src/context/context.h
+++ b/src/context/context.h
@@ -5,7 +5,7 @@
** Clark Barrett, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/context/context_mm.cpp b/src/context/context_mm.cpp
index 62c6a876d..e83e73e11 100644
--- a/src/context/context_mm.cpp
+++ b/src/context/context_mm.cpp
@@ -5,7 +5,7 @@
** Clark Barrett, Andres Noetzli, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/context/context_mm.h b/src/context/context_mm.h
index f450ed94e..158f694e0 100644
--- a/src/context/context_mm.h
+++ b/src/context/context_mm.h
@@ -5,7 +5,7 @@
** Clark Barrett, Andres Noetzli, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/decision/decision_attributes.h b/src/decision/decision_attributes.h
index 86939e3ce..367f13abe 100644
--- a/src/decision/decision_attributes.h
+++ b/src/decision/decision_attributes.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Tim King, Kshitij Bansal
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/decision/decision_engine.cpp b/src/decision/decision_engine.cpp
index 2d150998a..6ebd73a5f 100644
--- a/src/decision/decision_engine.cpp
+++ b/src/decision/decision_engine.cpp
@@ -5,7 +5,7 @@
** Kshitij Bansal, Aina Niemetz, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/decision/decision_engine.h b/src/decision/decision_engine.h
index ec2c5ff63..52e1e2d1a 100644
--- a/src/decision/decision_engine.h
+++ b/src/decision/decision_engine.h
@@ -5,7 +5,7 @@
** Kshitij Bansal, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/decision/decision_strategy.h b/src/decision/decision_strategy.h
index 258bf860c..f7c28299d 100644
--- a/src/decision/decision_strategy.h
+++ b/src/decision/decision_strategy.h
@@ -5,7 +5,7 @@
** Kshitij Bansal, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/decision/justification_heuristic.cpp b/src/decision/justification_heuristic.cpp
index 9787e8b00..baf0056e9 100644
--- a/src/decision/justification_heuristic.cpp
+++ b/src/decision/justification_heuristic.cpp
@@ -5,7 +5,7 @@
** Kshitij Bansal, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/decision/justification_heuristic.h b/src/decision/justification_heuristic.h
index e45dd2bef..5ecb5eb08 100644
--- a/src/decision/justification_heuristic.h
+++ b/src/decision/justification_heuristic.h
@@ -5,7 +5,7 @@
** Kshitij Bansal, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/CMakeLists.txt b/src/expr/CMakeLists.txt
index bad2f1f42..18de83e90 100644
--- a/src/expr/CMakeLists.txt
+++ b/src/expr/CMakeLists.txt
@@ -1,20 +1,37 @@
+#####################
+## CMakeLists.txt
+## Top contributors (to current version):
+## Mathias Preiner, Aina Niemetz, Andrew Reynolds
+## This file is part of the CVC4 project.
+## Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+## in the top-level source directory and their institutional affiliations.
+## All rights reserved. See the file COPYING in the top-level source
+## directory for licensing information.
+##
libcvc4_add_sources(
array.h
array_store_all.cpp
array_store_all.h
+ ascription_type.cpp
ascription_type.h
attribute.h
attribute.cpp
attribute_internals.h
attribute_unique_id.h
+ buffered_proof_generator.cpp
+ buffered_proof_generator.h
emptyset.cpp
emptyset.h
+ emptybag.cpp
+ emptybag.h
expr_iomanip.cpp
expr_iomanip.h
expr_manager_scope.h
kind_map.h
lazy_proof.cpp
lazy_proof.h
+ lazy_proof_chain.cpp
+ lazy_proof_chain.h
match_trie.cpp
match_trie.h
node.cpp
@@ -53,14 +70,25 @@ libcvc4_add_sources(
proof_node_updater.h
proof_rule.cpp
proof_rule.h
+ proof_set.h
proof_step_buffer.cpp
proof_step_buffer.h
skolem_manager.cpp
skolem_manager.h
+ symbol_manager.cpp
+ symbol_manager.h
symbol_table.cpp
symbol_table.h
+ tconv_seq_proof_generator.cpp
+ tconv_seq_proof_generator.h
term_canonize.cpp
term_canonize.h
+ term_context.cpp
+ term_context.h
+ term_context_node.cpp
+ term_context_node.h
+ term_context_stack.cpp
+ term_context_stack.h
term_conversion_proof_generator.cpp
term_conversion_proof_generator.h
type.cpp
@@ -71,8 +99,8 @@ libcvc4_add_sources(
type_node.cpp
type_node.h
variable_type_map.h
- datatype.h
- datatype.cpp
+ datatype_index.h
+ datatype_index.cpp
dtype.h
dtype.cpp
dtype_cons.h
@@ -83,6 +111,8 @@ libcvc4_add_sources(
record.h
sequence.cpp
sequence.h
+ subs.cpp
+ subs.h
sygus_datatype.cpp
sygus_datatype.h
uninterpreted_constant.cpp
diff --git a/src/expr/array.h b/src/expr/array.h
index 5bfd39844..620e61ea0 100644
--- a/src/expr/array.h
+++ b/src/expr/array.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/array_store_all.cpp b/src/expr/array_store_all.cpp
index 0777bc1cf..ed21f8f9c 100644
--- a/src/expr/array_store_all.cpp
+++ b/src/expr/array_store_all.cpp
@@ -2,10 +2,10 @@
/*! \file array_store_all.cpp
** \verbatim
** Top contributors (to current version):
- ** Tim King, Morgan Deters
+ ** Tim King, Andres Noetzli, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -45,7 +45,8 @@ ArrayStoreAll::ArrayStoreAll(const TypeNode& type, const Node& value)
"expr type `%s' does not match constituent type of array type `%s'",
value.getType().toString().c_str(),
type.toString().c_str());
-
+ Trace("arrays") << "constructing constant array of type: '" << type
+ << "' and value: '" << value << "'" << std::endl;
PrettyCheckArgument(
value.isConst(), value, "ArrayStoreAll requires a constant expression");
diff --git a/src/expr/array_store_all.h b/src/expr/array_store_all.h
index 7fa25516c..5bb796961 100644
--- a/src/expr/array_store_all.h
+++ b/src/expr/array_store_all.h
@@ -2,10 +2,10 @@
/*! \file array_store_all.h
** \verbatim
** Top contributors (to current version):
- ** Tim King, Morgan Deters, Mathias Preiner
+ ** Tim King, Andres Noetzli, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/ascription_type.cpp b/src/expr/ascription_type.cpp
new file mode 100644
index 000000000..d9466fdbf
--- /dev/null
+++ b/src/expr/ascription_type.cpp
@@ -0,0 +1,58 @@
+/********************* */
+/*! \file ascription_type.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Morgan Deters, Tim King, Mathias Preiner
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief A class representing a type ascription
+ **/
+
+#include "expr/ascription_type.h"
+
+#include <iostream>
+
+#include "expr/type_node.h"
+
+namespace CVC4 {
+
+AscriptionType::AscriptionType(TypeNode t) : d_type(new TypeNode(t)) {}
+
+AscriptionType::AscriptionType(const AscriptionType& at)
+ : d_type(new TypeNode(at.getType()))
+{
+}
+
+AscriptionType& AscriptionType::operator=(const AscriptionType& at)
+{
+ (*d_type) = at.getType();
+ return *this;
+}
+
+AscriptionType::~AscriptionType() {}
+TypeNode AscriptionType::getType() const { return *d_type.get(); }
+bool AscriptionType::operator==(const AscriptionType& other) const
+{
+ return getType() == other.getType();
+}
+bool AscriptionType::operator!=(const AscriptionType& other) const
+{
+ return getType() != other.getType();
+}
+
+size_t AscriptionTypeHashFunction::operator()(const AscriptionType& at) const
+{
+ return TypeNodeHashFunction()(at.getType());
+}
+
+std::ostream& operator<<(std::ostream& out, AscriptionType at)
+{
+ out << at.getType();
+ return out;
+}
+
+} // namespace CVC4
diff --git a/src/expr/ascription_type.h b/src/expr/ascription_type.h
index 743d779ef..800f46e0a 100644
--- a/src/expr/ascription_type.h
+++ b/src/expr/ascription_type.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,10 +19,13 @@
#ifndef CVC4__ASCRIPTION_TYPE_H
#define CVC4__ASCRIPTION_TYPE_H
-#include "expr/type.h"
+#include <iosfwd>
+#include <memory>
namespace CVC4 {
+class TypeNode;
+
/**
* A class used to parameterize a type ascription. For example,
* "nil :: list<nat>" is an expression of kind APPLY_TYPE_ASCRIPTION.
@@ -31,35 +34,29 @@ namespace CVC4 {
* coerce a Type into the expression tree.)
*/
class CVC4_PUBLIC AscriptionType {
- Type d_type;
-
public:
- AscriptionType(Type t) : d_type(t) {}
- Type getType() const { return d_type; }
- bool operator==(const AscriptionType& other) const
- {
- return d_type == other.d_type;
- }
- bool operator!=(const AscriptionType& other) const
- {
- return d_type != other.d_type;
- }
+ AscriptionType(TypeNode t);
+ ~AscriptionType();
+ AscriptionType(const AscriptionType& other);
+ AscriptionType& operator=(const AscriptionType& other);
+ TypeNode getType() const;
+ bool operator==(const AscriptionType& other) const;
+ bool operator!=(const AscriptionType& other) const;
+
+ private:
+ /** The type */
+ std::unique_ptr<TypeNode> d_type;
};/* class AscriptionType */
/**
* A hash function for type ascription operators.
*/
struct CVC4_PUBLIC AscriptionTypeHashFunction {
- inline size_t operator()(const AscriptionType& at) const {
- return TypeHashFunction()(at.getType());
- }
+ size_t operator()(const AscriptionType& at) const;
};/* struct AscriptionTypeHashFunction */
/** An output routine for AscriptionTypes */
-inline std::ostream& operator<<(std::ostream& out, AscriptionType at) {
- out << at.getType();
- return out;
-}
+std::ostream& operator<<(std::ostream& out, AscriptionType at) CVC4_PUBLIC;
}/* CVC4 namespace */
diff --git a/src/expr/attribute.cpp b/src/expr/attribute.cpp
index db05dc7e9..34c05976c 100644
--- a/src/expr/attribute.cpp
+++ b/src/expr/attribute.cpp
@@ -5,7 +5,7 @@
** Tim King, Dejan Jovanovic, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/attribute.h b/src/expr/attribute.h
index 9fa4b8a84..1b5b6974d 100644
--- a/src/expr/attribute.h
+++ b/src/expr/attribute.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,7 +25,6 @@
#define CVC4__EXPR__ATTRIBUTE_H
#include <string>
-#include <stdint.h>
#include "expr/attribute_unique_id.h"
// include supporting templates
@@ -37,6 +36,44 @@ namespace CVC4 {
namespace expr {
namespace attr {
+/**
+ * Attributes are roughly speaking [almost] global hash tables from Nodes
+ * (TNodes) to data. Attributes can be thought of as additional fields used to
+ * extend NodeValues. Attributes are mutable and come in both sat
+ * context-dependent and non-context dependent varieties. Attributes live only
+ * as long as the node itself does. If a Node is garbage-collected, Attributes
+ * associated with it will automatically be garbage collected. (Being in the
+ * domain of an Attribute does not increase a Node's reference count.) To
+ * achieve this special relationship with Nodes, Attributes are mapped by hash
+ * tables (AttrHash<> and CDAttrHash<>) that live in the AttributeManager. The
+ * AttributeManager is owned by the NodeManager.
+ *
+ * Example:
+ *
+ * Attributes tend to be defined in a fixed pattern:
+ *
+ * ```
+ * struct InstLevelAttributeId {};
+ * typedef expr::Attribute<InstLevelAttributeId, uint64_t> InstLevelAttribute;
+ * ```
+ *
+ * To get the value of an Attribute InstLevelAttribute on a Node n, use
+ * ```
+ * n.getAttribute(InstLevelAttribute());
+ * ```
+ *
+ * To check whether the attribute has been set:
+ * ```
+ * n.hasAttribute(InstLevelAttribute());
+ * ```
+ *
+ * To separate Attributes of the same type in the same table, each of the
+ * structures `struct InstLevelAttributeId {};` is given a different unique value
+ * at load time. An example is the empty struct InstLevelAttributeId. These
+ * should be unique for each Attribute. Then via some template messiness when
+ * InstLevelAttribute() is passed as the argument to getAttribute(...) the load
+ * time id is instantiated.
+ */
// ATTRIBUTE MANAGER ===========================================================
/**
diff --git a/src/expr/attribute_internals.h b/src/expr/attribute_internals.h
index c2441d539..e93656708 100644
--- a/src/expr/attribute_internals.h
+++ b/src/expr/attribute_internals.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -23,7 +23,6 @@
#ifndef CVC4__EXPR__ATTRIBUTE_INTERNALS_H
#define CVC4__EXPR__ATTRIBUTE_INTERNALS_H
-#include <cstdint>
#include <unordered_map>
namespace CVC4 {
diff --git a/src/expr/attribute_unique_id.h b/src/expr/attribute_unique_id.h
index 7cd93c1f3..bf7c8926b 100644
--- a/src/expr/attribute_unique_id.h
+++ b/src/expr/attribute_unique_id.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,8 +19,6 @@
#pragma once
-#include <stdint.h>
-
// ATTRIBUTE IDs ============================================================
namespace CVC4 {
diff --git a/src/expr/buffered_proof_generator.cpp b/src/expr/buffered_proof_generator.cpp
new file mode 100644
index 000000000..aa0fe19bd
--- /dev/null
+++ b/src/expr/buffered_proof_generator.cpp
@@ -0,0 +1,82 @@
+/********************* */
+/*! \file buffered_proof_generator.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Haniel Barbosa
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of a proof generator for buffered proof steps
+ **/
+
+#include "expr/buffered_proof_generator.h"
+
+#include "expr/proof.h"
+
+namespace CVC4 {
+
+BufferedProofGenerator::BufferedProofGenerator(context::Context* c,
+ ProofNodeManager* pnm)
+ : ProofGenerator(), d_facts(c), d_pnm(pnm)
+{
+}
+
+bool BufferedProofGenerator::addStep(Node fact,
+ ProofStep ps,
+ CDPOverwrite opolicy)
+{
+ // check duplicates if we are not always overwriting
+ if (opolicy != CDPOverwrite::ALWAYS)
+ {
+ if (d_facts.find(fact) != d_facts.end())
+ {
+ // duplicate
+ return false;
+ }
+ Node symFact = CDProof::getSymmFact(fact);
+ if (!symFact.isNull())
+ {
+ if (d_facts.find(symFact) != d_facts.end())
+ {
+ // duplicate due to symmetry
+ return false;
+ }
+ }
+ }
+ // note that this replaces the value fact is mapped to if there is already one
+ d_facts.insert(fact, std::make_shared<ProofStep>(ps));
+ return true;
+}
+
+std::shared_ptr<ProofNode> BufferedProofGenerator::getProofFor(Node fact)
+{
+ Trace("pfee-fact-gen") << "BufferedProofGenerator::getProofFor: " << fact
+ << std::endl;
+ NodeProofStepMap::iterator it = d_facts.find(fact);
+ if (it == d_facts.end())
+ {
+ Node symFact = CDProof::getSymmFact(fact);
+ if (symFact.isNull())
+ {
+ Trace("pfee-fact-gen") << "...cannot find step" << std::endl;
+ Assert(false);
+ return nullptr;
+ }
+ it = d_facts.find(symFact);
+ if (it == d_facts.end())
+ {
+ Assert(false);
+ Trace("pfee-fact-gen") << "...cannot find step (no sym)" << std::endl;
+ return nullptr;
+ }
+ }
+ Trace("pfee-fact-gen") << "...return via step " << *(*it).second << std::endl;
+ CDProof cdp(d_pnm);
+ cdp.addStep(fact, *(*it).second);
+ return cdp.getProofFor(fact);
+}
+
+} // namespace CVC4
diff --git a/src/expr/buffered_proof_generator.h b/src/expr/buffered_proof_generator.h
new file mode 100644
index 000000000..987bd2465
--- /dev/null
+++ b/src/expr/buffered_proof_generator.h
@@ -0,0 +1,65 @@
+/********************* */
+/*! \file buffered_proof_generator.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Haniel Barbosa
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief A proof generator for buffered proof steps
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__EXPR__BUFFERED_PROOF_GENERATOR_H
+#define CVC4__EXPR__BUFFERED_PROOF_GENERATOR_H
+
+#include <map>
+#include <vector>
+
+#include "context/cdhashmap.h"
+#include "context/cdhashset.h"
+#include "expr/proof_generator.h"
+#include "expr/proof_node_manager.h"
+#include "expr/proof_step_buffer.h"
+
+namespace CVC4 {
+
+/**
+ * The proof generator for buffered steps. This class is a context-dependent
+ * mapping from formulas to proof steps. It does not generate ProofNodes until it
+ * is asked to provide a proof for a given fact.
+ */
+class BufferedProofGenerator : public ProofGenerator
+{
+ typedef context::CDHashMap<Node, std::shared_ptr<ProofStep>, NodeHashFunction>
+ NodeProofStepMap;
+
+ public:
+ BufferedProofGenerator(context::Context* c, ProofNodeManager* pnm);
+ ~BufferedProofGenerator() {}
+ /** add step
+ * Unless the overwrite policy is ALWAYS it does not replace previously
+ * registered steps (modulo (dis)equality symmetry).
+ */
+ bool addStep(Node fact,
+ ProofStep ps,
+ CDPOverwrite opolicy = CDPOverwrite::NEVER);
+ /** Get proof for. It is robust to (dis)equality symmetry. */
+ std::shared_ptr<ProofNode> getProofFor(Node f) override;
+ /** identify */
+ std::string identify() const override { return "BufferedProofGenerator"; }
+
+ private:
+ /** maps expected to ProofStep */
+ NodeProofStepMap d_facts;
+ /** the proof node manager */
+ ProofNodeManager* d_pnm;
+};
+
+} // namespace CVC4
+
+#endif /* CVC4__EXPR__BUFFERED_PROOF_GENERATOR_H */
diff --git a/src/expr/datatype.cpp b/src/expr/datatype.cpp
deleted file mode 100644
index 9ec3ac5fd..000000000
--- a/src/expr/datatype.cpp
+++ /dev/null
@@ -1,974 +0,0 @@
-/********************* */
-/*! \file datatype.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Andrew Reynolds, Morgan Deters, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief A class representing a Datatype definition
- **
- ** A class representing a Datatype definition for the theory of
- ** inductive datatypes.
- **/
-#include "expr/datatype.h"
-
-#include <string>
-#include <sstream>
-
-#include "base/check.h"
-#include "expr/attribute.h"
-#include "expr/dtype.h"
-#include "expr/expr_manager.h"
-#include "expr/expr_manager_scope.h"
-#include "expr/node.h"
-#include "expr/node_algorithm.h"
-#include "expr/node_manager.h"
-#include "expr/type.h"
-#include "expr/type_matcher.h"
-#include "options/datatypes_options.h"
-#include "options/set_language.h"
-#include "theory/type_enumerator.h"
-
-using namespace std;
-
-namespace CVC4 {
-
-Datatype::~Datatype()
-{
- ExprManagerScope ems(*d_em);
- d_internal.reset();
- d_constructors.clear();
-}
-
-Datatype::Datatype(ExprManager* em, std::string name, bool isCo)
- : d_em(em),
- d_internal(nullptr),
- d_record(NULL),
- d_isRecord(false),
- d_constructors()
-{
- ExprManagerScope ems(*d_em);
- d_internal = std::make_shared<DType>(name, isCo);
-}
-
-Datatype::Datatype(ExprManager* em,
- std::string name,
- const std::vector<Type>& params,
- bool isCo)
- : d_em(em),
- d_internal(nullptr),
- d_record(NULL),
- d_isRecord(false),
- d_constructors()
-{
- ExprManagerScope ems(*d_em);
- std::vector<TypeNode> paramsn;
- for (const Type& t : params)
- {
- paramsn.push_back(TypeNode::fromType(t));
- }
- d_internal = std::make_shared<DType>(name, paramsn, isCo);
-}
-
-const Datatype& Datatype::datatypeOf(Expr item) {
- ExprManagerScope ems(item);
- TypeNode t = Node::fromExpr(item).getType();
- switch(t.getKind()) {
- case kind::CONSTRUCTOR_TYPE:
- return DatatypeType(t[t.getNumChildren() - 1].toType()).getDatatype();
- case kind::SELECTOR_TYPE:
- case kind::TESTER_TYPE:
- return DatatypeType(t[0].toType()).getDatatype();
- default:
- Unhandled() << "arg must be a datatype constructor, selector, or tester";
- }
-}
-
-size_t Datatype::indexOf(Expr item) {
- ExprManagerScope ems(item);
- PrettyCheckArgument(item.getType().isConstructor() ||
- item.getType().isTester() ||
- item.getType().isSelector(),
- item,
- "arg must be a datatype constructor, selector, or tester");
- return indexOfInternal(item);
-}
-
-size_t Datatype::indexOfInternal(Expr item)
-{
- TNode n = Node::fromExpr(item);
- if( item.getKind()==kind::APPLY_TYPE_ASCRIPTION ){
- return indexOf( item[0] );
- }else{
- Assert(n.hasAttribute(DTypeIndexAttr()));
- return n.getAttribute(DTypeIndexAttr());
- }
-}
-
-size_t Datatype::cindexOf(Expr item) {
- ExprManagerScope ems(item);
- PrettyCheckArgument(item.getType().isSelector(),
- item,
- "arg must be a datatype selector");
- return cindexOfInternal(item);
-}
-size_t Datatype::cindexOfInternal(Expr item)
-{
- TNode n = Node::fromExpr(item);
- if( item.getKind()==kind::APPLY_TYPE_ASCRIPTION ){
- return cindexOf( item[0] );
- }else{
- Assert(n.hasAttribute(DTypeConsIndexAttr()));
- return n.getAttribute(DTypeConsIndexAttr());
- }
-}
-
-void Datatype::resolve(const std::map<std::string, DatatypeType>& resolutions,
- const std::vector<Type>& placeholders,
- const std::vector<Type>& replacements,
- const std::vector<SortConstructorType>& paramTypes,
- const std::vector<DatatypeType>& paramReplacements)
-{
- PrettyCheckArgument(!isResolved(), this, "cannot resolve a Datatype twice");
- PrettyCheckArgument(resolutions.find(getName()) != resolutions.end(),
- resolutions,
- "Datatype::resolve(): resolutions doesn't contain me!");
- PrettyCheckArgument(placeholders.size() == replacements.size(), placeholders,
- "placeholders and replacements must be the same size");
- PrettyCheckArgument(paramTypes.size() == paramReplacements.size(), paramTypes,
- "paramTypes and paramReplacements must be the same size");
- PrettyCheckArgument(getNumConstructors() > 0, *this, "cannot resolve a Datatype that has no constructors");
-
- // we're using some internals, so we have to make sure that the Datatype's
- // ExprManager is active
- ExprManagerScope ems(*d_em);
-
- Trace("datatypes") << "Datatype::resolve: " << getName()
- << ", #placeholders=" << placeholders.size() << std::endl;
-
- std::map<std::string, TypeNode> resolutionsn;
- std::vector<TypeNode> placeholdersn;
- std::vector<TypeNode> replacementsn;
- std::vector<TypeNode> paramTypesn;
- std::vector<TypeNode> paramReplacementsn;
- for (const std::pair<const std::string, DatatypeType>& r : resolutions)
- {
- resolutionsn[r.first] = TypeNode::fromType(r.second);
- }
- for (const Type& t : placeholders)
- {
- placeholdersn.push_back(TypeNode::fromType(t));
- }
- for (const Type& t : replacements)
- {
- replacementsn.push_back(TypeNode::fromType(t));
- }
- for (const Type& t : paramTypes)
- {
- paramTypesn.push_back(TypeNode::fromType(t));
- }
- for (const Type& t : paramReplacements)
- {
- paramReplacementsn.push_back(TypeNode::fromType(t));
- }
- bool res = d_internal->resolve(resolutionsn,
- placeholdersn,
- replacementsn,
- paramTypesn,
- paramReplacementsn);
- if (!res)
- {
- IllegalArgument(*this,
- "could not resolve datatype that is not well formed");
- }
- Trace("dt-debug") << "Datatype::resolve: finished " << getName() << " "
- << d_constructors.size() << std::endl;
- AlwaysAssert(isResolved());
- //
- d_self = d_internal->getTypeNode().toType();
- for (DatatypeConstructor& c : d_constructors)
- {
- AlwaysAssert(c.isResolved());
- c.d_constructor = c.d_internal->getConstructor().toExpr();
- for (size_t i = 0, nargs = c.getNumArgs(); i < nargs; i++)
- {
- AlwaysAssert(c.d_args[i].isResolved());
- c.d_args[i].d_selector = c.d_args[i].d_internal->getSelector().toExpr();
- }
- }
-
- if( d_isRecord ){
- std::vector< std::pair<std::string, Type> > fields;
- for( unsigned i=0; i<(*this)[0].getNumArgs(); i++ ){
- fields.push_back( std::pair<std::string, Type>( (*this)[0][i].getName(), (*this)[0][i].getRangeType() ) );
- }
- d_record.reset(new Record(fields));
- }
-}
-
-void Datatype::addConstructor(const DatatypeConstructor& c) {
- Trace("dt-debug") << "Datatype::addConstructor" << std::endl;
- PrettyCheckArgument(
- !isResolved(), this, "cannot add a constructor to a finalized Datatype");
- d_constructors.push_back(c);
- d_internal->addConstructor(c.d_internal);
- Trace("dt-debug") << "Datatype::addConstructor: finished" << std::endl;
-}
-
-
-void Datatype::setSygus( Type st, Expr bvl, bool allow_const, bool allow_all ){
- PrettyCheckArgument(
- !isResolved(), this, "cannot set sygus type to a finalized Datatype");
- // We can be in a case where the only rule specified was
- // (Constant T), in which case we have not yet added a constructor. We
- // ensure an arbitrary constant is added in this case. We additionally
- // add a constant if the grammar has only non-nullary constructors, since this
- // ensures the datatype is well-founded (see 3423).
- // Notice we only want to do this for sygus datatypes that are user-provided.
- // At the moment, the condition !allow_all implies the grammar is
- // user-provided and hence may require a default constant.
- // TODO (https://github.com/CVC4/cvc4-projects/issues/38):
- // In an API for SyGuS, it probably makes more sense for the user to
- // explicitly add the "any constant" constructor with a call instead of
- // passing a flag. This would make the block of code unnecessary.
- if (allow_const && !allow_all)
- {
- // if i don't already have a constant (0-ary constructor)
- bool hasConstant = false;
- for (unsigned i = 0, ncons = getNumConstructors(); i < ncons; i++)
- {
- if ((*this)[i].getNumArgs() == 0)
- {
- hasConstant = true;
- break;
- }
- }
- if (!hasConstant)
- {
- // add an arbitrary one
- Expr op = st.mkGroundTerm();
- std::stringstream cname;
- cname << op;
- std::vector<Type> cargs;
- addSygusConstructor(op, cname.str(), cargs);
- }
- }
-
- TypeNode stn = TypeNode::fromType(st);
- Node bvln = Node::fromExpr(bvl);
- d_internal->setSygus(stn, bvln, allow_const, allow_all);
-}
-
-void Datatype::addSygusConstructor(Expr op,
- const std::string& cname,
- const std::vector<Type>& cargs,
- int weight)
-{
- // avoid name clashes
- std::stringstream ss;
- ss << getName() << "_" << getNumConstructors() << "_" << cname;
- std::string name = ss.str();
- unsigned cweight = weight >= 0 ? weight : (cargs.empty() ? 0 : 1);
- DatatypeConstructor c(name, cweight);
- c.setSygus(op);
- for( unsigned j=0; j<cargs.size(); j++ ){
- Debug("parser-sygus-debug") << " arg " << j << " : " << cargs[j] << std::endl;
- std::stringstream sname;
- sname << name << "_" << j;
- c.addArg(sname.str(), cargs[j]);
- }
- addConstructor(c);
-}
-
-void Datatype::addSygusConstructor(Kind k,
- const std::string& cname,
- const std::vector<Type>& cargs,
- int weight)
-{
- ExprManagerScope ems(*d_em);
- Expr op = d_em->operatorOf(k);
- addSygusConstructor(op, cname, cargs, weight);
-}
-
-void Datatype::setTuple() {
- PrettyCheckArgument(
- !isResolved(), this, "cannot set tuple to a finalized Datatype");
- d_internal->setTuple();
-}
-
-void Datatype::setRecord() {
- PrettyCheckArgument(
- !isResolved(), this, "cannot set record to a finalized Datatype");
- d_isRecord = true;
-}
-
-Cardinality Datatype::getCardinality(Type t) const
-{
- PrettyCheckArgument(isResolved(), this, "this datatype is not yet resolved");
- Assert(t.isDatatype() && ((DatatypeType)t).getDatatype() == *this);
- ExprManagerScope ems(d_self);
- TypeNode tn = TypeNode::fromType(t);
- return d_internal->getCardinality(tn);
-}
-
-Cardinality Datatype::getCardinality() const
-{
- PrettyCheckArgument(!isParametric(), this, "for getCardinality, this datatype cannot be parametric");
- ExprManagerScope ems(d_self);
- return d_internal->getCardinality();
-}
-
-bool Datatype::isRecursiveSingleton(Type t) const
-{
- PrettyCheckArgument(isResolved(), this, "this datatype is not yet resolved");
- Assert(t.isDatatype() && ((DatatypeType)t).getDatatype() == *this);
- ExprManagerScope ems(d_self);
- TypeNode tn = TypeNode::fromType(t);
- return d_internal->isRecursiveSingleton(tn);
-}
-
-bool Datatype::isRecursiveSingleton() const
-{
- PrettyCheckArgument(!isParametric(), this, "for isRecursiveSingleton, this datatype cannot be parametric");
- ExprManagerScope ems(d_self);
- return d_internal->isRecursiveSingleton();
-}
-
-unsigned Datatype::getNumRecursiveSingletonArgTypes(Type t) const
-{
- Assert(isRecursiveSingleton(t));
- ExprManagerScope ems(d_self);
- TypeNode tn = TypeNode::fromType(t);
- return d_internal->getNumRecursiveSingletonArgTypes(tn);
-}
-
-unsigned Datatype::getNumRecursiveSingletonArgTypes() const
-{
- PrettyCheckArgument(!isParametric(), this, "for getNumRecursiveSingletonArgTypes, this datatype cannot be parametric");
- ExprManagerScope ems(d_self);
- return d_internal->getNumRecursiveSingletonArgTypes();
-}
-
-Type Datatype::getRecursiveSingletonArgType(Type t, unsigned i) const
-{
- Assert(isRecursiveSingleton(t));
- ExprManagerScope ems(d_self);
- TypeNode tn = TypeNode::fromType(t);
- return d_internal->getRecursiveSingletonArgType(tn, i).toType();
-}
-
-Type Datatype::getRecursiveSingletonArgType(unsigned i) const
-{
- PrettyCheckArgument(!isParametric(), this, "for getRecursiveSingletonArgType, this datatype cannot be parametric");
- ExprManagerScope ems(d_self);
- return d_internal->getRecursiveSingletonArgType(i).toType();
-}
-
-bool Datatype::isFinite(Type t) const
-{
- PrettyCheckArgument(isResolved(), this, "this datatype is not yet resolved");
- Assert(t.isDatatype() && ((DatatypeType)t).getDatatype() == *this);
- ExprManagerScope ems(d_self);
- TypeNode tn = TypeNode::fromType(t);
- return d_internal->isFinite(tn);
-}
-bool Datatype::isFinite() const
-{
- PrettyCheckArgument(isResolved() && !isParametric(), this, "this datatype must be resolved and not parametric");
- ExprManagerScope ems(d_self);
- return d_internal->isFinite();
-}
-
-bool Datatype::isInterpretedFinite(Type t) const
-{
- PrettyCheckArgument(isResolved(), this, "this datatype is not yet resolved");
- Assert(t.isDatatype() && ((DatatypeType)t).getDatatype() == *this);
- ExprManagerScope ems(d_self);
- TypeNode tn = TypeNode::fromType(t);
- return d_internal->isInterpretedFinite(tn);
-}
-bool Datatype::isInterpretedFinite() const
-{
- PrettyCheckArgument(isResolved() && !isParametric(), this, "this datatype must be resolved and not parametric");
- ExprManagerScope ems(d_self);
- return d_internal->isInterpretedFinite();
-}
-
-bool Datatype::isWellFounded() const
-{
- ExprManagerScope ems(d_self);
- return d_internal->isWellFounded();
-}
-
-bool Datatype::hasNestedRecursion() const
-{
- ExprManagerScope ems(d_self);
- return d_internal->hasNestedRecursion();
-}
-
-Expr Datatype::mkGroundTerm(Type t) const
-{
- PrettyCheckArgument(isResolved(), this, "this datatype is not yet resolved");
- ExprManagerScope ems(d_self);
- TypeNode tn = TypeNode::fromType(t);
- Node gterm = d_internal->mkGroundTerm(tn);
- PrettyCheckArgument(
- !gterm.isNull(),
- this,
- "datatype is not well-founded, cannot construct a ground term!");
- return gterm.toExpr();
-}
-
-Expr Datatype::mkGroundValue(Type t) const
-{
- PrettyCheckArgument(isResolved(), this, "this datatype is not yet resolved");
- ExprManagerScope ems(d_self);
- TypeNode tn = TypeNode::fromType(t);
- Node gvalue = d_internal->mkGroundValue(tn);
- PrettyCheckArgument(
- !gvalue.isNull(),
- this,
- "datatype is not well-founded, cannot construct a ground value!");
- return gvalue.toExpr();
-}
-
-DatatypeType Datatype::getDatatypeType() const
-{
- PrettyCheckArgument(isResolved(), *this, "Datatype must be resolved to get its DatatypeType");
- ExprManagerScope ems(d_self);
- Type self = d_internal->getTypeNode().toType();
- PrettyCheckArgument(!self.isNull(), *this);
- return DatatypeType(self);
-}
-
-DatatypeType Datatype::getDatatypeType(const std::vector<Type>& params) const
-{
- PrettyCheckArgument(isResolved(), *this, "Datatype must be resolved to get its DatatypeType");
- ExprManagerScope ems(d_self);
- Type self = d_internal->getTypeNode().toType();
- PrettyCheckArgument(!self.isNull() && DatatypeType(self).isParametric(),
- this);
- return DatatypeType(self).instantiate(params);
-}
-
-bool Datatype::operator==(const Datatype& other) const
-{
- // two datatypes are == iff the name is the same and they have
- // exactly matching constructors (in the same order)
-
- if(this == &other) {
- return true;
- }
- return true;
-}
-
-const DatatypeConstructor& Datatype::operator[](size_t index) const {
- PrettyCheckArgument(index < getNumConstructors(), index, "index out of bounds");
- return d_constructors[index];
-}
-
-const DatatypeConstructor& Datatype::operator[](std::string name) const {
- for(const_iterator i = begin(); i != end(); ++i) {
- if((*i).getName() == name) {
- return *i;
- }
- }
- std::string dname = getName();
- IllegalArgument(name,
- "No such constructor `%s' of datatype `%s'",
- name.c_str(),
- dname.c_str());
-}
-
-Expr Datatype::getConstructor(std::string name) const {
- return (*this)[name].getConstructor();
-}
-
-Type Datatype::getSygusType() const {
- return d_internal->getSygusType().toType();
-}
-
-Expr Datatype::getSygusVarList() const {
- return d_internal->getSygusVarList().toExpr();
-}
-
-bool Datatype::getSygusAllowConst() const {
- return d_internal->getSygusAllowConst();
-}
-
-bool Datatype::getSygusAllowAll() const {
- return d_internal->getSygusAllowAll();
-}
-
-bool Datatype::involvesExternalType() const{
- return d_internal->involvesExternalType();
-}
-
-bool Datatype::involvesUninterpretedType() const{
- return d_internal->involvesUninterpretedType();
-}
-
-const std::vector<DatatypeConstructor>* Datatype::getConstructors() const
-{
- return &d_constructors;
-}
-
-DatatypeConstructor::DatatypeConstructor(std::string name, unsigned weight)
- : d_internal(nullptr)
-{
- PrettyCheckArgument(name != "", name, "cannot construct a datatype constructor without a name");
- d_internal = std::make_shared<DTypeConstructor>(name, weight);
-}
-
-void DatatypeConstructor::setSygus(Expr op)
-{
- PrettyCheckArgument(
- !isResolved(), this, "cannot modify a finalized Datatype constructor");
- Node opn = Node::fromExpr(op);
- d_internal->setSygus(op);
-}
-
-const std::vector<DatatypeConstructorArg>* DatatypeConstructor::getArgs()
- const
-{
- return &d_args;
-}
-
-void DatatypeConstructor::addArg(std::string selectorName, Type selectorType) {
- // We don't want to introduce a new data member, because eventually
- // we're going to be a constant stuffed inside a node. So we stow
- // the selector type away inside a var until resolution (when we can
- // create the proper selector type)
- PrettyCheckArgument(!isResolved(), this, "cannot modify a finalized Datatype constructor");
- PrettyCheckArgument(!selectorType.isNull(), selectorType, "cannot add a null selector type");
-
- // we're using some internals, so we have to set up this library context
- ExprManagerScope ems(selectorType);
-
- Expr type = NodeManager::currentNM()->mkSkolem("unresolved_" + selectorName, TypeNode::fromType(selectorType), "is an unresolved selector type placeholder", NodeManager::SKOLEM_EXACT_NAME | NodeManager::SKOLEM_NO_NOTIFY).toExpr();
- Debug("datatypes") << type << endl;
- d_args.push_back(DatatypeConstructorArg(selectorName, type));
- d_internal->addArg(d_args.back().d_internal);
-}
-
-void DatatypeConstructor::addArg(std::string selectorName, DatatypeUnresolvedType selectorType) {
- // We don't want to introduce a new data member, because eventually
- // we're going to be a constant stuffed inside a node. So we stow
- // the selector type away after a NUL in the name string until
- // resolution (when we can create the proper selector type)
- PrettyCheckArgument(!isResolved(), this, "cannot modify a finalized Datatype constructor");
- PrettyCheckArgument(selectorType.getName() != "", selectorType, "cannot add a null selector type");
- d_args.push_back(DatatypeConstructorArg(selectorName + '\0' + selectorType.getName(), Expr()));
- d_internal->addArg(d_args.back().d_internal);
-}
-
-void DatatypeConstructor::addArg(std::string selectorName, DatatypeSelfType) {
- // We don't want to introduce a new data member, because eventually
- // we're going to be a constant stuffed inside a node. So we mark
- // the name string with a NUL to indicate that we have a
- // self-selecting selector until resolution (when we can create the
- // proper selector type)
- PrettyCheckArgument(!isResolved(), this, "cannot modify a finalized Datatype constructor");
- d_args.push_back(DatatypeConstructorArg(selectorName + '\0', Expr()));
- d_internal->addArg(d_args.back().d_internal);
-}
-
-std::string DatatypeConstructor::getName() const
-{
- return d_internal->getName();
-}
-
-Expr DatatypeConstructor::getConstructor() const {
- PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved");
- return d_constructor;
-}
-
-Type DatatypeConstructor::getSpecializedConstructorType(Type returnType) const {
- PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved");
- PrettyCheckArgument(returnType.isDatatype(), this, "cannot get specialized constructor type for non-datatype type");
- ExprManagerScope ems(d_constructor);
- TypeNode tn = TypeNode::fromType(returnType);
- return d_internal->getSpecializedConstructorType(tn).toType();
-}
-
-Expr DatatypeConstructor::getTester() const {
- PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved");
- ExprManagerScope ems(d_constructor);
- return d_internal->getTester().toExpr();
-}
-
-Expr DatatypeConstructor::getSygusOp() const {
- PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved");
- ExprManagerScope ems(d_constructor);
- return d_internal->getSygusOp().toExpr();
-}
-
-bool DatatypeConstructor::isSygusIdFunc() const {
- PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved");
- ExprManagerScope ems(d_constructor);
- return d_internal->isSygusIdFunc();
-}
-
-unsigned DatatypeConstructor::getWeight() const
-{
- PrettyCheckArgument(
- isResolved(), this, "this datatype constructor is not yet resolved");
- ExprManagerScope ems(d_constructor);
- return d_internal->getWeight();
-}
-
-Cardinality DatatypeConstructor::getCardinality(Type t) const
-{
- PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved");
- ExprManagerScope ems(d_constructor);
- TypeNode tn = TypeNode::fromType(t);
- return d_internal->getCardinality(tn);
-}
-
-bool DatatypeConstructor::isFinite(Type t) const
-{
- PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved");
- ExprManagerScope ems(d_constructor);
- TypeNode tn = TypeNode::fromType(t);
- return d_internal->isFinite(tn);
-}
-
-bool DatatypeConstructor::isInterpretedFinite(Type t) const
-{
- PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved");
- ExprManagerScope ems(d_constructor);
- TypeNode tn = TypeNode::fromType(t);
- return d_internal->isInterpretedFinite(tn);
-}
-
-const DatatypeConstructorArg& DatatypeConstructor::operator[](size_t index) const {
- PrettyCheckArgument(index < getNumArgs(), index, "index out of bounds");
- return d_args[index];
-}
-
-const DatatypeConstructorArg& DatatypeConstructor::operator[](std::string name) const {
- for(const_iterator i = begin(); i != end(); ++i) {
- if((*i).getName() == name) {
- return *i;
- }
- }
- std::string dname = getName();
- IllegalArgument(name,
- "No such arg `%s' of constructor `%s'",
- name.c_str(),
- dname.c_str());
-}
-
-Expr DatatypeConstructor::getSelector(std::string name) const {
- return (*this)[name].d_selector;
-}
-
-Type DatatypeConstructor::getArgType(unsigned index) const
-{
- PrettyCheckArgument(index < getNumArgs(), index, "index out of bounds");
- ExprManagerScope ems(d_constructor);
- return d_internal->getArgType(index).toType();
-}
-
-bool DatatypeConstructor::involvesExternalType() const{
- ExprManagerScope ems(d_constructor);
- return d_internal->involvesExternalType();
-}
-
-bool DatatypeConstructor::involvesUninterpretedType() const{
- ExprManagerScope ems(d_constructor);
- return d_internal->involvesUninterpretedType();
-}
-
-DatatypeConstructorArg::DatatypeConstructorArg(std::string name, Expr selector)
- : d_internal(nullptr)
-{
- PrettyCheckArgument(name != "", name, "cannot construct a datatype constructor arg without a name");
- d_internal = std::make_shared<DTypeSelector>(name, Node::fromExpr(selector));
-}
-
-std::string DatatypeConstructorArg::getName() const
-{
- string name = d_internal->getName();
- const size_t nul = name.find('\0');
- if(nul != string::npos) {
- name.resize(nul);
- }
- return name;
-}
-
-Expr DatatypeConstructorArg::getSelector() const {
- PrettyCheckArgument(isResolved(), this, "cannot get a selector for an unresolved datatype constructor");
- return d_selector;
-}
-
-Expr DatatypeConstructor::getSelectorInternal( Type domainType, size_t index ) const {
- PrettyCheckArgument(isResolved(), this, "cannot get an internal selector for an unresolved datatype constructor");
- PrettyCheckArgument(index < getNumArgs(), index, "index out of bounds");
- ExprManagerScope ems(d_constructor);
- TypeNode dtn = TypeNode::fromType(domainType);
- return d_internal->getSelectorInternal(dtn, index).toExpr();
-}
-
-int DatatypeConstructor::getSelectorIndexInternal( Expr sel ) const {
- PrettyCheckArgument(isResolved(), this, "cannot get an internal selector index for an unresolved datatype constructor");
- ExprManagerScope ems(d_constructor);
- Node seln = Node::fromExpr(sel);
- return d_internal->getSelectorIndexInternal(seln);
-}
-
-Expr DatatypeConstructorArg::getConstructor() const {
- PrettyCheckArgument(isResolved(), this,
- "cannot get a associated constructor for argument of an unresolved datatype constructor");
- ExprManagerScope ems(d_selector);
- return d_internal->getConstructor().toExpr();
-}
-
-SelectorType DatatypeConstructorArg::getType() const {
- return d_selector.getType();
-}
-
-Type DatatypeConstructorArg::getRangeType() const {
- return getType().getRangeType();
-}
-
-bool DatatypeConstructorArg::isUnresolvedSelf() const
-{
- return d_selector.isNull();
-}
-
-bool DatatypeConstructorArg::isResolved() const
-{
- // We could just write:
- //
- // return !d_selector.isNull() && d_selector.getType().isSelector();
- //
- // HOWEVER, this causes problems in ExprManager tear-down, because
- // the attributes are removed before the pool is purged. When the
- // pool is purged, this triggers an equality test between Datatypes,
- // and this triggers a call to isResolved(), which breaks because
- // d_selector has no type after attributes are stripped.
- //
- // This problem, coupled with the fact that this function is called
- // _often_, means we should just use a boolean flag.
- //
- return d_internal->isResolved();
-}
-
-std::ostream& operator<<(std::ostream& os, const Datatype& dt)
-{
- // can only output datatypes in the CVC4 native language
- language::SetLanguage::Scope ls(os, language::output::LANG_CVC4);
- dt.toStream(os);
- return os;
-}
-
-void Datatype::toStream(std::ostream& out) const
-{
- out << "DATATYPE " << getName();
- if (isParametric())
- {
- out << '[';
- for (size_t i = 0; i < getNumParameters(); ++i)
- {
- if(i > 0) {
- out << ',';
- }
- out << getParameter(i);
- }
- out << ']';
- }
- out << " =" << endl;
- Datatype::const_iterator i = begin(), i_end = end();
- if(i != i_end) {
- out << " ";
- do {
- out << *i << endl;
- if(++i != i_end) {
- out << "| ";
- }
- } while(i != i_end);
- }
- out << "END;" << endl;
-}
-
-std::ostream& operator<<(std::ostream& os, const DatatypeConstructor& ctor) {
- // can only output datatypes in the CVC4 native language
- language::SetLanguage::Scope ls(os, language::output::LANG_CVC4);
- ctor.toStream(os);
- return os;
-}
-
-void DatatypeConstructor::toStream(std::ostream& out) const
-{
- out << getName();
-
- DatatypeConstructor::const_iterator i = begin(), i_end = end();
- if(i != i_end) {
- out << "(";
- do {
- out << *i;
- if(++i != i_end) {
- out << ", ";
- }
- } while(i != i_end);
- out << ")";
- }
-}
-
-std::ostream& operator<<(std::ostream& os, const DatatypeConstructorArg& arg) {
- // can only output datatypes in the CVC4 native language
- language::SetLanguage::Scope ls(os, language::output::LANG_CVC4);
- arg.toStream(os);
- return os;
-}
-
-void DatatypeConstructorArg::toStream(std::ostream& out) const
-{
- std::string name = getName();
- out << name << ": ";
-
- Type t;
- if (isResolved())
- {
- t = getRangeType();
- }
- else if (d_selector.isNull())
- {
- string typeName = name.substr(name.find('\0') + 1);
- out << ((typeName == "") ? "[self]" : typeName);
- return;
- }
- else
- {
- t = d_selector.getType();
- }
- out << t;
-}
-
-DatatypeIndexConstant::DatatypeIndexConstant(unsigned index) : d_index(index) {}
-std::ostream& operator<<(std::ostream& out, const DatatypeIndexConstant& dic) {
- return out << "index_" << dic.getIndex();
-}
-
-
-std::string Datatype::getName() const
-{
- ExprManagerScope ems(*d_em);
- return d_internal->getName();
-}
-size_t Datatype::getNumConstructors() const { return d_constructors.size(); }
-
-bool Datatype::isParametric() const
-{
- ExprManagerScope ems(*d_em);
- return d_internal->isParametric();
-}
-size_t Datatype::getNumParameters() const
-{
- ExprManagerScope ems(*d_em);
- return d_internal->getNumParameters();
-}
-Type Datatype::getParameter(unsigned int i) const
-{
- CheckArgument(isParametric(),
- this,
- "Cannot get type parameter of a non-parametric datatype.");
- CheckArgument(i < getNumParameters(),
- i,
- "Type parameter index out of range for datatype.");
- ExprManagerScope ems(*d_em);
- return d_internal->getParameter(i).toType();
-}
-
-std::vector<Type> Datatype::getParameters() const
-{
- CheckArgument(isParametric(),
- this,
- "Cannot get type parameters of a non-parametric datatype.");
- std::vector<Type> params;
- std::vector<TypeNode> paramsn = d_internal->getParameters();
- // convert to type
- for (unsigned i = 0, nparams = paramsn.size(); i < nparams; i++)
- {
- params.push_back(paramsn[i].toType());
- }
- return params;
-}
-
-bool Datatype::isCodatatype() const
-{
- ExprManagerScope ems(*d_em);
- return d_internal->isCodatatype();
-}
-
-bool Datatype::isSygus() const
-{
- ExprManagerScope ems(*d_em);
- return d_internal->isSygus();
-}
-
-bool Datatype::isTuple() const
-{
- ExprManagerScope ems(*d_em);
- return d_internal->isTuple();
-}
-
-bool Datatype::isRecord() const { return d_isRecord; }
-
-Record* Datatype::getRecord() const { return d_record.get(); }
-bool Datatype::operator!=(const Datatype& other) const
-{
- return !(*this == other);
-}
-
-bool Datatype::isResolved() const
-{
- ExprManagerScope ems(*d_em);
- return d_internal->isResolved();
-}
-Datatype::iterator Datatype::begin() { return iterator(d_constructors, true); }
-
-Datatype::iterator Datatype::end() { return iterator(d_constructors, false); }
-
-Datatype::const_iterator Datatype::begin() const
-{
- return const_iterator(d_constructors, true);
-}
-
-Datatype::const_iterator Datatype::end() const
-{
- return const_iterator(d_constructors, false);
-}
-
-bool DatatypeConstructor::isResolved() const
-{
- return d_internal->isResolved();
-}
-
-size_t DatatypeConstructor::getNumArgs() const { return d_args.size(); }
-
-DatatypeConstructor::iterator DatatypeConstructor::begin()
-{
- return iterator(d_args, true);
-}
-
-DatatypeConstructor::iterator DatatypeConstructor::end()
-{
- return iterator(d_args, false);
-}
-
-DatatypeConstructor::const_iterator DatatypeConstructor::begin() const
-{
- return const_iterator(d_args, true);
-}
-
-DatatypeConstructor::const_iterator DatatypeConstructor::end() const
-{
- return const_iterator(d_args, false);
-}
-}/* CVC4 namespace */
diff --git a/src/expr/datatype.h b/src/expr/datatype.h
deleted file mode 100644
index 54095050f..000000000
--- a/src/expr/datatype.h
+++ /dev/null
@@ -1,977 +0,0 @@
-/********************* */
-/*! \file datatype.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Andrew Reynolds, Morgan Deters, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief A class representing a Datatype definition
- **
- ** A class representing a Datatype definition for the theory of
- ** inductive datatypes.
- **/
-
-#include "cvc4_public.h"
-
-#ifndef CVC4__DATATYPE_H
-#define CVC4__DATATYPE_H
-
-#include <functional>
-#include <iostream>
-#include <string>
-#include <vector>
-#include <map>
-
-namespace CVC4 {
- // messy; Expr needs Datatype (because it's the payload of a
- // CONSTANT-kinded expression), and Datatype needs Expr.
- //class CVC4_PUBLIC Datatype;
- class CVC4_PUBLIC DatatypeIndexConstant;
-}/* CVC4 namespace */
-
-#include "base/exception.h"
-#include "expr/expr.h"
-#include "expr/type.h"
-#include "util/hash.h"
-
-
-namespace CVC4 {
-
-class CVC4_PUBLIC ExprManager;
-
-class CVC4_PUBLIC DatatypeConstructor;
-class CVC4_PUBLIC DatatypeConstructorArg;
-
-class CVC4_PUBLIC DatatypeConstructorIterator {
- const std::vector<DatatypeConstructor>* d_v;
- size_t d_i;
-
- friend class Datatype;
-
- DatatypeConstructorIterator(const std::vector<DatatypeConstructor>& v, bool start) : d_v(&v), d_i(start ? 0 : v.size()) {
- }
-
-public:
- typedef const DatatypeConstructor& value_type;
- const DatatypeConstructor& operator*() const { return (*d_v)[d_i]; }
- const DatatypeConstructor* operator->() const { return &(*d_v)[d_i]; }
- DatatypeConstructorIterator& operator++() { ++d_i; return *this; }
- DatatypeConstructorIterator operator++(int) { DatatypeConstructorIterator i(*this); ++d_i; return i; }
- bool operator==(const DatatypeConstructorIterator& other) const { return d_v == other.d_v && d_i == other.d_i; }
- bool operator!=(const DatatypeConstructorIterator& other) const { return d_v != other.d_v || d_i != other.d_i; }
-};/* class DatatypeConstructorIterator */
-
-class CVC4_PUBLIC DatatypeConstructorArgIterator {
- const std::vector<DatatypeConstructorArg>* d_v;
- size_t d_i;
-
- friend class DatatypeConstructor;
-
- DatatypeConstructorArgIterator(const std::vector<DatatypeConstructorArg>& v, bool start) : d_v(&v), d_i(start ? 0 : v.size()) {
- }
-
-public:
- typedef const DatatypeConstructorArg& value_type;
- const DatatypeConstructorArg& operator*() const { return (*d_v)[d_i]; }
- const DatatypeConstructorArg* operator->() const { return &(*d_v)[d_i]; }
- DatatypeConstructorArgIterator& operator++() { ++d_i; return *this; }
- DatatypeConstructorArgIterator operator++(int) { DatatypeConstructorArgIterator i(*this); ++d_i; return i; }
- bool operator==(const DatatypeConstructorArgIterator& other) const { return d_v == other.d_v && d_i == other.d_i; }
- bool operator!=(const DatatypeConstructorArgIterator& other) const { return d_v != other.d_v || d_i != other.d_i; }
-};/* class DatatypeConstructorArgIterator */
-
-/**
- * An exception that is thrown when a datatype resolution fails.
- */
-class CVC4_PUBLIC DatatypeResolutionException : public Exception {
- public:
- inline DatatypeResolutionException(std::string msg);
-};/* class DatatypeResolutionException */
-
-/**
- * A holder type (used in calls to DatatypeConstructor::addArg())
- * to allow a Datatype to refer to itself. Self-typed fields of
- * Datatypes will be properly typed when a Type is created for the
- * Datatype by the ExprManager (which calls Datatype::resolve()).
- */
-class CVC4_PUBLIC DatatypeSelfType {
-};/* class DatatypeSelfType */
-
-class DTypeSelector;
-
-/**
- * An unresolved type (used in calls to
- * DatatypeConstructor::addArg()) to allow a Datatype to refer to
- * itself or to other mutually-recursive Datatypes. Unresolved-type
- * fields of Datatypes will be properly typed when a Type is created
- * for the Datatype by the ExprManager (which calls
- * Datatype::resolve()).
- */
-class CVC4_PUBLIC DatatypeUnresolvedType {
- std::string d_name;
-public:
- inline DatatypeUnresolvedType(std::string name);
- inline std::string getName() const;
-};/* class DatatypeUnresolvedType */
-
-/**
- * A Datatype constructor argument (i.e., a Datatype field).
- */
-class CVC4_PUBLIC DatatypeConstructorArg {
- friend class DatatypeConstructor;
- friend class Datatype;
-
- public:
- /** Get the name of this constructor argument. */
- std::string getName() const;
-
- /**
- * Get the selector for this constructor argument; this call is
- * only permitted after resolution.
- */
- Expr getSelector() const;
-
- /**
- * Get the associated constructor for this constructor argument;
- * this call is only permitted after resolution.
- */
- Expr getConstructor() const;
-
- /**
- * Get the type of the selector for this constructor argument;
- * this call is only permitted after resolution.
- */
- SelectorType getType() const;
-
- /**
- * Get the range type of this argument.
- */
- Type getRangeType() const;
-
- /**
- * Returns true iff this constructor argument has been resolved.
- */
- bool isResolved() const;
-
- /** prints this datatype constructor argument to stream */
- void toStream(std::ostream& out) const;
-
- private:
- /** The internal representation */
- std::shared_ptr<DTypeSelector> d_internal;
- /** The selector */
- Expr d_selector;
- /** is this selector unresolved? */
- bool isUnresolvedSelf() const;
- /** constructor */
- DatatypeConstructorArg(std::string name, Expr selector);
-};/* class DatatypeConstructorArg */
-
-class DTypeConstructor;
-
-/**
- * A constructor for a Datatype.
- */
-class CVC4_PUBLIC DatatypeConstructor {
- friend class Datatype;
-
- public:
- /** The type for iterators over constructor arguments. */
- typedef DatatypeConstructorArgIterator iterator;
- /** The (const) type for iterators over constructor arguments. */
- typedef DatatypeConstructorArgIterator const_iterator;
-
- /**
- * Create a new Datatype constructor with the given name for the
- * constructor. The actual constructor and tester (meaning, the Exprs
- * representing operators for these entities) aren't created until
- * resolution time.
- * weight is the value that this constructor carries when computing size.
- * For example, if A, B, C have weights 0, 1, and 3 respectively, then
- * C( B( A() ), B( A() ) ) has size 5.
- */
- explicit DatatypeConstructor(std::string name, unsigned weight = 1);
-
- ~DatatypeConstructor() {}
- /**
- * Add an argument (i.e., a data field) of the given name and type
- * to this Datatype constructor. Selector names need not be unique;
- * they are for convenience and pretty-printing only.
- */
- void addArg(std::string selectorName, Type selectorType);
-
- /**
- * Add an argument (i.e., a data field) of the given name to this
- * Datatype constructor that refers to an as-yet-unresolved
- * Datatype (which may be mutually-recursive). Selector names need
- * not be unique; they are for convenience and pretty-printing only.
- */
- void addArg(std::string selectorName, DatatypeUnresolvedType selectorType);
-
- /**
- * Add a self-referential (i.e., a data field) of the given name
- * to this Datatype constructor that refers to the enclosing
- * Datatype. For example, using the familiar "nat" Datatype, to
- * create the "pred" field for "succ" constructor, one uses
- * succ::addArg("pred", DatatypeSelfType())---the actual Type
- * cannot be passed because the Datatype is still under
- * construction. Selector names need not be unique; they are for
- * convenience and pretty-printing only.
- *
- * This is a special case of
- * DatatypeConstructor::addArg(std::string, DatatypeUnresolvedType).
- */
- void addArg(std::string selectorName, DatatypeSelfType);
-
- /** Get the name of this Datatype constructor. */
- std::string getName() const;
-
- /**
- * Get the constructor operator of this Datatype constructor. The
- * Datatype must be resolved.
- */
- Expr getConstructor() const;
-
- /**
- * Get the tester operator of this Datatype constructor. The
- * Datatype must be resolved.
- */
- Expr getTester() const;
-
- /** get sygus op
- *
- * This method returns the operator or
- * term that this constructor represents
- * in the sygus encoding. This may be a
- * builtin operator, defined function, variable,
- * or constant that this constructor encodes in this
- * deep embedding.
- */
- Expr getSygusOp() const;
- /** is this a sygus identity function?
- *
- * This returns true if the sygus operator of this datatype constructor is
- * of the form (lambda (x) x).
- */
- bool isSygusIdFunc() const;
- /** get weight
- *
- * Get the weight of this constructor. This value is used when computing the
- * size of datatype terms that involve this constructor.
- */
- unsigned getWeight() const;
-
- /**
- * Get the number of arguments (so far) of this Datatype constructor.
- */
- size_t getNumArgs() const;
-
- /**
- * Get the specialized constructor type for a parametric
- * constructor; this call is only permitted after resolution.
- * Given a (concrete) returnType, the constructor's concrete
- * type in this parametric datatype is returned.
- *
- * For instance, if the datatype is list[T], with constructor
- * "cons[T]" of type "T -> list[T] -> list[T]", then calling
- * this function with "list[int]" will return the concrete
- * "cons" constructor type for lists of int---namely,
- * "int -> list[int] -> list[int]".
- */
- Type getSpecializedConstructorType(Type returnType) const;
-
- /**
- * Return the cardinality of this constructor (the product of the
- * cardinalities of its arguments).
- */
- Cardinality getCardinality(Type t) const;
-
- /**
- * Return true iff this constructor is finite (it is nullary or
- * each of its argument types are finite). This function can
- * only be called for resolved constructors.
- */
- bool isFinite(Type t) const;
- /**
- * Return true iff this constructor is finite (it is nullary or
- * each of its argument types are finite) under assumption
- * uninterpreted sorts are finite. This function can
- * only be called for resolved constructors.
- */
- bool isInterpretedFinite(Type t) const;
-
- /**
- * Returns true iff this Datatype constructor has already been
- * resolved.
- */
- bool isResolved() const;
-
- /** Get the beginning iterator over DatatypeConstructor args. */
- iterator begin();
- /** Get the ending iterator over DatatypeConstructor args. */
- iterator end();
- /** Get the beginning const_iterator over DatatypeConstructor args. */
- const_iterator begin() const;
- /** Get the ending const_iterator over DatatypeConstructor args. */
- const_iterator end() const;
-
- /** Get the ith DatatypeConstructor arg. */
- const DatatypeConstructorArg& operator[](size_t index) const;
-
- /**
- * Get the DatatypeConstructor arg named. This is a linear search
- * through the arguments, so in the case of multiple,
- * similarly-named arguments, the first is returned.
- */
- const DatatypeConstructorArg& operator[](std::string name) const;
-
- /**
- * Get the selector named. This is a linear search
- * through the arguments, so in the case of multiple,
- * similarly-named arguments, the selector for the first
- * is returned.
- */
- Expr getSelector(std::string name) const;
- /**
- * Get argument type. Returns the return type of the i^th selector of this
- * constructor.
- */
- Type getArgType(unsigned i) const;
-
- /** get selector internal
- *
- * This gets selector for the index^th argument
- * of this constructor. The type dtt is the datatype
- * type whose datatype is the owner of this constructor,
- * where this type may be an instantiated parametric datatype.
- *
- * If shared selectors are enabled,
- * this returns a shared (constructor-agnotic) selector, which
- * in the terminology of "Datatypes with Shared Selectors", is:
- * sel_{dtt}^{T,atos(T,C,index)}
- * where C is this constructor, and T is the type
- * of the index^th field of this constructor.
- * The semantics of sel_{dtt}^{T,n}( t ) is the n^th field of
- * type T of constructor term t if one exists, or is
- * unconstrained otherwise.
- */
- Expr getSelectorInternal(Type dtt, size_t index) const;
-
- /** get selector index internal
- *
- * This gets the argument number of this constructor
- * that the selector sel accesses. It returns -1 if the
- * selector sel is not a selector for this constructor.
- *
- * In the terminology of "Datatypes with Shared Selectors",
- * if sel is sel_{dtt}^{T,index} for some (T, index), where
- * dtt is the datatype type whose datatype is the owner
- * of this constructor, then this method returns
- * stoa(T,C,index)
- */
- int getSelectorIndexInternal( Expr sel ) const;
-
- /** involves external type
- *
- * Get whether this constructor has a subfield
- * in any constructor that is not a datatype type.
- */
- bool involvesExternalType() const;
- /** involves external type
- *
- * Get whether this constructor has a subfield
- * in any constructor that is an uninterpreted type.
- */
- bool involvesUninterpretedType() const;
-
- /** set sygus
- *
- * Set that this constructor is a sygus datatype constructor that encodes
- * operator op. spc is the sygus callback of this datatype constructor,
- * which is stored in a shared pointer.
- */
- void setSygus(Expr op);
-
- /**
- * Get the list of arguments to this constructor.
- */
- const std::vector<DatatypeConstructorArg>* getArgs() const;
-
- /** prints this datatype constructor to stream */
- void toStream(std::ostream& out) const;
-
- private:
- /** The internal representation */
- std::shared_ptr<DTypeConstructor> d_internal;
- /** The constructor */
- Expr d_constructor;
- /** the arguments of this constructor */
- std::vector<DatatypeConstructorArg> d_args;
-};/* class DatatypeConstructor */
-
-class DType;
-
-/**
- * The representation of an inductive datatype.
- *
- * This is far more complicated than it first seems. Consider this
- * datatype definition:
- *
- * DATATYPE nat =
- * succ(pred: nat)
- * | zero
- * END;
- *
- * You cannot define "nat" until you have a Type for it, but you
- * cannot have a Type for it until you fill in the type of the "pred"
- * selector, which needs the Type. So we have a chicken-and-egg
- * problem. It's even more complicated when we have mutual recursion
- * between datatypes, since the CVC presentation language does not
- * require forward-declarations. Here, we define trees of lists that
- * contain trees of lists (etc):
- *
- * DATATYPE
- * tree = node(left: tree, right: tree) | leaf(list),
- * list = cons(car: tree, cdr: list) | nil
- * END;
- *
- * Note that while parsing the "tree" definition, we have to take it
- * on faith that "list" is a valid type. We build Datatype objects to
- * describe "tree" and "list", and their constructors and constructor
- * arguments, but leave any unknown types (including self-references)
- * in an "unresolved" state. After parsing the whole DATATYPE block,
- * we create a DatatypeType through
- * ExprManager::mkMutualDatatypeTypes(). The ExprManager creates a
- * DatatypeType for each, but before "releasing" this type into the
- * wild, it does a round of in-place "resolution" on each Datatype by
- * calling Datatype::resolve() with a map of string -> DatatypeType to
- * allow the datatype to construct the necessary testers and
- * selectors.
- *
- * An additional point to make is that we want to ease the burden on
- * both the parser AND the users of the CVC4 API, so this class takes
- * on the task of generating its own selectors and testers, for
- * instance. That means that, after reifying the Datatype with the
- * ExprManager, the parser needs to go through the (now-resolved)
- * Datatype and request the constructor, selector, and tester terms.
- * See src/parser/parser.cpp for how this is done. For API usage
- * ideas, see test/unit/util/datatype_black.h.
- *
- * Datatypes may also be defined parametrically, such as this example:
- *
- * DATATYPE
- * list[T] = cons(car : T, cdr : list[T]) | null,
- * tree = node(children : list[tree]) | leaf
- * END;
- *
- * Here, the definition of the parametric datatype list, where T is a type variable.
- * In other words, this defines a family of types list[C] where C is any concrete
- * type. Datatypes can be parameterized over multiple type variables using the
- * syntax sym[ T1, ..., Tn ] = ...,
- *
- */
-class CVC4_PUBLIC Datatype {
- friend class DatatypeConstructor;
- friend class ExprManager; // for access to resolve()
- friend class NodeManager; // temporary, for access to d_internal
- public:
- /**
- * Get the datatype of a constructor, selector, or tester operator.
- */
- static const Datatype& datatypeOf(Expr item) CVC4_PUBLIC;
-
- /**
- * Get the index of a constructor or tester in its datatype, or the
- * index of a selector in its constructor. (Zero is always the
- * first index.)
- */
- static size_t indexOf(Expr item) CVC4_PUBLIC;
-
- /**
- * Get the index of constructor corresponding to selector. (Zero is
- * always the first index.)
- */
- static size_t cindexOf(Expr item) CVC4_PUBLIC;
-
- /**
- * Same as above, but without checks. These methods should be used by
- * internal (Node-level) code.
- */
- static size_t indexOfInternal(Expr item);
- static size_t cindexOfInternal(Expr item);
-
- /** The type for iterators over constructors. */
- typedef DatatypeConstructorIterator iterator;
- /** The (const) type for iterators over constructors. */
- typedef DatatypeConstructorIterator const_iterator;
-
- /** Create a new Datatype of the given name. */
- explicit Datatype(ExprManager* em, std::string name, bool isCo = false);
-
- /**
- * Create a new Datatype of the given name, with the given
- * parameterization.
- */
- Datatype(ExprManager* em,
- std::string name,
- const std::vector<Type>& params,
- bool isCo = false);
-
- ~Datatype();
-
- /** Add a constructor to this Datatype.
- *
- * Notice that constructor names need not
- * be unique; they are for convenience and pretty-printing only.
- */
- void addConstructor(const DatatypeConstructor& c);
-
- /** set sygus
- *
- * This marks this datatype as a sygus datatype.
- * A sygus datatype is one that represents terms of type st
- * via a deep embedding described in Section 4 of
- * Reynolds et al. CAV 2015. We say that this sygus datatype
- * "encodes" its sygus type st in the following.
- *
- * st : the type this datatype encodes (this can be Int, Bool, etc.),
- * bvl : the list of arguments for the synth-fun
- * allow_const : whether all constants are (implicitly) allowed by the
- * datatype
- * allow_all : whether all terms are (implicitly) allowed by the datatype
- *
- * Notice that allow_const/allow_all do not reflect the constructors
- * for this datatype, and instead are used solely for relaxing constraints
- * when doing solution reconstruction (Figure 5 of Reynolds et al.
- * CAV 2015).
- */
- void setSygus( Type st, Expr bvl, bool allow_const, bool allow_all );
- /** add sygus constructor
- *
- * This adds a sygus constructor to this datatype, where
- * this datatype should be currently unresolved.
- *
- * op : the builtin operator, constant, or variable that
- * this constructor encodes
- * cname : the name of the constructor (for printing only)
- * cargs : the arguments of the constructor
- *
- * It should be the case that cargs are sygus datatypes that
- * encode the arguments of op. For example, a sygus constructor
- * with op = PLUS should be such that cargs.size()>=2 and
- * the sygus type of cargs[i] is Real/Int for each i.
- *
- * weight denotes the value added by the constructor when computing the size
- * of datatype terms. Passing a value <0 denotes the default weight for the
- * constructor, which is 0 for nullary constructors and 1 for non-nullary
- * constructors.
- */
- void addSygusConstructor(Expr op,
- const std::string& cname,
- const std::vector<Type>& cargs,
- int weight = -1);
- /**
- * Same as above, with builtin kind k.
- */
- void addSygusConstructor(Kind k,
- const std::string& cname,
- const std::vector<Type>& cargs,
- int weight = -1);
-
- /** set that this datatype is a tuple */
- void setTuple();
-
- /** set that this datatype is a record */
- void setRecord();
-
- /** Get the name of this Datatype. */
- std::string getName() const;
-
- /** Get the number of constructors (so far) for this Datatype. */
- size_t getNumConstructors() const;
-
- /** Is this datatype parametric? */
- bool isParametric() const;
-
- /** Get the nubmer of type parameters */
- size_t getNumParameters() const;
-
- /** Get parameter */
- Type getParameter(unsigned int i) const;
-
- /** Get parameters */
- std::vector<Type> getParameters() const;
-
- /** is this a co-datatype? */
- bool isCodatatype() const;
-
- /** is this a sygus datatype? */
- bool isSygus() const;
-
- /** is this a tuple datatype? */
- bool isTuple() const;
-
- /** is this a record datatype? */
- bool isRecord() const;
-
- /** get the record representation for this datatype */
- Record* getRecord() const;
-
- /**
- * Return the cardinality of this datatype.
- * The Datatype must be resolved.
- *
- * The version of this method that takes Type t is required
- * for parametric datatypes, where t is an instantiated
- * parametric datatype type whose datatype is this class.
- */
- Cardinality getCardinality(Type t) const;
- Cardinality getCardinality() const;
-
- /**
- * Return true iff this Datatype has finite cardinality. If the
- * datatype is not well-founded, this method returns false. The
- * Datatype must be resolved or an exception is thrown.
- *
- * The version of this method that takes Type t is required
- * for parametric datatypes, where t is an instantiated
- * parametric datatype type whose datatype is this class.
- */
- bool isFinite(Type t) const;
- bool isFinite() const;
-
- /**
- * Return true iff this Datatype is finite (all constructors are
- * finite, i.e., there are finitely many ground terms) under the
- * assumption unintepreted sorts are finite. If the
- * datatype is not well-founded, this method returns false. The
- * Datatype must be resolved or an exception is thrown.
- *
- * The versions of these methods that takes Type t is required
- * for parametric datatypes, where t is an instantiated
- * parametric datatype type whose datatype is this class.
- */
- bool isInterpretedFinite(Type t) const;
- bool isInterpretedFinite() const;
-
- /** is well-founded
- *
- * Return true iff this datatype is well-founded (there exist finite
- * values of this type).
- * This datatype must be resolved or an exception is thrown.
- */
- bool isWellFounded() const;
- /** has nested recursion
- *
- * Return true iff this datatype has nested recursion.
- * This datatype must be resolved or an exception is thrown.
- */
- bool hasNestedRecursion() const;
-
- /** is recursive singleton
- *
- * Return true iff this datatype is a recursive singleton
- * (a recursive singleton is a recursive datatype with only
- * one infinite value). For details, see Reynolds et al. CADE 2015.
- *
- * The versions of these methods that takes Type t is required
- * for parametric datatypes, where t is an instantiated
- * parametric datatype type whose datatype is this class.
- */
- bool isRecursiveSingleton(Type t) const;
- bool isRecursiveSingleton() const;
-
- /** recursive single arguments
- *
- * Get recursive singleton argument types (uninterpreted sorts that the
- * cardinality of this datatype is dependent upon). For example, for :
- * stream := cons( head1 : U1, head2 : U2, tail : stream )
- * Then, the recursive singleton argument types of stream are { U1, U2 },
- * since if U1 and U2 have cardinality one, then stream has cardinality
- * one as well.
- *
- * The versions of these methods that takes Type t is required
- * for parametric datatypes, where t is an instantiated
- * parametric datatype type whose datatype is this class.
- */
- unsigned getNumRecursiveSingletonArgTypes(Type t) const;
- Type getRecursiveSingletonArgType(Type t, unsigned i) const;
- unsigned getNumRecursiveSingletonArgTypes() const;
- Type getRecursiveSingletonArgType(unsigned i) const;
-
- /**
- * Construct and return a ground term of this Datatype. The
- * Datatype must be both resolved and well-founded, or else an
- * exception is thrown.
- *
- * This method takes a Type t, which is a datatype type whose
- * datatype is this class, which may be an instantiated datatype
- * type if this datatype is parametric.
- */
- Expr mkGroundTerm(Type t) const;
- /** Make ground value
- *
- * Same as above, but constructs a constant value instead of a ground term.
- * These two notions typically coincide. However, for uninterpreted sorts,
- * they do not: mkGroundTerm returns a fresh variable whereas mkValue returns
- * an uninterpreted constant. The motivation for mkGroundTerm is that
- * unintepreted constants should never appear in lemmas. The motivation for
- * mkGroundValue is for things like type enumeration and model construction.
- */
- Expr mkGroundValue(Type t) const;
-
- /**
- * Get the DatatypeType associated to this Datatype. Can only be
- * called post-resolution.
- */
- DatatypeType getDatatypeType() const;
-
- /**
- * Get the DatatypeType associated to this (parameterized) Datatype. Can only be
- * called post-resolution.
- */
- DatatypeType getDatatypeType(const std::vector<Type>& params) const;
-
- /**
- * Return true iff the two Datatypes are the same.
- *
- * We need == for mkConst(Datatype) to properly work---since if the
- * Datatype Expr requested is the same as an already-existing one,
- * we need to return that one. For that, we have a hash and
- * operator==. We provide != for symmetry. We don't provide
- * operator<() etc. because given two Datatype Exprs, you could
- * simply compare those rather than the (bare) Datatypes. This
- * means, though, that Datatype cannot be stored in a sorted list or
- * RB tree directly, so maybe we can consider adding these
- * comparison operators later on.
- */
- bool operator==(const Datatype& other) const;
- /** Return true iff the two Datatypes are not the same. */
- bool operator!=(const Datatype& other) const;
-
- /** Return true iff this Datatype has already been resolved. */
- bool isResolved() const;
-
- /** Get the beginning iterator over DatatypeConstructors. */
- iterator begin();
- /** Get the ending iterator over DatatypeConstructors. */
- iterator end();
- /** Get the beginning const_iterator over DatatypeConstructors. */
- const_iterator begin() const;
- /** Get the ending const_iterator over DatatypeConstructors. */
- const_iterator end() const;
-
- /** Get the ith DatatypeConstructor. */
- const DatatypeConstructor& operator[](size_t index) const;
-
- /**
- * Get the DatatypeConstructor named. This is a linear search
- * through the constructors, so in the case of multiple,
- * similarly-named constructors, the first is returned.
- */
- const DatatypeConstructor& operator[](std::string name) const;
-
- /**
- * Get the constructor operator for the named constructor.
- * This is a linear search through the constructors, so in
- * the case of multiple, similarly-named constructors, the
- * first is returned.
- *
- * This Datatype must be resolved.
- */
- Expr getConstructor(std::string name) const;
-
- /** get sygus type
- * This gets the built-in type associated with
- * this sygus datatype, i.e. the type of the
- * term that this sygus datatype encodes.
- */
- Type getSygusType() const;
-
- /** get sygus var list
- * This gets the variable list of the function
- * to synthesize using this sygus datatype.
- * For example, if we are synthesizing a binary
- * function f where solutions are of the form:
- * f = (lambda (xy) t[x,y])
- * In this case, this method returns the
- * bound variable list containing x and y.
- */
- Expr getSygusVarList() const;
- /** get sygus allow constants
- *
- * Does this sygus datatype allow constants?
- * Notice that this is not a property of the
- * constructors of this datatype. Instead, it is
- * an auxiliary flag (provided in the call
- * to setSygus).
- */
- bool getSygusAllowConst() const;
- /** get sygus allow all
- *
- * Does this sygus datatype allow all terms?
- * Notice that this is not a property of the
- * constructors of this datatype. Instead, it is
- * an auxiliary flag (provided in the call
- * to setSygus).
- */
- bool getSygusAllowAll() const;
-
- /** involves external type
- * Get whether this datatype has a subfield
- * in any constructor that is not a datatype type.
- */
- bool involvesExternalType() const;
- /** involves uninterpreted type
- * Get whether this datatype has a subfield
- * in any constructor that is an uninterpreted type.
- */
- bool involvesUninterpretedType() const;
-
- /**
- * Get the list of constructors.
- */
- const std::vector<DatatypeConstructor>* getConstructors() const;
-
- /** prints this datatype to stream */
- void toStream(std::ostream& out) const;
-
- private:
- /** The expression manager that created this datatype */
- ExprManager* d_em;
- /** The internal representation */
- std::shared_ptr<DType> d_internal;
- /** self type */
- Type d_self;
- /** the data of the record for this datatype (if applicable) */
- std::shared_ptr<Record> d_record;
- /** whether the datatype is a record */
- bool d_isRecord;
- /** the constructors of this datatype */
- std::vector<DatatypeConstructor> d_constructors;
- /**
- * Datatypes refer to themselves, recursively, and we have a
- * chicken-and-egg problem. The DatatypeType around the Datatype
- * cannot exist until the Datatype is finalized, and the Datatype
- * cannot refer to the DatatypeType representing itself until it
- * exists. resolve() is called by the ExprManager when a Type is
- * ultimately requested of the Datatype specification (that is, when
- * ExprManager::mkDatatypeType() or ExprManager::mkMutualDatatypeTypes()
- * is called). Has the effect of freezing the object, too; that is,
- * addConstructor() will fail after a call to resolve().
- *
- * The basic goal of resolution is to assign constructors, selectors,
- * and testers. To do this, any UnresolvedType/SelfType references
- * must be cleared up. This is the purpose of the "resolutions" map;
- * it includes any mutually-recursive datatypes that are currently
- * under resolution. The four vectors come in two pairs (so, really
- * they are two maps). placeholders->replacements give type variables
- * that should be resolved in the case of parametric datatypes.
- *
- * @param resolutions a map of strings to DatatypeTypes currently under
- * resolution
- * @param placeholders the types in these Datatypes under resolution that must
- * be replaced
- * @param replacements the corresponding replacements
- * @param paramTypes the sort constructors in these Datatypes under resolution
- * that must be replaced
- * @param paramReplacements the corresponding (parametric) DatatypeTypes
- */
- void resolve(const std::map<std::string, DatatypeType>& resolutions,
- const std::vector<Type>& placeholders,
- const std::vector<Type>& replacements,
- const std::vector<SortConstructorType>& paramTypes,
- const std::vector<DatatypeType>& paramReplacements);
-};/* class Datatype */
-
-/**
- * A hash function for Datatypes. Needed to store them in hash sets
- * and hash maps.
- */
-struct CVC4_PUBLIC DatatypeHashFunction {
- inline size_t operator()(const Datatype& dt) const {
- return std::hash<std::string>()(dt.getName());
- }
- inline size_t operator()(const Datatype* dt) const {
- return std::hash<std::string>()(dt->getName());
- }
- inline size_t operator()(const DatatypeConstructor& dtc) const {
- return std::hash<std::string>()(dtc.getName());
- }
- inline size_t operator()(const DatatypeConstructor* dtc) const {
- return std::hash<std::string>()(dtc->getName());
- }
-};/* struct DatatypeHashFunction */
-
-
-
-/* stores an index to Datatype residing in NodeManager */
-class CVC4_PUBLIC DatatypeIndexConstant {
- public:
- DatatypeIndexConstant(unsigned index);
-
- unsigned getIndex() const { return d_index; }
- bool operator==(const DatatypeIndexConstant& uc) const
- {
- return d_index == uc.d_index;
- }
- bool operator!=(const DatatypeIndexConstant& uc) const
- {
- return !(*this == uc);
- }
- bool operator<(const DatatypeIndexConstant& uc) const
- {
- return d_index < uc.d_index;
- }
- bool operator<=(const DatatypeIndexConstant& uc) const
- {
- return d_index <= uc.d_index;
- }
- bool operator>(const DatatypeIndexConstant& uc) const
- {
- return !(*this <= uc);
- }
- bool operator>=(const DatatypeIndexConstant& uc) const
- {
- return !(*this < uc);
- }
-private:
- const unsigned d_index;
-};/* class DatatypeIndexConstant */
-
-std::ostream& operator<<(std::ostream& out, const DatatypeIndexConstant& dic) CVC4_PUBLIC;
-
-struct CVC4_PUBLIC DatatypeIndexConstantHashFunction {
- inline size_t operator()(const DatatypeIndexConstant& dic) const {
- return IntegerHashFunction()(dic.getIndex());
- }
-};/* struct DatatypeIndexConstantHashFunction */
-
-
-
-// FUNCTION DECLARATIONS FOR OUTPUT STREAMS
-
-std::ostream& operator<<(std::ostream& os, const Datatype& dt) CVC4_PUBLIC;
-std::ostream& operator<<(std::ostream& os, const DatatypeConstructor& ctor) CVC4_PUBLIC;
-std::ostream& operator<<(std::ostream& os, const DatatypeConstructorArg& arg) CVC4_PUBLIC;
-
-// INLINE FUNCTIONS
-
-inline DatatypeResolutionException::DatatypeResolutionException(std::string msg) :
- Exception(msg) {
-}
-
-inline DatatypeUnresolvedType::DatatypeUnresolvedType(std::string name) :
- d_name(name) {
-}
-
-inline std::string DatatypeUnresolvedType::getName() const { return d_name; }
-
-
-}/* CVC4 namespace */
-
-#endif /* CVC4__DATATYPE_H */
diff --git a/src/expr/datatype_index.cpp b/src/expr/datatype_index.cpp
new file mode 100644
index 000000000..694d75db6
--- /dev/null
+++ b/src/expr/datatype_index.cpp
@@ -0,0 +1,36 @@
+/********************* */
+/*! \file datatype_index.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief A class representing an index to a datatype living in NodeManager.
+ **/
+#include "expr/datatype_index.h"
+
+#include <sstream>
+#include <string>
+#include "util/integer.h"
+
+using namespace std;
+
+namespace CVC4 {
+
+DatatypeIndexConstant::DatatypeIndexConstant(unsigned index) : d_index(index) {}
+std::ostream& operator<<(std::ostream& out, const DatatypeIndexConstant& dic)
+{
+ return out << "index_" << dic.getIndex();
+}
+
+size_t DatatypeIndexConstantHashFunction::operator()(
+ const DatatypeIndexConstant& dic) const
+{
+ return IntegerHashFunction()(dic.getIndex());
+}
+
+} // namespace CVC4
diff --git a/src/expr/datatype_index.h b/src/expr/datatype_index.h
new file mode 100644
index 000000000..c7f170ff6
--- /dev/null
+++ b/src/expr/datatype_index.h
@@ -0,0 +1,71 @@
+/********************* */
+/*! \file datatype_index.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Tim King, Ken Matsui
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief A class representing an index to a datatype living in NodeManager.
+ **/
+
+#include "cvc4_public.h"
+
+#ifndef CVC4__DATATYPE_INDEX_H
+#define CVC4__DATATYPE_INDEX_H
+
+#include <iosfwd>
+#include "util/hash.h"
+
+namespace CVC4 {
+
+/* stores an index to Datatype residing in NodeManager */
+class CVC4_PUBLIC DatatypeIndexConstant
+{
+ public:
+ DatatypeIndexConstant(unsigned index);
+
+ unsigned getIndex() const { return d_index; }
+ bool operator==(const DatatypeIndexConstant& uc) const
+ {
+ return d_index == uc.d_index;
+ }
+ bool operator!=(const DatatypeIndexConstant& uc) const
+ {
+ return !(*this == uc);
+ }
+ bool operator<(const DatatypeIndexConstant& uc) const
+ {
+ return d_index < uc.d_index;
+ }
+ bool operator<=(const DatatypeIndexConstant& uc) const
+ {
+ return d_index <= uc.d_index;
+ }
+ bool operator>(const DatatypeIndexConstant& uc) const
+ {
+ return !(*this <= uc);
+ }
+ bool operator>=(const DatatypeIndexConstant& uc) const
+ {
+ return !(*this < uc);
+ }
+
+ private:
+ const unsigned d_index;
+}; /* class DatatypeIndexConstant */
+
+std::ostream& operator<<(std::ostream& out,
+ const DatatypeIndexConstant& dic) CVC4_PUBLIC;
+
+struct CVC4_PUBLIC DatatypeIndexConstantHashFunction
+{
+ size_t operator()(const DatatypeIndexConstant& dic) const;
+}; /* struct DatatypeIndexConstantHashFunction */
+
+} // namespace CVC4
+
+#endif /* CVC4__DATATYPE_H */
diff --git a/src/expr/dtype.cpp b/src/expr/dtype.cpp
index eb9a22702..4c93e5727 100644
--- a/src/expr/dtype.cpp
+++ b/src/expr/dtype.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,6 +25,7 @@ DType::DType(std::string name, bool isCo)
d_params(),
d_isCo(isCo),
d_isTuple(false),
+ d_isRecord(false),
d_constructors(),
d_resolved(false),
d_self(),
@@ -43,6 +44,7 @@ DType::DType(std::string name, const std::vector<TypeNode>& params, bool isCo)
d_params(params),
d_isCo(isCo),
d_isTuple(false),
+ d_isRecord(false),
d_constructors(),
d_resolved(false),
d_self(),
@@ -82,6 +84,8 @@ bool DType::isSygus() const { return !d_sygusType.isNull(); }
bool DType::isTuple() const { return d_isTuple; }
+bool DType::isRecord() const { return d_isRecord; }
+
bool DType::isResolved() const { return d_resolved; }
const DType& DType::datatypeOf(Node item)
@@ -216,9 +220,70 @@ void DType::addConstructor(std::shared_ptr<DTypeConstructor> c)
d_constructors.push_back(c);
}
+void DType::addSygusConstructor(Node op,
+ const std::string& cname,
+ const std::vector<TypeNode>& cargs,
+ int weight)
+{
+ // avoid name clashes
+ std::stringstream ss;
+ ss << getName() << "_" << getNumConstructors() << "_" << cname;
+ std::string name = ss.str();
+ unsigned cweight = weight >= 0 ? weight : (cargs.empty() ? 0 : 1);
+ std::shared_ptr<DTypeConstructor> c =
+ std::make_shared<DTypeConstructor>(name, cweight);
+ c->setSygus(op);
+ for (size_t j = 0, nargs = cargs.size(); j < nargs; j++)
+ {
+ std::stringstream sname;
+ sname << name << "_" << j;
+ c->addArg(sname.str(), cargs[j]);
+ }
+ addConstructor(c);
+}
+
void DType::setSygus(TypeNode st, Node bvl, bool allowConst, bool allowAll)
{
Assert(!d_resolved);
+ // We can be in a case where the only rule specified was
+ // (Constant T), in which case we have not yet added a constructor. We
+ // ensure an arbitrary constant is added in this case. We additionally
+ // add a constant if the grammar has only non-nullary constructors, since this
+ // ensures the datatype is well-founded (see 3423).
+ // Notice we only want to do this for sygus datatypes that are user-provided.
+ // At the moment, the condition !allow_all implies the grammar is
+ // user-provided and hence may require a default constant.
+ // TODO (https://github.com/CVC4/cvc4-projects/issues/38):
+ // In an API for SyGuS, it probably makes more sense for the user to
+ // explicitly add the "any constant" constructor with a call instead of
+ // passing a flag. This would make the block of code unnecessary.
+ if (allowConst && !allowAll)
+ {
+ // if I don't already have a constant (0-ary constructor)
+ bool hasConstant = false;
+ for (size_t i = 0, ncons = getNumConstructors(); i < ncons; i++)
+ {
+ if ((*this)[i].getNumArgs() == 0)
+ {
+ hasConstant = true;
+ break;
+ }
+ }
+ if (!hasConstant)
+ {
+ // add an arbitrary one
+ Node op = st.mkGroundTerm();
+ // use same naming convention as SygusDatatype
+ std::stringstream ss;
+ ss << getName() << "_" << getNumConstructors() << "_" << op;
+ // it has zero weight
+ std::shared_ptr<DTypeConstructor> c =
+ std::make_shared<DTypeConstructor>(ss.str(), 0);
+ c->setSygus(op);
+ addConstructor(c);
+ }
+ }
+
d_sygusType = st;
d_sygusBvl = bvl;
d_sygusAllowConst = allowConst || allowAll;
@@ -231,6 +296,12 @@ void DType::setTuple()
d_isTuple = true;
}
+void DType::setRecord()
+{
+ Assert(!d_resolved);
+ d_isRecord = true;
+}
+
Cardinality DType::getCardinality(TypeNode t) const
{
Trace("datatypes-init") << "DType::getCardinality " << std::endl;
diff --git a/src/expr/dtype.h b/src/expr/dtype.h
index fea51cd36..e4bae29b8 100644
--- a/src/expr/dtype.h
+++ b/src/expr/dtype.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -78,8 +78,6 @@ typedef expr::Attribute<DTypeUFiniteComputedTag, bool> DTypeUFiniteComputedAttr;
class NodeManager;
-class Datatype;
-
/**
* The Node-level representation of an inductive datatype, which currently
* resides within the Expr-level Datatype class (expr/datatype.h).
@@ -142,7 +140,6 @@ class Datatype;
*/
class DType
{
- friend class Datatype;
friend class DTypeConstructor;
friend class NodeManager; // for access to resolve()
@@ -191,6 +188,31 @@ class DType
* be unique; they are for convenience and pretty-printing only.
*/
void addConstructor(std::shared_ptr<DTypeConstructor> c);
+ /** add sygus constructor
+ *
+ * This adds a sygus constructor to this datatype, where
+ * this datatype should be currently unresolved. Note this method is
+ * syntactic sugar for adding a normal constructor and setting it to be a
+ * sygus constructor, and following a naming convention that avoids
+ * constructors with the same name.
+ *
+ * @param op : the builtin operator, constant, or variable that this
+ * constructor encodes
+ * @param cname the name of the constructor (for printing only)
+ * @param cargs the arguments of the constructor.
+ * It should be the case that cargs are sygus datatypes that
+ * encode the arguments of op. For example, a sygus constructor
+ * with op = PLUS should be such that cargs.size()>=2 and
+ * the sygus type of cargs[i] is Real/Int for each i.
+ * @param weight denotes the value added by the constructor when computing the
+ * size of datatype terms. Passing a value < 0 denotes the default weight for
+ * the constructor, which is 0 for nullary constructors and 1 for non-nullary
+ * constructors.
+ */
+ void addSygusConstructor(Node op,
+ const std::string& cname,
+ const std::vector<TypeNode>& cargs,
+ int weight = -1);
/** set sygus
*
@@ -216,6 +238,9 @@ class DType
/** set that this datatype is a tuple */
void setTuple();
+ /** set that this datatype is a record */
+ void setRecord();
+
/** Get the name of this DType. */
std::string getName() const;
@@ -243,6 +268,9 @@ class DType
/** is this a tuple datatype? */
bool isTuple() const;
+ /** is this a record datatype? */
+ bool isRecord() const;
+
/**
* Return the cardinality of this datatype.
* The DType must be resolved.
@@ -553,6 +581,8 @@ class DType
bool d_isCo;
/** whether the datatype is a tuple */
bool d_isTuple;
+ /** whether the datatype is a record */
+ bool d_isRecord;
/** the constructors of this datatype */
std::vector<std::shared_ptr<DTypeConstructor> > d_constructors;
/** whether this datatype has been resolved */
diff --git a/src/expr/dtype_cons.cpp b/src/expr/dtype_cons.cpp
index b2e3fbd43..d63db28d5 100644
--- a/src/expr/dtype_cons.cpp
+++ b/src/expr/dtype_cons.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -51,7 +51,7 @@ void DTypeConstructor::addArg(std::string selectorName, TypeNode selectorType)
selectorType,
"is an unresolved selector type placeholder",
NodeManager::SKOLEM_EXACT_NAME | NodeManager::SKOLEM_NO_NOTIFY);
- Trace("datatypes") << type << std::endl;
+ Trace("datatypes") << "DTypeConstructor::addArg: " << type << std::endl;
std::shared_ptr<DTypeSelector> a =
std::make_shared<DTypeSelector>(selectorName, type);
addArg(a);
@@ -62,7 +62,15 @@ void DTypeConstructor::addArg(std::shared_ptr<DTypeSelector> a)
d_args.push_back(a);
}
-std::string DTypeConstructor::getName() const { return d_name; }
+void DTypeConstructor::addArgSelf(std::string selectorName)
+{
+ Trace("datatypes") << "DTypeConstructor::addArgSelf" << std::endl;
+ std::shared_ptr<DTypeSelector> a =
+ std::make_shared<DTypeSelector>(selectorName + '\0', Node::null());
+ addArg(a);
+}
+
+const std::string& DTypeConstructor::getName() const { return d_name; }
Node DTypeConstructor::getConstructor() const
{
@@ -107,7 +115,10 @@ TypeNode DTypeConstructor::getSpecializedConstructorType(
TypeNode returnType) const
{
Assert(isResolved());
- Assert(returnType.isDatatype());
+ Assert(returnType.isDatatype())
+ << "DTypeConstructor::getSpecializedConstructorType: expected datatype, "
+ "got "
+ << returnType;
const DType& dt = DType::datatypeOf(d_constructor);
Assert(dt.isParametric());
TypeNode dtt = dt.getTypeNode();
@@ -142,60 +153,39 @@ Cardinality DTypeConstructor::getCardinality(TypeNode t) const
bool DTypeConstructor::isFinite(TypeNode t) const
{
- Assert(isResolved());
-
- TNode self = d_constructor;
- // is this already in the cache ?
- if (self.getAttribute(DTypeFiniteComputedAttr()))
- {
- return self.getAttribute(DTypeFiniteAttr());
- }
- std::vector<TypeNode> instTypes;
- std::vector<TypeNode> paramTypes;
- bool isParam = t.isParametricDatatype();
- if (isParam)
- {
- paramTypes = t.getDType().getParameters();
- instTypes = TypeNode(t).getParamTypes();
- }
- for (size_t i = 0, nargs = getNumArgs(); i < nargs; i++)
- {
- TypeNode tc = getArgType(i);
- if (isParam)
- {
- tc = tc.substitute(paramTypes.begin(),
- paramTypes.end(),
- instTypes.begin(),
- instTypes.end());
- }
- if (!tc.isFinite())
- {
- self.setAttribute(DTypeFiniteComputedAttr(), true);
- self.setAttribute(DTypeFiniteAttr(), false);
- return false;
- }
- }
- self.setAttribute(DTypeFiniteComputedAttr(), true);
- self.setAttribute(DTypeFiniteAttr(), true);
- return true;
+ std::pair<CardinalityType, bool> cinfo = computeCardinalityInfo(t);
+ return cinfo.first == CardinalityType::FINITE;
}
bool DTypeConstructor::isInterpretedFinite(TypeNode t) const
{
- Assert(isResolved());
- TNode self = d_constructor;
- // is this already in the cache ?
- if (self.getAttribute(DTypeUFiniteComputedAttr()))
+ std::pair<CardinalityType, bool> cinfo = computeCardinalityInfo(t);
+ return cinfo.first != CardinalityType::INFINITE;
+}
+
+bool DTypeConstructor::hasFiniteExternalArgType(TypeNode t) const
+{
+ std::pair<CardinalityType, bool> cinfo = computeCardinalityInfo(t);
+ return cinfo.second;
+}
+
+std::pair<DTypeConstructor::CardinalityType, bool>
+DTypeConstructor::computeCardinalityInfo(TypeNode t) const
+{
+ std::map<TypeNode, std::pair<CardinalityType, bool> >::iterator it =
+ d_cardInfo.find(t);
+ if (it != d_cardInfo.end())
{
- return self.getAttribute(DTypeUFiniteAttr());
+ return it->second;
}
+ std::pair<CardinalityType, bool> ret(CardinalityType::FINITE, false);
std::vector<TypeNode> instTypes;
std::vector<TypeNode> paramTypes;
bool isParam = t.isParametricDatatype();
if (isParam)
{
paramTypes = t.getDType().getParameters();
- instTypes = TypeNode(t).getParamTypes();
+ instTypes = t.getParamTypes();
}
for (unsigned i = 0, nargs = getNumArgs(); i < nargs; i++)
{
@@ -207,16 +197,30 @@ bool DTypeConstructor::isInterpretedFinite(TypeNode t) const
instTypes.begin(),
instTypes.end());
}
- if (!tc.isInterpretedFinite())
+ if (tc.isFinite())
{
- self.setAttribute(DTypeUFiniteComputedAttr(), true);
- self.setAttribute(DTypeUFiniteAttr(), false);
- return false;
+ // do nothing
}
+ else if (tc.isInterpretedFinite())
+ {
+ if (ret.first == CardinalityType::FINITE)
+ {
+ // not simply finite, it depends on uninterpreted sorts being finite
+ ret.first = CardinalityType::INTERPRETED_FINITE;
+ }
+ }
+ else
+ {
+ // infinite implies the constructor is infinite cardinality
+ ret.first = CardinalityType::INFINITE;
+ continue;
+ }
+ // if the argument is (interpreted) finite and external, set the flag
+ // for indicating it has a finite external argument
+ ret.second = ret.second || !tc.isDatatype();
}
- self.setAttribute(DTypeUFiniteComputedAttr(), true);
- self.setAttribute(DTypeUFiniteAttr(), true);
- return true;
+ d_cardInfo[t] = ret;
+ return ret;
}
bool DTypeConstructor::isResolved() const { return !d_tester.isNull(); }
@@ -276,6 +280,18 @@ int DTypeConstructor::getSelectorIndexInternal(Node sel) const
return -1;
}
+int DTypeConstructor::getSelectorIndexForName(const std::string& name) const
+{
+ for (size_t i = 0, nargs = getNumArgs(); i < nargs; i++)
+ {
+ if (d_args[i]->getName() == name)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
bool DTypeConstructor::involvesExternalType() const
{
for (size_t i = 0, nargs = getNumArgs(); i < nargs; i++)
@@ -422,7 +438,7 @@ Node DTypeConstructor::computeGroundTerm(TypeNode t,
<< ", ascribe to " << t << std::endl;
groundTerms[0] = nm->mkNode(
APPLY_TYPE_ASCRIPTION,
- nm->mkConst(AscriptionType(getSpecializedConstructorType(t).toType())),
+ nm->mkConst(AscriptionType(getSpecializedConstructorType(t))),
groundTerms[0]);
groundTerm = nm->mkNode(APPLY_CONSTRUCTOR, groundTerms);
}
@@ -557,6 +573,13 @@ bool DTypeConstructor::resolve(
arg->d_selector.setAttribute(DTypeIndexAttr(), index++);
arg->d_resolved = true;
argTypes.push_back(range);
+ // We use \0 as a distinguished marker for unresolved selectors for doing
+ // name resolutions. We now can remove \0 from name if necessary.
+ const size_t nul = arg->d_name.find('\0');
+ if (nul != std::string::npos)
+ {
+ arg->d_name.resize(nul);
+ }
}
Assert(index == getNumArgs());
diff --git a/src/expr/dtype_cons.h b/src/expr/dtype_cons.h
index d89ed6af7..2dba895e9 100644
--- a/src/expr/dtype_cons.h
+++ b/src/expr/dtype_cons.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -26,8 +26,6 @@
namespace CVC4 {
-class DatatypeConstructor;
-
/**
* The Node-level representation of a constructor for a datatype, which
* currently resides in the Expr-level DatatypeConstructor class
@@ -35,7 +33,6 @@ class DatatypeConstructor;
*/
class DTypeConstructor
{
- friend class DatatypeConstructor;
friend class DType;
public:
@@ -63,9 +60,23 @@ class DTypeConstructor
* Add an argument, given a pointer to a selector object.
*/
void addArg(std::shared_ptr<DTypeSelector> a);
+ /**
+ * Add a self-referential (i.e., a data field) of the given name
+ * to this Datatype constructor that refers to the enclosing
+ * Datatype. For example, using the familiar "nat" Datatype, to
+ * create the "pred" field for "succ" constructor, one uses
+ * succ::addArgSelf("pred")---the actual Type
+ * cannot be passed because the Datatype is still under
+ * construction. Selector names need not be unique; they are for
+ * convenience and pretty-printing only.
+ *
+ * This is a special case of
+ * DTypeConstructor::addArg(std::string).
+ */
+ void addArgSelf(std::string selectorName);
/** Get the name of this constructor. */
- std::string getName() const;
+ const std::string& getName() const;
/**
* Get the constructor operator of this constructor. The
@@ -147,6 +158,13 @@ class DTypeConstructor
* only be called for resolved constructors.
*/
bool isInterpretedFinite(TypeNode t) const;
+ /**
+ * Has finite external argument type. This returns true if this constructor
+ * has an argument type that is not a datatype and is interpreted as a
+ * finite type. This function can only be called for resolved constructors.
+ *
+ */
+ bool hasFiniteExternalArgType(TypeNode t) const;
/**
* Returns true iff this constructor has already been
@@ -195,6 +213,12 @@ class DTypeConstructor
* stoa(T,C,index)
*/
int getSelectorIndexInternal(Node sel) const;
+ /** get selector index for name
+ *
+ * Returns the index of selector with the given name, or -1 if it
+ * does not exist.
+ */
+ int getSelectorIndexForName(const std::string& name) const;
/** involves external type
*
@@ -212,6 +236,17 @@ class DTypeConstructor
void toStream(std::ostream& out) const;
private:
+ /** Constructor cardinality type */
+ enum class CardinalityType
+ {
+ // the constructor is finite
+ FINITE,
+ // the constructor is interpreted-finite (finite under the assumption that
+ // uninterpreted sorts are finite)
+ INTERPRETED_FINITE,
+ // the constructor is infinte
+ INFINITE
+ };
/** resolve
*
* This resolves (initializes) the constructor. For details
@@ -269,6 +304,13 @@ class DTypeConstructor
std::vector<TypeNode>& processing,
std::map<TypeNode, Node>& gt,
bool isValue) const;
+ /**
+ * Compute cardinality info, returns a pair where its first component is
+ * an identifier indicating the cardinality type of this constructor for
+ * type t, and a Boolean indicating whether the constructor has any arguments
+ * that have finite external type.
+ */
+ std::pair<CardinalityType, bool> computeCardinalityInfo(TypeNode t) const;
/** compute shared selectors
* This computes the maps d_sharedSelectors and d_sharedSelectorIndex.
*/
@@ -307,6 +349,8 @@ class DTypeConstructor
* its argument index for this constructor.
*/
mutable std::map<TypeNode, std::map<Node, unsigned> > d_sharedSelectorIndex;
+ /** A cache for computeCardinalityInfo. */
+ mutable std::map<TypeNode, std::pair<CardinalityType, bool> > d_cardInfo;
}; /* class DTypeConstructor */
/**
diff --git a/src/expr/dtype_selector.cpp b/src/expr/dtype_selector.cpp
index 302e6c51f..d6b907cc1 100644
--- a/src/expr/dtype_selector.cpp
+++ b/src/expr/dtype_selector.cpp
@@ -2,10 +2,10 @@
/*! \file dtype_selector.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds
+ ** Andrew Reynolds, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -26,7 +26,7 @@ DTypeSelector::DTypeSelector(std::string name, Node selector)
Assert(name != "");
}
-std::string DTypeSelector::getName() const { return d_name; }
+const std::string& DTypeSelector::getName() const { return d_name; }
Node DTypeSelector::getSelector() const
{
@@ -55,7 +55,11 @@ void DTypeSelector::toStream(std::ostream& out) const
TypeNode t;
if (d_resolved)
{
- t = getRangeType();
+ // don't try to print the range type of null, instead we print null itself.
+ if (!getType().isNull())
+ {
+ t = getRangeType();
+ }
}
else if (d_selector.isNull())
{
diff --git a/src/expr/dtype_selector.h b/src/expr/dtype_selector.h
index bd0271d90..4ba88c8aa 100644
--- a/src/expr/dtype_selector.h
+++ b/src/expr/dtype_selector.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -41,7 +41,7 @@ class DTypeSelector
DTypeSelector(std::string name, Node selector);
/** Get the name of this constructor argument. */
- std::string getName() const;
+ const std::string& getName() const;
/**
* Get the selector for this constructor argument; this call is
diff --git a/src/expr/emptybag.cpp b/src/expr/emptybag.cpp
new file mode 100644
index 000000000..888b3b92a
--- /dev/null
+++ b/src/expr/emptybag.cpp
@@ -0,0 +1,65 @@
+/********************* */
+/*! \file emptybag.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **/
+
+#include "expr/emptybag.h"
+
+#include <iostream>
+
+#include "expr/type_node.h"
+
+namespace CVC4 {
+
+std::ostream& operator<<(std::ostream& out, const EmptyBag& asa)
+{
+ return out << "emptybag(" << asa.getType() << ')';
+}
+
+size_t EmptyBagHashFunction::operator()(const EmptyBag& es) const
+{
+ return TypeNodeHashFunction()(es.getType());
+}
+
+/**
+ * Constructs an emptybag of the specified type. Note that the argument
+ * is the type of the bag itself, NOT the type of the elements.
+ */
+EmptyBag::EmptyBag(const TypeNode& bagType) : d_type(new TypeNode(bagType)) {}
+
+EmptyBag::EmptyBag(const EmptyBag& es) : d_type(new TypeNode(es.getType())) {}
+
+EmptyBag& EmptyBag::operator=(const EmptyBag& es)
+{
+ (*d_type) = es.getType();
+ return *this;
+}
+
+EmptyBag::~EmptyBag() {}
+const TypeNode& EmptyBag::getType() const { return *d_type; }
+bool EmptyBag::operator==(const EmptyBag& es) const
+{
+ return getType() == es.getType();
+}
+
+bool EmptyBag::operator!=(const EmptyBag& es) const { return !(*this == es); }
+bool EmptyBag::operator<(const EmptyBag& es) const
+{
+ return getType() < es.getType();
+}
+
+bool EmptyBag::operator<=(const EmptyBag& es) const
+{
+ return getType() <= es.getType();
+}
+
+bool EmptyBag::operator>(const EmptyBag& es) const { return !(*this <= es); }
+bool EmptyBag::operator>=(const EmptyBag& es) const { return !(*this < es); }
+} // namespace CVC4
diff --git a/src/expr/emptybag.h b/src/expr/emptybag.h
new file mode 100644
index 000000000..a16c12d86
--- /dev/null
+++ b/src/expr/emptybag.h
@@ -0,0 +1,63 @@
+/********************* */
+/*! \file emptybag.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief a class for empty bags
+ **/
+
+#include "cvc4_public.h"
+
+#ifndef CVC4__EMPTY_BAG_H
+#define CVC4__EMPTY_BAG_H
+
+#include <iosfwd>
+#include <memory>
+
+namespace CVC4 {
+
+class TypeNode;
+
+class CVC4_PUBLIC EmptyBag
+{
+ public:
+ /**
+ * Constructs an emptybag of the specified type. Note that the argument
+ * is the type of the bag itself, NOT the type of the elements.
+ */
+ EmptyBag(const TypeNode& bagType);
+ ~EmptyBag();
+ EmptyBag(const EmptyBag& other);
+ EmptyBag& operator=(const EmptyBag& other);
+
+ const TypeNode& getType() const;
+ bool operator==(const EmptyBag& es) const;
+ bool operator!=(const EmptyBag& es) const;
+ bool operator<(const EmptyBag& es) const;
+ bool operator<=(const EmptyBag& es) const;
+ bool operator>(const EmptyBag& es) const;
+ bool operator>=(const EmptyBag& es) const;
+
+ private:
+ EmptyBag();
+
+ /** the type of the empty bag itself (not the type of the elements)*/
+ std::unique_ptr<TypeNode> d_type;
+}; /* class EmptyBag */
+
+std::ostream& operator<<(std::ostream& out, const EmptyBag& es) CVC4_PUBLIC;
+
+struct CVC4_PUBLIC EmptyBagHashFunction
+{
+ size_t operator()(const EmptyBag& es) const;
+}; /* struct EmptyBagHashFunction */
+
+} // namespace CVC4
+
+#endif /* CVC4__EMPTY_BAG_H */
diff --git a/src/expr/emptyset.cpp b/src/expr/emptyset.cpp
index 6260e4373..059670f6a 100644
--- a/src/expr/emptyset.cpp
+++ b/src/expr/emptyset.cpp
@@ -2,10 +2,10 @@
/*! \file emptyset.cpp
** \verbatim
** Top contributors (to current version):
- ** Tim King, Kshitij Bansal
+ ** Tim King, Kshitij Bansal, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/emptyset.h b/src/expr/emptyset.h
index 1b5bc6897..511b21c66 100644
--- a/src/expr/emptyset.h
+++ b/src/expr/emptyset.h
@@ -2,10 +2,10 @@
/*! \file emptyset.h
** \verbatim
** Top contributors (to current version):
- ** Tim King, Kshitij Bansal, Morgan Deters
+ ** Tim King, Andres Noetzli, Kshitij Bansal
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/expr_iomanip.cpp b/src/expr/expr_iomanip.cpp
index 1ea1ca6aa..0ff29663c 100644
--- a/src/expr/expr_iomanip.cpp
+++ b/src/expr/expr_iomanip.cpp
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Kshitij Bansal
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -26,11 +26,8 @@ namespace CVC4 {
namespace expr {
const int ExprSetDepth::s_iosIndex = std::ios_base::xalloc();
-const int ExprPrintTypes::s_iosIndex = std::ios_base::xalloc();
const int ExprDag::s_iosIndex = std::ios_base::xalloc();
-
-
ExprSetDepth::ExprSetDepth(long depth) : d_depth(depth) {}
void ExprSetDepth::applyDepth(std::ostream& out) {
@@ -71,31 +68,6 @@ ExprSetDepth::Scope::~Scope() {
ExprSetDepth::setDepth(d_out, d_oldDepth);
}
-
-ExprPrintTypes::ExprPrintTypes(bool printTypes) : d_printTypes(printTypes) {}
-
-void ExprPrintTypes::applyPrintTypes(std::ostream& out) {
- out.iword(s_iosIndex) = d_printTypes;
-}
-
-bool ExprPrintTypes::getPrintTypes(std::ostream& out) {
- return out.iword(s_iosIndex);
-}
-
-void ExprPrintTypes::setPrintTypes(std::ostream& out, bool printTypes) {
- out.iword(s_iosIndex) = printTypes;
-}
-
-ExprPrintTypes::Scope::Scope(std::ostream& out, bool printTypes)
- : d_out(out),
- d_oldPrintTypes(ExprPrintTypes::getPrintTypes(out)) {
- ExprPrintTypes::setPrintTypes(out, printTypes);
-}
-
-ExprPrintTypes::Scope::~Scope() {
- ExprPrintTypes::setPrintTypes(d_out, d_oldPrintTypes);
-}
-
ExprDag::ExprDag(bool dag) : d_dag(dag ? 1 : 0) {}
ExprDag::ExprDag(int dag) : d_dag(dag < 0 ? 0 : dag) {}
@@ -145,11 +117,6 @@ std::ostream& operator<<(std::ostream& out, ExprDag d) {
return out;
}
-std::ostream& operator<<(std::ostream& out, ExprPrintTypes pt) {
- pt.applyPrintTypes(out);
- return out;
-}
-
std::ostream& operator<<(std::ostream& out, ExprSetDepth sd) {
sd.applyDepth(out);
return out;
diff --git a/src/expr/expr_iomanip.h b/src/expr/expr_iomanip.h
index f8464392a..e90366a81 100644
--- a/src/expr/expr_iomanip.h
+++ b/src/expr/expr_iomanip.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -92,56 +92,6 @@ public:
};/* class ExprSetDepth */
/**
- * IOStream manipulator to print type ascriptions or not.
- *
- * // let a, b, c, and d be variables of sort U
- * Expr e = em->mkExpr(OR, a, b, em->mkExpr(AND, c, em->mkExpr(NOT, d)))
- * out << e;
- *
- * gives "(OR a:U b:U (AND c:U (NOT d:U)))", but
- */
-class CVC4_PUBLIC ExprPrintTypes {
-public:
- /**
- * Construct a ExprPrintTypes with the given setting.
- */
- ExprPrintTypes(bool printTypes);
-
- void applyPrintTypes(std::ostream& out);
-
- static bool getPrintTypes(std::ostream& out);
-
- static void setPrintTypes(std::ostream& out, bool printTypes);
-
- /**
- * Set the print-types state on the output stream for the current
- * stack scope. This makes sure the old state is reset on the
- * stream after normal OR exceptional exit from the scope, using the
- * RAII C++ idiom.
- */
- class Scope {
- public:
- Scope(std::ostream& out, bool printTypes);
- ~Scope();
-
- private:
- std::ostream& d_out;
- bool d_oldPrintTypes;
- };/* class ExprPrintTypes::Scope */
-
- private:
- /**
- * The allocated index in ios_base for our setting.
- */
- static const int s_iosIndex;
-
- /**
- * When this manipulator is used, the setting is stored here.
- */
- bool d_printTypes;
-};/* class ExprPrintTypes */
-
-/**
* IOStream manipulator to print expressions as a dag (or not).
*/
class CVC4_PUBLIC ExprDag {
@@ -209,18 +159,6 @@ public:
*/
std::ostream& operator<<(std::ostream& out, ExprDag d) CVC4_PUBLIC;
-
-/**
- * Sets the default print-types setting when pretty-printing an Expr
- * to an ostream. Use like this:
- *
- * // let out be an ostream, e an Expr
- * out << Expr::printtypes(true) << e << endl;
- *
- * The setting stays permanently (until set again) with the stream.
- */
-std::ostream& operator<<(std::ostream& out, ExprPrintTypes pt) CVC4_PUBLIC;
-
/**
* Sets the default depth when pretty-printing a Expr to an ostream.
* Use like this:
diff --git a/src/expr/expr_manager_scope.h b/src/expr/expr_manager_scope.h
index 12d47c89b..8749bb8d6 100644
--- a/src/expr/expr_manager_scope.h
+++ b/src/expr/expr_manager_scope.h
@@ -5,7 +5,7 @@
** Morgan Deters, Christopher L. Conway, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/expr_manager_template.cpp b/src/expr/expr_manager_template.cpp
index 445ca9ee7..37f0e2527 100644
--- a/src/expr/expr_manager_template.cpp
+++ b/src/expr/expr_manager_template.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Christopher L. Conway, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -26,12 +26,6 @@
${includes}
-// This is a hack, but an important one: if there's an error, the
-// compiler directs the user to the template file instead of the
-// generated one. We don't want the user to modify the generated one,
-// since it'll get overwritten on a later build.
-#line 34 "${template}"
-
#ifdef CVC4_STATISTICS_ON
#define INC_STAT(kind) \
{ \
@@ -114,8 +108,6 @@ ExprManager::~ExprManager()
}
}
#endif
- // clear the datatypes
- d_ownedDatatypes.clear();
delete d_nodeManager;
d_nodeManager = NULL;
@@ -597,20 +589,6 @@ FunctionType ExprManager::mkPredicateType(const std::vector<Type>& sorts) {
return FunctionType(Type(d_nodeManager, new TypeNode(d_nodeManager->mkPredicateType(sortNodes))));
}
-DatatypeType ExprManager::mkTupleType(const std::vector<Type>& types) {
- NodeManagerScope nms(d_nodeManager);
- std::vector<TypeNode> typeNodes;
- for (unsigned i = 0, i_end = types.size(); i < i_end; ++ i) {
- typeNodes.push_back(*types[i].d_typeNode);
- }
- return DatatypeType(Type(d_nodeManager, new TypeNode(d_nodeManager->mkTupleType(typeNodes))));
-}
-
-DatatypeType ExprManager::mkRecordType(const Record& rec) {
- NodeManagerScope nms(d_nodeManager);
- return DatatypeType(Type(d_nodeManager, new TypeNode(d_nodeManager->mkRecordType(rec))));
-}
-
SExprType ExprManager::mkSExprType(const std::vector<Type>& types) {
NodeManagerScope nms(d_nodeManager);
std::vector<TypeNode> typeNodes;
@@ -648,198 +626,6 @@ SequenceType ExprManager::mkSequenceType(Type elementType) const
new TypeNode(d_nodeManager->mkSequenceType(*elementType.d_typeNode))));
}
-DatatypeType ExprManager::mkDatatypeType(Datatype& datatype, uint32_t flags)
-{
- // Not worth a special implementation; this doesn't need to be fast
- // code anyway.
- vector<Datatype> datatypes;
- datatypes.push_back(datatype);
- std::vector<DatatypeType> result = mkMutualDatatypeTypes(datatypes, flags);
- Assert(result.size() == 1);
- return result.front();
-}
-
-std::vector<DatatypeType> ExprManager::mkMutualDatatypeTypes(
- std::vector<Datatype>& datatypes, uint32_t flags)
-{
- std::set<Type> unresolvedTypes;
- return mkMutualDatatypeTypes(datatypes, unresolvedTypes, flags);
-}
-
-std::vector<DatatypeType> ExprManager::mkMutualDatatypeTypes(
- std::vector<Datatype>& datatypes,
- std::set<Type>& unresolvedTypes,
- uint32_t flags)
-{
- NodeManagerScope nms(d_nodeManager);
- std::map<std::string, DatatypeType> nameResolutions;
- std::vector<DatatypeType> dtts;
-
- // have to build deep copy so that datatypes will live in this class
- std::vector< Datatype* > dt_copies;
- for(std::vector<Datatype>::iterator i = datatypes.begin(), i_end = datatypes.end(); i != i_end; ++i) {
- d_ownedDatatypes.push_back(std::unique_ptr<Datatype>(new Datatype(*i)));
- dt_copies.push_back(d_ownedDatatypes.back().get());
- }
-
- // First do some sanity checks, set up the final Type to be used for
- // each datatype, and set up the "named resolutions" used to handle
- // simple self- and mutual-recursion, for example in the definition
- // "nat = succ(pred:nat) | zero", a named resolution can handle the
- // pred selector.
- for(std::vector<Datatype*>::iterator i = dt_copies.begin(), i_end = dt_copies.end(); i != i_end; ++i) {
- TypeNode* typeNode;
- // register datatype with the node manager
- unsigned index = d_nodeManager->registerDatatype((*i)->d_internal);
- if( (*i)->getNumParameters() == 0 ) {
- typeNode = new TypeNode(d_nodeManager->mkTypeConst(DatatypeIndexConstant(index)));
- //typeNode = new TypeNode(d_nodeManager->mkTypeConst(*i));
- } else {
- TypeNode cons = d_nodeManager->mkTypeConst(DatatypeIndexConstant(index));
- //TypeNode cons = d_nodeManager->mkTypeConst(*i);
- std::vector< TypeNode > params;
- params.push_back( cons );
- for( unsigned int ip = 0; ip < (*i)->getNumParameters(); ++ip ) {
- params.push_back( TypeNode::fromType( (*i)->getParameter( ip ) ) );
- }
-
- typeNode = new TypeNode(d_nodeManager->mkTypeNode(kind::PARAMETRIC_DATATYPE, params));
- }
- Type type(d_nodeManager, typeNode);
- DatatypeType dtt(type);
- PrettyCheckArgument(
- nameResolutions.find((*i)->getName()) == nameResolutions.end(),
- dt_copies,
- "cannot construct two datatypes at the same time "
- "with the same name `%s'",
- (*i)->getName().c_str());
- nameResolutions.insert(std::make_pair((*i)->getName(), dtt));
- dtts.push_back(dtt);
- }
-
- // Second, set up the type substitution map for complex type
- // resolution (e.g. if "list" is the type we're defining, and it has
- // a selector of type "ARRAY INT OF list", this can't be taken care
- // of using the named resolutions that we set up above. A
- // preliminary array type was set up, and now needs to have "list"
- // substituted in it for the correct type.
- //
- // @TODO get rid of named resolutions altogether and handle
- // everything with these resolutions?
- std::vector< SortConstructorType > paramTypes;
- std::vector< DatatypeType > paramReplacements;
- std::vector<Type> placeholders;// to hold the "unresolved placeholders"
- std::vector<Type> replacements;// to hold our final, resolved types
- for(std::set<Type>::iterator i = unresolvedTypes.begin(), i_end = unresolvedTypes.end(); i != i_end; ++i) {
- std::string name;
- if( (*i).isSort() ) {
- name = SortType(*i).getName();
- } else {
- Assert((*i).isSortConstructor());
- name = SortConstructorType(*i).getName();
- }
- std::map<std::string, DatatypeType>::const_iterator resolver =
- nameResolutions.find(name);
- PrettyCheckArgument(
- resolver != nameResolutions.end(),
- unresolvedTypes,
- "cannot resolve type `%s'; it's not among "
- "the datatypes being defined", name.c_str());
- // We will instruct the Datatype to substitute "*i" (the
- // unresolved SortType used as a placeholder in complex types)
- // with "(*resolver).second" (the DatatypeType we created in the
- // first step, above).
- if( (*i).isSort() ) {
- placeholders.push_back(*i);
- replacements.push_back( (*resolver).second );
- } else {
- Assert((*i).isSortConstructor());
- paramTypes.push_back( SortConstructorType(*i) );
- paramReplacements.push_back( (*resolver).second );
- }
- }
-
- // Lastly, perform the final resolutions and checks.
- for(std::vector<DatatypeType>::iterator i = dtts.begin(),
- i_end = dtts.end();
- i != i_end;
- ++i) {
- const Datatype& dt = (*i).getDatatype();
- if(!dt.isResolved()) {
- const_cast<Datatype&>(dt).resolve(nameResolutions,
- placeholders,
- replacements,
- paramTypes,
- paramReplacements);
- }
-
- // Now run some checks, including a check to make sure that no
- // selector is function-valued.
- checkResolvedDatatype(*i);
- }
-
- for(std::vector<NodeManagerListener*>::iterator i = d_nodeManager->d_listeners.begin(); i != d_nodeManager->d_listeners.end(); ++i) {
- (*i)->nmNotifyNewDatatypes(dtts, flags);
- }
-
- return dtts;
-}
-
-void ExprManager::checkResolvedDatatype(DatatypeType dtt) const {
- const Datatype& dt = dtt.getDatatype();
-
- AssertArgument(dt.isResolved(), dtt, "datatype should have been resolved");
-
- // for all constructors...
- for(Datatype::const_iterator i = dt.begin(), i_end = dt.end();
- i != i_end;
- ++i) {
- const DatatypeConstructor& c = *i;
- Type testerType CVC4_UNUSED = c.getTester().getType();
- Assert(c.isResolved() && testerType.isTester()
- && TesterType(testerType).getDomain() == dtt
- && TesterType(testerType).getRangeType() == booleanType())
- << "malformed tester in datatype post-resolution";
- Type ctorType CVC4_UNUSED = c.getConstructor().getType();
- Assert(ctorType.isConstructor()
- && ConstructorType(ctorType).getArity() == c.getNumArgs()
- && ConstructorType(ctorType).getRangeType() == dtt)
- << "malformed constructor in datatype post-resolution";
- // for all selectors...
- for(DatatypeConstructor::const_iterator j = c.begin(), j_end = c.end();
- j != j_end;
- ++j) {
- const DatatypeConstructorArg& a = *j;
- Type selectorType = a.getType();
- Assert(a.isResolved() && selectorType.isSelector()
- && SelectorType(selectorType).getDomain() == dtt)
- << "malformed selector in datatype post-resolution";
- // This next one's a "hard" check, performed in non-debug builds
- // as well; the other ones should all be guaranteed by the
- // CVC4::Datatype class, but this actually needs to be checked.
- AlwaysAssert(!SelectorType(selectorType)
- .getRangeType()
- .d_typeNode->isFunctionLike())
- << "cannot put function-like things in datatypes";
- }
- }
-}
-
-ConstructorType ExprManager::mkConstructorType(const DatatypeConstructor& constructor, Type range) const {
- NodeManagerScope nms(d_nodeManager);
- return Type(d_nodeManager, new TypeNode(d_nodeManager->mkConstructorType(constructor, *range.d_typeNode)));
-}
-
-SelectorType ExprManager::mkSelectorType(Type domain, Type range) const {
- NodeManagerScope nms(d_nodeManager);
- return Type(d_nodeManager, new TypeNode(d_nodeManager->mkSelectorType(*domain.d_typeNode, *range.d_typeNode)));
-}
-
-TesterType ExprManager::mkTesterType(Type domain) const {
- NodeManagerScope nms(d_nodeManager);
- return Type(d_nodeManager, new TypeNode(d_nodeManager->mkTesterType(*domain.d_typeNode)));
-}
-
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, flags))));
@@ -1113,13 +899,6 @@ Type ExprManager::exportType(const Type& t, ExprManager* em, ExprManagerMapColle
new TypeNode(expr::exportTypeInternal(*t.d_typeNode, t.d_nodeManager, em->d_nodeManager, vmap)));
}
-const Datatype& ExprManager::getDatatypeForIndex(unsigned index) const
-{
- // when the Node-level API is in place, this function will be deleted.
- Assert(index < d_ownedDatatypes.size());
- return *d_ownedDatatypes[index];
-}
-
${mkConst_implementations}
}/* CVC4 namespace */
diff --git a/src/expr/expr_manager_template.h b/src/expr/expr_manager_template.h
index 3f180e951..1458101ca 100644
--- a/src/expr/expr_manager_template.h
+++ b/src/expr/expr_manager_template.h
@@ -2,10 +2,10 @@
/*! \file expr_manager_template.h
** \verbatim
** Top contributors (to current version):
- ** Morgan Deters, Andrew Reynolds, Dejan Jovanovic
+ ** Morgan Deters, Dejan Jovanovic, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -28,12 +28,6 @@
${includes}
-// This is a hack, but an important one: if there's an error, the
-// compiler directs the user to the template file instead of the
-// generated one. We don't want the user to modify the generated one,
-// since it'll get overwritten on a later build.
-#line 36 "${template}"
-
namespace CVC4 {
namespace api {
@@ -65,11 +59,6 @@ class CVC4_PUBLIC ExprManager {
NodeManager* getNodeManager() const;
/**
- * Check some things about a newly-created DatatypeType.
- */
- void checkResolvedDatatype(DatatypeType dtt) const;
-
- /**
* SmtEngine will use all the internals, so it will grab the
* NodeManager.
*/
@@ -84,10 +73,6 @@ class CVC4_PUBLIC ExprManager {
// undefined, private copy constructor and assignment op (disallow copy)
ExprManager(const ExprManager&) = delete;
ExprManager& operator=(const ExprManager&) = delete;
-
- /** A list of datatypes owned by this expr manager. */
- std::vector<std::unique_ptr<Datatype> > d_ownedDatatypes;
-
/** Creates an expression manager. */
ExprManager();
public:
@@ -346,18 +331,6 @@ class CVC4_PUBLIC ExprManager {
FunctionType mkPredicateType(const std::vector<Type>& sorts);
/**
- * Make a tuple type with types from
- * <code>types[0..types.size()-1]</code>. <code>types</code> must
- * have at least one element.
- */
- DatatypeType mkTupleType(const std::vector<Type>& types);
-
- /**
- * Make a record type with types from the rec parameter.
- */
- DatatypeType mkRecordType(const Record& rec);
-
- /**
* Make a symbolic expressiontype with types from
* <code>types[0..types.size()-1]</code>. <code>types</code> may
* have any number of elements.
@@ -379,73 +352,6 @@ class CVC4_PUBLIC ExprManager {
/** Make the type of sequence with the given parameterization. */
SequenceType mkSequenceType(Type elementType) const;
- /** Bits for use in mkDatatypeType() flags.
- *
- * DATATYPE_FLAG_PLACEHOLDER indicates that the type should not be printed
- * out as a definition, for example, in models or during dumping.
- */
- enum
- {
- DATATYPE_FLAG_NONE = 0,
- DATATYPE_FLAG_PLACEHOLDER = 1
- }; /* enum */
-
- /** Make a type representing the given datatype. */
- DatatypeType mkDatatypeType(Datatype& datatype,
- uint32_t flags = DATATYPE_FLAG_NONE);
-
- /**
- * Make a set of types representing the given datatypes, which may be
- * mutually recursive.
- */
- std::vector<DatatypeType> mkMutualDatatypeTypes(
- std::vector<Datatype>& datatypes, uint32_t flags = DATATYPE_FLAG_NONE);
-
- /**
- * Make a set of types representing the given datatypes, which may
- * be mutually recursive. unresolvedTypes is a set of SortTypes
- * that were used as placeholders in the Datatypes for the Datatypes
- * of the same name. This is just a more complicated version of the
- * above mkMutualDatatypeTypes() function, but is required to handle
- * complex types.
- *
- * For example, unresolvedTypes might contain the single sort "list"
- * (with that name reported from SortType::getName()). The
- * datatypes list might have the single datatype
- *
- * DATATYPE
- * list = cons(car:ARRAY INT OF list, cdr:list) | nil;
- * END;
- *
- * To represent the Type of the array, the user had to create a
- * placeholder type (an uninterpreted sort) to stand for "list" in
- * the type of "car". It is this placeholder sort that should be
- * passed in unresolvedTypes. If the datatype was of the simpler
- * form:
- *
- * DATATYPE
- * list = cons(car:list, cdr:list) | nil;
- * END;
- *
- * then no complicated Type needs to be created, and the above,
- * simpler form of mkMutualDatatypeTypes() is enough.
- */
- std::vector<DatatypeType> mkMutualDatatypeTypes(
- std::vector<Datatype>& datatypes,
- std::set<Type>& unresolvedTypes,
- uint32_t flags = DATATYPE_FLAG_NONE);
-
- /**
- * Make a type representing a constructor with the given parameterization.
- */
- ConstructorType mkConstructorType(const DatatypeConstructor& constructor, Type range) const;
-
- /** Make a type representing a selector with the given parameterization. */
- SelectorType mkSelectorType(Type domain, Type range) const;
-
- /** 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,
@@ -578,13 +484,6 @@ class CVC4_PUBLIC ExprManager {
* maximal arity as the maximal possible number of children of a node.
**/
static bool isNAryKind(Kind fun);
-
- /**
- * Return the datatype at the given index owned by this class. Type nodes are
- * associated with datatypes through the DatatypeIndexConstant class. The
- * argument index is intended to be a value taken from that class.
- */
- const Datatype& getDatatypeForIndex(unsigned index) const;
};/* class ExprManager */
${mkConst_instantiations}
diff --git a/src/expr/expr_template.cpp b/src/expr/expr_template.cpp
index 226736e8f..f9a743cf6 100644
--- a/src/expr/expr_template.cpp
+++ b/src/expr/expr_template.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -29,12 +29,6 @@
${includes}
-// This is a hack, but an important one: if there's an error, the
-// compiler directs the user to the template file instead of the
-// generated one. We don't want the user to modify the generated one,
-// since it'll get overwritten on a later build.
-#line 37 "${template}"
-
using namespace CVC4::kind;
using namespace std;
@@ -599,10 +593,13 @@ bool Expr::hasFreeVariable() const
return expr::hasFreeVar(*d_node);
}
-void Expr::toStream(std::ostream& out, int depth, bool types, size_t dag,
- OutputLanguage language) const {
+void Expr::toStream(std::ostream& out,
+ int depth,
+ size_t dag,
+ OutputLanguage language) const
+{
ExprManagerScope ems(*this);
- d_node->toStream(out, depth, types, dag, language);
+ d_node->toStream(out, depth, dag, language);
}
Node Expr::getNode() const { return *d_node; }
diff --git a/src/expr/expr_template.h b/src/expr/expr_template.h
index 34374d354..e62dee7f6 100644
--- a/src/expr/expr_template.h
+++ b/src/expr/expr_template.h
@@ -5,7 +5,7 @@
** Morgan Deters, Dejan Jovanovic, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -26,7 +26,6 @@ ${includes}
#ifndef CVC4__EXPR_H
#define CVC4__EXPR_H
-#include <stdint.h>
#include <iosfwd>
#include <iterator>
#include <string>
@@ -39,12 +38,6 @@ ${includes}
#include "options/language.h"
#include "util/hash.h"
-// This is a hack, but an important one: if there's an error, the
-// compiler directs the user to the template file instead of the
-// generated one. We don't want the user to modify the generated one,
-// since it'll get overwritten on a later build.
-#line 47 "${template}"
-
namespace CVC4 {
// The internal expression representation
@@ -519,13 +512,12 @@ public:
* @param out the stream to serialize this expression to
* @param toDepth the depth to which to print this expression, or -1
* to print it fully
- * @param types set to true to ascribe types to the output
- * expressions (might break language compliance, but good for
- * debugging expressions)
* @param dag the dagification threshold to use (0 == off)
* @param language the language in which to output
*/
- void toStream(std::ostream& out, int toDepth = -1, bool types = false, size_t dag = 1,
+ void toStream(std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
OutputLanguage language = language::output::LANG_AUTO) const;
/**
@@ -621,8 +613,6 @@ private:
${getConst_instantiations}
-#line 625 "${template}"
-
inline size_t ExprHashFunction::operator()(CVC4::Expr e) const {
return (size_t) e.getId();
}
diff --git a/src/expr/kind_map.h b/src/expr/kind_map.h
index 10f475911..996a32268 100644
--- a/src/expr/kind_map.h
+++ b/src/expr/kind_map.h
@@ -5,7 +5,7 @@
** Dejan Jovanovic, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,7 +20,6 @@
#ifndef CVC4__KIND_MAP_H
#define CVC4__KIND_MAP_H
-#include <stdint.h>
#include <iterator>
#include "base/check.h"
diff --git a/src/expr/kind_template.cpp b/src/expr/kind_template.cpp
index 0d7f5f4e4..0bda68b7b 100644
--- a/src/expr/kind_template.cpp
+++ b/src/expr/kind_template.cpp
@@ -5,7 +5,7 @@
** Andres Noetzli, Christopher L. Conway, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -69,7 +69,6 @@ std::string kindToString(::CVC4::Kind k) {
std::ostream& operator<<(std::ostream& out, TypeConstant typeConstant) {
switch(typeConstant) {
${type_constant_descriptions}
-#line 73 "${template}"
default:
out << "UNKNOWN_TYPE_CONSTANT";
break;
@@ -85,7 +84,6 @@ TheoryId kindToTheoryId(::CVC4::Kind k) {
case kind::NULL_EXPR:
break;
${kind_to_theory_id}
-#line 89 "${template}"
case kind::LAST_KIND:
break;
}
@@ -97,7 +95,6 @@ TheoryId typeConstantToTheoryId(::CVC4::TypeConstant typeConstant)
switch (typeConstant)
{
${type_constant_to_theory_id}
-#line 101 "${template}"
case LAST_TYPE: break;
}
throw IllegalArgumentException(
diff --git a/src/expr/kind_template.h b/src/expr/kind_template.h
index d34179252..359e7234a 100644
--- a/src/expr/kind_template.h
+++ b/src/expr/kind_template.h
@@ -5,7 +5,7 @@
** Andres Noetzli, Morgan Deters, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -63,8 +63,6 @@ const char* toString(CVC4::Kind k);
*/
std::ostream& operator<<(std::ostream&, CVC4::Kind) CVC4_PUBLIC;
-#line 67 "${template}"
-
/** Returns true if the given kind is associative. This is used by ExprManager to
* decide whether it's safe to modify big expressions by changing the grouping of
* the arguments. */
@@ -86,7 +84,6 @@ struct KindHashFunction {
enum CVC4_PUBLIC TypeConstant
{
${type_constant_list}
-#line 90 "${template}"
LAST_TYPE
}; /* enum TypeConstant */
diff --git a/src/expr/lazy_proof.cpp b/src/expr/lazy_proof.cpp
index 3980a3cb3..267da2607 100644
--- a/src/expr/lazy_proof.cpp
+++ b/src/expr/lazy_proof.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,8 +20,9 @@ namespace CVC4 {
LazyCDProof::LazyCDProof(ProofNodeManager* pnm,
ProofGenerator* dpg,
- context::Context* c)
- : CDProof(pnm, c), d_gens(c ? c : &d_context), d_defaultGen(dpg)
+ context::Context* c,
+ std::string name)
+ : CDProof(pnm, c, name), d_gens(c ? c : &d_context), d_defaultGen(dpg)
{
}
@@ -56,36 +57,58 @@ std::shared_ptr<ProofNode> LazyCDProof::getProofFor(Node fact)
if (it == visited.end())
{
visited.insert(cur);
- if (cur->getRule() == PfRule::ASSUME)
+ Node cfact = cur->getResult();
+ if (getProof(cfact).get() != cur)
+ {
+ // We don't own this proof, skip it. This is to ensure that this method
+ // is idempotent, since it may be the case that a previous call to
+ // getProofFor connected a proof from a proof generator as a child of
+ // a ProofNode in the range of the map in CDProof. Thus, this ensures
+ // we don't touch such proofs.
+ Trace("lazy-cdproof") << "...skip unowned proof" << std::endl;
+ }
+ else if (cur->getRule() == PfRule::ASSUME)
{
- Node afact = cur->getResult();
bool isSym = false;
- ProofGenerator* pg = getGeneratorFor(afact, isSym);
+ ProofGenerator* pg = getGeneratorFor(cfact, isSym);
if (pg != nullptr)
{
- Trace("lazy-cdproof") << "LazyCDProof: Call generator for assumption "
- << afact << std::endl;
- Node afactGen = isSym ? CDProof::getSymmFact(afact) : afact;
- Assert(!afactGen.isNull());
- // use the addProofTo interface
- if (!pg->addProofTo(afactGen, this))
- {
- Trace("lazy-cdproof") << "LazyCDProof: Failed added fact for "
- << afactGen << std::endl;
- Assert(false) << "Proof generator " << pg->identify()
- << " could not add proof for fact " << afactGen
- << std::endl;
- }
- else
+ Trace("lazy-cdproof")
+ << "LazyCDProof: Call generator " << pg->identify()
+ << " for assumption " << cfact << std::endl;
+ Node cfactGen = isSym ? CDProof::getSymmFact(cfact) : cfact;
+ Assert(!cfactGen.isNull());
+ // Do not use the addProofTo interface, instead use the update node
+ // interface, since this ensures that we don't take ownership for
+ // the current proof. Instead, it is only linked, and ignored on
+ // future calls to getProofFor due to the check above.
+ std::shared_ptr<ProofNode> pgc = pg->getProofFor(cfactGen);
+ // If the proof was null, then the update is not performed. This is
+ // not considered an error, since this behavior is equivalent to
+ // if pg had provided the proof (ASSUME cfactGen). Ensuring the
+ // proper behavior wrt closed proofs should be done outside this
+ // method.
+ if (pgc != nullptr)
{
+ Trace("lazy-cdproof-gen")
+ << "LazyCDProof: stored proof: " << *pgc.get() << std::endl;
+
+ if (isSym)
+ {
+ d_manager->updateNode(cur, PfRule::SYMM, {pgc}, {});
+ }
+ else
+ {
+ d_manager->updateNode(cur, pgc.get());
+ }
Trace("lazy-cdproof") << "LazyCDProof: Successfully added fact for "
- << afactGen << std::endl;
+ << cfactGen << std::endl;
}
}
else
{
- Trace("lazy-cdproof")
- << "LazyCDProof: No generator for " << afact << std::endl;
+ Trace("lazy-cdproof") << "LazyCDProof: " << identify()
+ << " : No generator for " << cfact << std::endl;
}
// Notice that we do not traverse the proofs that have been generated
// lazily by the proof generators here. In other words, we assume that
@@ -104,14 +127,33 @@ std::shared_ptr<ProofNode> LazyCDProof::getProofFor(Node fact)
} while (!visit.empty());
// we have now updated the ASSUME leafs of opf, return it
Trace("lazy-cdproof") << "...finished" << std::endl;
+ Assert(opf->getResult() == fact);
return opf;
}
void LazyCDProof::addLazyStep(Node expected,
ProofGenerator* pg,
+ PfRule idNull,
+ bool isClosed,
+ const char* ctx,
bool forceOverwrite)
{
- Assert(pg != nullptr);
+ if (pg == nullptr)
+ {
+ // null generator, should have given a proof rule
+ if (idNull == PfRule::ASSUME)
+ {
+ Unreachable() << "LazyCDProof::addLazyStep: " << identify()
+ << ": failed to provide proof generator for " << expected;
+ return;
+ }
+ Trace("lazy-cdproof") << "LazyCDProof::addLazyStep: " << expected
+ << " set (trusted) step " << idNull << "\n";
+ addStep(expected, idNull, {}, {expected});
+ return;
+ }
+ Trace("lazy-cdproof") << "LazyCDProof::addLazyStep: " << expected
+ << " set to generator " << pg->identify() << "\n";
if (!forceOverwrite)
{
NodeProofGeneratorMap::const_iterator it = d_gens.find(expected);
@@ -123,6 +165,12 @@ void LazyCDProof::addLazyStep(Node expected,
}
// just store now
d_gens.insert(expected, pg);
+ // debug checking
+ if (isClosed)
+ {
+ Trace("lazy-cdproof-debug") << "Checking closed..." << std::endl;
+ pfgEnsureClosed(expected, pg, "lazy-cdproof-debug", ctx);
+ }
}
ProofGenerator* LazyCDProof::getGeneratorFor(Node fact,
@@ -176,6 +224,4 @@ bool LazyCDProof::hasGenerator(Node fact) const
return it != d_gens.end();
}
-std::string LazyCDProof::identify() const { return "LazyCDProof"; }
-
} // namespace CVC4
diff --git a/src/expr/lazy_proof.h b/src/expr/lazy_proof.h
index c802de39e..e2bba3015 100644
--- a/src/expr/lazy_proof.h
+++ b/src/expr/lazy_proof.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -45,7 +45,8 @@ class LazyCDProof : public CDProof
*/
LazyCDProof(ProofNodeManager* pnm,
ProofGenerator* dpg = nullptr,
- context::Context* c = nullptr);
+ context::Context* c = nullptr,
+ std::string name = "LazyCDProof");
~LazyCDProof();
/**
* Get lazy proof for fact, or nullptr if it does not exist. This may
@@ -66,12 +67,22 @@ class LazyCDProof : public CDProof
*
* @param expected The fact that can be proven.
* @param pg The generator that can proof expected.
+ * @param trustId If a null proof generator is provided, we add a step to
+ * the proof that has trustId as the rule and expected as the sole argument.
+ * We do this only if trustId is not PfRule::ASSUME. This is primarily used
+ * for identifying the kind of hole when a proof generator is not given.
+ * @param isClosed Whether to expect that pg can provide a closed proof for
+ * this fact.
+ * @param ctx The context we are in (for debugging).
* @param forceOverwrite If this flag is true, then this call overwrites
* an existing proof generator provided for expected, if one was provided
* via a previous call to addLazyStep in the current context.
*/
void addLazyStep(Node expected,
ProofGenerator* pg,
+ PfRule trustId = PfRule::ASSUME,
+ bool isClosed = false,
+ const char* ctx = "LazyCDProof::addLazyStep",
bool forceOverwrite = false);
/**
* Does this have any proof generators? This method always returns true
@@ -80,8 +91,6 @@ class LazyCDProof : public CDProof
bool hasGenerators() const;
/** Does the given fact have an explicitly provided generator? */
bool hasGenerator(Node fact) const;
- /** identify */
- std::string identify() const override;
protected:
typedef context::CDHashMap<Node, ProofGenerator*, NodeHashFunction>
diff --git a/src/expr/lazy_proof_chain.cpp b/src/expr/lazy_proof_chain.cpp
new file mode 100644
index 000000000..5c096767b
--- /dev/null
+++ b/src/expr/lazy_proof_chain.cpp
@@ -0,0 +1,317 @@
+/********************* */
+/*! \file lazy_proof_chain.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Haniel Barbosa
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of lazy proof utility
+ **/
+
+#include "expr/lazy_proof_chain.h"
+
+#include "expr/proof.h"
+#include "expr/proof_node_algorithm.h"
+#include "options/smt_options.h"
+
+namespace CVC4 {
+
+LazyCDProofChain::LazyCDProofChain(ProofNodeManager* pnm,
+ bool cyclic,
+ context::Context* c,
+ ProofGenerator* defGen,
+ bool defRec)
+ : d_manager(pnm),
+ d_cyclic(cyclic),
+ d_defRec(defRec),
+ d_context(),
+ d_gens(c ? c : &d_context),
+ d_defGen(defGen)
+{
+}
+
+LazyCDProofChain::~LazyCDProofChain() {}
+
+const std::map<Node, std::shared_ptr<ProofNode>> LazyCDProofChain::getLinks()
+ const
+{
+ std::map<Node, std::shared_ptr<ProofNode>> links;
+ for (const std::pair<const Node, ProofGenerator*>& link : d_gens)
+ {
+ Assert(link.second);
+ std::shared_ptr<ProofNode> pfn = link.second->getProofFor(link.first);
+ Assert(pfn);
+ links[link.first] = pfn;
+ }
+ return links;
+}
+
+std::shared_ptr<ProofNode> LazyCDProofChain::getProofFor(Node fact)
+{
+ Trace("lazy-cdproofchain")
+ << "LazyCDProofChain::getProofFor " << fact << "\n";
+ // which facts have had proofs retrieved for. This is maintained to avoid
+ // cycles. It also saves the proof node of the fact
+ std::unordered_map<Node, std::shared_ptr<ProofNode>, NodeHashFunction>
+ toConnect;
+ // leaves of proof node links in the chain, i.e. assumptions, yet to be
+ // expanded
+ std::unordered_map<Node,
+ std::vector<std::shared_ptr<ProofNode>>,
+ NodeHashFunction>
+ assumptionsToExpand;
+ // invariant of the loop below, the first iteration notwhistanding:
+ // visit = domain(assumptionsToExpand) \ domain(toConnect)
+ std::vector<Node> visit{fact};
+ std::unordered_map<Node, bool, NodeHashFunction> visited;
+ Node cur;
+ do
+ {
+ cur = visit.back();
+ visit.pop_back();
+ auto itVisited = visited.find(cur);
+ // pre-traversal
+ if (itVisited == visited.end())
+ {
+ Trace("lazy-cdproofchain")
+ << "LazyCDProofChain::getProofFor: check " << cur << "\n";
+ Assert(toConnect.find(cur) == toConnect.end());
+ bool rec = true;
+ ProofGenerator* pg = getGeneratorForInternal(cur, rec);
+ if (!pg)
+ {
+ Trace("lazy-cdproofchain")
+ << "LazyCDProofChain::getProofFor: nothing to do\n";
+ // nothing to do for this fact, it'll be a leaf in the final proof
+ // node, don't post-traverse.
+ visited[cur] = true;
+ continue;
+ }
+ Trace("lazy-cdproofchain")
+ << "LazyCDProofChain::getProofFor: Call generator " << pg->identify()
+ << " for chain link " << cur << "\n";
+ std::shared_ptr<ProofNode> curPfn = pg->getProofFor(cur);
+ if (curPfn == nullptr)
+ {
+ Trace("lazy-cdproofchain")
+ << "LazyCDProofChain::getProofFor: No proof found, skip\n";
+ visited[cur] = true;
+ continue;
+ }
+ // map node whose proof node must be expanded to the respective poof node
+ toConnect[cur] = curPfn;
+ if (!rec)
+ {
+ // we don't want to recursively connect this proof
+ visited[cur] = true;
+ continue;
+ }
+ Trace("lazy-cdproofchain-debug")
+ << "LazyCDProofChain::getProofFor: stored proof: " << *curPfn.get()
+ << "\n";
+ // retrieve free assumptions and their respective proof nodes
+ std::map<Node, std::vector<std::shared_ptr<ProofNode>>> famap;
+ expr::getFreeAssumptionsMap(curPfn, famap);
+ if (Trace.isOn("lazy-cdproofchain"))
+ {
+ Trace("lazy-cdproofchain")
+ << "LazyCDProofChain::getProofFor: free assumptions:\n";
+ for (auto fap : famap)
+ {
+ Trace("lazy-cdproofchain")
+ << "LazyCDProofChain::getProofFor: - " << fap.first << "\n";
+ }
+ }
+ // mark for post-traversal if we are controlling cycles
+ if (d_cyclic)
+ {
+ Trace("lazy-cdproofchain") << "LazyCDProofChain::getProofFor: marking "
+ << cur << " for cycle check\n";
+ visit.push_back(cur);
+ visited[cur] = false;
+ }
+ else
+ {
+ visited[cur] = true;
+ }
+ // enqueue free assumptions to process
+ for (const std::pair<const Node, std::vector<std::shared_ptr<ProofNode>>>&
+ fap : famap)
+ {
+ // check cycles
+ if (d_cyclic)
+ {
+ // cycles are assumptions being *currently* expanded and seen again,
+ // i.e. in toConnect and not yet post-visited
+ auto itToConnect = toConnect.find(fap.first);
+ if (itToConnect != toConnect.end() && !visited[fap.first])
+ {
+ // Since we have a cycle with an assumption, this fact will be an
+ // assumption in the final proof node produced by this
+ // method. Thus we erase it as something to be connected, which
+ // will keep it as an assumption.
+ Trace("lazy-cdproofchain") << "LazyCDProofChain::getProofFor: "
+ "removing cyclic assumption "
+ << fap.first << " from expansion\n";
+ continue;
+ }
+ }
+ // We always add assumptions to visit so that their last seen occurrence
+ // is expanded (rather than the first seen occurrence, if we were not
+ // adding assumptions, say, in assumptionsToExpand). This is so because
+ // in the case where we are checking cycles this is necessary (and
+ // harmless when we are not). For example the cycle
+ //
+ // a2
+ // ...
+ // ----
+ // a1
+ // ...
+ // --------
+ // a0 a1 a2
+ // ...
+ // ---------------
+ // n
+ //
+ // in which a2 has a1 as an assumption, which has a2 an assumption,
+ // would not be captured if we did not revisit a1, which is an
+ // assumption of n and this already occur in assumptionsToExpand when
+ // it shows up again as an assumption of a2.
+ visit.push_back(fap.first);
+ // add assumption proof nodes to be updated
+ assumptionsToExpand[fap.first].insert(
+ assumptionsToExpand[fap.first].end(),
+ fap.second.begin(),
+ fap.second.end());
+ }
+ if (d_cyclic)
+ {
+ Trace("lazy-cdproofchain") << push;
+ Trace("lazy-cdproofchain-debug") << push;
+ }
+ }
+ else if (!itVisited->second)
+ {
+ visited[cur] = true;
+ Trace("lazy-cdproofchain") << pop;
+ Trace("lazy-cdproofchain-debug") << pop;
+ Trace("lazy-cdproofchain")
+ << "LazyCDProofChain::getProofFor: post-visited " << cur << "\n";
+ }
+ else
+ {
+ Trace("lazy-cdproofchain")
+ << "LazyCDProofChain::getProofFor: already fully processed " << cur
+ << "\n";
+ }
+ } while (!visit.empty());
+ // expand all assumptions marked to be connected
+ for (const std::pair<const Node, std::shared_ptr<ProofNode>>& npfn :
+ toConnect)
+ {
+ auto it = assumptionsToExpand.find(npfn.first);
+ if (it == assumptionsToExpand.end())
+ {
+ Assert(npfn.first == fact);
+ continue;
+ }
+ Assert(npfn.second);
+ Trace("lazy-cdproofchain")
+ << "LazyCDProofChain::getProofFor: expand assumption " << npfn.first
+ << "\n";
+ Trace("lazy-cdproofchain-debug")
+ << "LazyCDProofChain::getProofFor: ...expand to " << *npfn.second.get()
+ << "\n";
+ // update each assumption proof node
+ for (std::shared_ptr<ProofNode> pfn : it->second)
+ {
+ d_manager->updateNode(pfn.get(), npfn.second.get());
+ }
+ }
+ // final proof of fact
+ auto it = toConnect.find(fact);
+ if (it == toConnect.end())
+ {
+ return nullptr;
+ }
+ return it->second;
+}
+
+void LazyCDProofChain::addLazyStep(Node expected, ProofGenerator* pg)
+{
+ Assert(pg != nullptr);
+ Trace("lazy-cdproofchain") << "LazyCDProofChain::addLazyStep: " << expected
+ << " set to generator " << pg->identify() << "\n";
+ // note this will replace the generator for expected, if any
+ d_gens.insert(expected, pg);
+}
+
+void LazyCDProofChain::addLazyStep(Node expected,
+ ProofGenerator* pg,
+ const std::vector<Node>& assumptions,
+ const char* ctx)
+{
+ Assert(pg != nullptr);
+ Trace("lazy-cdproofchain") << "LazyCDProofChain::addLazyStep: " << expected
+ << " set to generator " << pg->identify() << "\n";
+ // note this will rewrite the generator for expected, if any
+ d_gens.insert(expected, pg);
+ // check if chain is closed if options::proofNewEagerChecking() is on
+ if (options::proofNewEagerChecking())
+ {
+ Trace("lazy-cdproofchain")
+ << "LazyCDProofChain::addLazyStep: Checking closed proof...\n";
+ std::shared_ptr<ProofNode> pfn = pg->getProofFor(expected);
+ std::vector<Node> allowedLeaves{assumptions.begin(), assumptions.end()};
+ // add all current links in the chain
+ for (const std::pair<const Node, ProofGenerator*>& link : d_gens)
+ {
+ allowedLeaves.push_back(link.first);
+ }
+ if (Trace.isOn("lazy-cdproofchain"))
+ {
+ Trace("lazy-cdproofchain") << "Checking relative to leaves...\n";
+ for (const Node& n : allowedLeaves)
+ {
+ Trace("lazy-cdproofchain") << " - " << n << "\n";
+ }
+ Trace("lazy-cdproofchain") << "\n";
+ }
+ pfnEnsureClosedWrt(pfn.get(), allowedLeaves, "lazy-cdproofchain", ctx);
+ }
+}
+
+bool LazyCDProofChain::hasGenerator(Node fact) const
+{
+ return d_gens.find(fact) != d_gens.end();
+}
+
+ProofGenerator* LazyCDProofChain::getGeneratorFor(Node fact)
+{
+ bool rec = true;
+ return getGeneratorForInternal(fact, rec);
+}
+
+ProofGenerator* LazyCDProofChain::getGeneratorForInternal(Node fact, bool& rec)
+{
+ auto it = d_gens.find(fact);
+ if (it != d_gens.end())
+ {
+ return (*it).second;
+ }
+ // otherwise, if no explicit generators, we use the default one
+ if (d_defGen != nullptr)
+ {
+ rec = d_defRec;
+ return d_defGen;
+ }
+ return nullptr;
+}
+
+std::string LazyCDProofChain::identify() const { return "LazyCDProofChain"; }
+
+} // namespace CVC4
diff --git a/src/expr/lazy_proof_chain.h b/src/expr/lazy_proof_chain.h
new file mode 100644
index 000000000..28de3cea0
--- /dev/null
+++ b/src/expr/lazy_proof_chain.h
@@ -0,0 +1,153 @@
+/********************* */
+/*! \file lazy_proof_chain.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Haniel Barbosa
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Lazy proof chain utility
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__EXPR__LAZY_PROOF_CHAIN_H
+#define CVC4__EXPR__LAZY_PROOF_CHAIN_H
+
+#include <unordered_map>
+#include <vector>
+
+#include "context/cdhashmap.h"
+#include "expr/proof_generator.h"
+#include "expr/proof_node_manager.h"
+
+namespace CVC4 {
+
+/**
+ * A (context-dependent) lazy generator for proof chains. This class is an
+ * extension of ProofGenerator that additionally that maps facts to proof
+ * generators in a context-dependent manner. The map is built with the addition
+ * of lazy steps mapping facts to proof generators. More importantly, its
+ * getProofFor method expands the proof generators registered to this class by
+ * connecting, for the proof generated to one fact, assumptions to the proofs
+ * generated for those assumptinos that are registered in the chain.
+ */
+class LazyCDProofChain : public ProofGenerator
+{
+ public:
+ /** Constructor
+ *
+ * @param pnm The proof node manager for constructing ProofNode objects.
+ * @param cyclic Whether this instance is robust to cycles in the chain.
+ * @param c The context that this class depends on. If none is provided,
+ * this class is context-independent.
+ * @param defGen The default generator to be used if no generator exists
+ * for a step.
+ * @param defRec Whether this instance expands proofs from defGen recursively.
+ */
+ LazyCDProofChain(ProofNodeManager* pnm,
+ bool cyclic = true,
+ context::Context* c = nullptr,
+ ProofGenerator* defGen = nullptr,
+ bool defRec = true);
+ ~LazyCDProofChain();
+ /**
+ * Get lazy proof for fact, or nullptr if it does not exist, by connecting the
+ * proof nodes generated for each intermediate relevant fact registered in the
+ * chain (i.e., in the domain of d_gens).
+ *
+ * For example, if d_gens consists of the following pairs
+ *
+ * --- (A, PG1)
+ * --- (B, PG2)
+ * --- (C, PG3)
+ *
+ * and getProofFor(A) is called, with PG1 generating a proof with assumptions
+ * B and D, then B is expanded, with its assumption proof node being updated
+ * to the expanded proof node, while D is not. Assuming PG2 provides a proof
+ * with assumptions C and E, then C is expanded and E is not. Suppose PG3
+ * gives a closed proof, thus the call getProofFor(A) produces a proof node
+ *
+ * A : ( ... B : ( ... C : (...), ... ASSUME( E ) ), ... ASSUME( D ) )
+ *
+ * Note that the expansions are done directly on the proof nodes produced by
+ * the generators.
+ *
+ * If this instance has been set to be robust to cyclic proofs (i.e., d_cyclic
+ * is true), then the construction of the proof chain checks that there are no
+ * cycles, i.e., a given fact would have itself as an assumption when
+ * connecting the chain links. If such a cycle were to be detected then the
+ * fact will be marked as an assumption and not expanded in the final proof
+ * node. The method does not fail.
+ */
+ std::shared_ptr<ProofNode> getProofFor(Node fact) override;
+ /** Add step by generator
+ *
+ * This method stores that expected can be proven by proof generator pg if
+ * it is required to do so. This mapping is maintained in the remainder of
+ * the current context (according to the context c provided to this class).
+ *
+ * Moreover the lazy steps of this class are expected to fulfill the
+ * requirement that pg.getProofFor(expected) generates a proof node closed
+ * with relation to
+ * (1) a fixed set F1, ..., Fn,
+ * (2) formulas in the current domain of d_gens.
+ *
+ * This is so that we only add links to the chain that depend on a fixed set
+ * of assumptions or in other links.
+ *
+ * @param expected The fact that can be proven.
+ * @param pg The generator that can proof expected.
+ * @param assumptions The fixed set of assumptions with relation to which the
+ * chain, now augmented with expect, must be closed.
+ * @param ctx The context we are in (for debugging).
+ */
+ void addLazyStep(Node expected,
+ ProofGenerator* pg,
+ const std::vector<Node>& assumptions,
+ const char* ctx = "LazyCDProofChain::addLazyStep");
+
+ /** As above but does not do the closedness check. */
+ void addLazyStep(Node expected, ProofGenerator* pg);
+
+ /** Does the given fact have an explicitly provided generator? */
+ bool hasGenerator(Node fact) const;
+
+ /**
+ * Get generator for fact, or nullptr if it doesnt exist.
+ */
+ ProofGenerator* getGeneratorFor(Node fact);
+
+ /** identify */
+ std::string identify() const override;
+
+ /** Retrieve, for each fact in d_gens, it mapped to the proof node generated
+ * by its generator in d_gens. */
+ const std::map<Node, std::shared_ptr<ProofNode>> getLinks() const;
+
+ private:
+ /**
+ * Get generator for fact, or nullptr if it doesnt exist. Updates rec to
+ * true if we should recurse on its proof.
+ */
+ ProofGenerator* getGeneratorForInternal(Node fact, bool& rec);
+ /** The proof manager, used for allocating new ProofNode objects */
+ ProofNodeManager* d_manager;
+ /** Whether this instance is robust to cycles in the chain. */
+ bool d_cyclic;
+ /** Whether we expand recursively (for the default generator) */
+ bool d_defRec;
+ /** A dummy context used by this class if none is provided */
+ context::Context d_context;
+ /** Maps facts that can be proven to generators */
+ context::CDHashMap<Node, ProofGenerator*, NodeHashFunction> d_gens;
+ /** The default proof generator (if one exists) */
+ ProofGenerator* d_defGen;
+};
+
+} // namespace CVC4
+
+#endif /* CVC4__EXPR__LAZY_PROOF_CHAIN_H */
diff --git a/src/expr/match_trie.cpp b/src/expr/match_trie.cpp
index a7a1a1839..a76779b6e 100644
--- a/src/expr/match_trie.cpp
+++ b/src/expr/match_trie.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/match_trie.h b/src/expr/match_trie.h
index 7d330ee0d..37f2a0f71 100644
--- a/src/expr/match_trie.h
+++ b/src/expr/match_trie.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/metakind_template.cpp b/src/expr/metakind_template.cpp
index 5f72d5670..a4b9d17c8 100644
--- a/src/expr/metakind_template.cpp
+++ b/src/expr/metakind_template.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/metakind_template.h b/src/expr/metakind_template.h
index 5fa10c90a..3a453f9ac 100644
--- a/src/expr/metakind_template.h
+++ b/src/expr/metakind_template.h
@@ -5,7 +5,7 @@
** Morgan Deters, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -201,8 +201,6 @@ Kind operatorToKind(::CVC4::expr::NodeValue* nv);
}/* CVC4::kind namespace */
-#line 205 "${template}"
-
}/* CVC4 namespace */
#endif /* CVC4__NODE_MANAGER_NEEDS_CONSTANT_MAP */
diff --git a/src/expr/mkexpr b/src/expr/mkexpr
index c5f12f487..58531cba4 100755
--- a/src/expr/mkexpr
+++ b/src/expr/mkexpr
@@ -150,9 +150,7 @@ function typerule {
lineno=${BASH_LINENO[0]}
check_theory_seen
typerules="${typerules}
-#line $lineno \"$kf\"
case kind::$1:
-#line $lineno \"$kf\"
typeNode = $2::computeType(nodeManager, n, check);
break;
"
@@ -163,9 +161,7 @@ function construle {
lineno=${BASH_LINENO[0]}
check_theory_seen
construles="${construles}
-#line $lineno \"$kf\"
case kind::$1:
-#line $lineno \"$kf\"
return $2::computeIsConst(nodeManager, n);
"
}
@@ -218,26 +214,19 @@ function constant {
fi
mkConst_instantiations="${mkConst_instantiations}
-#line $lineno \"$kf\"
template <> Expr ExprManager::mkConst($2 const& val);
"
mkConst_implementations="${mkConst_implementations}
-#line $lineno \"$kf\"
template <> Expr ExprManager::mkConst($2 const& val) {
-#line $lineno \"$kf\"
return Expr(this, new Node(d_nodeManager->mkConst< $2 >(val)));
}
"
getConst_instantiations="${getConst_instantiations}
-#line $lineno \"$kf\"
template <> $2 const & Expr::getConst< $2 >() const;
"
getConst_implementations="${getConst_implementations}
-#line $lineno \"$kf\"
template <> $2 const & Expr::getConst() const {
-#line $lineno \"$kf\"
PrettyCheckArgument(getKind() == ::CVC4::kind::$1, *this, \"Improper kind for getConst<$2>()\");
-#line $lineno \"$kf\"
return d_node->getConst< $2 >();
}
"
@@ -288,10 +277,6 @@ check_builtin_theory_seen
## output
-# generate warnings about incorrect #line annotations in templates
-nl -ba -s' ' "$template" | grep '^ *[0-9][0-9]* # *line' |
- awk '{OFS="";if($1+1!=$3) print "'"$template"':",$1,": warning: incorrect annotation \"#line ",$3,"\" (it should be \"#line ",($1+1),"\")"}' >&2
-
text=$(cat "$template")
for var in \
includes \
diff --git a/src/expr/mkkind b/src/expr/mkkind
index fbf37eff4..55276549a 100755
--- a/src/expr/mkkind
+++ b/src/expr/mkkind
@@ -257,23 +257,23 @@ function register_sort {
"
type_constant_to_theory_id="${type_constant_to_theory_id} case $id: return $theory_id;
"
- type_constant_cardinalities="${type_constant_cardinalities}#line $lineno \"$kf\"
+ type_constant_cardinalities="${type_constant_cardinalities}
case $id: return Cardinality($cardinality);
"
- type_constant_wellfoundednesses="${type_constant_wellfoundednesses}#line $lineno \"$kf\"
+ type_constant_wellfoundednesses="${type_constant_wellfoundednesses}
case $id: return $wellfoundedness;
"
if [ -n "$groundterm" ]; then
- type_constant_groundterms="${type_constant_groundterms}#line $lineno \"$kf\"
+ type_constant_groundterms="${type_constant_groundterms}
case $id: return $groundterm;
"
if [ -n "$header" ]; then
- type_properties_includes="${type_properties_includes}#line $lineno \"$kf\"
+ type_properties_includes="${type_properties_includes}
#include \"$header\"
"
fi
else
- type_constant_groundterms="${type_constant_groundterms}#line $lineno \"$kf\"
+ type_constant_groundterms="${type_constant_groundterms}
case $id: Unhandled() << tc;
"
fi
@@ -284,11 +284,11 @@ function register_cardinality {
cardinality_computer=$(sed 's,%TYPE%,typeNode,g' <<<"$2")
header=$3
- type_cardinalities="${type_cardinalities}#line $lineno \"$kf\"
+ type_cardinalities="${type_cardinalities}
case $id: return $cardinality_computer;
"
if [ -n "$header" ]; then
- type_properties_includes="${type_properties_includes}#line $lineno \"$kf\"
+ type_properties_includes="${type_properties_includes}
#include \"$header\"
"
fi
@@ -314,20 +314,20 @@ function register_wellfoundedness {
fi
fi
- type_wellfoundednesses="${type_wellfoundednesses}#line $lineno \"$kf\"
+ type_wellfoundednesses="${type_wellfoundednesses}
case $id: return $wellfoundedness_computer;
"
if [ -n "$groundterm_computer" ]; then
- type_groundterms="${type_groundterms}#line $lineno \"$kf\"
+ type_groundterms="${type_groundterms}
case $id: return $groundterm_computer;
"
else
- type_groundterms="${type_groundterms}#line $lineno \"$kf\"
+ type_groundterms="${type_groundterms}
case $id: Unhandled() << typeNode;
"
fi
if [ -n "$header" ]; then
- type_properties_includes="${type_properties_includes}#line $lineno \"$kf\"
+ type_properties_includes="${type_properties_includes}
#include \"$header\"
"
fi
@@ -390,10 +390,6 @@ check_builtin_theory_seen
## output
-# generate warnings about incorrect #line annotations in templates
-nl -ba -s' ' "$template" | grep '^ *[0-9][0-9]* # *line' |
- awk '{OFS="";if($1+1!=$3) print "'"$template"':",$1,": warning: incorrect annotation \"#line ",$3,"\" (it should be \"#line ",($1+1),"\")"}' >&2
-
text=$(cat "$template")
for var in \
kind_decls \
diff --git a/src/expr/mkmetakind b/src/expr/mkmetakind
index e2a733ec8..9d2f0a475 100755
--- a/src/expr/mkmetakind
+++ b/src/expr/mkmetakind
@@ -270,19 +270,16 @@ $2 const& NodeValue::getConst< $2 >() const {
"
metakind_constHashes="${metakind_constHashes}
case kind::$1:
-#line $lineno \"$kf\"
return $3()(nv->getConst< $2 >());
"
metakind_constPrinters="${metakind_constPrinters}
case kind::$1:
-#line $lineno \"$kf\"
out << nv->getConst< $2 >();
break;
"
cname=`echo "$2" | awk 'BEGIN {FS="::"} {print$NF}'`
metakind_constDeleters="${metakind_constDeleters}
case kind::$1:
-#line $lineno \"$kf\"
std::allocator< $2 >().destroy(reinterpret_cast< $2* >(nv->d_children));
break;
"
@@ -301,7 +298,6 @@ function registerOperatorToKind {
operatorKind=$1
applyKind=$2
metakind_operatorKinds="${metakind_operatorKinds}
-#line $lineno \"$kf\"
case kind::$applyKind: return kind::$operatorKind;";
}
@@ -396,10 +392,6 @@ check_builtin_theory_seen
## output
-# generate warnings about incorrect #line annotations in templates
-nl -ba -s' ' "$template" | grep '^ *[0-9][0-9]* # *line' |
- awk '{OFS="";if($1+1!=$3) print "'"$template"':",$1,": warning: incorrect annotation \"#line ",$3,"\" (it should be \"#line ",($1+1),"\")"}' >&2
-
text=$(cat "$template")
for var in \
metakind_includes \
diff --git a/src/expr/node.cpp b/src/expr/node.cpp
index 90fb1f004..c45295622 100644
--- a/src/expr/node.cpp
+++ b/src/expr/node.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Yoni Zohar
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/node.h b/src/expr/node.h
index e431727f4..75d4d2022 100644
--- a/src/expr/node.h
+++ b/src/expr/node.h
@@ -5,7 +5,7 @@
** Morgan Deters, Dejan Jovanovic, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -22,8 +22,6 @@
#ifndef CVC4__NODE_H
#define CVC4__NODE_H
-#include <stdint.h>
-
#include <algorithm>
#include <functional>
#include <iostream>
@@ -821,19 +819,16 @@ public:
* @param out the stream to serialize this node to
* @param toDepth the depth to which to print this expression, or -1 to
* print it fully
- * @param types set to true to ascribe types to the output expressions
- * (might break language compliance, but good for debugging expressions)
* @param language the language in which to output
*/
inline void toStream(
std::ostream& out,
int toDepth = -1,
- bool types = false,
size_t dagThreshold = 1,
OutputLanguage language = language::output::LANG_AUTO) const
{
assertTNodeNotExpired();
- d_nv->toStream(out, toDepth, types, dagThreshold, language);
+ d_nv->toStream(out, toDepth, dagThreshold, language);
}
/**
@@ -853,17 +848,6 @@ public:
typedef expr::ExprSetDepth setdepth;
/**
- * IOStream manipulator to print type ascriptions or not.
- *
- * // let a, b, c, and d be variables of sort U
- * Node n = nm->mkNode(OR, a, b, nm->mkNode(AND, c, nm->mkNode(NOT, d)))
- * out << n;
- *
- * gives "(OR a:U b:U (AND c:U (NOT d:U)))", but
- */
- typedef expr::ExprPrintTypes printtypes;
-
- /**
* IOStream manipulator to print expressions as DAGs (or not).
*/
typedef expr::ExprDag dag;
@@ -909,7 +893,6 @@ public:
inline std::ostream& operator<<(std::ostream& out, TNode n) {
n.toStream(out,
Node::setdepth::getDepth(out),
- Node::printtypes::getPrintTypes(out),
Node::dag::getDag(out),
Node::setlanguage::getLanguage(out));
return out;
@@ -1417,7 +1400,7 @@ NodeTemplate<ref_count>::substitute(Iterator1 nodesBegin,
Assert(std::distance(nodesBegin, nodesEnd)
== std::distance(replacementsBegin, replacementsEnd))
<< "Substitution iterator ranges must be equal size";
- Iterator1 j = find(nodesBegin, nodesEnd, TNode(*this));
+ Iterator1 j = std::find(nodesBegin, nodesEnd, TNode(*this));
if(j != nodesEnd) {
Iterator2 b = replacementsBegin;
std::advance(b, std::distance(nodesBegin, j));
@@ -1523,7 +1506,6 @@ inline Node NodeTemplate<true>::fromExpr(const Expr& e) {
*/
static void __attribute__((used)) debugPrintNode(const NodeTemplate<true>& n) {
Warning() << Node::setdepth(-1)
- << Node::printtypes(false)
<< Node::dag(true)
<< Node::setlanguage(language::output::LANG_AST)
<< n << std::endl;
@@ -1531,7 +1513,6 @@ static void __attribute__((used)) debugPrintNode(const NodeTemplate<true>& n) {
}
static void __attribute__((used)) debugPrintNodeNoDag(const NodeTemplate<true>& n) {
Warning() << Node::setdepth(-1)
- << Node::printtypes(false)
<< Node::dag(false)
<< Node::setlanguage(language::output::LANG_AST)
<< n << std::endl;
@@ -1544,7 +1525,6 @@ static void __attribute__((used)) debugPrintRawNode(const NodeTemplate<true>& n)
static void __attribute__((used)) debugPrintTNode(const NodeTemplate<false>& n) {
Warning() << Node::setdepth(-1)
- << Node::printtypes(false)
<< Node::dag(true)
<< Node::setlanguage(language::output::LANG_AST)
<< n << std::endl;
@@ -1552,7 +1532,6 @@ static void __attribute__((used)) debugPrintTNode(const NodeTemplate<false>& n)
}
static void __attribute__((used)) debugPrintTNodeNoDag(const NodeTemplate<false>& n) {
Warning() << Node::setdepth(-1)
- << Node::printtypes(false)
<< Node::dag(false)
<< Node::setlanguage(language::output::LANG_AST)
<< n << std::endl;
diff --git a/src/expr/node_algorithm.cpp b/src/expr/node_algorithm.cpp
index be436bf8b..9d1c6ab41 100644
--- a/src/expr/node_algorithm.cpp
+++ b/src/expr/node_algorithm.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -374,10 +374,7 @@ bool getFreeVariables(TNode n,
{
visit.push_back(cur.getOperator());
}
- for (const TNode& cn : cur)
- {
- visit.push_back(cn);
- }
+ visit.insert(visit.end(), cur.begin(), cur.end());
}
else if (!itv->second)
{
@@ -413,10 +410,7 @@ bool getVariables(TNode n, std::unordered_set<TNode, TNodeHashFunction>& vs)
}
else
{
- for (const TNode& cn : cur)
- {
- visit.push_back(cn);
- }
+ visit.insert(visit.end(), cur.begin(), cur.end());
}
visited.insert(cur);
}
@@ -453,10 +447,41 @@ void getSymbols(TNode n,
{
visit.push_back(cur.getOperator());
}
- for (TNode cn : cur)
+ visit.insert(visit.end(), cur.begin(), cur.end());
+ }
+ } while (!visit.empty());
+}
+
+void getKindSubterms(TNode n,
+ Kind k,
+ bool topLevel,
+ std::unordered_set<Node, NodeHashFunction>& ts)
+{
+ std::unordered_set<TNode, TNodeHashFunction> visited;
+ std::vector<TNode> visit;
+ TNode cur;
+ visit.push_back(n);
+ do
+ {
+ cur = visit.back();
+ visit.pop_back();
+ if (visited.find(cur) == visited.end())
+ {
+ visited.insert(cur);
+ if (cur.getKind() == k)
+ {
+ ts.insert(cur);
+ if (topLevel)
+ {
+ // only considering top-level applications
+ continue;
+ }
+ }
+ if (cur.hasOperator())
{
- visit.push_back(cn);
+ visit.push_back(cur.getOperator());
}
+ visit.insert(visit.end(), cur.begin(), cur.end());
}
} while (!visit.empty());
}
@@ -500,10 +525,7 @@ void getOperatorsMap(
ops[tn].insert(o);
}
// add children to visit in the future
- for (TNode cn : cur)
- {
- visit.push_back(cn);
- }
+ visit.insert(visit.end(), cur.begin(), cur.end());
}
} while (!visit.empty());
}
diff --git a/src/expr/node_algorithm.h b/src/expr/node_algorithm.h
index 4fb40c739..7b6dd4f8c 100644
--- a/src/expr/node_algorithm.h
+++ b/src/expr/node_algorithm.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Yoni Zohar
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -134,6 +134,18 @@ void getSymbols(TNode n,
std::unordered_set<TNode, TNodeHashFunction>& visited);
/**
+ * For term n, this function collects the subterms of n whose kind is k.
+ * @param n The node under investigation
+ * @param k The kind we are considering
+ * @param topLevel If true, we collect only the top-level subterms with kind k.
+ * @param ts The set which the symbols of n are added to
+ */
+void getKindSubterms(TNode n,
+ Kind k,
+ bool topLevel,
+ std::unordered_set<Node, NodeHashFunction>& ts);
+
+/**
* For term n, this function collects the operators that occur in n.
* @param n The node under investigation
* @param ops The map (from each type to operators of that type) which the
diff --git a/src/expr/node_builder.h b/src/expr/node_builder.h
index 899961d73..eaa9a46d5 100644
--- a/src/expr/node_builder.h
+++ b/src/expr/node_builder.h
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -158,7 +158,6 @@
#include <cstdlib>
#include <iostream>
#include <memory>
-#include <stdint.h>
#include <vector>
namespace CVC4 {
diff --git a/src/expr/node_manager.cpp b/src/expr/node_manager.cpp
index c68b0df86..7c847d8ce 100644
--- a/src/expr/node_manager.cpp
+++ b/src/expr/node_manager.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -105,7 +105,76 @@ NodeManager::NodeManager(ExprManager* exprManager)
init();
}
+TypeNode NodeManager::booleanType()
+{
+ return mkTypeConst<TypeConstant>(BOOLEAN_TYPE);
+}
+
+TypeNode NodeManager::integerType()
+{
+ return mkTypeConst<TypeConstant>(INTEGER_TYPE);
+}
+
+TypeNode NodeManager::realType()
+{
+ return mkTypeConst<TypeConstant>(REAL_TYPE);
+}
+
+TypeNode NodeManager::stringType()
+{
+ return mkTypeConst<TypeConstant>(STRING_TYPE);
+}
+
+TypeNode NodeManager::regExpType()
+{
+ return mkTypeConst<TypeConstant>(REGEXP_TYPE);
+}
+
+TypeNode NodeManager::roundingModeType()
+{
+ return mkTypeConst<TypeConstant>(ROUNDINGMODE_TYPE);
+}
+
+TypeNode NodeManager::boundVarListType()
+{
+ return mkTypeConst<TypeConstant>(BOUND_VAR_LIST_TYPE);
+}
+
+TypeNode NodeManager::instPatternType()
+{
+ return mkTypeConst<TypeConstant>(INST_PATTERN_TYPE);
+}
+
+TypeNode NodeManager::instPatternListType()
+{
+ return mkTypeConst<TypeConstant>(INST_PATTERN_LIST_TYPE);
+}
+
+TypeNode NodeManager::builtinOperatorType()
+{
+ return mkTypeConst<TypeConstant>(BUILTIN_OPERATOR_TYPE);
+}
+
+TypeNode NodeManager::mkBitVectorType(unsigned size)
+{
+ return mkTypeConst<BitVectorSize>(BitVectorSize(size));
+}
+
+TypeNode NodeManager::mkFloatingPointType(unsigned exp, unsigned sig)
+{
+ return mkTypeConst<FloatingPointSize>(FloatingPointSize(exp, sig));
+}
+
+TypeNode NodeManager::mkFloatingPointType(FloatingPointSize fs)
+{
+ return mkTypeConst<FloatingPointSize>(fs);
+}
+
void NodeManager::init() {
+ // `mkConst()` indirectly needs the correct NodeManager in scope because we
+ // call `NodeValue::inc()` which uses `NodeManager::curentNM()`
+ NodeManagerScope nms(this);
+
poolInsert( &expr::NodeValue::null() );
for(unsigned i = 0; i < unsigned(kind::LAST_KIND); ++i) {
@@ -145,6 +214,8 @@ NodeManager::~NodeManager() {
d_rt_cache.d_children.clear();
d_rt_cache.d_data = dummy;
+ d_registeredDTypes.clear();
+ // clear the datatypes
d_ownedDTypes.clear();
Assert(!d_attrManager->inGarbageCollection());
@@ -194,15 +265,17 @@ NodeManager::~NodeManager() {
size_t NodeManager::registerDatatype(std::shared_ptr<DType> dt)
{
- size_t sz = d_ownedDTypes.size();
- d_ownedDTypes.push_back(dt);
+ size_t sz = d_registeredDTypes.size();
+ d_registeredDTypes.push_back(dt);
return sz;
}
-const DType& NodeManager::getDTypeForIndex(unsigned index) const
+const DType& NodeManager::getDTypeForIndex(size_t index) const
{
- Assert(index < d_ownedDTypes.size());
- return *d_ownedDTypes[index];
+ // if this assertion fails, it is likely due to not managing datatypes
+ // properly w.r.t. multiple NodeManagers.
+ Assert(index < d_registeredDTypes.size());
+ return *d_registeredDTypes[index];
}
void NodeManager::reclaimZombies() {
@@ -447,6 +520,18 @@ Node NodeManager::mkSkolem(const std::string& prefix, const TypeNode& type, cons
return n;
}
+TypeNode NodeManager::mkBagType(TypeNode elementType)
+{
+ CheckArgument(
+ !elementType.isNull(), elementType, "unexpected NULL element type");
+ CheckArgument(elementType.isFirstClass(),
+ elementType,
+ "cannot store types that are not first-class in bags. Try "
+ "option --uf-ho.");
+ Debug("bags") << "making bags type " << elementType << std::endl;
+ return mkTypeNode(kind::BAG_TYPE, elementType);
+}
+
TypeNode NodeManager::mkSequenceType(TypeNode elementType)
{
CheckArgument(
@@ -458,28 +543,159 @@ TypeNode NodeManager::mkSequenceType(TypeNode elementType)
return mkTypeNode(kind::SEQUENCE_TYPE, elementType);
}
-TypeNode NodeManager::mkConstructorType(const DatatypeConstructor& constructor,
- TypeNode range) {
- vector<TypeNode> sorts;
- Debug("datatypes") << "ctor name: " << constructor.getName() << endl;
- for(DatatypeConstructor::const_iterator i = constructor.begin();
- i != constructor.end();
- ++i) {
- TypeNode selectorType = *(*i).getSelector().getType().d_typeNode;
- Debug("datatypes") << selectorType << endl;
- TypeNode sort = selectorType[1];
+TypeNode NodeManager::mkDatatypeType(DType& datatype, uint32_t flags)
+{
+ // Not worth a special implementation; this doesn't need to be fast
+ // code anyway.
+ std::vector<DType> datatypes;
+ datatypes.push_back(datatype);
+ std::vector<TypeNode> result = mkMutualDatatypeTypes(datatypes, flags);
+ Assert(result.size() == 1);
+ return result.front();
+}
- // should be guaranteed here already, but just in case
- Assert(!sort.isFunctionLike());
+std::vector<TypeNode> NodeManager::mkMutualDatatypeTypes(
+ const std::vector<DType>& datatypes, uint32_t flags)
+{
+ std::set<TypeNode> unresolvedTypes;
+ return mkMutualDatatypeTypes(datatypes, unresolvedTypes, flags);
+}
+
+std::vector<TypeNode> NodeManager::mkMutualDatatypeTypes(
+ const std::vector<DType>& datatypes,
+ const std::set<TypeNode>& unresolvedTypes,
+ uint32_t flags)
+{
+ NodeManagerScope nms(this);
+ std::map<std::string, TypeNode> nameResolutions;
+ std::vector<TypeNode> dtts;
- Debug("datatypes") << "ctor sort: " << sort << endl;
- sorts.push_back(sort);
+ // have to build deep copy so that datatypes will live in this class
+ std::vector<std::shared_ptr<DType> > dt_copies;
+ for (const DType& dt : datatypes)
+ {
+ d_ownedDTypes.push_back(std::unique_ptr<DType>(new DType(dt)));
+ dt_copies.push_back(std::move(d_ownedDTypes.back()));
}
- Debug("datatypes") << "ctor range: " << range << endl;
- PrettyCheckArgument(!range.isFunctionLike(), range,
- "cannot create higher-order function types");
- sorts.push_back(range);
- return mkTypeNode(kind::CONSTRUCTOR_TYPE, sorts);
+
+ // First do some sanity checks, set up the final Type to be used for
+ // each datatype, and set up the "named resolutions" used to handle
+ // simple self- and mutual-recursion, for example in the definition
+ // "nat = succ(pred:nat) | zero", a named resolution can handle the
+ // pred selector.
+ for (const std::shared_ptr<DType>& dtc : dt_copies)
+ {
+ TypeNode typeNode;
+ // register datatype with the node manager
+ size_t index = registerDatatype(dtc);
+ if (dtc->getNumParameters() == 0)
+ {
+ typeNode = mkTypeConst(DatatypeIndexConstant(index));
+ }
+ else
+ {
+ TypeNode cons = mkTypeConst(DatatypeIndexConstant(index));
+ std::vector<TypeNode> params;
+ params.push_back(cons);
+ for (unsigned int ip = 0; ip < dtc->getNumParameters(); ++ip)
+ {
+ params.push_back(dtc->getParameter(ip));
+ }
+
+ typeNode = mkTypeNode(kind::PARAMETRIC_DATATYPE, params);
+ }
+ AlwaysAssert(nameResolutions.find(dtc->getName()) == nameResolutions.end())
+ << "cannot construct two datatypes at the same time "
+ "with the same name";
+ nameResolutions.insert(std::make_pair(dtc->getName(), typeNode));
+ dtts.push_back(typeNode);
+ }
+
+ // Second, set up the type substitution map for complex type
+ // resolution (e.g. if "list" is the type we're defining, and it has
+ // a selector of type "ARRAY INT OF list", this can't be taken care
+ // of using the named resolutions that we set up above. A
+ // preliminary array type was set up, and now needs to have "list"
+ // substituted in it for the correct type.
+ //
+ // @TODO get rid of named resolutions altogether and handle
+ // everything with these resolutions?
+ std::vector<TypeNode> paramTypes;
+ std::vector<TypeNode> paramReplacements;
+ std::vector<TypeNode> placeholders; // to hold the "unresolved placeholders"
+ std::vector<TypeNode> replacements; // to hold our final, resolved types
+ for (const TypeNode& ut : unresolvedTypes)
+ {
+ std::string name = ut.getAttribute(expr::VarNameAttr());
+ std::map<std::string, TypeNode>::const_iterator resolver =
+ nameResolutions.find(name);
+ AlwaysAssert(resolver != nameResolutions.end())
+ << "cannot resolve type " + name
+ + "; it's not among the datatypes being defined";
+ // We will instruct the Datatype to substitute "ut" (the
+ // unresolved SortType used as a placeholder in complex types)
+ // with "(*resolver).second" (the TypeNode we created in the
+ // first step, above).
+ if (ut.isSort())
+ {
+ placeholders.push_back(ut);
+ replacements.push_back((*resolver).second);
+ }
+ else
+ {
+ Assert(ut.isSortConstructor());
+ paramTypes.push_back(ut);
+ paramReplacements.push_back((*resolver).second);
+ }
+ }
+
+ // Lastly, perform the final resolutions and checks.
+ for (const TypeNode& ut : dtts)
+ {
+ const DType& dt = ut.getDType();
+ if (!dt.isResolved())
+ {
+ const_cast<DType&>(dt).resolve(nameResolutions,
+ placeholders,
+ replacements,
+ paramTypes,
+ paramReplacements);
+ }
+ // Check the datatype has been resolved properly.
+ for (size_t i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
+ {
+ const DTypeConstructor& c = dt[i];
+ TypeNode testerType CVC4_UNUSED = c.getTester().getType();
+ Assert(c.isResolved() && testerType.isTester() && testerType[0] == ut)
+ << "malformed tester in datatype post-resolution";
+ TypeNode ctorType CVC4_UNUSED = c.getConstructor().getType();
+ Assert(ctorType.isConstructor()
+ && ctorType.getNumChildren() == c.getNumArgs() + 1
+ && ctorType.getRangeType() == ut)
+ << "malformed constructor in datatype post-resolution";
+ // for all selectors...
+ for (size_t j = 0, nargs = c.getNumArgs(); j < nargs; j++)
+ {
+ const DTypeSelector& a = c[j];
+ TypeNode selectorType = a.getType();
+ Assert(a.isResolved() && selectorType.isSelector()
+ && selectorType[0] == ut)
+ << "malformed selector in datatype post-resolution";
+ // This next one's a "hard" check, performed in non-debug builds
+ // as well; the other ones should all be guaranteed by the
+ // CVC4::DType class, but this actually needs to be checked.
+ AlwaysAssert(!selectorType.getRangeType().isFunctionLike())
+ << "cannot put function-like things in datatypes";
+ }
+ }
+ }
+
+ for (NodeManagerListener* nml : d_listeners)
+ {
+ nml->nmNotifyNewDatatypes(dtts, flags);
+ }
+
+ return dtts;
}
TypeNode NodeManager::mkConstructorType(const std::vector<TypeNode>& args,
@@ -498,18 +714,19 @@ TypeNode NodeManager::TupleTypeCache::getTupleType( NodeManager * nm, std::vecto
for (unsigned i = 0; i < types.size(); ++ i) {
sst << "_" << types[i];
}
- Datatype dt(nm->toExprManager(), sst.str());
+ DType dt(sst.str());
dt.setTuple();
std::stringstream ssc;
ssc << sst.str() << "_ctor";
- DatatypeConstructor c(ssc.str());
+ std::shared_ptr<DTypeConstructor> c =
+ std::make_shared<DTypeConstructor>(ssc.str());
for (unsigned i = 0; i < types.size(); ++ i) {
std::stringstream ss;
ss << sst.str() << "_stor_" << i;
- c.addArg(ss.str().c_str(), types[i].toType());
+ c->addArg(ss.str().c_str(), types[i]);
}
dt.addConstructor(c);
- d_data = TypeNode::fromType(nm->toExprManager()->mkDatatypeType(dt));
+ d_data = nm->mkDatatypeType(dt);
Debug("tuprec-debug") << "Return type : " << d_data << std::endl;
}
return d_data;
@@ -527,16 +744,17 @@ TypeNode NodeManager::RecTypeCache::getRecordType( NodeManager * nm, const Recor
for(Record::FieldVector::const_iterator i = fields.begin(); i != fields.end(); ++i) {
sst << "_" << (*i).first << "_" << (*i).second;
}
- Datatype dt(nm->toExprManager(), sst.str());
+ DType dt(sst.str());
dt.setRecord();
std::stringstream ssc;
ssc << sst.str() << "_ctor";
- DatatypeConstructor c(ssc.str());
+ std::shared_ptr<DTypeConstructor> c =
+ std::make_shared<DTypeConstructor>(ssc.str());
for(Record::FieldVector::const_iterator i = fields.begin(); i != fields.end(); ++i) {
- c.addArg((*i).first, (*i).second);
+ c->addArg((*i).first, TypeNode::fromType((*i).second));
}
dt.addConstructor(c);
- d_data = TypeNode::fromType(nm->toExprManager()->mkDatatypeType(dt));
+ d_data = nm->mkDatatypeType(dt);
Debug("tuprec-debug") << "Return type : " << d_data << std::endl;
}
return d_data;
@@ -797,6 +1015,28 @@ Node NodeManager::mkNullaryOperator(const TypeNode& type, Kind k) {
}
}
+Node NodeManager::mkSingleton(const TypeNode& t, const TNode n)
+{
+ Assert(n.getType().isSubtypeOf(t))
+ << "Invalid operands for mkSingleton. The type '" << n.getType()
+ << "' of node '" << n << "' is not a subtype of '" << t << "'."
+ << std::endl;
+ Node op = mkConst(SingletonOp(t));
+ Node singleton = mkNode(kind::SINGLETON, op, n);
+ return singleton;
+}
+
+Node NodeManager::mkBag(const TypeNode& t, const TNode n, const TNode m)
+{
+ Assert(n.getType().isSubtypeOf(t))
+ << "Invalid operands for mkBag. The type '" << n.getType()
+ << "' of node '" << n << "' is not a subtype of '" << t << "'."
+ << std::endl;
+ Node op = mkConst(MakeBagOp(t));
+ Node bag = mkNode(kind::MK_BAG, op, n, m);
+ return bag;
+}
+
Node NodeManager::mkAbstractValue(const TypeNode& type) {
Node n = mkConst(AbstractValue(++d_abstractValueCount));
n.setAttribute(TypeAttr(), type);
diff --git a/src/expr/node_manager.h b/src/expr/node_manager.h
index 1a28a16eb..99db9feb2 100644
--- a/src/expr/node_manager.h
+++ b/src/expr/node_manager.h
@@ -2,10 +2,10 @@
/*! \file node_manager.h
** \verbatim
** Top contributors (to current version):
- ** Morgan Deters, Christopher L. Conway, Dejan Jovanovic
+ ** Morgan Deters, Christopher L. Conway, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -66,7 +66,7 @@ class NodeManagerListener {
virtual void nmNotifyNewSortConstructor(TypeNode tn, uint32_t flags) {}
virtual void nmNotifyInstantiateSortConstructor(TypeNode ctor, TypeNode sort,
uint32_t flags) {}
- virtual void nmNotifyNewDatatypes(const std::vector<DatatypeType>& datatypes,
+ virtual void nmNotifyNewDatatypes(const std::vector<TypeNode>& datatypes,
uint32_t flags)
{
}
@@ -91,10 +91,6 @@ class NodeManager {
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(
- std::vector<Datatype>&, std::set<Type>&, uint32_t);
-
/** Predicate for use with STL algorithms */
struct NodeValueReferenceCountNonZero {
bool operator()(expr::NodeValue* nv) { return nv->d_rc > 0; }
@@ -172,8 +168,12 @@ class NodeManager {
*/
std::vector<NodeManagerListener*> d_listeners;
- /** A list of datatypes owned by this node manager. */
- std::vector<std::shared_ptr<DType> > d_ownedDTypes;
+ /** A list of datatypes registered by its corresponding expr manager.
+ * !!! this member should be deleted when the Expr-layer is deleted.
+ */
+ std::vector<std::shared_ptr<DType> > d_registeredDTypes;
+ /** A list of datatypes owned by this node manager */
+ std::vector<std::unique_ptr<DType> > d_ownedDTypes;
/**
* A map of tuple and record types to their corresponding datatype.
@@ -376,8 +376,8 @@ class NodeManager {
/** Create a variable with the given type. */
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:
+
+ public:
explicit NodeManager(ExprManager* exprManager);
~NodeManager();
@@ -407,8 +407,10 @@ public:
Assert(elt != d_listeners.end()) << "listener not subscribed";
d_listeners.erase(elt);
}
-
- /** register datatype */
+
+ /** register that datatype dt was constructed by the expression manager
+ * !!! this interface should be deleted when the Expr-layer is deleted.
+ */
size_t registerDatatype(std::shared_ptr<DType> dt);
/**
* Return the datatype at the given index owned by this class. Type nodes are
@@ -420,7 +422,7 @@ public:
* would lead to memory leaks. Thus TypeNode are given a DatatypeIndexConstant
* which is used as an index to retrieve the DType via this call.
*/
- const DType& getDTypeForIndex(unsigned index) const;
+ const DType& getDTypeForIndex(size_t index) const;
/** Get a Kind from an operator expression */
static inline Kind operatorToKind(TNode n);
@@ -471,6 +473,28 @@ public:
template <bool ref_count>
Node* mkNodePtr(Kind kind, const std::vector<NodeTemplate<ref_count> >& children);
+ /**
+ * Create an AND node with arbitrary number of children. This returns the
+ * true node if children is empty, or the single node in children if
+ * it contains only one node.
+ *
+ * We define construction of AND as a special case here since it is widely
+ * used for e.g. constructing explanations.
+ */
+ template <bool ref_count>
+ Node mkAnd(const std::vector<NodeTemplate<ref_count> >& children);
+
+ /**
+ * Create an OR node with arbitrary number of children. This returns the
+ * false node if children is empty, or the single node in children if
+ * it contains only one node.
+ *
+ * We define construction of OR as a special case here since it is widely
+ * used for e.g. constructing explanations or lemmas.
+ */
+ template <bool ref_count>
+ Node mkOr(const std::vector<NodeTemplate<ref_count> >& children);
+
/** Create a node (with no children) by operator. */
Node mkNode(TNode opNode);
Node* mkNodePtr(TNode opNode);
@@ -552,17 +576,36 @@ public:
/** Create a instantiation constant with the given type. */
Node mkInstConstant(const TypeNode& type);
-
+
/** Create a boolean term variable. */
Node mkBooleanTermVariable();
/** Make a new abstract value with the given type. */
Node mkAbstractValue(const TypeNode& type);
-
+
/** make unique (per Type,Kind) variable. */
Node mkNullaryOperator(const TypeNode& type, Kind k);
/**
+ * Create a singleton set from the given element n.
+ * @param t the element type of the returned set.
+ * Note that the type of n needs to be a subtype of t.
+ * @param n the single element in the singleton.
+ * @return a singleton set constructed from the element n.
+ */
+ Node mkSingleton(const TypeNode& t, const TNode n);
+
+ /**
+ * Create a bag from the given element n along with its multiplicity m.
+ * @param t the element type of the returned bag.
+ * Note that the type of n needs to be a subtype of t.
+ * @param n the element that is used to to construct the bag
+ * @param m the multiplicity of the element n
+ * @return a bag that contains m occurrences of n.
+ */
+ Node mkBag(const TypeNode& t, const TNode n, const TNode m);
+
+ /**
* Create a constant of type T. It will have the appropriate
* CONST_* kind defined for T.
*/
@@ -765,37 +808,37 @@ public:
const typename AttrKind::value_type& value);
/** Get the (singleton) type for Booleans. */
- inline TypeNode booleanType();
+ TypeNode booleanType();
/** Get the (singleton) type for integers. */
- inline TypeNode integerType();
+ TypeNode integerType();
/** Get the (singleton) type for reals. */
- inline TypeNode realType();
+ TypeNode realType();
/** Get the (singleton) type for strings. */
- inline TypeNode stringType();
+ TypeNode stringType();
/** Get the (singleton) type for RegExp. */
- inline TypeNode regExpType();
+ TypeNode regExpType();
/** Get the (singleton) type for rounding modes. */
- inline TypeNode roundingModeType();
+ TypeNode roundingModeType();
/** Get the bound var list type. */
- inline TypeNode boundVarListType();
+ TypeNode boundVarListType();
/** Get the instantiation pattern type. */
- inline TypeNode instPatternType();
+ TypeNode instPatternType();
/** Get the instantiation pattern type. */
- inline TypeNode instPatternListType();
+ TypeNode instPatternListType();
/**
* Get the (singleton) type for builtin operators (that is, the type
* of the Node returned from Node::getOperator() when the operator
* is built-in, like EQUAL). */
- inline TypeNode builtinOperatorType();
+ TypeNode builtinOperatorType();
/**
* Make a function type from domain to range.
@@ -863,11 +906,11 @@ public:
/** Make the type of floating-point with <code>exp</code> bit exponent and
<code>sig</code> bit significand */
- inline TypeNode mkFloatingPointType(unsigned exp, unsigned sig);
- inline TypeNode mkFloatingPointType(FloatingPointSize fs);
+ TypeNode mkFloatingPointType(unsigned exp, unsigned sig);
+ TypeNode mkFloatingPointType(FloatingPointSize fs);
/** Make the type of bitvectors of size <code>size</code> */
- inline TypeNode mkBitVectorType(unsigned size);
+ TypeNode mkBitVectorType(unsigned size);
/** Make the type of arrays with the given parameterization */
inline TypeNode mkArrayType(TypeNode indexType, TypeNode constituentType);
@@ -875,11 +918,67 @@ public:
/** Make the type of set with the given parameterization */
inline TypeNode mkSetType(TypeNode elementType);
+ /** Make the type of bags with the given parameterization */
+ TypeNode mkBagType(TypeNode elementType);
+
/** Make the type of sequences with the given parameterization */
TypeNode mkSequenceType(TypeNode elementType);
- /** Make a type representing a constructor with the given parameterization */
- TypeNode mkConstructorType(const DatatypeConstructor& constructor, TypeNode range);
+ /** Bits for use in mkDatatypeType() flags.
+ *
+ * DATATYPE_FLAG_PLACEHOLDER indicates that the type should not be printed
+ * out as a definition, for example, in models or during dumping.
+ */
+ enum
+ {
+ DATATYPE_FLAG_NONE = 0,
+ DATATYPE_FLAG_PLACEHOLDER = 1
+ }; /* enum */
+
+ /** Make a type representing the given datatype. */
+ TypeNode mkDatatypeType(DType& datatype, uint32_t flags = DATATYPE_FLAG_NONE);
+
+ /**
+ * Make a set of types representing the given datatypes, which may be
+ * mutually recursive.
+ */
+ std::vector<TypeNode> mkMutualDatatypeTypes(
+ const std::vector<DType>& datatypes, uint32_t flags = DATATYPE_FLAG_NONE);
+
+ /**
+ * Make a set of types representing the given datatypes, which may
+ * be mutually recursive. unresolvedTypes is a set of SortTypes
+ * that were used as placeholders in the Datatypes for the Datatypes
+ * of the same name. This is just a more complicated version of the
+ * above mkMutualDatatypeTypes() function, but is required to handle
+ * complex types.
+ *
+ * For example, unresolvedTypes might contain the single sort "list"
+ * (with that name reported from SortType::getName()). The
+ * datatypes list might have the single datatype
+ *
+ * DATATYPE
+ * list = cons(car:ARRAY INT OF list, cdr:list) | nil;
+ * END;
+ *
+ * To represent the Type of the array, the user had to create a
+ * placeholder type (an uninterpreted sort) to stand for "list" in
+ * the type of "car". It is this placeholder sort that should be
+ * passed in unresolvedTypes. If the datatype was of the simpler
+ * form:
+ *
+ * DATATYPE
+ * list = cons(car:list, cdr:list) | nil;
+ * END;
+ *
+ * then no complicated Type needs to be created, and the above,
+ * simpler form of mkMutualDatatypeTypes() is enough.
+ */
+ std::vector<TypeNode> mkMutualDatatypeTypes(
+ const std::vector<DType>& datatypes,
+ const std::set<TypeNode>& unresolvedTypes,
+ uint32_t flags = DATATYPE_FLAG_NONE);
+
/**
* Make a type representing a constructor with the given argument (subfield)
* types and return type range.
@@ -1030,56 +1129,6 @@ public:
}
};/* class NodeManagerScope */
-/** Get the (singleton) type for booleans. */
-inline TypeNode NodeManager::booleanType() {
- return TypeNode(mkTypeConst<TypeConstant>(BOOLEAN_TYPE));
-}
-
-/** Get the (singleton) type for integers. */
-inline TypeNode NodeManager::integerType() {
- return TypeNode(mkTypeConst<TypeConstant>(INTEGER_TYPE));
-}
-
-/** Get the (singleton) type for reals. */
-inline TypeNode NodeManager::realType() {
- return TypeNode(mkTypeConst<TypeConstant>(REAL_TYPE));
-}
-
-/** Get the (singleton) type for strings. */
-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 (singleton) type for rounding modes. */
-inline TypeNode NodeManager::roundingModeType() {
- return TypeNode(mkTypeConst<TypeConstant>(ROUNDINGMODE_TYPE));
-}
-
-/** Get the bound var list type. */
-inline TypeNode NodeManager::boundVarListType() {
- return TypeNode(mkTypeConst<TypeConstant>(BOUND_VAR_LIST_TYPE));
-}
-
-/** Get the instantiation pattern type. */
-inline TypeNode NodeManager::instPatternType() {
- return TypeNode(mkTypeConst<TypeConstant>(INST_PATTERN_TYPE));
-}
-
-/** Get the instantiation pattern type. */
-inline TypeNode NodeManager::instPatternListType() {
- return TypeNode(mkTypeConst<TypeConstant>(INST_PATTERN_LIST_TYPE));
-}
-
-/** Get the (singleton) type for builtin operators. */
-inline TypeNode NodeManager::builtinOperatorType() {
- return TypeNode(mkTypeConst<TypeConstant>(BUILTIN_OPERATOR_TYPE));
-}
-
inline TypeNode NodeManager::mkSExprType(const std::vector<TypeNode>& types) {
std::vector<TypeNode> typeNodes;
for (unsigned i = 0; i < types.size(); ++ i) {
@@ -1088,18 +1137,6 @@ inline TypeNode NodeManager::mkSExprType(const std::vector<TypeNode>& types) {
return mkTypeNode(kind::SEXPR_TYPE, typeNodes);
}
-inline TypeNode NodeManager::mkBitVectorType(unsigned size) {
- return TypeNode(mkTypeConst<BitVectorSize>(BitVectorSize(size)));
-}
-
-inline TypeNode NodeManager::mkFloatingPointType(unsigned exp, unsigned sig) {
- return TypeNode(mkTypeConst<FloatingPointSize>(FloatingPointSize(exp,sig)));
-}
-
-inline TypeNode NodeManager::mkFloatingPointType(FloatingPointSize fs) {
- return TypeNode(mkTypeConst<FloatingPointSize>(fs));
-}
-
inline TypeNode NodeManager::mkArrayType(TypeNode indexType,
TypeNode constituentType) {
CheckArgument(!indexType.isNull(), indexType,
@@ -1305,6 +1342,34 @@ inline Node NodeManager::mkNode(Kind kind,
}
template <bool ref_count>
+Node NodeManager::mkAnd(const std::vector<NodeTemplate<ref_count> >& children)
+{
+ if (children.empty())
+ {
+ return mkConst(true);
+ }
+ else if (children.size() == 1)
+ {
+ return children[0];
+ }
+ return mkNode(kind::AND, children);
+}
+
+template <bool ref_count>
+Node NodeManager::mkOr(const std::vector<NodeTemplate<ref_count> >& children)
+{
+ if (children.empty())
+ {
+ return mkConst(false);
+ }
+ else if (children.size() == 1)
+ {
+ return children[0];
+ }
+ return mkNode(kind::OR, children);
+}
+
+template <bool ref_count>
inline Node* NodeManager::mkNodePtr(Kind kind,
const std::vector<NodeTemplate<ref_count> >&
children) {
@@ -1484,6 +1549,9 @@ TypeNode NodeManager::mkTypeConst(const T& val) {
template <class NodeClass, class T>
NodeClass NodeManager::mkConstInternal(const T& val) {
+ // This method indirectly calls `NodeValue::inc()`, which relies on having
+ // the correct `NodeManager` in scope.
+ NodeManagerScope nms(this);
// typedef typename kind::metakind::constantMap<T>::OwningTheory theory_t;
NVStorage<1> nvStorage;
diff --git a/src/expr/node_manager_attributes.h b/src/expr/node_manager_attributes.h
index be1fe5a6b..ba8df6fd0 100644
--- a/src/expr/node_manager_attributes.h
+++ b/src/expr/node_manager_attributes.h
@@ -5,7 +5,7 @@
** Morgan Deters, Kshitij Bansal
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/node_self_iterator.h b/src/expr/node_self_iterator.h
index ae76434af..118449b80 100644
--- a/src/expr/node_self_iterator.h
+++ b/src/expr/node_self_iterator.h
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/node_traversal.cpp b/src/expr/node_traversal.cpp
index 5968c4348..75a11eac7 100644
--- a/src/expr/node_traversal.cpp
+++ b/src/expr/node_traversal.cpp
@@ -5,7 +5,7 @@
** Alex Ozdemir, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/node_traversal.h b/src/expr/node_traversal.h
index 586cbb64d..e7e49db45 100644
--- a/src/expr/node_traversal.h
+++ b/src/expr/node_traversal.h
@@ -5,7 +5,7 @@
** Alex Ozdemir, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -17,7 +17,6 @@
#ifndef CVC4__EXPR__NODE_TRAVERSAL_H
#define CVC4__EXPR__NODE_TRAVERSAL_H
-#include <cstddef>
#include <functional>
#include <iterator>
#include <unordered_map>
diff --git a/src/expr/node_trie.cpp b/src/expr/node_trie.cpp
index da1e6a001..58ad36da9 100644
--- a/src/expr/node_trie.cpp
+++ b/src/expr/node_trie.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/node_trie.h b/src/expr/node_trie.h
index c1c7fdfc0..d783000ee 100644
--- a/src/expr/node_trie.h
+++ b/src/expr/node_trie.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/node_value.cpp b/src/expr/node_value.cpp
index 908f93104..8ceb5476a 100644
--- a/src/expr/node_value.cpp
+++ b/src/expr/node_value.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Aina Niemetz, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -39,19 +39,21 @@ string NodeValue::toString() const {
OutputLanguage outlang = (this == &null()) ? language::output::LANG_AUTO
: options::outputLanguage();
- toStream(ss, -1, false, false, outlang);
+ toStream(ss, -1, false, outlang);
return ss.str();
}
-void NodeValue::toStream(std::ostream& out, int toDepth, bool types, size_t dag,
- OutputLanguage language) const {
+void NodeValue::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
// Ensure that this node value is live for the length of this call.
// It really breaks things badly if we don't have a nonzero ref
// count, even just for printing.
RefCountGuard guard(this);
- Printer::getPrinter(language)->toStream(out, TNode(this), toDepth, types,
- dag);
+ Printer::getPrinter(language)->toStream(out, TNode(this), toDepth, dag);
}
void NodeValue::printAst(std::ostream& out, int ind) const {
diff --git a/src/expr/node_value.h b/src/expr/node_value.h
index fdc07b1ef..0635e983b 100644
--- a/src/expr/node_value.h
+++ b/src/expr/node_value.h
@@ -5,7 +5,7 @@
** Morgan Deters, Aina Niemetz, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -26,8 +26,6 @@
#ifndef CVC4__EXPR__NODE_VALUE_H
#define CVC4__EXPR__NODE_VALUE_H
-#include <stdint.h>
-
#include <iterator>
#include <string>
@@ -235,7 +233,6 @@ class NodeValue
void toStream(std::ostream& out,
int toDepth = -1,
- bool types = false,
size_t dag = 1,
OutputLanguage = language::output::LANG_AUTO) const;
@@ -517,7 +514,6 @@ inline T NodeValue::iterator<T>::operator*() const {
inline std::ostream& operator<<(std::ostream& out, const NodeValue& nv) {
nv.toStream(out,
Node::setdepth::getDepth(out),
- Node::printtypes::getPrintTypes(out),
Node::dag::getDag(out),
Node::setlanguage::getLanguage(out));
return out;
@@ -533,7 +529,6 @@ inline std::ostream& operator<<(std::ostream& out, const NodeValue& nv) {
*/
static void __attribute__((used)) debugPrintNodeValue(const expr::NodeValue* nv) {
Warning() << Node::setdepth(-1)
- << Node::printtypes(false)
<< Node::dag(true)
<< Node::setlanguage(language::output::LANG_AST)
<< *nv << std::endl;
@@ -541,7 +536,6 @@ static void __attribute__((used)) debugPrintNodeValue(const expr::NodeValue* nv)
}
static void __attribute__((used)) debugPrintNodeValueNoDag(const expr::NodeValue* nv) {
Warning() << Node::setdepth(-1)
- << Node::printtypes(false)
<< Node::dag(false)
<< Node::setlanguage(language::output::LANG_AST)
<< *nv << std::endl;
diff --git a/src/expr/node_visitor.h b/src/expr/node_visitor.h
index c960dde09..1ffd39406 100644
--- a/src/expr/node_visitor.h
+++ b/src/expr/node_visitor.h
@@ -5,7 +5,7 @@
** Dejan Jovanovic, Andrew Reynolds, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/proof.cpp b/src/expr/proof.cpp
index 20e8e29e2..94ca26dd6 100644
--- a/src/expr/proof.cpp
+++ b/src/expr/proof.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,8 +18,8 @@ using namespace CVC4::kind;
namespace CVC4 {
-CDProof::CDProof(ProofNodeManager* pnm, context::Context* c)
- : d_manager(pnm), d_context(), d_nodes(c ? c : &d_context)
+CDProof::CDProof(ProofNodeManager* pnm, context::Context* c, std::string name)
+ : d_manager(pnm), d_context(), d_nodes(c ? c : &d_context), d_name(name)
{
}
@@ -111,9 +111,13 @@ bool CDProof::addStep(Node expected,
bool ensureChildren,
CDPOverwrite opolicy)
{
- Trace("cdproof") << "CDProof::addStep: " << id << " " << expected
- << ", ensureChildren = " << ensureChildren
+ Trace("cdproof") << "CDProof::addStep: " << identify() << " : " << id << " "
+ << expected << ", ensureChildren = " << ensureChildren
<< ", overwrite policy = " << opolicy << std::endl;
+ Trace("cdproof-debug") << "CDProof::addStep: " << identify()
+ << " : children: " << children << "\n";
+ Trace("cdproof-debug") << "CDProof::addStep: " << identify()
+ << " : args: " << args << "\n";
// We must always provide expected to this method
Assert(!expected.isNull());
@@ -404,7 +408,8 @@ bool CDProof::isSame(TNode f, TNode g)
// symmetric equality
return true;
}
- if (fk == NOT && gk == NOT && f[0][0] == g[0][1] && f[0][1] == g[0][0])
+ if (fk == NOT && gk == NOT && f[0].getKind() == EQUAL
+ && g[0].getKind() == EQUAL && f[0][0] == g[0][1] && f[0][1] == g[0][0])
{
// symmetric disequality
return true;
@@ -424,6 +429,6 @@ Node CDProof::getSymmFact(TNode f)
return polarity ? symFact : symFact.notNode();
}
-std::string CDProof::identify() const { return "CDProof"; }
+std::string CDProof::identify() const { return d_name; }
} // namespace CVC4
diff --git a/src/expr/proof.h b/src/expr/proof.h
index ff6b8bbf1..b5bcc7d50 100644
--- a/src/expr/proof.h
+++ b/src/expr/proof.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -134,7 +134,9 @@ namespace CVC4 {
class CDProof : public ProofGenerator
{
public:
- CDProof(ProofNodeManager* pnm, context::Context* c = nullptr);
+ CDProof(ProofNodeManager* pnm,
+ context::Context* c = nullptr,
+ std::string name = "CDProof");
virtual ~CDProof();
/**
* Make proof for fact.
@@ -224,6 +226,8 @@ class CDProof : public ProofGenerator
* f suffices as a proof for g according to this class.
*/
static bool isSame(TNode f, TNode g);
+ /** Get proof for fact, or nullptr if it does not exist. */
+ std::shared_ptr<ProofNode> getProof(Node fact) const;
/**
* Get symmetric fact (a g such that isSame returns true for isSame(f,g)), or
* null if none exist.
@@ -241,8 +245,8 @@ class CDProof : public ProofGenerator
context::Context d_context;
/** The nodes of the proof */
NodeProofNodeMap d_nodes;
- /** Get proof for fact, or nullptr if it does not exist. */
- std::shared_ptr<ProofNode> getProof(Node fact) const;
+ /** Name identifier */
+ std::string d_name;
/** Ensure fact sym */
std::shared_ptr<ProofNode> getProofSymm(Node fact);
/**
diff --git a/src/expr/proof_checker.cpp b/src/expr/proof_checker.cpp
index 8f786052b..a60a82b60 100644
--- a/src/expr/proof_checker.cpp
+++ b/src/expr/proof_checker.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -15,6 +15,7 @@
#include "expr/proof_checker.h"
#include "expr/skolem_manager.h"
+#include "options/smt_options.h"
#include "smt/smt_statistics_registry.h"
using namespace CVC4::kind;
@@ -29,39 +30,6 @@ Node ProofRuleChecker::check(PfRule id,
return checkInternal(id, children, args);
}
-Node ProofRuleChecker::checkChildrenArg(PfRule id,
- const std::vector<Node>& children,
- Node arg)
-{
- return check(id, children, {arg});
-}
-Node ProofRuleChecker::checkChildren(PfRule id,
- const std::vector<Node>& children)
-{
- return check(id, children, {});
-}
-Node ProofRuleChecker::checkChild(PfRule id, Node child)
-{
- return check(id, {child}, {});
-}
-Node ProofRuleChecker::checkArg(PfRule id, Node arg)
-{
- return check(id, {}, {arg});
-}
-
-Node ProofRuleChecker::mkAnd(const std::vector<Node>& a)
-{
- if (a.empty())
- {
- return NodeManager::currentNM()->mkConst(true);
- }
- else if (a.size() == 1)
- {
- return a[0];
- }
- return NodeManager::currentNM()->mkNode(AND, a);
-}
-
bool ProofRuleChecker::getUInt32(TNode n, uint32_t& i)
{
// must be a non-negative integer constant that fits an unsigned int
@@ -85,6 +53,27 @@ bool ProofRuleChecker::getBool(TNode n, bool& b)
return false;
}
+bool ProofRuleChecker::getKind(TNode n, Kind& k)
+{
+ uint32_t i;
+ if (!getUInt32(n, i))
+ {
+ return false;
+ }
+ k = static_cast<Kind>(i);
+ return true;
+}
+
+Node ProofRuleChecker::mkKindNode(Kind k)
+{
+ if (k == UNDEFINED_KIND)
+ {
+ // UNDEFINED_KIND is negative, hence return null to avoid cast
+ return Node::null();
+ }
+ return NodeManager::currentNM()->mkConst(Rational(static_cast<uint32_t>(k)));
+}
+
ProofCheckerStatistics::ProofCheckerStatistics()
: d_ruleChecks("ProofCheckerStatistics::ruleChecks"),
d_totalRuleChecks("ProofCheckerStatistics::totalRuleChecks", 0)
@@ -149,8 +138,9 @@ Node ProofChecker::check(
Trace("pfcheck") << " expected: " << expected << std::endl;
std::stringstream out;
// we use trusted (null) checkers here, since we want the proof generation to
- // proceed without failing here.
- Node res = checkInternal(id, cchildren, args, expected, out, true);
+ // proceed without failing here. We always enable output since a failure
+ // implies that we will exit with the error message below.
+ Node res = checkInternal(id, cchildren, args, expected, out, true, true);
if (res.isNull())
{
Trace("pfcheck") << "ProofChecker::check: failed" << std::endl;
@@ -169,20 +159,25 @@ Node ProofChecker::checkDebug(PfRule id,
const char* traceTag)
{
std::stringstream out;
- // since we are debugging, we want to treat trusted (null) checkers as
- // a failure.
- Node res = checkInternal(id, cchildren, args, expected, out, false);
- Trace(traceTag) << "ProofChecker::checkDebug: " << id;
- if (res.isNull())
- {
- Trace(traceTag) << " failed, " << out.str() << std::endl;
- }
- else
+ bool traceEnabled = Trace.isOn(traceTag);
+ // Since we are debugging, we want to treat trusted (null) checkers as
+ // a failure. We only enable output if the trace is enabled for efficiency.
+ Node res =
+ checkInternal(id, cchildren, args, expected, out, false, traceEnabled);
+ if (traceEnabled)
{
- Trace(traceTag) << " success" << std::endl;
+ Trace(traceTag) << "ProofChecker::checkDebug: " << id;
+ if (res.isNull())
+ {
+ Trace(traceTag) << " failed, " << out.str() << std::endl;
+ }
+ else
+ {
+ Trace(traceTag) << " success" << std::endl;
+ }
+ Trace(traceTag) << "cchildren: " << cchildren << std::endl;
+ Trace(traceTag) << " args: " << args << std::endl;
}
- Trace(traceTag) << "cchildren: " << cchildren << std::endl;
- Trace(traceTag) << " args: " << args << std::endl;
return res;
}
@@ -191,13 +186,17 @@ Node ProofChecker::checkInternal(PfRule id,
const std::vector<Node>& args,
Node expected,
std::stringstream& out,
- bool useTrustedChecker)
+ bool useTrustedChecker,
+ bool enableOutput)
{
std::map<PfRule, ProofRuleChecker*>::iterator it = d_checker.find(id);
if (it == d_checker.end())
{
// no checker for the rule
- out << "no checker for rule " << id << std::endl;
+ if (enableOutput)
+ {
+ out << "no checker for rule " << id << std::endl;
+ }
return Node::null();
}
else if (it->second == nullptr)
@@ -210,7 +209,10 @@ Node ProofChecker::checkInternal(PfRule id,
}
else
{
- out << "trusted checker for rule " << id << std::endl;
+ if (enableOutput)
+ {
+ out << "trusted checker for rule " << id << std::endl;
+ }
return Node::null();
}
}
@@ -221,19 +223,42 @@ Node ProofChecker::checkInternal(PfRule id,
Node expectedw = expected;
if (res != expectedw)
{
- out << "result does not match expected value." << std::endl
- << " PfRule: " << id << std::endl;
- for (const Node& c : cchildren)
+ if (enableOutput)
{
- out << " child: " << c << std::endl;
+ out << "result does not match expected value." << std::endl
+ << " PfRule: " << id << std::endl;
+ for (const Node& c : cchildren)
+ {
+ out << " child: " << c << std::endl;
+ }
+ for (const Node& a : args)
+ {
+ out << " arg: " << a << std::endl;
+ }
+ out << " result: " << res << std::endl
+ << " expected: " << expected << std::endl;
}
- for (const Node& a : args)
+ // it did not match the given expectation, fail
+ return Node::null();
+ }
+ }
+ // fails if pedantic level is not met
+ if (options::proofNewEagerChecking())
+ {
+ std::stringstream serr;
+ if (isPedanticFailure(id, serr, enableOutput))
+ {
+ if (enableOutput)
{
- out << " arg: " << a << std::endl;
+ out << serr.str() << std::endl;
+ if (Trace.isOn("proof-new-pedantic"))
+ {
+ Trace("proof-new-pedantic")
+ << "Failed pedantic check for " << id << std::endl;
+ Trace("proof-new-pedantic") << "Expected: " << expected << std::endl;
+ out << "Expected: " << expected << std::endl;
+ }
}
- out << " result: " << res << std::endl
- << " expected: " << expected << std::endl;
- // it did not match the given expectation, fail
return Node::null();
}
}
@@ -253,6 +278,24 @@ void ProofChecker::registerChecker(PfRule id, ProofRuleChecker* psc)
d_checker[id] = psc;
}
+void ProofChecker::registerTrustedChecker(PfRule id,
+ ProofRuleChecker* psc,
+ uint32_t plevel)
+{
+ AlwaysAssert(plevel <= 10) << "ProofChecker::registerTrustedChecker: "
+ "pedantic level must be 0-10, got "
+ << plevel << " for " << id;
+ registerChecker(id, psc);
+ // overwrites if already there
+ if (d_plevel.find(id) != d_plevel.end())
+ {
+ Notice() << "ProofChecker::registerTrustedRule: already provided pedantic "
+ "level for "
+ << id << std::endl;
+ }
+ d_plevel[id] = plevel;
+}
+
ProofRuleChecker* ProofChecker::getCheckerFor(PfRule id)
{
std::map<PfRule, ProofRuleChecker*>::const_iterator it = d_checker.find(id);
@@ -263,4 +306,44 @@ ProofRuleChecker* ProofChecker::getCheckerFor(PfRule id)
return it->second;
}
+uint32_t ProofChecker::getPedanticLevel(PfRule id) const
+{
+ std::map<PfRule, uint32_t>::const_iterator itp = d_plevel.find(id);
+ if (itp != d_plevel.end())
+ {
+ return itp->second;
+ }
+ return 0;
+}
+
+bool ProofChecker::isPedanticFailure(PfRule id,
+ std::ostream& out,
+ bool enableOutput) const
+{
+ if (d_pclevel == 0)
+ {
+ return false;
+ }
+ std::map<PfRule, uint32_t>::const_iterator itp = d_plevel.find(id);
+ if (itp != d_plevel.end())
+ {
+ if (itp->second <= d_pclevel)
+ {
+ if (enableOutput)
+ {
+ out << "pedantic level for " << id << " not met (rule level is "
+ << itp->second << " which is at or below the pedantic level "
+ << d_pclevel << ")";
+ bool pedanticTraceEnabled = Trace.isOn("proof-new-pedantic");
+ if (!pedanticTraceEnabled)
+ {
+ out << ", use -t proof-new-pedantic for details";
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace CVC4
diff --git a/src/expr/proof_checker.h b/src/expr/proof_checker.h
index 65ad9f24d..ab9c24434 100644
--- a/src/expr/proof_checker.h
+++ b/src/expr/proof_checker.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -54,21 +54,15 @@ class ProofRuleChecker
Node check(PfRule id,
const std::vector<Node>& children,
const std::vector<Node>& args);
- /** Single arg version */
- Node checkChildrenArg(PfRule id, const std::vector<Node>& children, Node arg);
- /** No arg version */
- Node checkChildren(PfRule id, const std::vector<Node>& children);
- /** Single child only version */
- Node checkChild(PfRule id, Node child);
- /** Single argument only version */
- Node checkArg(PfRule id, Node arg);
-
- /** Make AND-kinded node with children a */
- static Node mkAnd(const std::vector<Node>& a);
+
/** get an index from a node, return false if we fail */
static bool getUInt32(TNode n, uint32_t& i);
/** get a Boolean from a node, return false if we fail */
static bool getBool(TNode n, bool& b);
+ /** get a Kind from a node, return false if we fail */
+ static bool getKind(TNode n, Kind& k);
+ /** Make a Kind into a node */
+ static Node mkKindNode(Kind k);
/** Register all rules owned by this rule checker into pc. */
virtual void registerTo(ProofChecker* pc) {}
@@ -106,7 +100,7 @@ class ProofCheckerStatistics
class ProofChecker
{
public:
- ProofChecker() {}
+ ProofChecker(uint32_t pclevel = 0) : d_pclevel(pclevel) {}
~ProofChecker() {}
/**
* Return the formula that is proven by proof node pn, or null if pn is not
@@ -156,25 +150,54 @@ class ProofChecker
const char* traceTag);
/** Indicate that psc is the checker for proof rule id */
void registerChecker(PfRule id, ProofRuleChecker* psc);
+ /**
+ * Indicate that id is a trusted rule with the given pedantic level, e.g.:
+ * 0: (mandatory) always a failure to use the given id
+ * 1: (major) failure on all (non-zero) pedantic levels
+ * 10: (minor) failure only on pedantic levels >= 10.
+ */
+ void registerTrustedChecker(PfRule id,
+ ProofRuleChecker* psc,
+ uint32_t plevel = 10);
/** get checker for */
ProofRuleChecker* getCheckerFor(PfRule id);
+ /**
+ * Get the pedantic level for id if it has been assigned a pedantic
+ * level via registerTrustedChecker above, or zero otherwise.
+ */
+ uint32_t getPedanticLevel(PfRule id) const;
+
+ /**
+ * Is pedantic failure? If so, we return true and write a debug message on the
+ * output stream out if enableOutput is true.
+ */
+ bool isPedanticFailure(PfRule id,
+ std::ostream& out,
+ bool enableOutput = true) const;
+
private:
/** statistics class */
ProofCheckerStatistics d_stats;
- /** Maps proof steps to their checker */
+ /** Maps proof rules to their checker */
std::map<PfRule, ProofRuleChecker*> d_checker;
+ /** Maps proof trusted rules to their pedantic level */
+ std::map<PfRule, uint32_t> d_plevel;
+ /** The pedantic level of this checker */
+ uint32_t d_pclevel;
/**
* Check internal. This is used by check and checkDebug above. It writes
- * checking errors on out. We treat trusted checkers (nullptr in the range
- * of the map d_checker) as failures if useTrustedChecker = false.
+ * checking errors on out when enableOutput is true. We treat trusted checkers
+ * (nullptr in the range of the map d_checker) as failures if
+ * useTrustedChecker = false.
*/
Node checkInternal(PfRule id,
const std::vector<Node>& cchildren,
const std::vector<Node>& args,
Node expected,
std::stringstream& out,
- bool useTrustedChecker);
+ bool useTrustedChecker,
+ bool enableOutput);
};
} // namespace CVC4
diff --git a/src/expr/proof_generator.cpp b/src/expr/proof_generator.cpp
index fd8f50415..68a819122 100644
--- a/src/expr/proof_generator.cpp
+++ b/src/expr/proof_generator.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -15,6 +15,8 @@
#include "expr/proof_generator.h"
#include "expr/proof.h"
+#include "expr/proof_node_algorithm.h"
+#include "options/smt_options.h"
namespace CVC4 {
@@ -41,7 +43,10 @@ std::shared_ptr<ProofNode> ProofGenerator::getProofFor(Node f)
return nullptr;
}
-bool ProofGenerator::addProofTo(Node f, CDProof* pf, CDPOverwrite opolicy)
+bool ProofGenerator::addProofTo(Node f,
+ CDProof* pf,
+ CDPOverwrite opolicy,
+ bool doCopy)
{
Trace("pfgen") << "ProofGenerator::addProofTo: " << f << "..." << std::endl;
Assert(pf != nullptr);
@@ -49,14 +54,8 @@ bool ProofGenerator::addProofTo(Node f, CDProof* pf, CDPOverwrite opolicy)
std::shared_ptr<ProofNode> apf = getProofFor(f);
if (apf != nullptr)
{
- if (Trace.isOn("pfgen"))
- {
- std::stringstream ss;
- apf->printDebug(ss);
- Trace("pfgen") << "...got proof " << ss.str() << std::endl;
- }
- // Add the proof, without deep copying.
- if (pf->addProof(apf, opolicy, false))
+ Trace("pfgen") << "...got proof " << *apf.get() << std::endl;
+ if (pf->addProof(apf, opolicy, doCopy))
{
Trace("pfgen") << "...success!" << std::endl;
return true;
@@ -71,4 +70,159 @@ bool ProofGenerator::addProofTo(Node f, CDProof* pf, CDPOverwrite opolicy)
return false;
}
+/**
+ * Ensure closed with respect to assumptions, internal version, which
+ * generalizes the check for a proof generator or a proof node.
+ */
+void ensureClosedWrtInternal(Node proven,
+ ProofGenerator* pg,
+ ProofNode* pnp,
+ const std::vector<Node>& assumps,
+ const char* c,
+ const char* ctx,
+ bool reqGen)
+{
+ if (!options::proofNew())
+ {
+ // proofs not enabled, do not do check
+ return;
+ }
+ bool isTraceDebug = Trace.isOn(c);
+ if (!options::proofNewEagerChecking() && !isTraceDebug)
+ {
+ // trace is off and proof new eager checking is off, do not do check
+ return;
+ }
+ std::stringstream sdiag;
+ bool isTraceOn = Trace.isOn(c);
+ if (!isTraceOn)
+ {
+ sdiag << ", use -t " << c << " for details";
+ }
+ bool dumpProofTraceOn = Trace.isOn("dump-proof-error");
+ if (!dumpProofTraceOn)
+ {
+ sdiag << ", use -t dump-proof-error for details on proof";
+ }
+ // get the proof node in question, which is either provided or built by the
+ // proof generator
+ std::shared_ptr<ProofNode> pn;
+ std::stringstream ss;
+ if (pnp != nullptr)
+ {
+ Assert(pg == nullptr);
+ ss << "ProofNode in context " << ctx;
+ }
+ else
+ {
+ ss << "ProofGenerator: " << (pg == nullptr ? "null" : pg->identify())
+ << " in context " << ctx;
+ if (pg == nullptr)
+ {
+ // only failure if flag is true
+ if (reqGen)
+ {
+ Unreachable() << "...ensureClosed: no generator in context " << ctx
+ << sdiag.str();
+ }
+ }
+ else
+ {
+ Assert(!proven.isNull());
+ pn = pg->getProofFor(proven);
+ pnp = pn.get();
+ }
+ }
+ Trace(c) << "=== ensureClosed: " << ss.str() << std::endl;
+ Trace(c) << "Proven: " << proven << std::endl;
+ if (pnp == nullptr)
+ {
+ if (pg == nullptr)
+ {
+ // did not require generator
+ Assert(!reqGen);
+ Trace(c) << "...ensureClosed: no generator in context " << ctx
+ << std::endl;
+ return;
+ }
+ }
+ // if we don't have a proof node, a generator failed
+ if (pnp == nullptr)
+ {
+ Assert(pg != nullptr);
+ AlwaysAssert(false) << "...ensureClosed: null proof from " << ss.str()
+ << sdiag.str();
+ }
+ std::vector<Node> fassumps;
+ expr::getFreeAssumptions(pnp, fassumps);
+ bool isClosed = true;
+ std::stringstream ssf;
+ for (const Node& fa : fassumps)
+ {
+ if (std::find(assumps.begin(), assumps.end(), fa) == assumps.end())
+ {
+ isClosed = false;
+ ssf << "- " << fa << std::endl;
+ }
+ }
+ if (!isClosed)
+ {
+ Trace(c) << "Free assumptions:" << std::endl;
+ Trace(c) << ssf.str();
+ if (!assumps.empty())
+ {
+ Trace(c) << "Expected assumptions:" << std::endl;
+ for (const Node& a : assumps)
+ {
+ Trace(c) << "- " << a << std::endl;
+ }
+ }
+ if (dumpProofTraceOn)
+ {
+ Trace("dump-proof-error") << " Proof: " << *pnp << std::endl;
+ }
+ }
+ AlwaysAssert(isClosed) << "...ensureClosed: open proof from " << ss.str()
+ << sdiag.str();
+ Trace(c) << "...ensureClosed: success" << std::endl;
+ Trace(c) << "====" << std::endl;
+}
+
+void pfgEnsureClosed(Node proven,
+ ProofGenerator* pg,
+ const char* c,
+ const char* ctx,
+ bool reqGen)
+{
+ Assert(!proven.isNull());
+ // proof generator may be null
+ std::vector<Node> assumps;
+ ensureClosedWrtInternal(proven, pg, nullptr, assumps, c, ctx, reqGen);
+}
+
+void pfgEnsureClosedWrt(Node proven,
+ ProofGenerator* pg,
+ const std::vector<Node>& assumps,
+ const char* c,
+ const char* ctx,
+ bool reqGen)
+{
+ Assert(!proven.isNull());
+ // proof generator may be null
+ ensureClosedWrtInternal(proven, pg, nullptr, assumps, c, ctx, reqGen);
+}
+
+void pfnEnsureClosed(ProofNode* pn, const char* c, const char* ctx)
+{
+ ensureClosedWrtInternal(Node::null(), nullptr, pn, {}, c, ctx, false);
+}
+
+void pfnEnsureClosedWrt(ProofNode* pn,
+ const std::vector<Node>& assumps,
+ const char* c,
+ const char* ctx)
+{
+ ensureClosedWrtInternal(Node::null(), nullptr, pn, assumps, c, ctx, false);
+}
+
} // namespace CVC4
diff --git a/src/expr/proof_generator.h b/src/expr/proof_generator.h
index 35f94194f..6e6316356 100644
--- a/src/expr/proof_generator.h
+++ b/src/expr/proof_generator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -82,11 +82,13 @@ class ProofGenerator
* @param f The fact to get the proof for.
* @param pf The CDProof object to add the proof to.
* @param opolicy The overwrite policy for adding to pf.
+ * @param doCopy Whether to do a deep copy of the proof steps into pf.
* @return True if this call was sucessful.
*/
virtual bool addProofTo(Node f,
CDProof* pf,
- CDPOverwrite opolicy = CDPOverwrite::ASSUME_ONLY);
+ CDPOverwrite opolicy = CDPOverwrite::ASSUME_ONLY,
+ bool doCopy = false);
/**
* Can we give the proof for formula f? This is used for debugging. This
* returns false if the generator cannot provide a proof of formula f.
@@ -105,6 +107,49 @@ class ProofGenerator
virtual std::string identify() const = 0;
};
+/**
+ * Debug check closed on Trace c. Context ctx is string for debugging.
+ * This method throws an assertion failure if pg cannot provide a closed
+ * proof for fact proven. This is checked only if --proof-new-eager-checking
+ * is enabled or the Trace c is enabled.
+ *
+ * @param reqGen Whether we consider a null generator to be a failure.
+ */
+void pfgEnsureClosed(Node proven,
+ ProofGenerator* pg,
+ const char* c,
+ const char* ctx,
+ bool reqGen = true);
+
+/**
+ * Debug check closed with Trace c. Context ctx is string for debugging and
+ * assumps is the set of allowed open assertions. This method throws an
+ * assertion failure if pg cannot provide a proof for fact proven whose
+ * free assumptions are contained in assumps.
+ *
+ * @param reqGen Whether we consider a null generator to be a failure.
+ */
+void pfgEnsureClosedWrt(Node proven,
+ ProofGenerator* pg,
+ const std::vector<Node>& assumps,
+ const char* c,
+ const char* ctx,
+ bool reqGen = true);
+
+/**
+ * Debug check closed with Trace c, proof node versions. This gives an
+ * assertion failure if pn is not closed. Detailed information is printed
+ * on trace c. Context ctx is a string used for debugging.
+ */
+void pfnEnsureClosed(ProofNode* pn, const char* c, const char* ctx);
+/**
+ * Same as above, but throws an assertion failure only if the free assumptions
+ * of pn are not contained in assumps.
+ */
+void pfnEnsureClosedWrt(ProofNode* pn,
+ const std::vector<Node>& assumps,
+ const char* c,
+ const char* ctx);
} // namespace CVC4
#endif /* CVC4__EXPR__PROOF_GENERATOR_H */
diff --git a/src/expr/proof_node.cpp b/src/expr/proof_node.cpp
index d817cbd65..3bef451ee 100644
--- a/src/expr/proof_node.cpp
+++ b/src/expr/proof_node.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -75,4 +75,10 @@ void ProofNode::printDebug(std::ostream& os) const
os << ps;
}
+std::ostream& operator<<(std::ostream& out, const ProofNode& pn)
+{
+ pn.printDebug(out);
+ return out;
+}
+
} // namespace CVC4
diff --git a/src/expr/proof_node.h b/src/expr/proof_node.h
index bca86f44f..6d7db7b25 100644
--- a/src/expr/proof_node.h
+++ b/src/expr/proof_node.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,6 +25,12 @@
namespace CVC4 {
class ProofNodeManager;
+class ProofNode;
+
+struct ProofNodeHashFunction
+{
+ inline size_t operator()(std::shared_ptr<ProofNode> pfn) const;
+}; /* struct ProofNodeHashFunction */
/** A node in a proof
*
@@ -117,6 +123,21 @@ class ProofNode
Node d_proven;
};
+inline size_t ProofNodeHashFunction::operator()(
+ std::shared_ptr<ProofNode> pfn) const
+{
+ return pfn->getResult().getId() + static_cast<unsigned>(pfn->getRule());
+}
+
+/**
+ * Serializes a given proof node to the given stream.
+ *
+ * @param out the output stream to use
+ * @param pn the proof node to output to the stream
+ * @return the stream
+ */
+std::ostream& operator<<(std::ostream& out, const ProofNode& pn);
+
} // namespace CVC4
#endif /* CVC4__EXPR__PROOF_NODE_H */
diff --git a/src/expr/proof_node_algorithm.cpp b/src/expr/proof_node_algorithm.cpp
index 45dc2d995..b21bdec23 100644
--- a/src/expr/proof_node_algorithm.cpp
+++ b/src/expr/proof_node_algorithm.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,22 +19,27 @@ namespace expr {
void getFreeAssumptions(ProofNode* pn, std::vector<Node>& assump)
{
- std::map<Node, std::vector<ProofNode*>> amap;
- getFreeAssumptionsMap(pn, amap);
- for (const std::pair<const Node, std::vector<ProofNode*>>& p : amap)
+ std::map<Node, std::vector<std::shared_ptr<ProofNode>>> amap;
+ std::shared_ptr<ProofNode> spn = std::make_shared<ProofNode>(
+ pn->getRule(), pn->getChildren(), pn->getArguments());
+ getFreeAssumptionsMap(spn, amap);
+ for (const std::pair<const Node, std::vector<std::shared_ptr<ProofNode>>>& p :
+ amap)
{
assump.push_back(p.first);
}
}
-void getFreeAssumptionsMap(ProofNode* pn,
- std::map<Node, std::vector<ProofNode*>>& amap)
+void getFreeAssumptionsMap(
+ std::shared_ptr<ProofNode> pn,
+ std::map<Node, std::vector<std::shared_ptr<ProofNode>>>& amap)
{
// proof should not be cyclic
// visited set false after preorder traversal, true after postorder traversal
std::unordered_map<ProofNode*, bool> visited;
std::unordered_map<ProofNode*, bool>::iterator it;
- std::vector<ProofNode*> visit;
+ std::vector<std::shared_ptr<ProofNode>> visit;
+ std::vector<std::shared_ptr<ProofNode>> traversing;
// Maps a bound assumption to the number of bindings it is under
// e.g. in (SCOPE (SCOPE (ASSUME x) (x y)) (y)), y would be mapped to 2 at
// (ASSUME x), and x would be mapped to 1.
@@ -54,20 +59,20 @@ void getFreeAssumptionsMap(ProofNode* pn,
// after postvisiting SCOPE2: {}
//
std::unordered_map<Node, uint32_t, NodeHashFunction> scopeDepth;
- ProofNode* cur;
+ std::shared_ptr<ProofNode> cur;
visit.push_back(pn);
do
{
cur = visit.back();
visit.pop_back();
- it = visited.find(cur);
+ it = visited.find(cur.get());
const std::vector<Node>& cargs = cur->getArguments();
if (it == visited.end())
{
- visited[cur] = true;
PfRule id = cur->getRule();
if (id == PfRule::ASSUME)
{
+ visited[cur.get()] = true;
Assert(cargs.size() == 1);
Node f = cargs[0];
if (!scopeDepth.count(f))
@@ -85,34 +90,84 @@ void getFreeAssumptionsMap(ProofNode* pn,
scopeDepth[a] += 1;
}
// will need to unbind the variables below
- visited[cur] = false;
}
// The following loop cannot be merged with the loop above because the
// same subproof
+ visited[cur.get()] = false;
+ visit.push_back(cur);
+ traversing.push_back(cur);
const std::vector<std::shared_ptr<ProofNode>>& cs = cur->getChildren();
for (const std::shared_ptr<ProofNode>& cp : cs)
{
- visit.push_back(cp.get());
+ if (std::find(traversing.begin(), traversing.end(), cp)
+ != traversing.end())
+ {
+ Unhandled() << "getFreeAssumptionsMap: cyclic proof! (use "
+ "--proof-new-eager-checking)"
+ << std::endl;
+ }
+ visit.push_back(cp);
}
}
}
else if (!it->second)
{
- Assert(cur->getRule() == PfRule::SCOPE);
- // unbind its assumptions
- for (const Node& a : cargs)
+ Assert(!traversing.empty());
+ traversing.pop_back();
+ visited[cur.get()] = true;
+ if (cur->getRule() == PfRule::SCOPE)
{
- auto scopeCt = scopeDepth.find(a);
- Assert(scopeCt != scopeDepth.end());
- scopeCt->second -= 1;
- if (scopeCt->second == 0)
+ // unbind its assumptions
+ for (const Node& a : cargs)
{
- scopeDepth.erase(scopeCt);
+ auto scopeCt = scopeDepth.find(a);
+ Assert(scopeCt != scopeDepth.end());
+ scopeCt->second -= 1;
+ if (scopeCt->second == 0)
+ {
+ scopeDepth.erase(scopeCt);
+ }
}
}
}
} while (!visit.empty());
}
+bool containsSubproof(ProofNode* pn, ProofNode* pnc)
+{
+ std::unordered_set<const ProofNode*> visited;
+ return containsSubproof(pn, pnc, visited);
+}
+
+bool containsSubproof(ProofNode* pn,
+ ProofNode* pnc,
+ std::unordered_set<const ProofNode*>& visited)
+{
+ std::unordered_map<const ProofNode*, bool>::iterator it;
+ std::vector<const ProofNode*> visit;
+ visit.push_back(pn);
+ const ProofNode* cur;
+ while (!visit.empty())
+ {
+ cur = visit.back();
+ visit.pop_back();
+ if (visited.find(cur) == visited.end())
+ {
+ visited.insert(cur);
+ if (cur == pnc)
+ {
+ return true;
+ }
+ const std::vector<std::shared_ptr<ProofNode>>& children =
+ cur->getChildren();
+ for (const std::shared_ptr<ProofNode>& cp : children)
+ {
+ visit.push_back(cp.get());
+ }
+ }
+ }
+ return false;
+}
+
} // namespace expr
} // namespace CVC4
diff --git a/src/expr/proof_node_algorithm.h b/src/expr/proof_node_algorithm.h
index bc44d7314..d6bd1963c 100644
--- a/src/expr/proof_node_algorithm.h
+++ b/src/expr/proof_node_algorithm.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -49,8 +49,23 @@ void getFreeAssumptions(ProofNode* pn, std::vector<Node>& assump);
* @param amap The mapping to add the free asumptions of pn and their
* corresponding proof nodes to.
*/
-void getFreeAssumptionsMap(ProofNode* pn,
- std::map<Node, std::vector<ProofNode*>>& amap);
+void getFreeAssumptionsMap(
+ std::shared_ptr<ProofNode> pn,
+ std::map<Node, std::vector<std::shared_ptr<ProofNode>>>& amap);
+
+/**
+ * @return true if pn contains pnc.
+ */
+bool containsSubproof(ProofNode* pn, ProofNode* pnc);
+
+/**
+ * Same as above, with a visited cache.
+ *
+ * @return true if pn contains pnc.
+ */
+bool containsSubproof(ProofNode* pn,
+ ProofNode* pnc,
+ std::unordered_set<const ProofNode*>& visited);
} // namespace expr
} // namespace CVC4
diff --git a/src/expr/proof_node_manager.cpp b/src/expr/proof_node_manager.cpp
index 078e918b8..4682bbebb 100644
--- a/src/expr/proof_node_manager.cpp
+++ b/src/expr/proof_node_manager.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,12 +16,18 @@
#include "expr/proof.h"
#include "expr/proof_node_algorithm.h"
+#include "options/smt_options.h"
+#include "theory/rewriter.h"
using namespace CVC4::kind;
namespace CVC4 {
-ProofNodeManager::ProofNodeManager(ProofChecker* pc) : d_checker(pc) {}
+ProofNodeManager::ProofNodeManager(ProofChecker* pc)
+ : d_checker(pc)
+{
+ d_true = NodeManager::currentNM()->mkConst(true);
+}
std::shared_ptr<ProofNode> ProofNodeManager::mkNode(
PfRule id,
@@ -29,6 +35,8 @@ std::shared_ptr<ProofNode> ProofNodeManager::mkNode(
const std::vector<Node>& args,
Node expected)
{
+ Trace("pnm") << "ProofNodeManager::mkNode " << id << " {" << expected.getId()
+ << "} " << expected << "\n";
Node res = checkInternal(id, children, args, expected);
if (res.isNull())
{
@@ -49,6 +57,18 @@ std::shared_ptr<ProofNode> ProofNodeManager::mkAssume(Node fact)
return mkNode(PfRule::ASSUME, {}, {fact}, fact);
}
+std::shared_ptr<ProofNode> ProofNodeManager::mkTrans(
+ const std::vector<std::shared_ptr<ProofNode>>& children, Node expected)
+{
+ Assert(!children.empty());
+ if (children.size() == 1)
+ {
+ Assert(expected.isNull() || children[0]->getResult() == expected);
+ return children[0];
+ }
+ return mkNode(PfRule::TRANS, children, {}, expected);
+}
+
std::shared_ptr<ProofNode> ProofNodeManager::mkScope(
std::shared_ptr<ProofNode> pf,
std::vector<Node>& assumps,
@@ -63,12 +83,20 @@ std::shared_ptr<ProofNode> ProofNodeManager::mkScope(
Trace("pnm-scope") << "ProofNodeManager::mkScope " << assumps << std::endl;
// we first ensure the assumptions are flattened
std::unordered_set<Node, NodeHashFunction> ac{assumps.begin(), assumps.end()};
+ // map from the rewritten form of assumptions to the original. This is only
+ // computed in the rare case when we need rewriting to match the
+ // assumptions. An example of this is for Boolean constant equalities in
+ // scoped proofs from the proof equality engine.
+ std::unordered_map<Node, Node, NodeHashFunction> acr;
+ // whether we have compute the map above
+ bool computedAcr = false;
// The free assumptions of the proof
- std::map<Node, std::vector<ProofNode*>> famap;
- expr::getFreeAssumptionsMap(pf.get(), famap);
+ std::map<Node, std::vector<std::shared_ptr<ProofNode>>> famap;
+ expr::getFreeAssumptionsMap(pf, famap);
std::unordered_set<Node, NodeHashFunction> acu;
- for (const std::pair<const Node, std::vector<ProofNode*>>& fa : famap)
+ for (const std::pair<const Node, std::vector<std::shared_ptr<ProofNode>>>&
+ fa : famap)
{
Node a = fa.first;
if (ac.find(a) != ac.end())
@@ -77,41 +105,100 @@ std::shared_ptr<ProofNode> ProofNodeManager::mkScope(
acu.insert(a);
continue;
}
+ // trivial assumption
+ if (a == d_true)
+ {
+ Trace("pnm-scope") << "- justify trivial True assumption\n";
+ for (std::shared_ptr<ProofNode> pfs : fa.second)
+ {
+ Assert(pfs->getResult() == a);
+ updateNode(pfs.get(), PfRule::MACRO_SR_PRED_INTRO, {}, {a});
+ }
+ Trace("pnm-scope") << "...finished" << std::endl;
+ acu.insert(a);
+ continue;
+ }
Trace("pnm-scope") << "- try matching free assumption " << a << "\n";
// otherwise it may be due to symmetry?
Node aeqSym = CDProof::getSymmFact(a);
Trace("pnm-scope") << " - try sym " << aeqSym << "\n";
- if (!aeqSym.isNull())
+ Node aMatch;
+ if (!aeqSym.isNull() && ac.count(aeqSym))
+ {
+ Trace("pnm-scope") << "- reorient assumption " << aeqSym << " via " << a
+ << " for " << fa.second.size() << " proof nodes"
+ << std::endl;
+ aMatch = aeqSym;
+ }
+ else
+ {
+ // Otherwise, may be derivable by rewriting. Note this is used in
+ // ensuring that proofs from the proof equality engine that involve
+ // equality with Boolean constants are closed.
+ if (!computedAcr)
+ {
+ computedAcr = true;
+ for (const Node& acc : ac)
+ {
+ Node accr = theory::Rewriter::rewrite(acc);
+ if (accr != acc)
+ {
+ acr[accr] = acc;
+ }
+ }
+ }
+ Node ar = theory::Rewriter::rewrite(a);
+ std::unordered_map<Node, Node, NodeHashFunction>::iterator itr =
+ acr.find(ar);
+ if (itr != acr.end())
+ {
+ aMatch = itr->second;
+ }
+ }
+
+ // if we found a match either by symmetry or rewriting, then we connect
+ // the assumption here.
+ if (!aMatch.isNull())
{
- if (ac.count(aeqSym))
+ std::shared_ptr<ProofNode> pfaa = mkAssume(aMatch);
+ // must correct the orientation on this leaf
+ std::vector<std::shared_ptr<ProofNode>> children;
+ children.push_back(pfaa);
+ for (std::shared_ptr<ProofNode> pfs : fa.second)
{
- Trace("pnm-scope") << "- reorient assumption " << aeqSym << " via " << a
- << " for " << fa.second.size() << " proof nodes"
- << std::endl;
- std::shared_ptr<ProofNode> pfaa = mkAssume(aeqSym);
- for (ProofNode* pfs : fa.second)
+ Assert(pfs->getResult() == a);
+ // use SYMM if possible
+ if (aMatch == aeqSym)
+ {
+ updateNode(pfs.get(), PfRule::SYMM, children, {});
+ }
+ else
{
- Assert(pfs->getResult() == a);
- // must correct the orientation on this leaf
- std::vector<std::shared_ptr<ProofNode>> children;
- children.push_back(pfaa);
- std::vector<Node> args;
- args.push_back(a);
- updateNode(pfs, PfRule::MACRO_SR_PRED_TRANSFORM, children, args);
+ updateNode(pfs.get(), PfRule::MACRO_SR_PRED_TRANSFORM, children, {a});
}
- Trace("pnm-scope") << "...finished" << std::endl;
- acu.insert(aeqSym);
- continue;
}
+ Trace("pnm-scope") << "...finished" << std::endl;
+ acu.insert(aMatch);
+ continue;
}
- // All free assumptions should be arguments to SCOPE.
+ // If we did not find a match, it is an error, since all free assumptions
+ // should be arguments to SCOPE.
std::stringstream ss;
- pf->printDebug(ss);
+
+ bool dumpProofTraceOn = Trace.isOn("dump-proof-error");
+ if (dumpProofTraceOn)
+ {
+ ss << "The proof : " << *pf << std::endl;
+ }
ss << std::endl << "Free assumption: " << a << std::endl;
for (const Node& aprint : ac)
{
ss << "- assumption: " << aprint << std::endl;
}
+ if (!dumpProofTraceOn)
+ {
+ ss << "Use -t dump-proof-error for details on proof" << std::endl;
+ }
Unreachable() << "Generated a proof that is not closed by the scope: "
<< ss.str() << std::endl;
}
@@ -142,23 +229,20 @@ std::shared_ptr<ProofNode> ProofNodeManager::mkScope(
Node minExpected;
NodeManager* nm = NodeManager::currentNM();
Node exp;
- Node conc = pf->getResult();
if (assumps.empty())
{
- Assert(!conc.isConst());
- minExpected = conc;
+ // SCOPE with no arguments is a no-op, just return original
+ return pf;
+ }
+ Node conc = pf->getResult();
+ exp = assumps.size() == 1 ? assumps[0] : nm->mkNode(AND, assumps);
+ if (conc.isConst() && !conc.getConst<bool>())
+ {
+ minExpected = exp.notNode();
}
else
{
- exp = assumps.size() == 1 ? assumps[0] : nm->mkNode(AND, assumps);
- if (conc.isConst() && !conc.getConst<bool>())
- {
- minExpected = exp.notNode();
- }
- else
- {
- minExpected = nm->mkNode(IMPLIES, exp, conc);
- }
+ minExpected = nm->mkNode(IMPLIES, exp, conc);
}
return mkNode(PfRule::SCOPE, {pf}, assumps, minExpected);
}
@@ -174,6 +258,8 @@ bool ProofNodeManager::updateNode(
bool ProofNodeManager::updateNode(ProofNode* pn, ProofNode* pnr)
{
+ Assert(pn != nullptr);
+ Assert(pnr != nullptr);
if (pn->getResult() != pnr->getResult())
{
return false;
@@ -216,24 +302,14 @@ bool ProofNodeManager::updateNodeInternal(
const std::vector<Node>& args,
bool needsCheck)
{
+ Assert(pn != nullptr);
// ---------------- check for cyclic
- std::unordered_map<const ProofNode*, bool> visited;
- std::unordered_map<const ProofNode*, bool>::iterator it;
- std::vector<const ProofNode*> visit;
- for (const std::shared_ptr<ProofNode>& cp : children)
- {
- visit.push_back(cp.get());
- }
- const ProofNode* cur;
- while (!visit.empty())
+ if (options::proofNewEagerChecking())
{
- cur = visit.back();
- visit.pop_back();
- it = visited.find(cur);
- if (it == visited.end())
+ std::unordered_set<const ProofNode*> visited;
+ for (const std::shared_ptr<ProofNode>& cpc : children)
{
- visited[cur] = true;
- if (cur == pn)
+ if (expr::containsSubproof(cpc.get(), pn, visited))
{
std::stringstream ss;
ss << "ProofNodeManager::updateNode: attempting to make cyclic proof! "
@@ -251,10 +327,6 @@ bool ProofNodeManager::updateNodeInternal(
}
Unreachable() << ss.str();
}
- for (const std::shared_ptr<ProofNode>& cp : cur->d_children)
- {
- visit.push_back(cp.get());
- }
}
}
// ---------------- end check for cyclic
diff --git a/src/expr/proof_node_manager.h b/src/expr/proof_node_manager.h
index 774177d66..dae0266bb 100644
--- a/src/expr/proof_node_manager.h
+++ b/src/expr/proof_node_manager.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -81,6 +81,15 @@ class ProofNodeManager
*/
std::shared_ptr<ProofNode> mkAssume(Node fact);
/**
+ * Make transitivity proof, where children contains one or more proofs of
+ * equalities that form an ordered chain. In other words, the vector children
+ * is a legal set of children for an application of TRANS.
+ */
+ std::shared_ptr<ProofNode> mkTrans(
+ const std::vector<std::shared_ptr<ProofNode>>& children,
+ Node expected = Node::null());
+
+ /**
* Make scope having body pf and arguments (assumptions-to-close) assumps.
* If ensureClosed is true, then this method throws an assertion failure if
* the returned proof is not closed. This is the case if a free assumption
@@ -102,7 +111,8 @@ class ProofNodeManager
*
* Additionally, if both ensureClosed and doMinimize are true, assumps is
* updated to contain exactly the free asumptions of pf. This also includes
- * having no duplicates.
+ * having no duplicates. Furthermore, if assumps is empty after minimization,
+ * this method is a no-op.
*
* In each case, the update vector assumps is passed as arguments to SCOPE.
*
@@ -118,7 +128,6 @@ class ProofNodeManager
bool ensureClosed = true,
bool doMinimize = false,
Node expected = Node::null());
-
/**
* This method updates pn to be a proof of the form <id>( children, args ),
* while maintaining its d_proven field. This method returns false if this
@@ -150,6 +159,8 @@ class ProofNodeManager
private:
/** The (optional) proof checker */
ProofChecker* d_checker;
+ /** the true node */
+ Node d_true;
/** Check internal
*
* This returns the result of proof checking a ProofNode with the provided
diff --git a/src/expr/proof_node_to_sexpr.cpp b/src/expr/proof_node_to_sexpr.cpp
index c6bde49fd..2dbb2a873 100644
--- a/src/expr/proof_node_to_sexpr.cpp
+++ b/src/expr/proof_node_to_sexpr.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -32,7 +32,7 @@ Node ProofNodeToSExpr::convertToSExpr(const ProofNode* pn)
NodeManager* nm = NodeManager::currentNM();
std::map<const ProofNode*, Node>::iterator it;
std::vector<const ProofNode*> visit;
- std::vector<const ProofNode*> constructing;
+ std::vector<const ProofNode*> traversing;
const ProofNode* cur;
visit.push_back(pn);
do
@@ -44,16 +44,17 @@ Node ProofNodeToSExpr::convertToSExpr(const ProofNode* pn)
if (it == d_pnMap.end())
{
d_pnMap[cur] = Node::null();
- constructing.push_back(cur);
+ traversing.push_back(cur);
visit.push_back(cur);
const std::vector<std::shared_ptr<ProofNode>>& pc = cur->getChildren();
for (const std::shared_ptr<ProofNode>& cp : pc)
{
- if (std::find(constructing.begin(), constructing.end(), cp.get())
- != constructing.end())
+ if (std::find(traversing.begin(), traversing.end(), cp.get())
+ != traversing.end())
{
- AlwaysAssert(false)
- << "ProofNodeToSExpr::convertToSExpr: cyclic proof!" << std::endl;
+ Unhandled() << "ProofNodeToSExpr::convertToSExpr: cyclic proof! (use "
+ "--proof-new-eager-checking)"
+ << std::endl;
return Node::null();
}
visit.push_back(cp.get());
@@ -61,8 +62,8 @@ Node ProofNodeToSExpr::convertToSExpr(const ProofNode* pn)
}
else if (it->second.isNull())
{
- Assert(!constructing.empty());
- constructing.pop_back();
+ Assert(!traversing.empty());
+ traversing.pop_back();
std::vector<Node> children;
// add proof rule
children.push_back(getOrMkPfRuleVariable(cur->getRule()));
diff --git a/src/expr/proof_node_to_sexpr.h b/src/expr/proof_node_to_sexpr.h
index 1f38f4cad..16a60e252 100644
--- a/src/expr/proof_node_to_sexpr.h
+++ b/src/expr/proof_node_to_sexpr.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/proof_node_updater.cpp b/src/expr/proof_node_updater.cpp
index 1e8fe4e7d..ac04baa6f 100644
--- a/src/expr/proof_node_updater.cpp
+++ b/src/expr/proof_node_updater.cpp
@@ -2,10 +2,10 @@
/*! \file proof_node_updater.cpp
** \verbatim
** Top contributors (to current version):
- ** Morgan Deters, Andrew Reynolds, Tim King
+ ** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -15,68 +15,246 @@
#include "expr/proof_node_updater.h"
#include "expr/lazy_proof.h"
+#include "expr/proof_node_algorithm.h"
namespace CVC4 {
ProofNodeUpdaterCallback::ProofNodeUpdaterCallback() {}
ProofNodeUpdaterCallback::~ProofNodeUpdaterCallback() {}
+bool ProofNodeUpdaterCallback::update(Node res,
+ PfRule id,
+ const std::vector<Node>& children,
+ const std::vector<Node>& args,
+ CDProof* cdp,
+ bool& continueUpdate)
+{
+ return false;
+}
+
ProofNodeUpdater::ProofNodeUpdater(ProofNodeManager* pnm,
- ProofNodeUpdaterCallback& cb)
- : d_pnm(pnm), d_cb(cb)
+ ProofNodeUpdaterCallback& cb,
+ bool mergeSubproofs)
+ : d_pnm(pnm),
+ d_cb(cb),
+ d_debugFreeAssumps(false),
+ d_mergeSubproofs(mergeSubproofs)
{
}
void ProofNodeUpdater::process(std::shared_ptr<ProofNode> pf)
{
+ if (d_debugFreeAssumps)
+ {
+ if (Trace.isOn("pfnu-debug"))
+ {
+ Trace("pfnu-debug2") << "Initial proof: " << *pf.get() << std::endl;
+ Trace("pfnu-debug") << "ProofNodeUpdater::process" << std::endl;
+ Trace("pfnu-debug") << "Expected free assumptions: " << std::endl;
+ for (const Node& fa : d_freeAssumps)
+ {
+ Trace("pfnu-debug") << "- " << fa << std::endl;
+ }
+ std::vector<Node> assump;
+ expr::getFreeAssumptions(pf.get(), assump);
+ Trace("pfnu-debug") << "Current free assumptions: " << std::endl;
+ for (const Node& fa : assump)
+ {
+ Trace("pfnu-debug") << "- " << fa << std::endl;
+ }
+ }
+ }
+ std::vector<std::shared_ptr<ProofNode>> traversing;
+ processInternal(pf, d_freeAssumps, traversing);
+}
+
+void ProofNodeUpdater::processInternal(
+ std::shared_ptr<ProofNode> pf,
+ const std::vector<Node>& fa,
+ std::vector<std::shared_ptr<ProofNode>>& traversing)
+{
Trace("pf-process") << "ProofNodeUpdater::process" << std::endl;
- std::unordered_set<ProofNode*> visited;
- std::unordered_set<ProofNode*>::iterator it;
- std::vector<ProofNode*> visit;
- ProofNode* cur;
- visit.push_back(pf.get());
+ std::unordered_map<std::shared_ptr<ProofNode>, bool> visited;
+ std::unordered_map<std::shared_ptr<ProofNode>, bool>::iterator it;
+ std::vector<std::shared_ptr<ProofNode>> visit;
+ std::shared_ptr<ProofNode> cur;
+ visit.push_back(pf);
+ std::map<Node, std::shared_ptr<ProofNode>>::iterator itc;
+ // A cache from formulas to proof nodes that are in the current scope.
+ // Notice that we make a fresh recursive call to process if the current
+ // rule is SCOPE below.
+ std::map<Node, std::shared_ptr<ProofNode>> resCache;
+ Node res;
do
{
cur = visit.back();
visit.pop_back();
it = visited.find(cur);
+ res = cur->getResult();
if (it == visited.end())
{
- visited.insert(cur);
- // should it be updated?
- if (d_cb.shouldUpdate(cur))
+ if (d_mergeSubproofs)
{
- PfRule id = cur->getRule();
- // use CDProof to open a scope for which the callback updates
- CDProof cpf(d_pnm);
- const std::vector<std::shared_ptr<ProofNode>>& cc = cur->getChildren();
- std::vector<Node> ccn;
- for (const std::shared_ptr<ProofNode>& cp : cc)
+ itc = resCache.find(res);
+ if (itc != resCache.end())
{
- Node cpres = cp->getResult();
- ccn.push_back(cpres);
- // store in the proof
- cpf.addProof(cp);
+ // already have a proof, merge it into this one
+ visited[cur] = true;
+ d_pnm->updateNode(cur.get(), itc->second.get());
+ continue;
}
- // only if the callback updated the node
- if (d_cb.update(id, ccn, cur->getArguments(), &cpf))
+ }
+ // run update to a fixed point
+ bool continueUpdate = true;
+ while (runUpdate(cur, fa, continueUpdate) && continueUpdate)
+ {
+ Trace("pf-process-debug") << "...updated proof." << std::endl;
+ }
+ visited[cur] = !continueUpdate;
+ if (!continueUpdate)
+ {
+ // no further changes should be made to cur according to the callback
+ Trace("pf-process-debug")
+ << "...marked to not continue update." << std::endl;
+ runFinalize(cur, fa, resCache);
+ continue;
+ }
+ traversing.push_back(cur);
+ visit.push_back(cur);
+ if (d_mergeSubproofs)
+ {
+ // If we are not the top-level proof, we were a scope, or became a
+ // scope after updating, we need to make a separate recursive call to
+ // this method. This is not necessary if we are not merging subproofs.
+ if (cur->getRule() == PfRule::SCOPE && cur != pf)
{
- // build the proof, which should be closed
- std::shared_ptr<ProofNode> npn = cpf.getProofFor(cur->getResult());
- Assert(npn->isClosed());
- // then, update the original proof node based on this one
- d_pnm->updateNode(cur, npn.get());
+ std::vector<Node> nfa;
+ // if we are debugging free assumptions, update the set
+ if (d_debugFreeAssumps)
+ {
+ nfa.insert(nfa.end(), fa.begin(), fa.end());
+ const std::vector<Node>& args = cur->getArguments();
+ nfa.insert(nfa.end(), args.begin(), args.end());
+ Trace("pfnu-debug2")
+ << "Process new scope with " << args << std::endl;
+ }
+ // Process in new call separately, since we should not cache
+ // the results of proofs that have a different scope.
+ processInternal(cur, nfa, traversing);
+ continue;
}
}
const std::vector<std::shared_ptr<ProofNode>>& ccp = cur->getChildren();
// now, process children
for (const std::shared_ptr<ProofNode>& cp : ccp)
{
- visit.push_back(cp.get());
+ if (std::find(traversing.begin(), traversing.end(), cp)
+ != traversing.end())
+ {
+ Unhandled()
+ << "ProofNodeUpdater::processInternal: cyclic proof! (use "
+ "--proof-new-eager-checking)"
+ << std::endl;
+ }
+ visit.push_back(cp);
}
}
+ else if (!it->second)
+ {
+ Assert(!traversing.empty());
+ traversing.pop_back();
+ visited[cur] = true;
+ // finalize the node
+ runFinalize(cur, fa, resCache);
+ }
} while (!visit.empty());
Trace("pf-process") << "ProofNodeUpdater::process: finished" << std::endl;
}
+bool ProofNodeUpdater::runUpdate(std::shared_ptr<ProofNode> cur,
+ const std::vector<Node>& fa,
+ bool& continueUpdate)
+{
+ // should it be updated?
+ if (!d_cb.shouldUpdate(cur, continueUpdate))
+ {
+ return false;
+ }
+ PfRule id = cur->getRule();
+ // use CDProof to open a scope for which the callback updates
+ CDProof cpf(d_pnm);
+ const std::vector<std::shared_ptr<ProofNode>>& cc = cur->getChildren();
+ std::vector<Node> ccn;
+ for (const std::shared_ptr<ProofNode>& cp : cc)
+ {
+ Node cpres = cp->getResult();
+ ccn.push_back(cpres);
+ // store in the proof
+ cpf.addProof(cp);
+ }
+ Trace("pf-process-debug")
+ << "Updating (" << cur->getRule() << ")..." << std::endl;
+ Node res = cur->getResult();
+ // only if the callback updated the node
+ if (d_cb.update(res, id, ccn, cur->getArguments(), &cpf, continueUpdate))
+ {
+ std::shared_ptr<ProofNode> npn = cpf.getProofFor(res);
+ std::vector<Node> fullFa;
+ if (d_debugFreeAssumps)
+ {
+ expr::getFreeAssumptions(cur.get(), fullFa);
+ Trace("pfnu-debug") << "Original proof : " << *cur << std::endl;
+ }
+ // then, update the original proof node based on this one
+ Trace("pf-process-debug") << "Update node..." << std::endl;
+ d_pnm->updateNode(cur.get(), npn.get());
+ Trace("pf-process-debug") << "...update node finished." << std::endl;
+ if (d_debugFreeAssumps)
+ {
+ fullFa.insert(fullFa.end(), fa.begin(), fa.end());
+ // We have that npn is a node we occurring the final updated version of
+ // the proof. We can now debug based on the expected set of free
+ // assumptions.
+ Trace("pfnu-debug") << "Ensure update closed..." << std::endl;
+ pfnEnsureClosedWrt(
+ npn.get(), fullFa, "pfnu-debug", "ProofNodeUpdater:postupdate");
+ }
+ Trace("pf-process-debug") << "..finished" << std::endl;
+ return true;
+ }
+ Trace("pf-process-debug") << "..finished" << std::endl;
+ return false;
+}
+
+void ProofNodeUpdater::runFinalize(
+ std::shared_ptr<ProofNode> cur,
+ const std::vector<Node>& fa,
+ std::map<Node, std::shared_ptr<ProofNode>>& resCache)
+{
+ if (d_mergeSubproofs)
+ {
+ Node res = cur->getResult();
+ // cache result if we are merging subproofs
+ resCache[res] = cur;
+ }
+ if (d_debugFreeAssumps)
+ {
+ // We have that npn is a node we occurring the final updated version of
+ // the proof. We can now debug based on the expected set of free
+ // assumptions.
+ Trace("pfnu-debug") << "Ensure update closed..." << std::endl;
+ pfnEnsureClosedWrt(
+ cur.get(), fa, "pfnu-debug", "ProofNodeUpdater:finalize");
+ }
+}
+
+void ProofNodeUpdater::setDebugFreeAssumptions(
+ const std::vector<Node>& freeAssumps)
+{
+ d_freeAssumps.clear();
+ d_freeAssumps.insert(
+ d_freeAssumps.end(), freeAssumps.begin(), freeAssumps.end());
+ d_debugFreeAssumps = true;
+}
+
} // namespace CVC4
diff --git a/src/expr/proof_node_updater.h b/src/expr/proof_node_updater.h
index be7a120ee..d4c2e8756 100644
--- a/src/expr/proof_node_updater.h
+++ b/src/expr/proof_node_updater.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -35,17 +35,32 @@ class ProofNodeUpdaterCallback
public:
ProofNodeUpdaterCallback();
virtual ~ProofNodeUpdaterCallback();
- /** Should proof pn be updated? */
- virtual bool shouldUpdate(ProofNode* pn) = 0;
+ /** Should proof pn be updated?
+ *
+ * @param pn the proof node that maybe should be updated
+ * @param continueUpdate whether we should continue recursively updating pn
+ * @return whether we should run the update method on pn
+ */
+ virtual bool shouldUpdate(std::shared_ptr<ProofNode> pn,
+ bool& continueUpdate) = 0;
/**
* Update the proof rule application, store steps in cdp. Return true if
* the proof changed. It can be assumed that cdp contains proofs of each
* fact in children.
+ *
+ * If continueUpdate is set to false in this method, then the resulting
+ * proof (the proof of res in cdp) is *not* called back to update by the
+ * proof node updater, nor are its children recursed. Otherwise, by default,
+ * the proof node updater will continue updating the resulting proof and will
+ * recursively update its children. This is analogous to marking REWRITE_DONE
+ * in a rewrite response.
*/
- virtual bool update(PfRule id,
+ virtual bool update(Node res,
+ PfRule id,
const std::vector<Node>& children,
const std::vector<Node>& args,
- CDProof* cdp) = 0;
+ CDProof* cdp,
+ bool& continueUpdate);
};
/**
@@ -60,18 +75,73 @@ class ProofNodeUpdaterCallback
class ProofNodeUpdater
{
public:
- ProofNodeUpdater(ProofNodeManager* pnm, ProofNodeUpdaterCallback& cb);
+ /**
+ * @param pnm The proof node manager we are using
+ * @param cb The callback to apply to each node
+ * @param mergeSubproofs Whether to automatically merge subproofs within
+ * the same SCOPE that prove the same fact.
+ */
+ ProofNodeUpdater(ProofNodeManager* pnm,
+ ProofNodeUpdaterCallback& cb,
+ bool mergeSubproofs = false);
/**
* Post-process, which performs the main post-processing technique described
* above.
*/
void process(std::shared_ptr<ProofNode> pf);
+ /**
+ * Set free assumptions to freeAssumps. This indicates that we expect
+ * the proof we are processing to have free assumptions that are in
+ * freeAssumps. This enables checking when this is violated, which is
+ * expensive in general. It is not recommended that this method is called
+ * by default.
+ */
+ void setDebugFreeAssumptions(const std::vector<Node>& freeAssumps);
+
private:
/** The proof node manager */
ProofNodeManager* d_pnm;
/** The callback */
ProofNodeUpdaterCallback& d_cb;
+ /**
+ * Post-process, which performs the main post-processing technique described
+ * above.
+ *
+ * @param pf The proof to process
+ * @param fa The assumptions of the scope that fa is a subproof of with
+ * respect to the original proof. For example, if (SCOPE P :args (A B)), we
+ * may call this method on P with fa = { A, B }.
+ * @param traversing The list of proof nodes we are currently traversing
+ * beneath. This is used for checking for cycles in the overall proof.
+ */
+ void processInternal(std::shared_ptr<ProofNode> pf,
+ const std::vector<Node>& fa,
+ std::vector<std::shared_ptr<ProofNode>>& traversing);
+ /**
+ * Update proof node cur based on the callback. This modifies curr using
+ * ProofNodeManager::updateNode based on the proof node constructed to
+ * replace it by the callback. Return true if cur was updated. If
+ * continueUpdate is updated to false, then cur is not updated further
+ * and its children are not traversed.
+ */
+ bool runUpdate(std::shared_ptr<ProofNode> cur,
+ const std::vector<Node>& fa,
+ bool& continueUpdate);
+ /**
+ * Finalize the node cur. This is called at the moment that it is established
+ * that cur will appear in the final proof. We do any final debug checking
+ * and add it to the results cache resCache if we are merging subproofs.
+ */
+ void runFinalize(std::shared_ptr<ProofNode> cur,
+ const std::vector<Node>& fa,
+ std::map<Node, std::shared_ptr<ProofNode>>& resCache);
+ /** Are we debugging free assumptions? */
+ bool d_debugFreeAssumps;
+ /** The initial free assumptions */
+ std::vector<Node> d_freeAssumps;
+ /** Whether we are merging subproofs */
+ bool d_mergeSubproofs;
};
} // namespace CVC4
diff --git a/src/expr/proof_rule.cpp b/src/expr/proof_rule.cpp
index c9250f9ea..4ba483101 100644
--- a/src/expr/proof_rule.cpp
+++ b/src/expr/proof_rule.cpp
@@ -2,10 +2,10 @@
/*! \file proof_rule.cpp
** \verbatim
** Top contributors (to current version):
- ** Haniel Barbosa, Andrew Reynolds
+ ** Andrew Reynolds, Haniel Barbosa, Alex Ozdemir
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -27,15 +27,33 @@ const char* toString(PfRule id)
case PfRule::SCOPE: return "SCOPE";
case PfRule::SUBS: return "SUBS";
case PfRule::REWRITE: return "REWRITE";
+ case PfRule::EVALUATE: return "EVALUATE";
case PfRule::MACRO_SR_EQ_INTRO: return "MACRO_SR_EQ_INTRO";
case PfRule::MACRO_SR_PRED_INTRO: return "MACRO_SR_PRED_INTRO";
case PfRule::MACRO_SR_PRED_ELIM: return "MACRO_SR_PRED_ELIM";
case PfRule::MACRO_SR_PRED_TRANSFORM: return "MACRO_SR_PRED_TRANSFORM";
+ case PfRule::REMOVE_TERM_FORMULA_AXIOM: return "REMOVE_TERM_FORMULA_AXIOM";
+ //================================================= Trusted rules
+ case PfRule::THEORY_LEMMA: return "THEORY_LEMMA";
case PfRule::THEORY_REWRITE: return "THEORY_REWRITE";
case PfRule::PREPROCESS: return "PREPROCESS";
+ case PfRule::PREPROCESS_LEMMA: return "PREPROCESS_LEMMA";
+ case PfRule::THEORY_PREPROCESS: return "THEORY_PREPROCESS";
+ case PfRule::THEORY_PREPROCESS_LEMMA: return "THEORY_PREPROCESS_LEMMA";
+ case PfRule::WITNESS_AXIOM: return "WITNESS_AXIOM";
+ case PfRule::TRUST_REWRITE: return "TRUST_REWRITE";
+ case PfRule::TRUST_SUBS: return "TRUST_SUBS";
+ case PfRule::TRUST_SUBS_MAP: return "TRUST_SUBS_MAP";
//================================================= Boolean rules
+ case PfRule::RESOLUTION: return "RESOLUTION";
+ case PfRule::CHAIN_RESOLUTION: return "CHAIN_RESOLUTION";
+ case PfRule::FACTORING: return "FACTORING";
+ case PfRule::REORDERING: return "REORDERING";
case PfRule::SPLIT: return "SPLIT";
case PfRule::EQ_RESOLVE: return "EQ_RESOLVE";
+ case PfRule::MODUS_PONENS: return "MODUS_PONENS";
+ case PfRule::NOT_NOT_ELIM: return "NOT_NOT_ELIM";
+ case PfRule::CONTRA: return "CONTRA";
case PfRule::AND_ELIM: return "AND_ELIM";
case PfRule::AND_INTRO: return "AND_INTRO";
case PfRule::NOT_OR_ELIM: return "NOT_OR_ELIM";
@@ -54,7 +72,6 @@ const char* toString(PfRule id)
case PfRule::ITE_ELIM2: return "ITE_ELIM2";
case PfRule::NOT_ITE_ELIM1: return "NOT_ITE_ELIM1";
case PfRule::NOT_ITE_ELIM2: return "NOT_ITE_ELIM2";
- case PfRule::CONTRA: return "CONTRA";
//================================================= De Morgan rules
case PfRule::NOT_AND: return "NOT_AND";
//================================================= CNF rules
@@ -88,11 +105,49 @@ const char* toString(PfRule id)
case PfRule::TRUE_ELIM: return "TRUE_ELIM";
case PfRule::FALSE_INTRO: return "FALSE_INTRO";
case PfRule::FALSE_ELIM: return "FALSE_ELIM";
+ case PfRule::HO_APP_ENCODE: return "HO_APP_ENCODE";
+ case PfRule::HO_CONG: return "HO_CONG";
+ //================================================= Array rules
+ case PfRule::ARRAYS_READ_OVER_WRITE: return "ARRAYS_READ_OVER_WRITE";
+ case PfRule::ARRAYS_READ_OVER_WRITE_CONTRA:
+ return "ARRAYS_READ_OVER_WRITE_CONTRA";
+ case PfRule::ARRAYS_READ_OVER_WRITE_1: return "ARRAYS_READ_OVER_WRITE_1";
+ case PfRule::ARRAYS_EXT: return "ARRAYS_EXT";
+ case PfRule::ARRAYS_TRUST: return "ARRAYS_TRUST";
+ //================================================= Datatype rules
+ case PfRule::DT_UNIF: return "DT_UNIF";
+ case PfRule::DT_INST: return "DT_INST";
+ case PfRule::DT_COLLAPSE: return "DT_COLLAPSE";
+ case PfRule::DT_SPLIT: return "DT_SPLIT";
+ case PfRule::DT_CLASH: return "DT_CLASH";
+ case PfRule::DT_TRUST: return "DT_TRUST";
//================================================= Quantifiers rules
case PfRule::WITNESS_INTRO: return "WITNESS_INTRO";
case PfRule::EXISTS_INTRO: return "EXISTS_INTRO";
case PfRule::SKOLEMIZE: return "SKOLEMIZE";
case PfRule::INSTANTIATE: return "INSTANTIATE";
+ //================================================= String rules
+ case PfRule::CONCAT_EQ: return "CONCAT_EQ";
+ case PfRule::CONCAT_UNIFY: return "CONCAT_UNIFY";
+ case PfRule::CONCAT_CONFLICT: return "CONCAT_CONFLICT";
+ case PfRule::CONCAT_SPLIT: return "CONCAT_SPLIT";
+ case PfRule::CONCAT_CSPLIT: return "CONCAT_CSPLIT";
+ case PfRule::CONCAT_LPROP: return "CONCAT_LPROP";
+ case PfRule::CONCAT_CPROP: return "CONCAT_CPROP";
+ case PfRule::STRING_DECOMPOSE: return "STRING_DECOMPOSE";
+ case PfRule::STRING_LENGTH_POS: return "STRING_LENGTH_POS";
+ case PfRule::STRING_LENGTH_NON_EMPTY: return "STRING_LENGTH_NON_EMPTY";
+ case PfRule::STRING_REDUCTION: return "STRING_REDUCTION";
+ case PfRule::STRING_EAGER_REDUCTION: return "STRING_EAGER_REDUCTION";
+ case PfRule::RE_INTER: return "RE_INTER";
+ case PfRule::RE_UNFOLD_POS: return "RE_UNFOLD_POS";
+ case PfRule::RE_UNFOLD_NEG: return "RE_UNFOLD_NEG";
+ case PfRule::RE_UNFOLD_NEG_CONCAT_FIXED:
+ return "RE_UNFOLD_NEG_CONCAT_FIXED";
+ case PfRule::RE_ELIM: return "RE_ELIM";
+ case PfRule::STRING_CODE_INJ: return "STRING_CODE_INJ";
+ case PfRule::STRING_SEQ_UNIT_INJ: return "STRING_SEQ_UNIT_INJ";
+ case PfRule::STRING_TRUST: return "STRING_TRUST";
//================================================= Arith rules
case PfRule::ARITH_SCALE_SUM_UPPER_BOUNDS: return "ARITH_SCALE_SUM_UPPER_BOUNDS";
case PfRule::ARITH_TRICHOTOMY: return "ARITH_TRICHOTOMY";
@@ -112,4 +167,9 @@ std::ostream& operator<<(std::ostream& out, PfRule id)
return out;
}
+size_t PfRuleHashFunction::operator()(PfRule id) const
+{
+ return static_cast<size_t>(id);
+}
+
} // namespace CVC4
diff --git a/src/expr/proof_rule.h b/src/expr/proof_rule.h
index e7464dd24..19efe6285 100644
--- a/src/expr/proof_rule.h
+++ b/src/expr/proof_rule.h
@@ -2,10 +2,10 @@
/*! \file proof_rule.h
** \verbatim
** Top contributors (to current version):
- ** Haniel Barbosa, Andrew Reynolds
+ ** Andrew Reynolds, Haniel Barbosa, Alex Ozdemir
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -91,6 +91,14 @@ enum class PfRule : uint32_t
// where idr is a MethodId identifier, which determines the kind of rewriter
// to apply, e.g. Rewriter::rewrite.
REWRITE,
+ // ======== Evaluate
+ // Children: none
+ // Arguments: (t)
+ // ----------------------------------------
+ // Conclusion: (= t Evaluator::evaluate(t))
+ // Note this is equivalent to:
+ // (REWRITE t MethodId::RW_EVALUATE)
+ EVALUATE,
// ======== Substitution + Rewriting equality introduction
//
// In this rule, we provide a term t and conclude that it is equal to its
@@ -121,14 +129,21 @@ enum class PfRule : uint32_t
// ---------------------------------------------------------------
// Conclusion: F
// where
- // Rewriter{idr}(toWitness(F)*sigma{ids}(Fn)*...*sigma{ids}(F1)) == true
+ // Rewriter{idr}(F*sigma{ids}(Fn)*...*sigma{ids}(F1)) == true
// where ids and idr are method identifiers.
//
- // Notice that we apply rewriting on the witness form of F, meaning that this
+ // More generally, this rule also holds when:
+ // Rewriter::rewrite(toWitness(F')) == true
+ // where F' is the result of the left hand side of the equality above. Here,
+ // notice that we apply rewriting on the witness form of F', meaning that this
// rule may conclude an F whose Skolem form is justified by the definition of
- // its (fresh) Skolem variables. Furthermore, notice that the rewriting and
- // substitution is applied only within the side condition, meaning the
- // rewritten form of the witness form of F does not escape this rule.
+ // its (fresh) Skolem variables. For example, this rule may justify the
+ // conclusion (= k t) where k is the purification Skolem for t, whose
+ // witness form is (witness ((x T)) (= x t)).
+ //
+ // Furthermore, notice that the rewriting and substitution is applied only
+ // within the side condition, meaning the rewritten form of the witness form
+ // of F does not escape this rule.
MACRO_SR_PRED_INTRO,
// ======== Substitution + Rewriting predicate elimination
//
@@ -157,33 +172,133 @@ enum class PfRule : uint32_t
// ----------------------------------------
// Conclusion: G
// where
- // Rewriter{idr}(toWitness(F)*sigma{ids}(Fn)*...*sigma{ids}(F1)) ==
- // Rewriter{idr}(toWitness(G)*sigma{ids}(Fn)*...*sigma{ids}(F1))
+ // Rewriter{idr}(F*sigma{ids}(Fn)*...*sigma{ids}(F1)) ==
+ // Rewriter{idr}(G*sigma{ids}(Fn)*...*sigma{ids}(F1))
//
- // Notice that we apply rewriting on the witness form of F and G, similar to
- // MACRO_SR_PRED_INTRO.
+ // More generally, this rule also holds when:
+ // Rewriter::rewrite(toWitness(F')) == Rewriter::rewrite(toWitness(G'))
+ // where F' and G' are the result of each side of the equation above. Here,
+ // witness forms are used in a similar manner to MACRO_SR_PRED_INTRO above.
MACRO_SR_PRED_TRANSFORM,
+
+ //================================================= Processing rules
+ // ======== Remove Term Formulas Axiom
+ // Children: none
+ // Arguments: (t)
+ // ---------------------------------------------------------------
+ // Conclusion: RemoveTermFormulas::getAxiomFor(t).
+ REMOVE_TERM_FORMULA_AXIOM,
+
+ //================================================= Trusted rules
+ // ======== Theory lemma
+ // Children: none
+ // Arguments: (F, tid)
+ // ---------------------------------------------------------------
+ // Conclusion: F
+ // where F is a (T-valid) theory lemma generated by theory with TheoryId tid.
+ // This is a "coarse-grained" rule that is used as a placeholder if a theory
+ // did not provide a proof for a lemma or conflict.
+ THEORY_LEMMA,
// ======== Theory Rewrite
// Children: none
- // Arguments: (t, preRewrite?)
+ // Arguments: (F, tid, rid)
// ----------------------------------------
- // Conclusion: (= t t')
- // where
- // t' is the result of applying either a pre-rewrite or a post-rewrite step
- // to t (depending on the second argument).
+ // Conclusion: F
+ // where F is an equality of the form (= t t') where t' is obtained by
+ // applying the kind of rewriting given by the method identifier rid, which
+ // is one of:
+ // { RW_REWRITE_THEORY_PRE, RW_REWRITE_THEORY_POST, RW_REWRITE_EQ_EXT }
+ // Notice that the checker for this rule does not replay the rewrite to ensure
+ // correctness, since theory rewriter methods are not static. For example,
+ // the quantifiers rewriter involves constructing new bound variables that are
+ // not guaranteed to be consistent on each call.
THEORY_REWRITE,
-
- //================================================= Processing rules
- // ======== Preprocess
+ // The rules in this section have the signature of a "trusted rule":
+ //
// Children: none
// Arguments: (F)
// ---------------------------------------------------------------
// Conclusion: F
+ //
// where F is an equality of the form t = t' where t was replaced by t'
// based on some preprocessing pass, or otherwise F was added as a new
// assertion by some preprocessing pass.
PREPROCESS,
+ // where F was added as a new assertion by some preprocessing pass.
+ PREPROCESS_LEMMA,
+ // where F is an equality of the form t = Theory::ppRewrite(t) for some
+ // theory. Notice this is a "trusted" rule.
+ THEORY_PREPROCESS,
+ // where F was added as a new assertion by theory preprocessing.
+ THEORY_PREPROCESS_LEMMA,
+ // where F is an existential (exists ((x T)) (P x)) used for introducing
+ // a witness term (witness ((x T)) (P x)).
+ WITNESS_AXIOM,
+ // where F is an equality (= t t') that holds by a form of rewriting that
+ // could not be replayed during proof postprocessing.
+ TRUST_REWRITE,
+ // where F is an equality (= t t') that holds by a form of substitution that
+ // could not be replayed during proof postprocessing.
+ TRUST_SUBS,
+ // where F is an equality (= t t') that holds by a form of substitution that
+ // could not be determined by the TrustSubstitutionMap.
+ TRUST_SUBS_MAP,
+
//================================================= Boolean rules
+ // ======== Resolution
+ // Children:
+ // (P1:C1, P2:C2)
+ // Arguments: (id, L)
+ // ---------------------
+ // Conclusion: C
+ // where
+ // - C1 and C2 are nodes viewed as clauses, i.e., either an OR node with
+ // each children viewed as a literal or a node viewed as a literal. Note
+ // that an OR node could also be a literal.
+ // - id is either true or false
+ // - L is the pivot of the resolution, which occurs as is (resp. under a
+ // NOT) in C1 and negatively (as is) in C2 if id = true (id = false).
+ // C is a clause resulting from collecting all the literals in C1, minus the
+ // first occurrence of the pivot or its negation, and C2, minus the first
+ // occurrence of the pivot or its negation, according to the policy above.
+ // If the resulting clause has a single literal, that literal itself is the
+ // result; if it has no literals, then the result is false; otherwise it's
+ // an OR node of the resulting literals.
+ //
+ // Note that it may be the case that the pivot does not occur in the
+ // clauses. In this case the rule is not unsound, but it does not correspond
+ // to resolution but rather to a weakening of the clause that did not have a
+ // literal eliminated.
+ RESOLUTION,
+ // ======== Chain Resolution
+ // Children: (P1:(or F_{1,1} ... F_{1,n1}), ..., Pm:(or F_{m,1} ... F_{m,nm}))
+ // Arguments: (L_1, ..., L_{m-1})
+ // ---------------------
+ // Conclusion: C_m'
+ // where
+ // let "C_1 <>_l C_2" represent the resolution of C_1 with C_2 with pivot l,
+ // let C_1' = C_1 (from P_1),
+ // for each i > 1, C_i' = C_i <>_L_i C_{i-1}'
+ CHAIN_RESOLUTION,
+ // ======== Factoring
+ // Children: (P:C1)
+ // Arguments: ()
+ // ---------------------
+ // Conclusion: C2
+ // where
+ // Set representations of C1 and C2 is the same and the number of literals in
+ // C2 is smaller than that of C1
+ FACTORING,
+ // ======== Reordering
+ // Children: (P:C1)
+ // Arguments: (C2)
+ // ---------------------
+ // Conclusion: C2
+ // where
+ // Set representations of C1 and C2 is the same but the number of literals in
+ // C2 is the same of that of C1
+ REORDERING,
+
// ======== Split
// Children: none
// Arguments: (F)
@@ -197,6 +312,25 @@ enum class PfRule : uint32_t
// Conclusion: (F2)
// Note this can optionally be seen as a macro for EQUIV_ELIM1+RESOLUTION.
EQ_RESOLVE,
+ // ======== Modus ponens
+ // Children: (P1:F1, P2:(=> F1 F2))
+ // Arguments: none
+ // ---------------------
+ // Conclusion: (F2)
+ // Note this can optionally be seen as a macro for IMPLIES_ELIM+RESOLUTION.
+ MODUS_PONENS,
+ // ======== Double negation elimination
+ // Children: (P:(not (not F)))
+ // Arguments: none
+ // ---------------------
+ // Conclusion: (F)
+ NOT_NOT_ELIM,
+ // ======== Contradiction
+ // Children: (P1:F P2:(not F))
+ // Arguments: ()
+ // ---------------------
+ // Conclusion: false
+ CONTRA,
// ======== And elimination
// Children: (P:(and F1 ... Fn))
// Arguments: (i)
@@ -305,12 +439,6 @@ enum class PfRule : uint32_t
// ---------------------
// Conclusion: (or C (not F2))
NOT_ITE_ELIM2,
- // ======== Not ITE elimination version 1
- // Children: (P1:P P2:(not P))
- // Arguments: ()
- // ---------------------
- // Conclusion: (false)
- CONTRA,
//================================================= De Morgan rules
// ======== Not And
@@ -466,11 +594,14 @@ enum class PfRule : uint32_t
// -----------------------
// Conclusion: (= t1 tn)
TRANS,
- // ======== Congruence (subsumed by Substitute?)
+ // ======== Congruence
// Children: (P1:(= t1 s1), ..., Pn:(= tn sn))
- // Arguments: (f)
+ // Arguments: (<kind> f?)
// ---------------------------------------------
- // Conclusion: (= (f t1 ... tn) (f s1 ... sn))
+ // Conclusion: (= (<kind> f? t1 ... tn) (<kind> f? s1 ... sn))
+ // Notice that f must be provided iff <kind> is a parameterized kind, e.g.
+ // APPLY_UF. The actual node for <kind> is constructible via
+ // ProofRuleChecker::mkKindNode.
CONG,
// ======== True intro
// Children: (P:F)
@@ -479,7 +610,7 @@ enum class PfRule : uint32_t
// Conclusion: (= F true)
TRUE_INTRO,
// ======== True elim
- // Children: (P:(= F true)
+ // Children: (P:(= F true))
// Arguments: none
// ----------------------------------------
// Conclusion: F
@@ -491,26 +622,120 @@ enum class PfRule : uint32_t
// Conclusion: (= F false)
FALSE_INTRO,
// ======== False elim
- // Children: (P:(= F false)
+ // Children: (P:(= F false))
// Arguments: none
// ----------------------------------------
// Conclusion: (not F)
FALSE_ELIM,
+ // ======== HO trust
+ // Children: none
+ // Arguments: (t)
+ // ---------------------
+ // Conclusion: (= t TheoryUfRewriter::getHoApplyForApplyUf(t))
+ // For example, this rule concludes (f x y) = (HO_APPLY (HO_APPLY f x) y)
+ HO_APP_ENCODE,
+ // ======== Congruence
+ // Children: (P1:(= f g), P2:(= t1 s1), ..., Pn+1:(= tn sn))
+ // Arguments: ()
+ // ---------------------------------------------
+ // Conclusion: (= (f t1 ... tn) (g s1 ... sn))
+ // Notice that this rule is only used when the application kinds are APPLY_UF.
+ HO_CONG,
+
+ //================================================= Array rules
+ // ======== Read over write
+ // Children: (P:(not (= i1 i2)))
+ // Arguments: ((select (store a i2 e) i1))
+ // ----------------------------------------
+ // Conclusion: (= (select (store a i2 e) i1) (select a i1))
+ ARRAYS_READ_OVER_WRITE,
+ // ======== Read over write, contrapositive
+ // Children: (P:(not (= (select (store a i2 e) i1) (select a i1)))
+ // Arguments: none
+ // ----------------------------------------
+ // Conclusion: (= i1 i2)
+ ARRAYS_READ_OVER_WRITE_CONTRA,
+ // ======== Read over write 1
+ // Children: none
+ // Arguments: ((select (store a i e) i))
+ // ----------------------------------------
+ // Conclusion: (= (select (store a i e) i) e)
+ ARRAYS_READ_OVER_WRITE_1,
+ // ======== Extensionality
+ // Children: (P:(not (= a b)))
+ // Arguments: none
+ // ----------------------------------------
+ // Conclusion: (not (= (select a k) (select b k)))
+ // where k is arrays::SkolemCache::getExtIndexSkolem((not (= a b))).
+ ARRAYS_EXT,
+ // ======== Array Trust
+ // Children: (P1 ... Pn)
+ // Arguments: (F)
+ // ---------------------
+ // Conclusion: F
+ ARRAYS_TRUST,
+
+ //================================================= Datatype rules
+ // ======== Unification
+ // Children: (P:(= (C t1 ... tn) (C s1 ... sn)))
+ // Arguments: (i)
+ // ----------------------------------------
+ // Conclusion: (= ti si)
+ // where C is a constructor.
+ DT_UNIF,
+ // ======== Instantiate
+ // Children: none
+ // Arguments: (t, n)
+ // ----------------------------------------
+ // Conclusion: (= ((_ is C) t) (= t (C (sel_1 t) ... (sel_n t))))
+ // where C is the n^th constructor of the type of T, and (_ is C) is the
+ // discriminator (tester) for C.
+ DT_INST,
+ // ======== Collapse
+ // Children: none
+ // Arguments: ((sel_i (C_j t_1 ... t_n)))
+ // ----------------------------------------
+ // Conclusion: (= (sel_i (C_j t_1 ... t_n)) r)
+ // where C_j is a constructor, r is t_i if sel_i is a correctly applied
+ // selector, or TypeNode::mkGroundTerm() of the proper type otherwise. Notice
+ // that the use of mkGroundTerm differs from the rewriter which uses
+ // mkGroundValue in this case.
+ DT_COLLAPSE,
+ // ======== Split
+ // Children: none
+ // Arguments: (t)
+ // ----------------------------------------
+ // Conclusion: (or ((_ is C1) t) ... ((_ is Cn) t))
+ DT_SPLIT,
+ // ======== Clash
+ // Children: (P1:((_ is Ci) t), P2: ((_ is Cj) t))
+ // Arguments: none
+ // ----------------------------------------
+ // Conclusion: false
+ // for i != j.
+ DT_CLASH,
+ // ======== Datatype Trust
+ // Children: (P1 ... Pn)
+ // Arguments: (F)
+ // ---------------------
+ // Conclusion: F
+ DT_TRUST,
//================================================= Quantifiers rules
// ======== Witness intro
- // Children: (P:F[t])
- // Arguments: (t)
+ // Children: (P:(exists ((x T)) F[x]))
+ // Arguments: none
// ----------------------------------------
- // Conclusion: (= t (witness ((x T)) F[x]))
- // where x is a BOUND_VARIABLE unique to the pair F,t.
+ // Conclusion: (= k (witness ((x T)) F[x]))
+ // where k is the Skolem form of (witness ((x T)) F[x]).
WITNESS_INTRO,
// ======== Exists intro
// Children: (P:F[t])
- // Arguments: (t)
+ // Arguments: ((exists ((x T)) F[x]))
// ----------------------------------------
// Conclusion: (exists ((x T)) F[x])
- // where x is a BOUND_VARIABLE unique to the pair F,t.
+ // This rule verifies that F[x] indeed matches F[t] with a substitution
+ // over x.
EXISTS_INTRO,
// ======== Skolemize
// Children: (P:(exists ((x1 T1) ... (xn Tn)) F))
@@ -519,7 +744,7 @@ enum class PfRule : uint32_t
// Conclusion: F*sigma
// sigma maps x1 ... xn to their representative skolems obtained by
// SkolemManager::mkSkolemize, returned in the skolems argument of that
- // method.
+ // method. Alternatively, can use negated forall as a premise.
SKOLEMIZE,
// ======== Instantiate
// Children: (P:(forall ((x1 T1) ... (xn Tn)) F))
@@ -529,6 +754,241 @@ enum class PfRule : uint32_t
// sigma maps x1 ... xn to t1 ... tn.
INSTANTIATE,
+ //================================================= String rules
+ //======================== Core solver
+ // ======== Concat eq
+ // Children: (P1:(= (str.++ t1 ... tn t) (str.++ t1 ... tn s)))
+ // Arguments: (b), indicating if reverse direction
+ // ---------------------
+ // Conclusion: (= t s)
+ //
+ // Notice that t or s may be empty, in which case they are implicit in the
+ // concatenation above. For example, if
+ // P1 concludes (= x (str.++ x z)), then
+ // (CONCAT_EQ P1 :args false) concludes (= "" z)
+ //
+ // Also note that constants are split, such that if
+ // P1 concludes (= (str.++ "abc" x) (str.++ "a" y)), then
+ // (CONCAT_EQ P1 :args false) concludes (= (str.++ "bc" x) y)
+ // This splitting is done only for constants such that Word::splitConstant
+ // returns non-null.
+ CONCAT_EQ,
+ // ======== Concat unify
+ // Children: (P1:(= (str.++ t1 t2) (str.++ s1 s2)),
+ // P2:(= (str.len t1) (str.len s1)))
+ // Arguments: (b), indicating if reverse direction
+ // ---------------------
+ // Conclusion: (= t1 s1)
+ CONCAT_UNIFY,
+ // ======== Concat conflict
+ // Children: (P1:(= (str.++ c1 t) (str.++ c2 s)))
+ // Arguments: (b), indicating if reverse direction
+ // ---------------------
+ // Conclusion: false
+ // Where c1, c2 are constants such that Word::splitConstant(c1,c2,index,b)
+ // is null, in other words, neither is a prefix of the other.
+ CONCAT_CONFLICT,
+ // ======== Concat split
+ // Children: (P1:(= (str.++ t1 t2) (str.++ s1 s2)),
+ // P2:(not (= (str.len t1) (str.len s1))))
+ // Arguments: (false)
+ // ---------------------
+ // Conclusion: (or (= t1 (str.++ s1 r_t)) (= s1 (str.++ t1 r_s)))
+ // where
+ // r_t = (witness ((z String)) (= z (suf t1 (str.len s1)))),
+ // r_s = (witness ((z String)) (= z (suf s1 (str.len t1)))).
+ //
+ // or the reverse form of the above:
+ //
+ // Children: (P1:(= (str.++ t1 t2) (str.++ s1 s2)),
+ // P2:(not (= (str.len t2) (str.len s2))))
+ // Arguments: (true)
+ // ---------------------
+ // Conclusion: (or (= t2 (str.++ r_t s2)) (= s2 (str.++ r_s t2)))
+ // where
+ // r_t = (witness ((z String)) (= z (pre t2 (- (str.len t2) (str.len
+ // s2))))), r_s = (witness ((z String)) (= z (pre s2 (- (str.len s2)
+ // (str.len t2))))).
+ //
+ // Above, (suf x n) is shorthand for (str.substr x n (- (str.len x) n)) and
+ // (pre x n) is shorthand for (str.substr x 0 n).
+ CONCAT_SPLIT,
+ // ======== Concat constant split
+ // Children: (P1:(= (str.++ t1 t2) (str.++ c s2)),
+ // P2:(not (= (str.len t1) 0)))
+ // Arguments: (false)
+ // ---------------------
+ // Conclusion: (= t1 (str.++ c r))
+ // where
+ // r = (witness ((z String)) (= z (suf t1 1))).
+ //
+ // or the reverse form of the above:
+ //
+ // Children: (P1:(= (str.++ t1 t2) (str.++ s1 c)),
+ // P2:(not (= (str.len t2) 0)))
+ // Arguments: (true)
+ // ---------------------
+ // Conclusion: (= t2 (str.++ r c))
+ // where
+ // r = (witness ((z String)) (= z (pre t2 (- (str.len t2) 1)))).
+ CONCAT_CSPLIT,
+ // ======== Concat length propagate
+ // Children: (P1:(= (str.++ t1 t2) (str.++ s1 s2)),
+ // P2:(> (str.len t1) (str.len s1)))
+ // Arguments: (false)
+ // ---------------------
+ // Conclusion: (= t1 (str.++ s1 r_t))
+ // where
+ // r_t = (witness ((z String)) (= z (suf t1 (str.len s1))))
+ //
+ // or the reverse form of the above:
+ //
+ // Children: (P1:(= (str.++ t1 t2) (str.++ s1 s2)),
+ // P2:(> (str.len t2) (str.len s2)))
+ // Arguments: (false)
+ // ---------------------
+ // Conclusion: (= t2 (str.++ r_t s2))
+ // where
+ // r_t = (witness ((z String)) (= z (pre t2 (- (str.len t2) (str.len
+ // s2))))).
+ CONCAT_LPROP,
+ // ======== Concat constant propagate
+ // Children: (P1:(= (str.++ t1 w1 t2) (str.++ w2 s)),
+ // P2:(not (= (str.len t1) 0)))
+ // Arguments: (false)
+ // ---------------------
+ // Conclusion: (= t1 (str.++ w3 r))
+ // where
+ // w1, w2, w3, w4 are words,
+ // w3 is (pre w2 p),
+ // w4 is (suf w2 p),
+ // p = Word::overlap((suf w2 1), w1),
+ // r = (witness ((z String)) (= z (suf t1 (str.len w3)))).
+ // In other words, w4 is the largest suffix of (suf w2 1) that can contain a
+ // prefix of w1; since t1 is non-empty, w3 must therefore be contained in t1.
+ //
+ // or the reverse form of the above:
+ //
+ // Children: (P1:(= (str.++ t1 w1 t2) (str.++ s w2)),
+ // P2:(not (= (str.len t2) 0)))
+ // Arguments: (true)
+ // ---------------------
+ // Conclusion: (= t2 (str.++ r w3))
+ // where
+ // w1, w2, w3, w4 are words,
+ // w3 is (suf w2 (- (str.len w2) p)),
+ // w4 is (pre w2 (- (str.len w2) p)),
+ // p = Word::roverlap((pre w2 (- (str.len w2) 1)), w1),
+ // r = (witness ((z String)) (= z (pre t2 (- (str.len t2) (str.len w3))))).
+ // In other words, w4 is the largest prefix of (pre w2 (- (str.len w2) 1))
+ // that can contain a suffix of w1; since t2 is non-empty, w3 must therefore
+ // be contained in t2.
+ CONCAT_CPROP,
+ // ======== String decompose
+ // Children: (P1: (>= (str.len t) n)
+ // Arguments: (false)
+ // ---------------------
+ // Conclusion: (and (= t (str.++ w1 w2)) (= (str.len w1) n))
+ // or
+ // Children: (P1: (>= (str.len t) n)
+ // Arguments: (true)
+ // ---------------------
+ // Conclusion: (and (= t (str.++ w1 w2)) (= (str.len w2) n))
+ // where
+ // w1 is (witness ((z String)) (= z (pre t n)))
+ // w2 is (witness ((z String)) (= z (suf t n)))
+ STRING_DECOMPOSE,
+ // ======== Length positive
+ // Children: none
+ // Arguments: (t)
+ // ---------------------
+ // Conclusion: (or (and (= (str.len t) 0) (= t "")) (> (str.len t 0)))
+ STRING_LENGTH_POS,
+ // ======== Length non-empty
+ // Children: (P1:(not (= t "")))
+ // Arguments: none
+ // ---------------------
+ // Conclusion: (not (= (str.len t) 0))
+ STRING_LENGTH_NON_EMPTY,
+ //======================== Extended functions
+ // ======== Reduction
+ // Children: none
+ // Arguments: (t)
+ // ---------------------
+ // Conclusion: (and R (= t w))
+ // where w = strings::StringsPreprocess::reduce(t, R, ...).
+ // In other words, R is the reduction predicate for extended term t, and w is
+ // (witness ((z T)) (= z t))
+ // Notice that the free variables of R are w and the free variables of t.
+ STRING_REDUCTION,
+ // ======== Eager Reduction
+ // Children: none
+ // Arguments: (t, id?)
+ // ---------------------
+ // Conclusion: R
+ // where R = strings::TermRegistry::eagerReduce(t, id).
+ STRING_EAGER_REDUCTION,
+ //======================== Regular expressions
+ // ======== Regular expression intersection
+ // Children: (P:(str.in.re t R1), P:(str.in.re t R2))
+ // Arguments: none
+ // ---------------------
+ // Conclusion: (str.in.re t (re.inter R1 R2)).
+ RE_INTER,
+ // ======== Regular expression unfold positive
+ // Children: (P:(str.in.re t R))
+ // Arguments: none
+ // ---------------------
+ // Conclusion:(RegExpOpr::reduceRegExpPos((str.in.re t R))),
+ // corresponding to the one-step unfolding of the premise.
+ RE_UNFOLD_POS,
+ // ======== Regular expression unfold negative
+ // Children: (P:(not (str.in.re t R)))
+ // Arguments: none
+ // ---------------------
+ // Conclusion:(RegExpOpr::reduceRegExpNeg((not (str.in.re t R)))),
+ // corresponding to the one-step unfolding of the premise.
+ RE_UNFOLD_NEG,
+ // ======== Regular expression unfold negative concat fixed
+ // Children: (P:(not (str.in.re t R)))
+ // Arguments: none
+ // ---------------------
+ // Conclusion:(RegExpOpr::reduceRegExpNegConcatFixed((not (str.in.re t
+ // R)),L,i)) where RegExpOpr::getRegExpConcatFixed((not (str.in.re t R)), i) =
+ // L. corresponding to the one-step unfolding of the premise, optimized for
+ // fixed length of component i of the regular expression concatenation R.
+ RE_UNFOLD_NEG_CONCAT_FIXED,
+ // ======== Regular expression elimination
+ // Children: (P:F)
+ // Arguments: none
+ // ---------------------
+ // Conclusion: R
+ // where R = strings::RegExpElimination::eliminate(F).
+ RE_ELIM,
+ //======================== Code points
+ // Children: none
+ // Arguments: (t, s)
+ // ---------------------
+ // Conclusion:(or (= (str.code t) (- 1))
+ // (not (= (str.code t) (str.code s)))
+ // (not (= t s)))
+ STRING_CODE_INJ,
+ //======================== Sequence unit
+ // Children: (P:(= (seq.unit x) (seq.unit y)))
+ // Arguments: none
+ // ---------------------
+ // Conclusion:(= x y)
+ // Also applies to the case where (seq.unit y) is a constant sequence
+ // of length one.
+ STRING_SEQ_UNIT_INJ,
+ // ======== String Trust
+ // Children: none
+ // Arguments: (Q)
+ // ---------------------
+ // Conclusion: (Q)
+ STRING_TRUST,
+
+ //================================================= Arithmetic rules
// ======== Adding Inequalities
// Note: an ArithLiteral is a term of the form (>< poly const)
// where
@@ -617,6 +1077,12 @@ const char* toString(PfRule id);
*/
std::ostream& operator<<(std::ostream& out, PfRule id);
+/** Hash function for proof rules */
+struct PfRuleHashFunction
+{
+ size_t operator()(PfRule id) const;
+}; /* struct PfRuleHashFunction */
+
} // namespace CVC4
#endif /* CVC4__EXPR__PROOF_RULE_H */
diff --git a/src/expr/proof_set.h b/src/expr/proof_set.h
new file mode 100644
index 000000000..20ef67efe
--- /dev/null
+++ b/src/expr/proof_set.h
@@ -0,0 +1,75 @@
+/********************* */
+/*! \file proof_set.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Proof set utility
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__EXPR__PROOF_SET_H
+#define CVC4__EXPR__PROOF_SET_H
+
+#include <memory>
+
+#include "context/cdlist.h"
+#include "context/context.h"
+#include "expr/proof_node_manager.h"
+
+namespace CVC4 {
+
+/**
+ * A (context-dependent) set of proofs, which is used for memory
+ * management purposes.
+ */
+template <typename T>
+class CDProofSet
+{
+ public:
+ CDProofSet(ProofNodeManager* pnm,
+ context::Context* c,
+ std::string namePrefix = "Proof")
+ : d_pnm(pnm), d_proofs(c), d_namePrefix(namePrefix)
+ {
+ }
+ /**
+ * Allocate a new proof.
+ *
+ * This returns a fresh proof object that remains alive in the context given
+ * to this class. Internally, this adds a new proof of type T to a
+ * context-dependent list of proofs and passes the following arguments to the
+ * T constructor:
+ * pnm, args..., name
+ * where pnm is the proof node manager
+ * provided to this proof set upon construction, args... are the arguments to
+ * allocateProof() and name is the namePrefix with an appended index.
+ */
+ template <typename... Args>
+ T* allocateProof(Args&&... args)
+ {
+ d_proofs.push_back(std::make_shared<T>(
+ d_pnm,
+ std::forward<Args>(args)...,
+ d_namePrefix + "_" + std::to_string(d_proofs.size())));
+ return d_proofs.back().get();
+ }
+
+ protected:
+ /** The proof node manager */
+ ProofNodeManager* d_pnm;
+ /** A context-dependent list of lazy proofs. */
+ context::CDList<std::shared_ptr<T>> d_proofs;
+ /** The name prefix of the lazy proofs */
+ std::string d_namePrefix;
+};
+
+} // namespace CVC4
+
+#endif /* CVC4__EXPR__LAZY_PROOF_SET_H */
diff --git a/src/expr/proof_step_buffer.cpp b/src/expr/proof_step_buffer.cpp
index 7108e4dae..bb02aeb20 100644
--- a/src/expr/proof_step_buffer.cpp
+++ b/src/expr/proof_step_buffer.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/proof_step_buffer.h b/src/expr/proof_step_buffer.h
index 5a9d82e42..4e463a7b3 100644
--- a/src/expr/proof_step_buffer.h
+++ b/src/expr/proof_step_buffer.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/record.cpp b/src/expr/record.cpp
index 075ca4de4..f4004d2e7 100644
--- a/src/expr/record.cpp
+++ b/src/expr/record.cpp
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Piotr Trojanek
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/record.h b/src/expr/record.h
index 0a2dcc515..62ccd42db 100644
--- a/src/expr/record.h
+++ b/src/expr/record.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/sequence.cpp b/src/expr/sequence.cpp
index 394c1a407..f65558184 100644
--- a/src/expr/sequence.cpp
+++ b/src/expr/sequence.cpp
@@ -2,10 +2,10 @@
/*! \file sequence.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds
+ ** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/sequence.h b/src/expr/sequence.h
index 5a037752f..27e5cf6f4 100644
--- a/src/expr/sequence.h
+++ b/src/expr/sequence.h
@@ -2,10 +2,10 @@
/*! \file sequence.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds
+ ** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/skolem_manager.cpp b/src/expr/skolem_manager.cpp
index e22bd26cf..a3647e84f 100644
--- a/src/expr/skolem_manager.cpp
+++ b/src/expr/skolem_manager.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -33,6 +33,7 @@ struct SkolemFormAttributeId
};
typedef expr::Attribute<SkolemFormAttributeId, Node> SkolemFormAttribute;
+// Maps terms to their purify skolem variables
struct PurifySkolemAttributeId
{
};
@@ -125,7 +126,7 @@ Node SkolemManager::skolemize(Node q,
// method deterministic ensures that the proof checker (e.g. for
// quantifiers) is capable of proving the expected value for conclusions
// of proof rules, instead of an alpha-equivalent variant of a conclusion.
- Node avp = getOrMakeBoundVariable(av, av);
+ Node avp = getOrMakeBoundVariable(av);
ovarsW.push_back(avp);
ovars.push_back(av);
}
@@ -182,19 +183,9 @@ Node SkolemManager::mkBooleanTermVariable(Node t)
return mkPurifySkolem(t, "", "", NodeManager::SKOLEM_BOOL_TERM_VAR);
}
-Node SkolemManager::mkExistential(Node t, Node p)
+ProofGenerator* SkolemManager::getProofGenerator(Node t) const
{
- Assert(p.getType().isBoolean());
- NodeManager* nm = NodeManager::currentNM();
- Node v = getOrMakeBoundVariable(t, p);
- Node bvl = nm->mkNode(BOUND_VAR_LIST, v);
- Node psubs = p.substitute(TNode(t), TNode(v));
- return nm->mkNode(EXISTS, bvl, psubs);
-}
-
-ProofGenerator* SkolemManager::getProofGenerator(Node t)
-{
- std::map<Node, ProofGenerator*>::iterator it = d_gens.find(t);
+ std::map<Node, ProofGenerator*>::const_iterator it = d_gens.find(t);
if (it != d_gens.end())
{
return it->second;
@@ -353,18 +344,16 @@ Node SkolemManager::getOrMakeSkolem(Node w,
return k;
}
-Node SkolemManager::getOrMakeBoundVariable(Node t, Node s)
+Node SkolemManager::getOrMakeBoundVariable(Node t)
{
- std::pair<Node, Node> key(t, s);
- std::map<std::pair<Node, Node>, Node>::iterator it =
- d_witnessBoundVar.find(key);
+ std::map<Node, Node>::iterator it = d_witnessBoundVar.find(t);
if (it != d_witnessBoundVar.end())
{
return it->second;
}
TypeNode tt = t.getType();
Node v = NodeManager::currentNM()->mkBoundVar(tt);
- d_witnessBoundVar[key] = v;
+ d_witnessBoundVar[t] = v;
return v;
}
diff --git a/src/expr/skolem_manager.h b/src/expr/skolem_manager.h
index 1e02d94f4..537c0b1e9 100644
--- a/src/expr/skolem_manager.h
+++ b/src/expr/skolem_manager.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -159,13 +159,7 @@ class SkolemManager
* Get proof generator for existentially quantified formula q. This returns
* the proof generator that was provided in a call to mkSkolem above.
*/
- ProofGenerator* getProofGenerator(Node q);
- /**
- * Make existential. Given t and p[t] where p is a formula, this returns
- * (exists ((x T)) p[x])
- * where T is the type of t, and x is a variable unique to t,p.
- */
- Node mkExistential(Node t, Node p);
+ ProofGenerator* getProofGenerator(Node q) const;
/**
* Convert to witness form, where notice this recursively replaces *all*
* skolems in n by their corresponding witness term. This is intended to be
@@ -197,7 +191,7 @@ class SkolemManager
* Map to canonical bound variables. This is used for example by the method
* mkExistential.
*/
- std::map<std::pair<Node, Node>, Node> d_witnessBoundVar;
+ std::map<Node, Node> d_witnessBoundVar;
/** Convert to witness or skolem form */
static Node convertInternal(Node n, bool toWitness);
/** Get or make skolem attribute for witness term w */
@@ -224,10 +218,11 @@ class SkolemManager
const std::string& comment = "",
int flags = NodeManager::SKOLEM_DEFAULT);
/**
- * Get or make bound variable unique to (s,t), for d_witnessBoundVar, where
- * t and s are terms.
+ * Get or make bound variable unique to t whose type is the same as t. This
+ * is used to construct canonical bound variables e.g. for constructing
+ * bound variables for witness terms in the skolemize method above.
*/
- Node getOrMakeBoundVariable(Node t, Node s);
+ Node getOrMakeBoundVariable(Node t);
};
} // namespace CVC4
diff --git a/src/expr/subs.cpp b/src/expr/subs.cpp
new file mode 100644
index 000000000..541db1ac5
--- /dev/null
+++ b/src/expr/subs.cpp
@@ -0,0 +1,177 @@
+/********************* */
+/*! \file subs.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Simple substitution utility
+ **/
+
+#include "expr/subs.h"
+
+#include "theory/rewriter.h"
+
+namespace CVC4 {
+
+bool Subs::empty() const { return d_vars.empty(); }
+
+size_t Subs::size() const { return d_vars.size(); }
+
+bool Subs::contains(Node v) const
+{
+ return std::find(d_vars.begin(), d_vars.end(), v) != d_vars.end();
+}
+
+Node Subs::getSubs(Node v) const
+{
+ std::vector<Node>::const_iterator it =
+ std::find(d_vars.begin(), d_vars.end(), v);
+ if (it == d_vars.end())
+ {
+ return Node::null();
+ }
+ size_t i = std::distance(d_vars.begin(), it);
+ Assert(i < d_subs.size());
+ return d_subs[i];
+}
+
+void Subs::add(Node v)
+{
+ // default, use a fresh skolem of the same type
+ Node s = NodeManager::currentNM()->mkSkolem("sk", v.getType());
+ add(v, s);
+}
+
+void Subs::add(const std::vector<Node>& vs)
+{
+ for (const Node& v : vs)
+ {
+ add(v);
+ }
+}
+
+void Subs::add(Node v, Node s)
+{
+ Assert(v.getType().isComparableTo(s.getType()));
+ d_vars.push_back(v);
+ d_subs.push_back(s);
+}
+
+void Subs::add(const std::vector<Node>& vs, const std::vector<Node>& ss)
+{
+ Assert(vs.size() == ss.size());
+ for (size_t i = 0, nvs = vs.size(); i < nvs; i++)
+ {
+ add(vs[i], ss[i]);
+ }
+}
+
+void Subs::addEquality(Node eq)
+{
+ Assert(eq.getKind() == kind::EQUAL);
+ add(eq[0], eq[1]);
+}
+
+void Subs::append(Subs& s)
+{
+ // add the substitution list
+ add(s.d_vars, s.d_subs);
+}
+
+Node Subs::apply(Node n, bool doRewrite) const
+{
+ if (d_vars.empty())
+ {
+ return n;
+ }
+ Node ns =
+ n.substitute(d_vars.begin(), d_vars.end(), d_subs.begin(), d_subs.end());
+ if (doRewrite)
+ {
+ ns = theory::Rewriter::rewrite(ns);
+ }
+ return ns;
+}
+Node Subs::rapply(Node n, bool doRewrite) const
+{
+ if (d_vars.empty())
+ {
+ return n;
+ }
+ Node ns =
+ n.substitute(d_subs.begin(), d_subs.end(), d_vars.begin(), d_vars.end());
+ if (doRewrite)
+ {
+ ns = theory::Rewriter::rewrite(ns);
+ }
+ return ns;
+}
+
+void Subs::applyToRange(Subs& s, bool doRewrite) const
+{
+ if (d_vars.empty())
+ {
+ return;
+ }
+ for (size_t i = 0, ns = s.d_subs.size(); i < ns; i++)
+ {
+ s.d_subs[i] = apply(s.d_subs[i], doRewrite);
+ }
+}
+
+void Subs::rapplyToRange(Subs& s, bool doRewrite) const
+{
+ if (d_vars.empty())
+ {
+ return;
+ }
+ for (size_t i = 0, ns = s.d_subs.size(); i < ns; i++)
+ {
+ s.d_subs[i] = rapply(s.d_subs[i], doRewrite);
+ }
+}
+
+Node Subs::getEquality(size_t i) const
+{
+ Assert(i < d_vars.size());
+ return d_vars[i].eqNode(d_subs[i]);
+}
+
+std::map<Node, Node> Subs::toMap() const
+{
+ std::map<Node, Node> ret;
+ for (size_t i = 0, nvs = d_vars.size(); i < nvs; i++)
+ {
+ ret[d_vars[i]] = d_subs[i];
+ }
+ return ret;
+}
+
+std::string Subs::toString() const
+{
+ std::stringstream ss;
+ ss << "[";
+ for (size_t i = 0, nvs = d_vars.size(); i < nvs; i++)
+ {
+ if (i > 0)
+ {
+ ss << " ";
+ }
+ ss << d_vars[i] << " -> " << d_subs[i];
+ }
+ ss << "]";
+ return ss.str();
+}
+
+std::ostream& operator<<(std::ostream& out, const Subs& s)
+{
+ out << s.toString();
+ return out;
+}
+
+} // namespace CVC4
diff --git a/src/expr/subs.h b/src/expr/subs.h
new file mode 100644
index 000000000..ac678d2ee
--- /dev/null
+++ b/src/expr/subs.h
@@ -0,0 +1,85 @@
+/********************* */
+/*! \file subs.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Simple substitution utility
+ **/
+
+#ifndef CVC4__EXPR__SUBS_H
+#define CVC4__EXPR__SUBS_H
+
+#include <map>
+#include <vector>
+#include "expr/node.h"
+
+namespace CVC4 {
+
+/**
+ * Helper substitution class. Stores a substitution in parallel vectors
+ * d_vars and d_subs, both of which may be arbitrary terms, having the same
+ * types pairwise.
+ *
+ * Notice this class applies substitutions using Node::substitute. Furthermore,
+ * it does not insist that the terms in d_vars are unique.
+ */
+class Subs
+{
+ public:
+ /** Is the substitution empty? */
+ bool empty() const;
+ /** The size of the substitution */
+ size_t size() const;
+ /** Does the substitution contain v? */
+ bool contains(Node v) const;
+ /** Get the substitution for v if it exists, or null otherwise */
+ Node getSubs(Node v) const;
+ /** Add v -> k for fresh skolem of the same type as v */
+ void add(Node v);
+ /** Add v -> k for fresh skolem of the same type as v for each v in vs */
+ void add(const std::vector<Node>& vs);
+ /** Add v -> s to the substitution */
+ void add(Node v, Node s);
+ /** Add vs -> ss to the substitution */
+ void add(const std::vector<Node>& vs, const std::vector<Node>& ss);
+ /** Add eq[0] -> eq[1] to the substitution */
+ void addEquality(Node eq);
+ /** Append the substitution s to this */
+ void append(Subs& s);
+ /** Return the result of this substitution on n */
+ Node apply(Node n, bool doRewrite = false) const;
+ /** Return the result of the reverse of this substitution on n */
+ Node rapply(Node n, bool doRewrite = false) const;
+ /** Apply this substitution to all nodes in the range of s */
+ void applyToRange(Subs& s, bool doRewrite = false) const;
+ /** Apply the reverse of this substitution to all nodes in the range of s */
+ void rapplyToRange(Subs& s, bool doRewrite = false) const;
+ /** Get equality (= v s) where v -> s is the i^th position in the vectors */
+ Node getEquality(size_t i) const;
+ /** Convert substitution to map */
+ std::map<Node, Node> toMap() const;
+ /** Get string for this substitution */
+ std::string toString() const;
+ /** The data */
+ std::vector<Node> d_vars;
+ std::vector<Node> d_subs;
+};
+
+/**
+ * Serializes a given substitution to the given stream.
+ *
+ * @param out the output stream to use
+ * @param s the substitution to output to the stream
+ * @return the stream
+ */
+std::ostream& operator<<(std::ostream& out, const Subs& s);
+
+} // namespace CVC4
+
+#endif /* CVC4__EXPR__SUBS_H */
diff --git a/src/expr/sygus_datatype.cpp b/src/expr/sygus_datatype.cpp
index 1efea4e15..3401e55f7 100644
--- a/src/expr/sygus_datatype.cpp
+++ b/src/expr/sygus_datatype.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,10 +18,7 @@ using namespace CVC4::kind;
namespace CVC4 {
-SygusDatatype::SygusDatatype(const std::string& name)
- : d_dt(Datatype(NodeManager::currentNM()->toExprManager(), name))
-{
-}
+SygusDatatype::SygusDatatype(const std::string& name) : d_dt(DType(name)) {}
std::string SygusDatatype::getName() const { return d_dt.getName(); }
@@ -79,25 +76,19 @@ void SygusDatatype::initializeDatatype(TypeNode sygusType,
Assert(!d_cons.empty());
/* Use the sygus type to not lose reference to the original types (Bool,
* Int, etc) */
- d_dt.setSygus(sygusType.toType(), sygusVars.toExpr(), allowConst, allowAll);
+ d_dt.setSygus(sygusType, sygusVars, allowConst, allowAll);
for (unsigned i = 0, ncons = d_cons.size(); i < ncons; ++i)
{
- // must convert to type now
- std::vector<Type> cargs;
- for (TypeNode& ct : d_cons[i].d_argTypes)
- {
- cargs.push_back(ct.toType());
- }
// add (sygus) constructor
- d_dt.addSygusConstructor(d_cons[i].d_op.toExpr(),
+ d_dt.addSygusConstructor(d_cons[i].d_op,
d_cons[i].d_name,
- cargs,
+ d_cons[i].d_argTypes,
d_cons[i].d_weight);
}
Trace("sygus-type-cons") << "...built datatype " << d_dt << " ";
}
-const Datatype& SygusDatatype::getDatatype() const
+const DType& SygusDatatype::getDatatype() const
{
// should have initialized by this point
Assert(isInitialized());
diff --git a/src/expr/sygus_datatype.h b/src/expr/sygus_datatype.h
index 4342aa291..2be3d9d49 100644
--- a/src/expr/sygus_datatype.h
+++ b/src/expr/sygus_datatype.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,7 +20,7 @@
#include <vector>
#include "expr/attribute.h"
-#include "expr/datatype.h"
+#include "expr/dtype.h"
#include "expr/node.h"
#include "expr/type_node.h"
@@ -122,7 +122,7 @@ class SygusDatatype
bool allowConst,
bool allowAll);
/** Get the sygus datatype initialized by this class */
- const Datatype& getDatatype() const;
+ const DType& getDatatype() const;
/** is initialized */
bool isInitialized() const;
@@ -131,7 +131,7 @@ class SygusDatatype
/** Information for each constructor. */
std::vector<SygusDatatypeConstructor> d_cons;
/** Datatype to represent type's structure */
- Datatype d_dt;
+ DType d_dt;
};
} // namespace CVC4
diff --git a/src/expr/symbol_manager.cpp b/src/expr/symbol_manager.cpp
new file mode 100644
index 000000000..a163e503d
--- /dev/null
+++ b/src/expr/symbol_manager.cpp
@@ -0,0 +1,256 @@
+/********************* */
+/*! \file symbol_manager.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The symbol manager
+ **/
+
+#include "expr/symbol_manager.h"
+
+#include "context/cdhashmap.h"
+#include "context/cdhashset.h"
+#include "context/cdo.h"
+
+using namespace CVC4::context;
+
+namespace CVC4 {
+
+// ---------------------------------------------- SymbolManager::Implementation
+
+class SymbolManager::Implementation
+{
+ using TermStringMap = CDHashMap<api::Term, std::string, api::TermHashFunction>;
+ using TermSet = CDHashSet<api::Term, api::TermHashFunction>;
+
+ public:
+ Implementation()
+ : d_context(),
+ d_names(&d_context),
+ d_namedAsserts(&d_context),
+ d_hasPushedScope(&d_context, false)
+ {
+ }
+
+ ~Implementation() {}
+ /** set expression name */
+ bool setExpressionName(api::Term t,
+ const std::string& name,
+ bool isAssertion = false);
+ /** get expression name */
+ bool getExpressionName(api::Term t,
+ std::string& name,
+ bool isAssertion = false) const;
+ /** get expression names */
+ void getExpressionNames(const std::vector<api::Term>& ts,
+ std::vector<std::string>& names,
+ bool areAssertions = false) const;
+ /** get expression names */
+ std::map<api::Term, std::string> getExpressionNames(bool areAssertions) const;
+ /** reset */
+ void reset();
+ /** Push a scope in the expression names. */
+ void pushScope(bool isUserContext);
+ /** Pop a scope in the expression names. */
+ void popScope();
+
+ private:
+ /** The context manager for the scope maps. */
+ Context d_context;
+ /** Map terms to names */
+ TermStringMap d_names;
+ /** The set of terms with assertion names */
+ TermSet d_namedAsserts;
+ /**
+ * Have we pushed a scope (e.g. a let or quantifier) in the current context?
+ */
+ CDO<bool> d_hasPushedScope;
+};
+
+bool SymbolManager::Implementation::setExpressionName(api::Term t,
+ const std::string& name,
+ bool isAssertion)
+{
+ Trace("sym-manager") << "set expression name: " << t << " -> " << name
+ << ", isAssertion=" << isAssertion << std::endl;
+ // cannot name subexpressions under quantifiers
+ PrettyCheckArgument(
+ !d_hasPushedScope.get(), name, "cannot name function in a scope");
+ if (isAssertion)
+ {
+ d_namedAsserts.insert(t);
+ }
+ if (d_names.find(t) != d_names.end())
+ {
+ // already named assertion
+ return false;
+ }
+ d_names[t] = name;
+ return true;
+}
+
+bool SymbolManager::Implementation::getExpressionName(api::Term t,
+ std::string& name,
+ bool isAssertion) const
+{
+ TermStringMap::const_iterator it = d_names.find(t);
+ if (it == d_names.end())
+ {
+ return false;
+ }
+ if (isAssertion)
+ {
+ // must be an assertion name
+ if (d_namedAsserts.find(t) == d_namedAsserts.end())
+ {
+ return false;
+ }
+ }
+ name = (*it).second;
+ return true;
+}
+
+void SymbolManager::Implementation::getExpressionNames(
+ const std::vector<api::Term>& ts,
+ std::vector<std::string>& names,
+ bool areAssertions) const
+{
+ for (const api::Term& t : ts)
+ {
+ std::string name;
+ if (getExpressionName(t, name, areAssertions))
+ {
+ names.push_back(name);
+ }
+ }
+}
+
+std::map<api::Term, std::string>
+SymbolManager::Implementation::getExpressionNames(bool areAssertions) const
+{
+ std::map<api::Term, std::string> emap;
+ for (TermStringMap::const_iterator it = d_names.begin(),
+ itend = d_names.end();
+ it != itend;
+ ++it)
+ {
+ api::Term t = (*it).first;
+ if (areAssertions && d_namedAsserts.find(t) == d_namedAsserts.end())
+ {
+ continue;
+ }
+ emap[t] = (*it).second;
+ }
+ return emap;
+}
+
+void SymbolManager::Implementation::pushScope(bool isUserContext)
+{
+ Trace("sym-manager") << "pushScope, isUserContext = " << isUserContext
+ << std::endl;
+ PrettyCheckArgument(!d_hasPushedScope.get() || !isUserContext,
+ "cannot push a user context within a scope context");
+ d_context.push();
+ if (!isUserContext)
+ {
+ d_hasPushedScope = true;
+ }
+}
+
+void SymbolManager::Implementation::popScope()
+{
+ Trace("sym-manager") << "popScope" << std::endl;
+ if (d_context.getLevel() == 0)
+ {
+ throw ScopeException();
+ }
+ d_context.pop();
+ Trace("sym-manager-debug")
+ << "d_hasPushedScope is now " << d_hasPushedScope.get() << std::endl;
+}
+
+void SymbolManager::Implementation::reset()
+{
+ // clear names?
+}
+
+// ---------------------------------------------- SymbolManager
+
+SymbolManager::SymbolManager(api::Solver* s)
+ : d_solver(s),
+ d_implementation(new SymbolManager::Implementation()),
+ d_globalDeclarations(false)
+{
+}
+
+SymbolManager::~SymbolManager() {}
+
+SymbolTable* SymbolManager::getSymbolTable() { return &d_symtabAllocated; }
+
+bool SymbolManager::setExpressionName(api::Term t,
+ const std::string& name,
+ bool isAssertion)
+{
+ return d_implementation->setExpressionName(t, name, isAssertion);
+}
+
+bool SymbolManager::getExpressionName(api::Term t,
+ std::string& name,
+ bool isAssertion) const
+{
+ return d_implementation->getExpressionName(t, name, isAssertion);
+}
+
+void SymbolManager::getExpressionNames(const std::vector<api::Term>& ts,
+ std::vector<std::string>& names,
+ bool areAssertions) const
+{
+ return d_implementation->getExpressionNames(ts, names, areAssertions);
+}
+
+std::map<api::Term, std::string> SymbolManager::getExpressionNames(
+ bool areAssertions) const
+{
+ return d_implementation->getExpressionNames(areAssertions);
+}
+
+size_t SymbolManager::scopeLevel() const
+{
+ return d_symtabAllocated.getLevel();
+}
+
+void SymbolManager::pushScope(bool isUserContext)
+{
+ d_implementation->pushScope(isUserContext);
+ d_symtabAllocated.pushScope();
+}
+
+void SymbolManager::popScope()
+{
+ d_symtabAllocated.popScope();
+ d_implementation->popScope();
+}
+
+void SymbolManager::setGlobalDeclarations(bool flag)
+{
+ d_globalDeclarations = flag;
+}
+
+bool SymbolManager::getGlobalDeclarations() const
+{
+ return d_globalDeclarations;
+}
+
+void SymbolManager::reset()
+{
+ d_symtabAllocated.reset();
+ d_implementation->reset();
+}
+
+} // namespace CVC4
diff --git a/src/expr/symbol_manager.h b/src/expr/symbol_manager.h
new file mode 100644
index 000000000..a3ca8e780
--- /dev/null
+++ b/src/expr/symbol_manager.h
@@ -0,0 +1,140 @@
+/********************* */
+/*! \file symbol_manager.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The symbol manager
+ **/
+
+#include "cvc4_public.h"
+
+#ifndef CVC4__EXPR__SYMBOL_MANAGER_H
+#define CVC4__EXPR__SYMBOL_MANAGER_H
+
+#include <map>
+#include <memory>
+#include <set>
+#include <string>
+
+#include "api/cvc4cpp.h"
+#include "expr/symbol_table.h"
+
+namespace CVC4 {
+
+/**
+ * Symbol manager, which manages:
+ * (1) The symbol table used by the parser,
+ * (2) Information related to the (! ... :named s) feature in SMT-LIB version 2.
+ *
+ * Like SymbolTable, this class currently lives in src/expr/ since it uses
+ * context-dependent data structures.
+ */
+class CVC4_PUBLIC SymbolManager
+{
+ public:
+ SymbolManager(api::Solver* s);
+ ~SymbolManager();
+ /** Get the underlying symbol table */
+ SymbolTable* getSymbolTable();
+ //---------------------------- named expressions
+ /** Set name of term t to name
+ *
+ * @param t The term to name
+ * @param name The given name
+ * @param isAssertion Whether t is being given a name in an assertion
+ * context. In particular, this is true if and only if there was an assertion
+ * command of the form (assert (! t :named name)).
+ * @return true if the name was set. This method may return false if t
+ * already has a name.
+ */
+ bool setExpressionName(api::Term t,
+ const std::string& name,
+ bool isAssertion = false);
+ /** Get name for term t
+ *
+ * @param t The term
+ * @param name The argument to update with the name of t
+ * @param isAssertion Whether we only wish to get the assertion name of t
+ * @return true if t has a name. If so, name is updated to that name.
+ * Otherwise, name is unchanged.
+ */
+ bool getExpressionName(api::Term t,
+ std::string& name,
+ bool isAssertion = false) const;
+ /**
+ * Convert list of terms to list of names. This adds to names the names of
+ * all terms in ts that has names. Terms that do not have names are not
+ * included.
+ *
+ * Notice that we do not distinguish what terms among those in ts have names.
+ * If the caller of this method wants more fine-grained information about what
+ * specific terms had names, then use the more fine grained interface above,
+ * per term.
+ *
+ * @param ts The terms
+ * @param names The name list
+ * @param areAssertions Whether we only wish to include assertion names
+ */
+ void getExpressionNames(const std::vector<api::Term>& ts,
+ std::vector<std::string>& names,
+ bool areAssertions = false) const;
+ /**
+ * Get a mapping of all expression names.
+ *
+ * @param areAssertions Whether we only wish to include assertion names
+ * @return the mapping containing all expression names.
+ */
+ std::map<api::Term, std::string> getExpressionNames(
+ bool areAssertions = false) const;
+ //---------------------------- end named expressions
+ /**
+ * Get the scope level of the symbol table.
+ */
+ size_t scopeLevel() const;
+ /**
+ * Push a scope in the symbol table.
+ *
+ * @param isUserContext If true, this push is denoting a push of the user
+ * context, e.g. via an smt2 push/pop command. Otherwise, this push is
+ * due to a let/quantifier binding.
+ */
+ void pushScope(bool isUserContext);
+ /**
+ * Pop a scope in the symbol table.
+ */
+ void popScope();
+ /**
+ * Reset this symbol manager, which resets the symbol table.
+ */
+ void reset();
+ /** Set global declarations to the value flag. */
+ void setGlobalDeclarations(bool flag);
+ /** Get global declarations flag. */
+ bool getGlobalDeclarations() const;
+
+ private:
+ /** The API Solver object. */
+ api::Solver* d_solver;
+ /**
+ * The declaration scope that is "owned" by this symbol manager.
+ */
+ SymbolTable d_symtabAllocated;
+ /** The implementation of the symbol manager */
+ class Implementation;
+ std::unique_ptr<Implementation> d_implementation;
+ /**
+ * Whether the global declarations option is enabled. This corresponds to the
+ * SMT-LIB option :global-declarations. By default, its value is false.
+ */
+ bool d_globalDeclarations;
+};
+
+} // namespace CVC4
+
+#endif /* CVC4__EXPR__SYMBOL_MANAGER_H */
diff --git a/src/expr/symbol_table.cpp b/src/expr/symbol_table.cpp
index 68d3904d3..3d01b778c 100644
--- a/src/expr/symbol_table.cpp
+++ b/src/expr/symbol_table.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -23,11 +23,11 @@
#include <unordered_map>
#include <utility>
+#include "api/cvc4cpp.h"
#include "context/cdhashmap.h"
#include "context/cdhashset.h"
#include "context/context.h"
-#include "expr/expr.h"
-#include "expr/expr_manager_scope.h"
+#include "expr/dtype.h"
#include "expr/type.h"
namespace CVC4 {
@@ -94,32 +94,34 @@ using ::std::vector;
class OverloadedTypeTrie {
public:
OverloadedTypeTrie(Context* c, bool allowFunVariants = false)
- : d_overloaded_symbols(new (true) CDHashSet<Expr, ExprHashFunction>(c)),
+ : d_overloaded_symbols(
+ new (true) CDHashSet<api::Term, api::TermHashFunction>(c)),
d_allowFunctionVariants(allowFunVariants)
{
}
~OverloadedTypeTrie() { d_overloaded_symbols->deleteSelf(); }
/** is this function overloaded? */
- bool isOverloadedFunction(Expr fun) const;
+ bool isOverloadedFunction(api::Term fun) const;
/** Get overloaded constant for type.
* If possible, it returns a defined symbol with name
* that has type t. Otherwise returns null expression.
*/
- Expr getOverloadedConstantForType(const std::string& name, Type t) const;
+ api::Term getOverloadedConstantForType(const std::string& name,
+ api::Sort t) const;
/**
* If possible, returns a defined function for a name
* and a vector of expected argument types. Otherwise returns
* null expression.
*/
- Expr getOverloadedFunctionForTypes(const std::string& name,
- const std::vector<Type>& argTypes) const;
+ api::Term getOverloadedFunctionForTypes(
+ const std::string& name, const std::vector<api::Sort>& argTypes) const;
/** called when obj is bound to name, and prev_bound_obj was already bound to
* name Returns false if the binding is invalid.
*/
- bool bind(const string& name, Expr prev_bound_obj, Expr obj);
+ bool bind(const string& name, api::Term prev_bound_obj, api::Term obj);
private:
/** Marks expression obj with name as overloaded.
@@ -137,9 +139,9 @@ class OverloadedTypeTrie {
* These are put in the same place in the trie but do not have identical type,
* hence we return false.
*/
- bool markOverloaded(const string& name, Expr obj);
+ bool markOverloaded(const string& name, api::Term obj);
/** the null expression */
- Expr d_nullExpr;
+ api::Term d_nullTerm;
// The (context-independent) trie storing that maps expected argument
// vectors to symbols. All expressions stored in d_symbols are only
// interpreted as active if they also appear in the context-dependent
@@ -147,15 +149,15 @@ class OverloadedTypeTrie {
class TypeArgTrie {
public:
// children of this node
- std::map<Type, TypeArgTrie> d_children;
+ std::map<api::Sort, TypeArgTrie> d_children;
// symbols at this node
- std::map<Type, Expr> d_symbols;
+ std::map<api::Sort, api::Term> d_symbols;
};
/** for each string with operator overloading, this stores the data structure
* above. */
std::unordered_map<std::string, TypeArgTrie> d_overload_type_arg_trie;
/** The set of overloaded symbols. */
- CDHashSet<Expr, ExprHashFunction>* d_overloaded_symbols;
+ CDHashSet<api::Term, api::TermHashFunction>* d_overloaded_symbols;
/** allow function variants
* This is true if we allow overloading (non-constant) functions that expect
* the same argument types.
@@ -167,77 +169,64 @@ class OverloadedTypeTrie {
* if reqUnique=true.
* Otherwise, it returns the null expression.
*/
- Expr getOverloadedFunctionAt(const TypeArgTrie* tat, bool reqUnique=true) const;
+ api::Term getOverloadedFunctionAt(const TypeArgTrie* tat,
+ bool reqUnique = true) const;
};
-bool OverloadedTypeTrie::isOverloadedFunction(Expr fun) const {
+bool OverloadedTypeTrie::isOverloadedFunction(api::Term fun) const
+{
return d_overloaded_symbols->find(fun) != d_overloaded_symbols->end();
}
-Expr OverloadedTypeTrie::getOverloadedConstantForType(const std::string& name,
- Type t) const {
+api::Term OverloadedTypeTrie::getOverloadedConstantForType(
+ const std::string& name, api::Sort t) const
+{
std::unordered_map<std::string, TypeArgTrie>::const_iterator it =
d_overload_type_arg_trie.find(name);
if (it != d_overload_type_arg_trie.end()) {
- std::map<Type, Expr>::const_iterator its = it->second.d_symbols.find(t);
+ std::map<api::Sort, api::Term>::const_iterator its =
+ it->second.d_symbols.find(t);
if (its != it->second.d_symbols.end()) {
- Expr expr = its->second;
+ api::Term expr = its->second;
// must be an active symbol
if (isOverloadedFunction(expr)) {
return expr;
}
}
}
- return d_nullExpr;
+ return d_nullTerm;
}
-Expr OverloadedTypeTrie::getOverloadedFunctionForTypes(
- const std::string& name, const std::vector<Type>& argTypes) const {
+api::Term OverloadedTypeTrie::getOverloadedFunctionForTypes(
+ const std::string& name, const std::vector<api::Sort>& argTypes) const
+{
std::unordered_map<std::string, TypeArgTrie>::const_iterator it =
d_overload_type_arg_trie.find(name);
if (it != d_overload_type_arg_trie.end()) {
const TypeArgTrie* tat = &it->second;
for (unsigned i = 0; i < argTypes.size(); i++) {
- std::map<Type, TypeArgTrie>::const_iterator itc =
+ std::map<api::Sort, TypeArgTrie>::const_iterator itc =
tat->d_children.find(argTypes[i]);
if (itc != tat->d_children.end()) {
tat = &itc->second;
} else {
Trace("parser-overloading")
<< "Could not find overloaded function " << name << std::endl;
- // it may be a parametric datatype
- TypeNode tna = TypeNode::fromType(argTypes[i]);
- if (tna.isParametricDatatype())
- {
- Trace("parser-overloading")
- << "Parametric overloaded datatype selector " << name << " "
- << tna << std::endl;
- DatatypeType tnd = static_cast<DatatypeType>(argTypes[i]);
- const Datatype& dt = tnd.getDatatype();
- // tng is the "generalized" version of the instantiated parametric
- // type tna
- Type tng = dt.getDatatypeType();
- itc = tat->d_children.find(tng);
- if (itc != tat->d_children.end())
- {
- tat = &itc->second;
- }
- }
- if (tat == nullptr)
- {
+
// no functions match
- return d_nullExpr;
- }
+ return d_nullTerm;
}
}
// we ensure that there is *only* one active symbol at this node
return getOverloadedFunctionAt(tat);
}
- return d_nullExpr;
+ return d_nullTerm;
}
-bool OverloadedTypeTrie::bind(const string& name, Expr prev_bound_obj,
- Expr obj) {
+bool OverloadedTypeTrie::bind(const string& name,
+ api::Term prev_bound_obj,
+ api::Term obj)
+{
bool retprev = true;
if (!isOverloadedFunction(prev_bound_obj)) {
// mark previous as overloaded
@@ -248,25 +237,33 @@ bool OverloadedTypeTrie::bind(const string& name, Expr prev_bound_obj,
return retprev && retobj;
}
-bool OverloadedTypeTrie::markOverloaded(const string& name, Expr obj) {
+bool OverloadedTypeTrie::markOverloaded(const string& name, api::Term obj)
+{
Trace("parser-overloading") << "Overloaded function : " << name;
- Trace("parser-overloading") << " with type " << obj.getType() << std::endl;
+ Trace("parser-overloading") << " with type " << obj.getSort() << std::endl;
// get the argument types
- Type t = obj.getType();
- Type rangeType = t;
- std::vector<Type> argTypes;
- if (t.isFunction()) {
- argTypes = static_cast<FunctionType>(t).getArgTypes();
- rangeType = static_cast<FunctionType>(t).getRangeType();
- } else if (t.isConstructor()) {
- argTypes = static_cast<ConstructorType>(t).getArgTypes();
- rangeType = static_cast<ConstructorType>(t).getRangeType();
- } else if (t.isTester()) {
- argTypes.push_back(static_cast<TesterType>(t).getDomain());
- rangeType = static_cast<TesterType>(t).getRangeType();
- } else if (t.isSelector()) {
- argTypes.push_back(static_cast<SelectorType>(t).getDomain());
- rangeType = static_cast<SelectorType>(t).getRangeType();
+ api::Sort t = obj.getSort();
+ api::Sort rangeType = t;
+ std::vector<api::Sort> argTypes;
+ if (t.isFunction())
+ {
+ argTypes = t.getFunctionDomainSorts();
+ rangeType = t.getFunctionCodomainSort();
+ }
+ else if (t.isConstructor())
+ {
+ argTypes = t.getConstructorDomainSorts();
+ rangeType = t.getConstructorCodomainSort();
+ }
+ else if (t.isTester())
+ {
+ argTypes.push_back(t.getTesterDomainSort());
+ rangeType = t.getTesterCodomainSort();
+ }
+ else if (t.isSelector())
+ {
+ argTypes.push_back(t.getSelectorDomainSort());
+ rangeType = t.getSelectorCodomainSort();
}
// add to the trie
TypeArgTrie* tat = &d_overload_type_arg_trie[name];
@@ -278,10 +275,11 @@ bool OverloadedTypeTrie::markOverloaded(const string& name, Expr obj) {
if (d_allowFunctionVariants || argTypes.empty())
{
// they are allowed, check for redefinition
- std::map<Type, Expr>::iterator it = tat->d_symbols.find(rangeType);
+ std::map<api::Sort, api::Term>::iterator it =
+ tat->d_symbols.find(rangeType);
if (it != tat->d_symbols.end())
{
- Expr prev_obj = it->second;
+ api::Term prev_obj = it->second;
// if there is already an active function with the same name and expects
// the same argument types and has the same return type, we reject the
// re-declaration here.
@@ -294,7 +292,7 @@ bool OverloadedTypeTrie::markOverloaded(const string& name, Expr obj) {
else
{
// they are not allowed, we cannot have any function defined here.
- Expr existingFun = getOverloadedFunctionAt(tat, false);
+ api::Term existingFun = getOverloadedFunctionAt(tat, false);
if (!existingFun.isNull())
{
return false;
@@ -307,15 +305,16 @@ bool OverloadedTypeTrie::markOverloaded(const string& name, Expr obj) {
return true;
}
-Expr OverloadedTypeTrie::getOverloadedFunctionAt(
+api::Term OverloadedTypeTrie::getOverloadedFunctionAt(
const OverloadedTypeTrie::TypeArgTrie* tat, bool reqUnique) const
{
- Expr retExpr;
- for (std::map<Type, Expr>::const_iterator its = tat->d_symbols.begin();
+ api::Term retExpr;
+ for (std::map<api::Sort, api::Term>::const_iterator its =
+ tat->d_symbols.begin();
its != tat->d_symbols.end();
++its)
{
- Expr expr = its->second;
+ api::Term expr = its->second;
if (isOverloadedFunction(expr))
{
if (retExpr.isNull())
@@ -332,7 +331,7 @@ Expr OverloadedTypeTrie::getOverloadedFunctionAt(
else
{
// multiple functions match
- return d_nullExpr;
+ return d_nullTerm;
}
}
}
@@ -343,27 +342,27 @@ class SymbolTable::Implementation {
public:
Implementation()
: d_context(),
- d_exprMap(new (true) CDHashMap<string, Expr>(&d_context)),
- d_typeMap(new (true) TypeMap(&d_context))
+ d_exprMap(&d_context),
+ d_typeMap(&d_context),
+ d_overload_trie(&d_context)
{
- d_overload_trie = new OverloadedTypeTrie(&d_context);
}
~Implementation() {
- d_exprMap->deleteSelf();
- d_typeMap->deleteSelf();
- delete d_overload_trie;
}
- bool bind(const string& name, Expr obj, bool levelZero, bool doOverload);
- void bindType(const string& name, Type t, bool levelZero = false);
- void bindType(const string& name, const vector<Type>& params, Type t,
+ bool bind(const string& name, api::Term obj, bool levelZero, bool doOverload);
+ void bindType(const string& name, api::Sort t, bool levelZero = false);
+ void bindType(const string& name,
+ const vector<api::Sort>& params,
+ api::Sort t,
bool levelZero = false);
bool isBound(const string& name) const;
bool isBoundType(const string& name) const;
- Expr lookup(const string& name) const;
- Type lookupType(const string& name) const;
- Type lookupType(const string& name, const vector<Type>& params) const;
+ api::Term lookup(const string& name) const;
+ api::Sort lookupType(const string& name) const;
+ api::Sort lookupType(const string& name,
+ const vector<api::Sort>& params) const;
size_t lookupArity(const string& name);
void popScope();
void pushScope();
@@ -371,105 +370,116 @@ class SymbolTable::Implementation {
void reset();
//------------------------ operator overloading
/** implementation of function from header */
- bool isOverloadedFunction(Expr fun) const;
+ bool isOverloadedFunction(api::Term fun) const;
/** implementation of function from header */
- Expr getOverloadedConstantForType(const std::string& name, Type t) const;
+ api::Term getOverloadedConstantForType(const std::string& name,
+ api::Sort t) const;
/** implementation of function from header */
- Expr getOverloadedFunctionForTypes(const std::string& name,
- const std::vector<Type>& argTypes) const;
+ api::Term getOverloadedFunctionForTypes(
+ const std::string& name, const std::vector<api::Sort>& argTypes) const;
//------------------------ end operator overloading
private:
/** The context manager for the scope maps. */
Context d_context;
/** A map for expressions. */
- CDHashMap<string, Expr>* d_exprMap;
+ CDHashMap<string, api::Term> d_exprMap;
/** A map for types. */
- using TypeMap = CDHashMap<string, std::pair<vector<Type>, Type>>;
- TypeMap* d_typeMap;
+ using TypeMap = CDHashMap<string, std::pair<vector<api::Sort>, api::Sort>>;
+ TypeMap d_typeMap;
//------------------------ operator overloading
// the null expression
- Expr d_nullExpr;
+ api::Term d_nullTerm;
// overloaded type trie, stores all information regarding overloading
- OverloadedTypeTrie* d_overload_trie;
+ OverloadedTypeTrie d_overload_trie;
/** bind with overloading
* This is called whenever obj is bound to name where overloading symbols is
* allowed. If a symbol is previously bound to that name, it marks both as
* overloaded. Returns false if the binding was invalid.
*/
- bool bindWithOverloading(const string& name, Expr obj);
+ bool bindWithOverloading(const string& name, api::Term obj);
//------------------------ end operator overloading
}; /* SymbolTable::Implementation */
-bool SymbolTable::Implementation::bind(const string& name, Expr obj,
- bool levelZero, bool doOverload) {
- PrettyCheckArgument(!obj.isNull(), obj, "cannot bind to a null Expr");
- ExprManagerScope ems(obj);
+bool SymbolTable::Implementation::bind(const string& name,
+ api::Term obj,
+ bool levelZero,
+ bool doOverload)
+{
+ PrettyCheckArgument(!obj.isNull(), obj, "cannot bind to a null api::Term");
if (doOverload) {
if (!bindWithOverloading(name, obj)) {
return false;
}
}
if (levelZero) {
- d_exprMap->insertAtContextLevelZero(name, obj);
+ d_exprMap.insertAtContextLevelZero(name, obj);
} else {
- d_exprMap->insert(name, obj);
+ d_exprMap.insert(name, obj);
}
return true;
}
bool SymbolTable::Implementation::isBound(const string& name) const {
- return d_exprMap->find(name) != d_exprMap->end();
+ return d_exprMap.find(name) != d_exprMap.end();
}
-Expr SymbolTable::Implementation::lookup(const string& name) const {
+api::Term SymbolTable::Implementation::lookup(const string& name) const
+{
Assert(isBound(name));
- Expr expr = (*d_exprMap->find(name)).second;
+ api::Term expr = (*d_exprMap.find(name)).second;
if (isOverloadedFunction(expr)) {
- return d_nullExpr;
+ return d_nullTerm;
} else {
return expr;
}
}
-void SymbolTable::Implementation::bindType(const string& name, Type t,
- bool levelZero) {
+void SymbolTable::Implementation::bindType(const string& name,
+ api::Sort t,
+ bool levelZero)
+{
if (levelZero) {
- d_typeMap->insertAtContextLevelZero(name, make_pair(vector<Type>(), t));
+ d_typeMap.insertAtContextLevelZero(name, make_pair(vector<api::Sort>(), t));
} else {
- d_typeMap->insert(name, make_pair(vector<Type>(), t));
+ d_typeMap.insert(name, make_pair(vector<api::Sort>(), t));
}
}
void SymbolTable::Implementation::bindType(const string& name,
- const vector<Type>& params, Type t,
- bool levelZero) {
+ const vector<api::Sort>& params,
+ api::Sort t,
+ bool levelZero)
+{
if (Debug.isOn("sort")) {
Debug("sort") << "bindType(" << name << ", [";
if (params.size() > 0) {
- copy(params.begin(), params.end() - 1,
- ostream_iterator<Type>(Debug("sort"), ", "));
+ copy(params.begin(),
+ params.end() - 1,
+ ostream_iterator<api::Sort>(Debug("sort"), ", "));
Debug("sort") << params.back();
}
Debug("sort") << "], " << t << ")" << endl;
}
if (levelZero) {
- d_typeMap->insertAtContextLevelZero(name, make_pair(params, t));
+ d_typeMap.insertAtContextLevelZero(name, make_pair(params, t));
} else {
- d_typeMap->insert(name, make_pair(params, t));
+ d_typeMap.insert(name, make_pair(params, t));
}
}
bool SymbolTable::Implementation::isBoundType(const string& name) const {
- return d_typeMap->find(name) != d_typeMap->end();
+ return d_typeMap.find(name) != d_typeMap.end();
}
-Type SymbolTable::Implementation::lookupType(const string& name) const {
- pair<vector<Type>, Type> p = (*d_typeMap->find(name)).second;
+api::Sort SymbolTable::Implementation::lookupType(const string& name) const
+{
+ std::pair<std::vector<api::Sort>, api::Sort> p =
+ (*d_typeMap.find(name)).second;
PrettyCheckArgument(p.first.size() == 0, name,
"type constructor arity is wrong: "
"`%s' requires %u parameters but was provided 0",
@@ -477,64 +487,53 @@ Type SymbolTable::Implementation::lookupType(const string& name) const {
return p.second;
}
-Type SymbolTable::Implementation::lookupType(const string& name,
- const vector<Type>& params) const {
- pair<vector<Type>, Type> p = (*d_typeMap->find(name)).second;
+api::Sort SymbolTable::Implementation::lookupType(
+ const string& name, const vector<api::Sort>& params) const
+{
+ std::pair<std::vector<api::Sort>, api::Sort> p =
+ (*d_typeMap.find(name)).second;
PrettyCheckArgument(p.first.size() == params.size(), params,
"type constructor arity is wrong: "
"`%s' requires %u parameters but was provided %u",
name.c_str(), p.first.size(), params.size());
if (p.first.size() == 0) {
- PrettyCheckArgument(p.second.isSort(), name.c_str());
+ PrettyCheckArgument(p.second.isUninterpretedSort(), name.c_str());
return p.second;
}
if (p.second.isSortConstructor()) {
if (Debug.isOn("sort")) {
Debug("sort") << "instantiating using a sort constructor" << endl;
Debug("sort") << "have formals [";
- copy(p.first.begin(), p.first.end() - 1,
- ostream_iterator<Type>(Debug("sort"), ", "));
+ copy(p.first.begin(),
+ p.first.end() - 1,
+ ostream_iterator<api::Sort>(Debug("sort"), ", "));
Debug("sort") << p.first.back() << "]" << endl << "parameters [";
- copy(params.begin(), params.end() - 1,
- ostream_iterator<Type>(Debug("sort"), ", "));
+ copy(params.begin(),
+ params.end() - 1,
+ ostream_iterator<api::Sort>(Debug("sort"), ", "));
Debug("sort") << params.back() << "]" << endl
<< "type ctor " << name << endl
<< "type is " << p.second << endl;
}
- Type instantiation = SortConstructorType(p.second).instantiate(params);
+ api::Sort instantiation = p.second.instantiate(params);
Debug("sort") << "instance is " << instantiation << endl;
return instantiation;
} else if (p.second.isDatatype()) {
- PrettyCheckArgument(DatatypeType(p.second).isParametric(), name,
- "expected parametric datatype");
- return DatatypeType(p.second).instantiate(params);
- } else {
- if (Debug.isOn("sort")) {
- Debug("sort") << "instantiating using a sort substitution" << endl;
- Debug("sort") << "have formals [";
- copy(p.first.begin(), p.first.end() - 1,
- ostream_iterator<Type>(Debug("sort"), ", "));
- Debug("sort") << p.first.back() << "]" << endl << "parameters [";
- copy(params.begin(), params.end() - 1,
- ostream_iterator<Type>(Debug("sort"), ", "));
- Debug("sort") << params.back() << "]" << endl
- << "type ctor " << name << endl
- << "type is " << p.second << endl;
- }
-
- Type instantiation = p.second.substitute(p.first, params);
-
- Debug("sort") << "instance is " << instantiation << endl;
-
- return instantiation;
+ PrettyCheckArgument(
+ p.second.isParametricDatatype(), name, "expected parametric datatype");
+ return p.second.instantiate(params);
}
+ // failed to instantiate
+ Unhandled() << "Could not instantiate sort";
+ return p.second;
}
size_t SymbolTable::Implementation::lookupArity(const string& name) {
- pair<vector<Type>, Type> p = (*d_typeMap->find(name)).second;
+ std::pair<std::vector<api::Sort>, api::Sort> p =
+ (*d_typeMap.find(name)).second;
return p.first.size();
}
@@ -556,66 +555,75 @@ void SymbolTable::Implementation::reset() {
new (this) SymbolTable::Implementation();
}
-bool SymbolTable::Implementation::isOverloadedFunction(Expr fun) const {
- return d_overload_trie->isOverloadedFunction(fun);
+bool SymbolTable::Implementation::isOverloadedFunction(api::Term fun) const
+{
+ return d_overload_trie.isOverloadedFunction(fun);
}
-Expr SymbolTable::Implementation::getOverloadedConstantForType(
- const std::string& name, Type t) const {
- return d_overload_trie->getOverloadedConstantForType(name, t);
+api::Term SymbolTable::Implementation::getOverloadedConstantForType(
+ const std::string& name, api::Sort t) const
+{
+ return d_overload_trie.getOverloadedConstantForType(name, t);
}
-Expr SymbolTable::Implementation::getOverloadedFunctionForTypes(
- const std::string& name, const std::vector<Type>& argTypes) const {
- return d_overload_trie->getOverloadedFunctionForTypes(name, argTypes);
+api::Term SymbolTable::Implementation::getOverloadedFunctionForTypes(
+ const std::string& name, const std::vector<api::Sort>& argTypes) const
+{
+ return d_overload_trie.getOverloadedFunctionForTypes(name, argTypes);
}
bool SymbolTable::Implementation::bindWithOverloading(const string& name,
- Expr obj) {
- CDHashMap<string, Expr>::const_iterator it = d_exprMap->find(name);
- if (it != d_exprMap->end()) {
- const Expr& prev_bound_obj = (*it).second;
+ api::Term obj)
+{
+ CDHashMap<string, api::Term>::const_iterator it = d_exprMap.find(name);
+ if (it != d_exprMap.end())
+ {
+ const api::Term& prev_bound_obj = (*it).second;
if (prev_bound_obj != obj) {
- return d_overload_trie->bind(name, prev_bound_obj, obj);
+ return d_overload_trie.bind(name, prev_bound_obj, obj);
}
}
return true;
}
-bool SymbolTable::isOverloadedFunction(Expr fun) const {
+bool SymbolTable::isOverloadedFunction(api::Term fun) const
+{
return d_implementation->isOverloadedFunction(fun);
}
-Expr SymbolTable::getOverloadedConstantForType(const std::string& name,
- Type t) const {
+api::Term SymbolTable::getOverloadedConstantForType(const std::string& name,
+ api::Sort t) const
+{
return d_implementation->getOverloadedConstantForType(name, t);
}
-Expr SymbolTable::getOverloadedFunctionForTypes(
- const std::string& name, const std::vector<Type>& argTypes) const {
+api::Term SymbolTable::getOverloadedFunctionForTypes(
+ const std::string& name, const std::vector<api::Sort>& argTypes) const
+{
return d_implementation->getOverloadedFunctionForTypes(name, argTypes);
}
-SymbolTable::SymbolTable()
- : d_implementation(new SymbolTable::Implementation()) {}
+SymbolTable::SymbolTable() : d_implementation(new SymbolTable::Implementation())
+{
+}
SymbolTable::~SymbolTable() {}
bool SymbolTable::bind(const string& name,
- Expr obj,
+ api::Term obj,
bool levelZero,
bool doOverload)
{
return d_implementation->bind(name, obj, levelZero, doOverload);
}
-void SymbolTable::bindType(const string& name, Type t, bool levelZero)
+void SymbolTable::bindType(const string& name, api::Sort t, bool levelZero)
{
d_implementation->bindType(name, t, levelZero);
}
void SymbolTable::bindType(const string& name,
- const vector<Type>& params,
- Type t,
+ const vector<api::Sort>& params,
+ api::Sort t,
bool levelZero)
{
d_implementation->bindType(name, params, t, levelZero);
@@ -629,17 +637,17 @@ bool SymbolTable::isBoundType(const string& name) const
{
return d_implementation->isBoundType(name);
}
-Expr SymbolTable::lookup(const string& name) const
+api::Term SymbolTable::lookup(const string& name) const
{
return d_implementation->lookup(name);
}
-Type SymbolTable::lookupType(const string& name) const
+api::Sort SymbolTable::lookupType(const string& name) const
{
return d_implementation->lookupType(name);
}
-Type SymbolTable::lookupType(const string& name,
- const vector<Type>& params) const
+api::Sort SymbolTable::lookupType(const string& name,
+ const vector<api::Sort>& params) const
{
return d_implementation->lookupType(name, params);
}
diff --git a/src/expr/symbol_table.h b/src/expr/symbol_table.h
index 2824d9f7a..35bed1dbf 100644
--- a/src/expr/symbol_table.h
+++ b/src/expr/symbol_table.h
@@ -5,7 +5,7 @@
** Morgan Deters, Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -29,6 +29,12 @@
namespace CVC4 {
+namespace api {
+class Solver;
+class Sort;
+class Term;
+} // namespace api
+
class CVC4_PUBLIC ScopeException : public Exception {};
/**
@@ -65,7 +71,7 @@ class CVC4_PUBLIC SymbolTable {
* Returns false if the binding was invalid.
*/
bool bind(const std::string& name,
- Expr obj,
+ api::Term obj,
bool levelZero = false,
bool doOverload = false);
@@ -80,7 +86,7 @@ class CVC4_PUBLIC SymbolTable {
* @param t the type to bind to <code>name</code>
* @param levelZero set if the binding must be done at level 0
*/
- void bindType(const std::string& name, Type t, bool levelZero = false);
+ void bindType(const std::string& name, api::Sort t, bool levelZero = false);
/**
* Bind a type to a name in the current scope. If <code>name</code>
@@ -96,8 +102,8 @@ class CVC4_PUBLIC SymbolTable {
* locally within the current scope)
*/
void bindType(const std::string& name,
- const std::vector<Type>& params,
- Type t,
+ const std::vector<api::Sort>& params,
+ api::Sort t,
bool levelZero = false);
/**
@@ -125,7 +131,7 @@ class CVC4_PUBLIC SymbolTable {
* It returns the null expression if there is not a unique expression bound to
* <code>name</code> in the current scope (i.e. if there is not exactly one).
*/
- Expr lookup(const std::string& name) const;
+ api::Term lookup(const std::string& name) const;
/**
* Lookup a bound type.
@@ -133,7 +139,7 @@ class CVC4_PUBLIC SymbolTable {
* @param name the type identifier to lookup
* @returns the type bound to <code>name</code> in the current scope.
*/
- Type lookupType(const std::string& name) const;
+ api::Sort lookupType(const std::string& name) const;
/**
* Lookup a bound parameterized type.
@@ -143,8 +149,8 @@ class CVC4_PUBLIC SymbolTable {
* @returns the type bound to <code>name(<i>params</i>)</code> in
* the current scope.
*/
- Type lookupType(const std::string& name,
- const std::vector<Type>& params) const;
+ api::Sort lookupType(const std::string& name,
+ const std::vector<api::Sort>& params) const;
/**
* Lookup the arity of a bound parameterized type.
@@ -170,13 +176,14 @@ class CVC4_PUBLIC SymbolTable {
//------------------------ operator overloading
/** is this function overloaded? */
- bool isOverloadedFunction(Expr fun) const;
+ bool isOverloadedFunction(api::Term fun) const;
/** Get overloaded constant for type.
* If possible, it returns the defined symbol with name
* that has type t. Otherwise returns null expression.
*/
- Expr getOverloadedConstantForType(const std::string& name, Type t) const;
+ api::Term getOverloadedConstantForType(const std::string& name,
+ api::Sort t) const;
/**
* If possible, returns the unique defined function for a name
@@ -189,15 +196,12 @@ class CVC4_PUBLIC SymbolTable {
* no functions with name and expected argTypes, or alternatively there is
* more than one function with name and expected argTypes.
*/
- Expr getOverloadedFunctionForTypes(const std::string& name,
- const std::vector< Type >& argTypes) const;
+ api::Term getOverloadedFunctionForTypes(
+ const std::string& name, const std::vector<api::Sort>& argTypes) const;
//------------------------ end operator overloading
private:
- // Copying and assignment have not yet been implemented.
- SymbolTable(const SymbolTable&);
- SymbolTable& operator=(SymbolTable&);
-
+ /** The implementation of the symbol table */
class Implementation;
std::unique_ptr<Implementation> d_implementation;
}; /* class SymbolTable */
diff --git a/src/expr/tconv_seq_proof_generator.cpp b/src/expr/tconv_seq_proof_generator.cpp
new file mode 100644
index 000000000..b22170b38
--- /dev/null
+++ b/src/expr/tconv_seq_proof_generator.cpp
@@ -0,0 +1,167 @@
+/********************* */
+/*! \file tconv_seq_proof_generator.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Term conversion sequence proof generator utility
+ **/
+
+#include "expr/tconv_seq_proof_generator.h"
+
+namespace CVC4 {
+
+TConvSeqProofGenerator::TConvSeqProofGenerator(
+ ProofNodeManager* pnm,
+ const std::vector<ProofGenerator*>& ts,
+ context::Context* c,
+ std::string name)
+ : d_pnm(pnm), d_converted(c), d_name(name)
+{
+ d_tconvs.insert(d_tconvs.end(), ts.begin(), ts.end());
+ AlwaysAssert(!d_tconvs.empty())
+ << "TConvSeqProofGenerator::TConvSeqProofGenerator: expecting non-empty "
+ "sequence";
+}
+
+TConvSeqProofGenerator::~TConvSeqProofGenerator() {}
+
+void TConvSeqProofGenerator::registerConvertedTerm(Node t, Node s, size_t index)
+{
+ if (t == s)
+ {
+ // no need
+ return;
+ }
+ std::pair<Node, size_t> key = std::pair<Node, size_t>(t, index);
+ d_converted[key] = s;
+}
+
+std::shared_ptr<ProofNode> TConvSeqProofGenerator::getProofFor(Node f)
+{
+ Trace("tconv-seq-pf-gen")
+ << "TConvSeqProofGenerator::getProofFor: " << identify() << ": " << f
+ << std::endl;
+ return getSubsequenceProofFor(f, 0, d_tconvs.size() - 1);
+}
+
+std::shared_ptr<ProofNode> TConvSeqProofGenerator::getSubsequenceProofFor(
+ Node f, size_t start, size_t end)
+{
+ Assert(end < d_tconvs.size());
+ if (f.getKind() != kind::EQUAL)
+ {
+ std::stringstream serr;
+ serr << "TConvSeqProofGenerator::getProofFor: " << identify()
+ << ": fail, non-equality " << f;
+ Unhandled() << serr.str();
+ Trace("tconv-seq-pf-gen") << serr.str() << std::endl;
+ return nullptr;
+ }
+ // start with the left hand side of the equality
+ Node curr = f[0];
+ // proofs forming transitivity chain
+ std::vector<std::shared_ptr<ProofNode>> transChildren;
+ std::pair<Node, size_t> currKey;
+ NodeIndexNodeMap::iterator itc;
+ // convert the term in sequence
+ for (size_t i = start; i <= end; i++)
+ {
+ currKey = std::pair<Node, size_t>(curr, i);
+ itc = d_converted.find(currKey);
+ // if we provided a conversion at this index via registerConvertedTerm
+ if (itc != d_converted.end())
+ {
+ Node next = (*itc).second;
+ Trace("tconv-seq-pf-gen") << "...convert to " << next << std::endl;
+ Node eq = curr.eqNode(next);
+ std::shared_ptr<ProofNode> pf = d_tconvs[i]->getProofFor(eq);
+ transChildren.push_back(pf);
+ curr = next;
+ }
+ }
+ // should end up with the right hand side of the equality
+ if (curr != f[1])
+ {
+ // unexpected
+ std::stringstream serr;
+ serr << "TConvSeqProofGenerator::getProofFor: " << identify()
+ << ": failed, mismatch (see -t tconv-seq-pf-gen-debug for details)"
+ << std::endl;
+ serr << " source: " << f[0] << std::endl;
+ serr << "expected after conversions: " << f[1] << std::endl;
+ serr << " actual after conversions: " << curr << std::endl;
+
+ if (Trace.isOn("tconv-seq-pf-gen-debug"))
+ {
+ Trace("tconv-pf-gen-debug")
+ << "Printing conversion steps..." << std::endl;
+ serr << "Conversions: " << std::endl;
+ for (NodeIndexNodeMap::const_iterator it = d_converted.begin();
+ it != d_converted.end();
+ ++it)
+ {
+ serr << "(" << (*it).first.first << ", " << (*it).first.second
+ << ") -> " << (*it).second << std::endl;
+ }
+ }
+ Unhandled() << serr.str();
+ return nullptr;
+ }
+ // otherwise, make transitivity
+ return d_pnm->mkTrans(transChildren, f);
+}
+
+theory::TrustNode TConvSeqProofGenerator::mkTrustRewriteSequence(
+ const std::vector<Node>& cterms)
+{
+ Assert(cterms.size() == d_tconvs.size() + 1);
+ if (cterms[0] == cterms[cterms.size() - 1])
+ {
+ return theory::TrustNode::null();
+ }
+ bool useThis = false;
+ ProofGenerator* pg = nullptr;
+ for (size_t i = 0, nconvs = d_tconvs.size(); i < nconvs; i++)
+ {
+ if (cterms[i] == cterms[i + 1])
+ {
+ continue;
+ }
+ else if (pg == nullptr)
+ {
+ // Maybe the i^th generator can explain it alone, which must be the case
+ // if there is only one position in the sequence where the term changes.
+ // We may overwrite pg with this class if another step is encountered in
+ // this loop.
+ pg = d_tconvs[i];
+ }
+ else
+ {
+ // need more than a single generator, use this class
+ useThis = true;
+ break;
+ }
+ }
+ if (useThis)
+ {
+ pg = this;
+ // if more than two steps, we must register each conversion step
+ for (size_t i = 0, nconvs = d_tconvs.size(); i < nconvs; i++)
+ {
+ registerConvertedTerm(cterms[i], cterms[i + 1], i);
+ }
+ }
+ Assert(pg != nullptr);
+ return theory::TrustNode::mkTrustRewrite(
+ cterms[0], cterms[cterms.size() - 1], pg);
+}
+
+std::string TConvSeqProofGenerator::identify() const { return d_name; }
+
+} // namespace CVC4
diff --git a/src/expr/tconv_seq_proof_generator.h b/src/expr/tconv_seq_proof_generator.h
new file mode 100644
index 000000000..95499d6b8
--- /dev/null
+++ b/src/expr/tconv_seq_proof_generator.h
@@ -0,0 +1,119 @@
+/********************* */
+/*! \file tconv_seq_proof_generator.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Term conversion sequence proof generator utility
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__EXPR__TCONV_SEQ_PROOF_GENERATOR_H
+#define CVC4__EXPR__TCONV_SEQ_PROOF_GENERATOR_H
+
+#include "context/cdhashmap.h"
+#include "expr/node.h"
+#include "expr/proof_generator.h"
+#include "expr/proof_node_manager.h"
+#include "theory/trust_node.h"
+
+namespace CVC4 {
+
+/**
+ * The term conversion sequence proof generator. This is used for maintaining
+ * a fixed sequence of proof generators that provide proofs for rewrites
+ * (equalities). We call these the "component generators" of this sequence,
+ * which are typically TConvProofGenerator.
+ */
+class TConvSeqProofGenerator : public ProofGenerator
+{
+ public:
+ /**
+ * @param pnm The proof node manager for constructing ProofNode objects.
+ * @param ts The list of component term conversion generators that are
+ * applied in sequence
+ * @param c The context that this class depends on. If none is provided,
+ * this class is context-independent.
+ * @param name The name of this generator (for debugging).
+ */
+ TConvSeqProofGenerator(ProofNodeManager* pnm,
+ const std::vector<ProofGenerator*>& ts,
+ context::Context* c = nullptr,
+ std::string name = "TConvSeqProofGenerator");
+ ~TConvSeqProofGenerator();
+ /**
+ * Indicate that the index^th proof generator converts term t to s. This
+ * should be called for a unique s for each (t, index). It must be the
+ * case that d_tconv[index] can provide a proof for t = s in the remainder
+ * of the context maintained by this class.
+ */
+ void registerConvertedTerm(Node t, Node s, size_t index);
+ /**
+ * Get the proof for formula f. It should be the case that f is of the form
+ * t_0 = t_n, where it must be the case that t_n is obtained by the following:
+ * For each i=0, ... n, let t_{i+1} be the term such that
+ * registerConvertedTerm(t_i, t_{i+1}, i)
+ * was called. Otherwise t_{i+1} = t_i.
+ * In other words, t_n is obtained by converting t_0, in order, based on the
+ * calls to registerConvertedTerm.
+ *
+ * @param f The equality fact to get the proof for.
+ * @return The proof for f.
+ */
+ std::shared_ptr<ProofNode> getProofFor(Node f) override;
+ /**
+ * Get subsequence proof for f, with given start and end steps (inclusive).
+ */
+ std::shared_ptr<ProofNode> getSubsequenceProofFor(Node f,
+ size_t start,
+ size_t end);
+ /** Identify this generator (for debugging, etc..) */
+ std::string identify() const override;
+
+ /**
+ * Make trust node from a sequence of converted terms. The number of
+ * terms in cterms should be 1 + the number of component proof generators
+ * maintained by this class. This selects a proof generator that is capable
+ * of proving cterms[0] = cterms[cterms.size()-1], which is either this
+ * generator, or one of the component proof generators, if only one step
+ * rewrote. In the former case, all steps are registered to this class.
+ * Using a component generator is an optimization that saves having to
+ * save the conversion steps or use this class. For example, if we have 2
+ * term conversion components, and call this method on:
+ * { a, b, c }
+ * then this method calls:
+ * registerConvertedTerm( a, b, 0 )
+ * registerConvertedTerm( b, c, 1 )
+ * and returns a trust node proving (= a c) with this class as the proof
+ * generator. On the other hand, if we call this method on:
+ * { d, d, e }
+ * then we return a trust node proving (= d e) with the 2nd component proof
+ * generator, as it alone is capable of proving this equality.
+ */
+ theory::TrustNode mkTrustRewriteSequence(const std::vector<Node>& cterms);
+
+ protected:
+ using NodeIndexPairHashFunction =
+ PairHashFunction<Node, size_t, NodeHashFunction>;
+ typedef context::
+ CDHashMap<std::pair<Node, size_t>, Node, NodeIndexPairHashFunction>
+ NodeIndexNodeMap;
+ /** The proof node manager */
+ ProofNodeManager* d_pnm;
+ /** The term conversion generators */
+ std::vector<ProofGenerator*> d_tconvs;
+ /** the set of converted terms */
+ NodeIndexNodeMap d_converted;
+ /** Name identifier */
+ std::string d_name;
+};
+
+} // namespace CVC4
+
+#endif /* CVC4__EXPR__TCONV_SEQ_PROOF_GENERATOR_H */
diff --git a/src/expr/term_canonize.cpp b/src/expr/term_canonize.cpp
index 4f92edd31..e5ebd0209 100644
--- a/src/expr/term_canonize.cpp
+++ b/src/expr/term_canonize.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/term_canonize.h b/src/expr/term_canonize.h
index 32ac2fd72..cd15fba41 100644
--- a/src/expr/term_canonize.h
+++ b/src/expr/term_canonize.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/term_context.cpp b/src/expr/term_context.cpp
new file mode 100644
index 000000000..67da6d842
--- /dev/null
+++ b/src/expr/term_context.cpp
@@ -0,0 +1,135 @@
+/********************* */
+/*! \file term_context.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of term context utilities.
+ **/
+
+#include "expr/term_context.h"
+
+namespace CVC4 {
+
+uint32_t TermContext::computeValueOp(TNode t, uint32_t tval) const
+{
+ // default is no change
+ return tval;
+}
+
+uint32_t RtfTermContext::initialValue() const
+{
+ // by default, not in a term context or a quantifier
+ return 0;
+}
+
+uint32_t RtfTermContext::computeValue(TNode t,
+ uint32_t tval,
+ size_t child) const
+{
+ if (t.isClosure())
+ {
+ if (tval % 2 == 0)
+ {
+ return tval + 1;
+ }
+ }
+ else if (hasNestedTermChildren(t))
+ {
+ if (tval < 2)
+ {
+ return tval + 2;
+ }
+ }
+ return tval;
+}
+
+uint32_t RtfTermContext::getValue(bool inQuant, bool inTerm)
+{
+ return (inQuant ? 1 : 0) + 2 * (inTerm ? 1 : 0);
+}
+
+void RtfTermContext::getFlags(uint32_t val, bool& inQuant, bool& inTerm)
+{
+ inQuant = val % 2 == 1;
+ inTerm = val >= 2;
+}
+
+bool RtfTermContext::hasNestedTermChildren(TNode t)
+{
+ Kind k = t.getKind();
+ // dont' worry about FORALL or EXISTS, these are part of inQuant.
+ return theory::kindToTheoryId(k) != theory::THEORY_BOOL && k != kind::EQUAL
+ && k != kind::SEP_STAR && k != kind::SEP_WAND && k != kind::SEP_LABEL
+ && k != kind::BITVECTOR_EAGER_ATOM;
+}
+
+uint32_t InQuantTermContext::initialValue() const { return 0; }
+
+uint32_t InQuantTermContext::computeValue(TNode t,
+ uint32_t tval,
+ size_t index) const
+{
+ return t.isClosure() ? 1 : tval;
+}
+
+uint32_t InQuantTermContext::getValue(bool inQuant) { return inQuant ? 1 : 0; }
+
+bool InQuantTermContext::inQuant(uint32_t val, bool& inQuant)
+{
+ return val == 1;
+}
+
+uint32_t PolarityTermContext::initialValue() const
+{
+ // by default, we have true polarity
+ return 2;
+}
+
+uint32_t PolarityTermContext::computeValue(TNode t,
+ uint32_t tval,
+ size_t index) const
+{
+ switch (t.getKind())
+ {
+ case kind::AND:
+ case kind::OR:
+ case kind::SEP_STAR:
+ // polarity preserved
+ return tval;
+ case kind::IMPLIES:
+ // first child reverses, otherwise we preserve
+ return index == 0 ? (tval == 0 ? 0 : (3 - tval)) : tval;
+ case kind::NOT:
+ // polarity reversed
+ return tval == 0 ? 0 : (3 - tval);
+ case kind::ITE:
+ // head has no polarity, branches preserve
+ return index == 0 ? 0 : tval;
+ case kind::FORALL:
+ // body preserves, others have no polarity.
+ return index == 1 ? tval : 0;
+ default:
+ // no polarity
+ break;
+ }
+ return 0;
+}
+
+uint32_t PolarityTermContext::getValue(bool hasPol, bool pol)
+{
+ return hasPol ? (pol ? 2 : 1) : 0;
+}
+
+void PolarityTermContext::getFlags(uint32_t val, bool& hasPol, bool& pol)
+{
+ hasPol = val == 0;
+ pol = val == 2;
+}
+
+} // namespace CVC4
diff --git a/src/expr/term_context.h b/src/expr/term_context.h
new file mode 100644
index 000000000..b0ce03e48
--- /dev/null
+++ b/src/expr/term_context.h
@@ -0,0 +1,168 @@
+/********************* */
+/*! \file term_context.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Term context utilities.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__EXPR__TERM_CONTEXT_H
+#define CVC4__EXPR__TERM_CONTEXT_H
+
+#include "expr/node.h"
+
+namespace CVC4 {
+
+/**
+ * This is an abstract class for computing "term context identifiers". A term
+ * context identifier is a hash value that identifies some property of the
+ * context in which a term occurs. Common examples of the implementation of
+ * such a mapping are implemented in the subclasses below.
+ *
+ * A term context identifier is intended to be information that can be locally
+ * computed from the parent's hash, and hence does not rely on maintaining
+ * paths.
+ *
+ * In the below documentation, we write t @ [p] to a term at a given position,
+ * where p is a list of indices. For example, the atomic subterms of:
+ * (and P (not Q))
+ * are P @ [0] and Q @ [1,0].
+ */
+class TermContext
+{
+ public:
+ TermContext() {}
+ virtual ~TermContext() {}
+ /** The default initial value of root terms. */
+ virtual uint32_t initialValue() const = 0;
+ /**
+ * Returns the term context identifier of the index^th child of t, where tval
+ * is the term context identifier of t.
+ */
+ virtual uint32_t computeValue(TNode t, uint32_t tval, size_t index) const = 0;
+ /**
+ * Returns the term context identifier of the operator of t, where tval
+ * is the term context identifier of t.
+ */
+ virtual uint32_t computeValueOp(TNode t, uint32_t tval) const;
+};
+
+/**
+ * Remove term formulas (rtf) term context.
+ *
+ * Computes whether we are inside a term (as opposed to being part of Boolean
+ * skeleton) and whether we are inside a quantifier. For example, for:
+ * (and (= a b) (forall ((x Int)) (P x)))
+ * we have the following mappings (term -> inTerm,inQuant)
+ * (= a b) @ [0] -> false, false
+ * a @ [0,1] -> true, false
+ * (P x) @ [1,1] -> false, true
+ * x @ [1,1,0] -> true, true
+ * Notice that the hash of a child can be computed from the parent's hash only,
+ * and hence this can be implemented as an instance of the abstract class.
+ */
+class RtfTermContext : public TermContext
+{
+ public:
+ RtfTermContext() {}
+ /** The initial value: not in a term context or beneath a quantifier. */
+ uint32_t initialValue() const override;
+ /** Compute the value of the index^th child of t whose hash is tval */
+ uint32_t computeValue(TNode t, uint32_t tval, size_t index) const override;
+ /** get hash value from the flags */
+ static uint32_t getValue(bool inQuant, bool inTerm);
+ /** get flags from the hash value */
+ static void getFlags(uint32_t val, bool& inQuant, bool& inTerm);
+
+ private:
+ /**
+ * Returns true if the children of t should be considered in a "term" context,
+ * which is any context beneath a symbol that does not belong to the Boolean
+ * theory as well as other exceptions like equality, separation logic
+ * connectives and bit-vector eager atoms.
+ */
+ static bool hasNestedTermChildren(TNode t);
+};
+
+/**
+ * Simpler version of above that only computes whether we are inside a
+ * quantifier.
+ */
+class InQuantTermContext : public TermContext
+{
+ public:
+ InQuantTermContext() {}
+ /** The initial value: not beneath a quantifier. */
+ uint32_t initialValue() const override;
+ /** Compute the value of the index^th child of t whose hash is tval */
+ uint32_t computeValue(TNode t, uint32_t tval, size_t index) const override;
+ /** get hash value from the flags */
+ static uint32_t getValue(bool inQuant);
+ /** get flags from the hash value */
+ static bool inQuant(uint32_t val, bool& inQuant);
+};
+
+/**
+ * Polarity term context.
+ *
+ * This class computes the polarity of a term-context-sensitive term, which is
+ * one of {true, false, none}. This corresponds to the value that can be
+ * assigned to that term while preservering satisfiability of the overall
+ * formula, or none if such a value does not exist. If not "none", this
+ * typically corresponds to whether the number of NOT the formula is beneath is
+ * even, although special cases exist (e.g. the first child of IMPLIES).
+ *
+ * For example, given the formula:
+ * (and P (not (= (f x) 0)))
+ * assuming the root of this formula has true polarity, we have that:
+ * P @ [0] -> true
+ * (not (= (f x) 0)) @ [1] -> true
+ * (= (f x) 0) @ [1,0] -> false
+ * (f x) @ [1,0,0]), x @ [1,0,0,0]), 0 @ [1,0,1] -> none
+ *
+ * Notice that a term-context-sensitive Node is not one-to-one with Node.
+ * In particular, given the formula:
+ * (and P (not P))
+ * We have that the P at path [0] has polarity true and the P at path [1,0] has
+ * polarity false.
+ *
+ * Finally, notice that polarity does not correspond to a value that the
+ * formula entails. Thus, for the formula:
+ * (or P Q)
+ * we have that
+ * P @ [0] -> true
+ * Q @ [1] -> true
+ * although neither is entailed.
+ *
+ * Notice that the hash of a child can be computed from the parent's hash only.
+ */
+class PolarityTermContext : public TermContext
+{
+ public:
+ PolarityTermContext() {}
+ /** The initial value: true polarity. */
+ uint32_t initialValue() const override;
+ /** Compute the value of the index^th child of t whose hash is tval */
+ uint32_t computeValue(TNode t, uint32_t tval, size_t index) const override;
+ /**
+ * Get hash value from the flags, where hasPol false means no polarity.
+ */
+ static uint32_t getValue(bool hasPol, bool pol);
+ /**
+ * get flags from the hash value. If we have no polarity, both hasPol and pol
+ * are set to false.
+ */
+ static void getFlags(uint32_t val, bool& hasPol, bool& pol);
+};
+
+} // namespace CVC4
+
+#endif /* CVC4__EXPR__TERM_CONVERSION_PROOF_GENERATOR_H */
diff --git a/src/expr/term_context_node.cpp b/src/expr/term_context_node.cpp
new file mode 100644
index 000000000..e5610ef46
--- /dev/null
+++ b/src/expr/term_context_node.cpp
@@ -0,0 +1,76 @@
+/********************* */
+/*! \file term_context_node.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Term context node utility.
+ **/
+
+#include "expr/term_context_node.h"
+
+#include "expr/term_context.h"
+
+namespace CVC4 {
+
+TCtxNode::TCtxNode(Node n, const TermContext* tctx)
+ : d_node(n), d_val(tctx->initialValue()), d_tctx(tctx)
+{
+}
+
+TCtxNode::TCtxNode(Node n, uint32_t val, const TermContext* tctx)
+ : d_node(n), d_val(val), d_tctx(tctx)
+{
+}
+
+size_t TCtxNode::getNumChildren() const { return d_node.getNumChildren(); }
+
+TCtxNode TCtxNode::getChild(size_t i) const
+{
+ Assert(i < d_node.getNumChildren());
+ // we are still computing the same term context, with the given child, where
+ // the hash has been updated based on the kind, node, current value and child
+ // index.
+ return TCtxNode(d_node[i], d_tctx->computeValue(d_node, d_val, i), d_tctx);
+}
+
+Node TCtxNode::getNode() const { return d_node; }
+
+uint32_t TCtxNode::getContextId() const { return d_val; }
+
+const TermContext* TCtxNode::getTermContext() const { return d_tctx; }
+
+Node TCtxNode::getNodeHash() const { return computeNodeHash(d_node, d_val); }
+
+Node TCtxNode::computeNodeHash(Node n, uint32_t val)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ return nm->mkNode(kind::SEXPR, n, nm->mkConst(Rational(val)));
+}
+
+Node TCtxNode::decomposeNodeHash(Node h, uint32_t& val)
+{
+ if (h.getKind() != kind::SEXPR || h.getNumChildren() != 2)
+ {
+ Assert(false) << "TermContext::decomposeNodeHash: unexpected node " << h;
+ return Node::null();
+ }
+ Node ival = h[1];
+ if (!ival.isConst() || !ival.getType().isInteger()
+ || !ival.getConst<Rational>().getNumerator().fitsUnsignedInt())
+ {
+ Assert(false) << "TermContext::decomposeNodeHash: unexpected term context "
+ "integer in hash "
+ << h;
+ return Node::null();
+ }
+ val = ival.getConst<Rational>().getNumerator().toUnsignedInt();
+ return h[0];
+}
+
+} // namespace CVC4
diff --git a/src/expr/term_context_node.h b/src/expr/term_context_node.h
new file mode 100644
index 000000000..ff8187bbc
--- /dev/null
+++ b/src/expr/term_context_node.h
@@ -0,0 +1,79 @@
+/********************* */
+/*! \file term_context_node.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Term context node utility.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__EXPR__TERM_CONTEXT_NODE_H
+#define CVC4__EXPR__TERM_CONTEXT_NODE_H
+
+#include "expr/node.h"
+#include "expr/term_context.h"
+
+namespace CVC4 {
+
+class TCtxStack;
+
+/**
+ * A (term-context) sensitive term. This is a wrapper around a Node that
+ * additionally has a term context identifier, see getTermContext(). It depends
+ * on a pointer to a TermContext callback class (see term_context.h).
+ */
+class TCtxNode
+{
+ friend class TCtxStack;
+
+ public:
+ TCtxNode(Node n, const TermContext* tctx);
+ /** get number of children */
+ size_t getNumChildren() const;
+ /** get child at index i */
+ TCtxNode getChild(size_t i) const;
+ /** get node */
+ Node getNode() const;
+ /** get context */
+ uint32_t getContextId() const;
+ /** get term context */
+ const TermContext* getTermContext() const;
+ //---------------------- utility methods
+ /**
+ * Get node hash, which is a unique node representation of this TCtxNode.
+ * This method calls the method below on the data members of this class.
+ */
+ Node getNodeHash() const;
+ /**
+ * Get node hash, which is a unique node representation of the pair (n, val).
+ * In particular, this returns (SEXPR n (CONST_RATIONAL val)).
+ */
+ static Node computeNodeHash(Node n, uint32_t val);
+ /**
+ * Decompose node hash, which is an inverse of the above operation. In
+ * particular, given input h, this returns a node n and sets val to a value
+ * such that computeNodeHash(n, val) returns h.
+ */
+ static Node decomposeNodeHash(Node h, uint32_t& val);
+ //---------------------- end utility methods
+ private:
+ /** private constructor */
+ TCtxNode(Node n, uint32_t val, const TermContext* tctx);
+ /** The node */
+ Node d_node;
+ /** The term context identifier */
+ uint32_t d_val;
+ /** The term context */
+ const TermContext* d_tctx;
+};
+
+} // namespace CVC4
+
+#endif /* CVC4__EXPR__TERM_CONVERSION_PROOF_GENERATOR_H */
diff --git a/src/expr/term_context_stack.cpp b/src/expr/term_context_stack.cpp
new file mode 100644
index 000000000..64cab7035
--- /dev/null
+++ b/src/expr/term_context_stack.cpp
@@ -0,0 +1,76 @@
+/********************* */
+/*! \file term_context_stack.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Term context stack
+ **/
+
+#include "expr/term_context_stack.h"
+
+namespace CVC4 {
+
+TCtxStack::TCtxStack(const TermContext* tctx) : d_tctx(tctx) {}
+
+void TCtxStack::pushInitial(Node t)
+{
+ Assert(d_stack.empty());
+ d_stack.push_back(std::pair<Node, uint32_t>(t, d_tctx->initialValue()));
+}
+
+void TCtxStack::pushChildren(Node t, uint32_t tval)
+{
+ for (size_t i = 0, nchild = t.getNumChildren(); i < nchild; i++)
+ {
+ pushChild(t, tval, i);
+ }
+}
+
+void TCtxStack::pushChild(Node t, uint32_t tval, size_t index)
+{
+ Assert(index < t.getNumChildren());
+ Trace("tctx-debug") << "TCtxStack::pushChild: computing " << t << "[" << index
+ << "] / " << tval << std::endl;
+ uint32_t tcval = d_tctx->computeValue(t, tval, index);
+ Trace("tctx-debug") << "TCtxStack::pushChild: returned " << t << "[" << index
+ << "] / " << tval << " ---> " << tcval << std::endl;
+ d_stack.push_back(std::pair<Node, uint32_t>(t[index], tcval));
+}
+
+void TCtxStack::pushOp(Node t, uint32_t tval)
+{
+ Assert(t.hasOperator());
+ uint32_t toval = d_tctx->computeValueOp(t, tval);
+ d_stack.push_back(std::pair<Node, uint32_t>(t.getOperator(), toval));
+}
+
+void TCtxStack::push(Node t, uint32_t tval)
+{
+ d_stack.push_back(std::pair<Node, uint32_t>(t, tval));
+}
+
+void TCtxStack::pop() { d_stack.pop_back(); }
+
+void TCtxStack::clear() { d_stack.clear(); }
+size_t TCtxStack::size() const { return d_stack.size(); }
+
+bool TCtxStack::empty() const { return d_stack.empty(); }
+
+std::pair<Node, uint32_t> TCtxStack::getCurrent() const
+{
+ return d_stack.back();
+}
+
+TCtxNode TCtxStack::getCurrentNode() const
+{
+ std::pair<Node, uint32_t> curr = TCtxStack::getCurrent();
+ return TCtxNode(curr.first, curr.second, d_tctx);
+}
+
+} // namespace CVC4
diff --git a/src/expr/term_context_stack.h b/src/expr/term_context_stack.h
new file mode 100644
index 000000000..ca72a6acd
--- /dev/null
+++ b/src/expr/term_context_stack.h
@@ -0,0 +1,73 @@
+/********************* */
+/*! \file term_context_stack.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Term context
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__EXPR__TERM_CONTEXT_STACK_H
+#define CVC4__EXPR__TERM_CONTEXT_STACK_H
+
+#include "expr/term_context_node.h"
+
+namespace CVC4 {
+
+/**
+ * A stack for term-context-sensitive terms. Its main advantage is that
+ * it does not rely on explicit construction of TCtxNode for efficiency.
+ */
+class TCtxStack
+{
+ public:
+ TCtxStack(const TermContext* tctx);
+ virtual ~TCtxStack() {}
+ /** Push t to the stack */
+ void pushInitial(Node t);
+ /**
+ * Push all children of t to the stack, where tval is the term context hash
+ * of t. */
+ void pushChildren(Node t, uint32_t tval);
+ /**
+ * Push the child of t with the given index to the stack, where tval is
+ * the term context hash of t.
+ */
+ void pushChild(Node t, uint32_t tval, size_t index);
+ /**
+ * Push the operator of t to the stack, where tval is the term context has
+ * of t.
+ */
+ void pushOp(Node t, uint32_t tval);
+ /** Push t to the stack with term context hash tval. */
+ void push(Node t, uint32_t tval);
+ /** Pop a term from the context */
+ void pop();
+ /** Clear the stack */
+ void clear();
+ /** Return the size of the stack */
+ size_t size() const;
+ /** Return true if the stack is empty */
+ bool empty() const;
+ /** Get the current stack element */
+ std::pair<Node, uint32_t> getCurrent() const;
+ /** Get the current stack element, node version */
+ TCtxNode getCurrentNode() const;
+
+ private:
+ /** The stack */
+ std::vector<std::pair<Node, uint32_t>> d_stack;
+ /** The term context */
+ const TermContext* d_tctx;
+};
+
+} // namespace CVC4
+
+#endif /* CVC4__EXPR__TERM_CONTEXT_STACK_H */
diff --git a/src/expr/term_conversion_proof_generator.cpp b/src/expr/term_conversion_proof_generator.cpp
index bad163375..02613345f 100644
--- a/src/expr/term_conversion_proof_generator.cpp
+++ b/src/expr/term_conversion_proof_generator.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,6 +14,8 @@
#include "expr/term_conversion_proof_generator.h"
+#include "expr/term_context_stack.h"
+
using namespace CVC4::kind;
namespace CVC4 {
@@ -29,29 +31,60 @@ std::ostream& operator<<(std::ostream& out, TConvPolicy tcpol)
return out;
}
+std::ostream& operator<<(std::ostream& out, TConvCachePolicy tcpol)
+{
+ switch (tcpol)
+ {
+ case TConvCachePolicy::STATIC: out << "STATIC"; break;
+ case TConvCachePolicy::DYNAMIC: out << "DYNAMIC"; break;
+ case TConvCachePolicy::NEVER: out << "NEVER"; break;
+ default: out << "TConvCachePolicy:unknown"; break;
+ }
+ return out;
+}
+
TConvProofGenerator::TConvProofGenerator(ProofNodeManager* pnm,
context::Context* c,
- TConvPolicy tpol)
- : d_proof(pnm, nullptr, c), d_rewriteMap(c ? c : &d_context), d_policy(tpol)
+ TConvPolicy pol,
+ TConvCachePolicy cpol,
+ std::string name,
+ TermContext* tccb,
+ bool rewriteOps)
+ : d_proof(pnm, nullptr, c, name + "::LazyCDProof"),
+ d_rewriteMap(c ? c : &d_context),
+ d_policy(pol),
+ d_cpolicy(cpol),
+ d_name(name),
+ d_tcontext(tccb),
+ d_rewriteOps(rewriteOps)
{
}
TConvProofGenerator::~TConvProofGenerator() {}
-void TConvProofGenerator::addRewriteStep(Node t, Node s, ProofGenerator* pg)
+void TConvProofGenerator::addRewriteStep(Node t,
+ Node s,
+ ProofGenerator* pg,
+ PfRule trustId,
+ bool isClosed,
+ uint32_t tctx)
{
- Node eq = registerRewriteStep(t, s);
+ Node eq = registerRewriteStep(t, s, tctx);
if (!eq.isNull())
{
- d_proof.addLazyStep(eq, pg);
+ d_proof.addLazyStep(eq, pg, trustId, isClosed);
}
}
-void TConvProofGenerator::addRewriteStep(Node t, Node s, ProofStep ps)
+void TConvProofGenerator::addRewriteStep(Node t,
+ Node s,
+ ProofStep ps,
+ uint32_t tctx)
{
- Node eq = registerRewriteStep(t, s);
+ Node eq = registerRewriteStep(t, s, tctx);
if (!eq.isNull())
{
+ AlwaysAssert(ps.d_rule != PfRule::ASSUME);
d_proof.addStep(eq, ps);
}
}
@@ -60,87 +93,202 @@ void TConvProofGenerator::addRewriteStep(Node t,
Node s,
PfRule id,
const std::vector<Node>& children,
- const std::vector<Node>& args)
+ const std::vector<Node>& args,
+ uint32_t tctx)
{
- Node eq = registerRewriteStep(t, s);
+ Node eq = registerRewriteStep(t, s, tctx);
if (!eq.isNull())
{
+ AlwaysAssert(id != PfRule::ASSUME);
d_proof.addStep(eq, id, children, args);
}
}
-bool TConvProofGenerator::hasRewriteStep(Node t) const
+bool TConvProofGenerator::hasRewriteStep(Node t, uint32_t tctx) const
{
- return !getRewriteStep(t).isNull();
+ return !getRewriteStep(t, tctx).isNull();
}
-Node TConvProofGenerator::registerRewriteStep(Node t, Node s)
+Node TConvProofGenerator::getRewriteStep(Node t, uint32_t tctx) const
+{
+ Node thash = t;
+ if (d_tcontext != nullptr)
+ {
+ thash = TCtxNode::computeNodeHash(t, tctx);
+ }
+ return getRewriteStepInternal(thash);
+}
+
+Node TConvProofGenerator::registerRewriteStep(Node t, Node s, uint32_t tctx)
{
if (t == s)
{
return Node::null();
}
+ Node thash = t;
+ if (d_tcontext != nullptr)
+ {
+ thash = TCtxNode::computeNodeHash(t, tctx);
+ }
+ else
+ {
+ // don't use term context ids if not using term context
+ Assert(tctx == 0);
+ }
// should not rewrite term to two different things
- if (!getRewriteStep(t).isNull())
+ if (!getRewriteStepInternal(thash).isNull())
{
- Assert(getRewriteStep(t) == s);
+ Assert(getRewriteStepInternal(thash) == s);
return Node::null();
}
- d_rewriteMap[t] = s;
+ d_rewriteMap[thash] = s;
+ if (d_cpolicy == TConvCachePolicy::DYNAMIC)
+ {
+ // clear the cache
+ d_cache.clear();
+ }
return t.eqNode(s);
}
std::shared_ptr<ProofNode> TConvProofGenerator::getProofFor(Node f)
{
- Trace("tconv-pf-gen") << "TConvProofGenerator::getProofFor: " << f
- << std::endl;
+ Trace("tconv-pf-gen") << "TConvProofGenerator::getProofFor: " << identify()
+ << ": " << f << std::endl;
if (f.getKind() != EQUAL)
{
- Trace("tconv-pf-gen") << "... fail, non-equality" << std::endl;
- Assert(false);
+ std::stringstream serr;
+ serr << "TConvProofGenerator::getProofFor: " << identify()
+ << ": fail, non-equality " << f;
+ Unhandled() << serr.str();
+ Trace("tconv-pf-gen") << serr.str() << std::endl;
return nullptr;
}
// we use the existing proofs
- LazyCDProof lpf(d_proof.getManager(), &d_proof);
- Node conc = getProofForRewriting(f[0], lpf);
- if (conc != f)
+ LazyCDProof lpf(
+ d_proof.getManager(), &d_proof, nullptr, d_name + "::LazyCDProof");
+ if (f[0] == f[1])
{
- Trace("tconv-pf-gen") << "...failed, mismatch: returned proof concludes "
- << conc << ", expected " << f << std::endl;
- Assert(false);
- return nullptr;
+ // assertion failure in debug
+ Assert(false) << "TConvProofGenerator::getProofFor: " << identify()
+ << ": don't ask for trivial proofs";
+ lpf.addStep(f, PfRule::REFL, {}, {f[0]});
}
+ else
+ {
+ Node conc = getProofForRewriting(f[0], lpf, d_tcontext);
+ if (conc != f)
+ {
+ Assert(conc.getKind() == EQUAL && conc[0] == f[0]);
+ std::stringstream serr;
+ serr << "TConvProofGenerator::getProofFor: " << toStringDebug()
+ << ": failed, mismatch (see -t tconv-pf-gen-debug for details)"
+ << std::endl;
+ serr << " source: " << f[0] << std::endl;
+ serr << "expected after rewriting: " << f[1] << std::endl;
+ serr << " actual after rewriting: " << conc[1] << std::endl;
+
+ if (Trace.isOn("tconv-pf-gen-debug"))
+ {
+ Trace("tconv-pf-gen-debug") << "Printing rewrite steps..." << std::endl;
+ serr << "Rewrite steps: " << std::endl;
+ for (NodeNodeMap::const_iterator it = d_rewriteMap.begin();
+ it != d_rewriteMap.end();
+ ++it)
+ {
+ serr << (*it).first << " -> " << (*it).second << std::endl;
+ }
+ }
+ Unhandled() << serr.str();
+ return nullptr;
+ }
+ }
+ std::shared_ptr<ProofNode> pfn = lpf.getProofFor(f);
Trace("tconv-pf-gen") << "... success" << std::endl;
- return lpf.getProofFor(f);
+ Assert (pfn!=nullptr);
+ Trace("tconv-pf-gen-debug") << "... proof is " << *pfn << std::endl;
+ return pfn;
}
-Node TConvProofGenerator::getProofForRewriting(Node t, LazyCDProof& pf)
+Node TConvProofGenerator::getProofForRewriting(Node t,
+ LazyCDProof& pf,
+ TermContext* tctx)
{
NodeManager* nm = NodeManager::currentNM();
- // Invariant: if visited[t] = s or rewritten[t] = s and t,s are distinct,
- // then pf is able to generate a proof of t=s.
+ // Invariant: if visited[hash(t)] = s or rewritten[hash(t)] = s and t,s are
+ // distinct, then pf is able to generate a proof of t=s. We must
+ // Node in the domains of the maps below due to hashing creating new (SEXPR)
+ // nodes.
+
// the final rewritten form of terms
- std::unordered_map<TNode, Node, TNodeHashFunction> visited;
+ std::unordered_map<Node, Node, TNodeHashFunction> visited;
// the rewritten form of terms we have processed so far
- std::unordered_map<TNode, Node, TNodeHashFunction> rewritten;
- std::unordered_map<TNode, Node, TNodeHashFunction>::iterator it;
- std::unordered_map<TNode, Node, TNodeHashFunction>::iterator itr;
+ std::unordered_map<Node, Node, TNodeHashFunction> rewritten;
+ std::unordered_map<Node, Node, TNodeHashFunction>::iterator it;
+ std::unordered_map<Node, Node, TNodeHashFunction>::iterator itr;
+ std::map<Node, std::shared_ptr<ProofNode> >::iterator itc;
+ Trace("tconv-pf-gen-rewrite")
+ << "TConvProofGenerator::getProofForRewriting: " << toStringDebug()
+ << std::endl;
+ Trace("tconv-pf-gen-rewrite") << "Input: " << t << std::endl;
+ // if provided, we use term context for cache
+ std::shared_ptr<TCtxStack> visitctx;
+ // otherwise, visit is used if we don't have a term context
std::vector<TNode> visit;
- TNode cur;
- visit.push_back(t);
+ Node tinitialHash;
+ if (tctx != nullptr)
+ {
+ visitctx = std::make_shared<TCtxStack>(tctx);
+ visitctx->pushInitial(t);
+ tinitialHash = TCtxNode::computeNodeHash(t, tctx->initialValue());
+ }
+ else
+ {
+ visit.push_back(t);
+ tinitialHash = t;
+ }
+ Node cur;
+ uint32_t curCVal = 0;
+ Node curHash;
do
{
- cur = visit.back();
- visit.pop_back();
- it = visited.find(cur);
-
+ // pop the top element
+ if (tctx != nullptr)
+ {
+ std::pair<Node, uint32_t> curPair = visitctx->getCurrent();
+ cur = curPair.first;
+ curCVal = curPair.second;
+ curHash = TCtxNode::computeNodeHash(cur, curCVal);
+ visitctx->pop();
+ }
+ else
+ {
+ cur = visit.back();
+ curHash = cur;
+ visit.pop_back();
+ }
+ Trace("tconv-pf-gen-rewrite") << "* visit : " << curHash << std::endl;
+ // has the proof for cur been cached?
+ itc = d_cache.find(curHash);
+ if (itc != d_cache.end())
+ {
+ Node res = itc->second->getResult();
+ Assert(res.getKind() == EQUAL);
+ Assert(!res[1].isNull());
+ visited[curHash] = res[1];
+ pf.addProof(itc->second);
+ continue;
+ }
+ it = visited.find(curHash);
if (it == visited.end())
{
- visited[cur] = Node::null();
+ Trace("tconv-pf-gen-rewrite") << "- previsit" << std::endl;
+ visited[curHash] = Node::null();
// did we rewrite the current node (possibly at pre-rewrite)?
- Node rcur = getRewriteStep(cur);
+ Node rcur = getRewriteStepInternal(curHash);
if (!rcur.isNull())
{
+ Trace("tconv-pf-gen-rewrite")
+ << "*** " << curHash << " prerewrites to " << rcur << std::endl;
// d_proof has a proof of cur = rcur. Hence there is nothing
// to do here, as pf will reference d_proof to get its proof.
if (d_policy == TConvPolicy::FIXPOINT)
@@ -148,26 +296,53 @@ Node TConvProofGenerator::getProofForRewriting(Node t, LazyCDProof& pf)
// It may be the case that rcur also rewrites, thus we cannot assign
// the final rewritten form for cur yet. Instead we revisit cur after
// finishing visiting rcur.
- rewritten[cur] = rcur;
- visit.push_back(cur);
- visit.push_back(rcur);
+ rewritten[curHash] = rcur;
+ if (tctx != nullptr)
+ {
+ visitctx->push(cur, curCVal);
+ visitctx->push(rcur, curCVal);
+ }
+ else
+ {
+ visit.push_back(cur);
+ visit.push_back(rcur);
+ }
}
else
{
Assert(d_policy == TConvPolicy::ONCE);
+ Trace("tconv-pf-gen-rewrite") << "-> (once, prewrite) " << curHash
+ << " = " << rcur << std::endl;
// not rewriting again, rcur is final
- visited[cur] = rcur;
+ Assert(!rcur.isNull());
+ visited[curHash] = rcur;
+ doCache(curHash, cur, rcur, pf);
}
}
+ else if (tctx != nullptr)
+ {
+ visitctx->push(cur, curCVal);
+ // visit operator if apply uf
+ if (d_rewriteOps && cur.getKind() == APPLY_UF)
+ {
+ visitctx->pushOp(cur, curCVal);
+ }
+ visitctx->pushChildren(cur, curCVal);
+ }
else
{
visit.push_back(cur);
+ // visit operator if apply uf
+ if (d_rewriteOps && cur.getKind() == APPLY_UF)
+ {
+ visit.push_back(cur.getOperator());
+ }
visit.insert(visit.end(), cur.begin(), cur.end());
}
}
else if (it->second.isNull())
{
- itr = rewritten.find(cur);
+ itr = rewritten.find(curHash);
if (itr != rewritten.end())
{
// only can generate partially rewritten nodes when rewrite again is
@@ -176,9 +351,17 @@ Node TConvProofGenerator::getProofForRewriting(Node t, LazyCDProof& pf)
// if it was rewritten, check the status of the rewritten node,
// which should be finished now
Node rcur = itr->second;
+ Trace("tconv-pf-gen-rewrite")
+ << "- postvisit, previously rewritten to " << rcur << std::endl;
+ Node rcurHash = rcur;
+ if (tctx != nullptr)
+ {
+ rcurHash = TCtxNode::computeNodeHash(rcur, curCVal);
+ }
Assert(cur != rcur);
// the final rewritten form of cur is the final form of rcur
- Node rcurFinal = visited[rcur];
+ Node rcurFinal = visited[rcurHash];
+ Assert(!rcurFinal.isNull());
if (rcurFinal != rcur)
{
// must connect via TRANS
@@ -188,31 +371,90 @@ Node TConvProofGenerator::getProofForRewriting(Node t, LazyCDProof& pf)
Node result = cur.eqNode(rcurFinal);
pf.addStep(result, PfRule::TRANS, pfChildren, {});
}
- visited[cur] = rcurFinal;
+ Trace("tconv-pf-gen-rewrite")
+ << "-> (rewritten postrewrite) " << curHash << " = " << rcurFinal
+ << std::endl;
+ visited[curHash] = rcurFinal;
+ doCache(curHash, cur, rcurFinal, pf);
}
else
{
+ Trace("tconv-pf-gen-rewrite") << "- postvisit" << std::endl;
Node ret = cur;
+ Node retHash = curHash;
bool childChanged = false;
std::vector<Node> children;
- if (cur.getMetaKind() == metakind::PARAMETERIZED)
- {
- children.push_back(cur.getOperator());
- }
- for (const Node& cn : cur)
+ Kind ck = cur.getKind();
+ if (d_rewriteOps && ck == APPLY_UF)
{
- it = visited.find(cn);
+ // the operator of APPLY_UF is visited
+ Node cop = cur.getOperator();
+ if (tctx != nullptr)
+ {
+ uint32_t coval = tctx->computeValueOp(cur, curCVal);
+ Node coHash = TCtxNode::computeNodeHash(cop, coval);
+ it = visited.find(coHash);
+ }
+ else
+ {
+ it = visited.find(cop);
+ }
Assert(it != visited.end());
Assert(!it->second.isNull());
- childChanged = childChanged || cn != it->second;
+ childChanged = childChanged || cop != it->second;
children.push_back(it->second);
}
+ else if (cur.getMetaKind() == metakind::PARAMETERIZED)
+ {
+ // all other parametrized operators are unchanged
+ children.push_back(cur.getOperator());
+ }
+ // get the results of the children
+ if (tctx != nullptr)
+ {
+ for (size_t i = 0, nchild = cur.getNumChildren(); i < nchild; i++)
+ {
+ Node cn = cur[i];
+ uint32_t cnval = tctx->computeValue(cur, curCVal, i);
+ Node cnHash = TCtxNode::computeNodeHash(cn, cnval);
+ it = visited.find(cnHash);
+ Assert(it != visited.end());
+ Assert(!it->second.isNull());
+ childChanged = childChanged || cn != it->second;
+ children.push_back(it->second);
+ }
+ }
+ else
+ {
+ // can use simple loop if not term-context-sensitive
+ for (const Node& cn : cur)
+ {
+ it = visited.find(cn);
+ Assert(it != visited.end());
+ Assert(!it->second.isNull());
+ childChanged = childChanged || cn != it->second;
+ children.push_back(it->second);
+ }
+ }
if (childChanged)
{
- ret = nm->mkNode(cur.getKind(), children);
- rewritten[cur] = ret;
+ ret = nm->mkNode(ck, children);
+ rewritten[curHash] = ret;
// congruence to show (cur = ret)
+ PfRule congRule = PfRule::CONG;
std::vector<Node> pfChildren;
+ std::vector<Node> pfArgs;
+ pfArgs.push_back(ProofRuleChecker::mkKindNode(ck));
+ if (ck == APPLY_UF && children[0] != cur.getOperator())
+ {
+ // use HO_CONG if the operator changed
+ congRule = PfRule::HO_CONG;
+ pfChildren.push_back(cur.getOperator().eqNode(children[0]));
+ }
+ else if (kind::metaKindOf(ck) == kind::metakind::PARAMETERIZED)
+ {
+ pfArgs.push_back(cur.getOperator());
+ }
for (size_t i = 0, size = cur.getNumChildren(); i < size; i++)
{
if (cur[i] == ret[i])
@@ -222,54 +464,91 @@ Node TConvProofGenerator::getProofForRewriting(Node t, LazyCDProof& pf)
}
pfChildren.push_back(cur[i].eqNode(ret[i]));
}
- std::vector<Node> pfArgs;
- Kind k = cur.getKind();
- if (kind::metaKindOf(k) == kind::metakind::PARAMETERIZED)
- {
- pfArgs.push_back(cur.getOperator());
- }
- else
+ Node result = cur.eqNode(ret);
+ pf.addStep(result, congRule, pfChildren, pfArgs);
+ // must update the hash
+ retHash = ret;
+ if (tctx != nullptr)
{
- pfArgs.push_back(nm->operatorOf(k));
+ retHash = TCtxNode::computeNodeHash(ret, curCVal);
}
- Node result = cur.eqNode(ret);
- pf.addStep(result, PfRule::CONG, pfChildren, pfArgs);
+ }
+ else if (tctx != nullptr)
+ {
+ // now we need the hash
+ retHash = TCtxNode::computeNodeHash(cur, curCVal);
}
// did we rewrite ret (at post-rewrite)?
Node rret;
// only if not ONCE policy, which only does pre-rewrite
if (d_policy != TConvPolicy::ONCE)
{
- rret = getRewriteStep(ret);
+ rret = getRewriteStepInternal(retHash);
}
if (!rret.isNull())
{
- if (cur != ret)
- {
- visit.push_back(cur);
- }
+ Trace("tconv-pf-gen-rewrite")
+ << "*** " << retHash << " postrewrites to " << rret << std::endl;
// d_proof should have a proof of ret = rret, hence nothing to do
// here, for the same reasons as above. It also may be the case that
// rret rewrites, hence we must revisit ret.
- rewritten[ret] = rret;
- visit.push_back(ret);
- visit.push_back(rret);
+ rewritten[retHash] = rret;
+ if (tctx != nullptr)
+ {
+ if (cur != ret)
+ {
+ visitctx->push(cur, curCVal);
+ }
+ visitctx->push(ret, curCVal);
+ visitctx->push(rret, curCVal);
+ }
+ else
+ {
+ if (cur != ret)
+ {
+ visit.push_back(cur);
+ }
+ visit.push_back(ret);
+ visit.push_back(rret);
+ }
}
else
{
+ Trace("tconv-pf-gen-rewrite")
+ << "-> (postrewrite) " << curHash << " = " << ret << std::endl;
// it is final
- visited[cur] = ret;
+ Assert(!ret.isNull());
+ visited[curHash] = ret;
+ doCache(curHash, cur, ret, pf);
}
}
}
- } while (!visit.empty());
- Assert(visited.find(t) != visited.end());
- Assert(!visited.find(t)->second.isNull());
+ else
+ {
+ Trace("tconv-pf-gen-rewrite") << "- already visited" << std::endl;
+ }
+ } while (!(tctx != nullptr ? visitctx->empty() : visit.empty()));
+ Assert(visited.find(tinitialHash) != visited.end());
+ Assert(!visited.find(tinitialHash)->second.isNull());
+ Trace("tconv-pf-gen-rewrite")
+ << "...finished, return " << visited[tinitialHash] << std::endl;
// return the conclusion of the overall proof
- return t.eqNode(visited[t]);
+ return t.eqNode(visited[tinitialHash]);
}
-Node TConvProofGenerator::getRewriteStep(Node t) const
+void TConvProofGenerator::doCache(Node curHash,
+ Node cur,
+ Node r,
+ LazyCDProof& pf)
+{
+ if (d_cpolicy != TConvCachePolicy::NEVER)
+ {
+ Node eq = cur.eqNode(r);
+ d_cache[curHash] = pf.getProofFor(eq);
+ }
+}
+
+Node TConvProofGenerator::getRewriteStepInternal(Node t) const
{
NodeNodeMap::const_iterator it = d_rewriteMap.find(t);
if (it == d_rewriteMap.end())
@@ -278,9 +557,14 @@ Node TConvProofGenerator::getRewriteStep(Node t) const
}
return (*it).second;
}
-std::string TConvProofGenerator::identify() const
+std::string TConvProofGenerator::identify() const { return d_name; }
+
+std::string TConvProofGenerator::toStringDebug() const
{
- return "TConvProofGenerator";
+ std::stringstream ss;
+ ss << identify() << " (policy=" << d_policy << ", cache policy=" << d_cpolicy
+ << (d_tcontext != nullptr ? ", term-context-sensitive" : "") << ")";
+ return ss.str();
}
} // namespace CVC4
diff --git a/src/expr/term_conversion_proof_generator.h b/src/expr/term_conversion_proof_generator.h
index d7ff6e8f6..0a1f4e70a 100644
--- a/src/expr/term_conversion_proof_generator.h
+++ b/src/expr/term_conversion_proof_generator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,6 +21,7 @@
#include "expr/lazy_proof.h"
#include "expr/proof_generator.h"
#include "expr/proof_node_manager.h"
+#include "expr/term_context.h"
namespace CVC4 {
@@ -35,6 +36,19 @@ enum class TConvPolicy : uint32_t
/** Writes a term conversion policy name to a stream. */
std::ostream& operator<<(std::ostream& out, TConvPolicy tcpol);
+/** A policy for how proofs are cached in TConvProofGenerator */
+enum class TConvCachePolicy : uint32_t
+{
+ // proofs are statically cached
+ STATIC,
+ // proofs are dynamically cached, cleared when a new rewrite is added
+ DYNAMIC,
+ // proofs are never cached
+ NEVER,
+};
+/** Writes a term conversion cache policy name to a stream. */
+std::ostream& operator<<(std::ostream& out, TConvCachePolicy tcpol);
+
/**
* The term conversion proof generator.
*
@@ -71,41 +85,96 @@ std::ostream& operator<<(std::ostream& out, TConvPolicy tcpol);
* addRewriteStep. In particular, notice that in the above example, we realize
* that f(a) --> c at pre-rewrite instead of post-rewriting a --> b and then
* ending with f(a)=f(b).
+ *
+ * This class may additionally be used for term-context-sensitive rewrite
+ * systems. An example is the term formula removal pass which rewrites
+ * terms dependending on whether they occur in a "term position", for details
+ * see RtfTermContext in expr/term_context.h. To use this class in a way
+ * that takes into account term contexts, the user of the term conversion
+ * proof generator should:
+ * (1) Provide a term context callback to the constructor of this class (tccb),
+ * (2) Register rewrite steps that indicate the term context identifier of
+ * the rewrite, which is a uint32_t.
+ *
+ * For example, RtfTermContext uses hash value 2 to indicate we are in a "term
+ * position". Say the user of this class calls:
+ * addRewriteStep( (and A B), BOOLEAN_TERM_VARIABLE_1, pg, true, 2)
+ * This indicates that (and A B) should rewrite to BOOLEAN_TERM_VARIABLE_1 if
+ * (and A B) occurs in a term position, where pg is a proof generator that can
+ * provide a closed proof of:
+ * (= (and A B) BOOLEAN_TERM_VARIABLE_1)
+ * Subsequently, this class may respond to a call to getProofFor on:
+ * (=
+ * (or (and A B) (P (and A B)))
+ * (or (and A B) (P BOOLEAN_TERM_VARIABLE_1)))
+ * where P is a predicate Bool -> Bool. The proof returned by this class
+ * involves congruence and pg's proof of the equivalence above. In particular,
+ * assuming its proof of the equivalence is P1, this proof is:
+ * (CONG{=} (CONG{or} (REFL (and A B)) (CONG{P} P1)))
+ * Notice the callback provided to this class ensures that the rewrite is
+ * replayed in the expected way, e.g. the occurrence of (and A B) that is not
+ * in term position is not rewritten.
*/
class TConvProofGenerator : public ProofGenerator
{
public:
- /** Constructor
+ /**
+ * Constructor, which notice does fixpoint rewriting (since this is the
+ * most common use case) and never caches.
*
* @param pnm The proof node manager for constructing ProofNode objects.
* @param c The context that this class depends on. If none is provided,
* this class is context-independent.
* @param tpol The policy for applying rewrite steps of this class. For
* details, see d_policy.
+ * @param cpol The caching policy for this generator.
+ * @param name The name of this generator (for debugging).
+ * @param tccb The term context callback that this class depends on. If this
+ * is non-null, then this class stores a term-context-sensitive rewrite
+ * system. The rewrite steps should be given term context identifiers.
*/
TConvProofGenerator(ProofNodeManager* pnm,
context::Context* c = nullptr,
- TConvPolicy pol = TConvPolicy::FIXPOINT);
+ TConvPolicy pol = TConvPolicy::FIXPOINT,
+ TConvCachePolicy cpol = TConvCachePolicy::NEVER,
+ std::string name = "TConvProofGenerator",
+ TermContext* tccb = nullptr,
+ bool rewriteOps = false);
~TConvProofGenerator();
/**
* Add rewrite step t --> s based on proof generator.
+ *
+ * @param trustId If a null proof generator is provided, we add a step to
+ * the proof that has trustId as the rule and expected as the sole argument.
+ * @param isClosed whether to expect that pg can provide a closed proof for
+ * this fact.
+ * @param tctx The term context identifier for the rewrite step. This
+ * value should correspond to one generated by the term context callback
+ * class provided in the argument tccb provided to the constructor of this
+ * class.
*/
- void addRewriteStep(Node t, Node s, ProofGenerator* pg);
+ void addRewriteStep(Node t,
+ Node s,
+ ProofGenerator* pg,
+ PfRule trustId = PfRule::ASSUME,
+ bool isClosed = false,
+ uint32_t tctx = 0);
/** Same as above, for a single step */
- void addRewriteStep(Node t, Node s, ProofStep ps);
+ void addRewriteStep(Node t, Node s, ProofStep ps, uint32_t tctx = 0);
/** Same as above, with explicit arguments */
void addRewriteStep(Node t,
Node s,
PfRule id,
const std::vector<Node>& children,
- const std::vector<Node>& args);
+ const std::vector<Node>& args,
+ uint32_t tctx = 0);
/** Has rewrite step for term t */
- bool hasRewriteStep(Node t) const;
+ bool hasRewriteStep(Node t, uint32_t tctx = 0) const;
/**
* Get rewrite step for term t, returns the s provided in a call to
* addRewriteStep if one exists, or null otherwise.
*/
- Node getRewriteStep(Node t) const;
+ Node getRewriteStep(Node t, uint32_t tctx = 0) const;
/**
* Get the proof for formula f. It should be the case that f is of the form
* t = t', where t' is the result of rewriting t based on the rewrite steps
@@ -136,17 +205,37 @@ class TConvProofGenerator : public ProofGenerator
* f(a,c) = f(f(c),d) if d_policy is ONCE.
*/
TConvPolicy d_policy;
+ /** The cache policy */
+ TConvCachePolicy d_cpolicy;
+ /** Name identifier */
+ std::string d_name;
+ /** The cache for terms */
+ std::map<Node, std::shared_ptr<ProofNode> > d_cache;
+ /** An (optional) term context object */
+ TermContext* d_tcontext;
+ /**
+ * Whether we rewrite operators. If this flag is true, then the main
+ * traversal algorithm of this proof generator traverses operators of
+ * APPLY_UF and uses HO_CONG to justify rewriting of subterms when necessary.
+ */
+ bool d_rewriteOps;
+ /** Get rewrite step for (hash value of) term. */
+ Node getRewriteStepInternal(Node thash) const;
/**
* Adds a proof of t = t' to the proof pf where t' is the result of rewriting
* t based on the rewrite steps registered to this class. This method then
* returns the proved equality t = t'.
*/
- Node getProofForRewriting(Node t, LazyCDProof& pf);
+ Node getProofForRewriting(Node t, LazyCDProof& pf, TermContext* tc = nullptr);
/**
* Register rewrite step, returns the equality t=s if t is distinct from s
* and a rewrite step has not already been registered for t.
*/
- Node registerRewriteStep(Node t, Node s);
+ Node registerRewriteStep(Node t, Node s, uint32_t tctx);
+ /** cache that r is the rewritten form of cur, pf can provide a proof */
+ void doCache(Node curHash, Node cur, Node r, LazyCDProof& pf);
+ /** get debug information on this generator */
+ std::string toStringDebug() const;
};
} // namespace CVC4
diff --git a/src/expr/type.cpp b/src/expr/type.cpp
index 7696d9d7a..dadbdc91d 100644
--- a/src/expr/type.cpp
+++ b/src/expr/type.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Dejan Jovanovic, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -331,8 +331,7 @@ bool Type::isTuple() const {
/** Is this a record type? */
bool Type::isRecord() const {
NodeManagerScope nms(d_nodeManager);
- return d_typeNode->getKind() == kind::DATATYPE_TYPE
- && DatatypeType(*this).getDatatype().isRecord();
+ return d_typeNode->isRecord();
}
/** Is this a symbolic expression type? */
@@ -586,26 +585,10 @@ std::vector<Type> ConstructorType::getArgTypes() const {
return args;
}
-const Datatype& DatatypeType::getDatatype() const {
- NodeManagerScope nms(d_nodeManager);
- Assert(isDatatype());
- if (d_typeNode->getKind() == kind::DATATYPE_TYPE)
- {
- DatatypeIndexConstant dic = d_typeNode->getConst<DatatypeIndexConstant>();
- return d_nodeManager->toExprManager()->getDatatypeForIndex(dic.getIndex());
- }
- Assert(d_typeNode->getKind() == kind::PARAMETRIC_DATATYPE);
- return DatatypeType((*d_typeNode)[0].toType()).getDatatype();
-}
-
bool DatatypeType::isParametric() const {
return d_typeNode->isParametricDatatype();
}
-Expr DatatypeType::getConstructor(std::string name) const {
- return getDatatype().getConstructor(name);
-}
-
bool DatatypeType::isInstantiated() const {
return d_typeNode->isInstantiatedDatatype();
}
@@ -662,14 +645,6 @@ std::vector<Type> DatatypeType::getTupleTypes() const {
return vect;
}
-/** Get the description of the record type */
-const Record& DatatypeType::getRecord() const {
- NodeManagerScope nms(d_nodeManager);
- Assert(isRecord());
- const Datatype& dt = getDatatype();
- return *(dt.getRecord());
-}
-
DatatypeType SelectorType::getDomain() const {
return DatatypeType(makeType((*d_typeNode)[0]));
}
diff --git a/src/expr/type.h b/src/expr/type.h
index 61cb7eabf..69a8363dc 100644
--- a/src/expr/type.h
+++ b/src/expr/type.h
@@ -5,7 +5,7 @@
** Morgan Deters, Dejan Jovanovic, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,7 +20,6 @@
#define CVC4__TYPE_H
#include <climits>
-#include <cstdint>
#include <string>
#include <vector>
@@ -30,7 +29,7 @@ namespace CVC4 {
class NodeManager;
class CVC4_PUBLIC ExprManager;
-class CVC4_PUBLIC Expr;
+class Expr;
class TypeNode;
struct CVC4_PUBLIC ExprManagerMapCollection;
@@ -616,18 +615,8 @@ class CVC4_PUBLIC DatatypeType : public Type {
/** Construct from the base type */
DatatypeType(const Type& type = Type());
- /** Get the underlying datatype */
- const Datatype& getDatatype() const;
-
/** Is this datatype parametric? */
bool isParametric() const;
-
- /**
- * Get the constructor operator associated to the given constructor
- * name in this datatype.
- */
- Expr getConstructor(std::string name) const;
-
/**
* Has this datatype been fully instantiated ?
*
@@ -654,9 +643,6 @@ class CVC4_PUBLIC DatatypeType : public Type {
/** Get the constituent types of a tuple type */
std::vector<Type> getTupleTypes() const;
- /** Get the description of the record type */
- const Record& getRecord() const;
-
};/* class DatatypeType */
/** Class encapsulating the constructor type. */
diff --git a/src/expr/type_checker.h b/src/expr/type_checker.h
index 4b8bff946..f385856e0 100644
--- a/src/expr/type_checker.h
+++ b/src/expr/type_checker.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/type_checker_template.cpp b/src/expr/type_checker_template.cpp
index 3dedd856a..e7685dba8 100644
--- a/src/expr/type_checker_template.cpp
+++ b/src/expr/type_checker_template.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,8 +14,6 @@
** TypeChecker implementation.
**/
-#line 18 "${template}"
-
#include "expr/node_manager.h"
#include "expr/node_manager_attributes.h"
#include "expr/type_checker.h"
@@ -23,8 +21,6 @@
${typechecker_includes}
-#line 27 "${template}"
-
namespace CVC4 {
namespace expr {
@@ -44,8 +40,6 @@ TypeNode TypeChecker::computeType(NodeManager* nodeManager, TNode n, bool check)
${typerules}
-#line 48 "${template}"
-
default:
Debug("getType") << "FAILURE" << std::endl;
Unhandled() << n.getKind();
@@ -68,8 +62,6 @@ bool TypeChecker::computeIsConst(NodeManager* nodeManager, TNode n)
switch(n.getKind()) {
${construles}
-#line 72 "${template}"
-
default:;
}
diff --git a/src/expr/type_checker_util.h b/src/expr/type_checker_util.h
index 411733dcb..312ffe53a 100644
--- a/src/expr/type_checker_util.h
+++ b/src/expr/type_checker_util.h
@@ -5,7 +5,7 @@
** Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/type_matcher.cpp b/src/expr/type_matcher.cpp
index c09f98ee1..b41004880 100644
--- a/src/expr/type_matcher.cpp
+++ b/src/expr/type_matcher.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/type_matcher.h b/src/expr/type_matcher.h
index 17a3917c8..47fc36eee 100644
--- a/src/expr/type_matcher.h
+++ b/src/expr/type_matcher.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/type_node.cpp b/src/expr/type_node.cpp
index c97a24d6d..0818ca8c1 100644
--- a/src/expr/type_node.cpp
+++ b/src/expr/type_node.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -318,9 +318,6 @@ bool TypeNode::isSubtypeOf(TypeNode t) const {
return false;
}
}
- if(isSet() && t.isSet()) {
- return getSetElementType().isSubtypeOf(t.getSetElementType());
- }
if (isFunction() && t.isFunction())
{
if (!isComparableTo(t))
@@ -342,9 +339,6 @@ bool TypeNode::isComparableTo(TypeNode t) const {
if(isSubtypeOf(NodeManager::currentNM()->realType())) {
return t.isSubtypeOf(NodeManager::currentNM()->realType());
}
- if(isSet() && t.isSet()) {
- return getSetElementType().isComparableTo(t.getSetElementType());
- }
if (isFunction() && t.isFunction())
{
// comparable if they have a common type node
@@ -353,6 +347,12 @@ bool TypeNode::isComparableTo(TypeNode t) const {
return false;
}
+TypeNode TypeNode::getTesterDomainType() const
+{
+ Assert(isTester());
+ return (*this)[0];
+}
+
TypeNode TypeNode::getSequenceElementType() const
{
Assert(isSequence());
@@ -396,12 +396,16 @@ std::vector<TypeNode> TypeNode::getParamTypes() const {
return params;
}
-
-/** Is this a tuple type? */
-bool TypeNode::isTuple() const {
+bool TypeNode::isTuple() const
+{
return (getKind() == kind::DATATYPE_TYPE && getDType().isTuple());
}
+bool TypeNode::isRecord() const
+{
+ return (getKind() == kind::DATATYPE_TYPE && getDType().isRecord());
+}
+
size_t TypeNode::getTupleLength() const {
Assert(isTuple());
const DType& dt = getDType();
@@ -471,6 +475,12 @@ uint64_t TypeNode::getSortConstructorArity() const
return getAttribute(expr::SortArityAttr());
}
+std::string TypeNode::getName() const
+{
+ Assert(isSort() || isSortConstructor());
+ return getAttribute(expr::VarNameAttr());
+}
+
TypeNode TypeNode::instantiateSortConstructor(
const std::vector<TypeNode>& params) const
{
@@ -576,27 +586,19 @@ TypeNode TypeNode::commonTypeNode(TypeNode t0, TypeNode t1, bool isLeast) {
case kind::ARRAY_TYPE:
case kind::DATATYPE_TYPE:
case kind::PARAMETRIC_DATATYPE:
- case kind::SEQUENCE_TYPE: return TypeNode();
+ case kind::SEQUENCE_TYPE:
case kind::SET_TYPE:
+ case kind::BAG_TYPE:
{
- // take the least common subtype of element types
- TypeNode elementType;
- if (t1.isSet()
- && !(elementType = commonTypeNode(t0[0], t1[0], isLeast)).isNull())
- {
- return NodeManager::currentNM()->mkSetType(elementType);
- }
- else
- {
- return TypeNode();
- }
+ // we don't support subtyping except for built in types Int and Real.
+ return TypeNode(); // return null type
}
- case kind::SEXPR_TYPE:
- Unimplemented()
- << "haven't implemented leastCommonType for symbolic expressions yet";
- default:
- Unimplemented() << "don't have a commonType for types `" << t0 << "' and `"
- << t1 << "'";
+ case kind::SEXPR_TYPE:
+ Unimplemented()
+ << "haven't implemented leastCommonType for symbolic expressions yet";
+ default:
+ Unimplemented() << "don't have a commonType for types `" << t0
+ << "' and `" << t1 << "'";
}
}
@@ -673,7 +675,7 @@ bool TypeNode::isSygusDatatype() const
std::string TypeNode::toString() const {
std::stringstream ss;
OutputLanguage outlang = (this == &s_null) ? language::output::LANG_AUTO : options::outputLanguage();
- d_nv->toStream(ss, -1, false, 0, outlang);
+ d_nv->toStream(ss, -1, 0, outlang);
return ss.str();
}
@@ -688,4 +690,15 @@ const DType& TypeNode::getDType() const
return (*this)[0].getDType();
}
+bool TypeNode::isBag() const
+{
+ return getKind() == kind::BAG_TYPE;
+}
+
+TypeNode TypeNode::getBagElementType() const
+{
+ Assert(isBag());
+ return (*this)[0];
+}
+
}/* CVC4 namespace */
diff --git a/src/expr/type_node.h b/src/expr/type_node.h
index f957fe0d0..01e096c72 100644
--- a/src/expr/type_node.h
+++ b/src/expr/type_node.h
@@ -5,7 +5,7 @@
** Morgan Deters, Dejan Jovanovic, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -22,8 +22,6 @@
#ifndef CVC4__TYPE_NODE_H
#define CVC4__TYPE_NODE_H
-#include <stdint.h>
-
#include <iostream>
#include <string>
#include <unordered_map>
@@ -385,7 +383,7 @@ public:
* @param language the language in which to output
*/
inline void toStream(std::ostream& out, OutputLanguage language = language::output::LANG_AUTO) const {
- d_nv->toStream(out, -1, false, 0, language);
+ d_nv->toStream(out, -1, 0, language);
}
/**
@@ -452,7 +450,7 @@ public:
/**
* Is this a first-class type?
* First-class types are types for which:
- * (1) we handle equalities between terms of that type, and
+ * (1) we handle equalities between terms of that type, and
* (2) they are allowed to be parameters of parametric types (e.g. index or element types of arrays).
*
* Examples of types that are not first-class include constructor types,
@@ -518,6 +516,9 @@ public:
/** Is this a Set type? */
bool isSet() const;
+ /** Is this a Bag type? */
+ bool isBag() const;
+
/** Is this a Sequence type? */
bool isSequence() const;
@@ -536,9 +537,15 @@ public:
/** Get the return type (for selector types) */
TypeNode getSelectorRangeType() const;
+ /** Get the domain type (for tester types) */
+ TypeNode getTesterDomainType() const;
+
/** Get the element type (for set types) */
TypeNode getSetElementType() const;
+ /** Get the element type (for bag types) */
+ TypeNode getBagElementType() const;
+
/** Get the element type (for sequence types) */
TypeNode getSequenceElementType() const;
/**
@@ -599,6 +606,9 @@ public:
/** Is this a tuple type? */
bool isTuple() const;
+ /** Is this a record type? */
+ bool isRecord() const;
+
/** Get the length of a tuple type */
size_t getTupleLength() const;
@@ -686,6 +696,11 @@ public:
uint64_t getSortConstructorArity() const;
/**
+ * Get name, for uninterpreted sorts and uninterpreted sort constructors.
+ */
+ std::string getName() const;
+
+ /**
* Instantiate a sort constructor type. The type on which this method is
* called should be a sort constructor type whose parameter list is the
* same size as argument params. This constructs the instantiated version of
@@ -709,7 +724,7 @@ public:
static TypeNode leastCommonTypeNode(TypeNode t0, TypeNode t1);
static TypeNode mostCommonTypeNode(TypeNode t0, TypeNode t1);
- /** get ensure type condition
+ /** get ensure type condition
* Return value is a condition that implies that n has type tn.
*/
static Node getEnsureTypeCondition( Node n, TypeNode tn );
@@ -763,6 +778,7 @@ inline Type TypeNode::toType() const
}
inline TypeNode TypeNode::fromType(const Type& t) {
+ NodeManagerScope scope(t.d_nodeManager);
return NodeManager::fromType(t);
}
@@ -1007,7 +1023,8 @@ inline TypeNode TypeNode::getRangeType() const {
if(isTester()) {
return NodeManager::currentNM()->booleanType();
}
- Assert(isFunction() || isConstructor() || isSelector());
+ Assert(isFunction() || isConstructor() || isSelector())
+ << "Cannot get range type of " << *this;
return (*this)[getNumChildren() - 1];
}
@@ -1054,10 +1071,9 @@ inline bool TypeNode::isTester() const {
/** Is this a floating-point type of with <code>exp</code> exponent bits
and <code>sig</code> significand bits */
inline bool TypeNode::isFloatingPoint(unsigned exp, unsigned sig) const {
- return
- ( getKind() == kind::FLOATINGPOINT_TYPE &&
- getConst<FloatingPointSize>().exponent() == exp &&
- getConst<FloatingPointSize>().significand() == sig );
+ return (getKind() == kind::FLOATINGPOINT_TYPE
+ && getConst<FloatingPointSize>().exponentWidth() == exp
+ && getConst<FloatingPointSize>().significandWidth() == sig);
}
/** Is this a bit-vector type of size <code>size</code> */
@@ -1069,13 +1085,13 @@ inline bool TypeNode::isBitVector(unsigned size) const {
/** Get the exponent size of this floating-point type */
inline unsigned TypeNode::getFloatingPointExponentSize() const {
Assert(isFloatingPoint());
- return getConst<FloatingPointSize>().exponent();
+ return getConst<FloatingPointSize>().exponentWidth();
}
/** Get the significand size of this floating-point type */
inline unsigned TypeNode::getFloatingPointSignificandSize() const {
Assert(isFloatingPoint());
- return getConst<FloatingPointSize>().significand();
+ return getConst<FloatingPointSize>().significandWidth();
}
/** Get the size of this bit-vector type */
@@ -1102,7 +1118,6 @@ inline unsigned TypeNode::getBitVectorSize() const {
*/
static void __attribute__((used)) debugPrintTypeNode(const TypeNode& n) {
Warning() << Node::setdepth(-1)
- << Node::printtypes(false)
<< Node::dag(true)
<< Node::setlanguage(language::output::LANG_AST)
<< n << std::endl;
@@ -1110,7 +1125,6 @@ static void __attribute__((used)) debugPrintTypeNode(const TypeNode& n) {
}
static void __attribute__((used)) debugPrintTypeNodeNoDag(const TypeNode& n) {
Warning() << Node::setdepth(-1)
- << Node::printtypes(false)
<< Node::dag(false)
<< Node::setlanguage(language::output::LANG_AST)
<< n << std::endl;
diff --git a/src/expr/type_properties_template.h b/src/expr/type_properties_template.h
index a8adadf6e..264d065d6 100644
--- a/src/expr/type_properties_template.h
+++ b/src/expr/type_properties_template.h
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,8 +19,6 @@
#ifndef CVC4__TYPE_PROPERTIES_H
#define CVC4__TYPE_PROPERTIES_H
-#line 23 "${template}"
-
#include <sstream>
#include "base/check.h"
@@ -31,8 +29,6 @@
${type_properties_includes}
-#line 35 "${template}"
-
namespace CVC4 {
namespace kind {
@@ -47,7 +43,6 @@ inline Cardinality getCardinality(TypeConstant tc)
switch (tc)
{
${type_constant_cardinalities}
-#line 51 "${template}"
default: InternalError() << "No cardinality known for type constant " << tc;
}
} /* getCardinality(TypeConstant) */
@@ -64,7 +59,6 @@ inline Cardinality getCardinality(TypeNode typeNode) {
case TYPE_CONSTANT:
return getCardinality(typeNode.getConst<TypeConstant>());
${type_cardinalities}
-#line 68 "${template}"
default:
InternalError() << "A theory kinds file did not provide a cardinality "
<< "or cardinality computer for type:\n"
@@ -75,7 +69,6 @@ ${type_cardinalities}
inline bool isWellFounded(TypeConstant tc) {
switch(tc) {
${type_constant_wellfoundednesses}
-#line 79 "${template}"
default:
InternalError() << "No well-foundedness status known for type constant: "
<< tc;
@@ -88,7 +81,6 @@ inline bool isWellFounded(TypeNode typeNode) {
case TYPE_CONSTANT:
return isWellFounded(typeNode.getConst<TypeConstant>());
${type_wellfoundednesses}
-#line 92 "${template}"
default:
InternalError() << "A theory kinds file did not provide a well-foundedness "
<< "or well-foundedness computer for type:\n"
@@ -101,7 +93,6 @@ inline Node mkGroundTerm(TypeConstant tc)
switch (tc)
{
${type_constant_groundterms}
-#line 105 "${template}"
default:
InternalError() << "No ground term known for type constant: " << tc;
}
@@ -115,7 +106,6 @@ inline Node mkGroundTerm(TypeNode typeNode)
case TYPE_CONSTANT:
return mkGroundTerm(typeNode.getConst<TypeConstant>());
${type_groundterms}
-#line 119 "${template}"
default:
InternalError() << "A theory kinds file did not provide a ground term "
<< "or ground term computer for type:\n"
diff --git a/src/expr/uninterpreted_constant.cpp b/src/expr/uninterpreted_constant.cpp
index c9cbcba20..ee490c7c7 100644
--- a/src/expr/uninterpreted_constant.cpp
+++ b/src/expr/uninterpreted_constant.cpp
@@ -2,10 +2,10 @@
/*! \file uninterpreted_constant.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Tim King, Morgan Deters
+ ** Andres Noetzli, Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/uninterpreted_constant.h b/src/expr/uninterpreted_constant.h
index eb6cc203a..b36bd6b1a 100644
--- a/src/expr/uninterpreted_constant.h
+++ b/src/expr/uninterpreted_constant.h
@@ -2,10 +2,10 @@
/*! \file uninterpreted_constant.h
** \verbatim
** Top contributors (to current version):
- ** Morgan Deters, Tim King
+ ** Andres Noetzli, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/expr/variable_type_map.h b/src/expr/variable_type_map.h
index 38f6e520d..fd51e0243 100644
--- a/src/expr/variable_type_map.h
+++ b/src/expr/variable_type_map.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/fix-install-headers.sh b/src/fix-install-headers.sh
index 39d8bc663..7f9fa5d5b 100755
--- a/src/fix-install-headers.sh
+++ b/src/fix-install-headers.sh
@@ -2,6 +2,7 @@
set -e -o pipefail
-dir=$1
+dir="$DESTDIR$1"
+
find "$dir/include/cvc4/" -type f \
-exec sed -i'' -e 's/include.*"\(.*\)"/include <cvc4\/\1>/' {} +
diff --git a/src/include/cvc4.h b/src/include/cvc4.h
index 89c90a8c4..bf59b6636 100644
--- a/src/include/cvc4.h
+++ b/src/include/cvc4.h
@@ -5,7 +5,7 @@
** Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,7 +20,7 @@
#include <cvc4/base/configuration.h>
#include <cvc4/base/exception.h>
-#include <cvc4/expr/datatype.h>
+#include <cvc4/expr/datatype_index.h>
#include <cvc4/expr/expr.h>
#include <cvc4/expr/expr_manager.h>
#include <cvc4/options/options.h>
diff --git a/src/include/cvc4_private.h b/src/include/cvc4_private.h
index ebf074f31..af84549b0 100644
--- a/src/include/cvc4_private.h
+++ b/src/include/cvc4_private.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/include/cvc4_private_library.h b/src/include/cvc4_private_library.h
index 875a4d78b..6d1edc094 100644
--- a/src/include/cvc4_private_library.h
+++ b/src/include/cvc4_private_library.h
@@ -5,7 +5,7 @@
** Andres Noetzli, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/include/cvc4_public.h b/src/include/cvc4_public.h
index 9cd2f9469..0e43335db 100644
--- a/src/include/cvc4_public.h
+++ b/src/include/cvc4_public.h
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,6 +19,7 @@
#ifndef CVC4_PUBLIC_H
#define CVC4_PUBLIC_H
+#include <stddef.h>
#include <stdint.h>
#if defined _WIN32 || defined __CYGWIN__
diff --git a/src/include/cvc4parser_private.h b/src/include/cvc4parser_private.h
index 51bf5ba17..2c4a68ad2 100644
--- a/src/include/cvc4parser_private.h
+++ b/src/include/cvc4parser_private.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/include/cvc4parser_public.h b/src/include/cvc4parser_public.h
index 08c8bdc08..0b72eef92 100644
--- a/src/include/cvc4parser_public.h
+++ b/src/include/cvc4parser_public.h
@@ -5,7 +5,7 @@
** Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/lib/clock_gettime.c b/src/lib/clock_gettime.c
index 733f3cb7c..332d32af9 100644
--- a/src/lib/clock_gettime.c
+++ b/src/lib/clock_gettime.c
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/lib/clock_gettime.h b/src/lib/clock_gettime.h
index 83164e7cf..6aa39c5ea 100644
--- a/src/lib/clock_gettime.h
+++ b/src/lib/clock_gettime.h
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/lib/ffs.c b/src/lib/ffs.c
index 3421e590a..d3e642364 100644
--- a/src/lib/ffs.c
+++ b/src/lib/ffs.c
@@ -5,7 +5,7 @@
** Morgan Deters, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/lib/ffs.h b/src/lib/ffs.h
index aa6c6cf4a..f66c456bd 100644
--- a/src/lib/ffs.h
+++ b/src/lib/ffs.h
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/lib/replacements.h b/src/lib/replacements.h
index 768ba03fe..956556068 100644
--- a/src/lib/replacements.h
+++ b/src/lib/replacements.h
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/lib/strtok_r.c b/src/lib/strtok_r.c
index 1be1aefa6..d0d9d65d2 100644
--- a/src/lib/strtok_r.c
+++ b/src/lib/strtok_r.c
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/lib/strtok_r.h b/src/lib/strtok_r.h
index db90b24e8..ba6aeff2d 100644
--- a/src/lib/strtok_r.h
+++ b/src/lib/strtok_r.h
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/main/CMakeLists.txt b/src/main/CMakeLists.txt
index 4fbb14183..393aef267 100644
--- a/src/main/CMakeLists.txt
+++ b/src/main/CMakeLists.txt
@@ -1,3 +1,13 @@
+#####################
+## CMakeLists.txt
+## Top contributors (to current version):
+## Mathias Preiner, Aina Niemetz, Gereon Kremer
+## This file is part of the CVC4 project.
+## Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+## in the top-level source directory and their institutional affiliations.
+## All rights reserved. See the file COPYING in the top-level source
+## directory for licensing information.
+##
#-----------------------------------------------------------------------------#
# libmain source files
@@ -31,8 +41,8 @@ add_dependencies(main cvc4 cvc4parser gen-tokens)
get_target_property(LIBCVC4_INCLUDES cvc4 INCLUDE_DIRECTORIES)
target_include_directories(main PRIVATE ${LIBCVC4_INCLUDES})
-# main-test library is only used for linking against system and unit tests so
-# that we don't have to include all object files of main into each unit/system
+# main-test library is only used for linking against api and unit tests so
+# that we don't have to include all object files of main into each api/unit
# test. Do not link against main-test in any other case.
add_library(main-test driver_unified.cpp $<TARGET_OBJECTS:main>)
target_compile_definitions(main-test PRIVATE -D__BUILDING_CVC4DRIVER)
@@ -51,11 +61,11 @@ target_link_libraries(cvc4-bin cvc4 cvc4parser)
if(PROGRAM_PREFIX)
install(PROGRAMS
$<TARGET_FILE:cvc4-bin>
- DESTINATION ${RUNTIME_INSTALL_DIR}
+ DESTINATION ${CMAKE_INSTALL_BINDIR}
RENAME ${PROGRAM_PREFIX}cvc4)
else()
install(TARGETS cvc4-bin
- DESTINATION ${RUNTIME_INSTALL_DIR})
+ DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
# In order to get a fully static executable we have to make sure that we also
@@ -68,10 +78,10 @@ if(ENABLE_STATIC_BINARY)
set_target_properties(cvc4-bin PROPERTIES LINK_SEARCH_END_STATIC ON)
endif()
-if(USE_READLINE)
- target_link_libraries(cvc4-bin ${Readline_LIBRARIES})
- target_link_libraries(main-test ${Readline_LIBRARIES})
- target_include_directories(main PRIVATE ${Readline_INCLUDE_DIR})
+if(USE_EDITLINE)
+ target_link_libraries(cvc4-bin ${Editline_LIBRARIES})
+ target_link_libraries(main-test ${Editline_LIBRARIES})
+ target_include_directories(main PRIVATE ${Editline_INCLUDE_DIRS})
endif()
#-----------------------------------------------------------------------------#
diff --git a/src/main/command_executor.cpp b/src/main/command_executor.cpp
index d63861b0c..b1a7c70b5 100644
--- a/src/main/command_executor.cpp
+++ b/src/main/command_executor.cpp
@@ -5,7 +5,7 @@
** Kshitij Bansal, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -50,12 +50,19 @@ void printStatsIncremental(std::ostream& out, const std::string& prvsStatsString
CommandExecutor::CommandExecutor(Options& options)
: d_solver(new api::Solver(&options)),
+ d_symman(new SymbolManager(d_solver.get())),
d_smtEngine(d_solver->getSmtEngine()),
d_options(options),
d_stats("driver"),
d_result()
{
}
+CommandExecutor::~CommandExecutor()
+{
+ // ensure that symbol manager is destroyed before solver
+ d_symman.reset(nullptr);
+ d_solver.reset(nullptr);
+}
void CommandExecutor::flushStatistics(std::ostream& out) const
{
@@ -118,12 +125,13 @@ bool CommandExecutor::doCommandSingleton(Command* cmd)
{
bool status = true;
if(d_options.getVerbosity() >= -1) {
- status = smtEngineInvoke(d_smtEngine, cmd, d_options.getOut());
+ status =
+ solverInvoke(d_solver.get(), d_symman.get(), cmd, d_options.getOut());
} else {
- status = smtEngineInvoke(d_smtEngine, cmd, nullptr);
+ status = solverInvoke(d_solver.get(), d_symman.get(), cmd, nullptr);
}
- Result res;
+ api::Result res;
const CheckSatCommand* cs = dynamic_cast<const CheckSatCommand*>(cmd);
if(cs != nullptr) {
d_result = res = cs->getResult();
@@ -149,34 +157,34 @@ bool CommandExecutor::doCommandSingleton(Command* cmd)
if (status) {
std::vector<std::unique_ptr<Command> > getterCommands;
if (d_options.getDumpModels()
- && (res.asSatisfiabilityResult() == Result::SAT
- || (res.isUnknown() && res.whyUnknown() == Result::INCOMPLETE)))
+ && (res.isSat()
+ || (res.isSatUnknown()
+ && res.getResult().whyUnknown() == Result::INCOMPLETE)))
{
getterCommands.emplace_back(new GetModelCommand());
}
- if (d_options.getDumpProofs()
- && res.asSatisfiabilityResult() == Result::UNSAT)
+ if (d_options.getDumpProofs() && res.isUnsat())
{
getterCommands.emplace_back(new GetProofCommand());
}
if (d_options.getDumpInstantiations()
&& ((d_options.getInstFormatMode() != options::InstFormatMode::SZS
- && (res.asSatisfiabilityResult() == Result::SAT
- || (res.isUnknown()
- && res.whyUnknown() == Result::INCOMPLETE)))
- || res.asSatisfiabilityResult() == Result::UNSAT))
+ && (res.isSat()
+ || (res.isSatUnknown()
+ && res.getResult().whyUnknown() == Result::INCOMPLETE)))
+ || res.isUnsat()))
{
getterCommands.emplace_back(new GetInstantiationsCommand());
}
- if (d_options.getDumpSynth() &&
- res.asSatisfiabilityResult() == Result::UNSAT) {
+ if (d_options.getDumpSynth() && res.isUnsat())
+ {
getterCommands.emplace_back(new GetSynthSolutionCommand());
}
- if (d_options.getDumpUnsatCores() &&
- res.asSatisfiabilityResult() == Result::UNSAT) {
+ if (d_options.getDumpUnsatCores() && res.isUnsat())
+ {
getterCommands.emplace_back(new GetUnsatCoreCommand());
}
@@ -197,17 +205,24 @@ bool CommandExecutor::doCommandSingleton(Command* cmd)
return status;
}
-bool smtEngineInvoke(SmtEngine* smt, Command* cmd, std::ostream *out)
+bool solverInvoke(api::Solver* solver,
+ SymbolManager* sm,
+ Command* cmd,
+ std::ostream* out)
{
- if(out == NULL) {
- cmd->invoke(smt);
- } else {
- cmd->invoke(smt, *out);
+ if (out == NULL)
+ {
+ cmd->invoke(solver, sm);
+ }
+ else
+ {
+ cmd->invoke(solver, sm, *out);
}
// ignore the error if the command-verbosity is 0 for this command
std::string commandName =
std::string("command-verbosity:") + cmd->getCommandName();
- if(smt->getOption(commandName).getIntegerValue() == 0) {
+ if (solver->getOption(commandName) == "0")
+ {
return true;
}
return !cmd->fail();
diff --git a/src/main/command_executor.h b/src/main/command_executor.h
index de21db74d..4023b86de 100644
--- a/src/main/command_executor.h
+++ b/src/main/command_executor.h
@@ -5,7 +5,7 @@
** Aina Niemetz, Kshitij Bansal, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,16 +20,14 @@
#include "api/cvc4cpp.h"
#include "expr/expr_manager.h"
+#include "expr/symbol_manager.h"
#include "options/options.h"
-#include "smt/command.h"
#include "smt/smt_engine.h"
#include "util/statistics_registry.h"
namespace CVC4 {
-namespace api {
-class Solver;
-}
+class Command;
namespace main {
@@ -39,18 +37,31 @@ class CommandExecutor
std::string d_lastStatistics;
protected:
+ /**
+ * The solver object, which is allocated by this class and is used for
+ * executing most commands (e.g. check-sat).
+ */
std::unique_ptr<api::Solver> d_solver;
+ /**
+ * The symbol manager, which is allocated by this class. This manages
+ * all things related to definitions of symbols and their impact on behaviors
+ * for commands (e.g. get-unsat-core, get-model, get-assignment), as well
+ * as tracking expression names. Note the symbol manager is independent from
+ * the parser, which uses this symbol manager given a text input.
+ *
+ * Certain commands (e.g. reset-assertions) have a specific impact on the
+ * symbol manager.
+ */
+ std::unique_ptr<SymbolManager> d_symman;
SmtEngine* d_smtEngine;
Options& d_options;
StatisticsRegistry d_stats;
- Result d_result;
+ api::Result d_result;
public:
CommandExecutor(Options& options);
- virtual ~CommandExecutor()
- {
- }
+ virtual ~CommandExecutor();
/**
* Executes a command. Recursively handles if cmd is a command
@@ -66,7 +77,10 @@ class CommandExecutor
/** Get a pointer to the solver object owned by this CommandExecutor. */
api::Solver* getSolver() { return d_solver.get(); }
- Result getResult() const { return d_result; }
+ /** Get a pointer to the symbol manager owned by this CommandExecutor */
+ SymbolManager* getSymbolManager() { return d_symman.get(); }
+
+ api::Result getResult() const { return d_result; }
void reset();
StatisticsRegistry& getStatisticsRegistry() {
@@ -100,7 +114,10 @@ private:
}; /* class CommandExecutor */
-bool smtEngineInvoke(SmtEngine* smt, Command* cmd, std::ostream *out);
+bool solverInvoke(api::Solver* solver,
+ SymbolManager* sm,
+ Command* cmd,
+ std::ostream* out);
}/* CVC4::main namespace */
}/* CVC4 namespace */
diff --git a/src/main/driver_unified.cpp b/src/main/driver_unified.cpp
index 1c32f069b..673c5ddd9 100644
--- a/src/main/driver_unified.cpp
+++ b/src/main/driver_unified.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Liana Hadarean, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -213,7 +213,8 @@ int runCvc4(int argc, char* argv[], Options& opts) {
cmd->setMuted(true);
pExecutor->doCommand(cmd);
}
- InteractiveShell shell(pExecutor->getSolver());
+ InteractiveShell shell(pExecutor->getSolver(),
+ pExecutor->getSymbolManager());
if(opts.getInteractivePrompt()) {
Message() << Configuration::getPackageName()
<< " " << Configuration::getVersionString();
@@ -258,7 +259,10 @@ int runCvc4(int argc, char* argv[], Options& opts) {
// pExecutor->doCommand(cmd);
}
- ParserBuilder parserBuilder(pExecutor->getSolver(), filename, opts);
+ ParserBuilder parserBuilder(pExecutor->getSolver(),
+ pExecutor->getSymbolManager(),
+ filename,
+ opts);
if( inputFromStdin ) {
#if defined(CVC4_COMPETITION_MODE) && !defined(CVC4_SMTCOMP_APPLICATION_TRACK)
@@ -411,7 +415,10 @@ int runCvc4(int argc, char* argv[], Options& opts) {
pExecutor->doCommand(cmd);
}
- ParserBuilder parserBuilder(pExecutor->getSolver(), filename, opts);
+ ParserBuilder parserBuilder(pExecutor->getSolver(),
+ pExecutor->getSymbolManager(),
+ filename,
+ opts);
if( inputFromStdin ) {
#if defined(CVC4_COMPETITION_MODE) && !defined(CVC4_SMTCOMP_APPLICATION_TRACK)
@@ -450,7 +457,7 @@ int runCvc4(int argc, char* argv[], Options& opts) {
}
}
- Result result;
+ api::Result result;
if(status) {
result = pExecutor->getResult();
returnValue = 0;
@@ -467,7 +474,7 @@ int runCvc4(int argc, char* argv[], Options& opts) {
_exit(returnValue);
#endif /* CVC4_COMPETITION_MODE */
- ReferenceStat< Result > s_statSatResult("sat/unsat", result);
+ ReferenceStat<api::Result> s_statSatResult("sat/unsat", result);
RegisterStatistic statSatResultReg(&pExecutor->getStatisticsRegistry(),
&s_statSatResult);
diff --git a/src/main/interactive_shell.cpp b/src/main/interactive_shell.cpp
index 17b792ab4..3586fce87 100644
--- a/src/main/interactive_shell.cpp
+++ b/src/main/interactive_shell.cpp
@@ -2,17 +2,17 @@
/*! \file interactive_shell.cpp
** \verbatim
** Top contributors (to current version):
- ** Morgan Deters, Christopher L. Conway, Tim King
+ ** Morgan Deters, Christopher L. Conway, Andrew V. Jones
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
** \brief Interactive shell for CVC4
**
** This file is the implementation for the CVC4 interactive shell.
- ** The shell supports the readline library.
+ ** The shell supports the editline library.
**/
#include "main/interactive_shell.h"
@@ -26,19 +26,19 @@
#include <utility>
#include <vector>
-//This must go before HAVE_LIBREADLINE.
+// This must go before HAVE_LIBEDITLINE.
#include "cvc4autoconfig.h"
-#if HAVE_LIBREADLINE
-# include <readline/readline.h>
-# include <readline/history.h>
+#if HAVE_LIBEDITLINE
+#include <editline/readline.h>
# if HAVE_EXT_STDIO_FILEBUF_H
# include <ext/stdio_filebuf.h>
# endif /* HAVE_EXT_STDIO_FILEBUF_H */
-#endif /* HAVE_LIBREADLINE */
+#endif /* HAVE_LIBEDITLINE */
#include "api/cvc4cpp.h"
#include "base/output.h"
+#include "expr/symbol_manager.h"
#include "options/language.h"
#include "options/options.h"
#include "parser/input.h"
@@ -56,7 +56,7 @@ using namespace language;
const string InteractiveShell::INPUT_FILENAME = "<shell>";
-#if HAVE_LIBREADLINE
+#if HAVE_LIBEDITLINE
#if HAVE_EXT_STDIO_FILEBUF_H
using __gnu_cxx::stdio_filebuf;
@@ -82,15 +82,15 @@ static const std::string* commandsEnd;
static set<string> s_declarations;
-#endif /* HAVE_LIBREADLINE */
+#endif /* HAVE_LIBEDITLINE */
-InteractiveShell::InteractiveShell(api::Solver* solver)
+InteractiveShell::InteractiveShell(api::Solver* solver, SymbolManager* sm)
: d_options(solver->getOptions()),
d_in(*d_options.getIn()),
d_out(*d_options.getOutConst()),
d_quit(false)
{
- ParserBuilder parserBuilder(solver, INPUT_FILENAME, d_options);
+ ParserBuilder parserBuilder(solver, sm, INPUT_FILENAME, d_options);
/* Create parser with bogus input. */
d_parser = parserBuilder.withStringInput("").build();
if(d_options.wasSetByUserForceLogicString()) {
@@ -98,14 +98,14 @@ InteractiveShell::InteractiveShell(api::Solver* solver)
d_parser->forceLogic(tmp.getLogicString());
}
-#if HAVE_LIBREADLINE
+#if HAVE_LIBEDITLINE
if(&d_in == &cin) {
::rl_readline_name = const_cast<char*>("CVC4");
-#if READLINE_COMPENTRY_FUNC_RETURNS_CHARP
+#if EDITLINE_COMPENTRY_FUNC_RETURNS_CHARP
::rl_completion_entry_function = commandGenerator;
-#else /* READLINE_COMPENTRY_FUNC_RETURNS_CHARP */
+#else /* EDITLINE_COMPENTRY_FUNC_RETURNS_CHARP */
::rl_completion_entry_function = (int (*)(const char*, int)) commandGenerator;
-#endif /* READLINE_COMPENTRY_FUNC_RETURNS_CHARP */
+#endif /* EDITLINE_COMPENTRY_FUNC_RETURNS_CHARP */
::using_history();
OutputLanguage lang = toOutputLanguage(d_options.getInputLanguage());
@@ -135,7 +135,7 @@ InteractiveShell::InteractiveShell(api::Solver* solver)
throw Exception(ss.str());
}
}
- d_usingReadline = true;
+ d_usingEditline = true;
int err = ::read_history(d_historyFilename.c_str());
::stifle_history(s_historyLimit);
if(Notice.isOn()) {
@@ -148,15 +148,15 @@ InteractiveShell::InteractiveShell(api::Solver* solver)
}
}
} else {
- d_usingReadline = false;
+ d_usingEditline = false;
}
-#else /* HAVE_LIBREADLINE */
- d_usingReadline = false;
-#endif /* HAVE_LIBREADLINE */
+#else /* HAVE_LIBEDITLINE */
+ d_usingEditline = false;
+#endif /* HAVE_LIBEDITLINE */
}/* InteractiveShell::InteractiveShell() */
InteractiveShell::~InteractiveShell() {
-#if HAVE_LIBREADLINE
+#if HAVE_LIBEDITLINE
int err = ::write_history(d_historyFilename.c_str());
if(err == 0) {
Notice() << "Wrote " << ::history_length << " lines of history to "
@@ -165,7 +165,7 @@ InteractiveShell::~InteractiveShell() {
Notice() << "Could not write history to " << d_historyFilename
<< ": " << strerror(err) << std::endl;
}
-#endif /* HAVE_LIBREADLINE */
+#endif /* HAVE_LIBEDITLINE */
delete d_parser;
}
@@ -189,8 +189,9 @@ restart:
}
/* Prompt the user for input. */
- if(d_usingReadline) {
-#if HAVE_LIBREADLINE
+ if (d_usingEditline)
+ {
+#if HAVE_LIBEDITLINE
lineBuf = ::readline(d_options.getInteractivePrompt()
? (line == "" ? "CVC4> " : "... > ") : "");
if(lineBuf != NULL && lineBuf[0] != '\0') {
@@ -198,8 +199,10 @@ restart:
}
line += lineBuf == NULL ? "" : lineBuf;
free(lineBuf);
-#endif /* HAVE_LIBREADLINE */
- } else {
+#endif /* HAVE_LIBEDITLINE */
+ }
+ else
+ {
if(d_options.getInteractivePrompt()) {
if(line == "") {
d_out << "CVC4> " << flush;
@@ -236,8 +239,9 @@ restart:
}
/* If we hit EOF, we're done. */
- if( (!d_usingReadline && d_in.eof()) ||
- (d_usingReadline && lineBuf == NULL) ) {
+ if ((!d_usingEditline && d_in.eof())
+ || (d_usingEditline && lineBuf == NULL))
+ {
input += line;
if(input.empty()) {
@@ -254,7 +258,8 @@ restart:
goto restart;
}
- if(!d_usingReadline) {
+ if (!d_usingEditline)
+ {
/* Extract the newline delimiter from the stream too */
int c CVC4_UNUSED = d_in.get();
assert(c == '\n');
@@ -268,16 +273,19 @@ restart:
n = input.length() - 1;
if( !line.empty() && input[n] == '\\' ) {
input[n] = '\n';
- if(d_usingReadline) {
-#if HAVE_LIBREADLINE
+ if (d_usingEditline)
+ {
+#if HAVE_LIBEDITLINE
lineBuf = ::readline(d_options.getInteractivePrompt() ? "... > " : "");
if(lineBuf != NULL && lineBuf[0] != '\0') {
::add_history(lineBuf);
}
line = lineBuf == NULL ? "" : lineBuf;
free(lineBuf);
-#endif /* HAVE_LIBREADLINE */
- } else {
+#endif /* HAVE_LIBEDITLINE */
+ }
+ else
+ {
if(d_options.getInteractivePrompt()) {
d_out << "... > " << flush;
}
@@ -302,34 +310,56 @@ restart:
CommandSequence *cmd_seq = new CommandSequence();
Command *cmd;
- try {
- while( (cmd = d_parser->nextCommand()) ) {
+ try
+ {
+ while ((cmd = d_parser->nextCommand()))
+ {
cmd_seq->addCommand(cmd);
- if(dynamic_cast<QuitCommand*>(cmd) != NULL) {
+ if (dynamic_cast<QuitCommand*>(cmd) != NULL)
+ {
d_quit = true;
break;
- } else {
-#if HAVE_LIBREADLINE
- if(dynamic_cast<DeclareFunctionCommand*>(cmd) != NULL) {
- s_declarations.insert(dynamic_cast<DeclareFunctionCommand*>(cmd)->getSymbol());
- } else if(dynamic_cast<DefineFunctionCommand*>(cmd) != NULL) {
- s_declarations.insert(dynamic_cast<DefineFunctionCommand*>(cmd)->getSymbol());
- } else if(dynamic_cast<DeclareTypeCommand*>(cmd) != NULL) {
- s_declarations.insert(dynamic_cast<DeclareTypeCommand*>(cmd)->getSymbol());
- } else if(dynamic_cast<DefineTypeCommand*>(cmd) != NULL) {
- s_declarations.insert(dynamic_cast<DefineTypeCommand*>(cmd)->getSymbol());
+ }
+ else
+ {
+#if HAVE_LIBEDITLINE
+ if (dynamic_cast<DeclareFunctionCommand*>(cmd) != NULL)
+ {
+ s_declarations.insert(
+ dynamic_cast<DeclareFunctionCommand*>(cmd)->getSymbol());
+ }
+ else if (dynamic_cast<DefineFunctionCommand*>(cmd) != NULL)
+ {
+ s_declarations.insert(
+ dynamic_cast<DefineFunctionCommand*>(cmd)->getSymbol());
+ }
+ else if (dynamic_cast<DeclareSortCommand*>(cmd) != NULL)
+ {
+ s_declarations.insert(
+ dynamic_cast<DeclareSortCommand*>(cmd)->getSymbol());
+ }
+ else if (dynamic_cast<DefineSortCommand*>(cmd) != NULL)
+ {
+ s_declarations.insert(
+ dynamic_cast<DefineSortCommand*>(cmd)->getSymbol());
}
-#endif /* HAVE_LIBREADLINE */
+#endif /* HAVE_LIBEDITLINE */
}
}
- } catch(ParserEndOfFileException& pe) {
+ }
+ catch (ParserEndOfFileException& pe)
+ {
line += "\n";
goto restart;
- } catch(ParserException& pe) {
+ }
+ catch (ParserException& pe)
+ {
if (language::isOutputLang_smt2(d_options.getOutputLanguage()))
{
d_out << "(error \"" << pe << "\")" << endl;
- } else {
+ }
+ else
+ {
d_out << pe << endl;
}
// We can't really clear out the sequence and abort the current line,
@@ -343,14 +373,14 @@ restart:
// FIXME: does that mean e.g. that a pushed LET scope might not yet have
// been popped?!
//
- //delete cmd_seq;
- //cmd_seq = new CommandSequence();
+ // delete cmd_seq;
+ // cmd_seq = new CommandSequence();
}
return cmd_seq;
}/* InteractiveShell::readCommand() */
-#if HAVE_LIBREADLINE
+#if HAVE_LIBEDITLINE
char** commandCompletion(const char* text, int start, int end) {
Debug("rl") << "text: " << text << endl;
@@ -400,6 +430,6 @@ char* commandGenerator(const char* text, int state) {
return *rlDeclaration == jj ? NULL : strdup((*(*rlDeclaration)++).c_str());
}
-#endif /* HAVE_LIBREADLINE */
+#endif /* HAVE_LIBEDITLINE */
}/* CVC4 namespace */
diff --git a/src/main/interactive_shell.h b/src/main/interactive_shell.h
index 87845b0ed..4d60d3445 100644
--- a/src/main/interactive_shell.h
+++ b/src/main/interactive_shell.h
@@ -5,7 +5,7 @@
** Morgan Deters, Christopher L. Conway, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -35,6 +35,8 @@ namespace parser {
class Parser;
}/* CVC4::parser namespace */
+class SymbolManager;
+
class CVC4_PUBLIC InteractiveShell
{
const Options& d_options;
@@ -42,7 +44,7 @@ class CVC4_PUBLIC InteractiveShell
std::ostream& d_out;
parser::Parser* d_parser;
bool d_quit;
- bool d_usingReadline;
+ bool d_usingEditline;
std::string d_historyFilename;
@@ -50,7 +52,7 @@ class CVC4_PUBLIC InteractiveShell
static const unsigned s_historyLimit = 500;
public:
- InteractiveShell(api::Solver* solver);
+ InteractiveShell(api::Solver* solver, SymbolManager* sm);
/**
* Close out the interactive session.
diff --git a/src/main/main.cpp b/src/main/main.cpp
index 9cf168392..e08898905 100644
--- a/src/main/main.cpp
+++ b/src/main/main.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Christopher L. Conway
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -32,7 +32,6 @@
#include "parser/parser.h"
#include "parser/parser_builder.h"
#include "parser/parser_exception.h"
-#include "smt/command.h"
#include "smt/smt_engine.h"
#include "util/result.h"
#include "util/statistics.h"
diff --git a/src/main/main.h b/src/main/main.h
index 6d321f05a..37916f769 100644
--- a/src/main/main.h
+++ b/src/main/main.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/main/signal_handlers.cpp b/src/main/signal_handlers.cpp
index 6f24dfc9b..ee66b906b 100644
--- a/src/main/signal_handlers.cpp
+++ b/src/main/signal_handlers.cpp
@@ -2,10 +2,10 @@
/*! \file signal_handlers.cpp
** \verbatim
** Top contributors (to current version):
- ** Morgan Deters, Andres Noetzli, Tim King
+ ** Morgan Deters, Andres Noetzli, Gereon Kremer
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/main/signal_handlers.h b/src/main/signal_handlers.h
index cc1917418..5eb3f24c7 100644
--- a/src/main/signal_handlers.h
+++ b/src/main/signal_handlers.h
@@ -5,7 +5,7 @@
** Gereon Kremer
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/main/time_limit.cpp b/src/main/time_limit.cpp
index fb07b5523..be506a518 100644
--- a/src/main/time_limit.cpp
+++ b/src/main/time_limit.cpp
@@ -5,7 +5,7 @@
** Gereon Kremer
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/main/time_limit.h b/src/main/time_limit.h
index 4da3e6845..22aaff8cd 100644
--- a/src/main/time_limit.h
+++ b/src/main/time_limit.h
@@ -5,7 +5,7 @@
** Gereon Kremer
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/CMakeLists.txt b/src/options/CMakeLists.txt
index 46bd17172..cd648955e 100644
--- a/src/options/CMakeLists.txt
+++ b/src/options/CMakeLists.txt
@@ -1,3 +1,13 @@
+#####################
+## CMakeLists.txt
+## Top contributors (to current version):
+## Mathias Preiner, Aina Niemetz, Andrew Reynolds
+## This file is part of the CVC4 project.
+## Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+## in the top-level source directory and their institutional affiliations.
+## All rights reserved. See the file COPYING in the top-level source
+## directory for licensing information.
+##
# Check if the toml Python module is installed.
execute_process(
COMMAND
@@ -26,6 +36,7 @@ libcvc4_add_sources(
options.h
options_handler.cpp
options_handler.h
+ options_listener.h
options_public_functions.cpp
printer_modes.cpp
printer_modes.h
diff --git a/src/options/arith_options.toml b/src/options/arith_options.toml
index a6c967dc9..20ae73fce 100644
--- a/src/options/arith_options.toml
+++ b/src/options/arith_options.toml
@@ -433,7 +433,6 @@ header = "options/arith_options.h"
long = "nl-ext"
type = "bool"
default = "true"
- read_only = true
help = "incremental linearization approach to non-linear"
[[option]]
@@ -460,7 +459,6 @@ header = "options/arith_options.h"
long = "nl-ext-tplanes"
type = "bool"
default = "false"
- read_only = true
help = "use non-terminating tangent plane strategy for non-linear incremental linearization solver"
[[option]]
@@ -534,6 +532,24 @@ header = "options/arith_options.h"
help = "whether to increment the precision for irrational function constraints"
[[option]]
+ name = "nlRlvMode"
+ category = "regular"
+ long = "nl-rlv=MODE"
+ type = "NlRlvMode"
+ default = "NONE"
+ help = "choose mode for using relevance of assertoins in non-linear arithmetic"
+ help_mode = "Modes for using relevance of assertoins in non-linear arithmetic."
+[[option.mode.NONE]]
+ name = "none"
+ help = "Do not use relevance."
+[[option.mode.INTERLEAVE]]
+ name = "interleave"
+ help = "Alternate rounds using relevance."
+[[option.mode.ALWAYS]]
+ name = "always"
+ help = "Always use relevance."
+
+[[option]]
name = "brabTest"
category = "regular"
long = "arith-brab"
@@ -541,3 +557,28 @@ header = "options/arith_options.h"
default = "true"
read_only = true
help = "whether to use simple rounding, similar to a unit-cube test, for integers"
+
+[[option]]
+ name = "nlCad"
+ category = "regular"
+ long = "nl-cad"
+ type = "bool"
+ default = "false"
+ help = "whether to use the cylindrical algebraic decomposition solver for non-linear arithmetic"
+
+[[option]]
+ name = "nlCadUseInitial"
+ category = "regular"
+ long = "nl-cad-initial"
+ type = "bool"
+ default = "false"
+ help = "whether to use the linear model as initial guess for the cylindrical algebraic decomposition solver"
+
+[[option]]
+ name = "nlICP"
+ category = "regular"
+ long = "nl-icp"
+ type = "bool"
+ default = "false"
+ help = "whether to use ICP-style propagations for non-linear arithmetic"
+
diff --git a/src/options/arrays_options.toml b/src/options/arrays_options.toml
index 389bb6e4c..309370163 100644
--- a/src/options/arrays_options.toml
+++ b/src/options/arrays_options.toml
@@ -11,14 +11,6 @@ header = "options/arrays_options.h"
help = "turn on optimization for linear array terms (see de Moura FMCAD 09 arrays paper)"
[[option]]
- name = "arraysLazyRIntro1"
- category = "regular"
- long = "arrays-lazy-rintro1"
- type = "bool"
- default = "true"
- help = "turn on optimization to only perform RIntro1 rule lazily (see Jovanovic/Barrett 2012: Being Careful with Theory Combination)"
-
-[[option]]
name = "arraysWeakEquivalence"
category = "regular"
long = "arrays-weak-equiv"
diff --git a/src/options/base_handlers.h b/src/options/base_handlers.h
index ba14e49a1..4f73e0373 100644
--- a/src/options/base_handlers.h
+++ b/src/options/base_handlers.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/base_options.toml b/src/options/base_options.toml
index 65eeda3ae..cab4332b8 100644
--- a/src/options/base_options.toml
+++ b/src/options/base_options.toml
@@ -151,6 +151,5 @@ header = "options/base_options.h"
category = "regular"
long = "print-success"
type = "bool"
- notifies = ["notifyPrintSuccess"]
read_only = true
help = "print the \"success\" output required of SMT-LIBv2"
diff --git a/src/options/bv_options.toml b/src/options/bv_options.toml
index f7ec33f75..42401268d 100644
--- a/src/options/bv_options.toml
+++ b/src/options/bv_options.toml
@@ -3,44 +3,6 @@ name = "Bitvector theory"
header = "options/bv_options.h"
[[option]]
- name = "bvProofFormat"
- category = "expert"
- long = "bv-proof-format=MODE"
- type = "BvProofFormat"
- default = "ER"
- predicates = ["checkSatSolverEnabled<BvProofFormat>"]
- help = "choose which UNSAT proof format to use, see --bv-sat-solver=help"
- help_mode = "Bit-vector proof formats."
-[[option.mode.ER]]
- name = "er"
- help = "Extended Resolution, i.e. resolution with new variable definitions."
-[[option.mode.DRAT]]
- name = "drat"
- help = "Deletion and Resolution Asymmetric Tautology Additions."
-[[option.mode.LRAT]]
- name = "lrat"
- help = "DRAT with unit propagation hints to accelerate checking."
-
-[[option]]
- name = "bvOptimizeSatProof"
- category = "expert"
- long = "bv-optimize-sat-proof=MODE"
- type = "BvOptimizeSatProof"
- default = "FORMULA"
- predicates = ["checkSatSolverEnabled<BvOptimizeSatProof>"]
- help = "enable SAT proof optimizations, see --bv-optimize-sat-proof=help"
- help_mode = "SAT proof optimization level."
-[[option.mode.NONE]]
- name = "none"
- help = "Do not optimize the SAT proof."
-[[option.mode.PROOF]]
- name = "proof"
- help = "Use drat-trim to shrink the SAT proof."
-[[option.mode.FORMULA]]
- name = "formula"
- help = "Use drat-trim to shrink the SAT proof and formula."
-
-[[option]]
name = "bvSatSolver"
smt_name = "bv-sat-solver"
category = "expert"
@@ -109,24 +71,6 @@ header = "options/bv_options.h"
help = "use the equality engine for the bit-vector theory (only if --bitblast=lazy)"
[[option]]
- name = "bitvectorEqualitySlicer"
- category = "regular"
- long = "bv-eq-slicer=MODE"
- type = "BvSlicerMode"
- default = "OFF"
- help = "turn on the slicing equality solver for the bit-vector theory (only if --bitblast=lazy)"
- help_mode = "Bit-vector equality slicer modes."
-[[option.mode.ON]]
- name = "on"
- help = "Turn slicer on."
-[[option.mode.OFF]]
- name = "off"
- help = "Turn slicer off."
-[[option.mode.AUTO]]
- name = "auto"
- help = "Turn slicer on if input has only equalities over core symbols."
-
-[[option]]
name = "bitvectorInequalitySolver"
category = "regular"
long = "bv-inequality-solver"
@@ -190,7 +134,7 @@ header = "options/bv_options.h"
category = "regular"
long = "bv-div-zero-const"
type = "bool"
- default = "false"
+ default = "true"
help = "always return -1 on division by zero"
[[option]]
@@ -291,3 +235,19 @@ header = "options/bv_options.h"
type = "bool"
default = "false"
help = "print bit-vector constants in decimal (e.g. (_ bv1 4)) instead of binary (e.g. #b0001), applies to SMT-LIB 2.x"
+
+[[option]]
+ name = "bvSolver"
+ category = "regular"
+ long = "bv-solver=MODE"
+ type = "BVSolver"
+ default = "LAZY"
+ help = "choose bit-vector solver, see --bv-solver=help"
+ help_mode = "Bit-vector solvers."
+[[option.mode.LAZY]]
+ name = "lazy"
+ help = "Enables the lazy BV solver infrastructure."
+[[option.mode.SIMPLE]]
+ name = "simple"
+ help = "Enables simple bitblasting solver with proof support."
+
diff --git a/src/options/decision_weight.h b/src/options/decision_weight.h
index 3fc7f037f..33f9d99c5 100644
--- a/src/options/decision_weight.h
+++ b/src/options/decision_weight.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Kshitij Bansal
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/didyoumean.cpp b/src/options/didyoumean.cpp
index a420beb37..76ac9f0c7 100644
--- a/src/options/didyoumean.cpp
+++ b/src/options/didyoumean.cpp
@@ -5,7 +5,7 @@
** Kshitij Bansal, Tim King, Clark Barrett
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/didyoumean.h b/src/options/didyoumean.h
index abace1352..b8f0c4f3a 100644
--- a/src/options/didyoumean.h
+++ b/src/options/didyoumean.h
@@ -5,7 +5,7 @@
** Kshitij Bansal, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/didyoumean_test.cpp b/src/options/didyoumean_test.cpp
index 8ff0a5847..0e72b73ed 100644
--- a/src/options/didyoumean_test.cpp
+++ b/src/options/didyoumean_test.cpp
@@ -5,7 +5,7 @@
** Kshitij Bansal, Tim King, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/expr_options.toml b/src/options/expr_options.toml
index 5f70aee43..368fb34e4 100644
--- a/src/options/expr_options.toml
+++ b/src/options/expr_options.toml
@@ -9,7 +9,6 @@ header = "options/expr_options.h"
type = "int"
default = "0"
predicates = ["setDefaultExprDepthPredicate"]
- notifies = ["notifySetDefaultExprDepth"]
read_only = true
help = "print exprs to depth N (0 == default, -1 == no limit)"
@@ -21,21 +20,10 @@ header = "options/expr_options.h"
type = "int"
default = "1"
predicates = ["setDefaultDagThreshPredicate"]
- notifies = ["notifySetDefaultDagThresh"]
read_only = true
help = "dagify common subexprs appearing > N times (1 == default, 0 == don't dagify)"
[[option]]
- name = "printExprTypes"
- category = "regular"
- long = "print-expr-types"
- type = "bool"
- default = "false"
- notifies = ["notifySetPrintExprTypes"]
- read_only = true
- help = "print types with variables when printing exprs"
-
-[[option]]
name = "typeChecking"
category = "regular"
long = "type-checking"
diff --git a/src/options/language.cpp b/src/options/language.cpp
index b00d5c102..c2eb13852 100644
--- a/src/options/language.cpp
+++ b/src/options/language.cpp
@@ -2,10 +2,10 @@
/*! \file language.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Morgan Deters, Andres Noetzli
+ ** Morgan Deters, Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -181,9 +181,8 @@ InputLanguage toInputLanguage(std::string language) {
return input::LANG_SMTLIB_V2_6;
} else if(language == "tptp" || language == "LANG_TPTP") {
return input::LANG_TPTP;
- }
- else if (language == "sygus2" || language == "LANG_SYGUS_V2")
- {
+ } else if(language == "sygus" || language == "sygus2" ||
+ language == "LANG_SYGUS" || language == "LANG_SYGUS_V2") {
return input::LANG_SYGUS_V2;
}
else if (language == "auto" || language == "LANG_AUTO")
diff --git a/src/options/language.h b/src/options/language.h
index 0a0f63ca6..b34ac378e 100644
--- a/src/options/language.h
+++ b/src/options/language.h
@@ -5,7 +5,7 @@
** Morgan Deters, Andrew Reynolds, Francois Bobot
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/mkoptions.py b/src/options/mkoptions.py
index 3f00204fb..08f54f608 100755..100644
--- a/src/options/mkoptions.py
+++ b/src/options/mkoptions.py
@@ -1,4 +1,14 @@
#!/usr/bin/env python
+#####################
+## mkoptions.py
+## Top contributors (to current version):
+## Mathias Preiner
+## This file is part of the CVC4 project.
+## Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+## in the top-level source directory and their institutional affiliations.
+## All rights reserved. See the file COPYING in the top-level source
+## directory for licensing information.
+##
"""
Generate option handling code and documentation in one pass. The generated
files are only written to the destination file if the contents of the file
diff --git a/src/options/module_template.cpp b/src/options/module_template.cpp
index f0b4210d3..2ef8bf67e 100644
--- a/src/options/module_template.cpp
+++ b/src/options/module_template.cpp
@@ -5,7 +5,7 @@
** Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/module_template.h b/src/options/module_template.h
index 4aa44d866..325df5362 100644
--- a/src/options/module_template.h
+++ b/src/options/module_template.h
@@ -5,7 +5,7 @@
** Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/open_ostream.cpp b/src/options/open_ostream.cpp
index b5ffe8eeb..4d54f9cb1 100644
--- a/src/options/open_ostream.cpp
+++ b/src/options/open_ostream.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/open_ostream.h b/src/options/open_ostream.h
index 883743960..6b6a1afb7 100644
--- a/src/options/open_ostream.h
+++ b/src/options/open_ostream.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/option_exception.cpp b/src/options/option_exception.cpp
index 17ae41dc2..31fd57fa6 100644
--- a/src/options/option_exception.cpp
+++ b/src/options/option_exception.cpp
@@ -5,7 +5,7 @@
** Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/option_exception.h b/src/options/option_exception.h
index c5b116cda..a637722c7 100644
--- a/src/options/option_exception.h
+++ b/src/options/option_exception.h
@@ -5,7 +5,7 @@
** Morgan Deters, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/options.h b/src/options/options.h
index 0732d4ddb..b0dca5748 100644
--- a/src/options/options.h
+++ b/src/options/options.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Paul Meng
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -40,6 +40,8 @@ namespace options {
class OptionsHandler;
}/* CVC4::options namespace */
+class OptionsListener;
+
class CVC4_PUBLIC Options {
friend api::Solver;
/** The struct that holds all option values. */
@@ -51,36 +53,6 @@ class CVC4_PUBLIC Options {
/** The current Options in effect */
static thread_local Options* s_current;
- /** Listeners for notifyBeforeSearch. */
- ListenerCollection d_beforeSearchListeners;
-
- /** Listeners for options::defaultExprDepth. */
- ListenerCollection d_setDefaultExprDepthListeners;
-
- /** Listeners for options::defaultDagThresh. */
- ListenerCollection d_setDefaultDagThreshListeners;
-
- /** Listeners for options::printExprTypes. */
- ListenerCollection d_setPrintExprTypesListeners;
-
- /** Listeners for options::dumpModeString. */
- ListenerCollection d_setDumpModeListeners;
-
- /** Listeners for options::printSuccess. */
- ListenerCollection d_setPrintSuccessListeners;
-
- /** Listeners for options::dumpToFileName. */
- ListenerCollection d_dumpToFileListeners;
-
- /** Listeners for options::regularChannelName. */
- ListenerCollection d_setRegularChannelListeners;
-
- /** Listeners for options::diagnosticChannelName. */
- ListenerCollection d_setDiagnosticChannelListeners;
-
- static ListenerCollection::Registration* registerAndNotify(
- ListenerCollection& collection, Listener* listener, bool notify);
-
/** Low-level assignment function for options */
template <class T>
void assign(T, std::string option, std::string value);
@@ -132,7 +104,7 @@ public:
return s_current;
}
- Options();
+ Options(OptionsListener* ol = nullptr);
~Options();
/**
@@ -178,7 +150,6 @@ public:
options::InstFormatMode getInstFormatMode() const;
OutputLanguage getOutputLanguage() const;
bool getUfHo() const;
- bool getCheckProofs() const;
bool getDumpInstantiations() const;
bool getDumpModels() const;
bool getDumpProofs() const;
@@ -195,7 +166,6 @@ public:
bool getMemoryMap() const;
bool getParseOnly() const;
bool getProduceModels() const;
- bool getProof() const;
bool getSegvSpin() const;
bool getSemanticChecks() const;
bool getStatistics() const;
@@ -300,113 +270,8 @@ public:
*/
std::vector<std::vector<std::string> > getOptions() const;
- /**
- * Registers a listener for the notification, notifyBeforeSearch.
- *
- * The memory for the Registration is controlled by the user and must
- * be destroyed before the Options object is.
- *
- * This has multiple usages so having a notifyIfSet flag does not add
- * clarity. Users should check the relevant flags before registering this.
- */
- ListenerCollection::Registration* registerBeforeSearchListener(
- Listener* listener);
-
- /**
- * Registers a listener for options::defaultExprDepth being set.
- *
- * If notifyIfSet is true, this calls notify on the listener
- * if the option was set by the user.
- *
- * The memory for the Registration is controlled by the user and must
- * be destroyed before the Options object is.
- */
- ListenerCollection::Registration* registerSetDefaultExprDepthListener(
- Listener* listener, bool notifyIfSet);
-
- /**
- * Registers a listener for options::defaultDagThresh being set.
- *
- * If notifyIfSet is true, this calls notify on the listener
- * if the option was set by the user.
- *
- * The memory for the Registration is controlled by the user and must
- * be destroyed before the Options object is.
- */
- ListenerCollection::Registration* registerSetDefaultExprDagListener(
- Listener* listener, bool notifyIfSet);
-
- /**
- * Registers a listener for options::printExprTypes being set.
- *
- * If notifyIfSet is true, this calls notify on the listener
- * if the option was set by the user.
- *
- * The memory for the Registration is controlled by the user and must
- * be destroyed before the Options object is.
- */
- ListenerCollection::Registration* registerSetPrintExprTypesListener(
- Listener* listener, bool notifyIfSet);
-
- /**
- * Registers a listener for options::dumpModeString being set.
- *
- * If notifyIfSet is true, this calls notify on the listener
- * if the option was set by the user.
- *
- * The memory for the Registration is controlled by the user and must
- * be destroyed before the Options object is.
- */
- ListenerCollection::Registration* registerSetDumpModeListener(
- Listener* listener, bool notifyIfSet);
-
- /**
- * Registers a listener for options::printSuccess being set.
- *
- * If notifyIfSet is true, this calls notify on the listener
- * if the option was set by the user.
- *
- * The memory for the Registration is controlled by the user and must
- * be destroyed before the Options object is.
- */
- ListenerCollection::Registration* registerSetPrintSuccessListener(
- Listener* listener, bool notifyIfSet);
-
- /**
- * Registers a listener for options::dumpToFileName being set.
- *
- * If notifyIfSet is true, this calls notify on the listener
- * if the option was set by the user.
- *
- * The memory for the Registration is controlled by the user and must
- * be destroyed before the Options object is.
- */
- ListenerCollection::Registration* registerDumpToFileNameListener(
- Listener* listener, bool notifyIfSet);
-
- /**
- * Registers a listener for options::regularChannelName being set.
- *
- * If notifyIfSet is true, this calls notify on the listener
- * if the option was set by the user.
- *
- * The memory for the Registration is controlled by the user and must
- * be destroyed before the Options object is.
- */
- ListenerCollection::Registration* registerSetRegularOutputChannelListener(
- Listener* listener, bool notifyIfSet);
-
- /**
- * Registers a listener for options::diagnosticChannelName being set.
- *
- * If notifyIfSet is true, this calls notify on the listener
- * if the option was set by the user.
- *
- * The memory for the Registration is controlled by the user and must
- * be destroyed before the Options object is.
- */
- ListenerCollection::Registration* registerSetDiagnosticOutputChannelListener(
- Listener* listener, bool notifyIfSet);
+ /** Set the generic listener associated with this class to ol */
+ void setListener(OptionsListener* ol);
/** Sends a std::flush to getErr(). */
void flushErr();
@@ -415,6 +280,13 @@ public:
void flushOut();
private:
+ /** Pointer to the options listener, if one exists */
+ OptionsListener* d_olisten;
+ /**
+ * Helper method for setOption, updates this object for setting the given
+ * option.
+ */
+ void setOptionInternal(const std::string& key, const std::string& optionarg);
/**
* Internal procedure for implementing the parseOptions function.
* Initializes the options object based on the given command-line
diff --git a/src/options/options_handler.cpp b/src/options/options_handler.cpp
index dd5265777..fe37e9363 100644
--- a/src/options/options_handler.cpp
+++ b/src/options/options_handler.cpp
@@ -2,10 +2,10 @@
/*! \file options_handler.cpp
** \verbatim
** Top contributors (to current version):
- ** Tim King, Aina Niemetz, Mathias Preiner
+ ** Aina Niemetz, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -69,17 +69,6 @@ void throwLazyBBUnsupported(options::SatSolverMode m)
OptionsHandler::OptionsHandler(Options* options) : d_options(options) { }
-void OptionsHandler::notifyBeforeSearch(const std::string& option)
-{
- try{
- d_options->d_beforeSearchListeners.notify();
- } catch (ModalException&){
- std::stringstream ss;
- ss << "cannot change option `" << option << "' after final initialization";
- throw ModalException(ss.str());
- }
-}
-
unsigned long OptionsHandler::limitHandler(std::string option,
std::string optarg)
{
@@ -92,12 +81,6 @@ unsigned long OptionsHandler::limitHandler(std::string option,
}
return ms;
}
-
-/* options/base_options_handlers.h */
-void OptionsHandler::notifyPrintSuccess(std::string option) {
- d_options->d_setPrintSuccessListeners.notify();
-}
-
// theory/quantifiers/options_handlers.h
void OptionsHandler::checkInstWhenMode(std::string option, InstWhenMode mode)
@@ -189,17 +172,6 @@ void OptionsHandler::checkBitblastMode(std::string option, BitblastMode m)
{
options::bitvectorEqualitySolver.set(true);
}
- if (!options::bitvectorEqualitySlicer.wasSetByUser())
- {
- if (options::incrementalSolving() || options::produceModels())
- {
- options::bitvectorEqualitySlicer.set(options::BvSlicerMode::OFF);
- }
- else
- {
- options::bitvectorEqualitySlicer.set(options::BvSlicerMode::AUTO);
- }
- }
if (!options::bitvectorInequalitySolver.wasSetByUser())
{
@@ -310,19 +282,6 @@ void OptionsHandler::LFSCEnabledBuild(std::string option, bool value) {
#endif /* CVC4_USE_LFSC */
}
-void OptionsHandler::notifyDumpToFile(std::string option) {
- d_options->d_dumpToFileListeners.notify();
-}
-
-
-void OptionsHandler::notifySetRegularOutputChannel(std::string option) {
- d_options->d_setRegularChannelListeners.notify();
-}
-
-void OptionsHandler::notifySetDiagnosticOutputChannel(std::string option) {
- d_options->d_setDiagnosticChannelListeners.notify();
-}
-
void OptionsHandler::statsEnabledBuild(std::string option, bool value)
{
#ifndef CVC4_STATISTICS_ON
@@ -338,12 +297,6 @@ void OptionsHandler::threadN(std::string option) {
throw OptionException(option + " is not a real option by itself. Use e.g. --thread0=\"--random-seed=10 --random-freq=0.02\" --thread1=\"--random-seed=20 --random-freq=0.05\"");
}
-void OptionsHandler::notifyDumpMode(std::string option)
-{
- d_options->d_setDumpModeListeners.notify();
-}
-
-
// expr/options_handlers.h
void OptionsHandler::setDefaultExprDepthPredicate(std::string option, int depth) {
if(depth < -1) {
@@ -357,19 +310,6 @@ void OptionsHandler::setDefaultDagThreshPredicate(std::string option, int dag) {
}
}
-void OptionsHandler::notifySetDefaultExprDepth(std::string option) {
- d_options->d_setDefaultExprDepthListeners.notify();
-}
-
-void OptionsHandler::notifySetDefaultDagThresh(std::string option) {
- d_options->d_setDefaultDagThreshListeners.notify();
-}
-
-void OptionsHandler::notifySetPrintExprTypes(std::string option) {
- d_options->d_setPrintExprTypesListeners.notify();
-}
-
-
// main/options_handlers.h
static void print_config (const char * str, std::string config) {
@@ -442,7 +382,8 @@ void OptionsHandler::showConfiguration(std::string option) {
print_config_cond("gmp", Configuration::isBuiltWithGmp());
print_config_cond("kissat", Configuration::isBuiltWithKissat());
print_config_cond("lfsc", Configuration::isBuiltWithLfsc());
- print_config_cond("readline", Configuration::isBuiltWithReadline());
+ print_config_cond("poly", Configuration::isBuiltWithPoly());
+ print_config_cond("editline", Configuration::isBuiltWithEditline());
print_config_cond("symfpu", Configuration::isBuiltWithSymFPU());
exit(0);
@@ -586,7 +527,7 @@ InputLanguage OptionsHandler::stringToInputLanguage(std::string option,
try {
return language::toInputLanguage(optarg);
} catch(OptionException& oe) {
- throw OptionException("Error in " + option + ": " + oe.getMessage() + "\nTry --language help");
+ throw OptionException("Error in " + option + ": " + oe.getMessage() + "\nTry --lang help");
}
Unreachable();
diff --git a/src/options/options_handler.h b/src/options/options_handler.h
index 876edfad7..07e629976 100644
--- a/src/options/options_handler.h
+++ b/src/options/options_handler.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -84,14 +84,9 @@ public:
* Throws a ModalException if this option is being set after final
* initialization.
*/
- void notifyBeforeSearch(const std::string& option);
- void notifyDumpMode(std::string option);
void setProduceAssertions(std::string option, bool value);
void proofEnabledBuild(std::string option, bool value);
void LFSCEnabledBuild(std::string option, bool value);
- void notifyDumpToFile(std::string option);
- void notifySetRegularOutputChannel(std::string option);
- void notifySetDiagnosticOutputChannel(std::string option);
void statsEnabledBuild(std::string option, bool value);
@@ -100,9 +95,6 @@ public:
/* expr/options_handlers.h */
void setDefaultExprDepthPredicate(std::string option, int depth);
void setDefaultDagThreshPredicate(std::string option, int dag);
- void notifySetDefaultExprDepth(std::string option);
- void notifySetDefaultDagThresh(std::string option);
- void notifySetPrintExprTypes(std::string option);
/* main/options_handlers.h */
void copyright(std::string option);
@@ -119,7 +111,6 @@ public:
InputLanguage stringToInputLanguage(std::string option, std::string optarg);
void enableTraceTag(std::string option, std::string optarg);
void enableDebugTag(std::string option, std::string optarg);
- void notifyPrintSuccess(std::string option);
private:
diff --git a/src/options/options_holder_template.h b/src/options/options_holder_template.h
index caaefdaa4..03ff21dc0 100644
--- a/src/options/options_holder_template.h
+++ b/src/options/options_holder_template.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/options_listener.h b/src/options/options_listener.h
new file mode 100644
index 000000000..f53a96b05
--- /dev/null
+++ b/src/options/options_listener.h
@@ -0,0 +1,37 @@
+/********************* */
+/*! \file options_listener.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Base class for option listener
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__OPTIONS__OPTIONS_LISTENER_H
+#define CVC4__OPTIONS__OPTIONS_LISTENER_H
+
+#include <string>
+
+namespace CVC4 {
+
+class OptionsListener
+{
+ public:
+ OptionsListener() {}
+ virtual ~OptionsListener() {}
+ /**
+ * Notify that option key has been set.
+ */
+ virtual void notifySetOption(const std::string& key) = 0;
+};
+
+} // namespace CVC4
+
+#endif /* CVC4__OPTIONS__OPTION_LISTENER_H */
diff --git a/src/options/options_public_functions.cpp b/src/options/options_public_functions.cpp
index c8104c584..4043365b9 100644
--- a/src/options/options_public_functions.cpp
+++ b/src/options/options_public_functions.cpp
@@ -2,10 +2,10 @@
/*! \file options_public_functions.cpp
** \verbatim
** Top contributors (to current version):
- ** Tim King, Andrew Reynolds, Mathias Preiner
+ ** Tim King, Andrew Reynolds, Gereon Kremer
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -54,10 +54,6 @@ OutputLanguage Options::getOutputLanguage() const {
bool Options::getUfHo() const { return (*this)[options::ufHo]; }
-bool Options::getCheckProofs() const{
- return (*this)[options::checkProofs];
-}
-
bool Options::getDumpInstantiations() const{
return (*this)[options::dumpInstantiations];
}
@@ -124,10 +120,6 @@ bool Options::getProduceModels() const{
return (*this)[options::produceModels];
}
-bool Options::getProof() const{
- return (*this)[options::proof];
-}
-
bool Options::getSegvSpin() const{
return (*this)[options::segvSpin];
}
diff --git a/src/options/options_template.cpp b/src/options/options_template.cpp
index bf8926521..af74fd31e 100644
--- a/src/options/options_template.cpp
+++ b/src/options/options_template.cpp
@@ -2,10 +2,10 @@
/*! \file options_template.cpp
** \verbatim
** Top contributors (to current version):
- ** Morgan Deters, Tim King, Mathias Preiner
+ ** Morgan Deters, Tim King, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -36,7 +36,6 @@ extern int optreset;
#include <unistd.h>
#include <string.h>
-#include <stdint.h>
#include <time.h>
#include <cstdio>
@@ -54,6 +53,7 @@ extern int optreset;
#include "options/didyoumean.h"
#include "options/language.h"
#include "options/options_handler.h"
+#include "options/options_listener.h"
${headers_module}$
@@ -223,11 +223,10 @@ void runBoolPredicates(T, std::string option, bool b, options::OptionsHandler* h
// that can throw exceptions.
}
-
-Options::Options()
- : d_holder(new options::OptionsHolder())
- , d_handler(new options::OptionsHandler(this))
- , d_beforeSearchListeners()
+Options::Options(OptionsListener* ol)
+ : d_holder(new options::OptionsHolder()),
+ d_handler(new options::OptionsHandler(this)),
+ d_olisten(ol)
{}
Options::~Options() {
@@ -250,93 +249,7 @@ std::string Options::formatThreadOptionException(const std::string& option) {
return ss.str();
}
-ListenerCollection::Registration* Options::registerAndNotify(
- ListenerCollection& collection, Listener* listener, bool notify)
-{
- ListenerCollection::Registration* registration =
- collection.registerListener(listener);
- if(notify) {
- try
- {
- listener->notify();
- }
- catch (OptionException& e)
- {
- // It can happen that listener->notify() throws an OptionException. In
- // that case, we have to make sure that we delete the registration of our
- // listener before rethrowing the exception. Otherwise the
- // ListenerCollection deconstructor will complain that not all
- // registrations have been removed before invoking the deconstructor.
- delete registration;
- throw OptionException(e.getRawMessage());
- }
- }
- return registration;
-}
-
-ListenerCollection::Registration* Options::registerBeforeSearchListener(
- Listener* listener)
-{
- return d_beforeSearchListeners.registerListener(listener);
-}
-
-ListenerCollection::Registration* Options::registerSetDefaultExprDepthListener(
- Listener* listener, bool notifyIfSet)
-{
- bool notify = notifyIfSet && wasSetByUser(options::defaultExprDepth);
- return registerAndNotify(d_setDefaultExprDepthListeners, listener, notify);
-}
-
-ListenerCollection::Registration* Options::registerSetDefaultExprDagListener(
- Listener* listener, bool notifyIfSet)
-{
- bool notify = notifyIfSet && wasSetByUser(options::defaultDagThresh);
- return registerAndNotify(d_setDefaultDagThreshListeners, listener, notify);
-}
-
-ListenerCollection::Registration* Options::registerSetPrintExprTypesListener(
- Listener* listener, bool notifyIfSet)
-{
- bool notify = notifyIfSet && wasSetByUser(options::printExprTypes);
- return registerAndNotify(d_setPrintExprTypesListeners, listener, notify);
-}
-
-ListenerCollection::Registration* Options::registerSetDumpModeListener(
- Listener* listener, bool notifyIfSet)
-{
- bool notify = notifyIfSet && wasSetByUser(options::dumpModeString);
- return registerAndNotify(d_setDumpModeListeners, listener, notify);
-}
-
-ListenerCollection::Registration* Options::registerSetPrintSuccessListener(
- Listener* listener, bool notifyIfSet)
-{
- bool notify = notifyIfSet && wasSetByUser(options::printSuccess);
- return registerAndNotify(d_setPrintSuccessListeners, listener, notify);
-}
-
-ListenerCollection::Registration* Options::registerDumpToFileNameListener(
- Listener* listener, bool notifyIfSet)
-{
- bool notify = notifyIfSet && wasSetByUser(options::dumpToFileName);
- return registerAndNotify(d_dumpToFileListeners, listener, notify);
-}
-
-ListenerCollection::Registration*
-Options::registerSetRegularOutputChannelListener(
- Listener* listener, bool notifyIfSet)
-{
- bool notify = notifyIfSet && wasSetByUser(options::regularChannelName);
- return registerAndNotify(d_setRegularChannelListeners, listener, notify);
-}
-
-ListenerCollection::Registration*
-Options::registerSetDiagnosticOutputChannelListener(
- Listener* listener, bool notifyIfSet)
-{
- bool notify = notifyIfSet && wasSetByUser(options::diagnosticChannelName);
- return registerAndNotify(d_setDiagnosticChannelListeners, listener, notify);
-}
+void Options::setListener(OptionsListener* ol) { d_olisten = ol; }
${custom_handlers}$
@@ -493,7 +406,6 @@ std::vector<std::string> Options::parseOptions(Options* options,
}
options->d_holder->binary_name = std::string(progName);
-
std::vector<std::string> nonoptions;
parseOptionsRecursive(options, argc, argv, &nonoptions);
if(Debug.isOn("options")){
@@ -662,24 +574,31 @@ std::vector<std::vector<std::string> > Options::getOptions() const
void Options::setOption(const std::string& key, const std::string& optionarg)
{
- options::OptionsHandler* handler = d_handler;
- Options* options = this;
- Trace("options") << "SMT setOption(" << key << ", " << optionarg << ")"
+ Trace("options") << "setOption(" << key << ", " << optionarg << ")"
<< std::endl;
+ // first update this object
+ setOptionInternal(key, optionarg);
+ // then, notify the provided listener
+ if (d_olisten != nullptr)
+ {
+ d_olisten->notifySetOption(key);
+ }
+}
+void Options::setOptionInternal(const std::string& key,
+ const std::string& optionarg)
+{
+ options::OptionsHandler* handler = d_handler;
+ Options* options = this;
${setoption_handlers}$
-
-
throw UnrecognizedOptionException(key);
}
std::string Options::getOption(const std::string& key) const
{
- Trace("options") << "SMT getOption(" << key << ")" << std::endl;
-
+ Trace("options") << "Options::getOption(" << key << ")" << std::endl;
${getoption_handlers}$
-
throw UnrecognizedOptionException(key);
}
diff --git a/src/options/printer_modes.cpp b/src/options/printer_modes.cpp
index 0bd770c67..22b61f3a4 100644
--- a/src/options/printer_modes.cpp
+++ b/src/options/printer_modes.cpp
@@ -5,7 +5,7 @@
** Mathias Preiner, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/printer_modes.h b/src/options/printer_modes.h
index b743b821b..9d403857d 100644
--- a/src/options/printer_modes.h
+++ b/src/options/printer_modes.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/proof_options.toml b/src/options/proof_options.toml
index a23241e3d..9db541e27 100644
--- a/src/options/proof_options.toml
+++ b/src/options/proof_options.toml
@@ -1,38 +1,3 @@
id = "PROOF"
name = "Proof"
header = "options/proof_options.h"
-
-[[option]]
- name = "lfscLetification"
- category = "regular"
- long = "lfsc-letification"
- type = "bool"
- default = "true"
- read_only = true
- help = "turns on global letification in LFSC proofs"
-
-[[option]]
- name = "aggressiveCoreMin"
- category = "regular"
- long = "aggressive-core-min"
- type = "bool"
- default = "false"
- read_only = true
- help = "turns on aggressive unsat core minimization (experimental)"
-
-[[option]]
- name = "fewerPreprocessingHoles"
- category = "regular"
- long = "fewer-preprocessing-holes"
- type = "bool"
- default = "false"
- help = "try to eliminate preprocessing holes in proofs"
-
-[[option]]
- name = "allowEmptyDependencies"
- category = "regular"
- long = "allow-empty-dependencies"
- type = "bool"
- default = "false"
- read_only = true
- help = "if unable to track the dependencies of a rewritten/preprocessed assertion, fail silently"
diff --git a/src/options/quantifiers_options.toml b/src/options/quantifiers_options.toml
index b62468cdd..d29052042 100644
--- a/src/options/quantifiers_options.toml
+++ b/src/options/quantifiers_options.toml
@@ -493,15 +493,6 @@ header = "options/quantifiers_options.h"
help = "allow theory combination to happen once initially, before quantifier strategies are run"
[[option]]
- name = "quantModelEe"
- category = "regular"
- long = "quant-model-ee"
- type = "bool"
- default = "false"
- read_only = true
- help = "use equality engine of model for last call effort"
-
-[[option]]
name = "instMaxLevel"
category = "regular"
long = "inst-max-level=N"
@@ -824,14 +815,6 @@ header = "options/quantifiers_options.h"
help = "do not consider instances of quantified formulas that are currently entailed"
[[option]]
- name = "instNoModelTrue"
- category = "regular"
- long = "inst-no-model-true"
- type = "bool"
- default = "false"
- help = "do not consider instances of quantified formulas that are currently true in model, if it is available"
-
-[[option]]
name = "qcfEagerTest"
category = "regular"
long = "qcf-eager-test"
@@ -1328,14 +1311,6 @@ header = "options/quantifiers_options.h"
help = "enumerate a stream of solutions instead of terminating after the first one"
[[option]]
- name = "sygusVerifySubcall"
- category = "regular"
- long = "sygus-verify-subcall"
- type = "bool"
- default = "true"
- help = "use separate copy of the SMT solver for verification lemmas in sygus"
-
-[[option]]
name = "sygusExtRew"
category = "regular"
long = "sygus-ext-rew"
@@ -2012,3 +1987,57 @@ header = "options/quantifiers_options.h"
type = "bool"
default = "false"
help = "Enable SyGuS instantiation quantifiers module"
+
+[[option]]
+ name = "sygusInstScope"
+ category = "regular"
+ long = "sygus-inst-scope=MODE"
+ type = "SygusInstScope"
+ default = "IN"
+ help = "select scope of ground terms"
+ help_mode = "scope for collecting ground terms for the grammar."
+[[option.mode.IN]]
+ name = "in"
+ help = "use ground terms inside given quantified formula only."
+[[option.mode.OUT]]
+ name = "out"
+ help = "use ground terms outside of quantified formulas only."
+[[option.mode.BOTH]]
+ name = "both"
+ help = "combines inside and outside."
+
+[[option]]
+ name = "sygusInstTermSel"
+ category = "regular"
+ long = "sygus-inst-term-sel=MODE"
+ type = "SygusInstTermSelMode"
+ default = "MIN"
+ help = "granularity for ground terms"
+ help_mode = "Ground term selection modes."
+[[option.mode.MIN]]
+ name = "min"
+ help = "collect minimal ground terms only."
+[[option.mode.MAX]]
+ name = "max"
+ help = "collect maximal ground terms only."
+[[option.mode.BOTH]]
+ name = "both"
+ help = "combines minimal and maximal ."
+
+[[option]]
+ name = "sygusInstMode"
+ category = "regular"
+ long = "sygus-inst-mode=MODE"
+ type = "SygusInstMode"
+ default = "PRIORITY_INST"
+ help = "select instantiation lemma mode"
+ help_mode = "SyGuS instantiation lemma modes."
+[[option.mode.PRIORITY_INST]]
+ name = "priority-inst"
+ help = "add instantiation lemmas first, add evaluation unfolding if instantiation fails."
+[[option.mode.PRIORITY_EVAL]]
+ name = "priority-eval"
+ help = "add evaluation unfolding lemma first, add instantiation lemma if unfolding lemmas already added."
+[[option.mode.INTERLEAVE]]
+ name = "interleave"
+ help = "add instantiation and evaluation unfolding lemmas in the same step."
diff --git a/src/options/set_language.cpp b/src/options/set_language.cpp
index 042165194..d2888616c 100644
--- a/src/options/set_language.cpp
+++ b/src/options/set_language.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Kshitij Bansal
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/set_language.h b/src/options/set_language.h
index abd12f21b..a69278154 100644
--- a/src/options/set_language.h
+++ b/src/options/set_language.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/options/smt_options.toml b/src/options/smt_options.toml
index e4847716a..405abfc4f 100644
--- a/src/options/smt_options.toml
+++ b/src/options/smt_options.toml
@@ -8,7 +8,6 @@ header = "options/smt_options.h"
category = "common"
long = "dump=MODE"
type = "std::string"
- notifies = ["notifyDumpMode"]
read_only = true
help = "dump preprocessed assertions, etc., see --dump=help"
@@ -18,7 +17,6 @@ header = "options/smt_options.h"
category = "common"
long = "dump-to=FILE"
type = "std::string"
- notifies = ["notifyDumpToFile"]
read_only = true
help = "all dumping goes to FILE (instead of stdout)"
@@ -71,7 +69,6 @@ header = "options/smt_options.h"
long = "produce-models"
type = "bool"
default = "false"
- notifies = ["notifyBeforeSearch"]
help = "support the get-value and get-model commands"
[[option]]
@@ -79,7 +76,6 @@ header = "options/smt_options.h"
category = "regular"
long = "check-models"
type = "bool"
- notifies = ["notifyBeforeSearch"]
help = "after SAT/INVALID/UNKNOWN, check that the generated model satisfies user assertions"
[[option]]
@@ -87,7 +83,6 @@ header = "options/smt_options.h"
category = "regular"
long = "debug-check-models"
type = "bool"
- notifies = ["notifyBeforeSearch"]
help = "after SAT/INVALID/UNKNOWN, check that the generated model satisfies user and internal assertions"
[[option]]
@@ -136,26 +131,6 @@ header = "options/smt_options.h"
help = "Block models based on the concrete model values for the free variables."
[[option]]
- name = "proof"
- smt_name = "produce-proofs"
- category = "regular"
- long = "proof"
- type = "bool"
- default = "false"
- predicates = ["proofEnabledBuild"]
- notifies = ["notifyBeforeSearch"]
- help = "turn on proof generation"
-
-[[option]]
- name = "checkProofs"
- category = "regular"
- long = "check-proofs"
- type = "bool"
- predicates = ["LFSCEnabledBuild"]
- notifies = ["notifyBeforeSearch"]
- help = "after UNSAT/VALID, machine-check the generated proof"
-
-[[option]]
name = "dumpProofs"
category = "regular"
long = "dump-proofs"
@@ -175,11 +150,48 @@ header = "options/smt_options.h"
[[option]]
name = "proofNewPedantic"
category = "regular"
- long = "proof-new-pedantic"
+ long = "proof-new-pedantic=N"
+ type = "uint32_t"
+ default = "0"
+ read_only = true
+ help = "assertion failure for any incorrect rule application or untrusted lemma having pedantic level <=N with proof-new"
+
+[[option]]
+ name = "proofNewEagerChecking"
+ category = "regular"
+ long = "proof-new-eager-checking"
type = "bool"
default = "false"
read_only = true
- help = "assertion failure for any incorrect rule application or untrusted lemma for fully supported portions with proof-new"
+ help = "check proofs eagerly with proof-new for local debugging"
+
+[[option]]
+ name = "proofGranularityMode"
+ category = "regular"
+ long = "proof-granularity=MODE"
+ type = "ProofGranularityMode"
+ default = "THEORY_REWRITE"
+ help = "modes for proof granularity"
+ help_mode = "Modes for proof granularity."
+[[option.mode.OFF]]
+ name = "off"
+ help = "Do not improve the granularity of proofs."
+[[option.mode.REWRITE]]
+ name = "rewrite"
+ help = "allow rewrite or substitution steps, expand macros."
+[[option.mode.THEORY_REWRITE]]
+ name = "theory-rewrite"
+ help = "allow theory rewrite steps, expand macros, rewrite and substitution steps."
+[[option.mode.DSL_REWRITE]]
+ name = "dsl-rewrite"
+ help = "Allow DSL rewrites and evaluation steps, expand macros, rewrite, substitution, and theory rewrite steps."
+
+[[option]]
+ name = "checkProofsNew"
+ category = "regular"
+ long = "check-proofs-new"
+ type = "bool"
+ help = "after UNSAT/VALID, check the generated proof (with proof-new)"
[[option]]
name = "dumpInstantiations"
@@ -234,7 +246,6 @@ header = "options/smt_options.h"
long = "produce-unsat-cores"
type = "bool"
predicates = ["proofEnabledBuild"]
- notifies = ["notifyBeforeSearch"]
help = "turn on unsat core generation"
[[option]]
@@ -250,7 +261,6 @@ header = "options/smt_options.h"
long = "dump-unsat-cores"
type = "bool"
default = "false"
- notifies = ["notifyBeforeSearch"]
help = "output unsat cores after every UNSAT/VALID response"
[[option]]
@@ -259,7 +269,6 @@ header = "options/smt_options.h"
long = "dump-unsat-cores-full"
type = "bool"
default = "false"
- notifies = ["notifyBeforeSearch"]
read_only = true
help = "dump the full unsat core, including unlabeled assertions"
@@ -270,7 +279,6 @@ header = "options/smt_options.h"
type = "bool"
default = "false"
predicates = ["proofEnabledBuild"]
- notifies = ["notifyBeforeSearch"]
read_only = true
help = "turn on unsat assumptions generation"
@@ -288,7 +296,6 @@ header = "options/smt_options.h"
long = "produce-assignments"
type = "bool"
default = "false"
- notifies = ["notifyBeforeSearch"]
help = "support the get-assignment command"
[[option]]
@@ -297,7 +304,6 @@ header = "options/smt_options.h"
category = "undocumented"
type = "bool"
predicates = ["setProduceAssertions"]
- notifies = ["notifyBeforeSearch"]
help = "deprecated name for produce-assertions"
[[option]]
@@ -306,7 +312,6 @@ header = "options/smt_options.h"
long = "produce-assertions"
type = "bool"
predicates = ["setProduceAssertions"]
- notifies = ["notifyBeforeSearch"]
help = "keep an assertions list (enables get-assertions command)"
[[option]]
@@ -387,7 +392,7 @@ header = "options/smt_options.h"
type = "bool"
default = "false"
help = "calculate sort inference of input problem, convert the input based on monotonic sorts"
-
+
[[option]]
name = "incrementalSolving"
category = "common"
@@ -407,13 +412,24 @@ header = "options/smt_options.h"
help = "in models, output arrays (and in future, maybe others) using abstract values, as required by the SMT-LIB standard"
[[option]]
- name = "modelUninterpDtEnum"
+ name = "modelUninterpPrint"
+ smt_name = "model-uninterp-print"
category = "regular"
- long = "model-u-dt-enum"
- type = "bool"
- default = "false"
+ long = "model-u-print=MODE"
+ type = "ModelUninterpPrintMode"
+ default = "DeclFun"
read_only = true
- help = "in models, output uninterpreted sorts as datatype enumerations"
+ help = "determines how to print uninterpreted elements in models"
+ help_mode = "uninterpreted elements in models printing modes."
+[[option.mode.DtEnum]]
+ name = "dtenum"
+ help = "print uninterpreted elements as datatype enumerations, where the sort is the datatype"
+[[option.mode.DeclSortAndFun]]
+ name = "decl-sort-and-fun"
+ help = "print uninterpreted elements declare-fun, and also include a declare-sort for the sort"
+[[option.mode.DeclFun]]
+ name = "decl-fun"
+ help = "(default) print uninterpreted elements declare-fun, but don't include a declare-sort for the sort"
[[option]]
name = "modelWitnessValue"
@@ -429,7 +445,6 @@ header = "options/smt_options.h"
smt_name = "regular-output-channel"
category = "regular"
type = "std::string"
- notifies = ["notifySetRegularOutputChannel"]
read_only = true
help = "set the regular output channel of the solver"
@@ -438,7 +453,6 @@ header = "options/smt_options.h"
smt_name = "diagnostic-output-channel"
category = "regular"
type = "std::string"
- notifies = ["notifySetDiagnosticOutputChannel"]
read_only = true
help = "set the diagnostic output channel of the solver"
@@ -483,22 +497,22 @@ header = "options/smt_options.h"
help = "enable resource limiting per query"
[[option]]
- name = "hardLimit"
- category = "common"
- long = "hard-limit"
- type = "bool"
- default = "false"
+ name = "arithPivotStep"
+ category = "expert"
+ long = "arith-pivot-step=N"
+ type = "unsigned"
+ default = "1"
read_only = true
- help = "the resource limit is hard potentially leaving the smtEngine in an unsafe state (should be destroyed and rebuild after resourcing out)"
+ help = "amount of resources spent for each arithmetic pivot step"
[[option]]
- name = "cpuTime"
- category = "common"
- long = "cpu-time"
- type = "bool"
- default = "false"
+ name = "arithNlLemmaStep"
+ category = "expert"
+ long = "arith-nl-lemma-step=N"
+ type = "unsigned"
+ default = "1"
read_only = true
- help = "measures CPU time if set to true and wall time if false (default false)"
+ help = "amount of resources spent for each arithmetic nonlinear lemma step"
[[option]]
name = "rewriteStep"
@@ -573,6 +587,15 @@ header = "options/smt_options.h"
help = "amount of resources spent when adding lemmas"
[[option]]
+ name = "newSkolemStep"
+ category = "expert"
+ long = "new-skolem-step=N"
+ type = "unsigned"
+ default = "1"
+ read_only = true
+ help = "amount of resources spent when adding new skolems"
+
+[[option]]
name = "restartStep"
category = "expert"
long = "restart-step=N"
@@ -627,6 +650,24 @@ header = "options/smt_options.h"
help = "amount of resources spent for each sat conflict (bitvectors)"
[[option]]
+ name = "bvSatPropagateStep"
+ category = "expert"
+ long = "bv-sat-propagate-step=N"
+ type = "unsigned"
+ default = "1"
+ read_only = true
+ help = "amount of resources spent for each sat propagate (bitvectors)"
+
+[[option]]
+ name = "bvSatSimplifyStep"
+ category = "expert"
+ long = "bv-sat-simplify-step=N"
+ type = "unsigned"
+ default = "1"
+ read_only = true
+ help = "amount of resources spent for each sat simplify (bitvectors)"
+
+[[option]]
name = "forceNoLimitCpuWhileDump"
category = "regular"
long = "force-no-limit-cpu-while-dump"
@@ -649,6 +690,12 @@ header = "options/smt_options.h"
[[option.mode.SUM]]
name = "sum"
help = "Generate a sum expression for each bvand instance, based on the value in --solbv-bv-as-int-granularity"
+[[option.mode.IAND]]
+ name = "iand"
+ help = "Translate bvand to the iand operator (experimental)"
+[[option.mode.BV]]
+ name = "bv"
+ help = "Translate bvand back to bit-vectors"
[[option]]
name = "BVAndIntegerGranularity"
@@ -677,7 +724,7 @@ header = "options/smt_options.h"
[[option.mode.BITWISE]]
name = "bitwise"
help = "use bitwise comparisons on binary representation of integer for refinement (experimental)"
-
+
[[option]]
name = "solveIntAsBV"
category = "undocumented"
diff --git a/src/options/strings_options.toml b/src/options/strings_options.toml
index 32c4c64c7..f9893ef3a 100644
--- a/src/options/strings_options.toml
+++ b/src/options/strings_options.toml
@@ -205,3 +205,28 @@ header = "options/strings_options.h"
[[option.mode.NONE]]
name = "none"
help = "Do not compute intersections for regular expressions."
+
+[[option]]
+ name = "stringUnifiedVSpt"
+ category = "regular"
+ long = "strings-unified-vspt"
+ type = "bool"
+ default = "true"
+ read_only = true
+ help = "use a single skolem for the variable splitting rule"
+
+[[option]]
+ name = "stringLenConc"
+ category = "regular"
+ long = "strings-len-conc"
+ type = "bool"
+ default = "false"
+ help = "add skolem length constraints in conclusions of inferences"
+
+[[option]]
+ name = "stringEagerEval"
+ category = "regular"
+ long = "strings-eager-eval"
+ type = "bool"
+ default = "true"
+ help = "perform eager context-dependent evaluation for applications of string kinds"
diff --git a/src/options/theory_options.toml b/src/options/theory_options.toml
index 84c994c3f..388333124 100644
--- a/src/options/theory_options.toml
+++ b/src/options/theory_options.toml
@@ -34,3 +34,35 @@ header = "options/theory_options.h"
default = "true"
read_only = true
help = "condense values for functions in models rather than explicitly representing them"
+
+[[option]]
+ name = "relevanceFilter"
+ category = "regular"
+ long = "relevance-filter"
+ type = "bool"
+ default = "false"
+ help = "enable analysis of relevance of asserted literals with respect to the input formula"
+
+[[option]]
+ name = "eeMode"
+ category = "expert"
+ long = "ee-mode=MODE"
+ type = "EqEngineMode"
+ default = "DISTRIBUTED"
+ help = "mode for managing equalities across theory solvers"
+ help_mode = "Defines mode for managing equalities across theory solvers."
+[[option.mode.DISTRIBUTED]]
+ name = "distributed"
+ help = "Each theory maintains its own equality engine."
+
+[[option]]
+ name = "tcMode"
+ category = "expert"
+ long = "tc-mode=MODE"
+ type = "TcMode"
+ default = "CARE_GRAPH"
+ help = "mode for theory combination"
+ help_mode = "Defines mode for theory combination."
+[[option.mode.CARE_GRAPH]]
+ name = "care-graph"
+ help = "Use care graphs for theory combination."
diff --git a/src/options/uf_options.toml b/src/options/uf_options.toml
index 6916598ce..a098061f8 100644
--- a/src/options/uf_options.toml
+++ b/src/options/uf_options.toml
@@ -12,15 +12,6 @@ header = "options/uf_options.h"
help = "use UF symmetry breaker (Deharbe et al., CADE 2011)"
[[option]]
- name = "ufssTotality"
- category = "regular"
- long = "uf-ss-totality"
- type = "bool"
- default = "false"
- read_only = true
- help = "always use totality axioms for enforcing cardinality constraints"
-
-[[option]]
name = "ufssTotalityLimited"
category = "regular"
long = "uf-ss-totality-limited=N"
diff --git a/src/parser/CMakeLists.txt b/src/parser/CMakeLists.txt
index 393b1597a..8e69da34b 100644
--- a/src/parser/CMakeLists.txt
+++ b/src/parser/CMakeLists.txt
@@ -1,3 +1,13 @@
+#####################
+## CMakeLists.txt
+## Top contributors (to current version):
+## Mathias Preiner, Aina Niemetz, Andrew Reynolds
+## This file is part of the CVC4 project.
+## Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+## in the top-level source directory and their institutional affiliations.
+## All rights reserved. See the file COPYING in the top-level source
+## directory for licensing information.
+##
set(ANTLR_HOME ${ANTLR_DIR})
find_package(ANTLR REQUIRED)
@@ -99,7 +109,7 @@ target_link_libraries(cvc4parser cvc4 ${ANTLR_LIBRARIES})
target_include_directories(cvc4parser PRIVATE ${ANTLR_INCLUDE_DIR})
install(TARGETS cvc4parser
EXPORT cvc4-targets
- DESTINATION ${LIBRARY_INSTALL_DIR})
+ DESTINATION ${CMAKE_INSTALL_LIBDIR})
# The generated lexer/parser files define some functions as
# __declspec(dllexport) via the ANTLR3_API macro, which leads to lots of
diff --git a/src/parser/antlr_input.cpp b/src/parser/antlr_input.cpp
index 1d5190e3f..ef85dd1a9 100644
--- a/src/parser/antlr_input.cpp
+++ b/src/parser/antlr_input.cpp
@@ -5,7 +5,7 @@
** Christopher L. Conway, Kshitij Bansal, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,7 +18,6 @@
#include <antlr3.h>
#include <limits.h>
-#include <stdint.h>
#include "base/output.h"
#include "expr/type.h"
@@ -33,7 +32,6 @@
#include "parser/smt2/smt2_input.h"
#include "parser/smt2/sygus_input.h"
#include "parser/tptp/tptp_input.h"
-#include "smt/command.h"
using namespace std;
using namespace CVC4;
@@ -389,7 +387,10 @@ size_t wholeWordMatch(string input, string pattern, bool (*isWordChar)(char)) {
* found to be totally unhelpful. (TODO: fix this upstream to
* improve)
*/
-std::string parseErrorHelper(const char* lineStart, int charPositionInLine, const std::string& message)
+std::string parseErrorHelper(const char* lineStart,
+ std::size_t lineLength,
+ std::size_t charPositionInLine,
+ const std::string& message)
{
// Is it a multi-line message
bool multilineMessage = (message.find('\n') != string::npos);
@@ -405,17 +406,20 @@ std::string parseErrorHelper(const char* lineStart, int charPositionInLine, cons
ss << message << endl << endl;
}
- int posSliceStart = (charPositionInLine - 50 <= 0) ? 0 : charPositionInLine - 50 + 5;
- int posSliceEnd = posSliceStart + 70;
- int caretPos = 0;
- int caretPosExtra = 0; // for inital intendation, epilipses etc.
+ std::size_t posSliceStart =
+ (charPositionInLine <= 50) ? 0 : charPositionInLine - 50 + 5;
+ std::size_t posSliceEnd = posSliceStart + 70;
+ std::size_t caretPos = 0;
+ std::size_t caretPosExtra = 0; // for inital intendation, epilipses etc.
ss << " "; caretPosExtra += 2;
if(posSliceStart > 0) {
ss << "..."; caretPosExtra += 3;
}
- for(int i = posSliceStart; lineStart[i] != '\n'; ++i) {
+ for (std::size_t i = posSliceStart; i < lineLength && lineStart[i] != '\n';
+ ++i)
+ {
if(i == posSliceEnd) {
ss << "...";
break;
@@ -501,9 +505,14 @@ std::string parseErrorHelper(const char* lineStart, int charPositionInLine, cons
void AntlrInput::parseError(const std::string& message, bool eofException)
{
- string updatedMessage = parseErrorHelper((const char*)d_antlr3InputStream->getLineBuf(d_antlr3InputStream),
- d_lexer->getCharPositionInLine(d_lexer),
- message);
+ auto lineLength = d_antlr3InputStream->sizeBuf
+ - (static_cast<char*>(d_antlr3InputStream->currentLine)
+ - static_cast<char*>(d_antlr3InputStream->data));
+ std::string updatedMessage = parseErrorHelper(
+ (const char*)d_antlr3InputStream->getLineBuf(d_antlr3InputStream),
+ lineLength,
+ d_lexer->getCharPositionInLine(d_lexer),
+ message);
Debug("parser") << "Throwing exception: "
<< (const char*)d_lexer->rec->state->tokSource->fileName->chars << ":"
diff --git a/src/parser/antlr_input.h b/src/parser/antlr_input.h
index d3ae9761d..46913ded1 100644
--- a/src/parser/antlr_input.h
+++ b/src/parser/antlr_input.h
@@ -5,7 +5,7 @@
** Christopher L. Conway, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/antlr_input_imports.cpp b/src/parser/antlr_input_imports.cpp
index dd0c078a2..73fc58d9c 100644
--- a/src/parser/antlr_input_imports.cpp
+++ b/src/parser/antlr_input_imports.cpp
@@ -5,7 +5,7 @@
** Christopher L. Conway, Francois Bobot, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/antlr_line_buffered_input.cpp b/src/parser/antlr_line_buffered_input.cpp
index cdf553880..39a239f89 100644
--- a/src/parser/antlr_line_buffered_input.cpp
+++ b/src/parser/antlr_line_buffered_input.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Andres Noetzli, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/antlr_line_buffered_input.h b/src/parser/antlr_line_buffered_input.h
index edd119d75..81d247828 100644
--- a/src/parser/antlr_line_buffered_input.h
+++ b/src/parser/antlr_line_buffered_input.h
@@ -5,7 +5,7 @@
** Andres Noetzli, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/antlr_tracing.h b/src/parser/antlr_tracing.h
index c59b21233..03e77224b 100644
--- a/src/parser/antlr_tracing.h
+++ b/src/parser/antlr_tracing.h
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/bounded_token_buffer.cpp b/src/parser/bounded_token_buffer.cpp
index f93b47042..ae53919b0 100644
--- a/src/parser/bounded_token_buffer.cpp
+++ b/src/parser/bounded_token_buffer.cpp
@@ -5,7 +5,7 @@
** Christopher L. Conway, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/bounded_token_buffer.h b/src/parser/bounded_token_buffer.h
index f5237dc9d..098d9869f 100644
--- a/src/parser/bounded_token_buffer.h
+++ b/src/parser/bounded_token_buffer.h
@@ -5,7 +5,7 @@
** Christopher L. Conway, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/bounded_token_factory.cpp b/src/parser/bounded_token_factory.cpp
index 2af675dbc..2c9c53861 100644
--- a/src/parser/bounded_token_factory.cpp
+++ b/src/parser/bounded_token_factory.cpp
@@ -5,7 +5,7 @@
** Christopher L. Conway
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/bounded_token_factory.h b/src/parser/bounded_token_factory.h
index 0f6cd5afe..ee123df44 100644
--- a/src/parser/bounded_token_factory.h
+++ b/src/parser/bounded_token_factory.h
@@ -5,7 +5,7 @@
** Christopher L. Conway, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/cvc/Cvc.g b/src/parser/cvc/Cvc.g
index fe5f5e636..91c7d0ded 100644
--- a/src/parser/cvc/Cvc.g
+++ b/src/parser/cvc/Cvc.g
@@ -5,7 +5,7 @@
** Morgan Deters, Andrew Reynolds, Christopher L. Conway
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -546,7 +546,6 @@ api::Term addNots(api::Solver* s, size_t n, api::Term e) {
#include <cassert>
#include <memory>
-#include <stdint.h>
#include "options/set_language.h"
#include "parser/antlr_tracing.h"
@@ -704,13 +703,12 @@ mainCommand[std::unique_ptr<CVC4::Command>* cmd]
bool formCommaFlag = true;
}
/* our bread & butter */
- : ASSERT_TOK formula[f] { cmd->reset(new AssertCommand(f.getExpr())); }
+ : ASSERT_TOK formula[f] { cmd->reset(new AssertCommand(f)); }
- | QUERY_TOK formula[f] { cmd->reset(new QueryCommand(f.getExpr())); }
+ | QUERY_TOK formula[f] { cmd->reset(new QueryCommand(f)); }
| CHECKSAT_TOK formula[f]?
{
- cmd->reset(f.isNull() ? new CheckSatCommand()
- : new CheckSatCommand(f.getExpr()));
+ cmd->reset(f.isNull() ? new CheckSatCommand() : new CheckSatCommand(f));
}
/* options */
| OPTION_TOK
@@ -764,7 +762,7 @@ mainCommand[std::unique_ptr<CVC4::Command>* cmd]
END_TOK
{ PARSER_STATE->popScope();
cmd->reset(new DatatypeDeclarationCommand(
- api::sortVectorToTypes(PARSER_STATE->bindMutualDatatypeTypes(dts))));
+ PARSER_STATE->bindMutualDatatypeTypes(dts)));
}
| CONTEXT_TOK
@@ -789,7 +787,7 @@ mainCommand[std::unique_ptr<CVC4::Command>* cmd]
{ UNSUPPORTED("GET_OP command"); }
| GET_VALUE_TOK formula[f]
- { cmd->reset(new GetValueCommand(f.getExpr())); }
+ { cmd->reset(new GetValueCommand(f)); }
| SUBSTITUTE_TOK identifier[id,CHECK_NONE,SYM_VARIABLE] COLON
type[t,CHECK_DECLARED] EQUAL_TOK formula[f] LBRACKET
@@ -823,7 +821,7 @@ mainCommand[std::unique_ptr<CVC4::Command>* cmd]
)
| TRANSFORM_TOK formula[f]
- { cmd->reset(new SimplifyCommand(f.getExpr())); }
+ { cmd->reset(new SimplifyCommand(f)); }
| PRINT_TOK formula[f]
{ UNSUPPORTED("PRINT command"); }
@@ -936,8 +934,7 @@ mainCommand[std::unique_ptr<CVC4::Command>* cmd]
PARSER_STATE->parseError("Type mismatch in definition");
}
}
- cmd->reset(
- new DefineFunctionRecCommand(SOLVER, funcs, formals, formulas, true));
+ cmd->reset(new DefineFunctionRecCommand(funcs, formals, formulas, true));
}
| toplevelDeclaration[cmd]
;
@@ -1059,7 +1056,7 @@ declareTypes[std::unique_ptr<CVC4::Command>* cmd,
// behavior here.
PARSER_STATE->checkDeclaration(*i, CHECK_UNDECLARED, SYM_SORT);
api::Sort sort = PARSER_STATE->mkSort(*i);
- Command* decl = new DeclareTypeCommand(*i, 0, sort.getType());
+ Command* decl = new DeclareSortCommand(*i, 0, sort);
seq->addCommand(decl);
}
cmd->reset(seq.release());
@@ -1125,8 +1122,7 @@ declareVariables[std::unique_ptr<CVC4::Command>* cmd, CVC4::api::Sort& t,
if(topLevel) {
api::Term func =
PARSER_STATE->bindVar(*i, t, ExprManager::VAR_FLAG_GLOBAL);
- Command* decl =
- new DeclareFunctionCommand(*i, func.getExpr(), t.getType());
+ Command* decl = new DeclareFunctionCommand(*i, func, t);
seq->addCommand(decl);
} else {
PARSER_STATE->bindBoundVar(*i, t);
@@ -1145,6 +1141,13 @@ declareVariables[std::unique_ptr<CVC4::Command>* cmd, CVC4::api::Sort& t,
PARSER_STATE->parseError("cannot construct a definition here; maybe you want a LET");
}
assert(!idList.empty());
+ api::Term fterm = f;
+ std::vector<api::Term> formals;
+ if (f.getKind()==api::LAMBDA)
+ {
+ formals.insert(formals.end(), f[0].begin(), f[0].end());
+ f = f[1];
+ }
for(std::vector<std::string>::const_iterator i = idList.begin(),
i_end = idList.end();
i != i_end;
@@ -1153,16 +1156,15 @@ declareVariables[std::unique_ptr<CVC4::Command>* cmd, CVC4::api::Sort& t,
PARSER_STATE->checkDeclaration(*i, CHECK_UNDECLARED, SYM_VARIABLE);
api::Term func = PARSER_STATE->mkVar(
*i,
- api::Sort(SOLVER, t.getType()),
+ t,
ExprManager::VAR_FLAG_GLOBAL | ExprManager::VAR_FLAG_DEFINED);
- PARSER_STATE->defineVar(*i, f);
- Command* decl =
- new DefineFunctionCommand(*i, func.getExpr(), f.getExpr(), true);
+ PARSER_STATE->defineVar(*i, fterm);
+ Command* decl = new DefineFunctionCommand(*i, func, formals, f, true);
seq->addCommand(decl);
}
}
if(topLevel) {
- cmd->reset(new DeclarationSequence());
+ cmd->reset(seq.release());
}
}
;
@@ -1646,9 +1648,9 @@ tupleStore[CVC4::api::Term& f]
ss << "tuple is of length " << length << "; cannot update index " << k;
PARSER_STATE->parseError(ss.str());
}
- const Datatype & dt = ((DatatypeType)t.getType()).getDatatype();
+ const api::Datatype& dt = t.getDatatype();
f2 = SOLVER->mkTerm(
- api::APPLY_SELECTOR, api::Term(SOLVER, dt[0][k].getSelector()), f);
+ api::APPLY_SELECTOR, dt[0][k].getSelectorTerm(), f);
}
( ( arrayStore[f2]
| DOT ( tupleStore[f2]
@@ -1675,13 +1677,9 @@ recordStore[CVC4::api::Term& f]
<< "its type: " << t;
PARSER_STATE->parseError(ss.str());
}
- const Record& rec = ((DatatypeType)t.getType()).getRecord();
- if(! rec.contains(id)) {
- PARSER_STATE->parseError(std::string("no such field `") + id + "' in record");
- }
- const Datatype & dt = ((DatatypeType)t.getType()).getDatatype();
+ const api::Datatype& dt = t.getDatatype();
f2 = SOLVER->mkTerm(
- api::APPLY_SELECTOR, api::Term(SOLVER, dt[0][id].getSelector()), f);
+ api::APPLY_SELECTOR, dt[0][id].getSelectorTerm(), f);
}
( ( arrayStore[f2]
| DOT ( tupleStore[f2]
@@ -1820,13 +1818,9 @@ postfixTerm[CVC4::api::Term& f]
if(! type.isRecord()) {
PARSER_STATE->parseError("record-select applied to non-record");
}
- const Record& rec = ((DatatypeType)type.getType()).getRecord();
- if(!rec.contains(id)){
- PARSER_STATE->parseError(std::string("no such field `") + id + "' in record");
- }
- const Datatype & dt = ((DatatypeType)type.getType()).getDatatype();
+ const api::Datatype& dt = type.getDatatype();
f = SOLVER->mkTerm(api::APPLY_SELECTOR,
- api::Term(SOLVER, dt[0][id].getSelector()),
+ dt[0][id].getSelectorTerm(),
f);
}
| k=numeral
@@ -1841,9 +1835,9 @@ postfixTerm[CVC4::api::Term& f]
ss << "tuple is of length " << length << "; cannot access index " << k;
PARSER_STATE->parseError(ss.str());
}
- const Datatype & dt = ((DatatypeType)type.getType()).getDatatype();
+ const api::Datatype& dt = type.getDatatype();
f = SOLVER->mkTerm(api::APPLY_SELECTOR,
- api::Term(SOLVER, dt[0][k].getSelector()),
+ dt[0][k].getSelectorTerm(),
f);
}
)
@@ -1883,8 +1877,8 @@ relationTerm[CVC4::api::Term& f]
args.push_back(f);
types.push_back(f.getSort());
api::Sort t = SOLVER->mkTupleSort(types);
- const Datatype& dt = Datatype(((DatatypeType)t.getType()).getDatatype());
- args.insert(args.begin(), api::Term(SOLVER, dt[0].getConstructor()));
+ const api::Datatype& dt = t.getDatatype();
+ args.insert(args.begin(), dt[0].getConstructorTerm());
f = MK_TERM(api::APPLY_CONSTRUCTOR, args);
}
| IDEN_TOK LPAREN formula[f] RPAREN
@@ -2135,8 +2129,8 @@ simpleTerm[CVC4::api::Term& f]
types.push_back((*i).getSort());
}
api::Sort dtype = SOLVER->mkTupleSort(types);
- const Datatype& dt = ((DatatypeType)dtype.getType()).getDatatype();
- args.insert(args.begin(), api::Term(SOLVER, dt[0].getConstructor()));
+ const api::Datatype& dt = dtype.getDatatype();
+ args.insert(args.begin(), dt[0].getConstructorTerm());
f = MK_TERM(api::APPLY_CONSTRUCTOR, args);
}
}
@@ -2145,9 +2139,8 @@ simpleTerm[CVC4::api::Term& f]
| LPAREN RPAREN
{ std::vector<api::Sort> types;
api::Sort dtype = SOLVER->mkTupleSort(types);
- const Datatype& dt = ((DatatypeType)dtype.getType()).getDatatype();
- f = MK_TERM(api::APPLY_CONSTRUCTOR,
- api::Term(SOLVER, dt[0].getConstructor()));
+ const api::Datatype& dt = dtype.getDatatype();
+ f = MK_TERM(api::APPLY_CONSTRUCTOR, dt[0].getConstructorTerm());
}
/* empty record literal */
@@ -2155,9 +2148,8 @@ simpleTerm[CVC4::api::Term& f]
{
api::Sort dtype = SOLVER->mkRecordSort(
std::vector<std::pair<std::string, api::Sort>>());
- const Datatype& dt = ((DatatypeType)dtype.getType()).getDatatype();
- f = MK_TERM(api::APPLY_CONSTRUCTOR,
- api::Term(SOLVER, dt[0].getConstructor()));
+ const api::Datatype& dt = dtype.getDatatype();
+ f = MK_TERM(api::APPLY_CONSTRUCTOR, dt[0].getConstructorTerm());
}
/* empty set literal */
| LBRACE RBRACE
@@ -2184,20 +2176,10 @@ simpleTerm[CVC4::api::Term& f]
}
/* array literals */
- | ARRAY_TOK /* { PARSER_STATE->pushScope(); } */ LPAREN
+ | ARRAY_TOK LPAREN
restrictedType[t, CHECK_DECLARED] OF_TOK restrictedType[t2, CHECK_DECLARED]
RPAREN COLON simpleTerm[f]
- { /* Eventually if we support a bound var (like a lambda) for array
- * literals, we can use the push/pop scope. */
- /* PARSER_STATE->popScope(); */
- t = SOLVER->mkArraySort(t, t2);
- if(!f.isConst()) {
- std::stringstream ss;
- ss << "expected constant term inside array constant, but found "
- << "nonconstant term" << std::endl
- << "the term: " << f;
- PARSER_STATE->parseError(ss.str());
- }
+ { t = SOLVER->mkArraySort(t, t2);
if(!t2.isComparableTo(f.getSort())) {
std::stringstream ss;
ss << "type mismatch inside array constant term:" << std::endl
@@ -2221,18 +2203,12 @@ simpleTerm[CVC4::api::Term& f]
std::stringstream strRat;
strRat << r;
f = SOLVER->mkReal(strRat.str());
- if(f.getSort().isInteger()) {
- // Must cast to Real to ensure correct type is passed to parametric type constructors.
- // We do this cast using division with 1.
- // This has the advantage wrt using TO_REAL since (constant) division is always included in the theory.
- f = MK_TERM(api::DIVISION, f, SOLVER->mkReal(1));
- }
}
| INTEGER_LITERAL {
Rational r = AntlrInput::tokenToRational($INTEGER_LITERAL);
std::stringstream strRat;
strRat << r;
- f = SOLVER->mkReal(strRat.str());
+ f = SOLVER->mkInteger(strRat.str());
}
/* bitvector literals */
| HEX_LITERAL
@@ -2254,8 +2230,8 @@ simpleTerm[CVC4::api::Term& f]
typeIds.push_back(std::make_pair(names[i], args[i].getSort()));
}
api::Sort dtype = SOLVER->mkRecordSort(typeIds);
- const Datatype& dt = ((DatatypeType)dtype.getType()).getDatatype();
- args.insert(args.begin(), api::Term(SOLVER, dt[0].getConstructor()));
+ const api::Datatype& dt = dtype.getDatatype();
+ args.insert(args.begin(), dt[0].getConstructorTerm());
f = MK_TERM(api::APPLY_CONSTRUCTOR, args);
}
@@ -2491,7 +2467,7 @@ fragment DOT:;
fragment DOTDOT:;
/**
- * Matches the hexidecimal digits (0-9, a-f, A-F)
+ * Matches the hexadecimal digits (0-9, a-f, A-F)
*/
fragment HEX_DIGIT : DIGIT | 'a'..'f' | 'A'..'F';
diff --git a/src/parser/cvc/cvc.cpp b/src/parser/cvc/cvc.cpp
index 4d409a0b4..d096b6c7c 100644
--- a/src/parser/cvc/cvc.cpp
+++ b/src/parser/cvc/cvc.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -15,6 +15,7 @@
**/
#include "parser/cvc/cvc.h"
+#include "smt/command.h"
namespace CVC4 {
namespace parser {
diff --git a/src/parser/cvc/cvc.h b/src/parser/cvc/cvc.h
index 7c226168f..7214b6455 100644
--- a/src/parser/cvc/cvc.h
+++ b/src/parser/cvc/cvc.h
@@ -5,7 +5,7 @@
** Andres Noetzli, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,7 +21,6 @@
#include "api/cvc4cpp.h"
#include "parser/parser.h"
-#include "smt/command.h"
namespace CVC4 {
@@ -39,10 +38,11 @@ class Cvc : public Parser
protected:
Cvc(api::Solver* solver,
+ SymbolManager* sm,
Input* input,
bool strictMode = false,
bool parseOnly = false)
- : Parser(solver, input, strictMode, parseOnly)
+ : Parser(solver, sm, input, strictMode, parseOnly)
{
}
};
diff --git a/src/parser/cvc/cvc_input.cpp b/src/parser/cvc/cvc_input.cpp
index 32ed589ab..5e3510a4b 100644
--- a/src/parser/cvc/cvc_input.cpp
+++ b/src/parser/cvc/cvc_input.cpp
@@ -5,7 +5,7 @@
** Christopher L. Conway, Morgan Deters, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/cvc/cvc_input.h b/src/parser/cvc/cvc_input.h
index 3e46dcb65..bedd04bd6 100644
--- a/src/parser/cvc/cvc_input.h
+++ b/src/parser/cvc/cvc_input.h
@@ -5,7 +5,7 @@
** Christopher L. Conway, Mathias Preiner, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/input.cpp b/src/parser/input.cpp
index 13903eaf5..603da0e31 100644
--- a/src/parser/input.cpp
+++ b/src/parser/input.cpp
@@ -5,7 +5,7 @@
** Christopher L. Conway, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -23,7 +23,6 @@
#include "expr/type.h"
#include "parser/parser.h"
#include "parser/parser_exception.h"
-#include "smt/command.h"
using namespace std;
diff --git a/src/parser/input.h b/src/parser/input.h
index 35f2ae0fb..19fd4db72 100644
--- a/src/parser/input.h
+++ b/src/parser/input.h
@@ -5,7 +5,7 @@
** Christopher L. Conway, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/line_buffer.cpp b/src/parser/line_buffer.cpp
index 35ecbfdbb..97a4754a7 100644
--- a/src/parser/line_buffer.cpp
+++ b/src/parser/line_buffer.cpp
@@ -5,7 +5,7 @@
** Andres Noetzli, Mathias Preiner, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/line_buffer.h b/src/parser/line_buffer.h
index 6557539eb..c443f5fcf 100644
--- a/src/parser/line_buffer.h
+++ b/src/parser/line_buffer.h
@@ -5,7 +5,7 @@
** Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/memory_mapped_input_buffer.cpp b/src/parser/memory_mapped_input_buffer.cpp
index a753c2404..9cc1e7dd3 100644
--- a/src/parser/memory_mapped_input_buffer.cpp
+++ b/src/parser/memory_mapped_input_buffer.cpp
@@ -5,7 +5,7 @@
** Christopher L. Conway, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,7 +16,6 @@
#include <fcntl.h>
#include <stdio.h>
-#include <stdint.h>
#include <antlr3input.h>
diff --git a/src/parser/memory_mapped_input_buffer.h b/src/parser/memory_mapped_input_buffer.h
index a601704c7..49b2570f2 100644
--- a/src/parser/memory_mapped_input_buffer.h
+++ b/src/parser/memory_mapped_input_buffer.h
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner, Christopher L. Conway
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/parse_op.cpp b/src/parser/parse_op.cpp
index 8ff1619fb..3ba36c507 100644
--- a/src/parser/parse_op.cpp
+++ b/src/parser/parse_op.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/parse_op.h b/src/parser/parse_op.h
index c68de390f..4f3d6ee24 100644
--- a/src/parser/parse_op.h
+++ b/src/parser/parse_op.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/parser.cpp b/src/parser/parser.cpp
index bf12ee87d..1fc995fd6 100644
--- a/src/parser/parser.cpp
+++ b/src/parser/parser.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Christopher L. Conway
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,8 +16,6 @@
#include "parser/parser.h"
-#include <stdint.h>
-
#include <cassert>
#include <fstream>
#include <iostream>
@@ -28,7 +26,6 @@
#include "api/cvc4cpp.h"
#include "base/output.h"
#include "expr/expr.h"
-#include "expr/expr_iomanip.h"
#include "expr/kind.h"
#include "expr/type.h"
#include "options/options.h"
@@ -43,14 +40,14 @@ namespace CVC4 {
namespace parser {
Parser::Parser(api::Solver* solver,
+ SymbolManager* sm,
Input* input,
bool strictMode,
bool parseOnly)
: d_input(input),
- d_symtabAllocated(),
- d_symtab(&d_symtabAllocated),
+ d_symman(sm),
+ d_symtab(sm->getSymbolTable()),
d_assertionLevel(0),
- d_globalDeclarations(false),
d_anonymousFunctionCount(0),
d_done(false),
d_checksEnabled(true),
@@ -82,7 +79,7 @@ api::Term Parser::getSymbol(const std::string& name, SymbolType type)
assert(isDeclared(name, type));
assert(type == SYM_VARIABLE);
// Functions share var namespace
- return api::Term(d_solver, d_symtab->lookup(name));
+ return d_symtab->lookup(name);
}
api::Term Parser::getVariable(const std::string& name)
@@ -159,7 +156,7 @@ api::Sort Parser::getSort(const std::string& name)
{
checkDeclaration(name, CHECK_DECLARED, SYM_SORT);
assert(isDeclared(name, SYM_SORT));
- api::Sort t = api::Sort(d_solver, d_symtab->lookupType(name));
+ api::Sort t = d_symtab->lookupType(name);
return t;
}
@@ -168,8 +165,7 @@ api::Sort Parser::getSort(const std::string& name,
{
checkDeclaration(name, CHECK_DECLARED, SYM_SORT);
assert(isDeclared(name, SYM_SORT));
- api::Sort t = api::Sort(
- d_solver, d_symtab->lookupType(name, api::sortVectorToTypes(params)));
+ api::Sort t = d_symtab->lookupType(name, params);
return t;
}
@@ -206,7 +202,8 @@ api::Term Parser::bindVar(const std::string& name,
uint32_t flags,
bool doOverload)
{
- if (d_globalDeclarations) {
+ if (d_symman->getGlobalDeclarations())
+ {
flags |= ExprManager::VAR_FLAG_GLOBAL;
}
Debug("parser") << "bindVar(" << name << ", " << type << ")" << std::endl;
@@ -230,8 +227,7 @@ std::vector<api::Term> Parser::bindBoundVars(
std::vector<api::Term> vars;
for (std::pair<std::string, api::Sort>& i : sortedVarNames)
{
- vars.push_back(
- bindBoundVar(i.first, api::Sort(d_solver, i.second.getType())));
+ vars.push_back(bindBoundVar(i.first, i.second));
}
return vars;
}
@@ -240,12 +236,14 @@ api::Term Parser::mkAnonymousFunction(const std::string& prefix,
const api::Sort& type,
uint32_t flags)
{
- if (d_globalDeclarations) {
+ bool globalDecls = d_symman->getGlobalDeclarations();
+ if (globalDecls)
+ {
flags |= ExprManager::VAR_FLAG_GLOBAL;
}
stringstream name;
name << prefix << "_anon_" << ++d_anonymousFunctionCount;
- return mkVar(name.str(), api::Sort(d_solver, type.getType()), flags);
+ return mkVar(name.str(), type, flags);
}
std::vector<api::Term> Parser::bindVars(const std::vector<std::string> names,
@@ -253,7 +251,9 @@ std::vector<api::Term> Parser::bindVars(const std::vector<std::string> names,
uint32_t flags,
bool doOverload)
{
- if (d_globalDeclarations) {
+ bool globalDecls = d_symman->getGlobalDeclarations();
+ if (globalDecls)
+ {
flags |= ExprManager::VAR_FLAG_GLOBAL;
}
std::vector<api::Term> vars;
@@ -279,7 +279,7 @@ void Parser::defineVar(const std::string& name,
bool doOverload)
{
Debug("parser") << "defineVar( " << name << " := " << val << ")" << std::endl;
- if (!d_symtab->bind(name, val.getExpr(), levelZero, doOverload))
+ if (!d_symtab->bind(name, val, levelZero, doOverload))
{
std::stringstream ss;
ss << "Cannot bind " << name << " to symbol of type " << val.getSort();
@@ -291,9 +291,15 @@ void Parser::defineVar(const std::string& name,
void Parser::defineType(const std::string& name,
const api::Sort& type,
- bool levelZero)
+ bool levelZero,
+ bool skipExisting)
{
- d_symtab->bindType(name, type.getType(), levelZero);
+ if (skipExisting && isDeclared(name, SYM_SORT))
+ {
+ assert(d_symtab->lookupType(name) == type);
+ return;
+ }
+ d_symtab->bindType(name, type, levelZero);
assert(isDeclared(name, SYM_SORT));
}
@@ -302,8 +308,7 @@ void Parser::defineType(const std::string& name,
const api::Sort& type,
bool levelZero)
{
- d_symtab->bindType(
- name, api::sortVectorToTypes(params), type.getType(), levelZero);
+ d_symtab->bindType(name, params, type, levelZero);
assert(isDeclared(name, SYM_SORT));
}
@@ -330,10 +335,9 @@ api::Sort Parser::mkSort(const std::string& name, uint32_t flags)
Debug("parser") << "newSort(" << name << ")" << std::endl;
api::Sort type =
api::Sort(d_solver, d_solver->getExprManager()->mkSort(name, flags));
+ bool globalDecls = d_symman->getGlobalDeclarations();
defineType(
- name,
- type,
- d_globalDeclarations && !(flags & ExprManager::SORT_FLAG_PLACEHOLDER));
+ name, type, globalDecls && !(flags & ExprManager::SORT_FLAG_PLACEHOLDER));
return type;
}
@@ -346,11 +350,11 @@ api::Sort Parser::mkSortConstructor(const std::string& name,
api::Sort type = api::Sort(
d_solver,
d_solver->getExprManager()->mkSortConstructor(name, arity, flags));
- defineType(
- name,
- vector<api::Sort>(arity),
- type,
- d_globalDeclarations && !(flags & ExprManager::SORT_FLAG_PLACEHOLDER));
+ bool globalDecls = d_symman->getGlobalDeclarations();
+ defineType(name,
+ vector<api::Sort>(arity),
+ type,
+ globalDecls && !(flags & ExprManager::SORT_FLAG_PLACEHOLDER));
return type;
}
@@ -409,6 +413,7 @@ std::vector<api::Sort> Parser::bindMutualDatatypeTypes(
d_solver->mkDatatypeSorts(datatypes, d_unresolved);
assert(datatypes.size() == types.size());
+ bool globalDecls = d_symman->getGlobalDeclarations();
for (unsigned i = 0; i < datatypes.size(); ++i) {
api::Sort t = types[i];
@@ -421,18 +426,17 @@ std::vector<api::Sort> Parser::bindMutualDatatypeTypes(
if (t.isParametricDatatype())
{
std::vector<api::Sort> paramTypes = t.getDatatypeParamSorts();
- defineType(name, paramTypes, t, d_globalDeclarations);
+ defineType(name, paramTypes, t, globalDecls);
}
else
{
- defineType(name, t, d_globalDeclarations);
+ defineType(name, t, globalDecls);
}
std::unordered_set< std::string > consNames;
std::unordered_set< std::string > selNames;
for (size_t j = 0, ncons = dt.getNumConstructors(); j < ncons; j++)
{
const api::DatatypeConstructor& ctor = dt[j];
- expr::ExprPrintTypes::Scope pts(Debug("parser-idt"), true);
api::Term constructor = ctor.getConstructorTerm();
Debug("parser-idt") << "+ define " << constructor << std::endl;
string constructorName = ctor.getName();
@@ -440,8 +444,7 @@ std::vector<api::Sort> Parser::bindMutualDatatypeTypes(
if(!doOverload) {
checkDeclaration(constructorName, CHECK_UNDECLARED);
}
- defineVar(
- constructorName, constructor, d_globalDeclarations, doOverload);
+ defineVar(constructorName, constructor, globalDecls, doOverload);
consNames.insert(constructorName);
}else{
throw ParserException(constructorName + " already declared in this datatype");
@@ -455,7 +458,7 @@ std::vector<api::Sort> Parser::bindMutualDatatypeTypes(
{
checkDeclaration(testerName, CHECK_UNDECLARED);
}
- defineVar(testerName, tester, d_globalDeclarations, doOverload);
+ defineVar(testerName, tester, globalDecls, doOverload);
}
for (size_t k = 0, nargs = ctor.getNumSelectors(); k < nargs; k++)
{
@@ -467,7 +470,7 @@ std::vector<api::Sort> Parser::bindMutualDatatypeTypes(
if(!doOverload) {
checkDeclaration(selectorName, CHECK_UNDECLARED);
}
- defineVar(selectorName, selector, d_globalDeclarations, doOverload);
+ defineVar(selectorName, selector, globalDecls, doOverload);
selNames.insert(selectorName);
}else{
throw ParserException(selectorName + " already declared in this datatype");
@@ -561,6 +564,10 @@ api::Term Parser::applyTypeAscription(api::Term t, api::Sort s)
{
t = d_solver->mkEmptySet(s);
}
+ else if (k == api::EMPTYBAG)
+ {
+ t = d_solver->mkEmptyBag(s);
+ }
else if (k == api::CONST_SEQUENCE)
{
if (!s.isSequence())
@@ -596,27 +603,17 @@ api::Term Parser::applyTypeAscription(api::Term t, api::Sort s)
api::Sort etype = t.getSort();
if (etype.isConstructor())
{
- // get the datatype that t belongs to
- api::Sort etyped = etype.getConstructorCodomainSort();
- api::Datatype d = etyped.getDatatype();
- // lookup by name
- api::DatatypeConstructor dc = d.getConstructor(t.toString());
-
// Type ascriptions only have an effect on the node structure if this is a
// parametric datatype.
if (s.isParametricDatatype())
{
- ExprManager* em = d_solver->getExprManager();
- // apply type ascription to the operator
- Expr e = t.getExpr();
- const DatatypeConstructor& dtc =
- Datatype::datatypeOf(e)[Datatype::indexOf(e)];
- t = api::Term(
- d_solver,
- em->mkExpr(kind::APPLY_TYPE_ASCRIPTION,
- em->mkConst(AscriptionType(
- dtc.getSpecializedConstructorType(s.getType()))),
- e));
+ // get the datatype that t belongs to
+ api::Sort etyped = etype.getConstructorCodomainSort();
+ api::Datatype d = etyped.getDatatype();
+ // lookup by name
+ api::DatatypeConstructor dc = d.getConstructor(t.toString());
+ // ask the constructor for the specialized constructor term
+ t = dc.getSpecializedConstructorTerm(s);
}
// the type of t does not match the sort s by design (constructor type
// vs datatype type), thus we use an alternative check here.
@@ -774,6 +771,31 @@ void Parser::attributeNotSupported(const std::string& attr) {
}
}
+size_t Parser::scopeLevel() const { return d_symman->scopeLevel(); }
+
+void Parser::pushScope(bool isUserContext)
+{
+ d_symman->pushScope(isUserContext);
+ if (isUserContext)
+ {
+ d_assertionLevel = scopeLevel();
+ }
+}
+
+void Parser::popScope()
+{
+ d_symman->popScope();
+ if (scopeLevel() < d_assertionLevel)
+ {
+ d_assertionLevel = scopeLevel();
+ d_reservedSymbols.clear();
+ }
+}
+
+void Parser::reset() { d_symman->reset(); }
+
+SymbolManager* Parser::getSymbolManager() { return d_symman; }
+
std::vector<unsigned> Parser::processAdHocStringEsc(const std::string& s)
{
std::vector<unsigned> str;
diff --git a/src/parser/parser.h b/src/parser/parser.h
index b993b08fb..96a16b31f 100644
--- a/src/parser/parser.h
+++ b/src/parser/parser.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Christopher L. Conway
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,8 +16,8 @@
#include "cvc4parser_public.h"
-#ifndef CVC4__PARSER__PARSER_STATE_H
-#define CVC4__PARSER__PARSER_STATE_H
+#ifndef CVC4__PARSER__PARSER_H
+#define CVC4__PARSER__PARSER_H
#include <cassert>
#include <list>
@@ -25,8 +25,8 @@
#include <string>
#include "api/cvc4cpp.h"
-#include "expr/expr.h"
#include "expr/kind.h"
+#include "expr/symbol_manager.h"
#include "expr/symbol_table.h"
#include "parser/input.h"
#include "parser/parse_op.h"
@@ -36,39 +36,9 @@
namespace CVC4 {
// Forward declarations
-class BooleanType;
class Command;
-class FunctionType;
-class Type;
class ResourceManager;
-//for sygus gterm two-pass parsing
-class CVC4_PUBLIC SygusGTerm {
-public:
- enum{
- gterm_op,
- gterm_constant,
- gterm_variable,
- gterm_input_variable,
- gterm_local_variable,
- gterm_nested_sort,
- gterm_unresolved,
- gterm_ignore,
- };
- api::Sort d_type;
- /** The parsed operator */
- ParseOp d_op;
- std::vector<api::Term> d_let_vars;
- unsigned d_gterm_type;
- std::string d_name;
- std::vector< SygusGTerm > d_children;
-
- unsigned getNumChildren() { return d_children.size(); }
- void addChild(){
- d_children.push_back( SygusGTerm() );
- }
-};
-
namespace parser {
class Input;
@@ -140,16 +110,13 @@ private:
Input* d_input;
/**
- * The declaration scope that is "owned" by this parser. May or
- * may not be the current declaration scope in use.
+ * Reference to the symbol manager, which manages the symbol table used by
+ * this parser.
*/
- SymbolTable d_symtabAllocated;
+ SymbolManager* d_symman;
/**
- * This current symbol table used by this parser. Initially points
- * to d_symtabAllocated, but can be changed (making this parser
- * delegate its definitions and lookups to another parser).
- * See useDeclarationsFrom().
+ * This current symbol table used by this parser, from symbol manager.
*/
SymbolTable* d_symtab;
@@ -161,12 +128,6 @@ private:
size_t d_assertionLevel;
/**
- * Whether we're in global declarations mode (all definitions and
- * declarations are global).
- */
- bool d_globalDeclarations;
-
- /**
* 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
@@ -246,7 +207,8 @@ protected:
* @attention The parser takes "ownership" of the given
* input and will delete it on destruction.
*
- * @param the solver API object
+ * @param solver solver API object
+ * @param symm reference to the symbol manager
* @param input the parser input
* @param strictMode whether to incorporate strict(er) compliance checks
* @param parseOnly whether we are parsing only (and therefore certain checks
@@ -254,6 +216,7 @@ protected:
* unimplementedFeature())
*/
Parser(api::Solver* solver,
+ SymbolManager* sm,
Input* input,
bool strictMode = false,
bool parseOnly = false);
@@ -531,11 +494,15 @@ public:
* @param name The name of the type
* @param type The type that should be associated with the name
* @param levelZero If true, the type definition is considered global and
- * cannot be removed by poppoing the user context
+ * cannot be removed by popping the user context
+ * @param skipExisting If true, the type definition is ignored if the same
+ * symbol has already been defined. It is assumed that
+ * the definition is the exact same as the existing one.
*/
void defineType(const std::string& name,
const api::Sort& type,
- bool levelZero = false);
+ bool levelZero = false,
+ bool skipExisting = false);
/**
* Create a new (parameterized) type definition.
@@ -680,6 +647,7 @@ public:
* Return term t with a type ascription applied to it. This is used for
* syntax like (as t T) in smt2 and t::T in the CVC language. This includes:
* - (as emptyset (Set T))
+ * - (as emptybag (Bag T))
* - (as univset (Set T))
* - (as sep.nil T)
* - (cons T)
@@ -777,50 +745,32 @@ public:
/**
* Gets the current declaration level.
*/
- inline size_t scopeLevel() const { return d_symtab->getLevel(); }
+ size_t scopeLevel() const;
/**
* Pushes a scope. All subsequent symbol declarations made are only valid in
* this scope, i.e. they are deleted on the next call to popScope.
*
- * The argument bindingLevel is true, the assertion level is set to the
- * current scope level. This determines which scope assertions are declared
- * at.
+ * The argument isUserContext is true, when we are pushing a user context
+ * e.g. via the smt2 command (push n). This may also include one initial
+ * pushScope when the parser is initialized. User-context pushes and pops
+ * have an impact on both expression names and the symbol table, whereas
+ * other pushes and pops only have an impact on the symbol table.
*/
- 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();
- }
- }
+ void pushScope(bool isUserContext = false);
- virtual void reset() {
- d_symtab->reset();
- }
-
- void setGlobalDeclarations(bool flag) {
- d_globalDeclarations = flag;
- }
+ void popScope();
- bool getGlobalDeclarations() { return d_globalDeclarations; }
+ virtual void reset();
- inline SymbolTable* getSymbolTable() const {
- return d_symtab;
- }
+ /** Return the symbol manager used by this parser. */
+ SymbolManager* getSymbolManager();
//------------------------ operator overloading
/** is this function overloaded? */
bool isOverloadedFunction(api::Term fun)
{
- return d_symtab->isOverloadedFunction(fun.getExpr());
+ return d_symtab->isOverloadedFunction(fun);
}
/** Get overloaded constant for type.
@@ -829,8 +779,7 @@ public:
*/
api::Term getOverloadedConstantForType(const std::string& name, api::Sort t)
{
- return api::Term(d_solver,
- d_symtab->getOverloadedConstantForType(name, t.getType()));
+ return d_symtab->getOverloadedConstantForType(name, t);
}
/**
@@ -841,9 +790,7 @@ public:
api::Term getOverloadedFunctionForTypes(const std::string& name,
std::vector<api::Sort>& argTypes)
{
- return api::Term(d_solver,
- d_symtab->getOverloadedFunctionForTypes(
- name, api::sortVectorToTypes(argTypes)));
+ return d_symtab->getOverloadedFunctionForTypes(name, argTypes);
}
//------------------------ end operator overloading
/**
diff --git a/src/parser/parser_builder.cpp b/src/parser/parser_builder.cpp
index f65618267..9adb46af1 100644
--- a/src/parser/parser_builder.cpp
+++ b/src/parser/parser_builder.cpp
@@ -5,7 +5,7 @@
** Christopher L. Conway, Morgan Deters, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -33,28 +33,34 @@
namespace CVC4 {
namespace parser {
-ParserBuilder::ParserBuilder(api::Solver* solver, const std::string& filename)
- : d_filename(filename), d_solver(solver)
+ParserBuilder::ParserBuilder(api::Solver* solver,
+ SymbolManager* sm,
+ const std::string& filename)
+ : d_filename(filename), d_solver(solver), d_symman(sm)
{
- init(solver, filename);
+ init(solver, sm, filename);
}
ParserBuilder::ParserBuilder(api::Solver* solver,
+ SymbolManager* sm,
const std::string& filename,
const Options& options)
- : d_filename(filename), d_solver(solver)
+ : d_filename(filename), d_solver(solver), d_symman(sm)
{
- init(solver, filename);
+ init(solver, sm, filename);
withOptions(options);
}
-void ParserBuilder::init(api::Solver* solver, const std::string& filename)
+void ParserBuilder::init(api::Solver* solver,
+ SymbolManager* sm,
+ const std::string& filename)
{
d_inputType = FILE_INPUT;
d_lang = language::input::LANG_AUTO;
d_filename = filename;
d_streamInput = NULL;
d_solver = solver;
+ d_symman = sm;
d_checksEnabled = true;
d_strictMode = false;
d_canIncludeFile = true;
@@ -90,19 +96,19 @@ Parser* ParserBuilder::build()
switch (d_lang)
{
case language::input::LANG_SYGUS_V2:
- parser = new Smt2(d_solver, input, d_strictMode, d_parseOnly);
+ parser = new Smt2(d_solver, d_symman, input, d_strictMode, d_parseOnly);
break;
case language::input::LANG_TPTP:
- parser = new Tptp(d_solver, input, d_strictMode, d_parseOnly);
+ parser = new Tptp(d_solver, d_symman, input, d_strictMode, d_parseOnly);
break;
default:
if (language::isInputLang_smt2(d_lang))
{
- parser = new Smt2(d_solver, input, d_strictMode, d_parseOnly);
+ parser = new Smt2(d_solver, d_symman, input, d_strictMode, d_parseOnly);
}
else
{
- parser = new Cvc(d_solver, input, d_strictMode, d_parseOnly);
+ parser = new Cvc(d_solver, d_symman, input, d_strictMode, d_parseOnly);
}
break;
}
diff --git a/src/parser/parser_builder.h b/src/parser/parser_builder.h
index 52dc76581..bf205b13a 100644
--- a/src/parser/parser_builder.h
+++ b/src/parser/parser_builder.h
@@ -5,7 +5,7 @@
** Morgan Deters, Christopher L. Conway, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -26,12 +26,13 @@
namespace CVC4 {
-class Options;
-
namespace api {
class Solver;
}
+class Options;
+class SymbolManager;
+
namespace parser {
class Parser;
@@ -67,6 +68,9 @@ class CVC4_PUBLIC ParserBuilder {
/** The API Solver object. */
api::Solver* d_solver;
+ /** The symbol manager */
+ SymbolManager* d_symman;
+
/** Should semantic checks be enabled during parsing? */
bool d_checksEnabled;
@@ -89,13 +93,18 @@ class CVC4_PUBLIC ParserBuilder {
std::string d_forcedLogic;
/** Initialize this parser builder */
- void init(api::Solver* solver, const std::string& filename);
+ void init(api::Solver* solver,
+ SymbolManager* sm,
+ const std::string& filename);
public:
/** Create a parser builder using the given Solver and filename. */
- ParserBuilder(api::Solver* solver, const std::string& filename);
+ ParserBuilder(api::Solver* solver,
+ SymbolManager* sm,
+ const std::string& filename);
ParserBuilder(api::Solver* solver,
+ SymbolManager* sm,
const std::string& filename,
const Options& options);
diff --git a/src/parser/parser_exception.h b/src/parser/parser_exception.h
index 118cc589f..7f184ecb0 100644
--- a/src/parser/parser_exception.h
+++ b/src/parser/parser_exception.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Christopher L. Conway
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g
index 75fa5ceef..a7149ed15 100644
--- a/src/parser/smt2/Smt2.g
+++ b/src/parser/smt2/Smt2.g
@@ -2,10 +2,10 @@
/*! \file Smt2.g
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Morgan Deters, Tim King
+ ** Andrew Reynolds, Morgan Deters, Christopher L. Conway
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -63,8 +63,6 @@ options {
}/* @lexer::includes */
@lexer::postinclude {
-#include <stdint.h>
-
#include "parser/smt2/smt2.h"
#include "parser/antlr_input.h"
@@ -85,28 +83,12 @@ using namespace CVC4::parser;
#include "smt/command.h"
namespace CVC4 {
- class Expr;
namespace api {
class Term;
class Sort;
}
- namespace parser {
- namespace smt2 {
- /**
- * Just exists to provide the uintptr_t constructor that ANTLR
- * requires.
- */
- struct myExpr : public CVC4::api::Term {
- myExpr() : CVC4::api::Term() {}
- myExpr(void*) : CVC4::api::Term() {}
- myExpr(const Expr& e) : CVC4::api::Term(nullptr, e) {}
- myExpr(const myExpr& e) : CVC4::api::Term(e) {}
- };/* struct myExpr */
- }/* CVC4::parser::smt2 namespace */
- }/* CVC4::parser namespace */
-
}/* CVC4 namespace */
}/* @parser::includes */
@@ -132,8 +114,6 @@ namespace CVC4 {
#include "util/hash.h"
#include "util/integer.h"
#include "util/rational.h"
-// \todo Review the need for this header
-#include "math.h"
using namespace CVC4;
using namespace CVC4::parser;
@@ -145,6 +125,8 @@ using namespace CVC4::parser;
#define PARSER_STATE ((Smt2*)PARSER->super)
#undef SOLVER
#define SOLVER PARSER_STATE->getSolver()
+#undef SYM_MAN
+#define SYM_MAN PARSER_STATE->getSymbolManager()
#undef MK_TERM
#define MK_TERM SOLVER->mkTerm
#define UNSUPPORTED PARSER_STATE->unimplementedFeature
@@ -156,7 +138,7 @@ using namespace CVC4::parser;
* @return the parsed expression, or the Null Expr if we've reached the
* end of the input
*/
-parseExpr returns [CVC4::parser::smt2::myExpr expr]
+parseExpr returns [CVC4::api::Term expr = CVC4::api::Term()]
@declarations {
CVC4::api::Term expr2;
}
@@ -263,10 +245,10 @@ command [std::unique_ptr<CVC4::Command>* cmd]
unsigned arity = AntlrInput::tokenToUnsigned(n);
if(arity == 0) {
api::Sort type = PARSER_STATE->mkSort(name);
- cmd->reset(new DeclareTypeCommand(name, 0, type.getType()));
+ cmd->reset(new DeclareSortCommand(name, 0, type));
} else {
api::Sort type = PARSER_STATE->mkSortConstructor(name, arity);
- cmd->reset(new DeclareTypeCommand(name, arity, type.getType()));
+ cmd->reset(new DeclareSortCommand(name, arity, type));
}
}
| /* sort definition */
@@ -274,7 +256,7 @@ command [std::unique_ptr<CVC4::Command>* cmd]
symbol[name,CHECK_UNDECLARED,SYM_SORT]
{ PARSER_STATE->checkUserSymbol(name); }
LPAREN_TOK symbolList[names,CHECK_NONE,SYM_SORT] RPAREN_TOK
- { PARSER_STATE->pushScope(true);
+ { PARSER_STATE->pushScope();
for(std::vector<std::string>::const_iterator i = names.begin(),
iend = names.end();
i != iend;
@@ -287,8 +269,7 @@ command [std::unique_ptr<CVC4::Command>* cmd]
// Do NOT call mkSort, since that creates a new sort!
// This name is not its own distinct sort, it's an alias.
PARSER_STATE->defineParameterizedType(name, sorts, t);
- cmd->reset(new DefineTypeCommand(
- name, api::sortVectorToTypes(sorts), t.getType()));
+ cmd->reset(new DefineSortCommand(name, sorts, t));
}
| /* function declaration */
DECLARE_FUN_TOK { PARSER_STATE->checkThatLogicIsSet(); }
@@ -314,8 +295,7 @@ command [std::unique_ptr<CVC4::Command>* cmd]
{
api::Term func =
PARSER_STATE->bindVar(name, t, ExprManager::VAR_FLAG_NONE, true);
- cmd->reset(
- new DeclareFunctionCommand(name, func.getExpr(), t.getType()));
+ cmd->reset(new DeclareFunctionCommand(name, func, t));
}
}
| /* function definition */
@@ -334,9 +314,10 @@ command [std::unique_ptr<CVC4::Command>* cmd]
++i) {
sorts.push_back((*i).second);
}
- t = PARSER_STATE->mkFlatFunctionType(sorts, t, flattenVars);
}
- PARSER_STATE->pushScope(true);
+
+ t = PARSER_STATE->mkFlatFunctionType(sorts, t, flattenVars);
+ PARSER_STATE->pushScope();
terms = PARSER_STATE->bindBoundVars(sortedVarNames);
}
term[expr, expr2]
@@ -354,19 +335,15 @@ command [std::unique_ptr<CVC4::Command>* cmd]
// we allow overloading for function definitions
api::Term func = PARSER_STATE->bindVar(name, t,
ExprManager::VAR_FLAG_DEFINED, true);
- cmd->reset(
- new DefineFunctionCommand(name,
- func.getExpr(),
- api::termVectorToExprs(terms),
- expr.getExpr(),
- PARSER_STATE->getGlobalDeclarations()));
+ cmd->reset(new DefineFunctionCommand(
+ name, func, terms, expr, SYM_MAN->getGlobalDeclarations()));
}
| DECLARE_DATATYPE_TOK datatypeDefCommand[false, cmd]
| DECLARE_DATATYPES_TOK datatypesDefCommand[false, cmd]
| /* value query */
GET_VALUE_TOK { PARSER_STATE->checkThatLogicIsSet(); }
( LPAREN_TOK termList[terms,expr] RPAREN_TOK
- { cmd->reset(new GetValueCommand(api::termVectorToExprs(terms))); }
+ { cmd->reset(new GetValueCommand(terms)); }
| ~LPAREN_TOK
{ PARSER_STATE->parseError("The get-value command expects a list of "
"terms. Perhaps you forgot a pair of "
@@ -381,15 +358,12 @@ command [std::unique_ptr<CVC4::Command>* cmd]
{ PARSER_STATE->clearLastNamedTerm(); }
term[expr, expr2]
{ bool inUnsatCore = PARSER_STATE->lastNamedTerm().first == expr;
- cmd->reset(new AssertCommand(expr.getExpr(), inUnsatCore));
+ cmd->reset(new AssertCommand(expr, inUnsatCore));
if(inUnsatCore) {
// set the expression name, if there was a named term
std::pair<api::Term, std::string> namedTerm =
PARSER_STATE->lastNamedTerm();
- Command* csen = new SetExpressionNameCommand(namedTerm.first.getExpr(),
- namedTerm.second);
- csen->setMuted(true);
- PARSER_STATE->preemptCommand(csen);
+ SYM_MAN->setExpressionName(namedTerm.first, namedTerm.second, true);
}
}
| /* check-sat */
@@ -407,12 +381,12 @@ command [std::unique_ptr<CVC4::Command>* cmd]
}
| { expr = api::Term(); }
)
- { cmd->reset(new CheckSatCommand(expr.getExpr())); }
+ { cmd->reset(new CheckSatCommand(expr)); }
| /* check-sat-assuming */
CHECK_SAT_ASSUMING_TOK { PARSER_STATE->checkThatLogicIsSet(); }
( LPAREN_TOK termList[terms,expr] RPAREN_TOK
{
- cmd->reset(new CheckSatAssumingCommand(api::termVectorToExprs(terms)));
+ cmd->reset(new CheckSatAssumingCommand(terms));
}
| ~LPAREN_TOK
{ PARSER_STATE->parseError("The check-sat-assuming command expects a "
@@ -443,12 +417,12 @@ command [std::unique_ptr<CVC4::Command>* cmd]
if(num == 0) {
cmd->reset(new EmptyCommand());
} else if(num == 1) {
- PARSER_STATE->pushScope();
+ PARSER_STATE->pushScope(true);
cmd->reset(new PushCommand());
} else {
std::unique_ptr<CommandSequence> seq(new CommandSequence());
do {
- PARSER_STATE->pushScope();
+ PARSER_STATE->pushScope(true);
Command* push_cmd = new PushCommand();
push_cmd->setMuted(num > 1);
seq->addCommand(push_cmd);
@@ -462,7 +436,7 @@ command [std::unique_ptr<CVC4::Command>* cmd]
"Strict compliance mode demands an integer to be provided to "
"PUSH. Maybe you want (push 1)?");
} else {
- PARSER_STATE->pushScope();
+ PARSER_STATE->pushScope(true);
cmd->reset(new PushCommand());
}
} )
@@ -542,14 +516,14 @@ command [std::unique_ptr<CVC4::Command>* cmd]
sygusCommand returns [std::unique_ptr<CVC4::Command> cmd]
@declarations {
- CVC4::api::Term expr, expr2;
+ CVC4::api::Term expr, expr2, fun;
CVC4::api::Sort t, range;
std::vector<std::string> names;
std::vector<std::pair<std::string, CVC4::api::Sort> > sortedVarNames;
- std::unique_ptr<Smt2::SynthFunFactory> synthFunFactory;
- std::string name, fun;
+ std::vector<CVC4::api::Term> sygusVars;
+ std::string name;
bool isInv;
- CVC4::api::Sort grammar;
+ CVC4::api::Grammar* grammar = nullptr;
}
: /* declare-var */
DECLARE_VAR_TOK { PARSER_STATE->checkThatLogicIsSet(); }
@@ -557,31 +531,45 @@ sygusCommand returns [std::unique_ptr<CVC4::Command> cmd]
{ PARSER_STATE->checkUserSymbol(name); }
sortSymbol[t,CHECK_DECLARED]
{
- api::Term var = PARSER_STATE->bindBoundVar(name, t);
- cmd.reset(new DeclareSygusVarCommand(name, var.getExpr(), t.getType()));
+ api::Term var = SOLVER->mkSygusVar(t, name);
+ PARSER_STATE->defineVar(name, var);
+ cmd.reset(new DeclareSygusVarCommand(name, var, t));
}
-
| /* synth-fun */
( SYNTH_FUN_TOK { isInv = false; }
| SYNTH_INV_TOK { isInv = true; range = SOLVER->getBooleanSort(); }
)
{ PARSER_STATE->checkThatLogicIsSet(); }
- symbol[fun,CHECK_UNDECLARED,SYM_VARIABLE]
+ symbol[name,CHECK_UNDECLARED,SYM_VARIABLE]
LPAREN_TOK sortedVarList[sortedVarNames] RPAREN_TOK
( sortSymbol[range,CHECK_DECLARED] )?
{
- synthFunFactory.reset(new Smt2::SynthFunFactory(
- PARSER_STATE, fun, isInv, range, sortedVarNames));
+ PARSER_STATE->pushScope();
+ sygusVars = PARSER_STATE->bindBoundVars(sortedVarNames);
}
(
// optionally, read the sygus grammar
//
// `grammar` specifies the required grammar for the function to
// synthesize, expressed as a type
- sygusGrammar[grammar, synthFunFactory->getSygusVars(), fun]
+ sygusGrammar[grammar, sygusVars, name]
)?
{
- cmd = synthFunFactory->mkCommand(grammar);
+ Debug("parser-sygus") << "Define synth fun : " << name << std::endl;
+
+ fun = isInv ? (grammar == nullptr
+ ? SOLVER->synthInv(name, sygusVars)
+ : SOLVER->synthInv(name, sygusVars, *grammar))
+ : (grammar == nullptr
+ ? SOLVER->synthFun(name, sygusVars, range)
+ : SOLVER->synthFun(name, sygusVars, range, *grammar));
+
+ Debug("parser-sygus") << "...read synth fun " << name << std::endl;
+ PARSER_STATE->popScope();
+ // we do not allow overloading for synth fun
+ PARSER_STATE->defineVar(name, fun);
+ cmd = std::unique_ptr<Command>(
+ new SynthFunCommand(name, fun, sygusVars, range, isInv, grammar));
}
| /* constraint */
CONSTRAINT_TOK {
@@ -591,7 +579,7 @@ sygusCommand returns [std::unique_ptr<CVC4::Command> cmd]
}
term[expr, expr2]
{ Debug("parser-sygus") << "...read constraint " << expr << std::endl;
- cmd.reset(new SygusConstraintCommand(expr.getExpr()));
+ cmd.reset(new SygusConstraintCommand(expr));
}
| /* inv-constraint */
INV_CONSTRAINT_TOK
@@ -618,23 +606,19 @@ sygusCommand returns [std::unique_ptr<CVC4::Command> cmd]
* The argument fun is a unique identifier to avoid naming clashes for the
* datatypes constructed by this call.
*/
-sygusGrammar[CVC4::api::Sort & ret,
+sygusGrammar[CVC4::api::Grammar*& ret,
const std::vector<CVC4::api::Term>& sygusVars,
const std::string& fun]
@declarations
{
// the pre-declaration
- std::vector<std::pair<std::string, CVC4::api::Sort> > sortedVarNames;
+ std::vector<std::pair<std::string, CVC4::api::Sort>> sortedVarNames;
// non-terminal symbols of the grammar
std::vector<CVC4::api::Term> ntSyms;
CVC4::api::Sort t;
std::string name;
CVC4::api::Term e, e2;
- std::vector<api::DatatypeDecl> datatypes;
- std::set<api::Sort> unresTypes;
- std::map<CVC4::api::Term, CVC4::api::Sort> ntsToUnres;
unsigned dtProcessed = 0;
- std::unordered_set<unsigned> allowConst;
}
:
// predeclaration
@@ -672,24 +656,16 @@ sygusGrammar[CVC4::api::Sort & ret,
RPAREN_TOK
{
// non-terminal symbols in the pre-declaration are locally scoped
- PARSER_STATE->pushScope(true);
+ PARSER_STATE->pushScope();
for (std::pair<std::string, api::Sort>& i : sortedVarNames)
{
- Trace("parser-sygus2") << "Declare datatype " << i.first << std::endl;
- // make the datatype, which encodes terms generated by this non-terminal
- std::string dname = i.first;
- datatypes.push_back(SOLVER->mkDatatypeDecl(dname));
- // make its unresolved type, used for referencing the final version of
- // the datatype
- PARSER_STATE->checkDeclaration(dname, CHECK_UNDECLARED, SYM_SORT);
- api::Sort urt = PARSER_STATE->mkUnresolvedType(dname);
- unresTypes.insert(urt);
+ PARSER_STATE->checkDeclaration(name, CHECK_UNDECLARED, SYM_SORT);
// make the non-terminal symbol, which will be parsed as an ordinary
// free variable.
api::Term nts = PARSER_STATE->bindBoundVar(i.first, i.second);
ntSyms.push_back(nts);
- ntsToUnres[nts] = urt;
}
+ ret = PARSER_STATE->mkGrammar(sygusVars, ntSyms);
}
// the grouped rule listing
LPAREN_TOK
@@ -719,17 +695,15 @@ sygusGrammar[CVC4::api::Sort & ret,
(
term[e,e2] {
// add term as constructor to datatype
- PARSER_STATE->addSygusConstructorTerm(
- datatypes[dtProcessed], e, ntsToUnres);
+ ret->addRule(ntSyms[dtProcessed], e);
}
| LPAREN_TOK SYGUS_CONSTANT_TOK sortSymbol[t, CHECK_DECLARED] RPAREN_TOK {
- // allow constants in datatypes[dtProcessed]
- allowConst.insert(dtProcessed);
+ // allow constants in datatype for ntSyms[dtProcessed]
+ ret->addAnyConstant(ntSyms[dtProcessed]);
}
| LPAREN_TOK SYGUS_VARIABLE_TOK sortSymbol[t, CHECK_DECLARED] RPAREN_TOK {
// add variable constructors to datatype
- PARSER_STATE->addSygusConstructorVariables(
- datatypes[dtProcessed], sygusVars, t);
+ ret->addAnyVariable(ntSyms[dtProcessed]);
}
)+
RPAREN_TOK
@@ -740,45 +714,8 @@ sygusGrammar[CVC4::api::Sort & ret,
)+
RPAREN_TOK
{
- if (dtProcessed != sortedVarNames.size())
- {
- PARSER_STATE->parseError(
- "Number of grouped rule listings does not match "
- "number of symbols in predeclaration.");
- }
- api::Term bvl;
- if (!sygusVars.empty())
- {
- bvl = MK_TERM(api::BOUND_VAR_LIST, sygusVars);
- }
- Trace("parser-sygus2") << "Process " << dtProcessed << " sygus datatypes..." << std::endl;
- for (unsigned i = 0; i < dtProcessed; i++)
- {
- bool aci = allowConst.find(i)!=allowConst.end();
- api::Sort btt = sortedVarNames[i].second;
- datatypes[i].getDatatype().setSygus(btt.getType(), bvl.getExpr(), aci, false);
- Trace("parser-sygus2") << "- " << datatypes[i].getName()
- << ", #cons= " << datatypes[i].getNumConstructors()
- << ", aci= " << aci << std::endl;
- // We can be in a case where the only rule specified was (Variable T)
- // and there are no variables of type T, in which case this is a bogus
- // grammar. This results in the error below.
- if (datatypes[i].getNumConstructors() == 0)
- {
- std::stringstream se;
- se << "Grouped rule listing for " << datatypes[i].getName()
- << " produced an empty rule list.";
- PARSER_STATE->parseError(se.str());
- }
- }
// pop scope from the pre-declaration
PARSER_STATE->popScope();
- // now, make the sygus datatype
- Trace("parser-sygus2") << "Make the sygus datatypes..." << std::endl;
- std::vector<api::Sort> datatypeTypes =
- SOLVER->mkDatatypeSorts(datatypes, unresTypes);
- // return is the first datatype
- ret = api::Sort(datatypeTypes[0]);
}
;
@@ -805,8 +742,9 @@ setOptionInternal[std::unique_ptr<CVC4::Command>* cmd]
// Ugly that this changes the state of the parser; but
// global-declarations affects parsing, so we can't hold off
// on this until some SmtEngine eventually (if ever) executes it.
- if(name == ":global-declarations") {
- PARSER_STATE->setGlobalDeclarations(sexpr.getValue() == "true");
+ if(name == ":global-declarations")
+ {
+ SYM_MAN->setGlobalDeclarations(sexpr.getValue() == "true");
}
}
;
@@ -840,7 +778,7 @@ smt25Command[std::unique_ptr<CVC4::Command>* cmd]
{ // allow overloading here
api::Term c =
PARSER_STATE->bindVar(name, t, ExprManager::VAR_FLAG_NONE, true);
- cmd->reset(new DeclareFunctionCommand(name, c.getExpr(), t.getType())); }
+ cmd->reset(new DeclareFunctionCommand(name, c, t)); }
/* get model */
| GET_MODEL_TOK { PARSER_STATE->checkThatLogicIsSet(); }
@@ -875,7 +813,7 @@ smt25Command[std::unique_ptr<CVC4::Command>* cmd]
func =
PARSER_STATE->bindDefineFunRec(fname, sortedVarNames, t, flattenVars);
PARSER_STATE->pushDefineFunRecScope(
- sortedVarNames, func, flattenVars, bvs, true);
+ sortedVarNames, func, flattenVars, bvs);
}
term[expr, expr2]
{ PARSER_STATE->popScope();
@@ -883,7 +821,7 @@ smt25Command[std::unique_ptr<CVC4::Command>* cmd]
expr = PARSER_STATE->mkHoApply( expr, flattenVars );
}
cmd->reset(new DefineFunctionRecCommand(
- SOLVER, func, bvs, expr, PARSER_STATE->getGlobalDeclarations()));
+ func, bvs, expr, SYM_MAN->getGlobalDeclarations()));
}
| DEFINE_FUNS_REC_TOK
{ PARSER_STATE->checkThatLogicIsSet();}
@@ -919,7 +857,7 @@ smt25Command[std::unique_ptr<CVC4::Command>* cmd]
}
bvs.clear();
PARSER_STATE->pushDefineFunRecScope( sortedVarNamesList[0], funcs[0],
- flattenVarsList[0], bvs, true);
+ flattenVarsList[0], bvs);
}
(
term[expr,expr2]
@@ -936,7 +874,7 @@ smt25Command[std::unique_ptr<CVC4::Command>* cmd]
if( func_defs.size()<funcs.size() ){
bvs.clear();
PARSER_STATE->pushDefineFunRecScope( sortedVarNamesList[j], funcs[j],
- flattenVarsList[j], bvs, true);
+ flattenVarsList[j], bvs);
}
}
)+
@@ -946,12 +884,8 @@ smt25Command[std::unique_ptr<CVC4::Command>* cmd]
"Number of functions defined does not match number listed in "
"define-funs-rec"));
}
- cmd->reset(
- new DefineFunctionRecCommand(SOLVER,
- funcs,
- formals,
- func_defs,
- PARSER_STATE->getGlobalDeclarations()));
+ cmd->reset(new DefineFunctionRecCommand(
+ funcs, formals, func_defs, SYM_MAN->getGlobalDeclarations()));
}
;
@@ -959,13 +893,14 @@ extendedCommand[std::unique_ptr<CVC4::Command>* cmd]
@declarations {
std::vector<api::DatatypeDecl> dts;
CVC4::api::Term e, e2;
- CVC4::api::Sort t;
+ CVC4::api::Sort t, s;
std::string name;
std::vector<std::string> names;
std::vector<CVC4::api::Term> terms;
std::vector<api::Sort> sorts;
std::vector<std::pair<std::string, CVC4::api::Sort> > sortedVarNames;
std::unique_ptr<CVC4::CommandSequence> seq;
+ api::Grammar* g = nullptr;
}
/* Extended SMT-LIB set of commands syntax, not permitted in
* --smtlib2 compliance mode. */
@@ -986,7 +921,7 @@ extendedCommand[std::unique_ptr<CVC4::Command>* cmd]
( symbol[name,CHECK_UNDECLARED,SYM_SORT]
{ PARSER_STATE->checkUserSymbol(name);
api::Sort type = PARSER_STATE->mkSort(name);
- seq->addCommand(new DeclareTypeCommand(name, 0, type.getType()));
+ seq->addCommand(new DeclareSortCommand(name, 0, type));
}
)+
RPAREN_TOK
@@ -1011,8 +946,7 @@ extendedCommand[std::unique_ptr<CVC4::Command>* cmd]
// allow overloading
api::Term func =
PARSER_STATE->bindVar(name, tt, ExprManager::VAR_FLAG_NONE, true);
- seq->addCommand(
- new DeclareFunctionCommand(name, func.getExpr(), tt.getType()));
+ seq->addCommand(new DeclareFunctionCommand(name, func, tt));
sorts.clear();
}
)+
@@ -1032,8 +966,7 @@ extendedCommand[std::unique_ptr<CVC4::Command>* cmd]
// allow overloading
api::Term func =
PARSER_STATE->bindVar(name, t, ExprManager::VAR_FLAG_NONE, true);
- seq->addCommand(
- new DeclareFunctionCommand(name, func.getExpr(), t.getType()));
+ seq->addCommand(new DeclareFunctionCommand(name, func, t));
sorts.clear();
}
)+
@@ -1048,11 +981,8 @@ extendedCommand[std::unique_ptr<CVC4::Command>* cmd]
{
api::Term func = PARSER_STATE->bindVar(name, e.getSort(),
ExprManager::VAR_FLAG_DEFINED);
- cmd->reset(
- new DefineFunctionCommand(name,
- func.getExpr(),
- e.getExpr(),
- PARSER_STATE->getGlobalDeclarations()));
+ cmd->reset(new DefineFunctionCommand(
+ name, func, e, SYM_MAN->getGlobalDeclarations()));
}
| // (define (f (v U) ...) t)
LPAREN_TOK
@@ -1061,7 +991,7 @@ extendedCommand[std::unique_ptr<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(true);
+ PARSER_STATE->pushScope();
terms = PARSER_STATE->bindBoundVars(sortedVarNames);
}
term[e,e2]
@@ -1082,12 +1012,8 @@ extendedCommand[std::unique_ptr<CVC4::Command>* cmd]
}
api::Term func = PARSER_STATE->bindVar(name, tt,
ExprManager::VAR_FLAG_DEFINED);
- cmd->reset(
- new DefineFunctionCommand(name,
- func.getExpr(),
- api::termVectorToExprs(terms),
- e.getExpr(),
- PARSER_STATE->getGlobalDeclarations()));
+ cmd->reset(new DefineFunctionCommand(
+ name, func, terms, e, SYM_MAN->getGlobalDeclarations()));
}
)
| // (define-const x U t)
@@ -1097,7 +1023,7 @@ extendedCommand[std::unique_ptr<CVC4::Command>* cmd]
sortSymbol[t,CHECK_DECLARED]
{ /* add variables to parser state before parsing term */
Debug("parser") << "define const: '" << name << "'" << std::endl;
- PARSER_STATE->pushScope(true);
+ PARSER_STATE->pushScope();
terms = PARSER_STATE->bindBoundVars(sortedVarNames);
}
term[e, e2]
@@ -1108,33 +1034,29 @@ extendedCommand[std::unique_ptr<CVC4::Command>* cmd]
// permitted)
api::Term func = PARSER_STATE->bindVar(name, t,
ExprManager::VAR_FLAG_DEFINED);
- cmd->reset(
- new DefineFunctionCommand(name,
- func.getExpr(),
- api::termVectorToExprs(terms),
- e.getExpr(),
- PARSER_STATE->getGlobalDeclarations()));
+ cmd->reset(new DefineFunctionCommand(
+ name, func, terms, e, SYM_MAN->getGlobalDeclarations()));
}
| SIMPLIFY_TOK { PARSER_STATE->checkThatLogicIsSet(); }
term[e,e2]
- { cmd->reset(new SimplifyCommand(e.getExpr())); }
+ { cmd->reset(new SimplifyCommand(e)); }
| GET_QE_TOK { PARSER_STATE->checkThatLogicIsSet(); }
term[e,e2]
- { cmd->reset(new GetQuantifierEliminationCommand(e.getExpr(), true)); }
+ { cmd->reset(new GetQuantifierEliminationCommand(e, true)); }
| GET_QE_DISJUNCT_TOK { PARSER_STATE->checkThatLogicIsSet(); }
term[e,e2]
- { cmd->reset(new GetQuantifierEliminationCommand(e.getExpr(), false)); }
+ { cmd->reset(new GetQuantifierEliminationCommand(e, false)); }
| GET_ABDUCT_TOK {
PARSER_STATE->checkThatLogicIsSet();
}
symbol[name,CHECK_UNDECLARED,SYM_VARIABLE]
term[e,e2]
(
- sygusGrammar[t, terms, name]
+ sygusGrammar[g, terms, name]
)?
{
- cmd->reset(new GetAbductCommand(name,e.getExpr(), t.getType()));
+ cmd->reset(new GetAbductCommand(name, e, g));
}
| GET_INTERPOL_TOK {
PARSER_STATE->checkThatLogicIsSet();
@@ -1142,23 +1064,22 @@ extendedCommand[std::unique_ptr<CVC4::Command>* cmd]
symbol[name,CHECK_UNDECLARED,SYM_VARIABLE]
term[e,e2]
(
- sygusGrammar[t, terms, name]
+ sygusGrammar[g, terms, name]
)?
{
- cmd->reset(new GetInterpolCommand(SOLVER, name, e, t.getType()));
+ cmd->reset(new GetInterpolCommand(name, e, g));
}
| DECLARE_HEAP LPAREN_TOK
sortSymbol[t, CHECK_DECLARED]
- sortSymbol[t, CHECK_DECLARED]
- // We currently do nothing with the type information declared for the heap.
- { cmd->reset(new EmptyCommand()); }
+ sortSymbol[s, CHECK_DECLARED]
+ { cmd->reset(new DeclareHeapCommand(t, s)); }
RPAREN_TOK
| BLOCK_MODEL_TOK { PARSER_STATE->checkThatLogicIsSet(); }
{ cmd->reset(new BlockModelCommand()); }
| BLOCK_MODEL_VALUES_TOK { PARSER_STATE->checkThatLogicIsSet(); }
( LPAREN_TOK termList[terms,e] RPAREN_TOK
- { cmd->reset(new BlockModelValuesCommand(api::termVectorToExprs(terms))); }
+ { cmd->reset(new BlockModelValuesCommand(terms)); }
| ~LPAREN_TOK
{ PARSER_STATE->parseError("The block-model-value command expects a list "
"of terms. Perhaps you forgot a pair of "
@@ -1178,7 +1099,7 @@ datatypes_2_5_DefCommand[bool isCo, std::unique_ptr<CVC4::Command>* cmd]
}
: { PARSER_STATE->checkThatLogicIsSet();
/* open a scope to keep the UnresolvedTypes contained */
- PARSER_STATE->pushScope(true); }
+ PARSER_STATE->pushScope(); }
LPAREN_TOK /* parametric sorts */
( symbol[name,CHECK_UNDECLARED,SYM_SORT]
{
@@ -1189,8 +1110,7 @@ datatypes_2_5_DefCommand[bool isCo, std::unique_ptr<CVC4::Command>* cmd]
LPAREN_TOK ( LPAREN_TOK datatypeDef[isCo, dts, sorts] RPAREN_TOK )+ RPAREN_TOK
{ PARSER_STATE->popScope();
cmd->reset(new DatatypeDeclarationCommand(
- api::sortVectorToTypes(
- PARSER_STATE->bindMutualDatatypeTypes(dts, true))));
+ PARSER_STATE->bindMutualDatatypeTypes(dts, true)));
}
;
@@ -1249,7 +1169,7 @@ datatypesDef[bool isCo,
std::string name;
std::vector<api::Sort> params;
}
- : { PARSER_STATE->pushScope(true);
+ : { PARSER_STATE->pushScope();
// Declare the datatypes that are currently being defined as unresolved
// types. If we do not know the arity of the datatype yet, we wait to
// define it until parsing the preamble of its body, which may optionally
@@ -1276,7 +1196,7 @@ datatypesDef[bool isCo,
PARSER_STATE->parseError("Too many datatypes defined in this block.");
}
}
- ( PAR_TOK { PARSER_STATE->pushScope(true); } LPAREN_TOK
+ ( PAR_TOK { PARSER_STATE->pushScope(); } LPAREN_TOK
( symbol[name,CHECK_UNDECLARED,SYM_SORT]
{
params.push_back( PARSER_STATE->mkSort(name, ExprManager::SORT_FLAG_PLACEHOLDER)); }
@@ -1316,10 +1236,13 @@ datatypesDef[bool isCo,
RPAREN_TOK
)+
{
+ if (dts.size() != dnames.size())
+ {
+ PARSER_STATE->parseError("Wrong number of datatypes provided.");
+ }
PARSER_STATE->popScope();
cmd->reset(new DatatypeDeclarationCommand(
- api::sortVectorToTypes(
- PARSER_STATE->bindMutualDatatypeTypes(dts, true))));
+ PARSER_STATE->bindMutualDatatypeTypes(dts, true)));
}
;
@@ -1434,7 +1357,7 @@ termNonVariable[CVC4::api::Term& expr, CVC4::api::Term& expr2]
{
PARSER_STATE->parseError("Quantifier used in non-quantified logic.");
}
- PARSER_STATE->pushScope(true);
+ PARSER_STATE->pushScope();
}
boundVarList[bvl]
term[f, f2] RPAREN_TOK
@@ -1449,7 +1372,7 @@ termNonVariable[CVC4::api::Term& expr, CVC4::api::Term& expr2]
expr = MK_TERM(kind, args);
}
| LPAREN_TOK COMPREHENSION_TOK
- { PARSER_STATE->pushScope(true); }
+ { PARSER_STATE->pushScope(); }
boundVarList[bvl]
{
args.push_back(bvl);
@@ -1468,7 +1391,7 @@ termNonVariable[CVC4::api::Term& expr, CVC4::api::Term& expr2]
| /* a let or sygus let binding */
LPAREN_TOK
LET_TOK LPAREN_TOK
- { PARSER_STATE->pushScope(true); }
+ { PARSER_STATE->pushScope(); }
( LPAREN_TOK symbol[name,CHECK_NONE,SYM_VARIABLE]
term[expr, f2]
RPAREN_TOK
@@ -1506,7 +1429,7 @@ termNonVariable[CVC4::api::Term& expr, CVC4::api::Term& expr2]
// case with non-nullary pattern
LPAREN_TOK LPAREN_TOK term[f, f2] {
args.clear();
- PARSER_STATE->pushScope(true);
+ PARSER_STATE->pushScope();
// f should be a constructor
type = f.getSort();
Debug("parser-dt") << "Pattern head : " << f << " " << type << std::endl;
@@ -1514,13 +1437,14 @@ termNonVariable[CVC4::api::Term& expr, CVC4::api::Term& expr2]
{
PARSER_STATE->parseError("Pattern must be application of a constructor or a variable.");
}
- Expr ef = f.getExpr();
- if (Datatype::datatypeOf(ef).isParametric())
+ api::Datatype dt = type.getConstructorCodomainSort().getDatatype();
+ if (dt.isParametric())
{
- type = api::Sort(
- SOLVER,
- Datatype::datatypeOf(ef)[Datatype::indexOf(ef)]
- .getSpecializedConstructorType(expr.getSort().getType()));
+ // lookup constructor by name
+ api::DatatypeConstructor dc = dt.getConstructor(f.toString());
+ api::Term scons = dc.getSpecializedConstructorTerm(expr.getSort());
+ // take the type of the specialized constructor instead
+ type = scons.getSort();
}
argTypes = type.getConstructorDomainSorts();
}
@@ -1624,7 +1548,7 @@ termNonVariable[CVC4::api::Term& expr, CVC4::api::Term& expr2]
}
| /* lambda */
LPAREN_TOK HO_LAMBDA_TOK
- { PARSER_STATE->pushScope(true); }
+ { PARSER_STATE->pushScope(); }
boundVarList[bvl]
term[f, f2] RPAREN_TOK
{
@@ -1765,7 +1689,7 @@ identifier[CVC4::ParseOp& p]
// we adopt a special syntax (_ tupSel n)
p.d_kind = api::APPLY_SELECTOR;
// put m in expr so that the caller can deal with this case
- p.d_expr = SOLVER->mkReal(AntlrInput::tokenToUnsigned($m));
+ p.d_expr = SOLVER->mkInteger(AntlrInput::tokenToUnsigned($m));
}
| sym=SIMPLE_SYMBOL nonemptyNumeralList[numerals]
{
@@ -1790,7 +1714,7 @@ termAtomic[CVC4::api::Term& atomTerm]
: INTEGER_LITERAL
{
std::string intStr = AntlrInput::tokenText($INTEGER_LITERAL);
- atomTerm = SOLVER->mkReal(intStr);
+ atomTerm = SOLVER->mkInteger(intStr);
}
| DECIMAL_LITERAL
{
@@ -1885,7 +1809,7 @@ attribute[CVC4::api::Term& expr, CVC4::api::Term& retExpr, std::string& attr]
{
std::stringstream sIntLit;
sIntLit << $INTEGER_LITERAL;
- api::Term n = SOLVER->mkReal(sIntLit.str());
+ api::Term n = SOLVER->mkInteger(sIntLit.str());
std::vector<api::Term> values;
values.push_back( n );
std::string attr_name(AntlrInput::tokenText($tok));
@@ -1893,8 +1817,7 @@ attribute[CVC4::api::Term& expr, CVC4::api::Term& retExpr, std::string& attr]
api::Sort boolType = SOLVER->getBooleanSort();
api::Term avar = PARSER_STATE->bindVar(attr_name, boolType);
retExpr = MK_TERM(api::INST_ATTRIBUTE, avar);
- Command* c = new SetUserAttributeCommand(
- attr_name, avar.getExpr(), api::termVectorToExprs(values));
+ Command* c = new SetUserAttributeCommand(attr_name, avar, values);
c->setMuted(true);
PARSER_STATE->preemptCommand(c);
}
@@ -1904,20 +1827,15 @@ attribute[CVC4::api::Term& expr, CVC4::api::Term& retExpr, std::string& attr]
api::Term avar = SOLVER->mkConst(boolType, sexpr.toString());
attr = std::string(":qid");
retExpr = MK_TERM(api::INST_ATTRIBUTE, avar);
- Command* c = new SetUserAttributeCommand("qid", avar.getExpr());
+ Command* c = new SetUserAttributeCommand("qid", avar);
c->setMuted(true);
PARSER_STATE->preemptCommand(c);
}
| ATTRIBUTE_NAMED_TOK symbolicExpr[sexpr]
{
attr = std::string(":named");
- api::Term func = PARSER_STATE->setNamedAttribute(expr, sexpr);
- std::string name = sexpr.getValue();
- // bind name to expr with define-fun
- Command* c = new DefineNamedFunctionCommand(
- name, func.getExpr(), std::vector<Expr>(), expr.getExpr(), PARSER_STATE->getGlobalDeclarations());
- c->setMuted(true);
- PARSER_STATE->preemptCommand(c);
+ // notify that expression was given a name
+ PARSER_STATE->notifyNamedExpression(expr, sexpr.getValue());
}
;
@@ -2132,7 +2050,15 @@ sortSymbol[CVC4::api::Sort& t, CVC4::parser::DeclarationCheck check]
PARSER_STATE->parseError("Illegal set type.");
}
t = SOLVER->mkSetSort( args[0] );
- } else if(name == "Seq" && !PARSER_STATE->strictModeEnabled() &&
+ }
+ else if(name == "Bag" &&
+ PARSER_STATE->isTheoryEnabled(theory::THEORY_BAGS) ) {
+ if(args.size() != 1) {
+ PARSER_STATE->parseError("Illegal bag type.");
+ }
+ t = SOLVER->mkBagSort( args[0] );
+ }
+ else if(name == "Seq" && !PARSER_STATE->strictModeEnabled() &&
PARSER_STATE->isTheoryEnabled(theory::THEORY_STRINGS) ) {
if(args.size() != 1) {
PARSER_STATE->parseError("Illegal sequence type.");
@@ -2240,7 +2166,7 @@ datatypeDef[bool isCo, std::vector<CVC4::api::DatatypeDecl>& datatypes,
* 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(true); }
+ : symbol[id,CHECK_NONE,SYM_SORT] { PARSER_STATE->pushScope(); }
{
datatypes.push_back(SOLVER->mkDatatypeDecl(id, params, isCo));
}
diff --git a/src/parser/smt2/smt2.cpp b/src/parser/smt2/smt2.cpp
index 69c4eabfd..b9279fcb0 100644
--- a/src/parser/smt2/smt2.cpp
+++ b/src/parser/smt2/smt2.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -32,17 +32,20 @@
namespace CVC4 {
namespace parser {
-Smt2::Smt2(api::Solver* solver, Input* input, bool strictMode, bool parseOnly)
- : Parser(solver, input, strictMode, parseOnly),
+Smt2::Smt2(api::Solver* solver,
+ SymbolManager* sm,
+ Input* input,
+ bool strictMode,
+ bool parseOnly)
+ : Parser(solver, sm, input, strictMode, parseOnly),
d_logicSet(false),
d_seenSetLogic(false)
{
- if (!strictModeEnabled())
- {
- addCoreSymbols();
- }
+ pushScope(true);
}
+Smt2::~Smt2() { popScope(); }
+
void Smt2::addArithmeticOperators() {
addOperator(api::PLUS, "+");
addOperator(api::MINUS, "-");
@@ -181,6 +184,7 @@ void Smt2::addStringOperators() {
addOperator(api::SEQ_REV, "seq.rev");
addOperator(api::SEQ_REPLACE_ALL, "seq.replace_all");
addOperator(api::SEQ_UNIT, "seq.unit");
+ addOperator(api::SEQ_NTH, "seq.nth");
}
// at the moment, we only use this syntax for smt2.6
if (getLanguage() == language::input::LANG_SMTLIB_V2_6
@@ -287,9 +291,9 @@ void Smt2::addSepOperators() {
void Smt2::addCoreSymbols()
{
- defineType("Bool", d_solver->getBooleanSort());
- defineVar("true", d_solver->mkTrue());
- defineVar("false", d_solver->mkFalse());
+ defineType("Bool", d_solver->getBooleanSort(), true, true);
+ defineVar("true", d_solver->mkTrue(), true, true);
+ defineVar("false", d_solver->mkFalse(), true, true);
addOperator(api::AND, "and");
addOperator(api::DISTINCT, "distinct");
addOperator(api::EQUAL, "=");
@@ -448,10 +452,9 @@ void Smt2::pushDefineFunRecScope(
const std::vector<std::pair<std::string, api::Sort>>& sortedVarNames,
api::Term func,
const std::vector<api::Term>& flattenVars,
- std::vector<api::Term>& bvs,
- bool bindingLevel)
+ std::vector<api::Term>& bvs)
{
- pushScope(bindingLevel);
+ pushScope();
// bound variables are those that are explicitly named in the preamble
// of the define-fun(s)-rec command, we define them here
@@ -471,10 +474,7 @@ void Smt2::reset() {
operatorKindMap.clear();
d_lastNamedTerm = std::pair<api::Term, std::string>();
this->Parser::reset();
-
- if( !strictModeEnabled() ) {
- addCoreSymbols();
- }
+ pushScope(true);
}
void Smt2::resetAssertions() {
@@ -482,55 +482,7 @@ void Smt2::resetAssertions() {
while (this->scopeLevel() > 0) {
this->popScope();
}
-}
-
-Smt2::SynthFunFactory::SynthFunFactory(
- Smt2* smt2,
- const std::string& fun,
- bool isInv,
- api::Sort range,
- std::vector<std::pair<std::string, api::Sort>>& sortedVarNames)
- : d_smt2(smt2), d_fun(fun), d_isInv(isInv)
-{
- if (range.isNull())
- {
- smt2->parseError("Must supply return type for synth-fun.");
- }
- if (range.isFunction())
- {
- smt2->parseError("Cannot use synth-fun with function return type.");
- }
- std::vector<api::Sort> varSorts;
- for (const std::pair<std::string, api::Sort>& p : sortedVarNames)
- {
- varSorts.push_back(p.second);
- }
- Debug("parser-sygus") << "Define synth fun : " << fun << std::endl;
- api::Sort synthFunType =
- varSorts.size() > 0 ? d_smt2->getSolver()->mkFunctionSort(varSorts, range)
- : range;
-
- // we do not allow overloading for synth fun
- d_synthFun = d_smt2->bindBoundVar(fun, synthFunType);
- // set the sygus type to be range by default, which is overwritten below
- // if a grammar is provided
- d_sygusType = range;
-
- d_smt2->pushScope(true);
- d_sygusVars = d_smt2->bindBoundVars(sortedVarNames);
-}
-
-Smt2::SynthFunFactory::~SynthFunFactory() { d_smt2->popScope(); }
-
-std::unique_ptr<Command> Smt2::SynthFunFactory::mkCommand(api::Sort grammar)
-{
- Debug("parser-sygus") << "...read synth fun " << d_fun << std::endl;
- return std::unique_ptr<Command>(new SynthFunCommand(
- d_fun,
- d_synthFun.getExpr(),
- grammar.isNull() ? d_sygusType.getType() : grammar.getType(),
- d_isInv,
- api::termVectorToExprs(d_sygusVars)));
+ pushScope(true);
}
std::unique_ptr<Command> Smt2::invConstraint(
@@ -560,8 +512,7 @@ std::unique_ptr<Command> Smt2::invConstraint(
terms.push_back(getVariable(name));
}
- return std::unique_ptr<Command>(
- new SygusInvConstraintCommand(api::termVectorToExprs(terms)));
+ return std::unique_ptr<Command>(new SygusInvConstraintCommand(terms));
}
Command* Smt2::setLogic(std::string name, bool fromCommand)
@@ -609,7 +560,7 @@ Command* Smt2::setLogic(std::string name, bool fromCommand)
if(d_logic.isTheoryEnabled(theory::THEORY_ARITH)) {
if(d_logic.areIntegersUsed()) {
- defineType("Int", d_solver->getIntegerSort());
+ defineType("Int", d_solver->getIntegerSort(), true, true);
addArithmeticOperators();
addOperator(api::INTS_DIVISION, "div");
addOperator(api::INTS_MODULUS, "mod");
@@ -619,7 +570,7 @@ Command* Smt2::setLogic(std::string name, bool fromCommand)
if (d_logic.areRealsUsed())
{
- defineType("Real", d_solver->getRealSort());
+ defineType("Real", d_solver->getRealSort(), true, true);
addArithmeticOperators();
addOperator(api::DIVISION, "/");
if (!strictModeEnabled())
@@ -668,7 +619,7 @@ Command* Smt2::setLogic(std::string name, bool fromCommand)
if(d_logic.isTheoryEnabled(theory::THEORY_DATATYPES)) {
const std::vector<api::Sort> types;
- defineType("Tuple", d_solver->mkTupleSort(types));
+ defineType("Tuple", d_solver->mkTupleSort(types), true, true);
addDatatypesOperators();
}
@@ -688,16 +639,35 @@ Command* Smt2::setLogic(std::string name, bool fromCommand)
addOperator(api::CARD, "card");
addOperator(api::COMPLEMENT, "complement");
addOperator(api::CHOOSE, "choose");
+ addOperator(api::IS_SINGLETON, "is_singleton");
addOperator(api::JOIN, "join");
addOperator(api::PRODUCT, "product");
addOperator(api::TRANSPOSE, "transpose");
addOperator(api::TCLOSURE, "tclosure");
}
+ if (d_logic.isTheoryEnabled(theory::THEORY_BAGS))
+ {
+ defineVar("emptybag", d_solver->mkEmptyBag(d_solver->getNullSort()));
+ addOperator(api::UNION_MAX, "union_max");
+ addOperator(api::UNION_DISJOINT, "union_disjoint");
+ addOperator(api::INTERSECTION_MIN, "intersection_min");
+ addOperator(api::DIFFERENCE_SUBTRACT, "difference_subtract");
+ addOperator(api::DIFFERENCE_REMOVE, "difference_remove");
+ addOperator(api::SUBBAG, "bag.is_included");
+ addOperator(api::BAG_COUNT, "bag.count");
+ addOperator(api::DUPLICATE_REMOVAL, "duplicate_removal");
+ addOperator(api::MK_BAG, "bag");
+ addOperator(api::BAG_CARD, "bag.card");
+ addOperator(api::BAG_CHOOSE, "bag.choose");
+ addOperator(api::BAG_IS_SINGLETON, "bag.is_singleton");
+ addOperator(api::BAG_FROM_SET, "bag.from_set");
+ addOperator(api::BAG_TO_SET, "bag.to_set");
+ }
if(d_logic.isTheoryEnabled(theory::THEORY_STRINGS)) {
- defineType("String", d_solver->getStringSort());
- defineType("RegLan", d_solver->getRegExpSort());
- defineType("Int", d_solver->getIntegerSort());
+ defineType("String", d_solver->getStringSort(), true, true);
+ defineType("RegLan", d_solver->getRegExpSort(), true, true);
+ defineType("Int", d_solver->getIntegerSort(), true, true);
if (getLanguage() == language::input::LANG_SMTLIB_V2_6
|| getLanguage() == language::input::LANG_SYGUS_V2)
@@ -722,11 +692,11 @@ Command* Smt2::setLogic(std::string name, bool fromCommand)
}
if (d_logic.isTheoryEnabled(theory::THEORY_FP)) {
- defineType("RoundingMode", d_solver->getRoundingmodeSort());
- defineType("Float16", d_solver->mkFloatingPointSort(5, 11));
- defineType("Float32", d_solver->mkFloatingPointSort(8, 24));
- defineType("Float64", d_solver->mkFloatingPointSort(11, 53));
- defineType("Float128", d_solver->mkFloatingPointSort(15, 113));
+ defineType("RoundingMode", d_solver->getRoundingModeSort(), true, true);
+ defineType("Float16", d_solver->mkFloatingPointSort(5, 11), true, true);
+ defineType("Float32", d_solver->mkFloatingPointSort(8, 24), true, true);
+ defineType("Float64", d_solver->mkFloatingPointSort(11, 53), true, true);
+ defineType("Float128", d_solver->mkFloatingPointSort(15, 113), true, true);
defineVar("RNE", d_solver->mkRoundingMode(api::ROUND_NEAREST_TIES_TO_EVEN));
defineVar("roundNearestTiesToEven",
@@ -761,6 +731,14 @@ Command* Smt2::setLogic(std::string name, bool fromCommand)
return cmd;
} /* Smt2::setLogic() */
+api::Grammar* Smt2::mkGrammar(const std::vector<api::Term>& boundVars,
+ const std::vector<api::Term>& ntSymbols)
+{
+ d_allocGrammars.emplace_back(
+ new api::Grammar(d_solver->mkSygusGrammar(boundVars, ntSymbols)));
+ return d_allocGrammars.back().get();
+}
+
bool Smt2::sygus() const
{
InputLanguage ilang = getLanguage();
@@ -816,7 +794,8 @@ void Smt2::checkLogicAllowsFreeSorts()
if (!d_logic.isTheoryEnabled(theory::THEORY_UF)
&& !d_logic.isTheoryEnabled(theory::THEORY_ARRAYS)
&& !d_logic.isTheoryEnabled(theory::THEORY_DATATYPES)
- && !d_logic.isTheoryEnabled(theory::THEORY_SETS))
+ && !d_logic.isTheoryEnabled(theory::THEORY_SETS)
+ && !d_logic.isTheoryEnabled(theory::THEORY_BAGS))
{
parseErrorLogic("Free sort symbols not allowed in ");
}
@@ -905,99 +884,6 @@ api::Term Smt2::mkAbstractValue(const std::string& name)
return d_solver->mkAbstractValue(name.substr(1));
}
-
-void Smt2::addSygusConstructorTerm(
- api::DatatypeDecl& dt,
- api::Term term,
- std::map<api::Term, api::Sort>& ntsToUnres) const
-{
- Trace("parser-sygus2") << "Add sygus cons term " << term << std::endl;
- // At this point, we should know that dt is well founded, and that its
- // builtin sygus operators are well-typed.
- // Now, purify each occurrence of a non-terminal symbol in term, replace by
- // free variables. These become arguments to constructors. Notice we must do
- // a tree traversal in this function, since unique paths to the same term
- // should be treated as distinct terms.
- // Notice that let expressions are forbidden in the input syntax of term, so
- // this does not lead to exponential behavior with respect to input size.
- std::vector<api::Term> args;
- std::vector<api::Sort> cargs;
- api::Term op = purifySygusGTerm(term, ntsToUnres, args, cargs);
- std::stringstream ssCName;
- ssCName << op.getKind();
- Trace("parser-sygus2") << "Purified operator " << op
- << ", #args/cargs=" << args.size() << "/"
- << cargs.size() << std::endl;
- if (!args.empty())
- {
- api::Term lbvl = d_solver->mkTerm(api::BOUND_VAR_LIST, args);
- // its operator is a lambda
- op = d_solver->mkTerm(api::LAMBDA, lbvl, op);
- }
- Trace("parser-sygus2") << "addSygusConstructor: operator " << op
- << std::endl;
- dt.getDatatype().addSygusConstructor(
- op.getExpr(), ssCName.str(), api::sortVectorToTypes(cargs));
-}
-
-api::Term Smt2::purifySygusGTerm(api::Term term,
- std::map<api::Term, api::Sort>& ntsToUnres,
- std::vector<api::Term>& args,
- std::vector<api::Sort>& cargs) const
-{
- Trace("parser-sygus2-debug")
- << "purifySygusGTerm: " << term
- << " #nchild=" << term.getExpr().getNumChildren() << std::endl;
- std::map<api::Term, api::Sort>::iterator itn = ntsToUnres.find(term);
- if (itn != ntsToUnres.end())
- {
- api::Term ret = d_solver->mkVar(term.getSort());
- Trace("parser-sygus2-debug")
- << "...unresolved non-terminal, intro " << ret << std::endl;
- args.push_back(api::Term(d_solver, ret.getExpr()));
- cargs.push_back(itn->second);
- return ret;
- }
- std::vector<api::Term> pchildren;
- bool childChanged = false;
- for (unsigned i = 0, nchild = term.getNumChildren(); i < nchild; i++)
- {
- Trace("parser-sygus2-debug")
- << "......purify child " << i << " : " << term[i] << std::endl;
- api::Term ptermc = purifySygusGTerm(term[i], ntsToUnres, args, cargs);
- pchildren.push_back(ptermc);
- childChanged = childChanged || ptermc != term[i];
- }
- if (!childChanged)
- {
- Trace("parser-sygus2-debug") << "...no child changed" << std::endl;
- return term;
- }
- api::Term nret = d_solver->mkTerm(term.getOp(), pchildren);
- Trace("parser-sygus2-debug")
- << "...child changed, return " << nret << std::endl;
- return nret;
-}
-
-void Smt2::addSygusConstructorVariables(api::DatatypeDecl& dt,
- const std::vector<api::Term>& sygusVars,
- api::Sort type) const
-{
- // each variable of appropriate type becomes a sygus constructor in dt.
- for (unsigned i = 0, size = sygusVars.size(); i < size; i++)
- {
- api::Term v = sygusVars[i];
- if (v.getSort() == type)
- {
- std::stringstream ss;
- ss << v;
- std::vector<api::Sort> cargs;
- dt.getDatatype().addSygusConstructor(
- v.getExpr(), ss.str(), api::sortVectorToTypes(cargs));
- }
- }
-}
-
InputLanguage Smt2::getLanguage() const
{
return d_solver->getOptions().getInputLanguage();
@@ -1172,33 +1058,22 @@ api::Term Smt2::applyParseOp(ParseOp& p, std::vector<api::Term>& args)
parseError("Too many arguments to array constant.");
}
api::Term constVal = args[0];
- if (!constVal.isConst())
+
+ // To parse array constants taking reals whose values are specified by
+ // rationals, e.g. ((as const (Array Int Real)) (/ 1 3)), we must handle
+ // the fact that (/ 1 3) is the division of constants 1 and 3, and not
+ // the resulting constant rational value. Thus, we must construct the
+ // resulting rational here. This also is applied for integral real values
+ // like 5.0 which are converted to (/ 5 1) to distinguish them from
+ // integer constants. We must ensure numerator and denominator are
+ // constant and the denominator is non-zero.
+ if (constVal.getKind() == api::DIVISION)
{
- // To parse array constants taking reals whose values are specified by
- // rationals, e.g. ((as const (Array Int Real)) (/ 1 3)), we must handle
- // the fact that (/ 1 3) is the division of constants 1 and 3, and not
- // the resulting constant rational value. Thus, we must construct the
- // resulting rational here. This also is applied for integral real values
- // like 5.0 which are converted to (/ 5 1) to distinguish them from
- // integer constants. We must ensure numerator and denominator are
- // constant and the denominator is non-zero.
- if (constVal.getKind() == api::DIVISION && constVal[0].isConst()
- && constVal[1].isConst()
- && !constVal[1].getExpr().getConst<Rational>().isZero())
- {
- std::stringstream sdiv;
- sdiv << constVal[0] << "/" << constVal[1];
- constVal = d_solver->mkReal(sdiv.str());
- }
- if (!constVal.isConst())
- {
- std::stringstream ss;
- ss << "expected constant term inside array constant, but found "
- << "nonconstant term:" << std::endl
- << "the term: " << constVal;
- parseError(ss.str());
- }
+ std::stringstream sdiv;
+ sdiv << constVal[0] << "/" << constVal[1];
+ constVal = d_solver->mkReal(sdiv.str());
}
+
if (!p.d_type.getArrayElementSort().isComparableTo(constVal.getSort()))
{
std::stringstream ss;
@@ -1238,11 +1113,9 @@ api::Term Smt2::applyParseOp(ParseOp& p, std::vector<api::Term>& args)
ss << "tuple is of length " << length << "; cannot access index " << n;
parseError(ss.str());
}
- const Datatype& dt = ((DatatypeType)t.getType()).getDatatype();
- api::Term ret =
- d_solver->mkTerm(api::APPLY_SELECTOR,
- api::Term(d_solver, dt[0][n].getSelector()),
- args[0]);
+ const api::Datatype& dt = t.getDatatype();
+ api::Term ret = d_solver->mkTerm(
+ api::APPLY_SELECTOR, dt[0][n].getSelectorTerm(), args[0]);
Debug("parser") << "applyParseOp: return selector " << ret << std::endl;
return ret;
}
@@ -1291,6 +1164,12 @@ api::Term Smt2::applyParseOp(ParseOp& p, std::vector<api::Term>& args)
parseError(
"eqrange predicate requires option --arrays-exp to be enabled.");
}
+ if (kind == api::SINGLETON && args.size() == 1)
+ {
+ api::Term ret = d_solver->mkTerm(api::SINGLETON, args[0]);
+ Debug("parser") << "applyParseOp: return singleton " << ret << std::endl;
+ return ret;
+ }
api::Term ret = d_solver->mkTerm(kind, args);
Debug("parser") << "applyParseOp: return default builtin " << ret
<< std::endl;
@@ -1339,28 +1218,16 @@ api::Term Smt2::applyParseOp(ParseOp& p, std::vector<api::Term>& args)
return ret;
}
-api::Term Smt2::setNamedAttribute(api::Term& expr, const SExpr& sexpr)
+void Smt2::notifyNamedExpression(api::Term& expr, std::string name)
{
- if (!sexpr.isKeyword())
- {
- parseError("improperly formed :named annotation");
- }
- std::string name = sexpr.getValue();
checkUserSymbol(name);
- // ensure expr is a closed subterm
- if (expr.getExpr().hasFreeVariable())
- {
- std::stringstream ss;
- ss << ":named annotations can only name terms that are closed";
- parseError(ss.str());
- }
- // check that sexpr is a fresh function symbol, and reserve it
- reserveSymbolAtAssertionLevel(name);
- // define it
- api::Term func = bindVar(name, expr.getSort(), ExprManager::VAR_FLAG_DEFINED);
- // remember the last term to have been given a :named attribute
+ // remember the expression name in the symbol manager
+ getSymbolManager()->setExpressionName(expr, name, false);
+ // define the variable
+ defineVar(name, expr);
+ // set the last named term, which ensures that we catch when assertions are
+ // named
setLastNamedTerm(expr, name);
- return func;
}
api::Term Smt2::mkAnd(const std::vector<api::Term>& es)
diff --git a/src/parser/smt2/smt2.h b/src/parser/smt2/smt2.h
index 579fa90ce..fd08ab241 100644
--- a/src/parser/smt2/smt2.h
+++ b/src/parser/smt2/smt2.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -28,12 +28,12 @@
#include "api/cvc4cpp.h"
#include "parser/parse_op.h"
#include "parser/parser.h"
-#include "smt/command.h"
#include "theory/logic_info.h"
#include "util/abstract_value.h"
namespace CVC4 {
+class Command;
class SExpr;
namespace api {
@@ -60,14 +60,22 @@ class Smt2 : public Parser
*/
std::unordered_map<std::string, api::Kind> d_indexedOpKindMap;
std::pair<api::Term, std::string> d_lastNamedTerm;
+ /**
+ * A list of sygus grammar objects. We keep track of them here to ensure that
+ * they don't get deleted before the commands using them get invoked.
+ */
+ std::vector<std::unique_ptr<api::Grammar>> d_allocGrammars;
protected:
Smt2(api::Solver* solver,
+ SymbolManager* sm,
Input* input,
bool strictMode = false,
bool parseOnly = false);
public:
+ ~Smt2();
+
/**
* Add core theory symbols to the parser state.
*/
@@ -161,7 +169,7 @@ class Smt2 : public Parser
/** Push scope for define-fun-rec
*
- * This calls Parser::pushScope(bindingLevel) and sets up
+ * This calls Parser::pushScope() and sets up
* initial information for reading a body of a function definition
* in the define-fun-rec and define-funs-rec command.
* The input parameters func/flattenVars are the result
@@ -172,7 +180,7 @@ class Smt2 : public Parser
* flattenVars : the implicit variables introduced when defining func.
*
* This function:
- * (1) Calls Parser::pushScope(bindingLevel).
+ * (1) Calls Parser::pushScope().
* (2) Computes the bound variable list for the quantified formula
* that defined this definition and stores it in bvs.
*/
@@ -180,58 +188,13 @@ class Smt2 : public Parser
const std::vector<std::pair<std::string, api::Sort>>& sortedVarNames,
api::Term func,
const std::vector<api::Term>& flattenVars,
- std::vector<api::Term>& bvs,
- bool bindingLevel = false);
+ std::vector<api::Term>& bvs);
void reset() override;
void resetAssertions();
/**
- * Class for creating instances of `SynthFunCommand`s. Creating an instance
- * of this class pushes the scope, destroying it pops the scope.
- */
- class SynthFunFactory
- {
- public:
- /**
- * Creates an instance of `SynthFunFactory`.
- *
- * @param smt2 Pointer to the parser state
- * @param fun Name of the function to synthesize
- * @param isInv True if the goal is to synthesize an invariant, false
- * otherwise
- * @param range The return type of the function-to-synthesize
- * @param sortedVarNames The parameters of the function-to-synthesize
- */
- SynthFunFactory(
- Smt2* smt2,
- const std::string& fun,
- bool isInv,
- api::Sort range,
- std::vector<std::pair<std::string, api::Sort>>& sortedVarNames);
- ~SynthFunFactory();
-
- const std::vector<api::Term>& getSygusVars() const { return d_sygusVars; }
-
- /**
- * Create an instance of `SynthFunCommand`.
- *
- * @param grammar Optional grammar associated with the synth-fun command
- * @return The instance of `SynthFunCommand`
- */
- std::unique_ptr<Command> mkCommand(api::Sort grammar);
-
- private:
- Smt2* d_smt2;
- std::string d_fun;
- api::Term d_synthFun;
- api::Sort d_sygusType;
- bool d_isInv;
- std::vector<api::Term> d_sygusVars;
- };
-
- /**
* Creates a command that adds an invariant constraint.
*
* @param names Name of four symbols corresponding to the
@@ -257,6 +220,15 @@ class Smt2 : public Parser
*/
const LogicInfo& getLogic() const { return d_logic; }
+ /**
+ * Create a Sygus grammar.
+ * @param boundVars the parameters to corresponding synth-fun/synth-inv
+ * @param ntSymbols the pre-declaration of the non-terminal symbols
+ * @return a pointer to the grammar
+ */
+ api::Grammar* mkGrammar(const std::vector<api::Term>& boundVars,
+ const std::vector<api::Term>& ntSymbols);
+
bool v2_0() const
{
return getLanguage() == language::input::LANG_SMTLIB_V2_0;
@@ -308,10 +280,13 @@ class Smt2 : public Parser
*/
void checkLogicAllowsFunctions();
- void checkUserSymbol(const std::string& name) {
- if(name.length() > 0 && (name[0] == '.' || name[0] == '@')) {
+ void checkUserSymbol(const std::string& name)
+ {
+ if (name.length() > 0 && (name[0] == '.' || name[0] == '@'))
+ {
std::stringstream ss;
- ss << "cannot declare or define symbol `" << name << "'; symbols starting with . and @ are reserved in SMT-LIB";
+ ss << "cannot declare or define symbol `" << name
+ << "'; symbols starting with . and @ are reserved in SMT-LIB";
parseError(ss.str());
}
else if (isOperatorEnabled(name))
@@ -329,7 +304,8 @@ class Smt2 : public Parser
d_lastNamedTerm = std::make_pair(e, name);
}
- void clearLastNamedTerm() {
+ void clearLastNamedTerm()
+ {
d_lastNamedTerm = std::make_pair(api::Term(), "");
}
@@ -346,31 +322,6 @@ class Smt2 : public Parser
api::Term mkAbstractValue(const std::string& name);
/**
- * Adds a constructor to sygus datatype dt whose sygus operator is term.
- *
- * ntsToUnres contains a mapping from non-terminal symbols to the unresolved
- * types they correspond to. This map indicates how the argument term should
- * be interpreted (instances of symbols from the domain of ntsToUnres
- * correspond to constructor arguments).
- *
- * The sygus operator that is actually added to dt corresponds to replacing
- * each occurrence of non-terminal symbols from the domain of ntsToUnres
- * with bound variables via purifySygusGTerm, and binding these variables
- * via a lambda.
- */
- void addSygusConstructorTerm(
- api::DatatypeDecl& dt,
- api::Term term,
- std::map<api::Term, api::Sort>& ntsToUnres) const;
- /**
- * This adds constructors to dt for sygus variables in sygusVars whose
- * type is argument type. This method should be called when the sygus grammar
- * term (Variable type) is encountered.
- */
- void addSygusConstructorVariables(api::DatatypeDecl& dt,
- const std::vector<api::Term>& sygusVars,
- api::Sort type) const;
- /**
* Smt2 parser provides its own checkDeclaration, which does the
* same as the base, but with some more helpful errors.
*/
@@ -392,17 +343,11 @@ class Smt2 : public Parser
}
this->Parser::checkDeclaration(name, check, type, notes);
}
- /** Set named attribute
- *
- * This is called when expression expr is annotated with a name, i.e.
- * (! expr :named sexpr). It sets up the necessary information to process
- * this naming, including marking that expr is the last named term.
- *
- * We construct an expression symbol whose name is the name of s-expression
- * which is used later for tracking assertions in unsat cores. This
- * symbol is returned by this method.
+ /**
+ * Notify that expression expr was given name std::string via a :named
+ * attribute.
*/
- api::Term setNamedAttribute(api::Term& expr, const SExpr& sexpr);
+ void notifyNamedExpression(api::Term& expr, std::string name);
// Throw a ParserException with msg appended with the current logic.
inline void parseErrorLogic(const std::string& msg)
@@ -475,22 +420,6 @@ class Smt2 : public Parser
//------------------------- end processing parse operators
private:
- /** Purify sygus grammar term
- *
- * This returns a term where all occurrences of non-terminal symbols (those
- * in the domain of ntsToUnres) are replaced by fresh variables. For each
- * variable replaced in this way, we add the fresh variable it is replaced
- * with to args, and the unresolved type corresponding to the non-terminal
- * symbol to cargs (constructor args). In other words, args contains the
- * free variables in the term returned by this method (which should be bound
- * by a lambda), and cargs contains the types of the arguments of the
- * sygus constructor.
- */
- api::Term purifySygusGTerm(api::Term term,
- std::map<api::Term, api::Sort>& ntsToUnres,
- std::vector<api::Term>& args,
- std::vector<api::Sort>& cargs) const;
-
void addArithmeticOperators();
void addTranscendentalOperators();
@@ -519,7 +448,7 @@ class Smt2 : public Parser
api::Term mkAnd(const std::vector<api::Term>& es);
}; /* class Smt2 */
-}/* CVC4::parser namespace */
-}/* CVC4 namespace */
+} // namespace parser
+} // namespace CVC4
#endif /* CVC4__PARSER__SMT2_H */
diff --git a/src/parser/smt2/smt2_input.cpp b/src/parser/smt2/smt2_input.cpp
index 521602e87..99907b51a 100644
--- a/src/parser/smt2/smt2_input.cpp
+++ b/src/parser/smt2/smt2_input.cpp
@@ -5,7 +5,7 @@
** Christopher L. Conway, Morgan Deters, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/smt2/smt2_input.h b/src/parser/smt2/smt2_input.h
index 843cdf584..57af32546 100644
--- a/src/parser/smt2/smt2_input.h
+++ b/src/parser/smt2/smt2_input.h
@@ -5,7 +5,7 @@
** Christopher L. Conway, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/smt2/sygus_input.cpp b/src/parser/smt2/sygus_input.cpp
index fa0038bd5..e1365f603 100644
--- a/src/parser/smt2/sygus_input.cpp
+++ b/src/parser/smt2/sygus_input.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/smt2/sygus_input.h b/src/parser/smt2/sygus_input.h
index d2cc58e34..baddc5431 100644
--- a/src/parser/smt2/sygus_input.h
+++ b/src/parser/smt2/sygus_input.h
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/tptp/Tptp.g b/src/parser/tptp/Tptp.g
index bae02a5d2..447a867c8 100644
--- a/src/parser/tptp/Tptp.g
+++ b/src/parser/tptp/Tptp.g
@@ -5,7 +5,7 @@
** Haniel Barbosa, Francois Bobot, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -61,7 +61,6 @@ options {
}/* @lexer::includes */
@lexer::postinclude {
-#include <stdint.h>
#include "parser/tptp/tptp.h"
#include "parser/antlr_input.h"
@@ -121,6 +120,8 @@ using namespace CVC4::parser;
#define PARSER_STATE ((Tptp*)PARSER->super)
#undef SOLVER
#define SOLVER PARSER_STATE->getSolver()
+#undef SYM_MAN
+#define SYM_MAN PARSER_STATE->getSymbolManager()
#undef MK_TERM
#define MK_TERM SOLVER->mkTerm
#define UNSUPPORTED PARSER_STATE->unimplementedFeature
@@ -161,12 +162,10 @@ parseCommand returns [CVC4::Command* cmd = NULL]
}
(COMMA_TOK anything*)? RPAREN_TOK DOT_TOK
{
- CVC4::api::Term aexpr = PARSER_STATE->getAssertionExpr(fr,expr);
+ CVC4::api::Term aexpr = PARSER_STATE->getAssertionExpr(fr, expr);
if( !aexpr.isNull() ){
// set the expression name (e.g. used with unsat core printing)
- Command* csen = new SetExpressionNameCommand(aexpr.getExpr(), name);
- csen->setMuted(true);
- PARSER_STATE->preemptCommand(csen);
+ SYM_MAN->setExpressionName(aexpr, name, true);
}
// make the command to assert the formula
cmd = PARSER_STATE->makeAssertCommand(fr, aexpr, /* cnf == */ true, true);
@@ -178,9 +177,7 @@ parseCommand returns [CVC4::Command* cmd = NULL]
CVC4::api::Term aexpr = PARSER_STATE->getAssertionExpr(fr,expr);
if( !aexpr.isNull() ){
// set the expression name (e.g. used with unsat core printing)
- Command* csen = new SetExpressionNameCommand(aexpr.getExpr(), name);
- csen->setMuted(true);
- PARSER_STATE->preemptCommand(csen);
+ SYM_MAN->setExpressionName(aexpr, name, true);
}
// make the command to assert the formula
cmd = PARSER_STATE->makeAssertCommand(fr, aexpr, /* cnf == */ false, true);
@@ -194,9 +191,7 @@ parseCommand returns [CVC4::Command* cmd = NULL]
CVC4::api::Term aexpr = PARSER_STATE->getAssertionExpr(fr,expr);
if( !aexpr.isNull() ){
// set the expression name (e.g. used with unsat core printing)
- Command* csen = new SetExpressionNameCommand(aexpr.getExpr(), name);
- csen->setMuted(true);
- PARSER_STATE->preemptCommand(csen);
+ SYM_MAN->setExpressionName(aexpr, name, true);
}
// make the command to assert the formula
cmd = PARSER_STATE->makeAssertCommand(fr, aexpr, /* cnf == */ false, true);
@@ -219,9 +214,7 @@ parseCommand returns [CVC4::Command* cmd = NULL]
if (!aexpr.isNull())
{
// set the expression name (e.g. used with unsat core printing)
- Command* csen = new SetExpressionNameCommand(aexpr.getExpr(), name);
- csen->setMuted(true);
- PARSER_STATE->preemptCommand(csen);
+ SYM_MAN->setExpressionName(aexpr, name, true);
}
// make the command to assert the formula
cmd = PARSER_STATE->makeAssertCommand(
@@ -255,7 +248,7 @@ parseCommand returns [CVC4::Command* cmd = NULL]
CVC4::api::Term aexpr = PARSER_STATE->getAssertionDistinctConstants();
if( !aexpr.isNull() )
{
- seq->addCommand(new AssertCommand(aexpr.getExpr(), false));
+ seq->addCommand(new AssertCommand(aexpr, false));
}
std::string filename = PARSER_STATE->getInput()->getInputStreamName();
@@ -268,7 +261,7 @@ parseCommand returns [CVC4::Command* cmd = NULL]
}
seq->addCommand(new SetInfoCommand("filename", SExpr(filename)));
if(PARSER_STATE->hasConjecture()) {
- seq->addCommand(new QueryCommand(SOLVER->mkFalse().getExpr()));
+ seq->addCommand(new QueryCommand(SOLVER->mkFalse()));
} else {
seq->addCommand(new CheckSatCommand());
}
@@ -477,7 +470,7 @@ definedPred[CVC4::ParseOp& p]
api::Term body =
MK_TERM(api::AND,
MK_TERM(api::NOT,
- MK_TERM(api::EQUAL, r, SOLVER->mkReal(0))),
+ MK_TERM(api::EQUAL, r, SOLVER->mkInteger(0))),
MK_TERM(api::EQUAL, qr, MK_TERM(api::MULT, n, rr)));
api::Term bvl = MK_TERM(api::BOUND_VAR_LIST, q, r);
body = MK_TERM(api::EXISTS, bvl, body);
@@ -537,7 +530,7 @@ thfDefinedPred[CVC4::ParseOp& p]
api::Term body = MK_TERM(
api::AND,
MK_TERM(api::NOT,
- MK_TERM(api::EQUAL, r, SOLVER->mkReal(0))),
+ MK_TERM(api::EQUAL, r, SOLVER->mkInteger(0))),
MK_TERM(api::EQUAL, qr, MK_TERM(api::MULT, n, rr)));
api::Term bvl = MK_TERM(api::BOUND_VAR_LIST, q, r);
body = MK_TERM(api::EXISTS, bvl, body);
@@ -708,7 +701,7 @@ definedFun[CVC4::ParseOp& p]
n,
SOLVER->mkReal(2)),
SOLVER->mkReal(1, 2))),
- SOLVER->mkReal(2))));
+ SOLVER->mkInteger(2))));
p.d_kind = api::LAMBDA;
p.d_expr = MK_TERM(api::LAMBDA, formals, expr);
}
@@ -967,7 +960,7 @@ thfAtomTyping[CVC4::Command*& cmd]
{
// as yet, it's undeclared
api::Sort atype = PARSER_STATE->mkSort(name);
- cmd = new DeclareTypeCommand(name, 0, atype.getType());
+ cmd = new DeclareSortCommand(name, 0, atype);
}
}
| parseThfType[type]
@@ -1007,8 +1000,7 @@ thfAtomTyping[CVC4::Command*& cmd]
{
freshExpr = PARSER_STATE->bindVar(name, type);
}
- cmd = new DeclareFunctionCommand(
- name, freshExpr.getExpr(), type.getType());
+ cmd = new DeclareFunctionCommand(name, freshExpr, type);
}
}
)
@@ -1320,7 +1312,7 @@ tffTypedAtom[CVC4::Command*& cmd]
} else {
// as yet, it's undeclared
api::Sort atype = PARSER_STATE->mkSort(name);
- cmd = new DeclareTypeCommand(name, 0, atype.getType());
+ cmd = new DeclareSortCommand(name, 0, atype);
}
}
| parseType[type]
@@ -1339,8 +1331,7 @@ tffTypedAtom[CVC4::Command*& cmd]
} else {
// as yet, it's undeclared
CVC4::api::Term aexpr = PARSER_STATE->bindVar(name, type);
- cmd =
- new DeclareFunctionCommand(name, aexpr.getExpr(), type.getType());
+ cmd = new DeclareFunctionCommand(name, aexpr, type);
}
}
)
@@ -1749,7 +1740,15 @@ NUMBER
: ( SIGN[pos]? num=DECIMAL
{ std::stringstream ss;
ss << ( pos ? "" : "-" ) << AntlrInput::tokenText($num);
- PARSER_STATE->d_tmp_expr = SOLVER->mkReal(ss.str());
+ std::string str = ss.str();
+ if (str.find(".") == std::string::npos)
+ {
+ PARSER_STATE->d_tmp_expr = SOLVER->mkInteger(str);
+ }
+ else
+ {
+ PARSER_STATE->d_tmp_expr = SOLVER->mkReal(str);
+ }
}
| SIGN[pos]? num=DECIMAL DOT den=DECIMAL (EXPONENT SIGN[posE]? e=DECIMAL)?
{
diff --git a/src/parser/tptp/tptp.cpp b/src/parser/tptp/tptp.cpp
index cb4d3fd9e..f80b9c3c8 100644
--- a/src/parser/tptp/tptp.cpp
+++ b/src/parser/tptp/tptp.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Francois Bobot, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -24,6 +24,7 @@
#include "expr/type.h"
#include "options/options.h"
#include "parser/parser.h"
+#include "smt/command.h"
// ANTLR defines these, which is really bad!
#undef true
@@ -32,8 +33,14 @@
namespace CVC4 {
namespace parser {
-Tptp::Tptp(api::Solver* solver, Input* input, bool strictMode, bool parseOnly)
- : Parser(solver, input, strictMode, parseOnly), d_cnf(false), d_fof(false)
+Tptp::Tptp(api::Solver* solver,
+ SymbolManager* sm,
+ Input* input,
+ bool strictMode,
+ bool parseOnly)
+ : Parser(solver, sm, input, strictMode, parseOnly),
+ d_cnf(false),
+ d_fof(false)
{
addTheory(Tptp::THEORY_CORE);
@@ -75,8 +82,7 @@ void Tptp::addTheory(Theory theory) {
{
std::string d_unsorted_name = "$$unsorted";
d_unsorted = d_solver->mkUninterpretedSort(d_unsorted_name);
- preemptCommand(
- new DeclareTypeCommand(d_unsorted_name, 0, d_unsorted.getType()));
+ preemptCommand(new DeclareSortCommand(d_unsorted_name, 0, d_unsorted));
}
// propositionnal
defineType("Bool", d_solver->getBooleanSort());
@@ -242,8 +248,7 @@ api::Term Tptp::parseOpToExpr(ParseOp& p)
api::Sort t =
p.d_type == d_solver->getBooleanSort() ? p.d_type : d_unsorted;
expr = bindVar(p.d_name, t, ExprManager::VAR_FLAG_GLOBAL); // levelZero
- preemptCommand(
- new DeclareFunctionCommand(p.d_name, expr.getExpr(), t.getType()));
+ preemptCommand(new DeclareFunctionCommand(p.d_name, expr, t));
}
return expr;
}
@@ -287,8 +292,7 @@ api::Term Tptp::applyParseOp(ParseOp& p, std::vector<api::Term>& args)
p.d_type == d_solver->getBooleanSort() ? p.d_type : d_unsorted;
t = d_solver->mkFunctionSort(sorts, t);
v = bindVar(p.d_name, t, ExprManager::VAR_FLAG_GLOBAL); // levelZero
- preemptCommand(
- new DeclareFunctionCommand(p.d_name, v.getExpr(), t.getType()));
+ preemptCommand(new DeclareFunctionCommand(p.d_name, v, t));
}
// args might be rationals, in which case we need to create
// distinct constants of the "unsorted" sort to represent them
@@ -393,13 +397,11 @@ api::Term Tptp::convertRatToUnsorted(api::Term expr)
// Conversion from rational to unsorted
t = d_solver->mkFunctionSort(d_solver->getRealSort(), d_unsorted);
d_rtu_op = d_solver->mkConst(t, "$$rtu");
- preemptCommand(
- new DeclareFunctionCommand("$$rtu", d_rtu_op.getExpr(), t.getType()));
+ preemptCommand(new DeclareFunctionCommand("$$rtu", d_rtu_op, t));
// Conversion from unsorted to rational
t = d_solver->mkFunctionSort(d_unsorted, d_solver->getRealSort());
d_utr_op = d_solver->mkConst(t, "$$utr");
- preemptCommand(
- new DeclareFunctionCommand("$$utr", d_utr_op.getExpr(), t.getType()));
+ 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
@@ -409,7 +411,7 @@ api::Term Tptp::convertRatToUnsorted(api::Term expr)
d_r_converted.insert(expr);
api::Term eq = d_solver->mkTerm(
api::EQUAL, expr, d_solver->mkTerm(api::APPLY_UF, d_utr_op, ret));
- preemptCommand(new AssertCommand(eq.getExpr()));
+ preemptCommand(new AssertCommand(eq));
}
return api::Term(ret);
}
@@ -505,7 +507,7 @@ Command* Tptp::makeAssertCommand(FormulaRole fr,
if( expr.isNull() ){
return new EmptyCommand("Untreated role for expression");
}else{
- return new AssertCommand(expr.getExpr(), inUnsatCore);
+ return new AssertCommand(expr, inUnsatCore);
}
}
diff --git a/src/parser/tptp/tptp.h b/src/parser/tptp/tptp.h
index 3d5419be9..ca4dd61bf 100644
--- a/src/parser/tptp/tptp.h
+++ b/src/parser/tptp/tptp.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Francois Bobot, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -28,11 +28,12 @@
#include "api/cvc4cpp.h"
#include "parser/parse_op.h"
#include "parser/parser.h"
-#include "smt/command.h"
#include "util/hash.h"
namespace CVC4 {
+class Command;
+
namespace api {
class Solver;
}
@@ -91,6 +92,7 @@ class Tptp : public Parser {
protected:
Tptp(api::Solver* solver,
+ SymbolManager* sm,
Input* input,
bool strictMode = false,
bool parseOnly = false);
diff --git a/src/parser/tptp/tptp_input.cpp b/src/parser/tptp/tptp_input.cpp
index cdd2ac7e5..5634510ff 100644
--- a/src/parser/tptp/tptp_input.cpp
+++ b/src/parser/tptp/tptp_input.cpp
@@ -5,7 +5,7 @@
** Francois Bobot, Morgan Deters, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/parser/tptp/tptp_input.h b/src/parser/tptp/tptp_input.h
index 9f8cd386f..769430e96 100644
--- a/src/parser/tptp/tptp_input.h
+++ b/src/parser/tptp/tptp_input.h
@@ -5,7 +5,7 @@
** Francois Bobot, Mathias Preiner, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/assertion_pipeline.cpp b/src/preprocessing/assertion_pipeline.cpp
index caad369b7..cd7aadf9a 100644
--- a/src/preprocessing/assertion_pipeline.cpp
+++ b/src/preprocessing/assertion_pipeline.cpp
@@ -2,10 +2,10 @@
/*! \file assertion_pipeline.cpp
** \verbatim
** Top contributors (to current version):
- ** Andres Noetzli, Justin Xu, Morgan Deters
+ ** Andres Noetzli, Andrew Reynolds, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,8 +16,9 @@
#include "preprocessing/assertion_pipeline.h"
#include "expr/node_manager.h"
-#include "proof/proof.h"
+#include "options/smt_options.h"
#include "proof/proof_manager.h"
+#include "theory/builtin/proof_checker.h"
#include "theory/rewriter.h"
namespace CVC4 {
@@ -28,7 +29,8 @@ AssertionPipeline::AssertionPipeline()
d_storeSubstsInAsserts(false),
d_substsIndex(0),
d_assumptionsStart(0),
- d_numAssumptions(0)
+ d_numAssumptions(0),
+ d_pppg(nullptr)
{
}
@@ -40,11 +42,15 @@ void AssertionPipeline::clear()
d_numAssumptions = 0;
}
-void AssertionPipeline::push_back(Node n, bool isAssumption)
+void AssertionPipeline::push_back(Node n,
+ bool isAssumption,
+ bool isInput,
+ ProofGenerator* pgen)
{
d_nodes.push_back(n);
if (isAssumption)
{
+ Assert(pgen == nullptr);
if (d_numAssumptions == 0)
{
d_assumptionsStart = d_nodes.size() - 1;
@@ -56,39 +62,70 @@ void AssertionPipeline::push_back(Node n, bool isAssumption)
Assert(d_assumptionsStart + d_numAssumptions == d_nodes.size() - 1);
d_numAssumptions++;
}
+ Trace("assert-pipeline") << "Assertions: ...new assertion " << n
+ << ", isInput=" << isInput << std::endl;
+ if (isProofEnabled())
+ {
+ if (!isInput)
+ {
+ // notice this is always called, regardless of whether pgen is nullptr
+ d_pppg->notifyNewAssert(n, pgen);
+ }
+ else
+ {
+ Assert(pgen == nullptr);
+ // n is an input assertion, whose proof should be ASSUME.
+ d_pppg->notifyInput(n);
+ }
+ }
}
-void AssertionPipeline::replace(size_t i, Node n)
+void AssertionPipeline::pushBackTrusted(theory::TrustNode trn)
{
- PROOF(ProofManager::currentPM()->addDependence(n, d_nodes[i]););
- d_nodes[i] = n;
+ Assert(trn.getKind() == theory::TrustNodeKind::LEMMA);
+ // push back what was proven
+ push_back(trn.getProven(), false, false, trn.getGenerator());
}
-void AssertionPipeline::replace(size_t i,
- Node n,
- const std::vector<Node>& addnDeps)
+void AssertionPipeline::replace(size_t i, Node n, ProofGenerator* pgen)
{
- PROOF(ProofManager::currentPM()->addDependence(n, d_nodes[i]);
- for (const auto& addnDep
- : addnDeps) {
- ProofManager::currentPM()->addDependence(n, addnDep);
- });
+ if (n == d_nodes[i])
+ {
+ // no change, skip
+ return;
+ }
+ Trace("assert-pipeline") << "Assertions: Replace " << d_nodes[i] << " with "
+ << n << std::endl;
+ if (options::unsatCores())
+ {
+ ProofManager::currentPM()->addDependence(n, d_nodes[i]);
+ }
+ if (isProofEnabled())
+ {
+ d_pppg->notifyPreprocessed(d_nodes[i], n, pgen);
+ }
d_nodes[i] = n;
}
-void AssertionPipeline::replace(size_t i, const std::vector<Node>& ns)
-{
- PROOF(
- for (const auto& n
- : ns) { ProofManager::currentPM()->addDependence(n, d_nodes[i]); });
- d_nodes[i] = NodeManager::currentNM()->mkConst<bool>(true);
-
- for (const auto& n : ns)
+void AssertionPipeline::replaceTrusted(size_t i, theory::TrustNode trn)
+{
+ if (trn.isNull())
{
- d_nodes.push_back(n);
+ // null trust node denotes no change, nothing to do
+ return;
}
+ Assert(trn.getKind() == theory::TrustNodeKind::REWRITE);
+ Assert(trn.getProven()[0] == d_nodes[i]);
+ replace(i, trn.getNode(), trn.getGenerator());
+}
+
+void AssertionPipeline::setProofGenerator(smt::PreprocessProofGenerator* pppg)
+{
+ d_pppg = pppg;
}
+bool AssertionPipeline::isProofEnabled() const { return d_pppg != nullptr; }
+
void AssertionPipeline::enableStoreSubstsInAsserts()
{
d_storeSubstsInAsserts = true;
@@ -101,14 +138,75 @@ void AssertionPipeline::disableStoreSubstsInAsserts()
d_storeSubstsInAsserts = false;
}
-void AssertionPipeline::addSubstitutionNode(Node n)
+void AssertionPipeline::addSubstitutionNode(Node n, ProofGenerator* pg)
{
Assert(d_storeSubstsInAsserts);
Assert(n.getKind() == kind::EQUAL);
- d_nodes[d_substsIndex] = theory::Rewriter::rewrite(
- NodeManager::currentNM()->mkNode(kind::AND, n, d_nodes[d_substsIndex]));
- Assert(theory::Rewriter::rewrite(d_nodes[d_substsIndex])
- == d_nodes[d_substsIndex]);
+ conjoin(d_substsIndex, n, pg);
+}
+
+void AssertionPipeline::conjoin(size_t i, Node n, ProofGenerator* pg)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ Node newConj = nm->mkNode(kind::AND, d_nodes[i], n);
+ Node newConjr = theory::Rewriter::rewrite(newConj);
+ Trace("assert-pipeline") << "Assertions: conjoin " << n << " to "
+ << d_nodes[i] << std::endl;
+ Trace("assert-pipeline-debug") << "conjoin " << n << " to " << d_nodes[i]
+ << ", got " << newConjr << std::endl;
+ if (newConjr == d_nodes[i])
+ {
+ // trivial, skip
+ return;
+ }
+ if (isProofEnabled())
+ {
+ if (newConjr == n)
+ {
+ // don't care about the previous proof and can simply plug in the
+ // proof from pg if the resulting assertion is the same as n.
+ d_pppg->notifyNewAssert(newConjr, pg);
+ }
+ else
+ {
+ // ---------- from pppg --------- from pg
+ // d_nodes[i] n
+ // -------------------------------- AND_INTRO
+ // d_nodes[i] ^ n
+ // -------------------------------- MACRO_SR_PRED_TRANSFORM
+ // rewrite( d_nodes[i] ^ n )
+ // allocate a fresh proof which will act as the proof generator
+ LazyCDProof* lcp = d_pppg->allocateHelperProof();
+ lcp->addLazyStep(n, pg, PfRule::PREPROCESS);
+ if (d_nodes[i].isConst() && d_nodes[i].getConst<bool>())
+ {
+ // skip the AND_INTRO if the previous d_nodes[i] was true
+ newConj = n;
+ }
+ else
+ {
+ lcp->addLazyStep(d_nodes[i], d_pppg);
+ lcp->addStep(newConj, PfRule::AND_INTRO, {d_nodes[i], n}, {});
+ }
+ if (newConjr != newConj)
+ {
+ lcp->addStep(
+ newConjr, PfRule::MACRO_SR_PRED_TRANSFORM, {newConj}, {newConjr});
+ }
+ // Notice we have constructed a proof of a new assertion, where d_pppg
+ // is referenced in the lazy proof above. If alternatively we had
+ // constructed a proof of d_nodes[i] = rewrite( d_nodes[i] ^ n ), we would
+ // have used notifyPreprocessed. However, it is simpler to make the
+ // above proof.
+ d_pppg->notifyNewAssert(newConjr, lcp);
+ }
+ }
+ if (options::unsatCores())
+ {
+ ProofManager::currentPM()->addDependence(newConjr, d_nodes[i]);
+ }
+ d_nodes[i] = newConjr;
+ Assert(theory::Rewriter::rewrite(newConjr) == newConjr);
}
} // namespace preprocessing
diff --git a/src/preprocessing/assertion_pipeline.h b/src/preprocessing/assertion_pipeline.h
index 5d8f64594..75f370450 100644
--- a/src/preprocessing/assertion_pipeline.h
+++ b/src/preprocessing/assertion_pipeline.h
@@ -2,10 +2,10 @@
/*! \file assertion_pipeline.h
** \verbatim
** Top contributors (to current version):
- ** Andres Noetzli, Justin Xu, Morgan Deters
+ ** Andres Noetzli, Andrew Reynolds, Justin Xu
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,7 +21,11 @@
#include <vector>
#include "expr/node.h"
+#include "expr/proof_generator.h"
+#include "expr/proof_node_manager.h"
+#include "smt/preprocess_proof_generator.h"
#include "smt/term_formula_removal.h"
+#include "theory/trust_node.h"
namespace CVC4 {
namespace preprocessing {
@@ -45,7 +49,6 @@ class AssertionPipeline
*/
void clear();
- Node& operator[](size_t i) { return d_nodes[i]; }
const Node& operator[](size_t i) const { return d_nodes[i]; }
/**
@@ -54,10 +57,22 @@ class AssertionPipeline
* @param n The assertion/assumption
* @param isAssumption If true, records that \p n is an assumption. Note that
* all assumptions have to be added contiguously.
+ * @param isInput If true, n is an input formula (an assumption in the main
+ * body of the overall proof).
+ * @param pg The proof generator who can provide a proof of n. The proof
+ * generator is not required and is ignored if isInput is true.
*/
- void push_back(Node n, bool isAssumption = false);
+ void push_back(Node n,
+ bool isAssumption = false,
+ bool isInput = false,
+ ProofGenerator* pg = nullptr);
+ /** Same as above, with TrustNode */
+ void pushBackTrusted(theory::TrustNode trn);
- std::vector<Node>& ref() { return d_nodes; }
+ /**
+ * Get the constant reference to the underlying assertions. It is only
+ * possible to modify these via the replace methods below.
+ */
const std::vector<Node>& ref() const { return d_nodes; }
std::vector<Node>::const_iterator begin() const { return d_nodes.cbegin(); }
@@ -66,21 +81,18 @@ class AssertionPipeline
/*
* Replaces assertion i with node n and records the dependency between the
* original assertion and its replacement.
+ *
+ * @param i The position of the assertion to replace.
+ * @param n The replacement assertion.
+ * @param pg The proof generator who can provide a proof of d_nodes[i] == n,
+ * where d_nodes[i] is the assertion at position i prior to this call.
*/
- void replace(size_t i, Node n);
-
- /*
- * Replaces assertion i with node n and records that this replacement depends
- * on assertion i and the nodes listed in addnDeps. The dependency
- * information is used for unsat cores and proofs.
- */
- void replace(size_t i, Node n, const std::vector<Node>& addnDeps);
-
- /*
- * Replaces an assertion with a vector of assertions and records the
- * dependencies.
+ void replace(size_t i, Node n, ProofGenerator* pg = nullptr);
+ /**
+ * Same as above, with TrustNode trn, which is of kind REWRITE and proves
+ * d_nodes[i] = n for some n.
*/
- void replace(size_t i, const std::vector<Node>& ns);
+ void replaceTrusted(size_t i, theory::TrustNode trn);
IteSkolemMap& getIteSkolemMap() { return d_iteSkolemMap; }
const IteSkolemMap& getIteSkolemMap() const { return d_iteSkolemMap; }
@@ -113,8 +125,23 @@ class AssertionPipeline
/**
* Adds a substitution node of the form (= lhs rhs) to the assertions.
+ * This conjoins n to assertions at a distinguished index given by
+ * d_substsIndex.
+ *
+ * @param n The substitution node
+ * @param pg The proof generator that can provide a proof of n.
*/
- void addSubstitutionNode(Node n);
+ void addSubstitutionNode(Node n, ProofGenerator* pg = nullptr);
+
+ /**
+ * Conjoin n to the assertion vector at position i. This replaces
+ * d_nodes[i] with the rewritten form of (AND d_nodes[i] n).
+ *
+ * @param i The assertion to replace
+ * @param n The formula to conjoin at position i
+ * @param pg The proof generator that can provide a proof of n
+ */
+ void conjoin(size_t i, Node n, ProofGenerator* pg = nullptr);
/**
* Checks whether the assertion at a given index represents substitutions.
@@ -125,7 +152,12 @@ class AssertionPipeline
{
return d_storeSubstsInAsserts && i == d_substsIndex;
}
-
+ //------------------------------------ for proofs
+ /** Set proof generator */
+ void setProofGenerator(smt::PreprocessProofGenerator* pppg);
+ /** Is proof enabled? */
+ bool isProofEnabled() const;
+ //------------------------------------ end for proofs
private:
/** The list of current assertions */
std::vector<Node> d_nodes;
@@ -157,6 +189,8 @@ class AssertionPipeline
size_t d_assumptionsStart;
/** The number of assumptions */
size_t d_numAssumptions;
+ /** The proof generator, if one is provided */
+ smt::PreprocessProofGenerator* d_pppg;
}; /* class AssertionPipeline */
} // namespace preprocessing
diff --git a/src/preprocessing/passes/ackermann.cpp b/src/preprocessing/passes/ackermann.cpp
index 31c92a09f..af6cae796 100644
--- a/src/preprocessing/passes/ackermann.cpp
+++ b/src/preprocessing/passes/ackermann.cpp
@@ -5,7 +5,7 @@
** Ying Sheng, Yoni Zohar, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -70,11 +70,14 @@ void addLemmaForPair(TNode args1,
}
else
{
- Assert(args1.getKind() == kind::SELECT && args1[0] == func);
- Assert(args2.getKind() == kind::SELECT && args2[0] == func);
+ Assert(args1.getKind() == kind::SELECT && args1.getOperator() == func);
+ Assert(args2.getKind() == kind::SELECT && args2.getOperator() == func);
Assert(args1.getNumChildren() == 2);
Assert(args2.getNumChildren() == 2);
- args_eq = nm->mkNode(kind::EQUAL, args1[1], args2[1]);
+ args_eq = nm->mkNode(Kind::AND,
+ nm->mkNode(kind::EQUAL, args1[0], args2[0]),
+ nm->mkNode(kind::EQUAL, args1[1], args2[1])
+ );
}
Node func_eq = nm->mkNode(kind::EQUAL, args1, args2);
Node lemma = nm->mkNode(kind::IMPLIES, args_eq, func_eq);
@@ -153,7 +156,7 @@ void collectFunctionsAndLemmas(FunctionToArgsMap& fun_to_args,
if (seen.find(term) == seen.end())
{
TNode func;
- if (term.getKind() == kind::APPLY_UF)
+ if (term.getKind() == kind::APPLY_UF || term.getKind() == kind::SELECT)
{
storeFunctionAndAddLemmas(term.getOperator(),
term,
@@ -163,11 +166,6 @@ void collectFunctionsAndLemmas(FunctionToArgsMap& fun_to_args,
nm,
vec);
}
- else if (term.getKind() == kind::SELECT)
- {
- storeFunctionAndAddLemmas(
- term[0], term, fun_to_args, fun_to_skolem, assertions, nm, vec);
- }
else
{
AlwaysAssert(term.getKind() != kind::STORE)
@@ -278,9 +276,13 @@ void usortsToBitVectors(const LogicInfo& d_logic,
for (size_t i = 0, size = assertions->size(); i < size; ++i)
{
Node old = (*assertions)[i];
- assertions->replace(i, usVarsToBVVars.apply((*assertions)[i]));
- Trace("uninterpretedSorts-to-bv")
- << " " << old << " => " << (*assertions)[i] << "\n";
+ Node newA = usVarsToBVVars.apply((*assertions)[i]);
+ if (newA != old)
+ {
+ assertions->replace(i, newA);
+ Trace("uninterpretedSorts-to-bv")
+ << " " << old << " => " << (*assertions)[i] << "\n";
+ }
}
}
}
diff --git a/src/preprocessing/passes/ackermann.h b/src/preprocessing/passes/ackermann.h
index 1d2b6e9ce..08d95927c 100644
--- a/src/preprocessing/passes/ackermann.h
+++ b/src/preprocessing/passes/ackermann.h
@@ -5,7 +5,7 @@
** Ying Sheng, Aina Niemetz, Yoni Zohar
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/apply_substs.cpp b/src/preprocessing/passes/apply_substs.cpp
index 71aa028d4..06821ab56 100644
--- a/src/preprocessing/passes/apply_substs.cpp
+++ b/src/preprocessing/passes/apply_substs.cpp
@@ -5,7 +5,7 @@
** Aina Niemetz, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -41,7 +41,7 @@ PreprocessingPassResult ApplySubsts::applyInternal(
// TODO(#1255): Substitutions in incremental mode should be managed with a
// proper data structure.
- theory::SubstitutionMap& substMap =
+ theory::TrustSubstitutionMap& tlsm =
d_preprocContext->getTopLevelSubstitutions();
unsigned size = assertionsToPreprocess->size();
for (unsigned i = 0; i < size; ++i)
@@ -54,9 +54,8 @@ PreprocessingPassResult ApplySubsts::applyInternal(
<< std::endl;
d_preprocContext->spendResource(
ResourceManager::Resource::PreprocessStep);
- assertionsToPreprocess->replace(i,
- theory::Rewriter::rewrite(substMap.apply(
- (*assertionsToPreprocess)[i])));
+ assertionsToPreprocess->replaceTrusted(
+ i, tlsm.apply((*assertionsToPreprocess)[i]));
Trace("apply-substs") << " got " << (*assertionsToPreprocess)[i]
<< std::endl;
}
diff --git a/src/preprocessing/passes/apply_substs.h b/src/preprocessing/passes/apply_substs.h
index 4f2dd24e5..781fcc79e 100644
--- a/src/preprocessing/passes/apply_substs.h
+++ b/src/preprocessing/passes/apply_substs.h
@@ -5,7 +5,7 @@
** Aina Niemetz, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/bool_to_bv.cpp b/src/preprocessing/passes/bool_to_bv.cpp
index ad512bdfd..47a504d59 100644
--- a/src/preprocessing/passes/bool_to_bv.cpp
+++ b/src/preprocessing/passes/bool_to_bv.cpp
@@ -5,7 +5,7 @@
** Makai Mann, Yoni Zohar, Clark Barrett
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/bool_to_bv.h b/src/preprocessing/passes/bool_to_bv.h
index 968672e86..c5e6f3801 100644
--- a/src/preprocessing/passes/bool_to_bv.h
+++ b/src/preprocessing/passes/bool_to_bv.h
@@ -5,7 +5,7 @@
** Makai Mann, Yoni Zohar, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/bv_abstraction.cpp b/src/preprocessing/passes/bv_abstraction.cpp
index 5d6ed9b4f..ebc169e42 100644
--- a/src/preprocessing/passes/bv_abstraction.cpp
+++ b/src/preprocessing/passes/bv_abstraction.cpp
@@ -5,7 +5,7 @@
** Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/bv_abstraction.h b/src/preprocessing/passes/bv_abstraction.h
index aa1134a9b..a49bdae2c 100644
--- a/src/preprocessing/passes/bv_abstraction.h
+++ b/src/preprocessing/passes/bv_abstraction.h
@@ -5,7 +5,7 @@
** Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/bv_eager_atoms.cpp b/src/preprocessing/passes/bv_eager_atoms.cpp
index d4dd2b9b9..460ef2597 100644
--- a/src/preprocessing/passes/bv_eager_atoms.cpp
+++ b/src/preprocessing/passes/bv_eager_atoms.cpp
@@ -5,7 +5,7 @@
** Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/bv_eager_atoms.h b/src/preprocessing/passes/bv_eager_atoms.h
index cd84f1aaa..4c1bb136c 100644
--- a/src/preprocessing/passes/bv_eager_atoms.h
+++ b/src/preprocessing/passes/bv_eager_atoms.h
@@ -5,7 +5,7 @@
** Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/bv_gauss.cpp b/src/preprocessing/passes/bv_gauss.cpp
index 68696015e..eaba90561 100644
--- a/src/preprocessing/passes/bv_gauss.cpp
+++ b/src/preprocessing/passes/bv_gauss.cpp
@@ -5,7 +5,7 @@
** Aina Niemetz, Mathias Preiner, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -737,8 +737,8 @@ PreprocessingPassResult BVGauss::applyInternal(
}
std::unordered_map<Node, Node, NodeHashFunction> subst;
- std::vector<Node>& atpp = assertionsToPreprocess->ref();
+ NodeManager* nm = NodeManager::currentNM();
for (const auto& eq : equations)
{
if (eq.second.size() <= 1) { continue; }
@@ -756,11 +756,12 @@ PreprocessingPassResult BVGauss::applyInternal(
<< std::endl;
if (ret != BVGauss::Result::INVALID)
{
- NodeManager *nm = NodeManager::currentNM();
if (ret == BVGauss::Result::NONE)
{
- atpp.clear();
- atpp.push_back(nm->mkConst<bool>(false));
+ assertionsToPreprocess->clear();
+ Node n = nm->mkConst<bool>(false);
+ assertionsToPreprocess->push_back(n);
+ return PreprocessingPassResult::CONFLICT;
}
else
{
@@ -773,7 +774,8 @@ PreprocessingPassResult BVGauss::applyInternal(
{
Node a = nm->mkNode(kind::EQUAL, p.first, p.second);
Trace("bv-gauss-elim") << "added assertion: " << a << std::endl;
- atpp.push_back(a);
+ // add new assertion
+ assertionsToPreprocess->push_back(a);
}
}
}
@@ -782,9 +784,13 @@ PreprocessingPassResult BVGauss::applyInternal(
if (!subst.empty())
{
/* delete (= substitute with true) obsolete assertions */
- for (auto& a : atpp)
+ const std::vector<Node>& aref = assertionsToPreprocess->ref();
+ for (size_t i = 0, asize = aref.size(); i < asize; ++i)
{
- a = a.substitute(subst.begin(), subst.end());
+ Node a = aref[i];
+ Node as = a.substitute(subst.begin(), subst.end());
+ // replace the assertion
+ assertionsToPreprocess->replace(i, as);
}
}
return PreprocessingPassResult::NO_CONFLICT;
diff --git a/src/preprocessing/passes/bv_gauss.h b/src/preprocessing/passes/bv_gauss.h
index f09b2dbe4..0b614251f 100644
--- a/src/preprocessing/passes/bv_gauss.h
+++ b/src/preprocessing/passes/bv_gauss.h
@@ -5,7 +5,7 @@
** Aina Niemetz, Mathias Preiner, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/bv_intro_pow2.cpp b/src/preprocessing/passes/bv_intro_pow2.cpp
index a0f2ffdd5..1e14e5b4b 100644
--- a/src/preprocessing/passes/bv_intro_pow2.cpp
+++ b/src/preprocessing/passes/bv_intro_pow2.cpp
@@ -5,7 +5,7 @@
** Mathias Preiner, Liana Hadarean
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/bv_intro_pow2.h b/src/preprocessing/passes/bv_intro_pow2.h
index fcfef6f39..92bdc2fc7 100644
--- a/src/preprocessing/passes/bv_intro_pow2.h
+++ b/src/preprocessing/passes/bv_intro_pow2.h
@@ -5,7 +5,7 @@
** Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/bv_to_bool.cpp b/src/preprocessing/passes/bv_to_bool.cpp
index f4d4d5b8c..ac8b01d74 100644
--- a/src/preprocessing/passes/bv_to_bool.cpp
+++ b/src/preprocessing/passes/bv_to_bool.cpp
@@ -5,7 +5,7 @@
** Yoni Zohar, Liana Hadarean, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/bv_to_bool.h b/src/preprocessing/passes/bv_to_bool.h
index f0f4b3856..5054edfc4 100644
--- a/src/preprocessing/passes/bv_to_bool.h
+++ b/src/preprocessing/passes/bv_to_bool.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Yoni Zohar, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/bv_to_int.cpp b/src/preprocessing/passes/bv_to_int.cpp
index bb0bde2f9..dbe751415 100644
--- a/src/preprocessing/passes/bv_to_int.cpp
+++ b/src/preprocessing/passes/bv_to_int.cpp
@@ -2,10 +2,10 @@
/*! \file bv_to_int.cpp
** \verbatim
** Top contributors (to current version):
- ** Yoni Zohar, Ahmed Irfan
+ ** Yoni Zohar, Ahmed Irfan, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -42,21 +42,6 @@ Rational intpow2(uint64_t b)
return Rational(Integer(2).pow(b), Integer(1));
}
-/**
- * Helper functions for createBitwiseNode
- */
-bool oneBitAnd(bool a, bool b) { return (a && b); }
-
-bool oneBitOr(bool a, bool b) { return (a || b); }
-
-bool oneBitXor(bool a, bool b) { return a != b; }
-
-bool oneBitXnor(bool a, bool b) { return a == b; }
-
-bool oneBitNand(bool a, bool b) { return !(a && b); }
-
-bool oneBitNor(bool a, bool b) { return !(a || b); }
-
} //end empty namespace
Node BVToInt::mkRangeConstraint(Node newVar, uint64_t k)
@@ -108,7 +93,7 @@ Node BVToInt::makeBinary(Node n)
d_binarizeCache[current] = Node();
toVisit.insert(toVisit.end(), current.begin(), current.end());
}
- else if (d_binarizeCache[current].isNull())
+ else if (d_binarizeCache[current].get().isNull())
{
/*
* We already visited the sub-dag rooted at the current node,
@@ -137,14 +122,13 @@ Node BVToInt::makeBinary(Node n)
{
// current has children, but we do not binarize it
NodeBuilder<> builder(k);
- if (current.getKind() == kind::BITVECTOR_EXTRACT
- || current.getKind() == kind::APPLY_UF)
+ if (current.getMetaKind() == kind::metakind::PARAMETERIZED)
{
builder << current.getOperator();
}
for (Node child : current)
{
- builder << d_binarizeCache[child];
+ builder << d_binarizeCache[child].get();
}
d_binarizeCache[current] = builder.constructNode();
}
@@ -179,6 +163,14 @@ Node BVToInt::eliminationPass(Node n)
while (!toVisit.empty())
{
current = toVisit.back();
+ // assert that the node is binarized
+ // The following variable is only used in assertions
+ CVC4_UNUSED kind::Kind_t k = current.getKind();
+ uint64_t numChildren = current.getNumChildren();
+ Assert((numChildren == 2)
+ || !(k == kind::BITVECTOR_PLUS || k == kind::BITVECTOR_MULT
+ || k == kind::BITVECTOR_AND || k == kind::BITVECTOR_OR
+ || k == kind::BITVECTOR_XOR || k == kind::BITVECTOR_CONCAT));
toVisit.pop_back();
bool inEliminationCache =
(d_eliminationCache.find(current) != d_eliminationCache.end());
@@ -186,25 +178,29 @@ Node BVToInt::eliminationPass(Node n)
(d_rebuildCache.find(current) != d_rebuildCache.end());
if (!inEliminationCache)
{
+ // current is not the elimination of any previously-visited node
// current hasn't been eliminated yet.
// eliminate operators from it
Node currentEliminated =
FixpointRewriteStrategy<RewriteRule<UdivZero>,
- RewriteRule<SdivEliminate>,
- RewriteRule<SremEliminate>,
- RewriteRule<SmodEliminate>,
+ RewriteRule<SdivEliminateFewerBitwiseOps>,
+ RewriteRule<SremEliminateFewerBitwiseOps>,
+ RewriteRule<SmodEliminateFewerBitwiseOps>,
+ RewriteRule<XnorEliminate>,
+ RewriteRule<NandEliminate>,
+ RewriteRule<NorEliminate>,
+ RewriteRule<NegEliminate>,
+ RewriteRule<XorEliminate>,
+ RewriteRule<OrEliminate>,
+ RewriteRule<SubEliminate>,
RewriteRule<RepeatEliminate>,
- RewriteRule<ZeroExtendEliminate>,
- RewriteRule<SignExtendEliminate>,
RewriteRule<RotateRightEliminate>,
RewriteRule<RotateLeftEliminate>,
RewriteRule<CompEliminate>,
RewriteRule<SleEliminate>,
RewriteRule<SltEliminate>,
RewriteRule<SgtEliminate>,
- RewriteRule<SgeEliminate>,
- RewriteRule<ShlByConst>,
- RewriteRule<LshrByConst> >::apply(current);
+ RewriteRule<SgeEliminate>>::apply(current);
// save in the cache
d_eliminationCache[current] = currentEliminated;
// also assign the eliminated now to itself to avoid revisiting.
@@ -221,10 +217,10 @@ Node BVToInt::eliminationPass(Node n)
if (inRebuildCache)
{
// current was already added to the rebuild cache.
- if (d_rebuildCache[current].isNull())
+ if (d_rebuildCache[current].get().isNull())
{
// current wasn't rebuilt yet.
- uint64_t numChildren = current.getNumChildren();
+ numChildren = current.getNumChildren();
if (numChildren == 0)
{
// We only eliminate operators that are not nullary.
@@ -235,8 +231,7 @@ Node BVToInt::eliminationPass(Node n)
// The main operator is replaced, and the children
// are replaced with their eliminated counterparts.
NodeBuilder<> builder(current.getKind());
- if (current.getKind() == kind::BITVECTOR_EXTRACT
- || current.getKind() == kind::APPLY_UF)
+ if (current.getMetaKind() == kind::metakind::PARAMETERIZED)
{
builder << current.getOperator();
}
@@ -245,8 +240,8 @@ Node BVToInt::eliminationPass(Node n)
Assert(d_eliminationCache.find(child) != d_eliminationCache.end());
Node eliminatedChild = d_eliminationCache[child];
Assert(d_rebuildCache.find(eliminatedChild) != d_eliminationCache.end());
- Assert(!d_rebuildCache[eliminatedChild].isNull());
- builder << d_rebuildCache[eliminatedChild];
+ Assert(!d_rebuildCache[eliminatedChild].get().isNull());
+ builder << d_rebuildCache[eliminatedChild].get();
}
d_rebuildCache[current] = builder.constructNode();
}
@@ -256,7 +251,7 @@ Node BVToInt::eliminationPass(Node n)
Assert(d_eliminationCache.find(n) != d_eliminationCache.end());
Node eliminated = d_eliminationCache[n];
Assert(d_rebuildCache.find(eliminated) != d_rebuildCache.end());
- Assert(!d_rebuildCache[eliminated].isNull());
+ Assert(!d_rebuildCache[eliminated].get().isNull());
return d_rebuildCache[eliminated];
}
@@ -265,11 +260,15 @@ Node BVToInt::eliminationPass(Node n)
*/
Node BVToInt::bvToInt(Node n)
{
+ // make sure the node is re-written before processing it.
+ n = Rewriter::rewrite(n);
+ n = makeBinary(n);
n = eliminationPass(n);
+ // binarize again, in case the elimination pass introduced
+ // non-binary terms (as can happen by RepeatEliminate, for example).
n = makeBinary(n);
vector<Node> toVisit;
toVisit.push_back(n);
- uint64_t granularity = options::BVAndIntegerGranularity();
while (!toVisit.empty())
{
@@ -278,13 +277,23 @@ Node BVToInt::bvToInt(Node n)
if (d_bvToIntCache.find(current) == d_bvToIntCache.end())
{
// This is the first time we visit this node and it is not in the cache.
+ // We mark this node as visited but not translated by assiging
+ // a null node to it.
d_bvToIntCache[current] = Node();
+ // all the node's children are added to the stack to be visited
+ // before visiting this node again.
toVisit.insert(toVisit.end(), current.begin(), current.end());
+ // If this is a UF applicatinon, we also add the function to
+ // toVisit.
+ if (current.getKind() == kind::APPLY_UF)
+ {
+ toVisit.push_back(current.getOperator());
+ }
}
else
{
- // We already visited this node
- if (!d_bvToIntCache[current].isNull())
+ // We already visited and translated this node
+ if (!d_bvToIntCache[current].get().isNull())
{
// We are done computing the translation for current
toVisit.pop_back();
@@ -293,47 +302,10 @@ Node BVToInt::bvToInt(Node n)
{
// We are now visiting current on the way back up.
// This is when we do the actual translation.
+ Node translation;
if (currentNumChildren == 0)
{
- Assert(current.isVar() || current.isConst());
- if (current.isVar())
- {
- if (current.getType().isBitVector())
- {
- // For bit-vector variables, we create integer variables and add a
- // range constraint.
- Node newVar = d_nm->mkSkolem("__bvToInt_var",
- d_nm->integerType(),
- "Variable introduced in bvToInt "
- "pass instead of original variable "
- + current.toString());
-
- d_bvToIntCache[current] = newVar;
- d_rangeAssertions.insert(mkRangeConstraint(
- newVar, current.getType().getBitVectorSize()));
- }
- else
- {
- // variables other than bit-vector variables are left intact
- d_bvToIntCache[current] = current;
- }
- }
- else
- {
- // current is a const
- if (current.getKind() == kind::CONST_BITVECTOR)
- {
- // Bit-vector constants are transformed into their integer value.
- BitVector constant(current.getConst<BitVector>());
- Integer c = constant.toInteger();
- d_bvToIntCache[current] = d_nm->mkConst<Rational>(c);
- }
- else
- {
- // Other constants stay the same.
- d_bvToIntCache[current] = current;
- }
- }
+ translation = translateNoChildren(current);
}
else
{
@@ -341,481 +313,556 @@ Node BVToInt::bvToInt(Node n)
* The current node has children.
* Since we are on the way back up,
* these children were already translated.
- * We save their translation for future use.
+ * We save their translation for easy access.
+ * If the node's kind is APPLY_UF,
+ * we also need to include the translated uninterpreted function in
+ * this list.
*/
vector<Node> translated_children;
- for (uint64_t i = 0; i < currentNumChildren; i++)
+ if (current.getKind() == kind::APPLY_UF)
{
- translated_children.push_back(d_bvToIntCache[current[i]]);
+ translated_children.push_back(
+ d_bvToIntCache[current.getOperator()]);
}
- // The translation of the current node is determined by the kind of
- // the node.
- kind::Kind_t oldKind = current.getKind();
- //ultbv and sltbv were supposed to be eliminated before this point.
- Assert(oldKind != kind::BITVECTOR_ULTBV);
- Assert(oldKind != kind::BITVECTOR_SLTBV);
- switch (oldKind)
+ for (uint64_t i = 0; i < currentNumChildren; i++)
{
- case kind::BITVECTOR_PLUS:
- {
- uint64_t bvsize = current[0].getType().getBitVectorSize();
- /**
- * we avoid modular arithmetics by the addition of an
- * indicator variable sigma.
- * Tr(a+b) is Tr(a)+Tr(b)-(sigma*2^k),
- * with k being the bit width,
- * and sigma being either 0 or 1.
- */
- Node sigma = d_nm->mkSkolem(
- "__bvToInt_sigma_var",
- d_nm->integerType(),
- "Variable introduced in bvToInt pass to avoid integer mod");
- Node plus = d_nm->mkNode(kind::PLUS, translated_children);
- Node multSig = d_nm->mkNode(kind::MULT, sigma, pow2(bvsize));
- d_bvToIntCache[current] =
- d_nm->mkNode(kind::MINUS, plus, multSig);
- d_rangeAssertions.insert(d_nm->mkNode(kind::LEQ, d_zero, sigma));
- d_rangeAssertions.insert(d_nm->mkNode(kind::LEQ, sigma, d_one));
- d_rangeAssertions.insert(
- mkRangeConstraint(d_bvToIntCache[current], bvsize));
- break;
- }
- case kind::BITVECTOR_MULT:
- {
- uint64_t bvsize = current[0].getType().getBitVectorSize();
- /**
- * we use a similar trick to the one used for addition.
- * Tr(a*b) is Tr(a)*Tr(b)-(sigma*2^k),
- * with k being the bit width,
- * and sigma is between [0, 2^k - 1).
- */
- Node sigma = d_nm->mkSkolem(
- "__bvToInt_sigma_var",
- d_nm->integerType(),
- "Variable introduced in bvToInt pass to avoid integer mod");
- Node mult = d_nm->mkNode(kind::MULT, translated_children);
- Node multSig = d_nm->mkNode(kind::MULT, sigma, pow2(bvsize));
- d_bvToIntCache[current] =
- d_nm->mkNode(kind::MINUS, mult, multSig);
- d_rangeAssertions.insert(
- mkRangeConstraint(d_bvToIntCache[current], bvsize));
- if (translated_children[0].isConst()
- || translated_children[1].isConst())
- {
- /*
- * based on equation (23), section 3.2.3 of:
- * Bozzano et al.
- * Encoding RTL Constructs for MathSAT: a Preliminary Report.
- */
- // this is an optimization when one of the children is constant
- Node c = translated_children[0].isConst()
- ? translated_children[0]
- : translated_children[1];
- d_rangeAssertions.insert(
- d_nm->mkNode(kind::LEQ, d_zero, sigma));
- // the value of sigma is bounded by (c - 1)
- // where c is the constant multiplicand
- d_rangeAssertions.insert(d_nm->mkNode(kind::LT, sigma, c));
- }
- else
- {
- d_rangeAssertions.insert(mkRangeConstraint(sigma, bvsize));
- }
- break;
- }
- case kind::BITVECTOR_UDIV_TOTAL:
- {
- uint64_t bvsize = current[0].getType().getBitVectorSize();
- // we use an ITE for the case where the second operand is 0.
- Node pow2BvSize = pow2(bvsize);
- Node divNode =
- d_nm->mkNode(kind::INTS_DIVISION_TOTAL, translated_children);
- Node ite = d_nm->mkNode(
- kind::ITE,
- d_nm->mkNode(kind::EQUAL, translated_children[1], d_zero),
- d_nm->mkNode(kind::MINUS, pow2BvSize, d_one),
- divNode);
- d_bvToIntCache[current] = ite;
- break;
- }
- case kind::BITVECTOR_UREM_TOTAL:
- {
- // we use an ITE for the case where the second operand is 0.
- Node modNode =
- d_nm->mkNode(kind::INTS_MODULUS_TOTAL, translated_children);
- Node ite = d_nm->mkNode(
- kind::ITE,
- d_nm->mkNode(kind::EQUAL, translated_children[1], d_zero),
- translated_children[0],
- modNode);
- d_bvToIntCache[current] = ite;
- break;
- }
- case kind::BITVECTOR_NEG:
- {
- // (bvneg x) is 2^k-x, unless x is 0,
- // in which case the result should be 0.
- // This can be expressed by (2^k-x) mod 2^k
- // However, since mod is an expensive arithmetic operation,
- // we represent `bvneg` using an ITE.
- uint64_t bvsize = current[0].getType().getBitVectorSize();
- Node pow2BvSize = pow2(bvsize);
- Node neg =
- d_nm->mkNode(kind::MINUS, pow2BvSize, translated_children[0]);
- Node isZero =
- d_nm->mkNode(kind::EQUAL, translated_children[0], d_zero);
- d_bvToIntCache[current] =
- d_nm->mkNode(kind::ITE, isZero, d_zero, neg);
- break;
- }
- case kind::BITVECTOR_NOT:
- {
- uint64_t bvsize = current[0].getType().getBitVectorSize();
- // we use a specified function to generate the node.
- d_bvToIntCache[current] =
- createBVNotNode(translated_children[0], bvsize);
- break;
- }
- case kind::BITVECTOR_TO_NAT:
- {
- // In this case, we already translated the child to integer.
- // So the result is the translated child.
- d_bvToIntCache[current] = translated_children[0];
- break;
- }
- case kind::BITVECTOR_AND:
- {
- // Construct an ite, based on granularity.
- uint64_t bvsize = current[0].getType().getBitVectorSize();
- Assert(translated_children.size() == 2);
- Node newNode = createBitwiseNode(translated_children[0],
- translated_children[1],
- bvsize,
- granularity,
- &oneBitAnd);
- d_bvToIntCache[current] = newNode;
- break;
- }
- case kind::BITVECTOR_OR:
- {
- // Construct an ite, based on granularity.
- uint64_t bvsize = current[0].getType().getBitVectorSize();
- Node newNode = createBitwiseNode(translated_children[0],
- translated_children[1],
- bvsize,
- granularity,
- &oneBitOr);
- d_bvToIntCache[current] = newNode;
- break;
- }
- case kind::BITVECTOR_XOR:
- {
- // Construct an ite, based on granularity.
- uint64_t bvsize = current[0].getType().getBitVectorSize();
- Node newNode = createBitwiseNode(translated_children[0],
- translated_children[1],
- bvsize,
- granularity,
- &oneBitXor);
- d_bvToIntCache[current] = newNode;
- break;
- }
- case kind::BITVECTOR_XNOR:
- {
- // Construct an ite, based on granularity.
- uint64_t bvsize = current[0].getType().getBitVectorSize();
- Node newNode = createBitwiseNode(translated_children[0],
- translated_children[1],
- bvsize,
- granularity,
- &oneBitXnor);
- d_bvToIntCache[current] = newNode;
- break;
- }
- case kind::BITVECTOR_NAND:
- {
- // Construct an ite, based on granularity.
- uint64_t bvsize = current[0].getType().getBitVectorSize();
- Node newNode = createBitwiseNode(translated_children[0],
- translated_children[1],
- bvsize,
- granularity,
- &oneBitNand);
- d_bvToIntCache[current] = newNode;
- break;
- }
- case kind::BITVECTOR_NOR:
- {
- // Construct an ite, based on granularity.
- uint64_t bvsize = current[0].getType().getBitVectorSize();
- Node newNode = createBitwiseNode(translated_children[0],
- translated_children[1],
- bvsize,
- granularity,
- &oneBitNor);
- d_bvToIntCache[current] = newNode;
- break;
- }
- case kind::BITVECTOR_SHL:
- {
- /**
- * a << b is a*2^b.
- * The exponentiation is simulated by an ite.
- * Only cases where b <= bit width are considered.
- * Otherwise, the result is 0.
- */
- uint64_t bvsize = current[0].getType().getBitVectorSize();
- Node newNode = createShiftNode(translated_children, bvsize, true);
- d_bvToIntCache[current] = newNode;
- break;
- }
- case kind::BITVECTOR_LSHR:
- {
- /**
- * a >> b is a div 2^b.
- * The exponentiation is simulated by an ite.
- * Only cases where b <= bit width are considered.
- * Otherwise, the result is 0.
- */
- uint64_t bvsize = current[0].getType().getBitVectorSize();
- Node newNode = createShiftNode(translated_children, bvsize, false);
- d_bvToIntCache[current] = newNode;
- break;
- }
- case kind::BITVECTOR_ASHR:
- {
- /* From SMT-LIB2:
- * (bvashr s t) abbreviates
- * (ite (= ((_ extract |m-1| |m-1|) s) #b0)
- * (bvlshr s t)
- * (bvnot (bvlshr (bvnot s) t)))
- *
- * Equivalently:
- * (bvashr s t) abbreviates
- * (ite (bvult s 100000...)
- * (bvlshr s t)
- * (bvnot (bvlshr (bvnot s) t)))
- *
- */
- uint64_t bvsize = current[0].getType().getBitVectorSize();
- // signed_min is 100000...
- Node signed_min = pow2(bvsize - 1);
- Node condition =
- d_nm->mkNode(kind::LT, translated_children[0], signed_min);
- Node thenNode = createShiftNode(translated_children, bvsize, false);
- vector<Node> children = {
- createBVNotNode(translated_children[0], bvsize),
- translated_children[1]};
- Node elseNode = createBVNotNode(
- createShiftNode(children, bvsize, false), bvsize);
- Node ite = d_nm->mkNode(kind::ITE, condition, thenNode, elseNode);
- d_bvToIntCache[current] = ite;
- break;
- }
- case kind::BITVECTOR_ITE:
- {
- // Lifted to a boolean ite.
- Node cond = d_nm->mkNode(kind::EQUAL, translated_children[0], d_one);
- Node ite = d_nm->mkNode(
- kind::ITE, cond, translated_children[1], translated_children[2]);
- d_bvToIntCache[current] = ite;
- break;
- }
- case kind::BITVECTOR_CONCAT:
- {
- // (concat a b) translates to a*2^k+b, k being the bitwidth of b.
- uint64_t bvsizeRight = current[1].getType().getBitVectorSize();
- Node pow2BvSizeRight = pow2(bvsizeRight);
- Node a = d_nm->mkNode(
- kind::MULT, translated_children[0], pow2BvSizeRight);
- Node b = translated_children[1];
- Node sum = d_nm->mkNode(kind::PLUS, a, b);
- d_bvToIntCache[current] = sum;
- break;
- }
- case kind::BITVECTOR_EXTRACT:
- {
- // ((_ extract i j) a) is a / 2^j mod 2^{i-j+1}
- // current = a[i:j]
- Node a = current[0];
- uint64_t i = bv::utils::getExtractHigh(current);
- uint64_t j = bv::utils::getExtractLow(current);
- Assert(d_bvToIntCache.find(a) != d_bvToIntCache.end());
- Assert(i >= j);
- Node div = d_nm->mkNode(
- kind::INTS_DIVISION_TOTAL, d_bvToIntCache[a], pow2(j));
- d_bvToIntCache[current] = modpow2(div, i - j + 1);
- break;
- }
- case kind::EQUAL:
- {
- d_bvToIntCache[current] =
- d_nm->mkNode(kind::EQUAL, translated_children);
- break;
- }
- case kind::BITVECTOR_ULT:
- {
- d_bvToIntCache[current] =
- d_nm->mkNode(kind::LT, translated_children);
- break;
- }
- case kind::BITVECTOR_ULE:
- {
- d_bvToIntCache[current] =
- d_nm->mkNode(kind::LEQ, translated_children);
- break;
- }
- case kind::BITVECTOR_UGT:
- {
- d_bvToIntCache[current] =
- d_nm->mkNode(kind::GT, translated_children);
- break;
- }
- case kind::BITVECTOR_UGE:
- {
- d_bvToIntCache[current] =
- d_nm->mkNode(kind::GEQ, translated_children);
- break;
- }
- case kind::LT:
- {
- d_bvToIntCache[current] =
- d_nm->mkNode(kind::LT, translated_children);
- break;
- }
- case kind::LEQ:
- {
- d_bvToIntCache[current] =
- d_nm->mkNode(kind::LEQ, translated_children);
- break;
- }
- case kind::GT:
- {
- d_bvToIntCache[current] =
- d_nm->mkNode(kind::GT, translated_children);
- break;
- }
- case kind::GEQ:
- {
- d_bvToIntCache[current] =
- d_nm->mkNode(kind::GEQ, translated_children);
- break;
- }
- case kind::ITE:
- {
- d_bvToIntCache[current] = d_nm->mkNode(oldKind, translated_children);
- break;
- }
- case kind::APPLY_UF:
- {
- /*
- * We replace all BV-sorts of the domain with INT
- * If the range is a BV sort, we replace it with INT
- * We cache both the term itself (e.g., f(a)) and the function
- * symbol f.
- */
-
- //Construct the function itself
- Node bvUF = current.getOperator();
- Node intUF;
- TypeNode tn = current.getOperator().getType();
- TypeNode bvRange = tn.getRangeType();
- if (d_bvToIntCache.find(bvUF) != d_bvToIntCache.end())
- {
- intUF = d_bvToIntCache[bvUF];
- }
- else
- {
- vector<TypeNode> bvDomain = tn.getArgTypes();
- vector<TypeNode> intDomain;
- /**
- * if the original range is a bit-vector sort,
- * the new range should be an integer sort.
- * Otherwise, we keep the original range.
- */
- TypeNode intRange =
- bvRange.isBitVector() ? d_nm->integerType() : bvRange;
- for (TypeNode d : bvDomain)
- {
- intDomain.push_back(d.isBitVector() ? d_nm->integerType()
- : d);
- }
- ostringstream os;
- os << "__bvToInt_fun_" << bvUF << "_int";
- intUF =
- d_nm->mkSkolem(os.str(),
- d_nm->mkFunctionType(intDomain, intRange),
- "bv2int function");
- // Insert the function symbol itself to the cache
- d_bvToIntCache[bvUF] = intUF;
- }
- if (childrenTypesChanged(current) && options::ufHo()) {
- /**
- * higher order logic allows comparing between functions
- * The current translation does not support this,
- * as the translated functions may be different outside
- * of the bounds that were relevant for the original
- * bit-vectors.
- */
- throw TypeCheckingException(
- current.toExpr(),
- string("Cannot translate to Int: ") + current.toString());
- }
- else {
- translated_children.insert(translated_children.begin(), intUF);
- // Insert the term to the cache
- d_bvToIntCache[current] =
- d_nm->mkNode(kind::APPLY_UF, translated_children);
- /**
- * Add range constraints if necessary.
- * If the original range was a BV sort, the current application of
- * the function Must be within the range determined by the
- * bitwidth.
- */
- if (bvRange.isBitVector())
- {
- d_rangeAssertions.insert(
- mkRangeConstraint(d_bvToIntCache[current],
- current.getType().getBitVectorSize()));
- }
- }
- break;
- }
- default:
- {
- if (childrenTypesChanged(current)) {
- /**
- * This is "failing on demand":
- * We throw an exception if we encounter a case
- * that we do not know how to translate,
- * only if we actually need to construct a new
- * node for such a case.
- */
- throw TypeCheckingException(
- current.toExpr(),
- string("Cannot translate to Int: ") + current.toString());
- }
- else {
- d_bvToIntCache[current] =
- d_nm->mkNode(oldKind, translated_children);
- }
- break;
- }
+ translated_children.push_back(d_bvToIntCache[current[i]]);
}
+ translation = translateWithChildren(current, translated_children);
}
+ // Map the current node to its translation in the cache.
+ d_bvToIntCache[current] = translation;
+ // Also map the translation to itself.
+ d_bvToIntCache[translation] = translation;
toVisit.pop_back();
}
}
}
- return d_bvToIntCache[n];
+ return d_bvToIntCache[n].get();
+}
+
+Node BVToInt::translateWithChildren(Node original,
+ const vector<Node>& translated_children)
+{
+ // The translation of the original node is determined by the kind of
+ // the node.
+ kind::Kind_t oldKind = original.getKind();
+ // ultbv and sltbv were supposed to be eliminated before this point.
+ Assert(oldKind != kind::BITVECTOR_ULTBV);
+ Assert(oldKind != kind::BITVECTOR_SLTBV);
+ // The following variable will only be used in assertions.
+ CVC4_UNUSED uint64_t originalNumChildren = original.getNumChildren();
+ Node returnNode;
+ switch (oldKind)
+ {
+ case kind::BITVECTOR_PLUS:
+ {
+ Assert(originalNumChildren == 2);
+ uint64_t bvsize = original[0].getType().getBitVectorSize();
+ Node plus = d_nm->mkNode(kind::PLUS, translated_children);
+ Node p2 = pow2(bvsize);
+ returnNode = d_nm->mkNode(kind::INTS_MODULUS_TOTAL, plus, p2);
+ break;
+ }
+ case kind::BITVECTOR_MULT:
+ {
+ Assert(originalNumChildren == 2);
+ uint64_t bvsize = original[0].getType().getBitVectorSize();
+ Node mult = d_nm->mkNode(kind::MULT, translated_children);
+ Node p2 = pow2(bvsize);
+ returnNode = d_nm->mkNode(kind::INTS_MODULUS_TOTAL, mult, p2);
+ break;
+ }
+ case kind::BITVECTOR_UDIV_TOTAL:
+ {
+ uint64_t bvsize = original[0].getType().getBitVectorSize();
+ // we use an ITE for the case where the second operand is 0.
+ Node pow2BvSize = pow2(bvsize);
+ Node divNode =
+ d_nm->mkNode(kind::INTS_DIVISION_TOTAL, translated_children);
+ returnNode = d_nm->mkNode(
+ kind::ITE,
+ d_nm->mkNode(kind::EQUAL, translated_children[1], d_zero),
+ d_nm->mkNode(kind::MINUS, pow2BvSize, d_one),
+ divNode);
+ break;
+ }
+ case kind::BITVECTOR_UREM_TOTAL:
+ {
+ // we use an ITE for the case where the second operand is 0.
+ Node modNode =
+ d_nm->mkNode(kind::INTS_MODULUS_TOTAL, translated_children);
+ returnNode = d_nm->mkNode(
+ kind::ITE,
+ d_nm->mkNode(kind::EQUAL, translated_children[1], d_zero),
+ translated_children[0],
+ modNode);
+ break;
+ }
+ case kind::BITVECTOR_NOT:
+ {
+ uint64_t bvsize = original[0].getType().getBitVectorSize();
+ // we use a specified function to generate the node.
+ returnNode = createBVNotNode(translated_children[0], bvsize);
+ break;
+ }
+ case kind::BITVECTOR_TO_NAT:
+ {
+ // In this case, we already translated the child to integer.
+ // So the result is the translated child.
+ returnNode = translated_children[0];
+ break;
+ }
+ case kind::BITVECTOR_AND:
+ {
+ // We support three configurations:
+ // 1. translating to IAND
+ // 2. translating back to BV (using BITVECTOR_TO_NAT and INT_TO_BV
+ // operators)
+ // 3. translating into a sum
+ uint64_t bvsize = original[0].getType().getBitVectorSize();
+ if (options::solveBVAsInt() == options::SolveBVAsIntMode::IAND)
+ {
+ Node iAndOp = d_nm->mkConst(IntAnd(bvsize));
+ returnNode = d_nm->mkNode(
+ kind::IAND, iAndOp, translated_children[0], translated_children[1]);
+ }
+ else if (options::solveBVAsInt() == options::SolveBVAsIntMode::BV)
+ {
+ // translate the children back to BV
+ Node intToBVOp = d_nm->mkConst<IntToBitVector>(IntToBitVector(bvsize));
+ Node x = translated_children[0];
+ Node y = translated_children[1];
+ Node bvx = d_nm->mkNode(intToBVOp, x);
+ Node bvy = d_nm->mkNode(intToBVOp, y);
+ // perform bvand on the bit-vectors
+ Node bvand = d_nm->mkNode(kind::BITVECTOR_AND, bvx, bvy);
+ // translate the result to integers
+ returnNode = d_nm->mkNode(kind::BITVECTOR_TO_NAT, bvand);
+ }
+ else
+ {
+ Assert(options::solveBVAsInt() == options::SolveBVAsIntMode::SUM);
+ // Construct a sum of ites, based on granularity.
+ Assert(translated_children.size() == 2);
+ returnNode =
+ d_iandTable.createBitwiseNode(translated_children[0],
+ translated_children[1],
+ bvsize,
+ options::BVAndIntegerGranularity());
+ }
+ break;
+ }
+ case kind::BITVECTOR_SHL:
+ {
+ /**
+ * a << b is a*2^b.
+ * The exponentiation is simulated by an ite.
+ * Only cases where b <= bit width are considered.
+ * Otherwise, the result is 0.
+ */
+ uint64_t bvsize = original[0].getType().getBitVectorSize();
+ returnNode = createShiftNode(translated_children, bvsize, true);
+ break;
+ }
+ case kind::BITVECTOR_LSHR:
+ {
+ /**
+ * a >> b is a div 2^b.
+ * The exponentiation is simulated by an ite.
+ * Only cases where b <= bit width are considered.
+ * Otherwise, the result is 0.
+ */
+ uint64_t bvsize = original[0].getType().getBitVectorSize();
+ returnNode = createShiftNode(translated_children, bvsize, false);
+ break;
+ }
+ case kind::BITVECTOR_ASHR:
+ {
+ /* From SMT-LIB2:
+ * (bvashr s t) abbreviates
+ * (ite (= ((_ extract |m-1| |m-1|) s) #b0)
+ * (bvlshr s t)
+ * (bvnot (bvlshr (bvnot s) t)))
+ *
+ * Equivalently:
+ * (bvashr s t) abbreviates
+ * (ite (bvult s 100000...)
+ * (bvlshr s t)
+ * (bvnot (bvlshr (bvnot s) t)))
+ *
+ */
+ uint64_t bvsize = original[0].getType().getBitVectorSize();
+ // signed_min is 100000...
+ Node signed_min = pow2(bvsize - 1);
+ Node condition =
+ d_nm->mkNode(kind::LT, translated_children[0], signed_min);
+ Node thenNode = createShiftNode(translated_children, bvsize, false);
+ vector<Node> children = {createBVNotNode(translated_children[0], bvsize),
+ translated_children[1]};
+ Node elseNode =
+ createBVNotNode(createShiftNode(children, bvsize, false), bvsize);
+ returnNode = d_nm->mkNode(kind::ITE, condition, thenNode, elseNode);
+ break;
+ }
+ case kind::BITVECTOR_ITE:
+ {
+ // Lifted to a boolean ite.
+ Node cond = d_nm->mkNode(kind::EQUAL, translated_children[0], d_one);
+ returnNode = d_nm->mkNode(
+ kind::ITE, cond, translated_children[1], translated_children[2]);
+ break;
+ }
+ case kind::BITVECTOR_ZERO_EXTEND:
+ {
+ returnNode = translated_children[0];
+ break;
+ }
+ case kind::BITVECTOR_SIGN_EXTEND:
+ {
+ uint64_t bvsize = original[0].getType().getBitVectorSize();
+ Node arg = translated_children[0];
+ if (arg.isConst())
+ {
+ Rational c(arg.getConst<Rational>());
+ Rational twoToKMinusOne(intpow2(bvsize - 1));
+ uint64_t amount = bv::utils::getSignExtendAmount(original);
+ /* if the msb is 0, this is like zero_extend.
+ * msb is 0 <-> the value is less than 2^{bvsize-1}
+ */
+ if (c < twoToKMinusOne || amount == 0)
+ {
+ returnNode = arg;
+ }
+ else
+ {
+ /* otherwise, we add the integer equivalent of
+ * 11....1 `amount` times
+ */
+ Rational max_of_amount = intpow2(amount) - 1;
+ Rational mul = max_of_amount * intpow2(bvsize);
+ Rational sum = mul + c;
+ returnNode = d_nm->mkConst(sum);
+ }
+ }
+ else
+ {
+ uint64_t amount = bv::utils::getSignExtendAmount(original);
+ if (amount == 0)
+ {
+ returnNode = translated_children[0];
+ }
+ else
+ {
+ Rational twoToKMinusOne(intpow2(bvsize - 1));
+ Node minSigned = d_nm->mkConst(twoToKMinusOne);
+ /* condition checks whether the msb is 1.
+ * This holds when the integer value is smaller than
+ * 100...0, which is 2^{bvsize-1}.
+ */
+ Node condition = d_nm->mkNode(kind::LT, arg, minSigned);
+ Node thenResult = arg;
+ Node left = maxInt(amount);
+ Node mul = d_nm->mkNode(kind::MULT, left, pow2(bvsize));
+ Node sum = d_nm->mkNode(kind::PLUS, mul, arg);
+ Node elseResult = sum;
+ Node ite = d_nm->mkNode(kind::ITE, condition, thenResult, elseResult);
+ returnNode = ite;
+ }
+ }
+ break;
+ }
+ case kind::BITVECTOR_CONCAT:
+ {
+ // (concat a b) translates to a*2^k+b, k being the bitwidth of b.
+ uint64_t bvsizeRight = original[1].getType().getBitVectorSize();
+ Node pow2BvSizeRight = pow2(bvsizeRight);
+ Node a =
+ d_nm->mkNode(kind::MULT, translated_children[0], pow2BvSizeRight);
+ Node b = translated_children[1];
+ returnNode = d_nm->mkNode(kind::PLUS, a, b);
+ break;
+ }
+ case kind::BITVECTOR_EXTRACT:
+ {
+ // ((_ extract i j) a) is a / 2^j mod 2^{i-j+1}
+ // original = a[i:j]
+ uint64_t i = bv::utils::getExtractHigh(original);
+ uint64_t j = bv::utils::getExtractLow(original);
+ Assert(i >= j);
+ Node div = d_nm->mkNode(
+ kind::INTS_DIVISION_TOTAL, translated_children[0], pow2(j));
+ returnNode = modpow2(div, i - j + 1);
+ break;
+ }
+ case kind::EQUAL:
+ {
+ returnNode = d_nm->mkNode(kind::EQUAL, translated_children);
+ break;
+ }
+ case kind::BITVECTOR_ULT:
+ {
+ returnNode = d_nm->mkNode(kind::LT, translated_children);
+ break;
+ }
+ case kind::BITVECTOR_ULE:
+ {
+ returnNode = d_nm->mkNode(kind::LEQ, translated_children);
+ break;
+ }
+ case kind::BITVECTOR_UGT:
+ {
+ returnNode = d_nm->mkNode(kind::GT, translated_children);
+ break;
+ }
+ case kind::BITVECTOR_UGE:
+ {
+ returnNode = d_nm->mkNode(kind::GEQ, translated_children);
+ break;
+ }
+ case kind::LT:
+ {
+ returnNode = d_nm->mkNode(kind::LT, translated_children);
+ break;
+ }
+ case kind::LEQ:
+ {
+ returnNode = d_nm->mkNode(kind::LEQ, translated_children);
+ break;
+ }
+ case kind::GT:
+ {
+ returnNode = d_nm->mkNode(kind::GT, translated_children);
+ break;
+ }
+ case kind::GEQ:
+ {
+ returnNode = d_nm->mkNode(kind::GEQ, translated_children);
+ break;
+ }
+ case kind::ITE:
+ {
+ returnNode = d_nm->mkNode(oldKind, translated_children);
+ break;
+ }
+ case kind::APPLY_UF:
+ {
+ /**
+ * higher order logic allows comparing between functions
+ * The translation does not support this,
+ * as the translated functions may be different outside
+ * of the bounds that were relevant for the original
+ * bit-vectors.
+ */
+ if (childrenTypesChanged(original) && options::ufHo())
+ {
+ throw TypeCheckingException(
+ original.toExpr(),
+ string("Cannot translate to Int: ") + original.toString());
+ }
+ // Insert the translated application term to the cache
+ returnNode = d_nm->mkNode(kind::APPLY_UF, translated_children);
+ // Add range constraints if necessary.
+ // If the original range was a BV sort, the original application of
+ // the function Must be within the range determined by the
+ // bitwidth.
+ if (original.getType().isBitVector())
+ {
+ d_rangeAssertions.insert(mkRangeConstraint(
+ returnNode, original.getType().getBitVectorSize()));
+ }
+ break;
+ }
+ case kind::BOUND_VAR_LIST:
+ {
+ returnNode = d_nm->mkNode(oldKind, translated_children);
+ break;
+ }
+ case kind::FORALL:
+ {
+ returnNode = translateQuantifiedFormula(original);
+ break;
+ }
+ case kind::EXISTS:
+ {
+ // Exists is eliminated by the rewriter.
+ Assert(false);
+ }
+ default:
+ {
+ // In the default case, we have reached an operator that we do not
+ // translate directly to integers. The children whose types have
+ // changed from bv to int should be adjusted back to bv and then
+ // this term is reconstructed.
+ TypeNode resultingType;
+ if (original.getType().isBitVector())
+ {
+ resultingType = d_nm->integerType();
+ }
+ else
+ {
+ resultingType = original.getType();
+ }
+ Node reconstruction =
+ reconstructNode(original, resultingType, translated_children);
+ returnNode = reconstruction;
+ break;
+ }
+ }
+ Trace("bv-to-int-debug") << "original: " << original << endl;
+ Trace("bv-to-int-debug") << "returnNode: " << returnNode << endl;
+ return returnNode;
+}
+
+Node BVToInt::translateNoChildren(Node original)
+{
+ Node translation;
+ Assert(original.isVar() || original.isConst());
+ if (original.isVar())
+ {
+ if (original.getType().isBitVector())
+ {
+ // For bit-vector variables, we create fresh integer variables.
+ if (original.getKind() == kind::BOUND_VARIABLE)
+ {
+ // Range constraints for the bound integer variables are not added now.
+ // they will be added once the quantifier itself is handled.
+ std::stringstream ss;
+ ss << original;
+ translation = d_nm->mkBoundVar(ss.str() + "_int", d_nm->integerType());
+ }
+ else
+ {
+ // New integer variables that are not bound (symbolic constants)
+ // are added together with range constraints induced by the
+ // bit-width of the original bit-vector variables.
+ Node newVar = d_nm->mkSkolem("__bvToInt_var",
+ d_nm->integerType(),
+ "Variable introduced in bvToInt "
+ "pass instead of original variable "
+ + original.toString());
+ uint64_t bvsize = original.getType().getBitVectorSize();
+ translation = newVar;
+ d_rangeAssertions.insert(mkRangeConstraint(newVar, bvsize));
+ defineBVUFAsIntUF(original, newVar);
+ }
+ }
+ else if (original.getType().isFunction())
+ {
+ translation = translateFunctionSymbol(original);
+ }
+ else
+ {
+ // variables other than bit-vector variables and function symbols
+ // are left intact
+ translation = original;
+ }
+ }
+ else
+ {
+ // original is a const
+ if (original.getKind() == kind::CONST_BITVECTOR)
+ {
+ // Bit-vector constants are transformed into their integer value.
+ BitVector constant(original.getConst<BitVector>());
+ Integer c = constant.toInteger();
+ translation = d_nm->mkConst<Rational>(c);
+ }
+ else
+ {
+ // Other constants stay the same.
+ translation = original;
+ }
+ }
+ return translation;
+}
+
+Node BVToInt::translateFunctionSymbol(Node bvUF)
+{
+ // construct the new function symbol.
+ Node intUF;
+ TypeNode tn = bvUF.getType();
+ TypeNode bvRange = tn.getRangeType();
+ // The function symbol has not been converted yet
+ vector<TypeNode> bvDomain = tn.getArgTypes();
+ vector<TypeNode> intDomain;
+ /**
+ * if the original range is a bit-vector sort,
+ * the new range should be an integer sort.
+ * Otherwise, we keep the original range.
+ * Similarly for the domains.
+ */
+ TypeNode intRange = bvRange.isBitVector() ? d_nm->integerType() : bvRange;
+ for (TypeNode d : bvDomain)
+ {
+ intDomain.push_back(d.isBitVector() ? d_nm->integerType() : d);
+ }
+ ostringstream os;
+ os << "__bvToInt_fun_" << bvUF << "_int";
+ intUF = d_nm->mkSkolem(
+ os.str(), d_nm->mkFunctionType(intDomain, intRange), "bv2int function");
+ // introduce a `define-fun` in the smt-engine to keep
+ // the correspondence between the original
+ // function symbol and the new one.
+ defineBVUFAsIntUF(bvUF, intUF);
+ return intUF;
+}
+
+void BVToInt::defineBVUFAsIntUF(Node bvUF, Node intUF)
+{
+ // The resulting term
+ Node result;
+ // The type of the resulting term
+ TypeNode resultType;
+ // symbolic arguments of original function
+ vector<Node> args;
+ if (!bvUF.getType().isFunction()) {
+ // bvUF is a variable.
+ // in this case, the result is just the original term
+ // (it will be casted later if needed)
+ result = intUF;
+ resultType = bvUF.getType();
+ } else {
+ // bvUF is a function with arguments
+ // The arguments need to be casted as well.
+ TypeNode tn = bvUF.getType();
+ resultType = tn.getRangeType();
+ vector<TypeNode> bvDomain = tn.getArgTypes();
+ // children of the new symbolic application
+ vector<Node> achildren;
+ achildren.push_back(intUF);
+ int i = 0;
+ for (const TypeNode& d : bvDomain)
+ {
+ // Each bit-vector argument is casted to a natural number
+ // Other arguments are left intact.
+ Node fresh_bound_var = d_nm->mkBoundVar(d);
+ args.push_back(fresh_bound_var);
+ Node castedArg = args[i];
+ if (d.isBitVector())
+ {
+ castedArg = castToType(castedArg, d_nm->integerType());
+ }
+ achildren.push_back(castedArg);
+ i++;
+ }
+ result = d_nm->mkNode(kind::APPLY_UF, achildren);
+ }
+ // If the result is BV, it needs to be casted back.
+ result = castToType(result, resultType);
+ // add the function definition to the smt engine.
+ d_preprocContext->getSmt()->defineFunction(bvUF, args, result, true);
}
-bool BVToInt::childrenTypesChanged(Node n) {
+bool BVToInt::childrenTypesChanged(Node n)
+{
bool result = false;
- for (Node child : n) {
+ for (const Node& child : n)
+ {
TypeNode originalType = child.getType();
- TypeNode newType = d_bvToIntCache[child].getType();
- if (! newType.isSubtypeOf(originalType)) {
+ TypeNode newType = d_bvToIntCache[child].get().getType();
+ if (!newType.isSubtypeOf(originalType))
+ {
result = true;
break;
}
@@ -823,12 +870,61 @@ bool BVToInt::childrenTypesChanged(Node n) {
return result;
}
+Node BVToInt::castToType(Node n, TypeNode tn)
+{
+ // If there is no reason to cast, return the
+ // original node.
+ if (n.getType().isSubtypeOf(tn))
+ {
+ return n;
+ }
+ // We only case int to bv or vice verse.
+ Assert((n.getType().isBitVector() && tn.isInteger())
+ || (n.getType().isInteger() && tn.isBitVector()));
+ if (n.getType().isInteger())
+ {
+ Assert(tn.isBitVector());
+ unsigned bvsize = tn.getBitVectorSize();
+ Node intToBVOp = d_nm->mkConst<IntToBitVector>(IntToBitVector(bvsize));
+ return d_nm->mkNode(intToBVOp, n);
+ }
+ Assert(n.getType().isBitVector());
+ Assert(tn.isInteger());
+ return d_nm->mkNode(kind::BITVECTOR_TO_NAT, n);
+}
+
+Node BVToInt::reconstructNode(Node originalNode,
+ TypeNode resultType,
+ const vector<Node>& translated_children)
+{
+ // first, we adjust the children of the node as needed.
+ // re-construct the term with the adjusted children.
+ kind::Kind_t oldKind = originalNode.getKind();
+ NodeBuilder<> builder(oldKind);
+ if (originalNode.getMetaKind() == kind::metakind::PARAMETERIZED)
+ {
+ builder << originalNode.getOperator();
+ }
+ for (size_t i = 0; i < originalNode.getNumChildren(); i++)
+ {
+ Node originalChild = originalNode[i];
+ Node translatedChild = translated_children[i];
+ Node adjustedChild = castToType(translatedChild, originalChild.getType());
+ builder << adjustedChild;
+ }
+ Node reconstruction = builder.constructNode();
+ // cast to tn in case the reconstruction is a bit-vector.
+ reconstruction = castToType(reconstruction, resultType);
+ return reconstruction;
+}
+
BVToInt::BVToInt(PreprocessingPassContext* preprocContext)
: PreprocessingPass(preprocContext, "bv-to-int"),
- d_binarizeCache(),
- d_eliminationCache(),
- d_bvToIntCache(),
- d_rangeAssertions()
+ d_binarizeCache(preprocContext->getUserContext()),
+ d_eliminationCache(preprocContext->getUserContext()),
+ d_rebuildCache(preprocContext->getUserContext()),
+ d_bvToIntCache(preprocContext->getUserContext()),
+ d_rangeAssertions(preprocContext->getUserContext())
{
d_nm = NodeManager::currentNM();
d_zero = d_nm->mkConst<Rational>(0);
@@ -838,7 +934,6 @@ BVToInt::BVToInt(PreprocessingPassContext* preprocContext)
PreprocessingPassResult BVToInt::applyInternal(
AssertionPipeline* assertionsToPreprocess)
{
- AlwaysAssert(!options::incrementalSolving());
for (uint64_t i = 0; i < assertionsToPreprocess->size(); ++i)
{
Node bvNode = (*assertionsToPreprocess)[i];
@@ -856,167 +951,106 @@ PreprocessingPassResult BVToInt::applyInternal(
void BVToInt::addFinalizeRangeAssertions(
AssertionPipeline* assertionsToPreprocess)
{
+ // collect the range assertions from d_rangeAssertions
+ // (which is a context-dependent set)
+ // into a vector.
vector<Node> vec_range;
- vec_range.assign(d_rangeAssertions.begin(), d_rangeAssertions.end());
- if (vec_range.size() == 1)
- {
- assertionsToPreprocess->push_back(vec_range[0]);
- Trace("bv-to-int-debug")
- << "range constraints: " << vec_range[0].toString() << std::endl;
- }
- else if (vec_range.size() >= 2)
- {
- Node rangeAssertions =
- Rewriter::rewrite(d_nm->mkNode(kind::AND, vec_range));
- assertionsToPreprocess->push_back(rangeAssertions);
- Trace("bv-to-int-debug")
- << "range constraints: " << rangeAssertions.toString() << std::endl;
- }
+ vec_range.assign(d_rangeAssertions.key_begin(), d_rangeAssertions.key_end());
+ // conjoin all range assertions and add the conjunction
+ // as a new assertion
+ Node rangeAssertions = Rewriter::rewrite(d_nm->mkAnd(vec_range));
+ assertionsToPreprocess->push_back(rangeAssertions);
+ Trace("bv-to-int-debug") << "range constraints: "
+ << rangeAssertions.toString() << std::endl;
}
Node BVToInt::createShiftNode(vector<Node> children,
uint64_t bvsize,
bool isLeftShift)
{
- Node x = children[0];
- Node y = children[1];
- Assert(!y.isConst());
- // ite represents 2^x for every integer x from 0 to bvsize-1.
- Node ite = pow2(0);
- for (uint64_t i = 1; i < bvsize; i++)
- {
- ite = d_nm->mkNode(kind::ITE,
- d_nm->mkNode(kind::EQUAL, y, d_nm->mkConst<Rational>(i)),
- pow2(i),
- ite);
- }
/**
* from SMT-LIB:
* [[(bvshl s t)]] := nat2bv[m](bv2nat([[s]]) * 2^(bv2nat([[t]])))
* [[(bvlshr s t)]] := nat2bv[m](bv2nat([[s]]) div 2^(bv2nat([[t]])))
- * Since we don't have exponentiation, we use the ite declared above.
+ * Since we don't have exponentiation, we use an ite.
+ * Important note: below we use INTS_DIVISION_TOTAL, which is safe here
+ * because we divide by 2^... which is never 0.
*/
- kind::Kind_t then_kind = isLeftShift ? kind::MULT : kind::INTS_DIVISION_TOTAL;
- return d_nm->mkNode(kind::ITE,
- d_nm->mkNode(kind::LT, y, d_nm->mkConst<Rational>(bvsize)),
- d_nm->mkNode(kind::INTS_MODULUS_TOTAL,
- d_nm->mkNode(then_kind, x, ite),
- pow2(bvsize)),
- d_zero);
-}
-
-Node BVToInt::createITEFromTable(
- Node x,
- Node y,
- uint64_t granularity,
- std::map<std::pair<uint64_t, uint64_t>, uint64_t> table)
-{
- Assert(granularity <= 8);
- uint64_t max_value = ((uint64_t)pow(2, granularity));
- // The table represents a function from pairs of integers to integers, where
- // all integers are between 0 (inclusive) and max_value (exclusive).
- Assert(table.size() == max_value * max_value);
- Node ite = d_nm->mkConst<Rational>(table[std::make_pair(0, 0)]);
- for (uint64_t i = 0; i < max_value; i++)
+ Node x = children[0];
+ Node y = children[1];
+ // shifting by const is eliminated by the theory rewriter
+ Assert(!y.isConst());
+ Node ite = d_zero;
+ Node body;
+ for (uint64_t i = 0; i < bvsize; i++)
{
- for (uint64_t j = 0; j < max_value; j++)
+ if (isLeftShift)
{
- if ((i == 0) && (j == 0))
- {
- continue;
- }
- ite = d_nm->mkNode(
- kind::ITE,
- d_nm->mkNode(
- kind::AND,
- d_nm->mkNode(kind::EQUAL, x, d_nm->mkConst<Rational>(i)),
- d_nm->mkNode(kind::EQUAL, y, d_nm->mkConst<Rational>(j))),
- d_nm->mkConst<Rational>(table[std::make_pair(i, j)]),
- ite);
+ body = d_nm->mkNode(kind::INTS_MODULUS_TOTAL,
+ d_nm->mkNode(kind::MULT, x, pow2(i)),
+ pow2(bvsize));
}
+ else
+ {
+ body = d_nm->mkNode(kind::INTS_DIVISION_TOTAL, x, pow2(i));
+ }
+ ite = d_nm->mkNode(kind::ITE,
+ d_nm->mkNode(kind::EQUAL, y, d_nm->mkConst<Rational>(i)),
+ body,
+ ite);
}
return ite;
}
-Node BVToInt::createBitwiseNode(Node x,
- Node y,
- uint64_t bvsize,
- uint64_t granularity,
- bool (*f)(bool, bool))
+Node BVToInt::translateQuantifiedFormula(Node quantifiedNode)
{
- /**
- * Standardize granularity.
- * If it is greater than bvsize, it is set to bvsize.
- * Otherwise, it is set to the closest (going down) divider of bvsize.
- */
- Assert(granularity > 0);
- if (granularity > bvsize)
+ kind::Kind_t k = quantifiedNode.getKind();
+ Node boundVarList = quantifiedNode[0];
+ Assert(boundVarList.getKind() == kind::BOUND_VAR_LIST);
+ // Since bit-vector variables are being translated to
+ // integer variables, we need to substitute the new ones
+ // for the old ones.
+ vector<Node> oldBoundVars;
+ vector<Node> newBoundVars;
+ vector<Node> rangeConstraints;
+ for (Node bv : quantifiedNode[0])
{
- granularity = bvsize;
- }
- else
- {
- while (bvsize % granularity != 0)
+ oldBoundVars.push_back(bv);
+ if (bv.getType().isBitVector())
{
- granularity = granularity - 1;
+ // bit-vector variables are replaced by integer ones.
+ // the new variables induce range constraints based on the
+ // original bit-width.
+ Node newBoundVar = d_bvToIntCache[bv];
+ newBoundVars.push_back(newBoundVar);
+ rangeConstraints.push_back(
+ mkRangeConstraint(newBoundVar, bv.getType().getBitVectorSize()));
}
- }
- // transform f into a table
- // f is defined over 1 bit, while the table is defined over `granularity` bits
- std::map<std::pair<uint64_t, uint64_t>, uint64_t> table;
- uint64_t max_value = ((uint64_t)pow(2, granularity));
- for (uint64_t i = 0; i < max_value; i++)
- {
- for (uint64_t j = 0; j < max_value; j++)
+ else
{
- uint64_t sum = 0;
- for (uint64_t n = 0; n < granularity; n++)
- {
- // b is the result of f on the current bit
- bool b = f((((i >> n) & 1) == 1), (((j >> n) & 1) == 1));
- // add the corresponding power of 2 only if the result is 1
- if (b)
- {
- sum += 1 << n;
- }
- }
- table[std::make_pair(i, j)] = sum;
+ // variables that are not bit-vectors are not changed
+ newBoundVars.push_back(bv);
}
}
- Assert(table.size() == max_value * max_value);
- /*
- * Create the sum.
- * For granularity 1, the sum has bvsize elements.
- * In contrast, if bvsize = granularity, sum has one element.
- * Each element in the sum is an ite that corresponds to the generated table,
- * multiplied by the appropriate power of two.
- * More details are in bv_to_int.h .
- */
- uint64_t sumSize = bvsize / granularity;
- Node sumNode = d_zero;
- /**
- * extract definition in integers is:
- * (define-fun intextract ((k Int) (i Int) (j Int) (a Int)) Int
- * (mod (div a (two_to_the j)) (two_to_the (+ (- i j) 1))))
- */
- for (uint64_t i = 0; i < sumSize; i++)
- {
- Node xExtract = d_nm->mkNode(
- kind::INTS_MODULUS_TOTAL,
- d_nm->mkNode(kind::INTS_DIVISION_TOTAL, x, pow2(i * granularity)),
- pow2(granularity));
- Node yExtract = d_nm->mkNode(
- kind::INTS_MODULUS_TOTAL,
- d_nm->mkNode(kind::INTS_DIVISION_TOTAL, y, pow2(i * granularity)),
- pow2(granularity));
- Node ite = createITEFromTable(xExtract, yExtract, granularity, table);
- sumNode =
- d_nm->mkNode(kind::PLUS,
- sumNode,
- d_nm->mkNode(kind::MULT, pow2(i * granularity), ite));
- }
- return sumNode;
+ // the body of the quantifier
+ Node matrix = d_bvToIntCache[quantifiedNode[1]];
+ // make the substitution
+ matrix = matrix.substitute(oldBoundVars.begin(),
+ oldBoundVars.end(),
+ newBoundVars.begin(),
+ newBoundVars.end());
+ // A node to represent all the range constraints.
+ Node ranges = d_nm->mkAnd(rangeConstraints);
+ // Add the range constraints to the body of the quantifier.
+ // For "exists", this is added conjunctively
+ // For "forall", this is added to the left side of an implication.
+ matrix = d_nm->mkNode(
+ k == kind::FORALL ? kind::IMPLIES : kind::AND, ranges, matrix);
+ // create the new quantified formula and return it.
+ Node newBoundVarsList = d_nm->mkNode(kind::BOUND_VAR_LIST, newBoundVars);
+ Node result = d_nm->mkNode(kind::FORALL, newBoundVarsList, matrix);
+ return result;
}
Node BVToInt::createBVNotNode(Node n, uint64_t bvsize)
diff --git a/src/preprocessing/passes/bv_to_int.h b/src/preprocessing/passes/bv_to_int.h
index 5015d1e8e..0f6a6a4bb 100644
--- a/src/preprocessing/passes/bv_to_int.h
+++ b/src/preprocessing/passes/bv_to_int.h
@@ -5,7 +5,7 @@
** Yoni Zohar
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,10 +18,18 @@
** Tr(x) = fresh_x for every bit-vector variable x, where fresh_x is a fresh
** integer variable.
** Tr(c) = the integer value of c, for any bit-vector constant c.
- ** Tr((bvadd s t)) = Tr(s) + Tr(t) mod 2^k, where k is the bit width of
+ ** Tr((bvadd s t)) = Tr(s) + Tr(t) mod 2^k, where k is the bit width of
** s and t.
** Similar transformations are done for bvmul, bvsub, bvudiv, bvurem, bvneg,
** bvnot, bvconcat, bvextract
+ ** Tr((_ zero_extend m) x) = Tr(x)
+ ** Tr((_ sign_extend m) x) = ite(msb(x)=0, x, 2^k*(2^m-1) + x))
+ ** explanation: if the msb is 0, this is the same as zero_extend,
+ ** which does not change the integer value.
+ ** If the msb is 1, then the result should correspond to
+ ** concat(1...1, x), with m 1's.
+ ** m 1's is 2^m-1, and multiplying it by x's width (k) moves it
+ ** to the front.
**
** Tr((bvand s t)) depends on the granularity, which is provided by the user
** when enabling this preprocessing pass.
@@ -62,14 +70,18 @@
#ifndef __CVC4__PREPROCESSING__PASSES__BV_TO_INT_H
#define __CVC4__PREPROCESSING__PASSES__BV_TO_INT_H
+#include "context/cdhashmap.h"
+#include "context/cdo.h"
+#include "context/context.h"
#include "preprocessing/preprocessing_pass.h"
#include "preprocessing/preprocessing_pass_context.h"
+#include "theory/arith/nl/iand_table.h"
namespace CVC4 {
namespace preprocessing {
namespace passes {
-using NodeMap = std::unordered_map<Node, Node, NodeHashFunction>;
+using CDNodeMap = context::CDHashMap<Node, Node, NodeHashFunction>;
class BVToInt : public PreprocessingPass
{
@@ -79,79 +91,6 @@ class BVToInt : public PreprocessingPass
protected:
PreprocessingPassResult applyInternal(
AssertionPipeline* assertionsToPreprocess) override;
-
- /**
- * A generic function that creates a node that represents a bitwise
- * operation.
- *
- * For example: Suppose bvsize is 4, granularity is 1, and f(x,y) = x && y.
- * Denote by ITE(a,b) the term: ite(a==0, 0, ite(b==1, 1, 0)).
- * The result of this function would be:
- * ITE(x[0], y[0])*2^0 + ... + ITE(x[3], y[3])*2^3
- *
- * For another example: Suppose bvsize is 4, granularity is 2,
- * and f(x,y) = x && y.
- * Denote by ITE(a,b) the term that corresponds to the following table:
- * a | b | ITE(a,b)
- * ----------------
- * 0 | 0 | 0
- * 0 | 1 | 0
- * 0 | 2 | 0
- * 0 | 3 | 0
- * 1 | 0 | 0
- * 1 | 1 | 1
- * 1 | 2 | 0
- * 1 | 3 | 1
- * 2 | 0 | 0
- * 2 | 1 | 0
- * 2 | 2 | 2
- * 2 | 3 | 2
- * 3 | 0 | 0
- * 3 | 1 | 1
- * 3 | 2 | 2
- * 3 | 3 | 3
- *
- * For example, 2 in binary is 10 and 1 in binary is 01, and so doing
- * "bitwise f" on them gives 00.
- * The result of this function would be:
- * ITE(x[1:0], y[1:0])*2^0 + ITE(x[3:2], y[3:2])*2^2
- *
- *
- * @param x is an integer operand that correspond to the first original
- * bit-vector operand.
- * @param y is an integer operand that correspond to the second original
- * bit-vector operand.
- * @param bvsize is the bit width of the original bit-vector variables.
- * @param granularity is specified in the options for this preprocessing
- * pass.
- * @param f is a pointer to a boolean function that corresponds
- * to the original bitwise operation.
- * @return A node that represents the operation, as described above.
- */
- Node createBitwiseNode(Node x,
- Node y,
- uint64_t bvsize,
- uint64_t granularity,
- bool (*f)(bool, bool));
-
- /**
- * A helper function for createBitwiseNode
- * @param x integer node corresponding to the original first bit-vector
- * argument
- * @param y integer node corresponding to the original second bit-vector
- * argument nodes.
- * @param granularity the bitwidth of the original bit-vector nodes.
- * @param table a function from pairs of integers to integers.
- * The domain of this function consists of pairs of
- * integers between 0 (inclusive) and 2^{bitwidth} (exclusive).
- * @return An ite term that represents this table.
- */
- Node createITEFromTable(
- Node x,
- Node y,
- uint64_t granularity,
- std::map<std::pair<uint64_t, uint64_t>, uint64_t> table);
-
/**
* A generic function that creates a logical shift node (either left or
* right). a << b gets translated to a * 2^b mod 2^k, where k is the bit
@@ -243,12 +182,89 @@ class BVToInt : public PreprocessingPass
void addFinalizeRangeAssertions(AssertionPipeline* assertionsToPreprocess);
/**
+ * @param quantifiedNode a node whose main operator is forall/exists.
+ * @return a node opbtained from quantifiedNode by:
+ * 1. Replacing all bound BV variables by new bound integer variables.
+ * 2. Add range constraints for the new variables, induced by the original
+ * bit-width. These range constraints are added with "AND" in case of exists
+ * and with "IMPLIES" in case of forall.
+ */
+ Node translateQuantifiedFormula(Node quantifiedNode);
+
+ /**
+ * Reconstructs a node whose main operator cannot be
+ * translated to integers.
+ * Reconstruction is done by casting to integers/bit-vectors
+ * as needed.
+ * For example, if node is (select A x) where A
+ * is a bit-vector array, we do not change A to be
+ * an integer array, even though x was translated
+ * to integers.
+ * In this case we cast x to (bv2nat x) during
+ * the reconstruction.
+ *
+ * @param originalNode the node that we are reconstructing
+ * @param resultType the desired type for the reconstruction
+ * @param translated_children the children of originalNode
+ * after their translation to integers.
+ * @return A node with originalNode's operator that has type resultType.
+ */
+ Node reconstructNode(Node originalNode,
+ TypeNode resultType,
+ const vector<Node>& translated_children);
+
+ /**
+ * A useful utility function.
+ * if n is an integer and tn is bit-vector,
+ * applies the IntToBitVector operator on n.
+ * if n is a vit-vector and tn is integer,
+ * applies BitVector_TO_NAT operator.
+ * Otherwise, keeps n intact.
+ */
+ Node castToType(Node n, TypeNode tn);
+
+ /**
+ * When a UF f is translated to a UF g,
+ * we add a define-fun command to the smt-engine
+ * to relate between f and g.
+ * We do the same when f and g are just variables.
+ * This is useful, for example, when asking
+ * for a model-value of a term that includes the
+ * original UF f.
+ * @param bvUF the original function or variable
+ * @param intUF the translated function or variable
+ */
+ void defineBVUFAsIntUF(Node bvUF, Node intUF);
+
+ /**
+ * @param bvUF is an uninterpreted function symbol from the original formula
+ * @return a fresh uninterpreted function symbol, obtained from bvUF
+ by replacing every argument of type BV to an argument of type Integer,
+ and the return type becomes integer in case it was BV.
+ */
+ Node translateFunctionSymbol(Node bvUF);
+
+ /**
+ * Performs the actual translation to integers for nodes
+ * that have children.
+ */
+ Node translateWithChildren(Node original,
+ const vector<Node>& translated_children);
+
+ /**
+ * Performs the actual translation to integers for nodes
+ * that don't have children (variables, constants, uninterpreted function
+ * symbols).
+ */
+ Node translateNoChildren(Node original);
+
+ /**
* Caches for the different functions
*/
- NodeMap d_binarizeCache;
- NodeMap d_eliminationCache;
- NodeMap d_rebuildCache;
- NodeMap d_bvToIntCache;
+ CDNodeMap d_binarizeCache;
+ CDNodeMap d_eliminationCache;
+ CDNodeMap d_rebuildCache;
+ CDNodeMap d_bvToIntCache;
/**
* Node manager that is used throughout the pass
@@ -259,13 +275,16 @@ class BVToInt : public PreprocessingPass
* A set of constraints of the form 0 <= x < 2^k
* These are added for every new integer variable that we introduce.
*/
- unordered_set<Node, NodeHashFunction> d_rangeAssertions;
+ context::CDHashSet<Node, NodeHashFunction> d_rangeAssertions;
/**
* Useful constants
*/
Node d_zero;
Node d_one;
+
+ /** helper class for handeling bvand translation */
+ theory::arith::nl::IAndTable d_iandTable;
};
} // namespace passes
diff --git a/src/preprocessing/passes/extended_rewriter_pass.cpp b/src/preprocessing/passes/extended_rewriter_pass.cpp
index 39b3e1512..f1cdd5b5d 100644
--- a/src/preprocessing/passes/extended_rewriter_pass.cpp
+++ b/src/preprocessing/passes/extended_rewriter_pass.cpp
@@ -5,7 +5,7 @@
** Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/extended_rewriter_pass.h b/src/preprocessing/passes/extended_rewriter_pass.h
index de6648d17..f4314a123 100644
--- a/src/preprocessing/passes/extended_rewriter_pass.h
+++ b/src/preprocessing/passes/extended_rewriter_pass.h
@@ -5,7 +5,7 @@
** Haniel Barbosa, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/fun_def_fmf.cpp b/src/preprocessing/passes/fun_def_fmf.cpp
new file mode 100644
index 000000000..6095be228
--- /dev/null
+++ b/src/preprocessing/passes/fun_def_fmf.cpp
@@ -0,0 +1,464 @@
+/********************* */
+/*! \file fun_def_fmf.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Function definition processor for finite model finding
+ **/
+
+#include "preprocessing/passes/fun_def_fmf.h"
+
+#include "options/smt_options.h"
+#include "proof/proof_manager.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
+#include "theory/quantifiers/term_database.h"
+#include "theory/quantifiers/term_util.h"
+
+using namespace std;
+using namespace CVC4::kind;
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+
+namespace CVC4 {
+namespace preprocessing {
+namespace passes {
+
+FunDefFmf::FunDefFmf(PreprocessingPassContext* preprocContext)
+ : PreprocessingPass(preprocContext, "fun-def-fmf"),
+ d_fmfRecFunctionsDefined(nullptr)
+{
+ d_fmfRecFunctionsDefined =
+ new (true) NodeList(preprocContext->getUserContext());
+}
+
+FunDefFmf::~FunDefFmf() { d_fmfRecFunctionsDefined->deleteSelf(); }
+
+PreprocessingPassResult FunDefFmf::applyInternal(
+ AssertionPipeline* assertionsToPreprocess)
+{
+ Assert(d_fmfRecFunctionsDefined != nullptr);
+ // reset
+ d_sorts.clear();
+ d_input_arg_inj.clear();
+ d_funcs.clear();
+ // must carry over current definitions (in case of incremental)
+ for (context::CDList<Node>::const_iterator fit =
+ d_fmfRecFunctionsDefined->begin();
+ fit != d_fmfRecFunctionsDefined->end();
+ ++fit)
+ {
+ Node f = (*fit);
+ Assert(d_fmfRecFunctionsAbs.find(f) != d_fmfRecFunctionsAbs.end());
+ TypeNode ft = d_fmfRecFunctionsAbs[f];
+ d_sorts[f] = ft;
+ std::map<Node, std::vector<Node>>::iterator fcit =
+ d_fmfRecFunctionsConcrete.find(f);
+ Assert(fcit != d_fmfRecFunctionsConcrete.end());
+ for (const Node& fcc : fcit->second)
+ {
+ d_input_arg_inj[f].push_back(fcc);
+ }
+ }
+ process(assertionsToPreprocess);
+ // must store new definitions (in case of incremental)
+ for (const Node& f : d_funcs)
+ {
+ d_fmfRecFunctionsAbs[f] = d_sorts[f];
+ d_fmfRecFunctionsConcrete[f].clear();
+ for (const Node& fcc : d_input_arg_inj[f])
+ {
+ d_fmfRecFunctionsConcrete[f].push_back(fcc);
+ }
+ d_fmfRecFunctionsDefined->push_back(f);
+ }
+ return PreprocessingPassResult::NO_CONFLICT;
+}
+
+void FunDefFmf::process(AssertionPipeline* assertionsToPreprocess)
+{
+ const std::vector<Node>& assertions = assertionsToPreprocess->ref();
+ std::vector<int> fd_assertions;
+ std::map<int, Node> subs_head;
+ // first pass : find defined functions, transform quantifiers
+ NodeManager* nm = NodeManager::currentNM();
+ for (size_t i = 0, asize = assertions.size(); i < asize; i++)
+ {
+ Node n = QuantAttributes::getFunDefHead(assertions[i]);
+ if (!n.isNull())
+ {
+ Assert(n.getKind() == APPLY_UF);
+ Node f = n.getOperator();
+
+ // check if already defined, if so, throw error
+ if (d_sorts.find(f) != d_sorts.end())
+ {
+ Unhandled() << "Cannot define function " << f << " more than once.";
+ }
+
+ Node bd = QuantAttributes::getFunDefBody(assertions[i]);
+ Trace("fmf-fun-def-debug")
+ << "Process function " << n << ", body = " << bd << std::endl;
+ if (!bd.isNull())
+ {
+ d_funcs.push_back(f);
+ bd = nm->mkNode(EQUAL, n, bd);
+
+ // create a sort S that represents the inputs of the function
+ std::stringstream ss;
+ ss << "I_" << f;
+ TypeNode iType = nm->mkSort(ss.str());
+ AbsTypeFunDefAttribute atfda;
+ iType.setAttribute(atfda, true);
+ d_sorts[f] = iType;
+
+ // create functions f1...fn mapping from this sort to concrete elements
+ size_t nchildn = n.getNumChildren();
+ for (size_t j = 0; j < nchildn; j++)
+ {
+ TypeNode typ = nm->mkFunctionType(iType, n[j].getType());
+ std::stringstream ssf;
+ ssf << f << "_arg_" << j;
+ d_input_arg_inj[f].push_back(
+ nm->mkSkolem(ssf.str(), typ, "op created during fun def fmf"));
+ }
+
+ // construct new quantifier forall S. F[f1(S)/x1....fn(S)/xn]
+ std::vector<Node> children;
+ Node bv = nm->mkBoundVar("?i", iType);
+ Node bvl = nm->mkNode(BOUND_VAR_LIST, bv);
+ std::vector<Node> subs;
+ std::vector<Node> vars;
+ for (size_t j = 0; j < nchildn; j++)
+ {
+ vars.push_back(n[j]);
+ subs.push_back(nm->mkNode(APPLY_UF, d_input_arg_inj[f][j], bv));
+ }
+ bd = bd.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
+ subs_head[i] =
+ n.substitute(vars.begin(), vars.end(), subs.begin(), subs.end());
+
+ Trace("fmf-fun-def")
+ << "FMF fun def: FUNCTION : rewrite " << assertions[i] << std::endl;
+ Trace("fmf-fun-def") << " to " << std::endl;
+ Node new_q = nm->mkNode(FORALL, bvl, bd);
+ new_q = Rewriter::rewrite(new_q);
+ assertionsToPreprocess->replace(i, new_q);
+ Trace("fmf-fun-def") << " " << assertions[i] << std::endl;
+ fd_assertions.push_back(i);
+ }
+ else
+ {
+ // can be, e.g. in corner cases forall x. f(x)=f(x), forall x.
+ // f(x)=f(x)+1
+ }
+ }
+ }
+ // second pass : rewrite assertions
+ std::map<int, std::map<Node, Node>> visited;
+ std::map<int, std::map<Node, Node>> visited_cons;
+ for (size_t i = 0, asize = assertions.size(); i < asize; i++)
+ {
+ bool is_fd = std::find(fd_assertions.begin(), fd_assertions.end(), i)
+ != fd_assertions.end();
+ std::vector<Node> constraints;
+ Trace("fmf-fun-def-rewrite")
+ << "Rewriting " << assertions[i]
+ << ", is function definition = " << is_fd << std::endl;
+ Node n = simplifyFormula(assertions[i],
+ true,
+ true,
+ constraints,
+ is_fd ? subs_head[i] : Node::null(),
+ is_fd,
+ visited,
+ visited_cons);
+ Assert(constraints.empty());
+ if (n != assertions[i])
+ {
+ n = Rewriter::rewrite(n);
+ Trace("fmf-fun-def-rewrite")
+ << "FMF fun def : rewrite " << assertions[i] << std::endl;
+ Trace("fmf-fun-def-rewrite") << " to " << std::endl;
+ Trace("fmf-fun-def-rewrite") << " " << n << std::endl;
+ assertionsToPreprocess->replace(i, n);
+ }
+ }
+}
+
+Node FunDefFmf::simplifyFormula(
+ Node n,
+ bool pol,
+ bool hasPol,
+ std::vector<Node>& constraints,
+ Node hd,
+ bool is_fun_def,
+ std::map<int, std::map<Node, Node>>& visited,
+ std::map<int, std::map<Node, Node>>& visited_cons)
+{
+ Assert(constraints.empty());
+ int index = (is_fun_def ? 1 : 0) + 2 * (hasPol ? (pol ? 1 : -1) : 0);
+ std::map<Node, Node>::iterator itv = visited[index].find(n);
+ if (itv != visited[index].end())
+ {
+ // constraints.insert( visited_cons[index]
+ std::map<Node, Node>::iterator itvc = visited_cons[index].find(n);
+ if (itvc != visited_cons[index].end())
+ {
+ constraints.push_back(itvc->second);
+ }
+ return itv->second;
+ }
+ NodeManager* nm = NodeManager::currentNM();
+ Node ret;
+ Trace("fmf-fun-def-debug2") << "Simplify " << n << " " << pol << " " << hasPol
+ << " " << is_fun_def << std::endl;
+ if (n.getKind() == FORALL)
+ {
+ Node c = simplifyFormula(
+ n[1], pol, hasPol, constraints, hd, is_fun_def, visited, visited_cons);
+ // append prenex to constraints
+ for (unsigned i = 0; i < constraints.size(); i++)
+ {
+ constraints[i] = nm->mkNode(FORALL, n[0], constraints[i]);
+ constraints[i] = Rewriter::rewrite(constraints[i]);
+ }
+ if (c != n[1])
+ {
+ ret = nm->mkNode(FORALL, n[0], c);
+ }
+ else
+ {
+ ret = n;
+ }
+ }
+ else
+ {
+ Node nn = n;
+ bool isBool = n.getType().isBoolean();
+ if (isBool && n.getKind() != APPLY_UF)
+ {
+ std::vector<Node> children;
+ bool childChanged = false;
+ // are we at a branch position (not all children are necessarily
+ // relevant)?
+ bool branch_pos =
+ (n.getKind() == ITE || n.getKind() == OR || n.getKind() == AND);
+ std::vector<Node> branch_constraints;
+ for (unsigned i = 0; i < n.getNumChildren(); i++)
+ {
+ Node c = n[i];
+ // do not process LHS of definition
+ if (!is_fun_def || c != hd)
+ {
+ bool newHasPol;
+ bool newPol;
+ QuantPhaseReq::getPolarity(n, i, hasPol, pol, newHasPol, newPol);
+ // get child constraints
+ std::vector<Node> cconstraints;
+ c = simplifyFormula(n[i],
+ newPol,
+ newHasPol,
+ cconstraints,
+ hd,
+ false,
+ visited,
+ visited_cons);
+ if (branch_pos)
+ {
+ // if at a branching position, the other constraints don't matter
+ // if this is satisfied
+ Node bcons = nm->mkAnd(cconstraints);
+ branch_constraints.push_back(bcons);
+ Trace("fmf-fun-def-debug2") << "Branching constraint at arg " << i
+ << " is " << bcons << std::endl;
+ }
+ constraints.insert(
+ constraints.end(), cconstraints.begin(), cconstraints.end());
+ }
+ children.push_back(c);
+ childChanged = c != n[i] || childChanged;
+ }
+ if (childChanged)
+ {
+ nn = nm->mkNode(n.getKind(), children);
+ }
+ if (branch_pos && !constraints.empty())
+ {
+ // if we are at a branching position in the formula, we can
+ // minimize recursive constraints on recursively defined predicates if
+ // we know one child forces the overall evaluation of this formula.
+ Node branch_cond;
+ if (n.getKind() == ITE)
+ {
+ // always care about constraints on the head of the ITE, but only
+ // care about one of the children depending on how it evaluates
+ branch_cond = nm->mkNode(
+ AND,
+ branch_constraints[0],
+ nm->mkNode(
+ ITE, n[0], branch_constraints[1], branch_constraints[2]));
+ }
+ else
+ {
+ // in the default case, we care about all conditions
+ branch_cond = nm->mkAnd(constraints);
+ for (size_t i = 0, nchild = n.getNumChildren(); i < nchild; i++)
+ {
+ // if this child holds with forcing polarity (true child of OR or
+ // false child of AND), then we only care about its associated
+ // recursive conditions
+ branch_cond = nm->mkNode(ITE,
+ (n.getKind() == OR ? n[i] : n[i].negate()),
+ branch_constraints[i],
+ branch_cond);
+ }
+ }
+ Trace("fmf-fun-def-debug2")
+ << "Made branching condition " << branch_cond << std::endl;
+ constraints.clear();
+ constraints.push_back(branch_cond);
+ }
+ }
+ else
+ {
+ // simplify term
+ std::map<Node, Node> visitedT;
+ getConstraints(n, constraints, visitedT);
+ }
+ if (!constraints.empty() && isBool && hasPol)
+ {
+ // conjoin with current
+ Node cons = nm->mkAnd(constraints);
+ if (pol)
+ {
+ ret = nm->mkNode(AND, nn, cons);
+ }
+ else
+ {
+ ret = nm->mkNode(OR, nn, cons.negate());
+ }
+ Trace("fmf-fun-def-debug2")
+ << "Add constraint to obtain " << ret << std::endl;
+ constraints.clear();
+ }
+ else
+ {
+ ret = nn;
+ }
+ }
+ if (!constraints.empty())
+ {
+ Node cons;
+ // flatten to AND node for the purposes of caching
+ if (constraints.size() > 1)
+ {
+ cons = nm->mkNode(AND, constraints);
+ cons = Rewriter::rewrite(cons);
+ constraints.clear();
+ constraints.push_back(cons);
+ }
+ else
+ {
+ cons = constraints[0];
+ }
+ visited_cons[index][n] = cons;
+ Assert(constraints.size() == 1 && constraints[0] == cons);
+ }
+ visited[index][n] = ret;
+ return ret;
+}
+
+void FunDefFmf::getConstraints(Node n,
+ std::vector<Node>& constraints,
+ std::map<Node, Node>& visited)
+{
+ std::map<Node, Node>::iterator itv = visited.find(n);
+ if (itv != visited.end())
+ {
+ // already visited
+ if (!itv->second.isNull())
+ {
+ // add the cached constraint if it does not already occur
+ if (std::find(constraints.begin(), constraints.end(), itv->second)
+ == constraints.end())
+ {
+ constraints.push_back(itv->second);
+ }
+ }
+ return;
+ }
+ visited[n] = Node::null();
+ std::vector<Node> currConstraints;
+ NodeManager* nm = NodeManager::currentNM();
+ if (n.getKind() == ITE)
+ {
+ // collect constraints for the condition
+ getConstraints(n[0], currConstraints, visited);
+ // collect constraints for each branch
+ Node cs[2];
+ for (unsigned i = 0; i < 2; i++)
+ {
+ std::vector<Node> ccons;
+ getConstraints(n[i + 1], ccons, visited);
+ cs[i] = nm->mkAnd(ccons);
+ }
+ if (!cs[0].isConst() || !cs[1].isConst())
+ {
+ Node itec = nm->mkNode(ITE, n[0], cs[0], cs[1]);
+ currConstraints.push_back(itec);
+ Trace("fmf-fun-def-debug")
+ << "---> add constraint " << itec << " for " << n << std::endl;
+ }
+ }
+ else
+ {
+ if (n.getKind() == APPLY_UF)
+ {
+ // check if f is defined, if so, we must enforce domain constraints for
+ // this f-application
+ Node f = n.getOperator();
+ std::map<Node, TypeNode>::iterator it = d_sorts.find(f);
+ if (it != d_sorts.end())
+ {
+ // create existential
+ Node z = nm->mkBoundVar("?z", it->second);
+ Node bvl = nm->mkNode(BOUND_VAR_LIST, z);
+ std::vector<Node> children;
+ for (unsigned j = 0, size = n.getNumChildren(); j < size; j++)
+ {
+ Node uz = nm->mkNode(APPLY_UF, d_input_arg_inj[f][j], z);
+ children.push_back(uz.eqNode(n[j]));
+ }
+ Node bd = nm->mkAnd(children);
+ bd = bd.negate();
+ Node ex = nm->mkNode(FORALL, bvl, bd);
+ ex = ex.negate();
+ currConstraints.push_back(ex);
+ Trace("fmf-fun-def-debug")
+ << "---> add constraint " << ex << " for " << n << std::endl;
+ }
+ }
+ for (const Node& cn : n)
+ {
+ getConstraints(cn, currConstraints, visited);
+ }
+ }
+ // set the visited cache
+ if (!currConstraints.empty())
+ {
+ Node finalc = nm->mkAnd(currConstraints);
+ visited[n] = finalc;
+ // add to constraints
+ getConstraints(n, constraints, visited);
+ }
+}
+
+} // namespace passes
+} // namespace preprocessing
+} // namespace CVC4
diff --git a/src/preprocessing/passes/fun_def_fmf.h b/src/preprocessing/passes/fun_def_fmf.h
new file mode 100644
index 000000000..36d1166b7
--- /dev/null
+++ b/src/preprocessing/passes/fun_def_fmf.h
@@ -0,0 +1,106 @@
+/********************* */
+/*! \file fun_def_fmf.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Function definition processor for finite model finding
+ **/
+
+#ifndef CVC4__PREPROCESSING__PASSES__FUN_DEF_FMF_H
+#define CVC4__PREPROCESSING__PASSES__FUN_DEF_FMF_H
+
+#include <map>
+#include <string>
+#include <vector>
+
+#include "expr/node.h"
+#include "preprocessing/preprocessing_pass.h"
+#include "preprocessing/preprocessing_pass_context.h"
+
+namespace CVC4 {
+namespace preprocessing {
+namespace passes {
+
+/**
+ * Preprocessing pass to allow finite model finding for admissible recursive
+ * function definitions. For details, see Reynolds et al "Model Finding for
+ * Recursive Functions" IJCAR 2016.
+ */
+class FunDefFmf : public PreprocessingPass
+{
+ /** The types for the recursive function definitions */
+ typedef context::CDList<Node> NodeList;
+
+ public:
+ FunDefFmf(PreprocessingPassContext* preprocContext);
+ ~FunDefFmf();
+
+ protected:
+ /**
+ * Run the preprocessing pass on the pipeline, taking into account the
+ * previous definitions.
+ */
+ PreprocessingPassResult applyInternal(
+ AssertionPipeline* assertionsToPreprocess) override;
+
+ private:
+ /** Run the preprocessing pass on the pipeline. */
+ void process(AssertionPipeline* assertionsToPreprocess);
+ /** simplify formula
+ * This is A_0 in Figure 1 of Reynolds et al "Model Finding for Recursive
+ * Functions". The input of A_0 in that paper is a pair ( term t, polarity p )
+ * The return value of A_0 in that paper is a pair ( term t', set of formulas
+ * X ).
+ *
+ * This function implements this such that :
+ * n is t
+ * pol/hasPol is p
+ * the return value is t'
+ * the set of formulas X are stored in "constraints"
+ *
+ * Additionally, is_fun_def is whether we are currently processing the top of
+ * a function defintion, since this affects whether we process the head of the
+ * definition.
+ */
+ Node simplifyFormula(Node n,
+ bool pol,
+ bool hasPol,
+ std::vector<Node>& constraints,
+ Node hd,
+ bool is_fun_def,
+ std::map<int, std::map<Node, Node>>& visited,
+ std::map<int, std::map<Node, Node>>& visited_cons);
+ /** get constraints
+ *
+ * This computes constraints for the final else branch of A_0 in Figure 1
+ * of Reynolds et al "Model Finding for Recursive Functions". The range of
+ * the cache visited stores the constraint (if any) for each node.
+ */
+ void getConstraints(Node n,
+ std::vector<Node>& constraints,
+ std::map<Node, Node>& visited);
+ /** recursive function definition abstractions for fmf-fun */
+ std::map<Node, TypeNode> d_fmfRecFunctionsAbs;
+ /** map to concrete definitions for fmf-fun */
+ std::map<Node, std::vector<Node>> d_fmfRecFunctionsConcrete;
+ /** List of defined recursive functions processed by fmf-fun */
+ NodeList* d_fmfRecFunctionsDefined;
+ // defined functions to input sort (alpha)
+ std::map<Node, TypeNode> d_sorts;
+ // defined functions to injections input -> argument elements (gamma)
+ std::map<Node, std::vector<Node>> d_input_arg_inj;
+ // (newly) defined functions
+ std::vector<Node> d_funcs;
+};
+
+} // namespace passes
+} // namespace preprocessing
+} // namespace CVC4
+
+#endif /* CVC4__PREPROCESSING__PASSES__SYGUS_INFERENCE_H_ */
diff --git a/src/preprocessing/passes/global_negate.cpp b/src/preprocessing/passes/global_negate.cpp
index 25bb0e532..00ca1efd3 100644
--- a/src/preprocessing/passes/global_negate.cpp
+++ b/src/preprocessing/passes/global_negate.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Yoni Zohar
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -27,7 +27,8 @@ namespace CVC4 {
namespace preprocessing {
namespace passes {
-Node GlobalNegate::simplify(std::vector<Node>& assertions, NodeManager* nm)
+Node GlobalNegate::simplify(const std::vector<Node>& assertions,
+ NodeManager* nm)
{
Assert(!assertions.empty());
Trace("cegqi-gn") << "Global negate : " << std::endl;
diff --git a/src/preprocessing/passes/global_negate.h b/src/preprocessing/passes/global_negate.h
index 67cb0f770..208b8d990 100644
--- a/src/preprocessing/passes/global_negate.h
+++ b/src/preprocessing/passes/global_negate.h
@@ -5,7 +5,7 @@
** Yoni Zohar, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -42,7 +42,7 @@ class GlobalNegate : public PreprocessingPass
AssertionPipeline* assertionsToPreprocess) override;
private:
- Node simplify(std::vector<Node>& assertions, NodeManager* nm);
+ Node simplify(const std::vector<Node>& assertions, NodeManager* nm);
};
} // namespace passes
diff --git a/src/preprocessing/passes/ho_elim.cpp b/src/preprocessing/passes/ho_elim.cpp
index 8b64dd4e6..445cac18e 100644
--- a/src/preprocessing/passes/ho_elim.cpp
+++ b/src/preprocessing/passes/ho_elim.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -33,8 +33,8 @@ HoElim::HoElim(PreprocessingPassContext* preprocContext)
Node HoElim::eliminateLambdaComplete(Node n, std::map<Node, Node>& newLambda)
{
NodeManager* nm = NodeManager::currentNM();
- std::unordered_map<TNode, Node, TNodeHashFunction>::iterator it;
- std::vector<TNode> visit;
+ std::unordered_map<Node, Node, TNodeHashFunction>::iterator it;
+ std::vector<Node> visit;
TNode cur;
visit.push_back(n);
do
@@ -148,7 +148,7 @@ Node HoElim::eliminateHo(Node n)
{
Trace("ho-elim-assert") << "Ho-elim assertion: " << n << std::endl;
NodeManager* nm = NodeManager::currentNM();
- std::unordered_map<TNode, Node, TNodeHashFunction>::iterator it;
+ std::unordered_map<Node, Node, NodeHashFunction>::iterator it;
std::map<Node, Node> preReplace;
std::map<Node, Node>::iterator itr;
std::vector<TNode> visit;
@@ -353,12 +353,10 @@ PreprocessingPassResult HoElim::applyInternal(
// add lambda lifting axioms as a conjunction to the first assertion
if (!axioms.empty())
{
- Node orig = (*assertionsToPreprocess)[0];
- axioms.push_back(orig);
- Node conj = nm->mkNode(AND, axioms);
+ Node conj = nm->mkAnd(axioms);
conj = theory::Rewriter::rewrite(conj);
Assert(!expr::hasFreeVar(conj));
- assertionsToPreprocess->replace(0, conj);
+ assertionsToPreprocess->conjoin(0, conj);
}
axioms.clear();
@@ -450,12 +448,10 @@ PreprocessingPassResult HoElim::applyInternal(
// add new axioms as a conjunction to the first assertion
if (!axioms.empty())
{
- Node orig = (*assertionsToPreprocess)[0];
- axioms.push_back(orig);
- Node conj = nm->mkNode(AND, axioms);
+ Node conj = nm->mkAnd(axioms);
conj = theory::Rewriter::rewrite(conj);
Assert(!expr::hasFreeVar(conj));
- assertionsToPreprocess->replace(0, conj);
+ assertionsToPreprocess->conjoin(0, conj);
}
return PreprocessingPassResult::NO_CONFLICT;
diff --git a/src/preprocessing/passes/ho_elim.h b/src/preprocessing/passes/ho_elim.h
index be088c46b..2edc96074 100644
--- a/src/preprocessing/passes/ho_elim.h
+++ b/src/preprocessing/passes/ho_elim.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -112,7 +112,7 @@ class HoElim : public PreprocessingPass
* Stores the set of nodes we have current visited and their results
* in steps [1] and [2] of this pass.
*/
- std::unordered_map<TNode, Node, TNodeHashFunction> d_visited;
+ std::unordered_map<Node, Node, NodeHashFunction> d_visited;
/**
* Stores the mapping from functions f to their corresponding function H(f)
* in the encoding for step [2] of this pass.
diff --git a/src/preprocessing/passes/int_to_bv.cpp b/src/preprocessing/passes/int_to_bv.cpp
index e30c03f26..fd0800f23 100644
--- a/src/preprocessing/passes/int_to_bv.cpp
+++ b/src/preprocessing/passes/int_to_bv.cpp
@@ -2,10 +2,10 @@
/*! \file int_to_bv.cpp
** \verbatim
** Top contributors (to current version):
- ** Andres Noetzli, Yoni Zohar, Andrew Reynolds
+ ** Andres Noetzli, Yoni Zohar, Alex Ozdemir
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/int_to_bv.h b/src/preprocessing/passes/int_to_bv.h
index 284cf7256..208e7ab6a 100644
--- a/src/preprocessing/passes/int_to_bv.h
+++ b/src/preprocessing/passes/int_to_bv.h
@@ -5,7 +5,7 @@
** Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/ite_removal.cpp b/src/preprocessing/passes/ite_removal.cpp
index f021fff28..a75b6f5ad 100644
--- a/src/preprocessing/passes/ite_removal.cpp
+++ b/src/preprocessing/passes/ite_removal.cpp
@@ -2,10 +2,10 @@
/*! \file ite_removal.cpp
** \verbatim
** Top contributors (to current version):
- ** Andres Noetzli, Mathias Preiner
+ ** Andres Noetzli, Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -34,9 +34,23 @@ PreprocessingPassResult IteRemoval::applyInternal(AssertionPipeline* assertions)
{
d_preprocContext->spendResource(ResourceManager::Resource::PreprocessStep);
+ IteSkolemMap& imap = assertions->getIteSkolemMap();
// Remove all of the ITE occurrences and normalize
- d_preprocContext->getIteRemover()->run(
- assertions->ref(), assertions->getIteSkolemMap(), true);
+ for (unsigned i = 0, size = assertions->size(); i < size; ++i)
+ {
+ std::vector<theory::TrustNode> newAsserts;
+ std::vector<Node> newSkolems;
+ TrustNode trn = d_preprocContext->getIteRemover()->run(
+ (*assertions)[i], newAsserts, newSkolems, true);
+ // process
+ assertions->replaceTrusted(i, trn);
+ Assert(newSkolems.size() == newAsserts.size());
+ for (unsigned j = 0, nnasserts = newAsserts.size(); j < nnasserts; j++)
+ {
+ imap[newSkolems[j]] = assertions->size();
+ assertions->pushBackTrusted(newAsserts[j]);
+ }
+ }
for (unsigned i = 0, size = assertions->size(); i < size; ++i)
{
assertions->replace(i, Rewriter::rewrite((*assertions)[i]));
diff --git a/src/preprocessing/passes/ite_removal.h b/src/preprocessing/passes/ite_removal.h
index 950d7342a..2b8a05fe4 100644
--- a/src/preprocessing/passes/ite_removal.h
+++ b/src/preprocessing/passes/ite_removal.h
@@ -5,7 +5,7 @@
** Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/ite_simp.cpp b/src/preprocessing/passes/ite_simp.cpp
index 9a6a8ec61..8c99493ba 100644
--- a/src/preprocessing/passes/ite_simp.cpp
+++ b/src/preprocessing/passes/ite_simp.cpp
@@ -2,10 +2,10 @@
/*! \file ite_simp.cpp
** \verbatim
** Top contributors (to current version):
- ** Aina Niemetz, Tim King, Liana Hadarean
+ ** Aina Niemetz, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,7 +16,6 @@
#include <vector>
-#include "options/proof_options.h"
#include "smt/smt_statistics_registry.h"
#include "smt_util/nary_builder.h"
#include "theory/arith/arith_ite_utils.h"
@@ -118,7 +117,7 @@ bool ITESimp::doneSimpITE(AssertionPipeline* assertionsToPreprocess)
// This pass does not support dependency tracking yet
// (learns substitutions from all assertions so just
// adding addDependence is not enough)
- if (options::unsatCores() || options::fewerPreprocessingHoles())
+ if (options::unsatCores())
{
return true;
}
@@ -128,7 +127,7 @@ bool ITESimp::doneSimpITE(AssertionPipeline* assertionsToPreprocess)
{
if (options::compressItes())
{
- result = d_iteUtilities.compress(assertionsToPreprocess->ref());
+ result = d_iteUtilities.compress(assertionsToPreprocess);
}
if (result)
@@ -176,7 +175,8 @@ bool ITESimp::doneSimpITE(AssertionPipeline* assertionsToPreprocess)
{
Node more = aiteu.reduceConstantIteByGCD(res);
Debug("arith::ite::red") << " gcd->" << more << endl;
- (*assertionsToPreprocess)[i] = Rewriter::rewrite(more);
+ Node morer = Rewriter::rewrite(more);
+ assertionsToPreprocess->replace(i, morer);
}
}
}
@@ -215,7 +215,8 @@ bool ITESimp::doneSimpITE(AssertionPipeline* assertionsToPreprocess)
<< " ->" << res << endl;
Node more = aiteu.reduceConstantIteByGCD(res);
Debug("arith::ite::red") << " gcd->" << more << endl;
- (*assertionsToPreprocess)[i] = Rewriter::rewrite(more);
+ Node morer = Rewriter::rewrite(more);
+ assertionsToPreprocess->replace(i, morer);
}
}
}
diff --git a/src/preprocessing/passes/ite_simp.h b/src/preprocessing/passes/ite_simp.h
index cf122c4c9..fe1dfa6e0 100644
--- a/src/preprocessing/passes/ite_simp.h
+++ b/src/preprocessing/passes/ite_simp.h
@@ -5,7 +5,7 @@
** Aina Niemetz, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/miplib_trick.cpp b/src/preprocessing/passes/miplib_trick.cpp
index f64fce118..f55665bc5 100644
--- a/src/preprocessing/passes/miplib_trick.cpp
+++ b/src/preprocessing/passes/miplib_trick.cpp
@@ -5,7 +5,7 @@
** Mathias Preiner, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -23,6 +23,7 @@
#include "smt_util/boolean_simplification.h"
#include "theory/booleans/circuit_propagator.h"
#include "theory/theory_model.h"
+#include "theory/trust_substitutions.h"
namespace CVC4 {
namespace preprocessing {
@@ -187,8 +188,10 @@ PreprocessingPassResult MipLibTrick::applyInternal(
const booleans::CircuitPropagator::BackEdgesMap& backEdges =
propagator->getBackEdges();
unordered_set<unsigned long> removeAssertions;
- SubstitutionMap& top_level_substs =
+
+ theory::TrustSubstitutionMap& tlsm =
d_preprocContext->getTopLevelSubstitutions();
+ SubstitutionMap& top_level_substs = tlsm.get();
NodeManager* nm = NodeManager::currentNM();
Node zero = nm->mkConst(Rational(0)), one = nm->mkConst(Rational(1));
@@ -519,19 +522,24 @@ PreprocessingPassResult MipLibTrick::applyInternal(
NodeManager::SKOLEM_EXACT_NAME);
Node geq = Rewriter::rewrite(nm->mkNode(kind::GEQ, newVar, zero));
Node leq = Rewriter::rewrite(nm->mkNode(kind::LEQ, newVar, one));
+ TrustNode tgeq = TrustNode::mkTrustLemma(geq, nullptr);
+ TrustNode tleq = TrustNode::mkTrustLemma(leq, nullptr);
Node n = Rewriter::rewrite(geq.andNode(leq));
assertionsToPreprocess->push_back(n);
- PROOF(ProofManager::currentPM()->addDependence(n, Node::null()));
-
- SubstitutionMap nullMap(&fakeContext);
+ if (options::unsatCores())
+ {
+ ProofManager::currentPM()->addDependence(n, Node::null());
+ }
+ TrustSubstitutionMap tnullMap(&fakeContext, nullptr);
+ CVC4_UNUSED SubstitutionMap& nullMap = tnullMap.get();
Theory::PPAssertStatus status CVC4_UNUSED; // just for assertions
- status = te->solve(geq, nullMap);
+ status = te->solve(tgeq, tnullMap);
Assert(status == Theory::PP_ASSERT_STATUS_UNSOLVED)
<< "unexpected solution from arith's ppAssert()";
Assert(nullMap.empty())
<< "unexpected substitution from arith's ppAssert()";
- status = te->solve(leq, nullMap);
+ status = te->solve(tleq, tnullMap);
Assert(status == Theory::PP_ASSERT_STATUS_UNSOLVED)
<< "unexpected solution from arith's ppAssert()";
Assert(nullMap.empty())
@@ -591,9 +599,11 @@ PreprocessingPassResult MipLibTrick::applyInternal(
Debug("miplib") << " " << newAssertion << endl;
assertionsToPreprocess->push_back(newAssertion);
- PROOF(ProofManager::currentPM()->addDependence(newAssertion,
- Node::null()));
-
+ if (options::unsatCores())
+ {
+ ProofManager::currentPM()->addDependence(newAssertion,
+ Node::null());
+ }
Debug("miplib") << " assertions to remove: " << endl;
for (vector<TNode>::const_iterator k = asserts[pos_var].begin(),
k_end = asserts[pos_var].end();
diff --git a/src/preprocessing/passes/miplib_trick.h b/src/preprocessing/passes/miplib_trick.h
index d57658d47..d3cf9da53 100644
--- a/src/preprocessing/passes/miplib_trick.h
+++ b/src/preprocessing/passes/miplib_trick.h
@@ -5,7 +5,7 @@
** Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/nl_ext_purify.cpp b/src/preprocessing/passes/nl_ext_purify.cpp
index 1f7e298ee..88bdf2e5c 100644
--- a/src/preprocessing/passes/nl_ext_purify.cpp
+++ b/src/preprocessing/passes/nl_ext_purify.cpp
@@ -5,7 +5,7 @@
** Haniel Barbosa, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -117,16 +117,19 @@ PreprocessingPassResult NlExtPurify::applyInternal(
for (unsigned i = 0; i < size; ++i)
{
Node a = (*assertionsToPreprocess)[i];
- assertionsToPreprocess->replace(i, purifyNlTerms(a, cache, bcache, var_eq));
- Trace("nl-ext-purify") << "Purify : " << a << " -> "
- << (*assertionsToPreprocess)[i] << "\n";
+ Node ap = purifyNlTerms(a, cache, bcache, var_eq);
+ if (a != ap)
+ {
+ assertionsToPreprocess->replace(i, ap);
+ Trace("nl-ext-purify")
+ << "Purify : " << a << " -> " << (*assertionsToPreprocess)[i] << "\n";
+ }
}
if (!var_eq.empty())
{
unsigned lastIndex = size - 1;
- var_eq.insert(var_eq.begin(), (*assertionsToPreprocess)[lastIndex]);
- assertionsToPreprocess->replace(
- lastIndex, NodeManager::currentNM()->mkNode(kind::AND, var_eq));
+ Node veq = NodeManager::currentNM()->mkAnd(var_eq);
+ assertionsToPreprocess->conjoin(lastIndex, veq);
}
return PreprocessingPassResult::NO_CONFLICT;
}
diff --git a/src/preprocessing/passes/nl_ext_purify.h b/src/preprocessing/passes/nl_ext_purify.h
index a3004a7e8..5c7c5776e 100644
--- a/src/preprocessing/passes/nl_ext_purify.h
+++ b/src/preprocessing/passes/nl_ext_purify.h
@@ -5,7 +5,7 @@
** Haniel Barbosa, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/non_clausal_simp.cpp b/src/preprocessing/passes/non_clausal_simp.cpp
index 6d2482a0e..cedee6d3c 100644
--- a/src/preprocessing/passes/non_clausal_simp.cpp
+++ b/src/preprocessing/passes/non_clausal_simp.cpp
@@ -2,10 +2,10 @@
/*! \file non_clausal_simp.cpp
** \verbatim
** Top contributors (to current version):
- ** Aina Niemetz, Andrew Reynolds, Andres Noetzli
+ ** Aina Niemetz, Haniel Barbosa, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,9 +19,9 @@
#include <vector>
#include "context/cdo.h"
-#include "options/proof_options.h"
#include "smt/smt_statistics_registry.h"
#include "theory/theory_model.h"
+#include "theory/trust_substitutions.h"
using namespace CVC4;
using namespace CVC4::theory;
@@ -47,14 +47,26 @@ NonClausalSimp::Statistics::~Statistics()
/* -------------------------------------------------------------------------- */
NonClausalSimp::NonClausalSimp(PreprocessingPassContext* preprocContext)
- : PreprocessingPass(preprocContext, "non-clausal-simp")
+ : PreprocessingPass(preprocContext, "non-clausal-simp"),
+ d_pnm(preprocContext->getProofNodeManager()),
+ d_llpg(d_pnm ? new smt::PreprocessProofGenerator(
+ d_pnm,
+ preprocContext->getUserContext(),
+ "NonClausalSimp::llpg")
+ : nullptr),
+ d_llra(d_pnm ? new LazyCDProof(d_pnm,
+ nullptr,
+ preprocContext->getUserContext(),
+ "NonClausalSimp::llra")
+ : nullptr),
+ d_tsubsList(preprocContext->getUserContext())
{
}
PreprocessingPassResult NonClausalSimp::applyInternal(
AssertionPipeline* assertionsToPreprocess)
{
- Assert(!options::unsatCores() && !options::fewerPreprocessingHoles());
+ Assert(!options::unsatCores());
d_preprocContext->spendResource(ResourceManager::Resource::PreprocessStep);
@@ -93,16 +105,19 @@ PreprocessingPassResult NonClausalSimp::applyInternal(
}
Trace("non-clausal-simplify") << "propagating" << std::endl;
- if (propagator->propagate())
+ TrustNode conf = propagator->propagate();
+ if (!conf.isNull())
{
// If in conflict, just return false
Trace("non-clausal-simplify")
<< "conflict in non-clausal propagation" << std::endl;
- Assert(!options::unsatCores() && !options::fewerPreprocessingHoles());
+ Assert(!options::unsatCores());
assertionsToPreprocess->clear();
- Node n = NodeManager::currentNM()->mkConst<bool>(false);
- assertionsToPreprocess->push_back(n);
- PROOF(ProofManager::currentPM()->addDependence(n, Node::null()));
+ assertionsToPreprocess->pushBackTrusted(conf);
+ if (options::unsatCores())
+ {
+ ProofManager::currentPM()->addDependence(conf.getNode(), Node::null());
+ }
propagator->setNeedsFinish(true);
return PreprocessingPassResult::CONFLICT;
}
@@ -111,39 +126,41 @@ PreprocessingPassResult NonClausalSimp::applyInternal(
<< "Iterate through " << propagator->getLearnedLiterals().size()
<< " learned literals." << std::endl;
// No conflict, go through the literals and solve them
- SubstitutionMap& top_level_substs =
- d_preprocContext->getTopLevelSubstitutions();
- SubstitutionMap constantPropagations(d_preprocContext->getUserContext());
- SubstitutionMap newSubstitutions(d_preprocContext->getUserContext());
- SubstitutionMap::iterator pos;
+ context::Context* u = d_preprocContext->getUserContext();
+ TrustSubstitutionMap& ttls = d_preprocContext->getTopLevelSubstitutions();
+ CVC4_UNUSED SubstitutionMap& top_level_substs = ttls.get();
+ // constant propagations
+ std::shared_ptr<TrustSubstitutionMap> constantPropagations =
+ std::make_shared<TrustSubstitutionMap>(
+ u, d_pnm, "NonClausalSimp::cprop", PfRule::PREPROCESS_LEMMA);
+ SubstitutionMap& cps = constantPropagations->get();
+ // new substitutions
+ std::shared_ptr<TrustSubstitutionMap> newSubstitutions =
+ std::make_shared<TrustSubstitutionMap>(
+ u, d_pnm, "NonClausalSimp::newSubs", PfRule::PREPROCESS_LEMMA);
+ SubstitutionMap& nss = newSubstitutions->get();
+
size_t j = 0;
- std::vector<Node>& learned_literals = propagator->getLearnedLiterals();
+ std::vector<TrustNode>& learned_literals = propagator->getLearnedLiterals();
+ // if proofs are enabled, we will need to track the proofs of learned literals
+ if (isProofEnabled())
+ {
+ d_tsubsList.push_back(constantPropagations);
+ d_tsubsList.push_back(newSubstitutions);
+ for (const TrustNode& tll : learned_literals)
+ {
+ d_llpg->notifyNewTrustedAssert(tll);
+ }
+ }
for (size_t i = 0, size = learned_literals.size(); i < size; ++i)
{
// Simplify the literal we learned wrt previous substitutions
- Node learnedLiteral = learned_literals[i];
+ Node learnedLiteral = learned_literals[i].getNode();
Assert(Rewriter::rewrite(learnedLiteral) == learnedLiteral);
Assert(top_level_substs.apply(learnedLiteral) == learnedLiteral);
- Trace("non-clausal-simplify")
- << "Process learnedLiteral : " << learnedLiteral << std::endl;
- Node learnedLiteralNew = newSubstitutions.apply(learnedLiteral);
- if (learnedLiteral != learnedLiteralNew)
- {
- learnedLiteral = Rewriter::rewrite(learnedLiteralNew);
- }
- Trace("non-clausal-simplify")
- << "Process learnedLiteral, after newSubs : " << learnedLiteral
- << std::endl;
- for (;;)
- {
- learnedLiteralNew = constantPropagations.apply(learnedLiteral);
- if (learnedLiteralNew == learnedLiteral)
- {
- break;
- }
- d_statistics.d_numConstantProps += 1;
- learnedLiteral = Rewriter::rewrite(learnedLiteralNew);
- }
+ // process the learned literal with substitutions and const propagations
+ learnedLiteral = processLearnedLit(
+ learnedLiteral, newSubstitutions.get(), constantPropagations.get());
Trace("non-clausal-simplify")
<< "Process learnedLiteral, after constProp : " << learnedLiteral
<< std::endl;
@@ -159,12 +176,15 @@ PreprocessingPassResult NonClausalSimp::applyInternal(
{
// If the learned literal simplifies to false, we're in conflict
Trace("non-clausal-simplify")
- << "conflict with " << learned_literals[i] << std::endl;
+ << "conflict with " << learned_literals[i].getNode() << std::endl;
Assert(!options::unsatCores());
assertionsToPreprocess->clear();
Node n = NodeManager::currentNM()->mkConst<bool>(false);
- assertionsToPreprocess->push_back(n);
- PROOF(ProofManager::currentPM()->addDependence(n, Node::null()));
+ assertionsToPreprocess->push_back(n, false, false, d_llpg.get());
+ if (options::unsatCores())
+ {
+ ProofManager::currentPM()->addDependence(n, Node::null());
+ }
propagator->setNeedsFinish(true);
return PreprocessingPassResult::CONFLICT;
}
@@ -174,9 +194,11 @@ PreprocessingPassResult NonClausalSimp::applyInternal(
// substitutions to newSubstitutions
Trace("non-clausal-simplify") << "solving " << learnedLiteral << std::endl;
+ TrustNode tlearnedLiteral =
+ TrustNode::mkTrustLemma(learnedLiteral, d_llpg.get());
Theory::PPAssertStatus solveStatus =
- d_preprocContext->getTheoryEngine()->solve(learnedLiteral,
- newSubstitutions);
+ d_preprocContext->getTheoryEngine()->solve(tlearnedLiteral,
+ *newSubstitutions.get());
switch (solveStatus)
{
@@ -185,16 +207,7 @@ PreprocessingPassResult NonClausalSimp::applyInternal(
// The literal should rewrite to true
Trace("non-clausal-simplify")
<< "solved " << learnedLiteral << std::endl;
- Assert(Rewriter::rewrite(newSubstitutions.apply(learnedLiteral))
- .isConst());
- // vector<pair<Node, Node> > equations;
- // constantPropagations.simplifyLHS(top_level_substs, equations,
- // true); if (equations.empty()) {
- // break;
- // }
- // Assert(equations[0].first.isConst() &&
- // equations[0].second.isConst() && equations[0].first !=
- // equations[0].second);
+ Assert(Rewriter::rewrite(nss.apply(learnedLiteral)).isConst());
// else fall through
break;
}
@@ -207,7 +220,10 @@ PreprocessingPassResult NonClausalSimp::applyInternal(
assertionsToPreprocess->clear();
Node n = NodeManager::currentNM()->mkConst<bool>(false);
assertionsToPreprocess->push_back(n);
- PROOF(ProofManager::currentPM()->addDependence(n, Node::null()));
+ if (options::unsatCores())
+ {
+ ProofManager::currentPM()->addDependence(n, Node::null());
+ }
propagator->setNeedsFinish(true);
return PreprocessingPassResult::CONFLICT;
}
@@ -229,22 +245,19 @@ PreprocessingPassResult NonClausalSimp::applyInternal(
c = learnedLiteral[1];
}
Assert(!t.isConst());
- Assert(constantPropagations.apply(t) == t);
+ Assert(cps.apply(t) == t);
Assert(top_level_substs.apply(t) == t);
- Assert(newSubstitutions.apply(t) == t);
- constantPropagations.addSubstitution(t, c);
- // vector<pair<Node,Node> > equations;
- // constantPropagations.simplifyLHS(t, c, equations, true);
- // if (!equations.empty()) {
- // Assert(equations[0].first.isConst() &&
- // equations[0].second.isConst() && equations[0].first !=
- // equations[0].second); assertionsToPreprocess->clear();
- // Node n = NodeManager::currentNM()->mkConst<bool>(false);
- // assertionsToPreprocess->push_back(n);
- // PROOF(ProofManager::currentPM()->addDependence(n, Node::null()));
- // false); return;
- // }
- // top_level_substs.simplifyRHS(constantPropagations);
+ Assert(nss.apply(t) == t);
+ // also add to learned literal
+ ProofGenerator* cpg = constantPropagations->addSubstitutionSolved(
+ t, c, tlearnedLiteral);
+ // We need to justify (= t c) as a literal, since it is reasserted
+ // to the assertion pipeline below. We do this with the proof
+ // generator returned by the above call.
+ if (isProofEnabled())
+ {
+ d_llpg->notifyNewAssert(t.eqNode(c), cpg);
+ }
}
else
{
@@ -268,34 +281,19 @@ PreprocessingPassResult NonClausalSimp::applyInternal(
// 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
- for (pos = newSubstitutions.begin(); pos != newSubstitutions.end(); ++pos)
+ for (SubstitutionMap::iterator pos = nss.begin(); pos != nss.end(); ++pos)
{
Assert((*pos).first.isVar());
Assert(top_level_substs.apply((*pos).first) == (*pos).first);
Assert(top_level_substs.apply((*pos).second) == (*pos).second);
- Assert(newSubstitutions.apply(newSubstitutions.apply((*pos).second))
- == newSubstitutions.apply((*pos).second));
+ Node app = nss.apply((*pos).second);
+ Assert(nss.apply(app) == app);
}
- for (pos = constantPropagations.begin(); pos != constantPropagations.end();
- ++pos)
+ for (SubstitutionMap::iterator pos = cps.begin(); pos != cps.end(); ++pos)
{
Assert((*pos).second.isConst());
Assert(Rewriter::rewrite((*pos).first) == (*pos).first);
- // Node newLeft = top_level_substs.apply((*pos).first);
- // if (newLeft != (*pos).first) {
- // newLeft = Rewriter::rewrite(newLeft);
- // Assert(newLeft == (*pos).second ||
- // (constantPropagations.hasSubstitution(newLeft) &&
- // constantPropagations.apply(newLeft) == (*pos).second));
- // }
- // newLeft = constantPropagations.apply((*pos).first);
- // if (newLeft != (*pos).first) {
- // newLeft = Rewriter::rewrite(newLeft);
- // Assert(newLeft == (*pos).second ||
- // (constantPropagations.hasSubstitution(newLeft) &&
- // constantPropagations.apply(newLeft) == (*pos).second));
- // }
- Assert(constantPropagations.apply((*pos).second) == (*pos).second);
+ Assert(cps.apply((*pos).second) == (*pos).second);
}
#endif /* CVC4_ASSERTIONS */
@@ -308,33 +306,31 @@ PreprocessingPassResult NonClausalSimp::applyInternal(
for (size_t i = 0, size = assertionsToPreprocess->size(); i < size; ++i)
{
Node assertion = (*assertionsToPreprocess)[i];
- Node assertionNew = newSubstitutions.apply(assertion);
+ TrustNode assertionNew = newSubstitutions->apply(assertion);
Trace("non-clausal-simplify") << "assertion = " << assertion << std::endl;
- Trace("non-clausal-simplify")
- << "assertionNew = " << assertionNew << std::endl;
- if (assertion != assertionNew)
+ if (!assertionNew.isNull())
{
- assertion = Rewriter::rewrite(assertionNew);
Trace("non-clausal-simplify")
- << "rewrite(assertion) = " << assertion << std::endl;
+ << "assertionNew = " << assertionNew.getNode() << std::endl;
+ assertionsToPreprocess->replaceTrusted(i, assertionNew);
+ assertion = assertionNew.getNode();
+ Assert(Rewriter::rewrite(assertion) == assertion);
}
- Assert(Rewriter::rewrite(assertion) == assertion);
for (;;)
{
- assertionNew = constantPropagations.apply(assertion);
- if (assertionNew == assertion)
+ assertionNew = constantPropagations->apply(assertion);
+ if (assertionNew.isNull())
{
break;
}
+ Assert(assertionNew.getNode() != assertion);
+ assertionsToPreprocess->replaceTrusted(i, assertionNew);
+ assertion = assertionNew.getNode();
d_statistics.d_numConstantProps += 1;
Trace("non-clausal-simplify")
- << "assertionNew = " << assertionNew << std::endl;
- assertion = Rewriter::rewrite(assertionNew);
- Trace("non-clausal-simplify")
- << "assertionNew = " << assertionNew << std::endl;
+ << "assertionNew = " << assertion << std::endl;
}
s.insert(assertion);
- assertionsToPreprocess->replace(i, assertion);
Trace("non-clausal-simplify")
<< "non-clausal preprocessed: " << assertion << std::endl;
}
@@ -343,10 +339,11 @@ PreprocessingPassResult NonClausalSimp::applyInternal(
TheoryModel* m = d_preprocContext->getTheoryEngine()->getModel();
Assert(m != nullptr);
NodeManager* nm = NodeManager::currentNM();
- for (pos = newSubstitutions.begin(); pos != newSubstitutions.end(); ++pos)
+ for (SubstitutionMap::iterator pos = nss.begin(); pos != nss.end(); ++pos)
{
Node lhs = (*pos).first;
- Node rhs = newSubstitutions.apply((*pos).second);
+ TrustNode trhs = newSubstitutions->apply((*pos).second);
+ Node rhs = trhs.isNull() ? (*pos).second : trhs.getNode();
// If using incremental, we must check whether this variable has occurred
// before now. If it hasn't we can add this as a substitution.
if (!assertionsToPreprocess->storeSubstsInAsserts()
@@ -364,64 +361,49 @@ PreprocessingPassResult NonClausalSimp::applyInternal(
Trace("non-clausal-simplify")
<< "substitute: will notify SAT layer of substitution: " << eq
<< std::endl;
- assertionsToPreprocess->addSubstitutionNode(eq);
+ trhs = newSubstitutions->apply((*pos).first);
+ Assert(!trhs.isNull());
+ assertionsToPreprocess->addSubstitutionNode(trhs.getProven(),
+ trhs.getGenerator());
}
}
- NodeBuilder<> learnedBuilder(kind::AND);
Assert(assertionsToPreprocess->getRealAssertionsEnd()
<= assertionsToPreprocess->size());
- learnedBuilder << (*assertionsToPreprocess)
- [assertionsToPreprocess->getRealAssertionsEnd() - 1];
+ // Learned literals to conjoin. If proofs are enabled, all these are
+ // justified by d_llpg.
+ std::vector<Node> learnedLitsToConjoin;
for (size_t i = 0; i < learned_literals.size(); ++i)
{
- Node learned = learned_literals[i];
+ Node learned = learned_literals[i].getNode();
Assert(top_level_substs.apply(learned) == learned);
- Node learnedNew = newSubstitutions.apply(learned);
- if (learned != learnedNew)
- {
- learned = Rewriter::rewrite(learnedNew);
- }
- Assert(Rewriter::rewrite(learned) == learned);
- for (;;)
- {
- learnedNew = constantPropagations.apply(learned);
- if (learnedNew == learned)
- {
- break;
- }
- d_statistics.d_numConstantProps += 1;
- learned = Rewriter::rewrite(learnedNew);
- }
+ // process learned literal
+ learned = processLearnedLit(
+ learned, newSubstitutions.get(), constantPropagations.get());
if (s.find(learned) != s.end())
{
continue;
}
s.insert(learned);
- learnedBuilder << learned;
+ learnedLitsToConjoin.push_back(learned);
Trace("non-clausal-simplify")
<< "non-clausal learned : " << learned << std::endl;
}
learned_literals.clear();
- for (pos = constantPropagations.begin(); pos != constantPropagations.end();
- ++pos)
+ for (SubstitutionMap::iterator pos = cps.begin(); pos != cps.end(); ++pos)
{
Node cProp = (*pos).first.eqNode((*pos).second);
Assert(top_level_substs.apply(cProp) == cProp);
- Node cPropNew = newSubstitutions.apply(cProp);
- if (cProp != cPropNew)
- {
- cProp = Rewriter::rewrite(cPropNew);
- Assert(Rewriter::rewrite(cProp) == cProp);
- }
+ // process learned literal (substitutions only)
+ cProp = processLearnedLit(cProp, newSubstitutions.get(), nullptr);
if (s.find(cProp) != s.end())
{
continue;
}
s.insert(cProp);
- learnedBuilder << cProp;
+ learnedLitsToConjoin.push_back(cProp);
Trace("non-clausal-simplify")
<< "non-clausal constant propagation : " << cProp << std::endl;
}
@@ -430,21 +412,89 @@ PreprocessingPassResult NonClausalSimp::applyInternal(
// Note that we don't have to keep rhs's in full solved form
// because SubstitutionMap::apply does a fixed-point iteration when
// substituting
- top_level_substs.addSubstitutions(newSubstitutions);
+ ttls.addSubstitutions(*newSubstitutions.get());
- if (learnedBuilder.getNumChildren() > 1)
+ if (!learnedLitsToConjoin.empty())
{
- assertionsToPreprocess->replace(
- assertionsToPreprocess->getRealAssertionsEnd() - 1,
- Rewriter::rewrite(Node(learnedBuilder)));
+ size_t replIndex = assertionsToPreprocess->getRealAssertionsEnd() - 1;
+ Node newConj = NodeManager::currentNM()->mkAnd(learnedLitsToConjoin);
+ Trace("non-clausal-simplify")
+ << "non-clausal simplification, reassert: " << newConj << std::endl;
+ ProofGenerator* pg = nullptr;
+ if (isProofEnabled())
+ {
+ // justify in d_llra
+ for (const Node& lit : learnedLitsToConjoin)
+ {
+ d_llra->addLazyStep(lit, d_llpg.get());
+ }
+ if (learnedLitsToConjoin.size() > 1)
+ {
+ d_llra->addStep(newConj, PfRule::AND_INTRO, learnedLitsToConjoin, {});
+ pg = d_llra.get();
+ }
+ else
+ {
+ // otherwise we ask the learned literal proof generator directly
+ pg = d_llpg.get();
+ }
+ }
+ // ------- from d_llpg --------- from d_llpg
+ // conj[0] .... d_conj[n]
+ // -------------------------------- AND_INTRO
+ // newConj
+ // where newConj is conjoined at the given index
+ assertionsToPreprocess->conjoin(replIndex, newConj, pg);
}
propagator->setNeedsFinish(true);
return PreprocessingPassResult::NO_CONFLICT;
-} // namespace passes
+}
+bool NonClausalSimp::isProofEnabled() const { return d_pnm != nullptr; }
-/* -------------------------------------------------------------------------- */
+Node NonClausalSimp::processLearnedLit(Node lit,
+ theory::TrustSubstitutionMap* subs,
+ theory::TrustSubstitutionMap* cp)
+{
+ TrustNode tlit;
+ if (subs != nullptr)
+ {
+ tlit = subs->apply(lit);
+ if (!tlit.isNull())
+ {
+ lit = processRewrittenLearnedLit(tlit);
+ }
+ Trace("non-clausal-simplify")
+ << "Process learnedLiteral, after newSubs : " << lit << std::endl;
+ }
+ // apply to fixed point
+ if (cp != nullptr)
+ {
+ for (;;)
+ {
+ tlit = cp->apply(lit);
+ if (tlit.isNull())
+ {
+ break;
+ }
+ Assert(lit != tlit.getNode());
+ lit = processRewrittenLearnedLit(tlit);
+ d_statistics.d_numConstantProps += 1;
+ }
+ }
+ return lit;
+}
+
+Node NonClausalSimp::processRewrittenLearnedLit(theory::TrustNode trn)
+{
+ if (isProofEnabled())
+ {
+ d_llpg->notifyTrustedPreprocessed(trn);
+ }
+ // return the node
+ return trn.getNode();
+}
} // namespace passes
} // namespace preprocessing
diff --git a/src/preprocessing/passes/non_clausal_simp.h b/src/preprocessing/passes/non_clausal_simp.h
index 6e3645177..d3a9e0b1a 100644
--- a/src/preprocessing/passes/non_clausal_simp.h
+++ b/src/preprocessing/passes/non_clausal_simp.h
@@ -5,7 +5,7 @@
** Aina Niemetz, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,9 +19,12 @@
#include <vector>
+#include "expr/lazy_proof.h"
#include "expr/node.h"
#include "preprocessing/preprocessing_pass.h"
#include "preprocessing/preprocessing_pass_context.h"
+#include "smt/preprocess_proof_generator.h"
+#include "theory/trust_node.h"
namespace CVC4 {
namespace preprocessing {
@@ -45,9 +48,44 @@ class NonClausalSimp : public PreprocessingPass
};
Statistics d_statistics;
-
- /** Learned literals */
- std::vector<Node> d_nonClausalLearnedLiterals;
+ /**
+ * Transform learned literal lit. We apply substitutions in subs once and then
+ * apply constant propagations cp to fixed point. Return the rewritten
+ * form of lit.
+ *
+ * If proofs are enabled, then we require that the learned literal preprocess
+ * proof generator (d_llpg) has a proof of lit when this method is called,
+ * and ensure that the return literal also has a proof in d_llpg.
+ */
+ Node processLearnedLit(Node lit,
+ theory::TrustSubstitutionMap* subs,
+ theory::TrustSubstitutionMap* cp);
+ /**
+ * Process rewritten learned literal. This is called when we have a
+ * learned literal lit that is rewritten to litr based on the proof generator
+ * contained in trn (if it exists). The trust node trn should be of kind
+ * REWRITE and proving (= lit litr).
+ *
+ * This tracks the proof in the learned literal preprocess proof generator
+ * d_llpg below and returns the rewritten learned literal.
+ */
+ Node processRewrittenLearnedLit(theory::TrustNode trn);
+ /** Is proof enabled? */
+ bool isProofEnabled() const;
+ /** The proof node manager */
+ ProofNodeManager* d_pnm;
+ /** the learned literal preprocess proof generator */
+ std::unique_ptr<smt::PreprocessProofGenerator> d_llpg;
+ /**
+ * An lazy proof for learned literals that are reasserted into the assertions
+ * pipeline by this class.
+ */
+ std::unique_ptr<LazyCDProof> d_llra;
+ /**
+ * A context-dependent list of trust substitution maps, which are required
+ * for storing proofs.
+ */
+ context::CDList<std::shared_ptr<theory::TrustSubstitutionMap> > d_tsubsList;
};
} // namespace passes
diff --git a/src/preprocessing/passes/pseudo_boolean_processor.cpp b/src/preprocessing/passes/pseudo_boolean_processor.cpp
index 1f9ca579c..2720d2f0b 100644
--- a/src/preprocessing/passes/pseudo_boolean_processor.cpp
+++ b/src/preprocessing/passes/pseudo_boolean_processor.cpp
@@ -5,7 +5,7 @@
** Tim King, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/pseudo_boolean_processor.h b/src/preprocessing/passes/pseudo_boolean_processor.h
index fed566f78..03137dac5 100644
--- a/src/preprocessing/passes/pseudo_boolean_processor.h
+++ b/src/preprocessing/passes/pseudo_boolean_processor.h
@@ -5,7 +5,7 @@
** Tim King, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/quantifier_macros.cpp b/src/preprocessing/passes/quantifier_macros.cpp
index a4d8454a0..604f8719c 100644
--- a/src/preprocessing/passes/quantifier_macros.cpp
+++ b/src/preprocessing/passes/quantifier_macros.cpp
@@ -2,10 +2,10 @@
/*! \file quantifier_macros.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Yoni Zohar, Mathias Preiner
+ ** Andrew Reynolds, Yoni Zohar, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,7 +19,6 @@
#include <vector>
#include "options/quantifiers_options.h"
-#include "proof/proof_manager.h"
#include "smt/smt_engine.h"
#include "smt/smt_engine_scope.h"
#include "theory/arith/arith_msum.h"
@@ -50,7 +49,7 @@ PreprocessingPassResult QuantifierMacros::applyInternal(
bool success;
do
{
- success = simplify(assertionsToPreprocess->ref(), true);
+ success = simplify(assertionsToPreprocess, true);
} while (success);
finalizeDefinitions();
clearMaps();
@@ -68,7 +67,9 @@ void QuantifierMacros::clearMaps()
d_ground_macros = false;
}
-bool QuantifierMacros::simplify( std::vector< Node >& assertions, bool doRewrite ){
+bool QuantifierMacros::simplify(AssertionPipeline* ap, bool doRewrite)
+{
+ const std::vector<Node>& assertions = ap->ref();
unsigned rmax =
options::macrosQuantMode() == options::MacrosQuantMode::ALL ? 2 : 1;
for( unsigned r=0; r<rmax; r++ ){
@@ -79,11 +80,14 @@ bool QuantifierMacros::simplify( std::vector< Node >& assertions, bool doRewrite
for( int i=0; i<(int)assertions.size(); i++ ){
Trace("macros-debug") << " process assertion " << assertions[i] << std::endl;
if( processAssertion( assertions[i] ) ){
- PROOF(
- if( std::find( macro_assertions.begin(), macro_assertions.end(), assertions[i] )==macro_assertions.end() ){
- macro_assertions.push_back( assertions[i] );
- }
- );
+ if (options::unsatCores()
+ && std::find(macro_assertions.begin(),
+ macro_assertions.end(),
+ assertions[i])
+ == macro_assertions.end())
+ {
+ macro_assertions.push_back(assertions[i]);
+ }
//process this assertion again
i--;
}
@@ -98,18 +102,23 @@ bool QuantifierMacros::simplify( std::vector< Node >& assertions, bool doRewrite
if( curr!=assertions[i] ){
curr = Rewriter::rewrite( curr );
Trace("macros-rewrite") << "Rewrite " << assertions[i] << " to " << curr << std::endl;
- //for now, it is dependent upon all assertions involving macros, this is an over-approximation.
- //a more fine-grained unsat core computation would require caching dependencies for each subterm of the formula,
- // which is expensive.
- PROOF(ProofManager::currentPM()->addDependence(curr, assertions[i]);
- for (unsigned j = 0; j < macro_assertions.size(); j++) {
- if (macro_assertions[j] != assertions[i])
- {
- ProofManager::currentPM()->addDependence(
- curr, macro_assertions[j]);
- }
- });
- assertions[i] = curr;
+ // for now, it is dependent upon all assertions involving macros, this
+ // is an over-approximation. a more fine-grained unsat core
+ // computation would require caching dependencies for each subterm of
+ // the formula, which is expensive.
+ if (options::unsatCores())
+ {
+ ProofManager::currentPM()->addDependence(curr, assertions[i]);
+ for (unsigned j = 0; j < macro_assertions.size(); j++)
+ {
+ if (macro_assertions[j] != assertions[i])
+ {
+ ProofManager::currentPM()->addDependence(curr,
+ macro_assertions[j]);
+ }
+ }
+ }
+ ap->replace(i, curr);
retVal = true;
}
}
@@ -432,9 +441,9 @@ Node QuantifierMacros::simplify( Node n ){
for( unsigned i=0; i<children.size(); i++ ){
Node etc = TypeNode::getEnsureTypeCondition( children[i], tno[i] );
if( etc.isNull() ){
- //if this does fail, we are incomplete, since we are eliminating quantified formula corresponding to op,
+ // if this does fail, we are incomplete, since we are eliminating
+ // quantified formula corresponding to op,
// and not ensuring it applies to n when its types are correct.
- //Assert( false );
success = false;
break;
}else if( !etc.isConst() ){
@@ -495,20 +504,21 @@ void QuantifierMacros::finalizeDefinitions() {
if( options::incrementalSolving() || options::produceModels() || doDefs ){
Trace("macros") << "Store as defined functions..." << std::endl;
//also store as defined functions
+ SmtEngine* smt = d_preprocContext->getSmt();
for( std::map< Node, Node >::iterator it = d_macro_defs.begin(); it != d_macro_defs.end(); ++it ){
Trace("macros-def") << "Macro definition for " << it->first << " : " << it->second << std::endl;
Trace("macros-def") << " basis is : ";
std::vector< Node > nargs;
- std::vector< Expr > args;
+ std::vector<Node> args;
for( unsigned i=0; i<d_macro_basis[it->first].size(); i++ ){
Node bv = NodeManager::currentNM()->mkBoundVar( d_macro_basis[it->first][i].getType() );
Trace("macros-def") << d_macro_basis[it->first][i] << " ";
nargs.push_back( bv );
- args.push_back( bv.toExpr() );
+ args.push_back(bv);
}
Trace("macros-def") << std::endl;
Node sbody = it->second.substitute( d_macro_basis[it->first].begin(), d_macro_basis[it->first].end(), nargs.begin(), nargs.end() );
- smt::currentSmtEngine()->defineFunction( it->first.toExpr(), args, sbody.toExpr() );
+ smt->defineFunction(it->first, args, sbody);
if( Trace.isOn("macros-warn") ){
debugMacroDefinition( it->first, sbody );
diff --git a/src/preprocessing/passes/quantifier_macros.h b/src/preprocessing/passes/quantifier_macros.h
index 30a83e54a..c5e557a9e 100644
--- a/src/preprocessing/passes/quantifier_macros.h
+++ b/src/preprocessing/passes/quantifier_macros.h
@@ -5,7 +5,7 @@
** Yoni Zohar, Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -64,7 +64,17 @@ class QuantifierMacros : public PreprocessingPass
bool reqComplete);
void addMacro(Node op, Node n, std::vector<Node>& opc);
void debugMacroDefinition(Node oo, Node n);
- bool simplify(std::vector<Node>& assertions, bool doRewrite = false);
+ /**
+ * This applies macro elimination to the given pipeline, which discovers
+ * whether there are any quantified formulas corresponding to macros.
+ *
+ * @param ap The pipeline to apply macros to.
+ * @param doRewrite Whether we also wish to rewrite the assertions based on
+ * the discovered macro definitions.
+ * @return Whether new definitions were inferred and we rewrote the assertions
+ * based on them.
+ */
+ bool simplify(AssertionPipeline* ap, bool doRewrite = false);
Node simplify(Node n);
void finalizeDefinitions();
void clearMaps();
diff --git a/src/preprocessing/passes/quantifiers_preprocess.cpp b/src/preprocessing/passes/quantifiers_preprocess.cpp
index 3052e9629..6daafff2d 100644
--- a/src/preprocessing/passes/quantifiers_preprocess.cpp
+++ b/src/preprocessing/passes/quantifiers_preprocess.cpp
@@ -2,10 +2,10 @@
/*! \file quantifiers_preprocess.cpp
** \verbatim
** Top contributors (to current version):
- ** Caleb Donovick
+ ** Caleb Donovick, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -39,9 +39,10 @@ PreprocessingPassResult QuantifiersPreprocess::applyInternal(
for (size_t i = 0; i < size; ++i)
{
Node prev = (*assertionsToPreprocess)[i];
- Node next = quantifiers::QuantifiersRewriter::preprocess(prev);
- if (next != prev)
+ TrustNode trn = quantifiers::QuantifiersRewriter::preprocess(prev);
+ if (!trn.isNull())
{
+ Node next = trn.getNode();
assertionsToPreprocess->replace(i, Rewriter::rewrite(next));
Trace("quantifiers-preprocess") << "*** Pre-skolemize " << prev << endl;
Trace("quantifiers-preprocess")
diff --git a/src/preprocessing/passes/quantifiers_preprocess.h b/src/preprocessing/passes/quantifiers_preprocess.h
index 1e8b298f1..43fce22b3 100644
--- a/src/preprocessing/passes/quantifiers_preprocess.h
+++ b/src/preprocessing/passes/quantifiers_preprocess.h
@@ -5,7 +5,7 @@
** Caleb Donovick, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/real_to_int.cpp b/src/preprocessing/passes/real_to_int.cpp
index 0e8ee3c4d..672e281d7 100644
--- a/src/preprocessing/passes/real_to_int.cpp
+++ b/src/preprocessing/passes/real_to_int.cpp
@@ -5,7 +5,7 @@
** Haniel Barbosa, Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -181,9 +181,8 @@ Node RealToInt::realToIntInternal(TNode n, NodeMap& cache, std::vector<Node>& va
var_eq.push_back(n.eqNode(ret));
// ensure that the original variable is defined to be the returned
// one, which is important for models and for incremental solving.
- std::vector<Expr> args;
- smt::currentSmtEngine()->defineFunction(
- n.toExpr(), args, ret.toExpr());
+ std::vector<Node> args;
+ d_preprocContext->getSmt()->defineFunction(n, args, ret);
}
}
}
diff --git a/src/preprocessing/passes/real_to_int.h b/src/preprocessing/passes/real_to_int.h
index d5c3be4e5..9fd8aca53 100644
--- a/src/preprocessing/passes/real_to_int.h
+++ b/src/preprocessing/passes/real_to_int.h
@@ -5,7 +5,7 @@
** Haniel Barbosa, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/rewrite.cpp b/src/preprocessing/passes/rewrite.cpp
index e12691cc0..b4a353862 100644
--- a/src/preprocessing/passes/rewrite.cpp
+++ b/src/preprocessing/passes/rewrite.cpp
@@ -5,7 +5,7 @@
** Caleb Donovick
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/rewrite.h b/src/preprocessing/passes/rewrite.h
index 3bced24b1..76493958a 100644
--- a/src/preprocessing/passes/rewrite.h
+++ b/src/preprocessing/passes/rewrite.h
@@ -5,7 +5,7 @@
** Caleb Donovick, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/sep_skolem_emp.cpp b/src/preprocessing/passes/sep_skolem_emp.cpp
index b6f575789..ef2014b8a 100644
--- a/src/preprocessing/passes/sep_skolem_emp.cpp
+++ b/src/preprocessing/passes/sep_skolem_emp.cpp
@@ -5,7 +5,7 @@
** Yoni Zohar, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/sep_skolem_emp.h b/src/preprocessing/passes/sep_skolem_emp.h
index 8cbab3e29..912fd1b60 100644
--- a/src/preprocessing/passes/sep_skolem_emp.h
+++ b/src/preprocessing/passes/sep_skolem_emp.h
@@ -5,7 +5,7 @@
** Yoni Zohar, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/sort_infer.cpp b/src/preprocessing/passes/sort_infer.cpp
index 92c2e55b1..79f387aa6 100644
--- a/src/preprocessing/passes/sort_infer.cpp
+++ b/src/preprocessing/passes/sort_infer.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,6 +16,7 @@
#include "options/smt_options.h"
#include "options/uf_options.h"
+#include "smt/dump_manager.h"
#include "theory/rewriter.h"
#include "theory/sort_inference.h"
@@ -65,12 +66,12 @@ PreprocessingPassResult SortInferencePass::applyInternal(
assertionsToPreprocess->push_back(nar);
}
// indicate correspondence between the functions
- // TODO (#2308): move this to a better place
SmtEngine* smt = smt::currentSmtEngine();
+ smt::DumpManager* dm = smt->getDumpManager();
for (const std::pair<const Node, Node>& mrf : model_replace_f)
{
- smt->setPrintFuncInModel(mrf.first.toExpr(), false);
- smt->setPrintFuncInModel(mrf.second.toExpr(), true);
+ dm->setPrintFuncInModel(mrf.first, false);
+ dm->setPrintFuncInModel(mrf.second, true);
}
}
// only need to compute monotonicity on the resulting formula if we are
diff --git a/src/preprocessing/passes/sort_infer.h b/src/preprocessing/passes/sort_infer.h
index 3a8646109..1a18b6fd1 100644
--- a/src/preprocessing/passes/sort_infer.h
+++ b/src/preprocessing/passes/sort_infer.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/static_learning.cpp b/src/preprocessing/passes/static_learning.cpp
index c15867a39..4ab1a038c 100644
--- a/src/preprocessing/passes/static_learning.cpp
+++ b/src/preprocessing/passes/static_learning.cpp
@@ -2,10 +2,10 @@
/*! \file static_learning.cpp
** \verbatim
** Top contributors (to current version):
- ** Yoni Zohar, Mathias Preiner
+ ** Yoni Zohar, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/static_learning.h b/src/preprocessing/passes/static_learning.h
index 16498f080..c86ebf90f 100644
--- a/src/preprocessing/passes/static_learning.h
+++ b/src/preprocessing/passes/static_learning.h
@@ -5,7 +5,7 @@
** Yoni Zohar, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/sygus_inference.cpp b/src/preprocessing/passes/sygus_inference.cpp
index 7336ac159..ea767e771 100644
--- a/src/preprocessing/passes/sygus_inference.cpp
+++ b/src/preprocessing/passes/sygus_inference.cpp
@@ -2,10 +2,10 @@
/*! \file sygus_inference.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Mathias Preiner
+ ** Andrew Reynolds, Mathias Preiner, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -24,6 +24,7 @@
using namespace std;
using namespace CVC4::kind;
+using namespace CVC4::theory;
namespace CVC4 {
namespace preprocessing {
@@ -43,21 +44,21 @@ PreprocessingPassResult SygusInference::applyInternal(
{
Assert(funs.size() == sols.size());
// if so, sygus gives us function definitions
- SmtEngine* master_smte = smt::currentSmtEngine();
+ SmtEngine* master_smte = d_preprocContext->getSmt();
for (unsigned i = 0, size = funs.size(); i < size; i++)
{
- std::vector<Expr> args;
+ std::vector<Node> args;
Node sol = sols[i];
// if it is a non-constant function
if (sol.getKind() == LAMBDA)
{
for (const Node& v : sol[0])
{
- args.push_back(v.toExpr());
+ args.push_back(v);
}
sol = sol[1];
}
- master_smte->defineFunction(funs[i].toExpr(), args, sol.toExpr());
+ master_smte->defineFunction(funs[i], args, sol);
}
// apply substitution to everything, should result in SAT
@@ -79,7 +80,7 @@ PreprocessingPassResult SygusInference::applyInternal(
return PreprocessingPassResult::NO_CONFLICT;
}
-bool SygusInference::solveSygus(std::vector<Node>& assertions,
+bool SygusInference::solveSygus(const std::vector<Node>& assertions,
std::vector<Node>& funs,
std::vector<Node>& sols)
{
@@ -135,7 +136,11 @@ bool SygusInference::solveSygus(std::vector<Node>& assertions,
if (pas.getKind() == FORALL)
{
// preprocess the quantified formula
- pas = theory::quantifiers::QuantifiersRewriter::preprocess(pas);
+ TrustNode trn = quantifiers::QuantifiersRewriter::preprocess(pas);
+ if (!trn.isNull())
+ {
+ pas = trn.getNode();
+ }
Trace("sygus-infer-debug") << " ...preprocessed to " << pas << std::endl;
}
if (pas.getKind() == FORALL)
@@ -313,25 +318,25 @@ bool SygusInference::solveSygus(std::vector<Node>& assertions,
return false;
}
// get the synthesis solutions
- std::map<Expr, Expr> synth_sols;
+ std::map<Node, Node> synth_sols;
rrSygus->getSynthSolutions(synth_sols);
std::vector<Node> final_ff;
std::vector<Node> final_ff_sol;
- for (std::map<Expr, Expr>::iterator it = synth_sols.begin();
+ for (std::map<Node, Node>::iterator it = synth_sols.begin();
it != synth_sols.end();
++it)
{
Trace("sygus-infer") << " synth sol : " << it->first << " -> "
<< it->second << std::endl;
- Node ffv = Node::fromExpr(it->first);
+ Node ffv = it->first;
std::map<Node, Node>::iterator itffv = ff_var_to_ff.find(ffv);
// all synthesis solutions should correspond to a variable we introduced
Assert(itffv != ff_var_to_ff.end());
if (itffv != ff_var_to_ff.end())
{
Node ff = itffv->second;
- Node body2 = Node::fromExpr(it->second);
+ Node body2 = it->second;
Trace("sygus-infer") << "Define " << ff << " as " << body2 << std::endl;
funs.push_back(ff);
sols.push_back(body2);
diff --git a/src/preprocessing/passes/sygus_inference.h b/src/preprocessing/passes/sygus_inference.h
index 6b84ea3fe..31d94efd2 100644
--- a/src/preprocessing/passes/sygus_inference.h
+++ b/src/preprocessing/passes/sygus_inference.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -59,7 +59,7 @@ class SygusInference : public PreprocessingPass
* If this function returns true, then we add all uninterpreted symbols s in
* assertions to funs and their corresponding solution to sols.
*/
- bool solveSygus(std::vector<Node>& assertions,
+ bool solveSygus(const std::vector<Node>& assertions,
std::vector<Node>& funs,
std::vector<Node>& sols);
};
diff --git a/src/preprocessing/passes/synth_rew_rules.cpp b/src/preprocessing/passes/synth_rew_rules.cpp
index d0ebe5f19..8465a63a0 100644
--- a/src/preprocessing/passes/synth_rew_rules.cpp
+++ b/src/preprocessing/passes/synth_rew_rules.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -40,7 +40,7 @@ PreprocessingPassResult SynthRewRulesPass::applyInternal(
{
Trace("srs-input") << "Synthesize rewrite rules from assertions..."
<< std::endl;
- std::vector<Node>& assertions = assertionsToPreprocess->ref();
+ const std::vector<Node>& assertions = assertionsToPreprocess->ref();
if (assertions.empty())
{
return PreprocessingPassResult::NO_CONFLICT;
@@ -241,7 +241,7 @@ PreprocessingPassResult SynthRewRulesPass::applyInternal(
Trace("srs-input") << "Construct unresolved types..." << std::endl;
// each canonical subterm corresponds to a grammar type
- std::set<Type> unres;
+ std::set<TypeNode> unres;
std::vector<SygusDatatype> sdts;
// make unresolved types for each canonical term
std::map<Node, TypeNode> cterm_to_utype;
@@ -253,7 +253,7 @@ PreprocessingPassResult SynthRewRulesPass::applyInternal(
std::string tname = ss.str();
TypeNode tnu = nm->mkSort(tname, ExprManager::SORT_FLAG_PLACEHOLDER);
cterm_to_utype[ct] = tnu;
- unres.insert(tnu.toType());
+ unres.insert(tnu);
sdts.push_back(SygusDatatype(tname));
}
Trace("srs-input") << "...finished." << std::endl;
@@ -369,19 +369,19 @@ PreprocessingPassResult SynthRewRulesPass::applyInternal(
Trace("srs-input") << "Make mutual datatype types for subterms..."
<< std::endl;
// extract the datatypes
- std::vector<Datatype> datatypes;
+ std::vector<DType> datatypes;
for (unsigned i = 0, ndts = sdts.size(); i < ndts; i++)
{
datatypes.push_back(sdts[i].getDatatype());
}
- std::vector<DatatypeType> types = nm->toExprManager()->mkMutualDatatypeTypes(
- datatypes, unres, ExprManager::DATATYPE_FLAG_PLACEHOLDER);
+ std::vector<TypeNode> types = nm->mkMutualDatatypeTypes(
+ datatypes, unres, NodeManager::DATATYPE_FLAG_PLACEHOLDER);
Trace("srs-input") << "...finished." << std::endl;
Assert(types.size() == unres.size());
std::map<Node, TypeNode> subtermTypes;
for (unsigned i = 0, ncterms = cterms.size(); i < ncterms; i++)
{
- subtermTypes[cterms[i]] = TypeNode::fromType(types[i]);
+ subtermTypes[cterms[i]] = types[i];
}
Trace("srs-input") << "Construct the top-level types..." << std::endl;
@@ -418,12 +418,12 @@ PreprocessingPassResult SynthRewRulesPass::applyInternal(
}
// set that this is a sygus datatype
sdttl.initializeDatatype(t, sygusVarList, false, false);
- Datatype dttl = sdttl.getDatatype();
- DatatypeType tlt = nm->toExprManager()->mkDatatypeType(
- dttl, ExprManager::DATATYPE_FLAG_PLACEHOLDER);
- tlGrammarTypes[t] = TypeNode::fromType(tlt);
+ DType dttl = sdttl.getDatatype();
+ TypeNode tlt =
+ nm->mkDatatypeType(dttl, NodeManager::DATATYPE_FLAG_PLACEHOLDER);
+ tlGrammarTypes[t] = tlt;
Trace("srs-input") << "Grammar is: " << std::endl;
- Trace("srs-input") << tlt.getDatatype() << std::endl;
+ Trace("srs-input") << tlt.getDType() << std::endl;
}
Trace("srs-input") << "...finished." << std::endl;
diff --git a/src/preprocessing/passes/synth_rew_rules.h b/src/preprocessing/passes/synth_rew_rules.h
index 80e09fd11..5613c1b22 100644
--- a/src/preprocessing/passes/synth_rew_rules.h
+++ b/src/preprocessing/passes/synth_rew_rules.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/theory_preprocess.cpp b/src/preprocessing/passes/theory_preprocess.cpp
index 5cc25b73f..bf9c3e9fe 100644
--- a/src/preprocessing/passes/theory_preprocess.cpp
+++ b/src/preprocessing/passes/theory_preprocess.cpp
@@ -5,7 +5,7 @@
** Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -32,12 +32,11 @@ PreprocessingPassResult TheoryPreprocess::applyInternal(
AssertionPipeline* assertionsToPreprocess)
{
TheoryEngine* te = d_preprocContext->getTheoryEngine();
- te->preprocessStart();
for (size_t i = 0, size = assertionsToPreprocess->size(); i < size; ++i)
{
TNode a = (*assertionsToPreprocess)[i];
Assert(Rewriter::rewrite(a) == a);
- assertionsToPreprocess->replace(i, te->preprocess(a));
+ assertionsToPreprocess->replaceTrusted(i, te->preprocess(a));
a = (*assertionsToPreprocess)[i];
Assert(Rewriter::rewrite(a) == a);
}
diff --git a/src/preprocessing/passes/theory_preprocess.h b/src/preprocessing/passes/theory_preprocess.h
index 764685b85..49597828d 100644
--- a/src/preprocessing/passes/theory_preprocess.h
+++ b/src/preprocessing/passes/theory_preprocess.h
@@ -5,7 +5,7 @@
** Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/passes/unconstrained_simplifier.cpp b/src/preprocessing/passes/unconstrained_simplifier.cpp
index 7d1f66d65..a4e7ac703 100644
--- a/src/preprocessing/passes/unconstrained_simplifier.cpp
+++ b/src/preprocessing/passes/unconstrained_simplifier.cpp
@@ -5,7 +5,7 @@
** Clark Barrett, Andres Noetzli, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,6 +18,7 @@
#include "preprocessing/passes/unconstrained_simplifier.h"
+#include "expr/dtype.h"
#include "smt/smt_statistics_registry.h"
#include "theory/logic_info.h"
#include "theory/rewriter.h"
@@ -33,8 +34,7 @@ UnconstrainedSimplifier::UnconstrainedSimplifier(
: PreprocessingPass(preprocContext, "unconstrained-simplifier"),
d_numUnconstrainedElim("preprocessor::number of unconstrained elims", 0),
d_context(preprocContext->getDecisionContext()),
- d_substitutions(preprocContext->getDecisionContext()),
- d_logicInfo(preprocContext->getLogicInfo())
+ d_substitutions(preprocContext->getDecisionContext())
{
smtStatisticsRegistry()->registerStat(&d_numUnconstrainedElim);
}
@@ -262,8 +262,8 @@ void UnconstrainedSimplifier::processUnconstrained()
if (parent[0].getType().isDatatype())
{
TypeNode tn = parent[0].getType();
- const Datatype& dt = ((DatatypeType)(tn).toType()).getDatatype();
- if (dt.isRecursiveSingleton(tn.toType()))
+ const DType& dt = tn.getDType();
+ if (dt.isRecursiveSingleton(tn))
{
// domain size may be 1
break;
@@ -587,7 +587,7 @@ void UnconstrainedSimplifier::processUnconstrained()
// Uninterpreted function - if domain is infinite, no quantifiers are
// used, and any child is unconstrained, result is unconstrained
case kind::APPLY_UF:
- if (d_logicInfo.isQuantified()
+ if (d_preprocContext->getLogicInfo().isQuantified()
|| !current.getType().getCardinality().isInfinite())
{
break;
@@ -841,7 +841,7 @@ PreprocessingPassResult UnconstrainedSimplifier::applyInternal(
{
d_preprocContext->spendResource(ResourceManager::Resource::PreprocessStep);
- std::vector<Node>& assertions = assertionsToPreprocess->ref();
+ const std::vector<Node>& assertions = assertionsToPreprocess->ref();
d_context->push();
@@ -854,9 +854,12 @@ PreprocessingPassResult UnconstrainedSimplifier::applyInternal(
{
processUnconstrained();
// d_substitutions.print(Message.getStream());
- for (Node& assertion : assertions)
+ for (size_t i = 0, asize = assertions.size(); i < asize; ++i)
{
- assertion = Rewriter::rewrite(d_substitutions.apply(assertion));
+ Node a = assertions[i];
+ Node as = Rewriter::rewrite(d_substitutions.apply(a));
+ // replace the assertion
+ assertionsToPreprocess->replace(i, as);
}
}
diff --git a/src/preprocessing/passes/unconstrained_simplifier.h b/src/preprocessing/passes/unconstrained_simplifier.h
index c10730d60..ebfe51e79 100644
--- a/src/preprocessing/passes/unconstrained_simplifier.h
+++ b/src/preprocessing/passes/unconstrained_simplifier.h
@@ -5,7 +5,7 @@
** Clark Barrett, Andres Noetzli, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -61,7 +61,6 @@ class UnconstrainedSimplifier : public PreprocessingPass
context::Context* d_context;
theory::SubstitutionMap d_substitutions;
- const LogicInfo& d_logicInfo;
/**
* Visit all subterms in assertion. This method throws a LogicException if
* there is a subterm that is unhandled by this preprocessing pass (e.g. a
diff --git a/src/preprocessing/preprocessing_pass.cpp b/src/preprocessing/preprocessing_pass.cpp
index 965edcd2f..78b0022c6 100644
--- a/src/preprocessing/preprocessing_pass.cpp
+++ b/src/preprocessing/preprocessing_pass.cpp
@@ -5,7 +5,7 @@
** Justin Xu, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,6 +18,7 @@
#include "smt/dump.h"
#include "smt/smt_statistics_registry.h"
+#include "printer/printer.h"
namespace CVC4 {
namespace preprocessing {
@@ -39,8 +40,13 @@ void PreprocessingPass::dumpAssertions(const char* key,
if (Dump.isOn("assertions") && Dump.isOn(std::string("assertions:") + key))
{
// Push the simplified assertions to the dump output stream
- for (const auto& n : assertionList) {
- Dump("assertions") << AssertCommand(Expr(n.toExpr()));
+ OutputManager& outMgr = d_preprocContext->getSmt()->getOutputManager();
+ const Printer& printer = outMgr.getPrinter();
+ std::ostream& out = outMgr.getDumpOut();
+
+ for (const auto& n : assertionList)
+ {
+ printer.toStreamCmdAssert(out, n);
}
}
}
diff --git a/src/preprocessing/preprocessing_pass.h b/src/preprocessing/preprocessing_pass.h
index e81f71666..b8ddb9846 100644
--- a/src/preprocessing/preprocessing_pass.h
+++ b/src/preprocessing/preprocessing_pass.h
@@ -5,7 +5,7 @@
** Justin Xu, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/preprocessing_pass_context.cpp b/src/preprocessing/preprocessing_pass_context.cpp
index 2dfad99c2..5893635cf 100644
--- a/src/preprocessing/preprocessing_pass_context.cpp
+++ b/src/preprocessing/preprocessing_pass_context.cpp
@@ -2,10 +2,10 @@
/*! \file preprocessing_pass_context.cpp
** \verbatim
** Top contributors (to current version):
- ** Aina Niemetz, Mathias Preiner, Andres Noetzli
+ ** Aina Niemetz, Mathias Preiner, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,7 +14,7 @@
** The preprocessing pass context for passes.
**/
-#include "preprocessing_pass_context.h"
+#include "preprocessing/preprocessing_pass_context.h"
#include "expr/node_algorithm.h"
@@ -24,12 +24,14 @@ namespace preprocessing {
PreprocessingPassContext::PreprocessingPassContext(
SmtEngine* smt,
RemoveTermFormulas* iteRemover,
- theory::booleans::CircuitPropagator* circuitPropagator)
+ theory::booleans::CircuitPropagator* circuitPropagator,
+ ProofNodeManager* pnm)
: d_smt(smt),
d_resourceManager(smt->getResourceManager()),
d_iteRemover(iteRemover),
- d_topLevelSubstitutions(smt->getUserContext()),
+ d_topLevelSubstitutions(smt->getUserContext(), pnm),
d_circuitPropagator(circuitPropagator),
+ d_pnm(pnm),
d_symsInAssertions(smt->getUserContext())
{
}
@@ -40,6 +42,12 @@ void PreprocessingPassContext::widenLogic(theory::TheoryId id)
req.widenLogic(id);
}
+theory::TrustSubstitutionMap&
+PreprocessingPassContext::getTopLevelSubstitutions()
+{
+ return d_topLevelSubstitutions;
+}
+
void PreprocessingPassContext::enableIntegers()
{
LogicRequest req(*d_smt);
@@ -61,5 +69,10 @@ void PreprocessingPassContext::recordSymbolsInAssertions(
}
}
+ProofNodeManager* PreprocessingPassContext::getProofNodeManager()
+{
+ return d_pnm;
+}
+
} // namespace preprocessing
} // namespace CVC4
diff --git a/src/preprocessing/preprocessing_pass_context.h b/src/preprocessing/preprocessing_pass_context.h
index feed945d5..824197bc5 100644
--- a/src/preprocessing/preprocessing_pass_context.h
+++ b/src/preprocessing/preprocessing_pass_context.h
@@ -5,7 +5,7 @@
** Aina Niemetz, Mathias Preiner, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -29,6 +29,7 @@
#include "smt/term_formula_removal.h"
#include "theory/booleans/circuit_propagator.h"
#include "theory/theory_engine.h"
+#include "theory/trust_substitutions.h"
#include "util/resource_manager.h"
namespace CVC4 {
@@ -40,7 +41,8 @@ class PreprocessingPassContext
PreprocessingPassContext(
SmtEngine* smt,
RemoveTermFormulas* iteRemover,
- theory::booleans::CircuitPropagator* circuitPropagator);
+ theory::booleans::CircuitPropagator* circuitPropagator,
+ ProofNodeManager* pnm);
SmtEngine* getSmt() { return d_smt; }
TheoryEngine* getTheoryEngine() { return d_smt->getTheoryEngine(); }
@@ -64,16 +66,14 @@ class PreprocessingPassContext
d_resourceManager->spendResource(r);
}
- const LogicInfo& getLogicInfo() { return d_smt->d_logic; }
+ /** Get the current logic info of the SmtEngine */
+ const LogicInfo& getLogicInfo() { return d_smt->getLogicInfo(); }
/* Widen the logic to include the given theory. */
void widenLogic(theory::TheoryId id);
/** Gets a reference to the top-level substitution map */
- theory::SubstitutionMap& getTopLevelSubstitutions()
- {
- return d_topLevelSubstitutions;
- }
+ theory::TrustSubstitutionMap& getTopLevelSubstitutions();
/* Enable Integers. */
void enableIntegers();
@@ -85,6 +85,9 @@ class PreprocessingPassContext
*/
void recordSymbolsInAssertions(const std::vector<Node>& assertions);
+ /** The the proof node manager associated with this context, if it exists */
+ ProofNodeManager* getProofNodeManager();
+
private:
/** Pointer to the SmtEngine that this context was created in. */
SmtEngine* d_smt;
@@ -96,10 +99,12 @@ class PreprocessingPassContext
RemoveTermFormulas* d_iteRemover;
/* The top level substitutions */
- theory::SubstitutionMap d_topLevelSubstitutions;
+ theory::TrustSubstitutionMap d_topLevelSubstitutions;
/** Instance of the circuit propagator */
theory::booleans::CircuitPropagator* d_circuitPropagator;
+ /** Pointer to the proof node manager, if it exists */
+ ProofNodeManager* d_pnm;
/**
* The (user-context-dependent) set of symbols that occur in at least one
diff --git a/src/preprocessing/preprocessing_pass_registry.cpp b/src/preprocessing/preprocessing_pass_registry.cpp
index 59c03479e..46c1fff68 100644
--- a/src/preprocessing/preprocessing_pass_registry.cpp
+++ b/src/preprocessing/preprocessing_pass_registry.cpp
@@ -5,7 +5,7 @@
** Andres Noetzli, Yoni Zohar, Justin Xu
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -33,6 +33,7 @@
#include "preprocessing/passes/bv_to_bool.h"
#include "preprocessing/passes/bv_to_int.h"
#include "preprocessing/passes/extended_rewriter_pass.h"
+#include "preprocessing/passes/fun_def_fmf.h"
#include "preprocessing/passes/global_negate.h"
#include "preprocessing/passes/ho_elim.h"
#include "preprocessing/passes/int_to_bv.h"
@@ -147,6 +148,7 @@ PreprocessingPassRegistry::PreprocessingPassRegistry()
registerPassInfo("nl-ext-purify", callCtor<NlExtPurify>);
registerPassInfo("bool-to-bv", callCtor<BoolToBV>);
registerPassInfo("ho-elim", callCtor<HoElim>);
+ registerPassInfo("fun-def-fmf", callCtor<FunDefFmf>);
}
} // namespace preprocessing
diff --git a/src/preprocessing/preprocessing_pass_registry.h b/src/preprocessing/preprocessing_pass_registry.h
index cf10ab902..ce5c5da22 100644
--- a/src/preprocessing/preprocessing_pass_registry.h
+++ b/src/preprocessing/preprocessing_pass_registry.h
@@ -5,7 +5,7 @@
** Andres Noetzli, Justin Xu, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/preprocessing/util/ite_utilities.cpp b/src/preprocessing/util/ite_utilities.cpp
index 45762341a..c9bf283ac 100644
--- a/src/preprocessing/util/ite_utilities.cpp
+++ b/src/preprocessing/util/ite_utilities.cpp
@@ -5,7 +5,7 @@
** Tim King, Aina Niemetz, Clark Barrett
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -130,13 +130,13 @@ bool ITEUtilities::simpIteDidALotOfWorkHeuristic() const
}
/* returns false if an assertion is discovered to be equal to false. */
-bool ITEUtilities::compress(std::vector<Node>& assertions)
+bool ITEUtilities::compress(AssertionPipeline* assertionsToPreprocess)
{
if (d_compressor == NULL)
{
d_compressor = new ITECompressor(d_containsVisitor.get());
}
- return d_compressor->compress(assertions);
+ return d_compressor->compress(assertionsToPreprocess);
}
Node ITEUtilities::simplifyWithCare(TNode e)
@@ -527,17 +527,18 @@ Node ITECompressor::compressBoolean(Node toCompress)
}
}
-bool ITECompressor::compress(std::vector<Node>& assertions)
+bool ITECompressor::compress(AssertionPipeline* assertionsToPreprocess)
{
reset();
- d_assertions = &assertions;
- d_incoming.computeReachability(assertions);
+ d_assertions = assertionsToPreprocess;
+ d_incoming.computeReachability(assertionsToPreprocess->ref());
++(d_statistics.d_compressCalls);
Chat() << "Computed reachability" << endl;
bool nofalses = true;
+ const std::vector<Node>& assertions = assertionsToPreprocess->ref();
size_t original_size = assertions.size();
Chat() << "compressing " << original_size << endl;
for (size_t i = 0; i < original_size && nofalses; ++i)
@@ -545,7 +546,8 @@ bool ITECompressor::compress(std::vector<Node>& assertions)
Node assertion = assertions[i];
Node compressed = compressBoolean(assertion);
Node rewritten = theory::Rewriter::rewrite(compressed);
- assertions[i] = rewritten;
+ // replace
+ assertionsToPreprocess->replace(i, rewritten);
Assert(!d_contains->containsTermITE(rewritten));
nofalses = (rewritten != d_false);
diff --git a/src/preprocessing/util/ite_utilities.h b/src/preprocessing/util/ite_utilities.h
index d26dee206..c82bf7958 100644
--- a/src/preprocessing/util/ite_utilities.h
+++ b/src/preprocessing/util/ite_utilities.h
@@ -5,7 +5,7 @@
** Tim King, Aina Niemetz, Clark Barrett
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -27,6 +27,7 @@
#include <vector>
#include "expr/node.h"
+#include "preprocessing/assertion_pipeline.h"
#include "util/hash.h"
#include "util/statistics_registry.h"
@@ -74,7 +75,7 @@ class ITEUtilities
bool simpIteDidALotOfWorkHeuristic() const;
/* returns false if an assertion is discovered to be equal to false. */
- bool compress(std::vector<Node>& assertions);
+ bool compress(AssertionPipeline* assertionsToPreprocess);
Node simplifyWithCare(TNode e);
@@ -167,7 +168,7 @@ class ITECompressor
~ITECompressor();
/* returns false if an assertion is discovered to be equal to false. */
- bool compress(std::vector<Node>& assertions);
+ bool compress(AssertionPipeline* assertionsToPreprocess);
/* garbage Collects the compressor. */
void garbageCollect();
@@ -176,7 +177,7 @@ class ITECompressor
Node d_true; /* Copy of true. */
Node d_false; /* Copy of false. */
ContainsTermITEVisitor* d_contains;
- std::vector<Node>* d_assertions;
+ AssertionPipeline* d_assertions;
IncomingArcCounter d_incoming;
typedef std::unordered_map<Node, Node, NodeHashFunction> NodeMap;
diff --git a/src/printer/ast/ast_printer.cpp b/src/printer/ast/ast_printer.cpp
index 1923594f3..8bf3bd24e 100644
--- a/src/printer/ast/ast_printer.cpp
+++ b/src/printer/ast/ast_printer.cpp
@@ -2,10 +2,10 @@
/*! \file ast_printer.cpp
** \verbatim
** Top contributors (to current version):
- ** Morgan Deters, Tim King, Andrew Reynolds
+ ** Morgan Deters, Abdalrhman Mohamed, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -26,6 +26,7 @@
#include "options/language.h" // for LANG_AST
#include "printer/dagification_visitor.h"
#include "smt/command.h"
+#include "smt/node_command.h"
#include "theory/substitutions.h"
using namespace std;
@@ -34,8 +35,10 @@ namespace CVC4 {
namespace printer {
namespace ast {
-void AstPrinter::toStream(
- std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const
+void AstPrinter::toStream(std::ostream& out,
+ TNode n,
+ int toDepth,
+ size_t dag) const
{
if(dag != 0) {
DagificationVisitor dv(dag);
@@ -53,26 +56,23 @@ void AstPrinter::toStream(
} else {
first = false;
}
- toStream(out, (*i).second, toDepth, types, false);
+ toStream(out, (*i).second, toDepth, false);
out << " := ";
- toStream(out, (*i).first, toDepth, types, false);
+ toStream(out, (*i).first, toDepth, false);
}
out << " IN ";
}
Node body = dv.getDagifiedBody();
- toStream(out, body, toDepth, types);
+ toStream(out, body, toDepth);
if(!lets.empty()) {
out << ')';
}
} else {
- toStream(out, n, toDepth, types);
+ toStream(out, n, toDepth);
}
}
-void AstPrinter::toStream(std::ostream& out,
- TNode n,
- int toDepth,
- bool types) const
+void AstPrinter::toStream(std::ostream& out, TNode n, int toDepth) const
{
// null
if(n.getKind() == kind::NULL_EXPR) {
@@ -88,12 +88,6 @@ void AstPrinter::toStream(std::ostream& out,
} else {
out << "var_" << n.getId();
}
- if(types) {
- // print the whole type, but not *its* type
- out << ":";
- n.getType().toStream(out, language::output::LANG_AST);
- }
-
return;
}
@@ -107,7 +101,7 @@ void AstPrinter::toStream(std::ostream& out,
if(n.getMetaKind() == kind::metakind::PARAMETERIZED) {
out << ' ';
if(toDepth != 0) {
- toStream(out, n.getOperator(), toDepth < 0 ? toDepth : toDepth - 1, types);
+ toStream(out, n.getOperator(), toDepth < 0 ? toDepth : toDepth - 1);
} else {
out << "(...)";
}
@@ -120,7 +114,7 @@ void AstPrinter::toStream(std::ostream& out,
out << ' ';
}
if(toDepth != 0) {
- toStream(out, *i, toDepth < 0 ? toDepth : toDepth - 1, types);
+ toStream(out, *i, toDepth < 0 ? toDepth : toDepth - 1);
} else {
out << "(...)";
}
@@ -132,55 +126,6 @@ void AstPrinter::toStream(std::ostream& out,
template <class T>
static bool tryToStream(std::ostream& out, const Command* c);
-void AstPrinter::toStream(std::ostream& out,
- const Command* c,
- int toDepth,
- bool types,
- size_t dag) const
-{
- expr::ExprSetDepth::Scope sdScope(out, toDepth);
- expr::ExprPrintTypes::Scope ptScope(out, types);
- expr::ExprDag::Scope dagScope(out, dag);
-
- if(tryToStream<EmptyCommand>(out, c) ||
- tryToStream<AssertCommand>(out, c) ||
- tryToStream<PushCommand>(out, c) ||
- tryToStream<PopCommand>(out, c) ||
- tryToStream<CheckSatCommand>(out, c) ||
- tryToStream<CheckSatAssumingCommand>(out, c) ||
- tryToStream<QueryCommand>(out, c) ||
- tryToStream<ResetCommand>(out, c) ||
- tryToStream<ResetAssertionsCommand>(out, c) ||
- tryToStream<QuitCommand>(out, c) ||
- tryToStream<DeclarationSequence>(out, c) ||
- tryToStream<CommandSequence>(out, c) ||
- tryToStream<DeclareFunctionCommand>(out, c) ||
- tryToStream<DeclareTypeCommand>(out, c) ||
- tryToStream<DefineTypeCommand>(out, c) ||
- tryToStream<DefineNamedFunctionCommand>(out, c) ||
- tryToStream<DefineFunctionCommand>(out, c) ||
- tryToStream<SimplifyCommand>(out, c) ||
- tryToStream<GetValueCommand>(out, c) ||
- tryToStream<GetModelCommand>(out, c) ||
- tryToStream<GetAssignmentCommand>(out, c) ||
- tryToStream<GetAssertionsCommand>(out, c) ||
- tryToStream<GetProofCommand>(out, c) ||
- tryToStream<SetBenchmarkStatusCommand>(out, c) ||
- tryToStream<SetBenchmarkLogicCommand>(out, c) ||
- tryToStream<SetInfoCommand>(out, c) ||
- tryToStream<GetInfoCommand>(out, c) ||
- tryToStream<SetOptionCommand>(out, c) ||
- tryToStream<GetOptionCommand>(out, c) ||
- tryToStream<DatatypeDeclarationCommand>(out, c) ||
- tryToStream<CommentCommand>(out, c)) {
- return;
- }
-
- out << "ERROR: don't know how to print a Command of class: "
- << typeid(*c).name() << endl;
-
-}/* AstPrinter::toStream(Command*) */
-
template <class T>
static bool tryToStream(std::ostream& out, const CommandStatus* s);
@@ -198,211 +143,250 @@ void AstPrinter::toStream(std::ostream& out, const CommandStatus* s) const
}/* AstPrinter::toStream(CommandStatus*) */
-void AstPrinter::toStream(std::ostream& out, const Model& m) const
+void AstPrinter::toStream(std::ostream& out, const smt::Model& m) const
{
out << "Model()";
}
void AstPrinter::toStream(std::ostream& out,
- const Model& m,
- const Command* c) const
+ const smt::Model& m,
+ const NodeCommand* c) const
{
// shouldn't be called; only the non-Command* version above should be
Unreachable();
}
-static void toStream(std::ostream& out, const EmptyCommand* c)
+void AstPrinter::toStreamCmdEmpty(std::ostream& out,
+ const std::string& name) const
+{
+ out << "EmptyCommand(" << name << ')' << std::endl;
+}
+
+void AstPrinter::toStreamCmdEcho(std::ostream& out,
+ const std::string& output) const
{
- out << "EmptyCommand(" << c->getName() << ")";
+ out << "EchoCommand(" << output << ')' << std::endl;
}
-static void toStream(std::ostream& out, const AssertCommand* c)
+void AstPrinter::toStreamCmdAssert(std::ostream& out, Node n) const
{
- out << "Assert(" << c->getExpr() << ")";
+ out << "Assert(" << n << ')' << std::endl;
}
-static void toStream(std::ostream& out, const PushCommand* c)
+void AstPrinter::toStreamCmdPush(std::ostream& out) const
{
- out << "Push()";
+ out << "Push()" << std::endl;
}
-static void toStream(std::ostream& out, const PopCommand* c) { out << "Pop()"; }
+void AstPrinter::toStreamCmdPop(std::ostream& out) const {
+ out << "Pop()" << std::endl;
+}
-static void toStream(std::ostream& out, const CheckSatCommand* c)
+void AstPrinter::toStreamCmdCheckSat(std::ostream& out, Node n) const
{
- Expr e = c->getExpr();
- if(e.isNull()) {
+ if (n.isNull())
+ {
out << "CheckSat()";
- } else {
- out << "CheckSat(" << e << ")";
}
+ else
+ {
+ out << "CheckSat(" << n << ')';
+ }
+ out << std::endl;
}
-static void toStream(std::ostream& out, const CheckSatAssumingCommand* c)
+void AstPrinter::toStreamCmdCheckSatAssuming(
+ std::ostream& out, const std::vector<Node>& nodes) const
{
- const vector<Expr>& terms = c->getTerms();
out << "CheckSatAssuming( << ";
- copy(terms.begin(), terms.end(), ostream_iterator<Expr>(out, ", "));
- out << ">> )";
+ copy(nodes.begin(), nodes.end(), ostream_iterator<Node>(out, ", "));
+ out << ">> )" << std::endl;
}
-static void toStream(std::ostream& out, const QueryCommand* c)
+void AstPrinter::toStreamCmdQuery(std::ostream& out, Node n) const
{
- out << "Query(" << c->getExpr() << ')';
+ out << "Query(" << n << ')' << std::endl;
}
-static void toStream(std::ostream& out, const ResetCommand* c)
+void AstPrinter::toStreamCmdReset(std::ostream& out) const
{
- out << "Reset()";
+ out << "Reset()" << std::endl;
}
-static void toStream(std::ostream& out, const ResetAssertionsCommand* c)
+void AstPrinter::toStreamCmdResetAssertions(std::ostream& out) const
{
- out << "ResetAssertions()";
+ out << "ResetAssertions()" << std::endl;
}
-static void toStream(std::ostream& out, const QuitCommand* c)
+void AstPrinter::toStreamCmdQuit(std::ostream& out) const
{
- out << "Quit()";
+ out << "Quit()" << std::endl;
}
-static void toStream(std::ostream& out, const DeclarationSequence* c)
+void AstPrinter::toStreamCmdDeclarationSequence(
+ std::ostream& out, const std::vector<Command*>& sequence) const
{
out << "DeclarationSequence[" << endl;
- for(CommandSequence::const_iterator i = c->begin();
- i != c->end();
- ++i) {
+ for (CommandSequence::const_iterator i = sequence.cbegin();
+ i != sequence.cend();
+ ++i)
+ {
out << *i << endl;
}
- out << "]";
+ out << "]" << std::endl;
}
-static void toStream(std::ostream& out, const CommandSequence* c)
+void AstPrinter::toStreamCmdCommandSequence(
+ std::ostream& out, const std::vector<Command*>& sequence) const
{
out << "CommandSequence[" << endl;
- for(CommandSequence::const_iterator i = c->begin();
- i != c->end();
- ++i) {
+ for (CommandSequence::const_iterator i = sequence.cbegin();
+ i != sequence.cend();
+ ++i)
+ {
out << *i << endl;
}
- out << "]";
+ out << "]" << std::endl;
}
-static void toStream(std::ostream& out, const DeclareFunctionCommand* c)
+void AstPrinter::toStreamCmdDeclareFunction(std::ostream& out,
+ const std::string& id,
+ TypeNode type) const
{
- out << "Declare(" << c->getSymbol() << "," << c->getType() << ")";
+ out << "Declare(" << id << "," << type << ')' << std::endl;
}
-static void toStream(std::ostream& out, const DefineFunctionCommand* c)
+void AstPrinter::toStreamCmdDefineFunction(std::ostream& out,
+ const std::string& id,
+ const std::vector<Node>& formals,
+ TypeNode range,
+ Node formula) const
{
- Expr func = c->getFunction();
- const std::vector<Expr>& formals = c->getFormals();
- Expr formula = c->getFormula();
- out << "DefineFunction( \"" << func << "\", [";
- if(formals.size() > 0) {
- copy( formals.begin(), formals.end() - 1,
- ostream_iterator<Expr>(out, ", ") );
+ out << "DefineFunction( \"" << id << "\", [";
+ if (formals.size() > 0)
+ {
+ copy(formals.begin(), formals.end() - 1, ostream_iterator<Node>(out, ", "));
out << formals.back();
}
- out << "], << " << formula << " >> )";
+ out << "], << " << formula << " >> )" << std::endl;
}
-static void toStream(std::ostream& out, const DeclareTypeCommand* c)
+void AstPrinter::toStreamCmdDeclareType(std::ostream& out,
+ const std::string& id,
+ size_t arity,
+ TypeNode type) const
{
- out << "DeclareType(" << c->getSymbol() << "," << c->getArity() << ","
- << c->getType() << ")";
+ out << "DeclareType(" << id << "," << arity << "," << type << ')'
+ << std::endl;
}
-static void toStream(std::ostream& out, const DefineTypeCommand* c)
+void AstPrinter::toStreamCmdDefineType(std::ostream& out,
+ const std::string& id,
+ const std::vector<TypeNode>& params,
+ TypeNode t) const
{
- const vector<Type>& params = c->getParameters();
- out << "DefineType(" << c->getSymbol() << ",[";
- if(params.size() > 0) {
- copy( params.begin(), params.end() - 1,
- ostream_iterator<Type>(out, ", ") );
+ out << "DefineType(" << id << ",[";
+ if (params.size() > 0)
+ {
+ copy(params.begin(),
+ params.end() - 1,
+ ostream_iterator<TypeNode>(out, ", "));
out << params.back();
}
- out << "]," << c->getType() << ")";
+ out << "]," << t << ')' << std::endl;
}
-static void toStream(std::ostream& out, const DefineNamedFunctionCommand* c)
+void AstPrinter::toStreamCmdSimplify(std::ostream& out, Node n) const
{
- out << "DefineNamedFunction( ";
- toStream(out, static_cast<const DefineFunctionCommand*>(c));
- out << " )";
+ out << "Simplify( << " << n << " >> )" << std::endl;
}
-static void toStream(std::ostream& out, const SimplifyCommand* c)
+void AstPrinter::toStreamCmdGetValue(std::ostream& out,
+ const std::vector<Node>& nodes) const
{
- out << "Simplify( << " << c->getTerm() << " >> )";
+ out << "GetValue( << ";
+ copy(nodes.begin(), nodes.end(), ostream_iterator<Node>(out, ", "));
+ out << ">> )" << std::endl;
}
-static void toStream(std::ostream& out, const GetValueCommand* c)
+void AstPrinter::toStreamCmdGetModel(std::ostream& out) const
{
- out << "GetValue( << ";
- const vector<Expr>& terms = c->getTerms();
- copy(terms.begin(), terms.end(), ostream_iterator<Expr>(out, ", "));
- out << ">> )";
+ out << "GetModel()" << std::endl;
}
-static void toStream(std::ostream& out, const GetModelCommand* c)
+void AstPrinter::toStreamCmdGetAssignment(std::ostream& out) const
{
- out << "GetModel()";
+ out << "GetAssignment()" << std::endl;
}
-static void toStream(std::ostream& out, const GetAssignmentCommand* c)
+void AstPrinter::toStreamCmdGetAssertions(std::ostream& out) const
{
- out << "GetAssignment()";
+ out << "GetAssertions()" << std::endl;
}
-static void toStream(std::ostream& out, const GetAssertionsCommand* c)
+
+void AstPrinter::toStreamCmdGetProof(std::ostream& out) const
{
- out << "GetAssertions()";
+ out << "GetProof()" << std::endl;
}
-static void toStream(std::ostream& out, const GetProofCommand* c)
+
+void AstPrinter::toStreamCmdGetUnsatCore(std::ostream& out) const
{
- out << "GetProof()";
+ out << "GetUnsatCore()" << std::endl;
}
-static void toStream(std::ostream& out, const SetBenchmarkStatusCommand* c)
+
+void AstPrinter::toStreamCmdSetBenchmarkStatus(std::ostream& out,
+ Result::Sat status) const
{
- out << "SetBenchmarkStatus(" << c->getStatus() << ")";
+ out << "SetBenchmarkStatus(" << status << ')' << std::endl;
}
-static void toStream(std::ostream& out, const SetBenchmarkLogicCommand* c)
+
+void AstPrinter::toStreamCmdSetBenchmarkLogic(std::ostream& out,
+ const std::string& logic) const
{
- out << "SetBenchmarkLogic(" << c->getLogic() << ")";
+ out << "SetBenchmarkLogic(" << logic << ')' << std::endl;
}
-static void toStream(std::ostream& out, const SetInfoCommand* c)
+
+void AstPrinter::toStreamCmdSetInfo(std::ostream& out,
+ const std::string& flag,
+ SExpr sexpr) const
{
- out << "SetInfo(" << c->getFlag() << ", " << c->getSExpr() << ")";
+ out << "SetInfo(" << flag << ", " << sexpr << ')' << std::endl;
}
-static void toStream(std::ostream& out, const GetInfoCommand* c)
+void AstPrinter::toStreamCmdGetInfo(std::ostream& out,
+ const std::string& flag) const
{
- out << "GetInfo(" << c->getFlag() << ")";
+ out << "GetInfo(" << flag << ')' << std::endl;
}
-static void toStream(std::ostream& out, const SetOptionCommand* c)
+
+void AstPrinter::toStreamCmdSetOption(std::ostream& out,
+ const std::string& flag,
+ SExpr sexpr) const
{
- out << "SetOption(" << c->getFlag() << ", " << c->getSExpr() << ")";
+ out << "SetOption(" << flag << ", " << sexpr << ')' << std::endl;
}
-static void toStream(std::ostream& out, const GetOptionCommand* c)
+void AstPrinter::toStreamCmdGetOption(std::ostream& out,
+ const std::string& flag) const
{
- out << "GetOption(" << c->getFlag() << ")";
+ out << "GetOption(" << flag << ')' << std::endl;
}
-static void toStream(std::ostream& out, const DatatypeDeclarationCommand* c)
+void AstPrinter::toStreamCmdDatatypeDeclaration(
+ std::ostream& out, const std::vector<TypeNode>& datatypes) const
{
- const vector<Type>& datatypes = c->getDatatypes();
out << "DatatypeDeclarationCommand([";
- for (const Type& t : datatypes)
+ for (const TypeNode& t : datatypes)
{
out << t << ";" << endl;
}
- out << "])";
+ out << "])" << std::endl;
}
-static void toStream(std::ostream& out, const CommentCommand* c)
+void AstPrinter::toStreamCmdComment(std::ostream& out,
+ const std::string& comment) const
{
- out << "CommentCommand([" << c->getComment() << "])";
+ out << "CommentCommand([" << comment << "])" << std::endl;
}
template <class T>
diff --git a/src/printer/ast/ast_printer.h b/src/printer/ast/ast_printer.h
index 2fd7da749..ad20ffb79 100644
--- a/src/printer/ast/ast_printer.h
+++ b/src/printer/ast/ast_printer.h
@@ -2,10 +2,10 @@
/*! \file ast_printer.h
** \verbatim
** Top contributors (to current version):
- ** Tim King, Morgan Deters, Mathias Preiner
+ ** Abdalrhman Mohamed, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -27,31 +27,151 @@ namespace CVC4 {
namespace printer {
namespace ast {
-class AstPrinter : public CVC4::Printer {
+class AstPrinter : public CVC4::Printer
+{
public:
using CVC4::Printer::toStream;
void toStream(std::ostream& out,
TNode n,
int toDepth,
- bool types,
- size_t dag) const override;
- void toStream(std::ostream& out,
- const Command* c,
- int toDepth,
- bool types,
size_t dag) const override;
void toStream(std::ostream& out, const CommandStatus* s) const override;
- void toStream(std::ostream& out, const Model& m) const override;
+ void toStream(std::ostream& out, const smt::Model& m) const override;
+
+ /** Print empty command */
+ void toStreamCmdEmpty(std::ostream& out,
+ const std::string& name) const override;
+
+ /** Print echo command */
+ void toStreamCmdEcho(std::ostream& out,
+ const std::string& output) const override;
+
+ /** Print assert command */
+ void toStreamCmdAssert(std::ostream& out, Node n) const override;
+
+ /** Print push command */
+ void toStreamCmdPush(std::ostream& out) const override;
+
+ /** Print pop command */
+ void toStreamCmdPop(std::ostream& out) const override;
+
+ /** Print declare-fun command */
+ void toStreamCmdDeclareFunction(std::ostream& out,
+ const std::string& id,
+ TypeNode type) const override;
+
+ /** Print declare-sort command */
+ void toStreamCmdDeclareType(std::ostream& out,
+ const std::string& id,
+ size_t arity,
+ TypeNode type) const override;
+
+ /** Print define-sort command */
+ void toStreamCmdDefineType(std::ostream& out,
+ const std::string& id,
+ const std::vector<TypeNode>& params,
+ TypeNode t) const override;
+
+ /** Print define-fun command */
+ void toStreamCmdDefineFunction(std::ostream& out,
+ const std::string& id,
+ const std::vector<Node>& formals,
+ TypeNode range,
+ Node formula) const override;
+
+ /** Print check-sat command */
+ void toStreamCmdCheckSat(std::ostream& out,
+ Node n = Node::null()) const override;
+
+ /** Print check-sat-assuming command */
+ void toStreamCmdCheckSatAssuming(
+ std::ostream& out, const std::vector<Node>& nodes) const override;
+
+ /** Print query command */
+ void toStreamCmdQuery(std::ostream& out, Node n) const override;
+
+ /** Print simplify command */
+ void toStreamCmdSimplify(std::ostream& out, Node nodes) const override;
+
+ /** Print get-value command */
+ void toStreamCmdGetValue(std::ostream& out,
+ const std::vector<Node>& n) const override;
+
+ /** Print get-assignment command */
+ void toStreamCmdGetAssignment(std::ostream& out) const override;
+
+ /** Print get-model command */
+ void toStreamCmdGetModel(std::ostream& out) const override;
+
+ /** Print get-proof command */
+ void toStreamCmdGetProof(std::ostream& out) const override;
+
+ /** Print get-unsat-core command */
+ void toStreamCmdGetUnsatCore(std::ostream& out) const override;
+
+ /** Print get-assertions command */
+ void toStreamCmdGetAssertions(std::ostream& out) const override;
+
+ /** Print set-info :status command */
+ void toStreamCmdSetBenchmarkStatus(std::ostream& out,
+ Result::Sat status) const override;
+
+ /** Print set-logic command */
+ void toStreamCmdSetBenchmarkLogic(std::ostream& out,
+ const std::string& logic) const override;
+
+ /** Print set-info command */
+ void toStreamCmdSetInfo(std::ostream& out,
+ const std::string& flag,
+ SExpr sexpr) const override;
+
+ /** Print get-info command */
+ void toStreamCmdGetInfo(std::ostream& out,
+ const std::string& flag) const override;
+
+ /** Print set-option command */
+ void toStreamCmdSetOption(std::ostream& out,
+ const std::string& flag,
+ SExpr sexpr) const override;
+
+ /** Print get-option command */
+ void toStreamCmdGetOption(std::ostream& out,
+ const std::string& flag) const override;
+
+ /** Print declare-datatype(s) command */
+ void toStreamCmdDatatypeDeclaration(
+ std::ostream& out, const std::vector<TypeNode>& datatypes) const override;
+
+ /** Print reset command */
+ void toStreamCmdReset(std::ostream& out) const override;
+
+ /** Print reset-assertions command */
+ void toStreamCmdResetAssertions(std::ostream& out) const override;
+
+ /** Print quit command */
+ void toStreamCmdQuit(std::ostream& out) const override;
+
+ /** Print comment command */
+ void toStreamCmdComment(std::ostream& out,
+ const std::string& comment) const override;
+
+ /** Print command sequence command */
+ void toStreamCmdCommandSequence(
+ std::ostream& out, const std::vector<Command*>& sequence) const override;
+
+ /** Print declaration sequence command */
+ void toStreamCmdDeclarationSequence(
+ std::ostream& out, const std::vector<Command*>& sequence) const override;
private:
- void toStream(std::ostream& out, TNode n, int toDepth, bool types) const;
+ void toStream(std::ostream& out, TNode n, int toDepth) const;
void toStream(std::ostream& out,
- const Model& m,
- const Command* c) const override;
-};/* class AstPrinter */
+ const smt::Model& m,
+ const NodeCommand* c) const override;
+}; /* class AstPrinter */
-}/* CVC4::printer::ast namespace */
-}/* CVC4::printer namespace */
-}/* CVC4 namespace */
+} // namespace ast
+} // namespace printer
+} // namespace CVC4
#endif /* CVC4__PRINTER__AST_PRINTER_H */
diff --git a/src/printer/cvc/cvc_printer.cpp b/src/printer/cvc/cvc_printer.cpp
index 900651e1d..44ff7be10 100644
--- a/src/printer/cvc/cvc_printer.cpp
+++ b/src/printer/cvc/cvc_printer.cpp
@@ -2,10 +2,10 @@
/*! \file cvc_printer.cpp
** \verbatim
** Top contributors (to current version):
- ** Morgan Deters, Dejan Jovanovic, Tim King
+ ** Morgan Deters, Dejan Jovanovic, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -33,6 +33,7 @@
#include "options/smt_options.h"
#include "printer/dagification_visitor.h"
#include "smt/command.h"
+#include "smt/node_command.h"
#include "smt/smt_engine.h"
#include "theory/arrays/theory_arrays_rewriter.h"
#include "theory/substitutions.h"
@@ -44,8 +45,10 @@ namespace CVC4 {
namespace printer {
namespace cvc {
-void CvcPrinter::toStream(
- std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const
+void CvcPrinter::toStream(std::ostream& out,
+ TNode n,
+ int toDepth,
+ size_t dag) const
{
if(dag != 0) {
DagificationVisitor dv(dag);
@@ -63,16 +66,16 @@ void CvcPrinter::toStream(
} else {
first = false;
}
- toStream(out, (*i).second, toDepth, types, false);
+ toStream(out, (*i).second, toDepth, false);
out << " = ";
- toStream(out, (*i).first, toDepth, types, false);
+ toStream(out, (*i).first, toDepth, false);
}
out << " IN ";
}
Node body = dv.getDagifiedBody();
- toStream(out, body, toDepth, types, false);
+ toStream(out, body, toDepth, false);
} else {
- toStream(out, n, toDepth, types, false);
+ toStream(out, n, toDepth, false);
}
}
@@ -90,8 +93,10 @@ void toStreamRational(std::ostream& out, Node n, bool forceRational)
}
}
-void CvcPrinter::toStream(
- std::ostream& out, TNode n, int depth, bool types, bool bracket) const
+void CvcPrinter::toStream(std::ostream& out,
+ TNode n,
+ int depth,
+ bool bracket) const
{
if (depth == 0) {
out << "(...)";
@@ -118,11 +123,6 @@ void CvcPrinter::toStream(
}
out << n.getId();
}
- if(types) {
- // print the whole type, but not *its* type
- out << ":";
- n.getType().toStream(out, language::output::LANG_CVC4);
- }
return;
}
if(n.isNullaryOp()) {
@@ -211,26 +211,27 @@ void CvcPrinter::toStream(
break;
case kind::DATATYPE_TYPE: {
- const Datatype& dt =
- NodeManager::currentNM()->toExprManager()->getDatatypeForIndex(
- n.getConst<DatatypeIndexConstant>().getIndex());
+ const DType& dt = NodeManager::currentNM()->getDTypeForIndex(
+ n.getConst<DatatypeIndexConstant>().getIndex());
if( dt.isTuple() ){
out << '[';
for (unsigned i = 0; i < dt[0].getNumArgs(); ++ i) {
if (i > 0) {
out << ", ";
}
- Type t = ((SelectorType)dt[0][i].getSelector().getType()).getRangeType();
+ TypeNode t = dt[0][i].getRangeType();
out << t;
}
out << ']';
- }else if( dt.isRecord() ){
+ }
+ else if (dt.isRecord())
+ {
out << "[# ";
for (unsigned i = 0; i < dt[0].getNumArgs(); ++ i) {
if (i > 0) {
out << ", ";
}
- Type t = ((SelectorType)dt[0][i].getSelector().getType()).getRangeType();
+ TypeNode t = dt[0][i].getRangeType();
out << dt[0][i].getSelector() << ":" << t;
}
out << " #]";
@@ -285,11 +286,11 @@ void CvcPrinter::toStream(
break;
case kind::ITE:
out << "IF ";
- toStream(out, n[0], depth, types, true);
+ toStream(out, n[0], depth, true);
out << " THEN ";
- toStream(out, n[1], depth, types, true);
+ toStream(out, n[1], depth, true);
out << " ELSE ";
- toStream(out, n[2], depth, types, true);
+ toStream(out, n[2], depth, true);
out << " ENDIF";
return;
break;
@@ -299,7 +300,7 @@ void CvcPrinter::toStream(
if (i > 0) {
out << ", ";
}
- toStream(out, n[i], depth, types, false);
+ toStream(out, n[i], depth, false);
}
out << ']';
return;
@@ -309,15 +310,22 @@ void CvcPrinter::toStream(
break;
case kind::LAMBDA:
out << "(LAMBDA";
- toStream(out, n[0], depth, types, true);
+ toStream(out, n[0], depth, true);
out << ": ";
- toStream(out, n[1], depth, types, true);
+ toStream(out, n[1], depth, true);
out << ")";
return;
break;
+ case kind::WITNESS:
+ out << "(WITNESS";
+ toStream(out, n[0], depth, false);
+ out << " : ";
+ toStream(out, n[1], depth, false);
+ out << ')';
+ return;
case kind::DISTINCT:
// distinct not supported directly, blast it away with the rewriter
- toStream(out, theory::Rewriter::rewrite(n), depth, types, true);
+ toStream(out, theory::Rewriter::rewrite(n), depth, true);
return;
case kind::SORT_TYPE:
{
@@ -352,9 +360,7 @@ void CvcPrinter::toStream(
break;
// UF
- case kind::APPLY_UF:
- toStream(op, n.getOperator(), depth, types, false);
- break;
+ case kind::APPLY_UF: toStream(op, n.getOperator(), depth, false); break;
case kind::CARDINALITY_CONSTRAINT:
case kind::COMBINED_CARDINALITY_CONSTRAINT:
out << "CARDINALITY_CONSTRAINT";
@@ -369,14 +375,14 @@ void CvcPrinter::toStream(
if (i > 1) {
out << ", ";
}
- toStream(out, n[i - 1], depth, types, false);
+ toStream(out, n[i - 1], depth, false);
}
if (n.getNumChildren() > 2) {
out << ')';
}
}
out << " -> ";
- toStream(out, n[n.getNumChildren() - 1], depth, types, false);
+ toStream(out, n[n.getNumChildren() - 1], depth, false);
return;
break;
@@ -398,10 +404,10 @@ void CvcPrinter::toStream(
return;
break;
case kind::APPLY_TYPE_ASCRIPTION: {
- toStream(out, n[0], depth, types, false);
- out << "::";
- TypeNode t = TypeNode::fromType(n.getOperator().getConst<AscriptionType>().getType());
- out << (t.isFunctionLike() ? t.getRangeType() : t);
+ toStream(out, n[0], depth, false);
+ out << "::";
+ TypeNode t = n.getOperator().getConst<AscriptionType>().getType();
+ out << (t.isFunctionLike() ? t.getRangeType() : t);
}
return;
break;
@@ -414,25 +420,24 @@ void CvcPrinter::toStream(
}
else if (t.toType().isRecord())
{
- const Record& rec = static_cast<DatatypeType>(t.toType()).getRecord();
+ const DType& dt = t.getDType();
+ const DTypeConstructor& recCons = dt[0];
out << "(# ";
- TNode::iterator i = n.begin();
- bool first = true;
- const Record::FieldVector& fields = rec.getFields();
- for(Record::FieldVector::const_iterator j = fields.begin(); j != fields.end(); ++i, ++j) {
- if(!first) {
+ for (size_t i = 0, nargs = recCons.getNumArgs(); i < nargs; i++)
+ {
+ if (i != 0)
+ {
out << ", ";
}
- out << (*j).first << " := ";
- toStream(out, *i, depth, types, false);
- first = false;
+ out << recCons[i].getName() << " := ";
+ toStream(out, n[i], depth, false);
}
out << " #)";
return;
}
else
{
- toStream(op, n.getOperator(), depth, types, false);
+ toStream(op, n.getOperator(), depth, false);
if (n.getNumChildren() == 0)
{
// for datatype constants d, we print "d" and not "d()"
@@ -448,20 +453,19 @@ void CvcPrinter::toStream(
Node opn = n.getOperator();
if (!t.isDatatype())
{
- toStream(op, opn, depth, types, false);
+ toStream(op, opn, depth, false);
}
- else if (t.isTuple()
- || DatatypeType(t.toType()).isRecord())
+ else if (t.isTuple() || t.isRecord())
{
- toStream(out, n[0], depth, types, true);
+ toStream(out, n[0], depth, true);
out << '.';
- const Datatype& dt = ((DatatypeType)t.toType()).getDatatype();
+ const DType& dt = t.getDType();
if (t.isTuple())
{
int sindex;
if (n.getKind() == kind::APPLY_SELECTOR)
{
- sindex = Datatype::indexOf(opn.toExpr());
+ sindex = DType::indexOf(opn.toExpr());
}
else
{
@@ -472,20 +476,20 @@ void CvcPrinter::toStream(
}
else
{
- toStream(out, opn, depth, types, false);
+ toStream(out, opn, depth, false);
}
return;
}else{
- toStream(op, opn, depth, types, false);
+ toStream(op, opn, depth, false);
}
}
break;
case kind::APPLY_TESTER: {
Assert(!n.getType().isTuple() && !n.getType().toType().isRecord());
op << "is_";
- unsigned cindex = Datatype::indexOf(n.getOperator().toExpr());
- const Datatype& dt = Datatype::datatypeOf(n.getOperator().toExpr());
- toStream(op, Node::fromExpr(dt[cindex].getConstructor()), depth, types, false);
+ unsigned cindex = DType::indexOf(n.getOperator());
+ const DType& dt = DType::datatypeOf(n.getOperator());
+ toStream(op, dt[cindex].getConstructor(), depth, false);
}
break;
case kind::CONSTRUCTOR_TYPE:
@@ -498,45 +502,45 @@ void CvcPrinter::toStream(
if(i > 0) {
out << ", ";
}
- toStream(out, n[i], depth, types, false);
+ toStream(out, n[i], depth, false);
}
if(n.getNumChildren() > 2) {
out << ')';
}
out << " -> ";
}
- toStream(out, n[n.getNumChildren() - 1], depth, types, false);
+ toStream(out, n[n.getNumChildren() - 1], depth, false);
return;
case kind::TESTER_TYPE:
- toStream(out, n[0], depth, types, false);
+ toStream(out, n[0], depth, false);
out << " -> BOOLEAN";
return;
break;
case kind::TUPLE_UPDATE:
- toStream(out, n[0], depth, types, true);
+ toStream(out, n[0], depth, true);
out << " WITH ." << n.getOperator().getConst<TupleUpdate>().getIndex() << " := ";
- toStream(out, n[1], depth, types, true);
+ toStream(out, n[1], depth, true);
return;
break;
case kind::RECORD_UPDATE:
- toStream(out, n[0], depth, types, true);
+ toStream(out, n[0], depth, true);
out << " WITH ." << n.getOperator().getConst<RecordUpdate>().getField() << " := ";
- toStream(out, n[1], depth, types, true);
+ toStream(out, n[1], depth, true);
return;
break;
// ARRAYS
case kind::ARRAY_TYPE:
out << "ARRAY ";
- toStream(out, n[0], depth, types, false);
+ toStream(out, n[0], depth, false);
out << " OF ";
- toStream(out, n[1], depth, types, false);
+ toStream(out, n[1], depth, false);
return;
break;
case kind::SELECT:
- toStream(out, n[0], depth, types, true);
+ toStream(out, n[0], depth, true);
out << '[';
- toStream(out, n[1], depth, types, false);
+ toStream(out, n[1], depth, false);
out << ']';
return;
break;
@@ -550,18 +554,18 @@ void CvcPrinter::toStream(
out << '(';
}
TNode x = stk.top();
- toStream(out, x[0], depth, types, false);
+ toStream(out, x[0], depth, false);
out << " WITH [";
- toStream(out, x[1], depth, types, false);
+ toStream(out, x[1], depth, false);
out << "] := ";
- toStream(out, x[2], depth, types, false);
+ toStream(out, x[2], depth, false);
stk.pop();
while(!stk.empty()) {
x = stk.top();
out << ", [";
- toStream(out, x[1], depth, types, false);
+ toStream(out, x[1], depth, false);
out << "] := ";
- toStream(out, x[2], depth, types, false);
+ toStream(out, x[2], depth, false);
stk.pop();
}
if (bracket) {
@@ -637,6 +641,8 @@ void CvcPrinter::toStream(
opType = PREFIX;
break;
case kind::TO_REAL:
+ case kind::CAST_TO_REAL:
+ {
if (n[0].getKind() == kind::CONST_RATIONAL)
{
// print the constant as a rational
@@ -645,12 +651,13 @@ void CvcPrinter::toStream(
else
{
// ignore, there is no to-real in CVC language
- toStream(out, n[0], depth, types, false);
+ toStream(out, n[0], depth, false);
}
return;
+ }
case kind::DIVISIBLE:
out << "DIVISIBLE(";
- toStream(out, n[0], depth, types, false);
+ toStream(out, n[0], depth, false);
out << ", " << n.getOperator().getConst<Divisible>().k << ")";
return;
@@ -751,16 +758,16 @@ void CvcPrinter::toStream(
out << "BVPLUS(";
out << BitVectorType(n.getType().toType()).getSize();
out << ',';
- toStream(out, n[child], depth, types, false);
+ toStream(out, n[child], depth, false);
out << ',';
++child;
}
out << "BVPLUS(";
out << BitVectorType(n.getType().toType()).getSize();
out << ',';
- toStream(out, n[child], depth, types, false);
+ toStream(out, n[child], depth, false);
out << ',';
- toStream(out, n[child + 1], depth, types, false);
+ toStream(out, n[child + 1], depth, false);
while (child > 0) {
out << ')';
--child;
@@ -774,9 +781,9 @@ void CvcPrinter::toStream(
Assert(n.getType().isBitVector());
out << BitVectorType(n.getType().toType()).getSize();
out << ',';
- toStream(out, n[0], depth, types, false);
+ toStream(out, n[0], depth, false);
out << ',';
- toStream(out, n[1], depth, types, false);
+ toStream(out, n[1], depth, false);
out << ')';
return;
break;
@@ -788,16 +795,16 @@ void CvcPrinter::toStream(
out << "BVMULT(";
out << BitVectorType(n.getType().toType()).getSize();
out << ',';
- toStream(out, n[child], depth, types, false);
+ toStream(out, n[child], depth, false);
out << ',';
++child;
}
out << "BVMULT(";
out << BitVectorType(n.getType().toType()).getSize();
out << ',';
- toStream(out, n[child], depth, types, false);
+ toStream(out, n[child], depth, false);
out << ',';
- toStream(out, n[child + 1], depth, types, false);
+ toStream(out, n[child + 1], depth, false);
while (child > 0) {
out << ')';
--child;
@@ -816,31 +823,31 @@ void CvcPrinter::toStream(
break;
case kind::BITVECTOR_REPEAT:
out << "BVREPEAT(";
- toStream(out, n[0], depth, types, false);
+ toStream(out, n[0], depth, false);
out << ", " << n.getOperator().getConst<BitVectorRepeat>() << ')';
return;
break;
case kind::BITVECTOR_ZERO_EXTEND:
out << "BVZEROEXTEND(";
- toStream(out, n[0], depth, types, false);
+ toStream(out, n[0], depth, false);
out << ", " << n.getOperator().getConst<BitVectorZeroExtend>() << ')';
return;
break;
case kind::BITVECTOR_SIGN_EXTEND:
out << "SX(";
- toStream(out, n[0], depth, types, false);
+ toStream(out, n[0], depth, false);
out << ", " << BitVectorType(n.getType().toType()).getSize() << ')';
return;
break;
case kind::BITVECTOR_ROTATE_LEFT:
out << "BVROTL(";
- toStream(out, n[0], depth, types, false);
+ toStream(out, n[0], depth, false);
out << ", " << n.getOperator().getConst<BitVectorRotateLeft>() << ')';
return;
break;
case kind::BITVECTOR_ROTATE_RIGHT:
out << "BVROTR(";
- toStream(out, n[0], depth, types, false);
+ toStream(out, n[0], depth, false);
out << ", " << n.getOperator().getConst<BitVectorRotateRight>() << ')';
return;
break;
@@ -848,7 +855,7 @@ void CvcPrinter::toStream(
// SETS
case kind::SET_TYPE:
out << "SET OF ";
- toStream(out, n[0], depth, types, false);
+ toStream(out, n[0], depth, false);
return;
break;
case kind::UNION:
@@ -901,7 +908,7 @@ void CvcPrinter::toStream(
break;
case kind::SINGLETON:
out << "{";
- toStream(out, n[0], depth, types, false);
+ toStream(out, n[0], depth, false);
out << "}";
return;
break;
@@ -911,13 +918,13 @@ void CvcPrinter::toStream(
}
out << '{';
size_t i = 0;
- toStream(out, n[i++], depth, types, false);
+ toStream(out, n[i++], depth, false);
for(;i+1 < n.getNumChildren(); ++i) {
out << ", ";
- toStream(out, n[i], depth, types, false);
+ toStream(out, n[i], depth, false);
}
out << "} | ";
- toStream(out, n[i], depth, types, true);
+ toStream(out, n[i], depth, true);
if(bracket) {
out << ')';
}
@@ -926,7 +933,7 @@ void CvcPrinter::toStream(
}
case kind::CARD: {
out << "CARD(";
- toStream(out, n[0], depth, types, false);
+ toStream(out, n[0], depth, false);
out << ")";
return;
break;
@@ -935,17 +942,17 @@ void CvcPrinter::toStream(
// Quantifiers
case kind::FORALL:
out << "(FORALL";
- toStream(out, n[0], depth, types, false);
+ toStream(out, n[0], depth, false);
out << " : ";
- toStream(out, n[1], depth, types, false);
+ toStream(out, n[1], depth, false);
out << ')';
// TODO: user patterns?
return;
case kind::EXISTS:
out << "(EXISTS";
- toStream(out, n[0], depth, types, false);
+ toStream(out, n[0], depth, false);
out << " : ";
- toStream(out, n[1], depth, types, false);
+ toStream(out, n[1], depth, false);
out << ')';
// TODO: user patterns?
return;
@@ -958,7 +965,9 @@ void CvcPrinter::toStream(
if(i > 0) {
out << ", ";
}
- toStream(out, n[i], -1, true, false); // ascribe types
+ toStream(out, n[i], -1, false);
+ out << ":";
+ n[i].getType().toStream(out, language::output::LANG_CVC4);
}
out << ')';
return;
@@ -1012,7 +1021,7 @@ void CvcPrinter::toStream(
out << ", ";
}
}
- toStream(out, n[i], depth, types, opType == INFIX);
+ toStream(out, n[i], depth, opType == INFIX);
}
switch (opType) {
@@ -1037,57 +1046,6 @@ void CvcPrinter::toStream(
template <class T>
static bool tryToStream(std::ostream& out, const Command* c, bool cvc3Mode);
-void CvcPrinter::toStream(std::ostream& out,
- const Command* c,
- int toDepth,
- bool types,
- size_t dag) const
-{
- expr::ExprSetDepth::Scope sdScope(out, toDepth);
- expr::ExprPrintTypes::Scope ptScope(out, types);
- expr::ExprDag::Scope dagScope(out, dag);
-
- if(tryToStream<AssertCommand>(out, c, d_cvc3Mode) ||
- tryToStream<PushCommand>(out, c, d_cvc3Mode) ||
- tryToStream<PopCommand>(out, c, d_cvc3Mode) ||
- tryToStream<CheckSatCommand>(out, c, d_cvc3Mode) ||
- tryToStream<CheckSatAssumingCommand>(out, c, d_cvc3Mode) ||
- tryToStream<QueryCommand>(out, c, d_cvc3Mode) ||
- tryToStream<ResetCommand>(out, c, d_cvc3Mode) ||
- tryToStream<ResetAssertionsCommand>(out, c, d_cvc3Mode) ||
- tryToStream<QuitCommand>(out, c, d_cvc3Mode) ||
- tryToStream<DeclarationSequence>(out, c, d_cvc3Mode) ||
- tryToStream<CommandSequence>(out, c, d_cvc3Mode) ||
- tryToStream<DeclareFunctionCommand>(out, c, d_cvc3Mode) ||
- tryToStream<DeclareTypeCommand>(out, c, d_cvc3Mode) ||
- tryToStream<DefineTypeCommand>(out, c, d_cvc3Mode) ||
- tryToStream<DefineNamedFunctionCommand>(out, c, d_cvc3Mode) ||
- tryToStream<DefineFunctionCommand>(out, c, d_cvc3Mode) ||
- tryToStream<SimplifyCommand>(out, c, d_cvc3Mode) ||
- tryToStream<GetValueCommand>(out, c, d_cvc3Mode) ||
- tryToStream<GetModelCommand>(out, c, d_cvc3Mode) ||
- tryToStream<GetAssignmentCommand>(out, c, d_cvc3Mode) ||
- tryToStream<GetAssertionsCommand>(out, c, d_cvc3Mode) ||
- tryToStream<GetProofCommand>(out, c, d_cvc3Mode) ||
- tryToStream<GetUnsatCoreCommand>(out, c, d_cvc3Mode) ||
- tryToStream<SetBenchmarkStatusCommand>(out, c, d_cvc3Mode) ||
- tryToStream<SetBenchmarkLogicCommand>(out, c, d_cvc3Mode) ||
- tryToStream<SetInfoCommand>(out, c, d_cvc3Mode) ||
- tryToStream<GetInfoCommand>(out, c, d_cvc3Mode) ||
- tryToStream<SetOptionCommand>(out, c, d_cvc3Mode) ||
- tryToStream<GetOptionCommand>(out, c, d_cvc3Mode) ||
- tryToStream<DatatypeDeclarationCommand>(out, c, d_cvc3Mode) ||
- tryToStream<CommentCommand>(out, c, d_cvc3Mode) ||
- tryToStream<EmptyCommand>(out, c, d_cvc3Mode) ||
- tryToStream<EchoCommand>(out, c, d_cvc3Mode)) {
- return;
- }
-
- out << "ERROR: don't know how to print a Command of class: "
- << typeid(*c).name() << endl;
-
-}/* CvcPrinter::toStream(Command*) */
-
template <class T>
static bool tryToStream(std::ostream& out,
const CommandStatus* s,
@@ -1111,15 +1069,15 @@ void CvcPrinter::toStream(std::ostream& out, const CommandStatus* s) const
namespace {
-void DeclareTypeCommandToStream(std::ostream& out,
- const theory::TheoryModel& model,
- const DeclareTypeCommand& command)
+void DeclareTypeNodeCommandToStream(std::ostream& out,
+ const theory::TheoryModel& model,
+ const DeclareTypeNodeCommand& command)
{
- TypeNode type_node = TypeNode::fromType(command.getType());
+ TypeNode type_node = command.getType();
const std::vector<Node>* type_reps =
model.getRepSet()->getTypeRepsOrNull(type_node);
- if (options::modelUninterpDtEnum() && type_node.isSort()
- && type_reps != nullptr)
+ if (options::modelUninterpPrint() == options::ModelUninterpPrintMode::DtEnum
+ && type_node.isSort() && type_reps != nullptr)
{
out << "DATATYPE" << std::endl;
out << " " << command.getSymbol() << " = ";
@@ -1156,11 +1114,12 @@ void DeclareTypeCommandToStream(std::ostream& out,
}
}
-void DeclareFunctionCommandToStream(std::ostream& out,
- const theory::TheoryModel& model,
- const DeclareFunctionCommand& command)
+void DeclareFunctionNodeCommandToStream(
+ std::ostream& out,
+ const theory::TheoryModel& model,
+ const DeclareFunctionNodeCommand& command)
{
- Node n = Node::fromExpr(command.getFunction());
+ Node n = command.getFunction();
if (n.getKind() == kind::SKOLEM)
{
// don't print out internal stuff
@@ -1185,8 +1144,11 @@ void DeclareFunctionCommandToStream(std::ostream& out,
{
out << tn;
}
- Node val = Node::fromExpr(model.getSmtEngine()->getValue(n.toExpr()));
- if (options::modelUninterpDtEnum() && val.getKind() == kind::STORE)
+ // We get the value from the theory model directly, which notice
+ // does not have to go through the standard SmtEngine::getValue interface.
+ Node val = model.getValue(n);
+ if (options::modelUninterpPrint() == options::ModelUninterpPrintMode::DtEnum
+ && val.getKind() == kind::STORE)
{
TypeNode type_node = val[1].getType();
if (tn.isSort())
@@ -1205,11 +1167,12 @@ void DeclareFunctionCommandToStream(std::ostream& out,
} // namespace
-void CvcPrinter::toStream(std::ostream& out, const Model& m) const
+void CvcPrinter::toStream(std::ostream& out, const smt::Model& m) const
{
+ const theory::TheoryModel* tm = m.getTheoryModel();
// print the model comments
std::stringstream c;
- m.getComments(c);
+ tm->getComments(c);
std::string ln;
while (std::getline(c, ln))
{
@@ -1223,315 +1186,340 @@ void CvcPrinter::toStream(std::ostream& out, const Model& m) const
}
void CvcPrinter::toStream(std::ostream& out,
- const Model& model,
- const Command* command) const
+ const smt::Model& model,
+ const NodeCommand* command) const
{
- const auto* theory_model = dynamic_cast<const theory::TheoryModel*>(&model);
+ const auto* theory_model = model.getTheoryModel();
AlwaysAssert(theory_model != nullptr);
if (const auto* declare_type_command =
- dynamic_cast<const DeclareTypeCommand*>(command))
+ dynamic_cast<const DeclareTypeNodeCommand*>(command))
{
- DeclareTypeCommandToStream(out, *theory_model, *declare_type_command);
+ DeclareTypeNodeCommandToStream(out, *theory_model, *declare_type_command);
}
else if (const auto* dfc =
- dynamic_cast<const DeclareFunctionCommand*>(command))
+ dynamic_cast<const DeclareFunctionNodeCommand*>(command))
{
- DeclareFunctionCommandToStream(out, *theory_model, *dfc);
+ DeclareFunctionNodeCommandToStream(out, *theory_model, *dfc);
}
else
{
- out << command << std::endl;
+ out << *command << std::endl;
}
}
-static void toStream(std::ostream& out, const AssertCommand* c, bool cvc3Mode)
+void CvcPrinter::toStreamCmdAssert(std::ostream& out, Node n) const
{
- out << "ASSERT " << c->getExpr() << ";";
+ out << "ASSERT " << n << ';' << std::endl;
}
-static void toStream(std::ostream& out, const PushCommand* c, bool cvc3Mode)
+void CvcPrinter::toStreamCmdPush(std::ostream& out) const
{
- out << "PUSH;";
+ out << "PUSH;" << std::endl;
}
-static void toStream(std::ostream& out, const PopCommand* c, bool cvc3Mode)
+void CvcPrinter::toStreamCmdPop(std::ostream& out) const
{
- out << "POP;";
+ out << "POP;" << std::endl;
}
-static void toStream(std::ostream& out, const CheckSatCommand* c, bool cvc3Mode)
+void CvcPrinter::toStreamCmdCheckSat(std::ostream& out, Node n) const
{
- Expr e = c->getExpr();
- if(cvc3Mode) {
+ if (d_cvc3Mode)
+ {
out << "PUSH; ";
}
- if(!e.isNull()) {
- out << "CHECKSAT " << e << ";";
- } else {
+ if (!n.isNull())
+ {
+ out << "CHECKSAT " << n << ';';
+ }
+ else
+ {
out << "CHECKSAT;";
}
- if(cvc3Mode) {
+ if (d_cvc3Mode)
+ {
out << " POP;";
}
+ out << std::endl;
}
-static void toStream(std::ostream& out,
- const CheckSatAssumingCommand* c,
- bool cvc3Mode)
+void CvcPrinter::toStreamCmdCheckSatAssuming(
+ std::ostream& out, const std::vector<Node>& nodes) const
{
- const vector<Expr>& exprs = c->getTerms();
- if (cvc3Mode)
+ if (d_cvc3Mode)
{
out << "PUSH; ";
}
out << "CHECKSAT";
- if (exprs.size() > 0)
+ if (nodes.size() > 0)
{
- out << " " << exprs[0];
- for (size_t i = 1, n = exprs.size(); i < n; ++i)
+ out << ' ' << nodes[0];
+ for (size_t i = 1, n = nodes.size(); i < n; ++i)
{
- out << " AND " << exprs[i];
+ out << " AND " << nodes[i];
}
}
- out << ";";
- if (cvc3Mode)
+ out << ';';
+ if (d_cvc3Mode)
{
out << " POP;";
}
+ out << std::endl;
}
-static void toStream(std::ostream& out, const QueryCommand* c, bool cvc3Mode)
+void CvcPrinter::toStreamCmdQuery(std::ostream& out, Node n) const
{
- Expr e = c->getExpr();
- if(cvc3Mode) {
+ if (d_cvc3Mode)
+ {
out << "PUSH; ";
}
- if(!e.isNull()) {
- out << "QUERY " << e << ";";
- } else {
+ if (!n.isNull())
+ {
+ out << "QUERY " << n << ';';
+ }
+ else
+ {
out << "QUERY TRUE;";
}
- if(cvc3Mode) {
+ if (d_cvc3Mode)
+ {
out << " POP;";
}
+ out << std::endl;
}
-static void toStream(std::ostream& out, const ResetCommand* c, bool cvc3Mode)
+void CvcPrinter::toStreamCmdReset(std::ostream& out) const
{
- out << "RESET;";
+ out << "RESET;" << std::endl;
}
-static void toStream(std::ostream& out,
- const ResetAssertionsCommand* c,
- bool cvc3Mode)
+void CvcPrinter::toStreamCmdResetAssertions(std::ostream& out) const
{
- out << "RESET ASSERTIONS;";
+ out << "RESET ASSERTIONS;" << std::endl;
}
-static void toStream(std::ostream& out, const QuitCommand* c, bool cvc3Mode)
+void CvcPrinter::toStreamCmdQuit(std::ostream& out) const
{
- //out << "EXIT;";
+ // out << "EXIT;" << std::endl;
}
-static void toStream(std::ostream& out, const CommandSequence* c, bool cvc3Mode)
+void CvcPrinter::toStreamCmdCommandSequence(
+ std::ostream& out, const std::vector<Command*>& sequence) const
{
- for(CommandSequence::const_iterator i = c->begin();
- i != c->end();
- ++i) {
- out << *i << endl;
+ for (CommandSequence::const_iterator i = sequence.cbegin();
+ i != sequence.cend();
+ ++i)
+ {
+ out << *i;
}
}
-static void toStream(std::ostream& out,
- const DeclarationSequence* c,
- bool cvc3Mode)
+void CvcPrinter::toStreamCmdDeclarationSequence(
+ std::ostream& out, const std::vector<Command*>& sequence) const
{
- DeclarationSequence::const_iterator i = c->begin();
- for(;;) {
+ DeclarationSequence::const_iterator i = sequence.cbegin();
+ for (;;)
+ {
DeclarationDefinitionCommand* dd =
- static_cast<DeclarationDefinitionCommand*>(*i++);
- if(i != c->end()) {
+ static_cast<DeclarationDefinitionCommand*>(*i++);
+ if (i != sequence.cend())
+ {
out << dd->getSymbol() << ", ";
- } else {
+ }
+ else
+ {
out << *dd;
break;
}
}
+ out << std::endl;
}
-static void toStream(std::ostream& out,
- const DeclareFunctionCommand* c,
- bool cvc3Mode)
+void CvcPrinter::toStreamCmdDeclareFunction(std::ostream& out,
+ const std::string& id,
+ TypeNode type) const
{
- out << c->getSymbol() << " : " << c->getType() << ";";
+ out << id << " : " << type << ';' << std::endl;
}
-static void toStream(std::ostream& out,
- const DefineFunctionCommand* c,
- bool cvc3Mode)
+void CvcPrinter::toStreamCmdDefineFunction(std::ostream& out,
+ const std::string& id,
+ const std::vector<Node>& formals,
+ TypeNode range,
+ Node formula) const
{
- Expr func = c->getFunction();
- const vector<Expr>& formals = c->getFormals();
- Expr formula = c->getFormula();
- out << func << " : " << func.getType() << " = ";
- if(formals.size() > 0) {
+ std::vector<TypeNode> sorts;
+ sorts.reserve(formals.size() + 1);
+ for (const Node& n : formals)
+ {
+ sorts.push_back(n.getType());
+ }
+ sorts.push_back(range);
+
+ out << id << " : " << NodeManager::currentNM()->mkFunctionType(sorts)
+ << " = ";
+ if (formals.size() > 0)
+ {
out << "LAMBDA(";
- vector<Expr>::const_iterator i = formals.begin();
- while(i != formals.end()) {
+ vector<Node>::const_iterator i = formals.cbegin();
+ while (i != formals.end())
+ {
out << (*i) << ":" << (*i).getType();
- if(++i != formals.end()) {
+ if (++i != formals.end())
+ {
out << ", ";
}
}
out << "): ";
}
- out << formula << ";";
+ out << formula << ';' << std::endl;
}
-static void toStream(std::ostream& out,
- const DeclareTypeCommand* c,
- bool cvc3Mode)
+void CvcPrinter::toStreamCmdDeclareType(std::ostream& out,
+ const std::string& id,
+ size_t arity,
+ TypeNode type) const
{
- if(c->getArity() > 0) {
- //TODO?
+ if (arity > 0)
+ {
+ // TODO?
out << "ERROR: Don't know how to print parameterized type declaration "
- "in CVC language." << endl;
- } else {
- out << c->getSymbol() << " : TYPE;";
+ "in CVC language."
+ << std::endl;
+ }
+ else
+ {
+ out << id << " : TYPE;" << std::endl;
}
}
-static void toStream(std::ostream& out,
- const DefineTypeCommand* c,
- bool cvc3Mode)
+void CvcPrinter::toStreamCmdDefineType(std::ostream& out,
+ const std::string& id,
+ const std::vector<TypeNode>& params,
+ TypeNode t) const
{
- if(c->getParameters().size() > 0) {
+ if (params.size() > 0)
+ {
out << "ERROR: Don't know how to print parameterized type definition "
- "in CVC language:" << endl << c->toString() << endl;
- } else {
- out << c->getSymbol() << " : TYPE = " << c->getType() << ";";
+ "in CVC language:"
+ << std::endl;
+ }
+ else
+ {
+ out << id << " : TYPE = " << t << ';' << std::endl;
}
}
-static void toStream(std::ostream& out,
- const DefineNamedFunctionCommand* c,
- bool cvc3Mode)
-{
- toStream(out, static_cast<const DefineFunctionCommand*>(c), cvc3Mode);
-}
-
-static void toStream(std::ostream& out, const SimplifyCommand* c, bool cvc3Mode)
+void CvcPrinter::toStreamCmdSimplify(std::ostream& out, Node n) const
{
- out << "TRANSFORM " << c->getTerm() << ";";
+ out << "TRANSFORM " << n << ';' << std::endl;
}
-static void toStream(std::ostream& out, const GetValueCommand* c, bool cvc3Mode)
+void CvcPrinter::toStreamCmdGetValue(std::ostream& out,
+ const std::vector<Node>& nodes) const
{
- const vector<Expr>& terms = c->getTerms();
- Assert(!terms.empty());
+ Assert(!nodes.empty());
out << "GET_VALUE ";
- copy(terms.begin(), terms.end() - 1, ostream_iterator<Expr>(out, ";\nGET_VALUE "));
- out << terms.back() << ";";
+ copy(nodes.begin(),
+ nodes.end() - 1,
+ ostream_iterator<Node>(out, ";\nGET_VALUE "));
+ out << nodes.back() << ';' << std::endl;
}
-static void toStream(std::ostream& out, const GetModelCommand* c, bool cvc3Mode)
+void CvcPrinter::toStreamCmdGetModel(std::ostream& out) const
{
- out << "COUNTERMODEL;";
+ out << "COUNTERMODEL;" << std::endl;
}
-static void toStream(std::ostream& out,
- const GetAssignmentCommand* c,
- bool cvc3Mode)
+void CvcPrinter::toStreamCmdGetAssignment(std::ostream& out) const
{
- out << "% (get-assignment)";
+ out << "% (get-assignment)" << std::endl;
}
-static void toStream(std::ostream& out,
- const GetAssertionsCommand* c,
- bool cvc3Mode)
+void CvcPrinter::toStreamCmdGetAssertions(std::ostream& out) const
{
- out << "WHERE;";
+ out << "WHERE;" << std::endl;
}
-static void toStream(std::ostream& out, const GetProofCommand* c, bool cvc3Mode)
+void CvcPrinter::toStreamCmdGetProof(std::ostream& out) const
{
- out << "DUMP_PROOF;";
+ out << "DUMP_PROOF;" << std::endl;
}
-static void toStream(std::ostream& out,
- const GetUnsatCoreCommand* c,
- bool cvc3Mode)
+void CvcPrinter::toStreamCmdGetUnsatCore(std::ostream& out) const
{
- out << "DUMP_UNSAT_CORE;";
+ out << "DUMP_UNSAT_CORE;" << std::endl;
}
-static void toStream(std::ostream& out,
- const SetBenchmarkStatusCommand* c,
- bool cvc3Mode)
+void CvcPrinter::toStreamCmdSetBenchmarkStatus(std::ostream& out,
+ Result::Sat status) const
{
- out << "% (set-info :status " << c->getStatus() << ")";
+ out << "% (set-info :status " << status << ')' << std::endl;
}
-static void toStream(std::ostream& out,
- const SetBenchmarkLogicCommand* c,
- bool cvc3Mode)
+void CvcPrinter::toStreamCmdSetBenchmarkLogic(std::ostream& out,
+ const std::string& logic) const
{
- out << "OPTION \"logic\" \"" << c->getLogic() << "\";";
+ out << "OPTION \"logic\" \"" << logic << "\";" << std::endl;
}
-static void toStream(std::ostream& out, const SetInfoCommand* c, bool cvc3Mode)
+void CvcPrinter::toStreamCmdSetInfo(std::ostream& out,
+ const std::string& flag,
+ SExpr sexpr) const
{
- out << "% (set-info " << c->getFlag() << " ";
+ out << "% (set-info " << flag << ' ';
OutputLanguage language =
- cvc3Mode ? language::output::LANG_CVC3 : language::output::LANG_CVC4;
- SExpr::toStream(out, c->getSExpr(), language);
- out << ")";
+ d_cvc3Mode ? language::output::LANG_CVC3 : language::output::LANG_CVC4;
+ SExpr::toStream(out, sexpr, language);
+ out << ')' << std::endl;
}
-static void toStream(std::ostream& out, const GetInfoCommand* c, bool cvc3Mode)
+void CvcPrinter::toStreamCmdGetInfo(std::ostream& out,
+ const std::string& flag) const
{
- out << "% (get-info " << c->getFlag() << ")";
+ out << "% (get-info " << flag << ')' << std::endl;
}
-static void toStream(std::ostream& out,
- const SetOptionCommand* c,
- bool cvc3Mode)
+void CvcPrinter::toStreamCmdSetOption(std::ostream& out,
+ const std::string& flag,
+ SExpr sexpr) const
{
- out << "OPTION \"" << c->getFlag() << "\" ";
- SExpr::toStream(out, c->getSExpr(), language::output::LANG_CVC4);
- out << ";";
+ out << "OPTION \"" << flag << "\" ";
+ SExpr::toStream(out, sexpr, language::output::LANG_CVC4);
+ out << ';' << std::endl;
}
-static void toStream(std::ostream& out,
- const GetOptionCommand* c,
- bool cvc3Mode)
+void CvcPrinter::toStreamCmdGetOption(std::ostream& out,
+ const std::string& flag) const
{
- out << "% (get-option " << c->getFlag() << ")";
+ out << "% (get-option " << flag << ')' << std::endl;
}
-static void toStream(std::ostream& out,
- const DatatypeDeclarationCommand* c,
- bool cvc3Mode)
+void CvcPrinter::toStreamCmdDatatypeDeclaration(
+ std::ostream& out, const std::vector<TypeNode>& datatypes) const
{
- const vector<Type>& datatypes = c->getDatatypes();
Assert(!datatypes.empty() && datatypes[0].isDatatype());
- const Datatype& dt0 = DatatypeType(datatypes[0]).getDatatype();
- //do not print tuple/datatype internal declarations
+ const DType& dt0 = datatypes[0].getDType();
+ // do not print tuple/datatype internal declarations
if (datatypes.size() != 1 || (!dt0.isTuple() && !dt0.isRecord()))
{
out << "DATATYPE" << endl;
bool firstDatatype = true;
- for (const Type& t : datatypes)
+ for (const TypeNode& t : datatypes)
{
- if(! firstDatatype) {
+ if (!firstDatatype)
+ {
out << ',' << endl;
}
- const Datatype& dt = DatatypeType(t).getDatatype();
+ const DType& dt = t.getDType();
out << " " << dt.getName();
- if(dt.isParametric()) {
+ if (dt.isParametric())
+ {
out << '[';
- for(size_t j = 0; j < dt.getNumParameters(); ++j) {
- if(j > 0) {
+ for (size_t j = 0; j < dt.getNumParameters(); ++j)
+ {
+ if (j > 0)
+ {
out << ',';
}
out << dt.getParameter(j);
@@ -1539,31 +1527,28 @@ static void toStream(std::ostream& out,
out << ']';
}
out << " = ";
- bool firstConstructor = true;
- for(Datatype::const_iterator j = dt.begin(); j != dt.end(); ++j) {
- if(! firstConstructor) {
+ for (size_t j = 0, ncons = dt.getNumConstructors(); j < ncons; j++)
+ {
+ const DTypeConstructor& cons = dt[j];
+ if (j != 0)
+ {
out << " | ";
}
- firstConstructor = false;
- const DatatypeConstructor& cons = *j;
out << cons.getName();
if (cons.getNumArgs() > 0)
{
out << '(';
- bool firstSelector = true;
- for (DatatypeConstructor::const_iterator k = cons.begin();
- k != cons.end();
- ++k)
+ for (size_t k = 0, nargs = cons.getNumArgs(); k < nargs; k++)
{
- if(! firstSelector) {
+ if (k != 0)
+ {
out << ", ";
}
- firstSelector = false;
- const DatatypeConstructorArg& selector = *k;
- Type tr = SelectorType(selector.getType()).getRangeType();
+ const DTypeSelector& selector = cons[k];
+ TypeNode tr = selector.getRangeType();
if (tr.isDatatype())
{
- const Datatype& sdt = DatatypeType(tr).getDatatype();
+ const DType& sdt = tr.getDType();
out << selector.getName() << ": " << sdt.getName();
}
else
@@ -1576,20 +1561,26 @@ static void toStream(std::ostream& out,
}
firstDatatype = false;
}
- out << endl << "END;";
+ out << endl << "END;" << std::endl;
}
}
-static void toStream(std::ostream& out, const CommentCommand* c, bool cvc3Mode)
+void CvcPrinter::toStreamCmdComment(std::ostream& out,
+ const std::string& comment) const
{
- out << "% " << c->getComment();
+ out << "% " << comment << std::endl;
}
-static void toStream(std::ostream& out, const EmptyCommand* c, bool cvc3Mode) {}
+void CvcPrinter::toStreamCmdEmpty(std::ostream& out,
+ const std::string& name) const
+{
+ out << std::endl;
+}
-static void toStream(std::ostream& out, const EchoCommand* c, bool cvc3Mode)
+void CvcPrinter::toStreamCmdEcho(std::ostream& out,
+ const std::string& output) const
{
- out << "ECHO \"" << c->getOutput() << "\";";
+ out << "ECHO \"" << output << "\";" << std::endl;
}
template <class T>
diff --git a/src/printer/cvc/cvc_printer.h b/src/printer/cvc/cvc_printer.h
index f5a06a082..ee4750a61 100644
--- a/src/printer/cvc/cvc_printer.h
+++ b/src/printer/cvc/cvc_printer.h
@@ -2,10 +2,10 @@
/*! \file cvc_printer.h
** \verbatim
** Top contributors (to current version):
- ** Tim King, Morgan Deters, Mathias Preiner
+ ** Abdalrhman Mohamed, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -27,35 +27,154 @@ namespace CVC4 {
namespace printer {
namespace cvc {
-class CvcPrinter : public CVC4::Printer {
+class CvcPrinter : public CVC4::Printer
+{
public:
using CVC4::Printer::toStream;
- CvcPrinter(bool cvc3Mode = false) : d_cvc3Mode(cvc3Mode) { }
+ CvcPrinter(bool cvc3Mode = false) : d_cvc3Mode(cvc3Mode) {}
void toStream(std::ostream& out,
TNode n,
int toDepth,
- bool types,
- size_t dag) const override;
- void toStream(std::ostream& out,
- const Command* c,
- int toDepth,
- bool types,
size_t dag) const override;
void toStream(std::ostream& out, const CommandStatus* s) const override;
- void toStream(std::ostream& out, const Model& m) const override;
+ void toStream(std::ostream& out, const smt::Model& m) const override;
+
+ /** Print empty command */
+ void toStreamCmdEmpty(std::ostream& out,
+ const std::string& name) const override;
+
+ /** Print echo command */
+ void toStreamCmdEcho(std::ostream& out,
+ const std::string& output) const override;
+
+ /** Print assert command */
+ void toStreamCmdAssert(std::ostream& out, Node n) const override;
+
+ /** Print push command */
+ void toStreamCmdPush(std::ostream& out) const override;
+
+ /** Print pop command */
+ void toStreamCmdPop(std::ostream& out) const override;
+
+ /** Print declare-fun command */
+ void toStreamCmdDeclareFunction(std::ostream& out,
+ const std::string& id,
+ TypeNode type) const override;
+
+ /** Print declare-sort command */
+ void toStreamCmdDeclareType(std::ostream& out,
+ const std::string& id,
+ size_t arity,
+ TypeNode type) const override;
+
+ /** Print define-sort command */
+ void toStreamCmdDefineType(std::ostream& out,
+ const std::string& id,
+ const std::vector<TypeNode>& params,
+ TypeNode t) const override;
+
+ /** Print define-fun command */
+ void toStreamCmdDefineFunction(std::ostream& out,
+ const std::string& id,
+ const std::vector<Node>& formals,
+ TypeNode range,
+ Node formula) const override;
+
+ /** Print check-sat command */
+ void toStreamCmdCheckSat(std::ostream& out,
+ Node n = Node::null()) const override;
+
+ /** Print check-sat-assuming command */
+ void toStreamCmdCheckSatAssuming(
+ std::ostream& out, const std::vector<Node>& nodes) const override;
+
+ /** Print query command */
+ void toStreamCmdQuery(std::ostream& out, Node n) const override;
+
+ /** Print simplify command */
+ void toStreamCmdSimplify(std::ostream& out, Node nodes) const override;
+
+ /** Print get-value command */
+ void toStreamCmdGetValue(std::ostream& out,
+ const std::vector<Node>& n) const override;
+
+ /** Print get-assignment command */
+ void toStreamCmdGetAssignment(std::ostream& out) const override;
+
+ /** Print get-model command */
+ void toStreamCmdGetModel(std::ostream& out) const override;
+
+ /** Print get-proof command */
+ void toStreamCmdGetProof(std::ostream& out) const override;
+
+ /** Print get-unsat-core command */
+ void toStreamCmdGetUnsatCore(std::ostream& out) const override;
+
+ /** Print get-assertions command */
+ void toStreamCmdGetAssertions(std::ostream& out) const override;
+
+ /** Print set-info :status command */
+ void toStreamCmdSetBenchmarkStatus(std::ostream& out,
+ Result::Sat status) const override;
+
+ /** Print set-logic command */
+ void toStreamCmdSetBenchmarkLogic(std::ostream& out,
+ const std::string& logic) const override;
+
+ /** Print set-info command */
+ void toStreamCmdSetInfo(std::ostream& out,
+ const std::string& flag,
+ SExpr sexpr) const override;
+
+ /** Print get-info command */
+ void toStreamCmdGetInfo(std::ostream& out,
+ const std::string& flag) const override;
+
+ /** Print set-option command */
+ void toStreamCmdSetOption(std::ostream& out,
+ const std::string& flag,
+ SExpr sexpr) const override;
+
+ /** Print get-option command */
+ void toStreamCmdGetOption(std::ostream& out,
+ const std::string& flag) const override;
+
+ /** Print declare-datatype(s) command */
+ void toStreamCmdDatatypeDeclaration(
+ std::ostream& out, const std::vector<TypeNode>& datatypes) const override;
+
+ /** Print reset command */
+ void toStreamCmdReset(std::ostream& out) const override;
+
+ /** Print reset-assertions command */
+ void toStreamCmdResetAssertions(std::ostream& out) const override;
+
+ /** Print quit command */
+ void toStreamCmdQuit(std::ostream& out) const override;
+
+ /** Print comment command */
+ void toStreamCmdComment(std::ostream& out,
+ const std::string& comment) const override;
+
+ /** Print command sequence command */
+ void toStreamCmdCommandSequence(
+ std::ostream& out, const std::vector<Command*>& sequence) const override;
+
+ /** Print declaration sequence command */
+ void toStreamCmdDeclarationSequence(
+ std::ostream& out, const std::vector<Command*>& sequence) const override;
private:
- void toStream(
- std::ostream& out, TNode n, int toDepth, bool types, bool bracket) const;
+ void toStream(std::ostream& out, TNode n, int toDepth, bool bracket) const;
void toStream(std::ostream& out,
- const Model& m,
- const Command* c) const override;
+ const smt::Model& m,
+ const NodeCommand* c) const override;
bool d_cvc3Mode;
-};/* class CvcPrinter */
+}; /* class CvcPrinter */
-}/* CVC4::printer::cvc namespace */
-}/* CVC4::printer namespace */
-}/* CVC4 namespace */
+} // namespace cvc
+} // namespace printer
+} // namespace CVC4
#endif /* CVC4__PRINTER__CVC_PRINTER_H */
diff --git a/src/printer/dagification_visitor.cpp b/src/printer/dagification_visitor.cpp
index e6f24f15c..cf2635172 100644
--- a/src/printer/dagification_visitor.cpp
+++ b/src/printer/dagification_visitor.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/printer/dagification_visitor.h b/src/printer/dagification_visitor.h
index 5ebbc6e18..7c6f57af8 100644
--- a/src/printer/dagification_visitor.h
+++ b/src/printer/dagification_visitor.h
@@ -5,7 +5,7 @@
** Morgan Deters, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/printer/let_binding.cpp b/src/printer/let_binding.cpp
new file mode 100644
index 000000000..439037b64
--- /dev/null
+++ b/src/printer/let_binding.cpp
@@ -0,0 +1,210 @@
+/********************* */
+/*! \file let_binding.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief A let binding utility
+ **/
+
+#include "printer/let_binding.h"
+
+namespace CVC4 {
+
+LetBinding::LetBinding(uint32_t thresh)
+ : d_thresh(thresh),
+ d_context(),
+ d_visitList(&d_context),
+ d_count(&d_context),
+ d_letList(&d_context),
+ d_letMap(&d_context)
+{
+}
+
+uint32_t LetBinding::getThreshold() const { return d_thresh; }
+
+void LetBinding::process(Node n)
+{
+ Assert(!n.isNull());
+ if (d_thresh == 0)
+ {
+ // value of 0 means do not introduce let
+ return;
+ }
+ // update the count of occurrences
+ updateCounts(n);
+}
+
+void LetBinding::letify(Node n, std::vector<Node>& letList)
+{
+ Assert(!n.isNull());
+ // first, push the context
+ pushScope();
+ // process the node
+ process(n);
+ // now, letify
+ letify(letList);
+}
+
+void LetBinding::letify(std::vector<Node>& letList)
+{
+ size_t prevSize = d_letList.size();
+ // populate the d_letList and d_letMap
+ convertCountToLet();
+ // add the new entries to the letList
+letList.insert(letList.end(), d_letList.begin() + prevSize, d_letList.end());
+}
+
+void LetBinding::pushScope() { d_context.push(); }
+
+void LetBinding::popScope() { d_context.pop(); }
+
+uint32_t LetBinding::getId(Node n) const
+{
+ NodeIdMap::const_iterator it = d_letMap.find(n);
+ if (it == d_letMap.end())
+ {
+ return 0;
+ }
+ return (*it).second;
+}
+
+Node LetBinding::convert(Node n, const std::string& prefix, bool letTop) const
+{
+ if (d_letMap.empty())
+ {
+ return n;
+ }
+ NodeManager* nm = NodeManager::currentNM();
+ std::unordered_map<TNode, Node, TNodeHashFunction> visited;
+ std::unordered_map<TNode, Node, TNodeHashFunction>::iterator it;
+ std::vector<TNode> visit;
+ TNode cur;
+ visit.push_back(n);
+ do
+ {
+ cur = visit.back();
+ visit.pop_back();
+ it = visited.find(cur);
+
+ if (it == visited.end())
+ {
+ uint32_t id = getId(cur);
+ // do not letify id 0, or n itself if letTop is false
+ if (id > 0 && (cur != n || letTop))
+ {
+ // make the let variable
+ std::stringstream ss;
+ ss << prefix << id;
+ visited[cur] = nm->mkBoundVar(ss.str(), cur.getType());
+ }
+ else
+ {
+ visited[cur] = Node::null();
+ visit.push_back(cur);
+ visit.insert(visit.end(), cur.begin(), cur.end());
+ }
+ }
+ else if (it->second.isNull())
+ {
+ Node ret = cur;
+ bool childChanged = false;
+ std::vector<Node> children;
+ if (cur.getMetaKind() == kind::metakind::PARAMETERIZED)
+ {
+ children.push_back(cur.getOperator());
+ }
+ for (const Node& cn : cur)
+ {
+ it = visited.find(cn);
+ Assert(it != visited.end());
+ Assert(!it->second.isNull());
+ childChanged = childChanged || cn != it->second;
+ children.push_back(it->second);
+ }
+ if (childChanged)
+ {
+ ret = nm->mkNode(cur.getKind(), children);
+ }
+ visited[cur] = ret;
+ }
+ } while (!visit.empty());
+ Assert(visited.find(n) != visited.end());
+ Assert(!visited.find(n)->second.isNull());
+ return visited[n];
+}
+
+void LetBinding::updateCounts(Node n)
+{
+ NodeIdMap::iterator it;
+ std::vector<Node> visit;
+ TNode cur;
+ visit.push_back(n);
+ do
+ {
+ cur = visit.back();
+ it = d_count.find(cur);
+ if (it == d_count.end())
+ {
+ // do not traverse beneath quantifiers
+ if (cur.getNumChildren() == 0 || cur.isClosure())
+ {
+ d_visitList.push_back(cur);
+ d_count[cur] = 1;
+ visit.pop_back();
+ }
+ else
+ {
+ d_count[cur] = 0;
+ visit.insert(visit.end(), cur.begin(), cur.end());
+ }
+ }
+ else
+ {
+ if ((*it).second == 0)
+ {
+ d_visitList.push_back(cur);
+ }
+ d_count[cur] = (*it).second + 1;
+ visit.pop_back();
+ }
+ } while (!visit.empty());
+}
+
+void LetBinding::convertCountToLet()
+{
+ Assert(d_thresh > 0);
+ // Assign ids for those whose d_count is >= d_thresh, traverse in d_visitList
+ // in order so that deeper nodes are assigned lower identifiers, which
+ // ensures the let list can be printed.
+ NodeIdMap::const_iterator itc;
+ for (const Node& n : d_visitList)
+ {
+ if (n.getNumChildren() == 0)
+ {
+ // do not letify terms with no children
+ continue;
+ }
+ else if (d_letMap.find(n) != d_letMap.end())
+ {
+ // already letified, perhaps at a lower context
+ continue;
+ }
+ itc = d_count.find(n);
+ Assert(itc != d_count.end());
+ if ((*itc).second >= d_thresh)
+ {
+ d_letList.push_back(n);
+ // start with id 1
+ size_t id = d_letMap.size() + 1;
+ d_letMap[n] = id;
+ }
+ }
+}
+
+} // namespace CVC4
diff --git a/src/printer/let_binding.h b/src/printer/let_binding.h
new file mode 100644
index 000000000..d81274c87
--- /dev/null
+++ b/src/printer/let_binding.h
@@ -0,0 +1,150 @@
+/********************* */
+/*! \file let_binding.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief A let binding
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__PRINTER__LET_BINDING_H
+#define CVC4__PRINTER__LET_BINDING_H
+
+#include <map>
+#include <vector>
+
+#include "context/cdhashmap.h"
+#include "context/cdlist.h"
+#include "expr/node.h"
+
+namespace CVC4 {
+
+/**
+ * A flexible let binding class. This class provides functionalities for
+ * printing letified terms. A simple use case is the following for Node n
+ * and LetBinding lbind:
+ * ```
+ * std::vector<Node> letList;
+ * lbind.letify(n, letList);
+ * ```
+ * Now, letList contains a list of subterms of n that should be letified based
+ * on the threshold value passed to this class where a value n>0 indicates that
+ * terms with n or more occurrences should be letified.
+ *
+ * The above is equivalent to:
+ * ```
+ * std::vector<Node> letList;
+ * lbind.pushScope();
+ * lbind.process(n);
+ * lbind.letify(letList);
+ * ```
+ * In fact, multiple terms can be passed to calls to process, in which case the
+ * counting is cumulative.
+ *
+ * All quantified formulas are treated as black boxes. This class can be used
+ * to letify terms with quantifiers, where multiple calls to pushScope /
+ * popScope can be used. In particular, consider:
+ * ```
+ * std::vector<Node> letList1;
+ * lbind.letify(n1, letList1);
+ * std::vector<Node> letList2;
+ * lbind.letify(n2, letList2);
+ * ...
+ * lbind.popScope();
+ * lbind.popScope();
+ * ```
+ * In a typical use case, n2 is the body of a quantified formula that is a
+ * subterm of n1. We have that letList2 is the list of subterms of n2 that
+ * should be letified, assuming that we have already have let definitions
+ * given by letList1.
+ *
+ * Internally, a let binding is a list and a map that can be printed as a let
+ * expression. In particular, the list d_letList is ordered such that
+ * d_letList[i] does not contain subterm d_letList[j] for j>i.
+ * It is intended that d_letList contains only unique nodes. Each node
+ * in d_letList is mapped to a unique identifier in d_letMap.
+ */
+class LetBinding
+{
+ using NodeList = context::CDList<Node>;
+ using NodeIdMap = context::CDHashMap<Node, uint32_t, NodeHashFunction>;
+
+ public:
+ LetBinding(uint32_t thresh = 2);
+ /** Get threshold */
+ uint32_t getThreshold() const;
+ /**
+ * This updates this let binding to consider the counts for node n.
+ */
+ void process(Node n);
+ /**
+ * This pushes a scope, computes the letification for n, adds the (new) terms
+ * that must be letified in this context to letList.
+ *
+ * Notice that this method does not traverse inside of closures.
+ *
+ * @param n The node to letify
+ * @param letList The list of terms that should be letified within n. This
+ * list is ordered in such a way that letList[i] does not contain subterm
+ * letList[j] for j>i.
+ */
+ void letify(Node n, std::vector<Node>& letList);
+ /**
+ * Same as above, without a node to letify.
+ */
+ void letify(std::vector<Node>& letList);
+ /** Push scope */
+ void pushScope();
+ /** Pop scope for n, reverts the state change of the above method */
+ void popScope();
+ /**
+ * @return the identifier for node n, or 0 if it does not have one.
+ */
+ uint32_t getId(Node n) const;
+ /**
+ * Convert n based on the state of the let binding. This replaces all
+ * letified subterms of n with a fresh variable whose name prefix is the
+ * given one.
+ *
+ * @param n The node to convert
+ * @param prefix The prefix of variables to convert
+ * @param letTop Whether we letify n itself
+ * @return the converted node.
+ */
+ Node convert(Node n, const std::string& prefix, bool letTop = true) const;
+
+ private:
+ /**
+ * Compute the count of sub nodes in n, store in d_count. Additionally,
+ * store each node in the domain of d_count in an order in d_visitList
+ * such that d_visitList[i] does not contain sub d_visitList[j] for j>i.
+ */
+ void updateCounts(Node n);
+ /**
+ * Convert a count to a let binding.
+ */
+ void convertCountToLet();
+ /** The dag threshold */
+ uint32_t d_thresh;
+ /** An internal context */
+ context::Context d_context;
+ /** Visit list */
+ NodeList d_visitList;
+ /** Count */
+ NodeIdMap d_count;
+ /** The let list */
+ NodeList d_letList;
+ /** The let map */
+ NodeIdMap d_letMap;
+};
+
+} // namespace CVC4
+
+#endif
diff --git a/src/printer/printer.cpp b/src/printer/printer.cpp
index 67dbe1036..b24025124 100644
--- a/src/printer/printer.cpp
+++ b/src/printer/printer.cpp
@@ -2,10 +2,10 @@
/*! \file printer.cpp
** \verbatim
** Top contributors (to current version):
- ** Morgan Deters, Aina Niemetz, Andrew Reynolds
+ ** Abdalrhman Mohamed, Morgan Deters, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -23,6 +23,9 @@
#include "printer/cvc/cvc_printer.h"
#include "printer/smt2/smt2_printer.h"
#include "printer/tptp/tptp_printer.h"
+#include "proof/unsat_core.h"
+#include "smt/command.h"
+#include "smt/node_command.h"
using namespace std;
@@ -69,11 +72,12 @@ unique_ptr<Printer> Printer::makePrinter(OutputLanguage lang)
}
}
-void Printer::toStream(std::ostream& out, const Model& m) const
+void Printer::toStream(std::ostream& out, const smt::Model& m) const
{
for(size_t i = 0; i < m.getNumCommands(); ++i) {
- const Command* cmd = m.getCommand(i);
- const DeclareFunctionCommand* dfc = dynamic_cast<const DeclareFunctionCommand*>(cmd);
+ const NodeCommand* cmd = m.getCommand(i);
+ const DeclareFunctionNodeCommand* dfc =
+ dynamic_cast<const DeclareFunctionNodeCommand*>(cmd);
if (dfc != NULL && !m.isModelCoreSymbol(dfc->getFunction()))
{
continue;
@@ -85,8 +89,7 @@ void Printer::toStream(std::ostream& out, const Model& m) const
void Printer::toStream(std::ostream& out, const UnsatCore& core) const
{
for(UnsatCore::iterator i = core.begin(); i != core.end(); ++i) {
- AssertCommand cmd(*i);
- toStream(out, &cmd, -1, false, -1);
+ toStreamCmdAssert(out, *i);
out << std::endl;
}
}/* Printer::toStream(UnsatCore) */
@@ -117,5 +120,309 @@ Printer* Printer::getPrinter(OutputLanguage lang)
return d_printers[lang].get();
}
+void Printer::printUnknownCommand(std::ostream& out,
+ const std::string& name) const
+{
+ out << "ERROR: don't know how to print " << name << " command" << std::endl;
+}
+
+void Printer::toStreamCmdEmpty(std::ostream& out, const std::string& name) const
+{
+ printUnknownCommand(out, "empty");
+}
+
+void Printer::toStreamCmdEcho(std::ostream& out,
+ const std::string& output) const
+{
+ printUnknownCommand(out, "echo");
+}
+
+void Printer::toStreamCmdAssert(std::ostream& out, Node n) const
+{
+ printUnknownCommand(out, "assert");
+}
+
+void Printer::toStreamCmdPush(std::ostream& out) const
+{
+ printUnknownCommand(out, "push");
+}
+
+void Printer::toStreamCmdPop(std::ostream& out) const
+{
+ printUnknownCommand(out, "pop");
+}
+
+void Printer::toStreamCmdDeclareFunction(std::ostream& out,
+ const std::string& id,
+ TypeNode type) const
+{
+ printUnknownCommand(out, "declare-fun");
+}
+
+void Printer::toStreamCmdDeclareType(std::ostream& out,
+ const std::string& id,
+ size_t arity,
+ TypeNode type) const
+{
+ printUnknownCommand(out, "declare-sort");
+}
+
+void Printer::toStreamCmdDefineType(std::ostream& out,
+ const std::string& id,
+ const std::vector<TypeNode>& params,
+ TypeNode t) const
+{
+ printUnknownCommand(out, "define-sort");
+}
+
+void Printer::toStreamCmdDefineFunction(std::ostream& out,
+ const std::string& id,
+ const std::vector<Node>& formals,
+ TypeNode range,
+ Node formula) const
+{
+ printUnknownCommand(out, "define-fun");
+}
+
+void Printer::toStreamCmdDefineFunctionRec(
+ std::ostream& out,
+ const std::vector<Node>& funcs,
+ const std::vector<std::vector<Node>>& formals,
+ const std::vector<Node>& formulas) const
+{
+ printUnknownCommand(out, "define-fun-rec");
+}
+
+void Printer::toStreamCmdSetUserAttribute(std::ostream& out,
+ const std::string& attr,
+ Node n) const
+{
+ printUnknownCommand(out, "set-user-attribute");
+}
+
+void Printer::toStreamCmdCheckSat(std::ostream& out, Node n) const
+{
+ printUnknownCommand(out, "check-sat");
+}
+
+void Printer::toStreamCmdCheckSatAssuming(std::ostream& out,
+ const std::vector<Node>& nodes) const
+{
+ printUnknownCommand(out, "check-sat-assuming");
+}
+
+void Printer::toStreamCmdQuery(std::ostream& out, Node n) const
+{
+ printUnknownCommand(out, "query");
+}
+
+void Printer::toStreamCmdDeclareVar(std::ostream& out,
+ Node var,
+ TypeNode type) const
+{
+ printUnknownCommand(out, "declare-var");
+}
+
+void Printer::toStreamCmdSynthFun(std::ostream& out,
+ const std::string& sym,
+ const std::vector<Node>& vars,
+ TypeNode range,
+ bool isInv,
+ TypeNode sygusType) const
+{
+ printUnknownCommand(out, isInv ? "synth-inv" : "synth-fun");
+}
+
+void Printer::toStreamCmdConstraint(std::ostream& out, Node n) const
+{
+ printUnknownCommand(out, "constraint");
+}
+
+void Printer::toStreamCmdInvConstraint(
+ std::ostream& out, Node inv, Node pre, Node trans, Node post) const
+{
+ printUnknownCommand(out, "inv-constraint");
+}
+
+void Printer::toStreamCmdCheckSynth(std::ostream& out) const
+{
+ printUnknownCommand(out, "check-synth");
+}
+
+void Printer::toStreamCmdSimplify(std::ostream& out, Node n) const
+{
+ printUnknownCommand(out, "simplify");
+}
+
+void Printer::toStreamCmdGetValue(std::ostream& out,
+ const std::vector<Node>& nodes) const
+{
+ printUnknownCommand(out, "get-value");
+}
+
+void Printer::toStreamCmdGetAssignment(std::ostream& out) const
+{
+ printUnknownCommand(out, "get-assignment");
+}
+
+void Printer::toStreamCmdGetModel(std::ostream& out) const
+{
+ printUnknownCommand(out, "ge-model");
+}
+
+void Printer::toStreamCmdBlockModel(std::ostream& out) const
+{
+ printUnknownCommand(out, "block-model");
+}
+
+void Printer::toStreamCmdBlockModelValues(std::ostream& out,
+ const std::vector<Node>& nodes) const
+{
+ printUnknownCommand(out, "block-model-values");
+}
+
+void Printer::toStreamCmdGetProof(std::ostream& out) const
+{
+ printUnknownCommand(out, "get-proof");
+}
+
+void Printer::toStreamCmdGetInstantiations(std::ostream& out) const
+{
+ printUnknownCommand(out, "get-instantiations");
+}
+
+void Printer::toStreamCmdGetSynthSolution(std::ostream& out) const
+{
+ printUnknownCommand(out, "get-synth-solution");
+}
+
+void Printer::toStreamCmdGetInterpol(std::ostream& out,
+ const std::string& name,
+ Node conj,
+ TypeNode sygusType) const
+{
+ printUnknownCommand(out, "get-interpol");
+}
+
+void Printer::toStreamCmdGetAbduct(std::ostream& out,
+ const std::string& name,
+ Node conj,
+ TypeNode sygusType) const
+{
+ printUnknownCommand(out, "get-abduct");
+}
+
+void Printer::toStreamCmdGetQuantifierElimination(std::ostream& out,
+ Node n) const
+{
+ printUnknownCommand(out, "get-quantifier-elimination");
+}
+
+void Printer::toStreamCmdGetUnsatAssumptions(std::ostream& out) const
+{
+ printUnknownCommand(out, "get-unsat-assumption");
+}
+
+void Printer::toStreamCmdGetUnsatCore(std::ostream& out) const
+{
+ printUnknownCommand(out, "get-unsat-core");
+}
+
+void Printer::toStreamCmdGetAssertions(std::ostream& out) const
+{
+ printUnknownCommand(out, "get-assertions");
+}
+
+void Printer::toStreamCmdSetBenchmarkStatus(std::ostream& out,
+ Result::Sat status) const
+{
+ printUnknownCommand(out, "set-info");
+}
+
+void Printer::toStreamCmdSetBenchmarkLogic(std::ostream& out,
+ const std::string& logic) const
+{
+ printUnknownCommand(out, "set-logic");
+}
+
+void Printer::toStreamCmdSetInfo(std::ostream& out,
+ const std::string& flag,
+ SExpr sexpr) const
+{
+ printUnknownCommand(out, "set-info");
+}
+
+void Printer::toStreamCmdGetInfo(std::ostream& out,
+ const std::string& flag) const
+{
+ printUnknownCommand(out, "get-info");
+}
+
+void Printer::toStreamCmdSetOption(std::ostream& out,
+ const std::string& flag,
+ SExpr sexpr) const
+{
+ printUnknownCommand(out, "set-option");
+}
+
+void Printer::toStreamCmdGetOption(std::ostream& out,
+ const std::string& flag) const
+{
+ printUnknownCommand(out, "get-option");
+}
+
+void Printer::toStreamCmdSetExpressionName(std::ostream& out,
+ Node n,
+ const std::string& name) const
+{
+ printUnknownCommand(out, "set-expression-name");
+}
+
+void Printer::toStreamCmdDatatypeDeclaration(
+ std::ostream& out, const std::vector<TypeNode>& datatypes) const
+{
+ printUnknownCommand(
+ out, datatypes.size() == 1 ? "declare-datatype" : "declare-datatypes");
+}
+
+void Printer::toStreamCmdReset(std::ostream& out) const
+{
+ printUnknownCommand(out, "reset");
+}
+
+void Printer::toStreamCmdResetAssertions(std::ostream& out) const
+{
+ printUnknownCommand(out, "reset-assertions");
+}
+
+void Printer::toStreamCmdQuit(std::ostream& out) const
+{
+ printUnknownCommand(out, "quit");
+}
+
+void Printer::toStreamCmdComment(std::ostream& out,
+ const std::string& comment) const
+{
+ printUnknownCommand(out, "comment");
+}
+
+void Printer::toStreamCmdDeclareHeap(std::ostream& out,
+ TypeNode locType,
+ TypeNode dataType) const
+{
+ printUnknownCommand(out, "declare-heap");
+}
+
+void Printer::toStreamCmdCommandSequence(
+ std::ostream& out, const std::vector<Command*>& sequence) const
+{
+ printUnknownCommand(out, "sequence");
+}
+
+void Printer::toStreamCmdDeclarationSequence(
+ std::ostream& out, const std::vector<Command*>& sequence) const
+{
+ printUnknownCommand(out, "sequence");
+}
}/* CVC4 namespace */
diff --git a/src/printer/printer.h b/src/printer/printer.h
index fd788209c..d32418deb 100644
--- a/src/printer/printer.h
+++ b/src/printer/printer.h
@@ -2,10 +2,10 @@
/*! \file printer.h
** \verbatim
** Top contributors (to current version):
- ** Tim King, Andrew Reynolds, Aina Niemetz
+ ** Abdalrhman Mohamed, Tim King, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -24,12 +24,17 @@
#include "expr/node.h"
#include "options/language.h"
-#include "smt/command.h"
#include "smt/model.h"
+#include "util/result.h"
#include "util/sexpr.h"
namespace CVC4 {
+class Command;
+class CommandStatus;
+class NodeCommand;
+class UnsatCore;
+
class Printer
{
public:
@@ -46,43 +51,241 @@ class Printer
virtual void toStream(std::ostream& out,
TNode n,
int toDepth,
- bool types,
- size_t dag) const = 0;
-
- /** Write a Command out to a stream with this Printer. */
- virtual void toStream(std::ostream& out,
- const Command* c,
- int toDepth,
- bool types,
size_t dag) const = 0;
/** Write a CommandStatus out to a stream with this Printer. */
virtual void toStream(std::ostream& out, const CommandStatus* s) const = 0;
/** Write a Model out to a stream with this Printer. */
- virtual void toStream(std::ostream& out, const Model& m) const;
+ virtual void toStream(std::ostream& out, const smt::Model& m) const;
/** Write an UnsatCore out to a stream with this Printer. */
virtual void toStream(std::ostream& out, const UnsatCore& core) const;
+ /** Print empty command */
+ virtual void toStreamCmdEmpty(std::ostream& out,
+ const std::string& name) const;
+
+ /** Print echo command */
+ virtual void toStreamCmdEcho(std::ostream& out,
+ const std::string& output) const;
+
+ /** Print assert command */
+ virtual void toStreamCmdAssert(std::ostream& out, Node n) const;
+
+ /** Print push command */
+ virtual void toStreamCmdPush(std::ostream& out) const;
+
+ /** Print pop command */
+ virtual void toStreamCmdPop(std::ostream& out) const;
+
+ /** Print declare-fun command */
+ virtual void toStreamCmdDeclareFunction(std::ostream& out,
+ const std::string& id,
+ TypeNode type) const;
+
+ /** Print declare-sort command */
+ virtual void toStreamCmdDeclareType(std::ostream& out,
+ const std::string& id,
+ size_t arity,
+ TypeNode type) const;
+
+ /** Print define-sort command */
+ virtual void toStreamCmdDefineType(std::ostream& out,
+ const std::string& id,
+ const std::vector<TypeNode>& params,
+ TypeNode t) const;
+
+ /** Print define-fun command */
+ virtual void toStreamCmdDefineFunction(std::ostream& out,
+ const std::string& id,
+ const std::vector<Node>& formals,
+ TypeNode range,
+ Node formula) const;
+
+ /** Print define-fun-rec command */
+ virtual void toStreamCmdDefineFunctionRec(
+ std::ostream& out,
+ const std::vector<Node>& funcs,
+ const std::vector<std::vector<Node>>& formals,
+ const std::vector<Node>& formulas) const;
+
+ /** Print set-user-attribute command */
+ void toStreamCmdSetUserAttribute(std::ostream& out,
+ const std::string& attr,
+ Node n) const;
+
+ /** Print check-sat command */
+ virtual void toStreamCmdCheckSat(std::ostream& out,
+ Node n = Node::null()) const;
+
+ /** Print check-sat-assuming command */
+ virtual void toStreamCmdCheckSatAssuming(
+ std::ostream& out, const std::vector<Node>& nodes) const;
+
+ /** Print query command */
+ virtual void toStreamCmdQuery(std::ostream& out, Node n) const;
+
+ /** Print declare-var command */
+ virtual void toStreamCmdDeclareVar(std::ostream& out,
+ Node var,
+ TypeNode type) const;
+
+ /** Print synth-fun command */
+ virtual void toStreamCmdSynthFun(std::ostream& out,
+ const std::string& sym,
+ const std::vector<Node>& vars,
+ TypeNode range,
+ bool isInv,
+ TypeNode sygusType) const;
+
+ /** Print constraint command */
+ virtual void toStreamCmdConstraint(std::ostream& out, Node n) const;
+
+ /** Print inv-constraint command */
+ virtual void toStreamCmdInvConstraint(
+ std::ostream& out, Node inv, Node pre, Node trans, Node post) const;
+
+ /** Print check-synth command */
+ virtual void toStreamCmdCheckSynth(std::ostream& out) const;
+
+ /** Print simplify command */
+ virtual void toStreamCmdSimplify(std::ostream& out, Node n) const;
+
+ /** Print get-value command */
+ virtual void toStreamCmdGetValue(std::ostream& out,
+ const std::vector<Node>& nodes) const;
+
+ /** Print get-assignment command */
+ virtual void toStreamCmdGetAssignment(std::ostream& out) const;
+
+ /** Print get-model command */
+ virtual void toStreamCmdGetModel(std::ostream& out) const;
+
+ /** Print block-model command */
+ void toStreamCmdBlockModel(std::ostream& out) const;
+
+ /** Print block-model-values command */
+ void toStreamCmdBlockModelValues(std::ostream& out,
+ const std::vector<Node>& nodes) const;
+
+ /** Print get-proof command */
+ virtual void toStreamCmdGetProof(std::ostream& out) const;
+
+ /** Print get-instantiations command */
+ void toStreamCmdGetInstantiations(std::ostream& out) const;
+
+ /** Print get-synth-solution command */
+ void toStreamCmdGetSynthSolution(std::ostream& out) const;
+
+ /** Print get-interpol command */
+ void toStreamCmdGetInterpol(std::ostream& out,
+ const std::string& name,
+ Node conj,
+ TypeNode sygusType) const;
+
+ /** Print get-abduct command */
+ virtual void toStreamCmdGetAbduct(std::ostream& out,
+ const std::string& name,
+ Node conj,
+ TypeNode sygusType) const;
+
+ /** Print get-quantifier-elimination command */
+ void toStreamCmdGetQuantifierElimination(std::ostream& out, Node n) const;
+
+ /** Print get-unsat-assumptions command */
+ virtual void toStreamCmdGetUnsatAssumptions(std::ostream& out) const;
+
+ /** Print get-unsat-core command */
+ virtual void toStreamCmdGetUnsatCore(std::ostream& out) const;
+
+ /** Print get-assertions command */
+ virtual void toStreamCmdGetAssertions(std::ostream& out) const;
+
+ /** Print set-info :status command */
+ virtual void toStreamCmdSetBenchmarkStatus(std::ostream& out,
+ Result::Sat status) const;
+
+ /** Print set-logic command */
+ virtual void toStreamCmdSetBenchmarkLogic(std::ostream& out,
+ const std::string& logic) const;
+
+ /** Print set-info command */
+ virtual void toStreamCmdSetInfo(std::ostream& out,
+ const std::string& flag,
+ SExpr sexpr) const;
+
+ /** Print get-info command */
+ virtual void toStreamCmdGetInfo(std::ostream& out,
+ const std::string& flag) const;
+
+ /** Print set-option command */
+ virtual void toStreamCmdSetOption(std::ostream& out,
+ const std::string& flag,
+ SExpr sexpr) const;
+
+ /** Print get-option command */
+ virtual void toStreamCmdGetOption(std::ostream& out,
+ const std::string& flag) const;
+
+ /** Print set-expression-name command */
+ void toStreamCmdSetExpressionName(std::ostream& out,
+ Node n,
+ const std::string& name) const;
+
+ /** Print declare-datatype(s) command */
+ virtual void toStreamCmdDatatypeDeclaration(
+ std::ostream& out, const std::vector<TypeNode>& datatypes) const;
+
+ /** Print reset command */
+ virtual void toStreamCmdReset(std::ostream& out) const;
+
+ /** Print reset-assertions command */
+ virtual void toStreamCmdResetAssertions(std::ostream& out) const;
+
+ /** Print quit command */
+ virtual void toStreamCmdQuit(std::ostream& out) const;
+
+ /** Print comment command */
+ virtual void toStreamCmdComment(std::ostream& out,
+ const std::string& comment) const;
+ /** Declare heap command */
+ virtual void toStreamCmdDeclareHeap(std::ostream& out,
+ TypeNode locType,
+ TypeNode dataType) const;
+
+ /** Print command sequence command */
+ virtual void toStreamCmdCommandSequence(
+ std::ostream& out, const std::vector<Command*>& sequence) const;
+
+ /** Print declaration sequence command */
+ virtual void toStreamCmdDeclarationSequence(
+ std::ostream& out, const std::vector<Command*>& sequence) const;
+
protected:
/** Derived classes can construct, but no one else. */
Printer() {}
/** write model response to command */
virtual void toStream(std::ostream& out,
- const Model& m,
- const Command* c) const = 0;
+ const smt::Model& m,
+ const NodeCommand* c) const = 0;
/** write model response to command using another language printer */
void toStreamUsing(OutputLanguage lang,
std::ostream& out,
- const Model& m,
- const Command* c) const
+ const smt::Model& m,
+ const NodeCommand* c) const
{
getPrinter(lang)->toStream(out, m, c);
}
+ /**
+ * Write an error to `out` stating that command `name` is not supported by
+ * this printer.
+ */
+ void printUnknownCommand(std::ostream& out, const std::string& name) const;
+
private:
/** Disallow copy, assignment */
Printer(const Printer&) = delete;
diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp
index c4a0a96d5..747873bee 100644
--- a/src/printer/smt2/smt2_printer.cpp
+++ b/src/printer/smt2/smt2_printer.cpp
@@ -2,10 +2,10 @@
/*! \file smt2_printer.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Morgan Deters, Tim King
+ ** Andrew Reynolds, Morgan Deters, Abdalrhman Mohamed
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -31,11 +31,15 @@
#include "options/printer_options.h"
#include "options/smt_options.h"
#include "printer/dagification_visitor.h"
+#include "printer/let_binding.h"
+#include "proof/unsat_core.h"
+#include "smt/command.h"
+#include "smt/node_command.h"
#include "smt/smt_engine.h"
#include "smt_util/boolean_simplification.h"
#include "theory/arrays/theory_arrays_rewriter.h"
-#include "theory/quantifiers/quantifiers_attributes.h"
#include "theory/datatypes/sygus_datatype_utils.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
#include "theory/substitutions.h"
#include "theory/theory_model.h"
#include "util/smt2_quote_string.h"
@@ -56,47 +60,101 @@ bool isVariant_2_6(Variant v) { return v == smt2_6_variant; }
static void toStreamRational(std::ostream& out,
const Rational& r,
bool decimal,
- Variant v);
-
-void Smt2Printer::toStream(
- std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const
+ Variant v)
{
- if(dag != 0) {
- DagificationVisitor dv(dag);
- NodeVisitor<DagificationVisitor> visitor;
- visitor.run(dv, n);
- const theory::SubstitutionMap& lets = dv.getLets();
- if(!lets.empty()) {
- theory::SubstitutionMap::const_iterator i = lets.begin();
- theory::SubstitutionMap::const_iterator i_end = lets.end();
- for(; i != i_end; ++ i) {
- out << "(let ((";
- toStream(out, (*i).second, toDepth, types, TypeNode::null());
- out << ' ';
- toStream(out, (*i).first, toDepth, types, TypeNode::null());
- out << ")) ";
- }
+ bool neg = r.sgn() < 0;
+ // Print the rational, possibly as decimal.
+ // Notice that we print (/ (- 5) 3) instead of (- (/ 5 3)),
+ // the former is compliant with real values in the smt lib standard.
+ if (r.isIntegral())
+ {
+ if (neg)
+ {
+ out << "(- " << -r;
}
- Node body = dv.getDagifiedBody();
- toStream(out, body, toDepth, types, TypeNode::null());
- if(!lets.empty()) {
- theory::SubstitutionMap::const_iterator i = lets.begin();
- theory::SubstitutionMap::const_iterator i_end = lets.end();
- for(; i != i_end; ++ i) {
- out << ")";
- }
+ else
+ {
+ out << r;
+ }
+ if (decimal)
+ {
+ out << ".0";
+ }
+ if (neg)
+ {
+ out << ")";
+ }
+ }
+ else
+ {
+ out << "(/ ";
+ if (neg)
+ {
+ Rational abs_r = (-r);
+ out << "(- " << abs_r.getNumerator();
+ out << ") " << abs_r.getDenominator();
}
+ else
+ {
+ out << r.getNumerator();
+ out << ' ' << r.getDenominator();
+ }
+ out << ')';
+ }
+}
+
+void Smt2Printer::toStream(std::ostream& out,
+ TNode n,
+ int toDepth,
+ size_t dag) const
+{
+ if(dag != 0) {
+ LetBinding lbind(dag + 1);
+ toStreamWithLetify(out, n, toDepth, &lbind);
} else {
- toStream(out, n, toDepth, types, TypeNode::null());
+ toStream(out, n, toDepth);
+ }
+}
+
+void Smt2Printer::toStreamWithLetify(std::ostream& out,
+ Node n,
+ int toDepth,
+ LetBinding* lbind) const
+{
+ if (lbind == nullptr)
+ {
+ toStream(out, n, toDepth);
+ return;
+ }
+ std::stringstream cparen;
+ std::vector<Node> letList;
+ lbind->letify(n, letList);
+ if (!letList.empty())
+ {
+ std::map<Node, uint32_t>::const_iterator it;
+ for (size_t i = 0, nlets = letList.size(); i < nlets; i++)
+ {
+ Node nl = letList[i];
+ out << "(let ((";
+ uint32_t id = lbind->getId(nl);
+ out << "_let_" << id << " ";
+ Node nlc = lbind->convert(nl, "_let_", false);
+ toStream(out, nlc, toDepth, lbind);
+ out << ")) ";
+ cparen << ")";
+ }
}
+ Node nc = lbind->convert(n, "_let_");
+ // print the body, passing the lbind object
+ toStream(out, nc, toDepth, lbind);
+ out << cparen.str();
+ lbind->popScope();
}
-// force_nt is the type that n must have
void Smt2Printer::toStream(std::ostream& out,
TNode n,
int toDepth,
- bool types,
- TypeNode force_nt) const
+ LetBinding* lbind) const
{
// null
if(n.getKind() == kind::NULL_EXPR) {
@@ -104,6 +162,7 @@ void Smt2Printer::toStream(std::ostream& out,
return;
}
+ NodeManager* nm = NodeManager::currentNM();
// constant
if(n.getMetaKind() == kind::metakind::CONSTANT) {
switch(n.getKind()) {
@@ -122,17 +181,12 @@ void Smt2Printer::toStream(std::ostream& out,
}
break;
case kind::BITVECTOR_TYPE:
- if(d_variant == sygus_variant ){
- out << "(BitVec " << n.getConst<BitVectorSize>().d_size << ")";
- }else{
- out << "(_ BitVec " << n.getConst<BitVectorSize>().d_size << ")";
- }
+ out << "(_ BitVec " << n.getConst<BitVectorSize>().d_size << ")";
break;
case kind::FLOATINGPOINT_TYPE:
out << "(_ FloatingPoint "
- << n.getConst<FloatingPointSize>().exponent() << " "
- << n.getConst<FloatingPointSize>().significand()
- << ")";
+ << n.getConst<FloatingPointSize>().exponentWidth() << " "
+ << n.getConst<FloatingPointSize>().significandWidth() << ")";
break;
case kind::CONST_BITVECTOR:
{
@@ -155,14 +209,14 @@ void Smt2Printer::toStream(std::ostream& out,
}
case kind::CONST_ROUNDINGMODE:
switch (n.getConst<RoundingMode>()) {
- case roundNearestTiesToEven : out << "roundNearestTiesToEven"; break;
- case roundNearestTiesToAway : out << "roundNearestTiesToAway"; break;
- case roundTowardPositive : out << "roundTowardPositive"; break;
- case roundTowardNegative : out << "roundTowardNegative"; break;
- case roundTowardZero : out << "roundTowardZero"; break;
- default :
- Unreachable() << "Invalid value of rounding mode constant ("
- << n.getConst<RoundingMode>() << ")";
+ case ROUND_NEAREST_TIES_TO_EVEN: out << "roundNearestTiesToEven"; break;
+ case ROUND_NEAREST_TIES_TO_AWAY: out << "roundNearestTiesToAway"; break;
+ case ROUND_TOWARD_POSITIVE: out << "roundTowardPositive"; break;
+ case ROUND_TOWARD_NEGATIVE: out << "roundTowardNegative"; break;
+ case ROUND_TOWARD_ZERO: out << "roundTowardZero"; break;
+ default:
+ Unreachable() << "Invalid value of rounding mode constant ("
+ << n.getConst<RoundingMode>() << ")";
}
break;
case kind::CONST_BOOLEAN:
@@ -175,8 +229,7 @@ void Smt2Printer::toStream(std::ostream& out,
break;
case kind::CONST_RATIONAL: {
const Rational& r = n.getConst<Rational>();
- toStreamRational(
- out, r, !force_nt.isNull() && !force_nt.isInteger(), d_variant);
+ toStreamRational(out, r, false, d_variant);
break;
}
@@ -266,6 +319,10 @@ void Smt2Printer::toStream(std::ostream& out,
case kind::EMPTYSET:
out << "(as emptyset " << n.getConst<EmptySet>().getType() << ")";
break;
+
+ case kind::EMPTYBAG:
+ out << "(as emptybag " << n.getConst<EmptyBag>().getType() << ")";
+ break;
case kind::BITVECTOR_EXTRACT_OP:
{
BitVectorExtract p = n.getConst<BitVectorExtract>();
@@ -297,53 +354,76 @@ void Smt2Printer::toStream(std::ostream& out,
break;
case kind::FLOATINGPOINT_TO_FP_IEEE_BITVECTOR_OP:
out << "(_ to_fp "
- << n.getConst<FloatingPointToFPIEEEBitVector>().t.exponent() << ' '
- << n.getConst<FloatingPointToFPIEEEBitVector>().t.significand()
+ << n.getConst<FloatingPointToFPIEEEBitVector>()
+ .d_fp_size.exponentWidth()
+ << ' '
+ << n.getConst<FloatingPointToFPIEEEBitVector>()
+ .d_fp_size.significandWidth()
<< ")";
break;
case kind::FLOATINGPOINT_TO_FP_FLOATINGPOINT_OP:
out << "(_ to_fp "
- << n.getConst<FloatingPointToFPFloatingPoint>().t.exponent() << ' '
- << n.getConst<FloatingPointToFPFloatingPoint>().t.significand()
+ << n.getConst<FloatingPointToFPFloatingPoint>()
+ .d_fp_size.exponentWidth()
+ << ' '
+ << n.getConst<FloatingPointToFPFloatingPoint>()
+ .d_fp_size.significandWidth()
<< ")";
break;
case kind::FLOATINGPOINT_TO_FP_REAL_OP:
- out << "(_ to_fp " << n.getConst<FloatingPointToFPReal>().t.exponent()
- << ' ' << n.getConst<FloatingPointToFPReal>().t.significand() << ")";
+ out << "(_ to_fp "
+ << n.getConst<FloatingPointToFPReal>().d_fp_size.exponentWidth()
+ << ' '
+ << n.getConst<FloatingPointToFPReal>().d_fp_size.significandWidth()
+ << ")";
break;
case kind::FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR_OP:
out << "(_ to_fp "
- << n.getConst<FloatingPointToFPSignedBitVector>().t.exponent() << ' '
- << n.getConst<FloatingPointToFPSignedBitVector>().t.significand()
+ << n.getConst<FloatingPointToFPSignedBitVector>()
+ .d_fp_size.exponentWidth()
+ << ' '
+ << n.getConst<FloatingPointToFPSignedBitVector>()
+ .d_fp_size.significandWidth()
<< ")";
break;
case kind::FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR_OP:
out << "(_ to_fp_unsigned "
- << n.getConst<FloatingPointToFPUnsignedBitVector>().t.exponent()
+ << n.getConst<FloatingPointToFPUnsignedBitVector>()
+ .d_fp_size.exponentWidth()
<< ' '
- << n.getConst<FloatingPointToFPUnsignedBitVector>().t.significand()
+ << n.getConst<FloatingPointToFPUnsignedBitVector>()
+ .d_fp_size.significandWidth()
<< ")";
break;
case kind::FLOATINGPOINT_TO_FP_GENERIC_OP:
- out << "(_ to_fp " << n.getConst<FloatingPointToFPGeneric>().t.exponent()
- << ' ' << n.getConst<FloatingPointToFPGeneric>().t.significand()
+ out << "(_ to_fp "
+ << n.getConst<FloatingPointToFPGeneric>().d_fp_size.exponentWidth()
+ << ' '
+ << n.getConst<FloatingPointToFPGeneric>().d_fp_size.significandWidth()
<< ")";
break;
case kind::FLOATINGPOINT_TO_UBV_OP:
- out << "(_ fp.to_ubv " << n.getConst<FloatingPointToUBV>().bvs.d_size
- << ")";
+ out << "(_ fp.to_ubv "
+ << n.getConst<FloatingPointToUBV>().d_bv_size.d_size << ")";
break;
case kind::FLOATINGPOINT_TO_SBV_OP:
- out << "(_ fp.to_sbv " << n.getConst<FloatingPointToSBV>().bvs.d_size
- << ")";
+ out << "(_ fp.to_sbv "
+ << n.getConst<FloatingPointToSBV>().d_bv_size.d_size << ")";
break;
case kind::FLOATINGPOINT_TO_UBV_TOTAL_OP:
out << "(_ fp.to_ubv_total "
- << n.getConst<FloatingPointToUBVTotal>().bvs.d_size << ")";
+ << n.getConst<FloatingPointToUBVTotal>().d_bv_size.d_size << ")";
break;
case kind::FLOATINGPOINT_TO_SBV_TOTAL_OP:
out << "(_ fp.to_sbv_total "
- << n.getConst<FloatingPointToSBVTotal>().bvs.d_size << ")";
+ << n.getConst<FloatingPointToSBVTotal>().d_bv_size.d_size << ")";
+ break;
+ case kind::REGEXP_REPEAT_OP:
+ out << "(_ re.^ " << n.getConst<RegExpRepeat>().d_repeatAmount << ")";
+ break;
+ case kind::REGEXP_LOOP_OP:
+ out << "(_ re.loop " << n.getConst<RegExpLoop>().d_loopMinOcc << " "
+ << n.getConst<RegExpLoop>().d_loopMaxOcc << ")";
break;
default:
// fall back on whatever operator<< does on underlying type; we
@@ -365,7 +445,7 @@ void Smt2Printer::toStream(std::ostream& out,
if(n.getNumChildren() != 0) {
for(unsigned i = 0; i < n.getNumChildren(); ++i) {
out << ' ';
- toStream(out, n[i], toDepth, types, TypeNode::null());
+ toStream(out, n[i], toDepth);
}
out << ')';
}
@@ -374,16 +454,18 @@ void Smt2Printer::toStream(std::ostream& out,
// determine if we are printing out a type ascription, store the argument of
// the type ascription into type_asc_arg.
+ Kind k = n.getKind();
Node type_asc_arg;
- if (n.getKind() == kind::APPLY_TYPE_ASCRIPTION)
+ TypeNode force_nt;
+ if (k == kind::APPLY_TYPE_ASCRIPTION)
{
- force_nt = TypeNode::fromType(
- n.getOperator().getConst<AscriptionType>().getType());
+ force_nt = n.getOperator().getConst<AscriptionType>().getType();
type_asc_arg = n[0];
}
- else if (!force_nt.isNull() && n.getType() != force_nt)
+ else if (k == kind::CAST_TO_REAL)
{
- type_asc_arg = n;
+ force_nt = nm->realType();
+ type_asc_arg = n[0];
}
if (!type_asc_arg.isNull())
{
@@ -394,26 +476,31 @@ void Smt2Printer::toStream(std::ostream& out,
// or the logic is non-linear, whereas (to_real x) is compliant when
// the logic is mixed int/real. The former occurs more frequently.
bool is_int = force_nt.isInteger();
- out << "("
- << smtKindString(is_int ? kind::TO_INTEGER : kind::DIVISION,
- d_variant)
- << " ";
- toStream(out, type_asc_arg, toDepth, types, TypeNode::null());
- if (!is_int)
+ // If constant rational, print as special case
+ if (type_asc_arg.getKind() == kind::CONST_RATIONAL)
{
- out << " 1";
+ const Rational& r = type_asc_arg.getConst<Rational>();
+ toStreamRational(out, r, !is_int, d_variant);
+ }
+ else
+ {
+ out << "("
+ << smtKindString(is_int ? kind::TO_INTEGER : kind::DIVISION,
+ d_variant)
+ << " ";
+ toStream(out, type_asc_arg, toDepth, lbind);
+ if (!is_int)
+ {
+ out << " 1";
+ }
+ out << ")";
}
- out << ")";
}
else
{
// use type ascription
out << "(as ";
- toStream(out,
- type_asc_arg,
- toDepth < 0 ? toDepth : toDepth - 1,
- types,
- TypeNode::null());
+ toStream(out, type_asc_arg, toDepth < 0 ? toDepth : toDepth - 1, lbind);
out << " " << force_nt << ")";
}
return;
@@ -439,26 +526,15 @@ void Smt2Printer::toStream(std::ostream& out,
}
out << n.getId();
}
- if (types)
- {
- // print the whole type, but not *its* type
- out << ":";
- n.getType().toStream(out, language::output::LANG_SMTLIB_V2_5);
- }
-
return;
}
bool stillNeedToPrintParams = true;
bool forceBinary = false; // force N-ary to binary when outputing children
- bool parametricTypeChildren = false; // parametric operators that are (op t1 ... tn) where t1...tn must have same type
- bool typeChildren = false; // operators (op t1...tn) where at least one of t1...tn may require a type cast e.g. Int -> Real
// operator
- Kind k = n.getKind();
- if(n.getNumChildren() != 0 &&
- k != kind::INST_PATTERN_LIST &&
- k != kind::APPLY_TYPE_ASCRIPTION &&
- k != kind::CONSTRUCTOR_TYPE) {
+ if (n.getNumChildren() != 0 && k != kind::INST_PATTERN_LIST
+ && k != kind::CONSTRUCTOR_TYPE)
+ {
out << '(';
}
switch(k) {
@@ -466,14 +542,13 @@ void Smt2Printer::toStream(std::ostream& out,
case kind::EQUAL:
case kind::DISTINCT:
out << smtKindString(k, d_variant) << " ";
- parametricTypeChildren = true;
break;
case kind::FUNCTION_TYPE:
out << "->";
for (Node nc : n)
{
out << " ";
- toStream(out, nc, toDepth, types, TypeNode::null());
+ toStream(out, nc, toDepth);
}
out << ")";
return;
@@ -490,7 +565,7 @@ void Smt2Printer::toStream(std::ostream& out,
break;
// uf theory
- case kind::APPLY_UF: typeChildren = true; break;
+ case kind::APPLY_UF: break;
// higher-order
case kind::HO_APPLY:
if (!options::flattenHOChains())
@@ -510,20 +585,19 @@ void Smt2Printer::toStream(std::ostream& out,
args.insert(args.begin(), head[1]);
head = head[0];
}
- toStream(out, head, toDepth, types, TypeNode::null());
+ toStream(out, head, toDepth, lbind);
for (unsigned i = 0, size = args.size(); i < size; ++i)
{
out << " ";
- toStream(out, args[i], toDepth, types, TypeNode::null());
+ toStream(out, args[i], toDepth, lbind);
}
out << ")";
}
return;
- case kind::LAMBDA: out << smtKindString(k, d_variant) << " "; break;
case kind::MATCH:
out << smtKindString(k, d_variant) << " ";
- toStream(out, n[0], toDepth, types, TypeNode::null());
+ toStream(out, n[0], toDepth, lbind);
out << " (";
for (size_t i = 1, nchild = n.getNumChildren(); i < nchild; i++)
{
@@ -531,21 +605,20 @@ void Smt2Printer::toStream(std::ostream& out,
{
out << " ";
}
- toStream(out, n[i], toDepth, types, TypeNode::null());
+ toStream(out, n[i], toDepth, lbind);
}
out << "))";
return;
case kind::MATCH_BIND_CASE:
// ignore the binder
- toStream(out, n[1], toDepth, types, TypeNode::null());
+ toStream(out, n[1], toDepth, lbind);
out << " ";
- toStream(out, n[2], toDepth, types, TypeNode::null());
+ toStream(out, n[2], toDepth, lbind);
out << ")";
return;
case kind::MATCH_CASE:
// do nothing
break;
- case kind::WITNESS: out << smtKindString(k, d_variant) << " "; break;
// arith theory
case kind::PLUS:
@@ -583,7 +656,6 @@ void Smt2Printer::toStream(std::ostream& out,
case kind::TO_INTEGER:
case kind::TO_REAL:
case kind::POW:
- parametricTypeChildren = true;
out << smtKindString(k, d_variant) << " ";
break;
case kind::IAND:
@@ -598,7 +670,7 @@ void Smt2Printer::toStream(std::ostream& out,
// arrays theory
case kind::SELECT:
- case kind::STORE: typeChildren = true; CVC4_FALLTHROUGH;
+ case kind::STORE:
case kind::PARTIAL_SELECT_0:
case kind::PARTIAL_SELECT_1:
case kind::ARRAY_TYPE:
@@ -642,12 +714,20 @@ void Smt2Printer::toStream(std::ostream& out,
case kind::REGEXP_PLUS:
case kind::REGEXP_OPT:
case kind::REGEXP_RANGE:
- case kind::REGEXP_LOOP:
case kind::REGEXP_COMPLEMENT:
+ case kind::REGEXP_DIFF:
case kind::REGEXP_EMPTY:
case kind::REGEXP_SIGMA:
case kind::SEQ_UNIT:
+ case kind::SEQ_NTH:
case kind::SEQUENCE_TYPE: out << smtKindString(k, d_variant) << " "; break;
+ case kind::REGEXP_REPEAT:
+ case kind::REGEXP_LOOP:
+ {
+ out << n.getOperator() << ' ';
+ stillNeedToPrintParams = false;
+ break;
+ }
case kind::CARDINALITY_CONSTRAINT: out << "fmf.card "; break;
case kind::CARDINALITY_VALUE: out << "fmf.card.val "; break;
@@ -713,18 +793,30 @@ void Smt2Printer::toStream(std::ostream& out,
case kind::PRODUCT:
case kind::TRANSPOSE:
case kind::TCLOSURE:
- parametricTypeChildren = true;
out << smtKindString(k, d_variant) << " ";
break;
case kind::COMPREHENSION: out << smtKindString(k, d_variant) << " "; break;
- case kind::MEMBER: typeChildren = true; CVC4_FALLTHROUGH;
+ case kind::SINGLETON:
+ {
+ out << smtKindString(k, d_variant) << " ";
+ TypeNode elemType = n.getType().getSetElementType();
+ toStreamCastToType(
+ out, n[0], toDepth < 0 ? toDepth : toDepth - 1, elemType);
+ out << ")";
+ return;
+ }
+ break;
+ case kind::MEMBER:
case kind::INSERT:
case kind::SET_TYPE:
- case kind::SINGLETON:
case kind::COMPLEMENT:
- case kind::CHOOSE: out << smtKindString(k, d_variant) << " "; break;
+ case kind::CHOOSE:
+ case kind::IS_SINGLETON: out << smtKindString(k, d_variant) << " "; break;
case kind::UNIVERSE_SET:out << "(as univset " << n.getType() << ")";break;
+ // bags
+ case kind::BAG_TYPE: out << smtKindString(k, d_variant) << " "; break;
+
// fp theory
case kind::FLOATINGPOINT_FP:
case kind::FLOATINGPOINT_EQ:
@@ -776,8 +868,7 @@ void Smt2Printer::toStream(std::ostream& out,
case kind::APPLY_CONSTRUCTOR:
{
- typeChildren = true;
- const Datatype& dt = Datatype::datatypeOf(n.getOperator().toExpr());
+ const DType& dt = DType::datatypeOf(n.getOperator());
if (dt.isTuple())
{
stillNeedToPrintParams = false;
@@ -809,23 +900,16 @@ void Smt2Printer::toStream(std::ostream& out,
// quantifiers
case kind::FORALL:
case kind::EXISTS:
+ case kind::LAMBDA:
+ case kind::WITNESS:
{
- if (k == kind::FORALL)
- {
- out << "forall ";
- }
- else
- {
- out << "exists ";
- }
- for (unsigned i = 0; i < 2; i++)
+ out << smtKindString(k, d_variant) << " ";
+ if (n.getNumChildren() == 3)
{
- out << n[i] << " ";
- if (i == 0 && n.getNumChildren() == 3)
- {
- out << "(! ";
- }
+ out << "(! ";
}
+ out << n[0] << " ";
+ toStreamWithLetify(out, n[1], toDepth - 1, lbind);
if (n.getNumChildren() == 3)
{
out << n[2];
@@ -841,7 +925,7 @@ void Smt2Printer::toStream(std::ostream& out,
for (TNode::iterator i = n.begin(), iend = n.end(); i != iend;)
{
out << '(';
- toStream(out, *i, toDepth < 0 ? toDepth : toDepth - 1, types, 0);
+ toStream(out, *i, toDepth < 0 ? toDepth : toDepth - 1);
out << ' ';
out << (*i).getType();
out << ')';
@@ -882,19 +966,24 @@ void Smt2Printer::toStream(std::ostream& out,
if(toDepth != 0) {
if (n.getKind() == kind::APPLY_TESTER)
{
- unsigned cindex = Datatype::indexOf(n.getOperator().toExpr());
- const Datatype& dt = Datatype::datatypeOf(n.getOperator().toExpr());
+ unsigned cindex = DType::indexOf(n.getOperator().toExpr());
+ const DType& dt = DType::datatypeOf(n.getOperator().toExpr());
if (isVariant_2_6(d_variant))
{
out << "(_ is ";
- toStream(out, Node::fromExpr(dt[cindex].getConstructor()), toDepth < 0 ? toDepth : toDepth - 1, types, TypeNode::null());
+ toStream(out,
+ dt[cindex].getConstructor(),
+ toDepth < 0 ? toDepth : toDepth - 1);
out << ")";
}else{
out << "is-";
- toStream(out, Node::fromExpr(dt[cindex].getConstructor()), toDepth < 0 ? toDepth : toDepth - 1, types, TypeNode::null());
+ toStream(out,
+ dt[cindex].getConstructor(),
+ toDepth < 0 ? toDepth : toDepth - 1);
}
}else{
- toStream(out, n.getOperator(), toDepth < 0 ? toDepth : toDepth - 1, types, TypeNode::null());
+ toStream(
+ out, n.getOperator(), toDepth < 0 ? toDepth : toDepth - 1, lbind);
}
} else {
out << "(...)";
@@ -905,74 +994,9 @@ void Smt2Printer::toStream(std::ostream& out,
}
stringstream parens;
- // calculate the child type casts
- std::map< unsigned, TypeNode > force_child_type;
- if( parametricTypeChildren ){
- if( n.getNumChildren()>1 ){
- TypeNode force_ct = n[0].getType();
- bool do_force = false;
- for(size_t i = 1; i < n.getNumChildren(); ++i ) {
- TypeNode ct = n[i].getType();
- if( ct!=force_ct ){
- force_ct = TypeNode::leastCommonTypeNode( force_ct, ct );
- do_force = true;
- }
- }
- if( do_force ){
- for(size_t i = 0; i < n.getNumChildren(); ++i ) {
- force_child_type[i] = force_ct;
- }
- }
- }
- // operators that may require type casting
- }else if( typeChildren ){
- if(n.getKind()==kind::SELECT){
- TypeNode indexType = TypeNode::leastCommonTypeNode( n[0].getType().getArrayIndexType(), n[1].getType() );
- TypeNode elemType = n[0].getType().getArrayConstituentType();
- force_child_type[0] = NodeManager::currentNM()->mkArrayType( indexType, elemType );
- force_child_type[1] = indexType;
- }else if(n.getKind()==kind::STORE){
- TypeNode indexType = TypeNode::leastCommonTypeNode( n[0].getType().getArrayIndexType(), n[1].getType() );
- TypeNode elemType = TypeNode::leastCommonTypeNode( n[0].getType().getArrayConstituentType(), n[2].getType() );
- force_child_type[0] = NodeManager::currentNM()->mkArrayType( indexType, elemType );
- force_child_type[1] = indexType;
- force_child_type[2] = elemType;
- }else if(n.getKind()==kind::MEMBER){
- TypeNode elemType = TypeNode::leastCommonTypeNode( n[0].getType(), n[1].getType().getSetElementType() );
- force_child_type[0] = elemType;
- force_child_type[1] = NodeManager::currentNM()->mkSetType( elemType );
- }else{
- // APPLY_UF, APPLY_CONSTRUCTOR, etc.
- Assert(n.hasOperator());
- TypeNode opt = n.getOperator().getType();
- if (n.getKind() == kind::APPLY_CONSTRUCTOR)
- {
- Type tn = n.getType().toType();
- // may be parametric, in which case the constructor type must be
- // specialized
- const Datatype& dt = static_cast<DatatypeType>(tn).getDatatype();
- if (dt.isParametric())
- {
- unsigned ci = Datatype::indexOf(n.getOperator().toExpr());
- opt = TypeNode::fromType(dt[ci].getSpecializedConstructorType(tn));
- }
- }
- Assert(opt.getNumChildren() == n.getNumChildren() + 1);
- for(size_t i = 0; i < n.getNumChildren(); ++i ) {
- force_child_type[i] = opt[i];
- }
- }
- }
-
for(size_t i = 0, c = 1; i < n.getNumChildren(); ) {
if(toDepth != 0) {
- Node cn = n[i];
- std::map< unsigned, TypeNode >::iterator itfc = force_child_type.find( i );
- if( itfc!=force_child_type.end() ){
- toStream(out, cn, toDepth < 0 ? toDepth : toDepth - c, types, itfc->second);
- }else{
- toStream(out, cn, toDepth < 0 ? toDepth : toDepth - c, types, TypeNode::null());
- }
+ toStream(out, n[i], toDepth < 0 ? toDepth : toDepth - c, lbind);
} else {
out << "(...)";
}
@@ -988,10 +1012,30 @@ void Smt2Printer::toStream(std::ostream& out,
}
}
}
- if(n.getNumChildren() != 0) {
+ if (n.getNumChildren() != 0)
+ {
out << parens.str() << ')';
}
-}/* Smt2Printer::toStream(TNode) */
+}
+
+void Smt2Printer::toStreamCastToType(std::ostream& out,
+ TNode n,
+ int toDepth,
+ TypeNode tn) const
+{
+ Node nasc;
+ if (n.getType().isInteger() && !tn.isInteger())
+ {
+ Assert(tn.isReal());
+ // probably due to subtyping integers and reals, cast it
+ nasc = NodeManager::currentNM()->mkNode(kind::CAST_TO_REAL, n);
+ }
+ else
+ {
+ nasc = n;
+ }
+ toStream(out, nasc, toDepth);
+}
static string smtKindString(Kind k, Variant v)
{
@@ -1012,8 +1056,7 @@ static string smtKindString(Kind k, Variant v)
// uf theory
case kind::APPLY_UF: break;
- case kind::LAMBDA:
- return "lambda";
+ case kind::LAMBDA: return "lambda";
case kind::MATCH: return "match";
case kind::WITNESS: return "witness";
@@ -1119,11 +1162,14 @@ static string smtKindString(Kind k, Variant v)
case kind::CARD: return "card";
case kind::COMPREHENSION: return "comprehension";
case kind::CHOOSE: return "choose";
+ case kind::IS_SINGLETON: return "is_singleton";
case kind::JOIN: return "join";
case kind::PRODUCT: return "product";
case kind::TRANSPOSE: return "transpose";
- case kind::TCLOSURE:
- return "tclosure";
+ case kind::TCLOSURE: return "tclosure";
+
+ // bag theory
+ case kind::BAG_TYPE: return "Bag";
// fp theory
case kind::FLOATINGPOINT_FP: return "fp";
@@ -1212,10 +1258,13 @@ static string smtKindString(Kind k, Variant v)
case kind::REGEXP_PLUS: return "re.+";
case kind::REGEXP_OPT: return "re.opt";
case kind::REGEXP_RANGE: return "re.range";
+ case kind::REGEXP_REPEAT: return "re.^";
case kind::REGEXP_LOOP: return "re.loop";
case kind::REGEXP_COMPLEMENT: return "re.comp";
+ case kind::REGEXP_DIFF: return "re.diff";
case kind::SEQUENCE_TYPE: return "Seq";
case kind::SEQ_UNIT: return "seq.unit";
+ case kind::SEQ_NTH: return "seq.nth";
//sep theory
case kind::SEP_STAR: return "sep";
@@ -1223,6 +1272,10 @@ static string smtKindString(Kind k, Variant v)
case kind::SEP_WAND: return "wand";
case kind::SEP_EMP: return "emp";
+ // quantifiers
+ case kind::FORALL: return "forall";
+ case kind::EXISTS: return "exists";
+
default:
; /* fall through */
}
@@ -1236,66 +1289,6 @@ static bool tryToStream(std::ostream& out, const Command* c);
template <class T>
static bool tryToStream(std::ostream& out, const Command* c, Variant v);
-void Smt2Printer::toStream(std::ostream& out,
- const Command* c,
- int toDepth,
- bool types,
- size_t dag) const
-{
- expr::ExprSetDepth::Scope sdScope(out, toDepth);
- expr::ExprPrintTypes::Scope ptScope(out, types);
- expr::ExprDag::Scope dagScope(out, dag);
-
- if (tryToStream<AssertCommand>(out, c) || tryToStream<PushCommand>(out, c)
- || tryToStream<PopCommand>(out, c) || tryToStream<CheckSatCommand>(out, c)
- || tryToStream<CheckSatAssumingCommand>(out, c)
- || tryToStream<QueryCommand>(out, c, d_variant)
- || tryToStream<ResetCommand>(out, c)
- || tryToStream<ResetAssertionsCommand>(out, c)
- || tryToStream<QuitCommand>(out, c)
- || tryToStream<DeclarationSequence>(out, c)
- || tryToStream<CommandSequence>(out, c)
- || tryToStream<DeclareFunctionCommand>(out, c)
- || tryToStream<DeclareTypeCommand>(out, c)
- || tryToStream<DefineTypeCommand>(out, c)
- || tryToStream<DefineNamedFunctionCommand>(out, c)
- || tryToStream<DefineFunctionCommand>(out, c)
- || tryToStream<DefineFunctionRecCommand>(out, c)
- || tryToStream<SimplifyCommand>(out, c)
- || tryToStream<GetValueCommand>(out, c)
- || tryToStream<GetModelCommand>(out, c)
- || tryToStream<GetAssignmentCommand>(out, c)
- || tryToStream<GetAssertionsCommand>(out, c)
- || tryToStream<GetProofCommand>(out, c)
- || tryToStream<GetUnsatAssumptionsCommand>(out, c)
- || tryToStream<GetUnsatCoreCommand>(out, c)
- || tryToStream<SetBenchmarkStatusCommand>(out, c, d_variant)
- || tryToStream<SetBenchmarkLogicCommand>(out, c, d_variant)
- || tryToStream<SetInfoCommand>(out, c, d_variant)
- || tryToStream<GetInfoCommand>(out, c)
- || tryToStream<SetOptionCommand>(out, c)
- || tryToStream<GetOptionCommand>(out, c)
- || tryToStream<DatatypeDeclarationCommand>(out, c, d_variant)
- || tryToStream<CommentCommand>(out, c, d_variant)
- || tryToStream<EmptyCommand>(out, c)
- || tryToStream<EchoCommand>(out, c, d_variant)
- || tryToStream<SynthFunCommand>(out, c)
- || tryToStream<DeclareSygusFunctionCommand>(out, c)
- || tryToStream<DeclareSygusVarCommand>(out, c)
- || tryToStream<SygusConstraintCommand>(out, c)
- || tryToStream<SygusInvConstraintCommand>(out, c)
- || tryToStream<CheckSynthCommand>(out, c)
- || tryToStream<GetAbductCommand>(out, c))
- {
- return;
- }
-
- out << "ERROR: don't know how to print a Command of class: "
- << typeid(*c).name() << endl;
-
-}/* Smt2Printer::toStream(Command*) */
-
-
static std::string quoteSymbol(TNode n) {
std::stringstream ss;
ss << n;
@@ -1323,39 +1316,46 @@ void Smt2Printer::toStream(std::ostream& out, const CommandStatus* s) const
void Smt2Printer::toStream(std::ostream& out, const UnsatCore& core) const
{
out << "(" << std::endl;
- SmtEngine * smt = core.getSmtEngine();
- Assert(smt != NULL);
- for(UnsatCore::const_iterator i = core.begin(); i != core.end(); ++i) {
- std::string name;
- if (smt->getExpressionName(*i,name)) {
- // Named assertions always get printed
- out << CVC4::quoteSymbol(name) << endl;
- } else if (options::dumpUnsatCoresFull()) {
- // Unnamed assertions only get printed if the option is set
+ if (core.useNames())
+ {
+ // use the names
+ const std::vector<std::string>& cnames = core.getCoreNames();
+ for (const std::string& cn : cnames)
+ {
+ out << CVC4::quoteSymbol(cn) << std::endl;
+ }
+ }
+ else
+ {
+ // otherwise, use the formulas
+ for (UnsatCore::const_iterator i = core.begin(); i != core.end(); ++i)
+ {
out << *i << endl;
}
}
out << ")" << endl;
}/* Smt2Printer::toStream(UnsatCore, map<Expr, string>) */
-void Smt2Printer::toStream(std::ostream& out, const Model& m) const
+void Smt2Printer::toStream(std::ostream& out, const smt::Model& m) const
{
+ const theory::TheoryModel* tm = m.getTheoryModel();
//print the model comments
std::stringstream c;
- m.getComments( c );
+ tm->getComments(c);
std::string ln;
while( std::getline( c, ln ) ){
out << "; " << ln << std::endl;
}
//print the model
- out << "(model" << endl;
+ out << "(" << endl;
// don't need to print approximations since they are built into choice
// functions in the values of variables.
this->Printer::toStream(out, m);
out << ")" << endl;
//print the heap model, if it exists
- Expr h, neq;
- if( m.getHeapModel( h, neq ) ){
+ Node h, neq;
+ if (tm->getHeapModel(h, neq))
+ {
// description of the heap+what nil is equal to fully describes model
out << "(heap" << endl;
out << h << endl;
@@ -1365,25 +1365,25 @@ void Smt2Printer::toStream(std::ostream& out, const Model& m) const
}
void Smt2Printer::toStream(std::ostream& out,
- const Model& model,
- const Command* command) const
+ const smt::Model& model,
+ const NodeCommand* command) const
{
- const theory::TheoryModel* theory_model =
- dynamic_cast<const theory::TheoryModel*>(&model);
+ const theory::TheoryModel* theory_model = model.getTheoryModel();
AlwaysAssert(theory_model != nullptr);
- if (const DeclareTypeCommand* dtc =
- dynamic_cast<const DeclareTypeCommand*>(command))
+ if (const DeclareTypeNodeCommand* dtc =
+ dynamic_cast<const DeclareTypeNodeCommand*>(command))
{
// print out the DeclareTypeCommand
- Type t = (*dtc).getType();
- if (!t.isSort())
+ TypeNode tn = dtc->getType();
+ if (!tn.isSort())
{
out << (*dtc) << endl;
}
else
{
- std::vector<Expr> elements = theory_model->getDomainElements(t);
- if (options::modelUninterpDtEnum())
+ std::vector<Node> elements = theory_model->getDomainElements(tn);
+ if (options::modelUninterpPrint()
+ == options::ModelUninterpPrintMode::DtEnum)
{
if (isVariant_2_6(d_variant))
{
@@ -1393,7 +1393,7 @@ void Smt2Printer::toStream(std::ostream& out,
{
out << "(declare-datatypes () ((" << (*dtc).getSymbol() << " ";
}
- for (const Expr& type_ref : elements)
+ for (const Node& type_ref : elements)
{
out << "(" << type_ref << ")";
}
@@ -1402,15 +1402,18 @@ void Smt2Printer::toStream(std::ostream& out,
else
{
// print the cardinality
- out << "; cardinality of " << t << " is " << elements.size() << endl;
- out << (*dtc) << endl;
+ out << "; cardinality of " << tn << " is " << elements.size() << endl;
+ if (options::modelUninterpPrint()
+ == options::ModelUninterpPrintMode::DeclSortAndFun)
+ {
+ out << (*dtc) << endl;
+ }
// print the representatives
- for (const Expr& type_ref : elements)
+ for (const Node& trn : elements)
{
- Node trn = Node::fromExpr(type_ref);
if (trn.isVar())
{
- out << "(declare-fun " << quoteSymbol(trn) << " () " << t << ")"
+ out << "(declare-fun " << quoteSymbol(trn) << " () " << tn << ")"
<< endl;
}
else
@@ -1421,11 +1424,11 @@ void Smt2Printer::toStream(std::ostream& out,
}
}
}
- else if (const DeclareFunctionCommand* dfc =
- dynamic_cast<const DeclareFunctionCommand*>(command))
+ else if (const DeclareFunctionNodeCommand* dfc =
+ dynamic_cast<const DeclareFunctionNodeCommand*>(command))
{
// print out the DeclareFunctionCommand
- Node n = Node::fromExpr((*dfc).getFunction());
+ Node n = dfc->getFunction();
if ((*dfc).getPrintInModelSetByUser())
{
if (!(*dfc).getPrintInModel())
@@ -1438,19 +1441,22 @@ void Smt2Printer::toStream(std::ostream& out,
// don't print out internal stuff
return;
}
- Node val =
- Node::fromExpr(theory_model->getSmtEngine()->getValue(n.toExpr()));
+ // We get the value from the theory model directly, which notice
+ // does not have to go through the standard SmtEngine::getValue interface.
+ Node val = theory_model->getValue(n);
if (val.getKind() == kind::LAMBDA)
{
- out << "(define-fun " << n << " " << val[0] << " "
- << n.getType().getRangeType() << " ";
+ TypeNode rangeType = n.getType().getRangeType();
+ out << "(define-fun " << n << " " << val[0] << " " << rangeType << " ";
// call toStream and force its type to be proper
- toStream(out, val[1], -1, false, n.getType().getRangeType());
+ toStreamCastToType(out, val[1], -1, rangeType);
out << ")" << endl;
}
else
{
- if (options::modelUninterpDtEnum() && val.getKind() == kind::STORE)
+ if (options::modelUninterpPrint()
+ == options::ModelUninterpPrintMode::DtEnum
+ && val.getKind() == kind::STORE)
{
TypeNode tn = val[1].getType();
const std::vector<Node>* type_refs =
@@ -1464,14 +1470,14 @@ void Smt2Printer::toStream(std::ostream& out,
}
out << "(define-fun " << n << " () " << n.getType() << " ";
// call toStream and force its type to be proper
- toStream(out, val, -1, false, n.getType());
+ toStreamCastToType(out, val, -1, n.getType());
out << ")" << endl;
}
}
- else if (const DatatypeDeclarationCommand* datatype_declaration_command =
- dynamic_cast<const DatatypeDeclarationCommand*>(command))
+ else if (const DeclareDatatypeNodeCommand* declare_datatype_command =
+ dynamic_cast<const DeclareDatatypeNodeCommand*>(command))
{
- toStream(out, datatype_declaration_command, -1, false, 1);
+ out << *declare_datatype_command;
}
else
{
@@ -1479,147 +1485,151 @@ void Smt2Printer::toStream(std::ostream& out,
}
}
-static void toStream(std::ostream& out, const AssertCommand* c)
+void Smt2Printer::toStreamCmdAssert(std::ostream& out, Node n) const
{
- out << "(assert " << c->getExpr() << ")";
+ out << "(assert " << n << ')' << std::endl;
}
-static void toStream(std::ostream& out, const PushCommand* c)
+void Smt2Printer::toStreamCmdPush(std::ostream& out) const
{
- out << "(push 1)";
+ out << "(push 1)" << std::endl;
}
-static void toStream(std::ostream& out, const PopCommand* c)
+void Smt2Printer::toStreamCmdPop(std::ostream& out) const
{
- out << "(pop 1)";
+ out << "(pop 1)" << std::endl;
}
-static void toStream(std::ostream& out, const CheckSatCommand* c)
+void Smt2Printer::toStreamCmdCheckSat(std::ostream& out, Node n) const
{
- Expr e = c->getExpr();
- if(!e.isNull() && !(e.getKind() == kind::CONST_BOOLEAN && e.getConst<bool>())) {
- out << PushCommand() << endl
- << AssertCommand(e) << endl
- << CheckSatCommand() << endl
- << PopCommand();
- } else {
+ if (!n.isNull())
+ {
+ toStreamCmdPush(out);
+ out << std::endl;
+ toStreamCmdAssert(out, n);
+ out << std::endl;
+ toStreamCmdCheckSat(out);
+ out << std::endl;
+ toStreamCmdPop(out);
+ }
+ else
+ {
out << "(check-sat)";
}
+ out << std::endl;
}
-static void toStream(std::ostream& out, const CheckSatAssumingCommand* c)
+void Smt2Printer::toStreamCmdCheckSatAssuming(
+ std::ostream& out, const std::vector<Node>& nodes) const
{
out << "(check-sat-assuming ( ";
- const vector<Expr>& terms = c->getTerms();
- copy(terms.begin(), terms.end(), ostream_iterator<Expr>(out, " "));
- out << "))";
+ copy(nodes.begin(), nodes.end(), ostream_iterator<Node>(out, " "));
+ out << "))" << std::endl;
}
-static void toStream(std::ostream& out, const QueryCommand* c, Variant v)
+void Smt2Printer::toStreamCmdQuery(std::ostream& out, Node n) const
{
- Expr e = c->getExpr();
- if(!e.isNull()) {
- if (v == smt2_0_variant)
+ if (!n.isNull())
+ {
+ if (d_variant == smt2_0_variant)
{
- out << PushCommand() << endl
- << AssertCommand(BooleanSimplification::negate(e)) << endl
- << CheckSatCommand() << endl
- << PopCommand();
+ toStreamCmdCheckSat(out, BooleanSimplification::negate(n));
}
else
{
- out << CheckSatAssumingCommand(e.notExpr()) << endl;
+ toStreamCmdCheckSatAssuming(out, {n});
}
- } else {
- out << "(check-sat)";
+ }
+ else
+ {
+ toStreamCmdCheckSat(out);
}
}
-static void toStream(std::ostream& out, const ResetCommand* c)
+void Smt2Printer::toStreamCmdReset(std::ostream& out) const
{
- out << "(reset)";
+ out << "(reset)" << std::endl;
}
-static void toStream(std::ostream& out, const ResetAssertionsCommand* c)
+void Smt2Printer::toStreamCmdResetAssertions(std::ostream& out) const
{
- out << "(reset-assertions)";
+ out << "(reset-assertions)" << std::endl;
}
-static void toStream(std::ostream& out, const QuitCommand* c)
+void Smt2Printer::toStreamCmdQuit(std::ostream& out) const
{
- out << "(exit)";
+ out << "(exit)" << std::endl;
}
-static void toStream(std::ostream& out, const CommandSequence* c)
+void Smt2Printer::toStreamCmdCommandSequence(
+ std::ostream& out, const std::vector<Command*>& sequence) const
{
- CommandSequence::const_iterator i = c->begin();
- if(i != c->end()) {
- for(;;) {
- out << *i;
- if(++i != c->end()) {
- out << endl;
- } else {
- break;
- }
- }
+ for (Command* i : sequence)
+ {
+ out << *i;
}
}
-static void toStream(std::ostream& out, const DeclareFunctionCommand* c)
+void Smt2Printer::toStreamCmdDeclarationSequence(
+ std::ostream& out, const std::vector<Command*>& sequence) const
+{
+ toStreamCmdCommandSequence(out, sequence);
+}
+
+void Smt2Printer::toStreamCmdDeclareFunction(std::ostream& out,
+ const std::string& id,
+ TypeNode type) const
{
- Type type = c->getType();
- out << "(declare-fun " << CVC4::quoteSymbol(c->getSymbol()) << " (";
- if(type.isFunction()) {
- FunctionType ft = type;
- const vector<Type> argTypes = ft.getArgTypes();
- if(argTypes.size() > 0) {
- copy( argTypes.begin(), argTypes.end() - 1,
- ostream_iterator<Type>(out, " ") );
+ out << "(declare-fun " << CVC4::quoteSymbol(id) << " (";
+ if (type.isFunction())
+ {
+ const vector<TypeNode> argTypes = type.getArgTypes();
+ if (argTypes.size() > 0)
+ {
+ copy(argTypes.begin(),
+ argTypes.end() - 1,
+ ostream_iterator<TypeNode>(out, " "));
out << argTypes.back();
}
- type = ft.getRangeType();
+ type = type.getRangeType();
}
- out << ") " << type << ")";
+ out << ") " << type << ')' << std::endl;
}
-static void toStream(std::ostream& out, const DefineFunctionCommand* c)
+void Smt2Printer::toStreamCmdDefineFunction(std::ostream& out,
+ const std::string& id,
+ const std::vector<Node>& formals,
+ TypeNode range,
+ Node formula) const
{
- Expr func = c->getFunction();
- const vector<Expr>* formals = &c->getFormals();
- out << "(define-fun " << func << " (";
- Type type = func.getType();
- Expr formula = c->getFormula();
- if(type.isFunction()) {
- 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 << "(define-fun " << id << " (";
+ if (!formals.empty())
+ {
+ vector<Node>::const_iterator i = formals.cbegin();
+ for (;;)
+ {
out << "(" << (*i) << " " << (*i).getType() << ")";
++i;
- if(i != formals->end()) {
+ if (i != formals.cend())
+ {
out << " ";
- } else {
+ }
+ else
+ {
break;
}
}
- type = FunctionType(type).getRangeType();
}
- out << ") " << type << " " << formula << ")";
+ out << ") " << range << ' ' << formula << ')' << std::endl;
}
-static void toStream(std::ostream& out, const DefineFunctionRecCommand* c)
+void Smt2Printer::toStreamCmdDefineFunctionRec(
+ std::ostream& out,
+ const std::vector<Node>& funcs,
+ const std::vector<std::vector<Node>>& formals,
+ const std::vector<Node>& formulas) const
{
- const vector<api::Term>& funcs = c->getFunctions();
- const vector<vector<api::Term> >& formals = c->getFormals();
out << "(define-fun";
if (funcs.size() > 1)
{
@@ -1642,10 +1652,10 @@ static void toStream(std::ostream& out, const DefineFunctionRecCommand* c)
}
out << funcs[i] << " (";
// print its type signature
- vector<api::Term>::const_iterator itf = formals[i].begin();
+ vector<Node>::const_iterator itf = formals[i].cbegin();
for (;;)
{
- out << "(" << (*itf) << " " << (*itf).getSort() << ")";
+ out << "(" << (*itf) << " " << (*itf).getType() << ")";
++itf;
if (itf != formals[i].end())
{
@@ -1656,8 +1666,8 @@ static void toStream(std::ostream& out, const DefineFunctionRecCommand* c)
break;
}
}
- api::Sort type = funcs[i].getSort();
- type = type.getFunctionCodomainSort();
+ TypeNode type = funcs[i].getType();
+ type = type.getRangeType();
out << ") " << type;
if (funcs.size() > 1)
{
@@ -1668,7 +1678,6 @@ static void toStream(std::ostream& out, const DefineFunctionRecCommand* c)
{
out << ") (";
}
- const vector<api::Term>& formulas = c->getFormulas();
for (unsigned i = 0, size = formulas.size(); i < size; i++)
{
if (i > 0)
@@ -1681,178 +1690,143 @@ static void toStream(std::ostream& out, const DefineFunctionRecCommand* c)
{
out << ")";
}
- out << ")";
-}
-
-static void toStreamRational(std::ostream& out,
- const Rational& r,
- bool decimal,
- Variant v)
-{
- bool neg = r.sgn() < 0;
- // Print the rational, possibly as decimal.
- // Notice that we print (/ (- 5) 3) instead of (- (/ 5 3)),
- // the former is compliant with real values in the smt lib standard.
- if(r.isIntegral()) {
- if (neg)
- {
- out << (v == sygus_variant ? "-" : "(- ") << -r;
- }
- else
- {
- out << r;
- }
- if (decimal) { out << ".0"; }
- if (neg)
- {
- out << (v == sygus_variant ? "" : ")");
- }
- }else{
- out << "(/ ";
- if(neg) {
- Rational abs_r = (-r);
- out << (v == sygus_variant ? "-" : "(- ") << abs_r.getNumerator();
- out << (v == sygus_variant ? " " : ") ") << abs_r.getDenominator();
- }else{
- out << r.getNumerator();
- out << ' ' << r.getDenominator();
- }
- out << ')';
- }
+ out << ")" << std::endl;
}
-static void toStream(std::ostream& out, const DeclareTypeCommand* c)
+void Smt2Printer::toStreamCmdDeclareType(std::ostream& out,
+ const std::string& id,
+ size_t arity,
+ TypeNode type) const
{
- out << "(declare-sort " << CVC4::quoteSymbol(c->getSymbol()) << " "
- << c->getArity() << ")";
+ out << "(declare-sort " << CVC4::quoteSymbol(id) << " " << arity << ")"
+ << std::endl;
}
-static void toStream(std::ostream& out, const DefineTypeCommand* c)
+void Smt2Printer::toStreamCmdDefineType(std::ostream& out,
+ const std::string& id,
+ const std::vector<TypeNode>& params,
+ TypeNode t) const
{
- const vector<Type>& params = c->getParameters();
- out << "(define-sort " << c->getSymbol() << " (";
- if(params.size() > 0) {
- copy( params.begin(), params.end() - 1,
- ostream_iterator<Type>(out, " ") );
+ out << "(define-sort " << CVC4::quoteSymbol(id) << " (";
+ if (params.size() > 0)
+ {
+ copy(
+ params.begin(), params.end() - 1, ostream_iterator<TypeNode>(out, " "));
out << params.back();
}
- out << ") " << c->getType() << ")";
-}
-
-static void toStream(std::ostream& out, const DefineNamedFunctionCommand* c)
-{
- out << "DefineNamedFunction( ";
- toStream(out, static_cast<const DefineFunctionCommand*>(c));
- out << " )";
-
- out << "ERROR: don't know how to output define-named-function command" << endl;
+ out << ") " << t << ")" << std::endl;
}
-static void toStream(std::ostream& out, const SimplifyCommand* c)
+void Smt2Printer::toStreamCmdSimplify(std::ostream& out, Node n) const
{
- out << "(simplify " << c->getTerm() << ")";
+ out << "(simplify " << n << ')' << std::endl;
}
-static void toStream(std::ostream& out, const GetValueCommand* c)
+void Smt2Printer::toStreamCmdGetValue(std::ostream& out,
+ const std::vector<Node>& nodes) const
{
out << "(get-value ( ";
- const vector<Expr>& terms = c->getTerms();
- copy(terms.begin(), terms.end(), ostream_iterator<Expr>(out, " "));
- out << "))";
+ copy(nodes.begin(), nodes.end(), ostream_iterator<Node>(out, " "));
+ out << "))" << std::endl;
}
-static void toStream(std::ostream& out, const GetModelCommand* c)
+void Smt2Printer::toStreamCmdGetModel(std::ostream& out) const
{
- out << "(get-model)";
+ out << "(get-model)" << std::endl;
}
-static void toStream(std::ostream& out, const GetAssignmentCommand* c)
+void Smt2Printer::toStreamCmdGetAssignment(std::ostream& out) const
{
- out << "(get-assignment)";
+ out << "(get-assignment)" << std::endl;
}
-static void toStream(std::ostream& out, const GetAssertionsCommand* c)
+void Smt2Printer::toStreamCmdGetAssertions(std::ostream& out) const
{
- out << "(get-assertions)";
+ out << "(get-assertions)" << std::endl;
}
-static void toStream(std::ostream& out, const GetProofCommand* c)
+void Smt2Printer::toStreamCmdGetProof(std::ostream& out) const
{
- out << "(get-proof)";
+ out << "(get-proof)" << std::endl;
}
-static void toStream(std::ostream& out, const GetUnsatAssumptionsCommand* c)
+void Smt2Printer::toStreamCmdGetUnsatAssumptions(std::ostream& out) const
{
- out << "(get-unsat-assumptions)";
+ out << "(get-unsat-assumptions)" << std::endl;
}
-static void toStream(std::ostream& out, const GetUnsatCoreCommand* c)
+void Smt2Printer::toStreamCmdGetUnsatCore(std::ostream& out) const
{
- out << "(get-unsat-core)";
+ out << "(get-unsat-core)" << std::endl;
}
-static void toStream(std::ostream& out,
- const SetBenchmarkStatusCommand* c,
- Variant v)
+void Smt2Printer::toStreamCmdSetBenchmarkStatus(std::ostream& out,
+ Result::Sat status) const
{
- out << "(set-info :status " << c->getStatus() << ")";
+ out << "(set-info :status " << status << ')' << std::endl;
}
-static void toStream(std::ostream& out,
- const SetBenchmarkLogicCommand* c,
- Variant v)
+void Smt2Printer::toStreamCmdSetBenchmarkLogic(std::ostream& out,
+ const std::string& logic) const
{
- out << "(set-logic " << c->getLogic() << ")";
+ out << "(set-logic " << logic << ')' << std::endl;
}
-static void toStream(std::ostream& out, const SetInfoCommand* c, Variant v)
+void Smt2Printer::toStreamCmdSetInfo(std::ostream& out,
+ const std::string& flag,
+ SExpr sexpr) const
{
- out << "(set-info :" << c->getFlag() << " ";
- SExpr::toStream(out, c->getSExpr(), variantToLanguage(v));
- out << ")";
+ out << "(set-info :" << flag << ' ';
+ SExpr::toStream(out, sexpr, variantToLanguage(d_variant));
+ out << ')' << std::endl;
}
-static void toStream(std::ostream& out, const GetInfoCommand* c)
+void Smt2Printer::toStreamCmdGetInfo(std::ostream& out,
+ const std::string& flag) const
{
- out << "(get-info :" << c->getFlag() << ")";
+ out << "(get-info :" << flag << ')' << std::endl;
}
-static void toStream(std::ostream& out, const SetOptionCommand* c)
+void Smt2Printer::toStreamCmdSetOption(std::ostream& out,
+ const std::string& flag,
+ SExpr sexpr) const
{
- out << "(set-option :" << c->getFlag() << " ";
- SExpr::toStream(out, c->getSExpr(), language::output::LANG_SMTLIB_V2_5);
- out << ")";
+ out << "(set-option :" << flag << ' ';
+ SExpr::toStream(out, sexpr, language::output::LANG_SMTLIB_V2_5);
+ out << ')' << std::endl;
}
-static void toStream(std::ostream& out, const GetOptionCommand* c)
+void Smt2Printer::toStreamCmdGetOption(std::ostream& out,
+ const std::string& flag) const
{
- out << "(get-option :" << c->getFlag() << ")";
+ out << "(get-option :" << flag << ')' << std::endl;
}
-static void toStream(std::ostream& out, const Datatype & d) {
- for(Datatype::const_iterator ctor = d.begin(), ctor_end = d.end();
- ctor != ctor_end; ++ctor){
- if( ctor!=d.begin() ) out << " ";
- out << "(" << CVC4::quoteSymbol(ctor->getName());
-
- for(DatatypeConstructor::const_iterator arg = ctor->begin(), arg_end = ctor->end();
- arg != arg_end; ++arg){
- out << " (" << arg->getSelector() << " "
- << static_cast<SelectorType>(arg->getType()).getRangeType() << ")";
+void Smt2Printer::toStream(std::ostream& out, const DType& dt) const
+{
+ for (size_t i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
+ {
+ const DTypeConstructor& cons = dt[i];
+ if (i != 0)
+ {
+ out << " ";
+ }
+ out << "(" << CVC4::quoteSymbol(cons.getName());
+ for (size_t j = 0, nargs = cons.getNumArgs(); j < nargs; j++)
+ {
+ const DTypeSelector& arg = cons[j];
+ out << " (" << arg.getSelector() << " " << arg.getRangeType() << ")";
}
out << ")";
}
}
-static void toStream(std::ostream& out,
- const DatatypeDeclarationCommand* c,
- Variant v)
+void Smt2Printer::toStreamCmdDatatypeDeclaration(
+ std::ostream& out, const std::vector<TypeNode>& datatypes) const
{
- const std::vector<Type>& datatypes = c->getDatatypes();
Assert(!datatypes.empty());
Assert(datatypes[0].isDatatype());
- DatatypeType dt0 = DatatypeType(datatypes[0]);
- const Datatype& d0 = dt0.getDatatype();
+ const DType& d0 = datatypes[0].getDType();
if (d0.isTuple())
{
// not necessary to print tuples
@@ -1865,21 +1839,21 @@ static void toStream(std::ostream& out,
out << "co";
}
out << "datatypes";
- if (isVariant_2_6(v))
+ if (isVariant_2_6(d_variant))
{
out << " (";
- for (const Type& t : datatypes)
+ for (const TypeNode& t : datatypes)
{
Assert(t.isDatatype());
- const Datatype& d = DatatypeType(t).getDatatype();
+ const DType& d = t.getDType();
out << "(" << CVC4::quoteSymbol(d.getName());
out << " " << d.getNumParameters() << ")";
}
out << ") (";
- for (const Type& t : datatypes)
+ for (const TypeNode& t : datatypes)
{
Assert(t.isDatatype());
- const Datatype& d = DatatypeType(t).getDatatype();
+ const DType& d = t.getDType();
if (d.isParametric())
{
out << "(par (";
@@ -1911,7 +1885,7 @@ static void toStream(std::ostream& out,
for (unsigned j = 1, ndt = datatypes.size(); j < ndt; j++)
{
Assert(datatypes[j].isDatatype());
- const Datatype& dj = DatatypeType(datatypes[j]).getDatatype();
+ const DType& dj = datatypes[j].getDType();
if (dj.getNumParameters() != nparam)
{
success = false;
@@ -1948,42 +1922,57 @@ static void toStream(std::ostream& out,
out << std::endl;
}
out << ") (";
- for (const Type& t : datatypes)
+ for (const TypeNode& t : datatypes)
{
Assert(t.isDatatype());
- const Datatype& dt = DatatypeType(t).getDatatype();
+ const DType& dt = t.getDType();
out << "(" << CVC4::quoteSymbol(dt.getName()) << " ";
toStream(out, dt);
out << ")";
}
out << ")";
}
- out << ")" << endl;
+ out << ")" << std::endl;
}
-static void toStream(std::ostream& out, const CommentCommand* c, Variant v)
+void Smt2Printer::toStreamCmdComment(std::ostream& out,
+ const std::string& comment) const
{
- string s = c->getComment();
+ std::string s = comment;
size_t pos = 0;
- while((pos = s.find_first_of('"', pos)) != string::npos) {
- s.replace(pos, 1, v == smt2_0_variant ? "\\\"" : "\"\"");
+ while ((pos = s.find_first_of('"', pos)) != string::npos)
+ {
+ s.replace(pos, 1, d_variant == smt2_0_variant ? "\\\"" : "\"\"");
pos += 2;
}
- out << "(set-info :notes \"" << s << "\")";
+ out << "(set-info :notes \"" << s << "\")" << std::endl;
}
-static void toStream(std::ostream& out, const EmptyCommand* c) {}
+void Smt2Printer::toStreamCmdDeclareHeap(std::ostream& out,
+ TypeNode locType,
+ TypeNode dataType) const
+{
+ out << "(declare-heap (" << locType << " " << dataType << "))" << std::endl;
+}
+
+void Smt2Printer::toStreamCmdEmpty(std::ostream& out,
+ const std::string& name) const
+{
+ out << std::endl;
+}
-static void toStream(std::ostream& out, const EchoCommand* c, Variant v)
+void Smt2Printer::toStreamCmdEcho(std::ostream& out,
+ const std::string& output) const
{
- std::string s = c->getOutput();
+ std::string s = output;
// escape all double-quotes
size_t pos = 0;
- while((pos = s.find('"', pos)) != string::npos) {
- s.replace(pos, 1, v == smt2_0_variant ? "\\\"" : "\"\"");
+ while ((pos = s.find('"', pos)) != string::npos)
+ {
+ s.replace(pos, 1, d_variant == smt2_0_variant ? "\\\"" : "\"\"");
pos += 2;
}
- out << "(echo \"" << s << "\")";
+ out << "(echo \"" << s << "\")" << std::endl;
}
/*
@@ -1992,14 +1981,13 @@ static void toStream(std::ostream& out, const EchoCommand* c, Variant v)
--------------------------------------------------------------------------
*/
-static void toStreamSygusGrammar(std::ostream& out, const Type& t)
+static void toStreamSygusGrammar(std::ostream& out, const TypeNode& t)
{
- if (!t.isNull() && t.isDatatype()
- && static_cast<DatatypeType>(t).getDatatype().isSygus())
+ if (!t.isNull() && t.isDatatype() && t.getDType().isSygus())
{
std::stringstream types_predecl, types_list;
- std::set<Type> grammarTypes;
- std::list<Type> typesToPrint;
+ std::set<TypeNode> grammarTypes;
+ std::list<TypeNode> typesToPrint;
grammarTypes.insert(t);
typesToPrint.push_back(t);
NodeManager* nm = NodeManager::currentNM();
@@ -2009,28 +1997,28 @@ static void toStreamSygusGrammar(std::ostream& out, const Type& t)
// constructors in order
do
{
- Type curr = typesToPrint.front();
+ TypeNode curr = typesToPrint.front();
typesToPrint.pop_front();
- Assert(curr.isDatatype()
- && static_cast<DatatypeType>(curr).getDatatype().isSygus());
- const Datatype& dt = static_cast<DatatypeType>(curr).getDatatype();
+ Assert(curr.isDatatype() && curr.getDType().isSygus());
+ const DType& dt = curr.getDType();
types_list << '(' << dt.getName() << ' ' << dt.getSygusType() << " (";
types_predecl << '(' << dt.getName() << ' ' << dt.getSygusType() << ") ";
if (dt.getSygusAllowConst())
{
types_list << "(Constant " << dt.getSygusType() << ") ";
}
- for (const DatatypeConstructor& cons : dt)
+ for (size_t i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
{
+ const DTypeConstructor& cons = dt[i];
// make a sygus term
std::vector<Node> cchildren;
- cchildren.push_back(Node::fromExpr(cons.getConstructor()));
- for (const DatatypeConstructorArg& i : cons)
+ cchildren.push_back(cons.getConstructor());
+ for (size_t j = 0, nargs = cons.getNumArgs(); j < nargs; j++)
{
- Type argType = i.getRangeType();
+ TypeNode argType = cons[j].getRangeType();
std::stringstream ss;
ss << argType;
- Node bv = nm->mkBoundVar(ss.str(), TypeNode::fromType(argType));
+ Node bv = nm->mkBoundVar(ss.str(), argType);
cchildren.push_back(bv);
// if fresh type, store it for later processing
if (grammarTypes.insert(argType).second)
@@ -2040,7 +2028,8 @@ static void toStreamSygusGrammar(std::ostream& out, const Type& t)
}
Node consToPrint = nm->mkNode(kind::APPLY_CONSTRUCTOR, cchildren);
// now, print it using the conversion to builtin with external
- types_list << theory::datatypes::utils::sygusToBuiltin(consToPrint, true);
+ types_list << theory::datatypes::utils::sygusToBuiltin(consToPrint,
+ true);
types_list << ' ';
}
types_list << "))\n";
@@ -2050,19 +2039,20 @@ static void toStreamSygusGrammar(std::ostream& out, const Type& t)
}
}
-static void toStream(std::ostream& out, const SynthFunCommand* c)
+void Smt2Printer::toStreamCmdSynthFun(std::ostream& out,
+ const std::string& sym,
+ const std::vector<Node>& vars,
+ TypeNode range,
+ bool isInv,
+ TypeNode sygusType) const
{
- out << '(' << c->getCommandName() << ' ' << CVC4::quoteSymbol(c->getSymbol())
+ out << '(' << (isInv ? "synth-inv " : "synth-fun ") << CVC4::quoteSymbol(sym)
<< ' ';
- Type type = c->getFunction().getType();
- const std::vector<Expr>& vars = c->getVars();
- Assert(!type.isFunction() || !vars.empty());
out << '(';
- if (type.isFunction())
+ if (!vars.empty())
{
// print variable list
- std::vector<Expr>::const_iterator i = vars.begin(), i_end = vars.end();
- Assert(i != i_end);
+ std::vector<Node>::const_iterator i = vars.cbegin(), i_end = vars.cend();
out << '(' << *i << ' ' << i->getType() << ')';
++i;
while (i != i_end)
@@ -2070,73 +2060,61 @@ static void toStream(std::ostream& out, const SynthFunCommand* c)
out << " (" << *i << ' ' << i->getType() << ')';
++i;
}
- FunctionType ft = type;
- type = ft.getRangeType();
}
out << ')';
// if not invariant-to-synthesize, print return type
- if (!c->isInv())
+ if (!isInv)
{
- out << ' ' << type;
+ out << ' ' << range;
}
+ out << '\n';
// print grammar, if any
- toStreamSygusGrammar(out, c->getSygusType());
- out << ')';
-}
-
-static void toStream(std::ostream& out, const DeclareSygusFunctionCommand* c)
-{
- out << '(' << c->getCommandName() << ' ' << CVC4::quoteSymbol(c->getSymbol());
-
- FunctionType ft = c->getType();
- stringstream ss;
-
- for (const Type& i : ft.getArgTypes())
+ if (sygusType != TypeNode::null())
{
- ss << i << ' ';
+ toStreamSygusGrammar(out, sygusType);
}
-
- string argTypes = ss.str();
- argTypes.pop_back();
-
- out << " (" << argTypes << ") " << ft.getRangeType() << ')';
+ out << ')' << std::endl;
}
-static void toStream(std::ostream& out, const DeclareSygusVarCommand* c)
+void Smt2Printer::toStreamCmdDeclareVar(std::ostream& out,
+ Node var,
+ TypeNode type) const
{
- out << '(' << c->getCommandName() << ' ' << c->getVar() << ' ' << c->getType()
- << ')';
+ out << "(declare-var " << var << ' ' << type << ')' << std::endl;
}
-static void toStream(std::ostream& out, const SygusConstraintCommand* c)
+void Smt2Printer::toStreamCmdConstraint(std::ostream& out, Node n) const
{
- out << '(' << c->getCommandName() << ' ' << c->getExpr() << ')';
+ out << "(constraint " << n << ')' << std::endl;
}
-static void toStream(std::ostream& out, const SygusInvConstraintCommand* c)
+void Smt2Printer::toStreamCmdInvConstraint(
+ std::ostream& out, Node inv, Node pre, Node trans, Node post) const
{
- out << '(' << c->getCommandName() << ' ';
- copy(c->getPredicates().cbegin(),
- c->getPredicates().cend(),
- std::ostream_iterator<Expr>(out, " "));
- out << ')';
+ out << "(inv-constraint " << inv << ' ' << pre << ' ' << trans << ' ' << post
+ << ')' << std::endl;
}
-static void toStream(std::ostream& out, const CheckSynthCommand* c)
+void Smt2Printer::toStreamCmdCheckSynth(std::ostream& out) const
{
- out << '(' << c->getCommandName() << ')';
+ out << "(check-synth)" << std::endl;
}
-static void toStream(std::ostream& out, const GetAbductCommand* c)
+void Smt2Printer::toStreamCmdGetAbduct(std::ostream& out,
+ const std::string& name,
+ Node conj,
+ TypeNode sygusType) const
{
- out << '(';
- out << c->getCommandName() << ' ';
- out << c->getAbductName() << ' ';
- out << c->getConjecture();
+ out << "(get-abduct ";
+ out << name << ' ';
+ out << conj << ' ';
// print grammar, if any
- toStreamSygusGrammar(out, c->getGrammarType());
- out << ')';
+ if (!sygusType.isNull())
+ {
+ toStreamSygusGrammar(out, sygusType);
+ }
+ out << ')' << std::endl;
}
/*
diff --git a/src/printer/smt2/smt2_printer.h b/src/printer/smt2/smt2_printer.h
index 640521a67..c83a74d97 100644
--- a/src/printer/smt2/smt2_printer.h
+++ b/src/printer/smt2/smt2_printer.h
@@ -2,10 +2,10 @@
/*! \file smt2_printer.h
** \verbatim
** Top contributors (to current version):
- ** Tim King, Andrew Reynolds, Morgan Deters
+ ** Abdalrhman Mohamed, Tim King, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,11 +19,12 @@
#ifndef CVC4__PRINTER__SMT2_PRINTER_H
#define CVC4__PRINTER__SMT2_PRINTER_H
-#include <iostream>
-
#include "printer/printer.h"
namespace CVC4 {
+
+class LetBinding;
+
namespace printer {
namespace smt2 {
@@ -33,24 +34,19 @@ enum Variant
smt2_0_variant, // old-style 2.0 syntax, when it makes a difference
smt2_6_variant, // new-style 2.6 syntax, when it makes a difference, with
// support for the string standard
- sygus_variant // variant for sygus
}; /* enum Variant */
-class Smt2Printer : public CVC4::Printer {
+
+class Smt2Printer : public CVC4::Printer
+{
public:
- Smt2Printer(Variant variant = no_variant) : d_variant(variant) { }
+ Smt2Printer(Variant variant = no_variant) : d_variant(variant) {}
using CVC4::Printer::toStream;
void toStream(std::ostream& out,
TNode n,
int toDepth,
- bool types,
- size_t dag) const override;
- void toStream(std::ostream& out,
- const Command* c,
- int toDepth,
- bool types,
size_t dag) const override;
void toStream(std::ostream& out, const CommandStatus* s) const override;
- void toStream(std::ostream& out, const Model& m) const override;
+ void toStream(std::ostream& out, const smt::Model& m) const override;
/**
* Writes the unsat core to the stream out.
* We use the expression names that are stored in the SMT engine associated
@@ -58,19 +54,213 @@ class Smt2Printer : public CVC4::Printer {
*/
void toStream(std::ostream& out, const UnsatCore& core) const override;
+ /** Print empty command */
+ void toStreamCmdEmpty(std::ostream& out,
+ const std::string& name) const override;
+
+ /** Print echo command */
+ void toStreamCmdEcho(std::ostream& out,
+ const std::string& output) const override;
+
+ /** Print assert command */
+ void toStreamCmdAssert(std::ostream& out, Node n) const override;
+
+ /** Print push command */
+ void toStreamCmdPush(std::ostream& out) const override;
+
+ /** Print pop command */
+ void toStreamCmdPop(std::ostream& out) const override;
+
+ /** Print declare-fun command */
+ void toStreamCmdDeclareFunction(std::ostream& out,
+ const std::string& id,
+ TypeNode type) const override;
+
+ /** Print declare-sort command */
+ void toStreamCmdDeclareType(std::ostream& out,
+ const std::string& id,
+ size_t arity,
+ TypeNode type) const override;
+
+ /** Print define-sort command */
+ void toStreamCmdDefineType(std::ostream& out,
+ const std::string& id,
+ const std::vector<TypeNode>& params,
+ TypeNode t) const override;
+
+ /** Print define-fun command */
+ void toStreamCmdDefineFunction(std::ostream& out,
+ const std::string& id,
+ const std::vector<Node>& formals,
+ TypeNode range,
+ Node formula) const override;
+
+ /** Print define-fun-rec command */
+ void toStreamCmdDefineFunctionRec(
+ std::ostream& out,
+ const std::vector<Node>& funcs,
+ const std::vector<std::vector<Node>>& formals,
+ const std::vector<Node>& formulas) const override;
+
+ /** Print check-sat command */
+ void toStreamCmdCheckSat(std::ostream& out,
+ Node n = Node::null()) const override;
+
+ /** Print check-sat-assuming command */
+ void toStreamCmdCheckSatAssuming(
+ std::ostream& out, const std::vector<Node>& nodes) const override;
+
+ /** Print query command */
+ void toStreamCmdQuery(std::ostream& out, Node n) const override;
+
+ /** Print declare-var command */
+ void toStreamCmdDeclareVar(std::ostream& out,
+ Node var,
+ TypeNode type) const override;
+
+ /** Print synth-fun command */
+ void toStreamCmdSynthFun(std::ostream& out,
+ const std::string& sym,
+ const std::vector<Node>& vars,
+ TypeNode range,
+ bool isInv,
+ TypeNode sygusType) const override;
+
+ /** Print constraint command */
+ void toStreamCmdConstraint(std::ostream& out, Node n) const override;
+
+ /** Print inv-constraint command */
+ void toStreamCmdInvConstraint(std::ostream& out,
+ Node inv,
+ Node pre,
+ Node trans,
+ Node post) const override;
+
+ /** Print check-synth command */
+ void toStreamCmdCheckSynth(std::ostream& out) const override;
+
+ /** Print simplify command */
+ void toStreamCmdSimplify(std::ostream& out, Node nodes) const override;
+
+ /** Print get-value command */
+ void toStreamCmdGetValue(std::ostream& out,
+ const std::vector<Node>& n) const override;
+
+ /** Print get-assignment command */
+ void toStreamCmdGetAssignment(std::ostream& out) const override;
+
+ /** Print get-model command */
+ void toStreamCmdGetModel(std::ostream& out) const override;
+
+ /** Print get-proof command */
+ void toStreamCmdGetProof(std::ostream& out) const override;
+
+ /** Print get-abduct command */
+ void toStreamCmdGetAbduct(std::ostream& out,
+ const std::string& name,
+ Node conj,
+ TypeNode sygusType) const override;
+
+ /** Print get-unsat-assumptions command */
+ void toStreamCmdGetUnsatAssumptions(std::ostream& out) const override;
+
+ /** Print get-unsat-core command */
+ void toStreamCmdGetUnsatCore(std::ostream& out) const override;
+
+ /** Print get-assertions command */
+ void toStreamCmdGetAssertions(std::ostream& out) const override;
+
+ /** Print set-info :status command */
+ void toStreamCmdSetBenchmarkStatus(std::ostream& out,
+ Result::Sat status) const override;
+
+ /** Print set-logic command */
+ void toStreamCmdSetBenchmarkLogic(std::ostream& out,
+ const std::string& logic) const override;
+
+ /** Print set-info command */
+ void toStreamCmdSetInfo(std::ostream& out,
+ const std::string& flag,
+ SExpr sexpr) const override;
+
+ /** Print get-info command */
+ void toStreamCmdGetInfo(std::ostream& out,
+ const std::string& flag) const override;
+
+ /** Print set-option command */
+ void toStreamCmdSetOption(std::ostream& out,
+ const std::string& flag,
+ SExpr sexpr) const override;
+
+ /** Print get-option command */
+ void toStreamCmdGetOption(std::ostream& out,
+ const std::string& flag) const override;
+
+ /** Print declare-datatype(s) command */
+ void toStreamCmdDatatypeDeclaration(
+ std::ostream& out, const std::vector<TypeNode>& datatypes) const override;
+
+ /** Print reset command */
+ void toStreamCmdReset(std::ostream& out) const override;
+
+ /** Print reset-assertions command */
+ void toStreamCmdResetAssertions(std::ostream& out) const override;
+
+ /** Print quit command */
+ void toStreamCmdQuit(std::ostream& out) const override;
+
+ /** Print comment command */
+ void toStreamCmdComment(std::ostream& out,
+ const std::string& comment) const override;
+
+ /** Print declare-heap command */
+ void toStreamCmdDeclareHeap(std::ostream& out,
+ TypeNode locType,
+ TypeNode dataType) const override;
+
+ /** Print command sequence command */
+ void toStreamCmdCommandSequence(
+ std::ostream& out, const std::vector<Command*>& sequence) const override;
+
+ /** Print declaration sequence command */
+ void toStreamCmdDeclarationSequence(
+ std::ostream& out, const std::vector<Command*>& sequence) const override;
+
private:
- void toStream(
- std::ostream& out, TNode n, int toDepth, bool types, TypeNode nt) const;
+ /**
+ * The main printing method for nodes n.
+ */
+ void toStream(std::ostream& out,
+ TNode n,
+ int toDepth,
+ LetBinding* lbind = nullptr) const;
+ /**
+ * To stream, with a forced type. This method is used in some corner cases
+ * to force a node n to be printed as if it had type tn. This is used e.g.
+ * for the body of define-fun commands and arguments of singleton terms.
+ */
+ void toStreamCastToType(std::ostream& out,
+ TNode n,
+ int toDepth,
+ TypeNode tn) const;
void toStream(std::ostream& out,
- const Model& m,
- const Command* c) const override;
+ const smt::Model& m,
+ const NodeCommand* c) const override;
void toStream(std::ostream& out, const SExpr& sexpr) const;
-
+ void toStream(std::ostream& out, const DType& dt) const;
+ /**
+ * To stream with let binding. This prints n, possibly in the scope
+ * of letification generated by this method based on lbind.
+ */
+ void toStreamWithLetify(std::ostream& out,
+ Node n,
+ int toDepth,
+ LetBinding* lbind) const;
Variant d_variant;
-};/* class Smt2Printer */
+}; /* class Smt2Printer */
-}/* CVC4::printer::smt2 namespace */
-}/* CVC4::printer namespace */
-}/* CVC4 namespace */
+} // namespace smt2
+} // namespace printer
+} // namespace CVC4
#endif /* CVC4__PRINTER__SMT2_PRINTER_H */
diff --git a/src/printer/tptp/tptp_printer.cpp b/src/printer/tptp/tptp_printer.cpp
index f1c1089ad..c93f3593a 100644
--- a/src/printer/tptp/tptp_printer.cpp
+++ b/src/printer/tptp/tptp_printer.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,12 +20,14 @@
#include <typeinfo>
#include <vector>
-#include "expr/expr.h" // for ExprSetDepth etc..
-#include "expr/node_manager.h" // for VarNameAttr
-#include "options/language.h" // for LANG_AST
-#include "options/smt_options.h" // for unsat cores
-#include "smt/smt_engine.h"
+#include "expr/expr.h" // for ExprSetDepth etc..
+#include "expr/node_manager.h" // for VarNameAttr
+#include "options/language.h" // for LANG_AST
+#include "options/smt_options.h" // for unsat cores
+#include "proof/unsat_core.h"
#include "smt/command.h"
+#include "smt/node_command.h"
+#include "smt/smt_engine.h"
using namespace std;
@@ -33,19 +35,12 @@ namespace CVC4 {
namespace printer {
namespace tptp {
-void TptpPrinter::toStream(
- std::ostream& out, TNode n, int toDepth, bool types, size_t dag) const
-{
- n.toStream(out, toDepth, types, dag, language::output::LANG_SMTLIB_V2_5);
-}/* TptpPrinter::toStream() */
-
void TptpPrinter::toStream(std::ostream& out,
- const Command* c,
+ TNode n,
int toDepth,
- bool types,
size_t dag) const
{
- c->toStream(out, toDepth, types, dag, language::output::LANG_SMTLIB_V2_5);
+ n.toStream(out, toDepth, dag, language::output::LANG_SMTLIB_V2_5);
}/* TptpPrinter::toStream() */
void TptpPrinter::toStream(std::ostream& out, const CommandStatus* s) const
@@ -53,7 +48,7 @@ void TptpPrinter::toStream(std::ostream& out, const CommandStatus* s) const
s->toStream(out, language::output::LANG_SMTLIB_V2_5);
}/* TptpPrinter::toStream() */
-void TptpPrinter::toStream(std::ostream& out, const Model& m) const
+void TptpPrinter::toStream(std::ostream& out, const smt::Model& m) const
{
std::string statusName(m.isKnownSat() ? "FiniteModel"
: "CandidateFiniteModel");
@@ -67,8 +62,8 @@ void TptpPrinter::toStream(std::ostream& out, const Model& m) const
}
void TptpPrinter::toStream(std::ostream& out,
- const Model& m,
- const Command* c) const
+ const smt::Model& m,
+ const NodeCommand* c) const
{
// shouldn't be called; only the non-Command* version above should be
Unreachable();
@@ -76,15 +71,20 @@ void TptpPrinter::toStream(std::ostream& out,
void TptpPrinter::toStream(std::ostream& out, const UnsatCore& core) const
{
out << "% SZS output start UnsatCore " << std::endl;
- SmtEngine * smt = core.getSmtEngine();
- Assert(smt != NULL);
- for(UnsatCore::const_iterator i = core.begin(); i != core.end(); ++i) {
- std::string name;
- if (smt->getExpressionName(*i, name)) {
- // Named assertions always get printed
- out << name << endl;
- } else if (options::dumpUnsatCoresFull()) {
- // Unnamed assertions only get printed if the option is set
+ if (core.useNames())
+ {
+ // use the names
+ const std::vector<std::string>& cnames = core.getCoreNames();
+ for (const std::string& cn : cnames)
+ {
+ out << cn << std::endl;
+ }
+ }
+ else
+ {
+ // otherwise, use the formulas
+ for (UnsatCore::const_iterator i = core.begin(); i != core.end(); ++i)
+ {
out << *i << endl;
}
}
diff --git a/src/printer/tptp/tptp_printer.h b/src/printer/tptp/tptp_printer.h
index d183a19d0..449fe409c 100644
--- a/src/printer/tptp/tptp_printer.h
+++ b/src/printer/tptp/tptp_printer.h
@@ -2,10 +2,10 @@
/*! \file tptp_printer.h
** \verbatim
** Top contributors (to current version):
- ** Tim King, Morgan Deters, Andrew Reynolds
+ ** Tim King, Abdalrhman Mohamed, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -27,35 +27,31 @@ namespace CVC4 {
namespace printer {
namespace tptp {
-class TptpPrinter : public CVC4::Printer {
+class TptpPrinter : public CVC4::Printer
+{
public:
using CVC4::Printer::toStream;
void toStream(std::ostream& out,
TNode n,
int toDepth,
- bool types,
- size_t dag) const override;
- void toStream(std::ostream& out,
- const Command* c,
- int toDepth,
- bool types,
size_t dag) const override;
void toStream(std::ostream& out, const CommandStatus* s) const override;
- void toStream(std::ostream& out, const Model& m) const override;
+ void toStream(std::ostream& out, const smt::Model& m) const override;
/** print unsat core to stream
- * We use the expression names stored in the SMT engine associated with the unsat core
- * with UnsatCore::getSmtEngine.
- */
+ * We use the expression names stored in the SMT engine associated with the
+ * unsat core with UnsatCore::getSmtEngine.
+ */
void toStream(std::ostream& out, const UnsatCore& core) const override;
private:
void toStream(std::ostream& out,
- const Model& m,
- const Command* c) const override;
-};/* class TptpPrinter */
+ const smt::Model& m,
+ const NodeCommand* c) const override;
+
+}; /* class TptpPrinter */
-}/* CVC4::printer::tptp namespace */
-}/* CVC4::printer namespace */
-}/* CVC4 namespace */
+} // namespace tptp
+} // namespace printer
+} // namespace CVC4
#endif /* CVC4__PRINTER__TPTP_PRINTER_H */
diff --git a/src/proof/arith_proof.cpp b/src/proof/arith_proof.cpp
deleted file mode 100644
index 635767b97..000000000
--- a/src/proof/arith_proof.cpp
+++ /dev/null
@@ -1,1207 +0,0 @@
-/********************* */
-/*! \file arith_proof.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Alex Ozdemir, Liana Hadarean, Guy Katz
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** [[ Add lengthier description here ]]
-
- ** \todo document this file
-
-**/
-#include "proof/arith_proof.h"
-
-#include <memory>
-#include <stack>
-
-#include "base/check.h"
-#include "expr/node.h"
-#include "expr/type_checker_util.h"
-#include "proof/proof_manager.h"
-#include "proof/theory_proof.h"
-#include "theory/arith/constraint_forward.h"
-#include "theory/arith/normal_form.h"
-#include "theory/arith/theory_arith.h"
-
-#define CVC4_ARITH_VAR_TERM_PREFIX "term."
-
-namespace CVC4 {
-
-inline static Node eqNode(TNode n1, TNode n2) {
- return NodeManager::currentNM()->mkNode(kind::EQUAL, n1, n2);
-}
-
-// congrence matching term helper
-inline static bool match(TNode n1, TNode n2) {
- Debug("pf::arith") << "match " << n1 << " " << n2 << std::endl;
- if(ProofManager::currentPM()->hasOp(n1)) {
- n1 = ProofManager::currentPM()->lookupOp(n1);
- }
- if(ProofManager::currentPM()->hasOp(n2)) {
- n2 = ProofManager::currentPM()->lookupOp(n2);
- }
- Debug("pf::arith") << "+ match " << n1 << " " << n2 << std::endl;
- if(n1 == n2) {
- return true;
- }
- if(n1.getType().isFunction() && n2.hasOperator()) {
- if(ProofManager::currentPM()->hasOp(n2.getOperator())) {
- return n1 == ProofManager::currentPM()->lookupOp(n2.getOperator());
- } else {
- return n1 == n2.getOperator();
- }
- }
- if(n2.getType().isFunction() && n1.hasOperator()) {
- if(ProofManager::currentPM()->hasOp(n1.getOperator())) {
- return n2 == ProofManager::currentPM()->lookupOp(n1.getOperator());
- } else {
- return n2 == n1.getOperator();
- }
- }
- if(n1.hasOperator() && n2.hasOperator() && n1.getOperator() != n2.getOperator()) {
- return false;
- }
- for(size_t i = 0; i < n1.getNumChildren() && i < n2.getNumChildren(); ++i) {
- if(n1[i] != n2[i]) {
- return false;
- }
- }
- return true;
-}
-
-void ProofArith::toStream(std::ostream& out) const
-{
- Trace("theory-proof-debug") << "; Print Arith proof..." << std::endl;
- //AJR : carry this further?
- ProofLetMap map;
- toStreamLFSC(out, ProofManager::getArithProof(), *d_proof, map);
-}
-
-void ProofArith::toStreamLFSC(std::ostream& out,
- TheoryProof* tp,
- const theory::eq::EqProof& pf,
- const ProofLetMap& map)
-{
- Debug("lfsc-arith") << "Printing arith proof in LFSC : " << std::endl;
- pf.debug_print("lfsc-arith");
- Debug("lfsc-arith") << std::endl;
- toStreamRecLFSC(out, tp, pf, 0, map);
-}
-
-Node ProofArith::toStreamRecLFSC(std::ostream& out,
- TheoryProof* tp,
- const theory::eq::EqProof& pf,
- unsigned tb,
- const ProofLetMap& map)
-{
- Debug("pf::arith") << std::endl
- << std::endl
- << "toStreamRecLFSC called. tb = " << tb
- << " . proof:" << std::endl;
- pf.debug_print("pf::arith");
- Debug("pf::arith") << std::endl;
-
- if(tb == 0) {
- Assert(pf.d_id == theory::eq::MERGED_THROUGH_TRANS);
- Assert(!pf.d_node.isNull());
- Assert(pf.d_children.size() >= 2);
-
- int neg = -1;
- std::shared_ptr<theory::eq::EqProof> subTrans =
- std::make_shared<theory::eq::EqProof>();
- subTrans->d_id = theory::eq::MERGED_THROUGH_TRANS;
- subTrans->d_node = pf.d_node;
-
- size_t i = 0;
- while (i < pf.d_children.size()) {
- // Look for the negative clause, with which we will form a contradiction.
- if(!pf.d_children[i]->d_node.isNull() && pf.d_children[i]->d_node.getKind() == kind::NOT) {
- Assert(neg < 0);
- neg = i;
- ++i;
- }
-
- // Handle congruence closures over equalities.
- else if (pf.d_children[i]->d_id==theory::eq::MERGED_THROUGH_CONGRUENCE && pf.d_children[i]->d_node.isNull()) {
- Debug("pf::arith") << "Handling congruence over equalities" << std::endl;
-
- // Gather the sequence of consecutive congruence closures.
- std::vector<std::shared_ptr<const theory::eq::EqProof>> congruenceClosures;
- unsigned count;
- Debug("pf::arith") << "Collecting congruence sequence" << std::endl;
- for (count = 0;
- i + count < pf.d_children.size() &&
- pf.d_children[i + count]->d_id==theory::eq::MERGED_THROUGH_CONGRUENCE &&
- pf.d_children[i + count]->d_node.isNull();
- ++count) {
- Debug("pf::arith") << "Found a congruence: " << std::endl;
- pf.d_children[i+count]->debug_print("pf::arith");
- congruenceClosures.push_back(pf.d_children[i+count]);
- }
-
- Debug("pf::arith") << "Total number of congruences found: " << congruenceClosures.size() << std::endl;
-
- // Determine if the "target" of the congruence sequence appears right before or right after the sequence.
- bool targetAppearsBefore = true;
- bool targetAppearsAfter = true;
-
- if ((i == 0) || (i == 1 && neg == 0)) {
- Debug("pf::arith") << "Target does not appear before" << std::endl;
- targetAppearsBefore = false;
- }
-
- if ((i + count >= pf.d_children.size()) ||
- (!pf.d_children[i + count]->d_node.isNull() &&
- pf.d_children[i + count]->d_node.getKind() == kind::NOT)) {
- Debug("pf::arith") << "Target does not appear after" << std::endl;
- targetAppearsAfter = false;
- }
-
- // Assert that we have precisely one target clause.
- Assert(targetAppearsBefore != targetAppearsAfter);
-
- // Begin breaking up the congruences and ordering the equalities correctly.
- std::vector<std::shared_ptr<theory::eq::EqProof>> orderedEqualities;
-
-
- // Insert target clause first.
- if (targetAppearsBefore) {
- orderedEqualities.push_back(pf.d_children[i - 1]);
- // The target has already been added to subTrans; remove it.
- subTrans->d_children.pop_back();
- } else {
- orderedEqualities.push_back(pf.d_children[i + count]);
- }
-
- // Start with the congruence closure closest to the target clause, and work our way back/forward.
- if (targetAppearsBefore) {
- for (unsigned j = 0; j < count; ++j) {
- if (pf.d_children[i + j]->d_children[0]->d_id != theory::eq::MERGED_THROUGH_REFLEXIVITY)
- orderedEqualities.insert(orderedEqualities.begin(), pf.d_children[i + j]->d_children[0]);
- if (pf.d_children[i + j]->d_children[1]->d_id != theory::eq::MERGED_THROUGH_REFLEXIVITY)
- orderedEqualities.insert(orderedEqualities.end(), pf.d_children[i + j]->d_children[1]);
- }
- } else {
- for (unsigned j = 0; j < count; ++j) {
- if (pf.d_children[i + count - 1 - j]->d_children[0]->d_id != theory::eq::MERGED_THROUGH_REFLEXIVITY)
- orderedEqualities.insert(orderedEqualities.begin(), pf.d_children[i + count - 1 - j]->d_children[0]);
- if (pf.d_children[i + count - 1 - j]->d_children[1]->d_id != theory::eq::MERGED_THROUGH_REFLEXIVITY)
- orderedEqualities.insert(orderedEqualities.end(), pf.d_children[i + count - 1 - j]->d_children[1]);
- }
- }
-
- // Copy the result into the main transitivity proof.
- subTrans->d_children.insert(subTrans->d_children.end(), orderedEqualities.begin(), orderedEqualities.end());
-
- // Increase i to skip over the children that have been processed.
- i += count;
- if (targetAppearsAfter) {
- ++i;
- }
- }
-
- // Else, just copy the child proof as is
- else {
- subTrans->d_children.push_back(pf.d_children[i]);
- ++i;
- }
- }
- Assert(neg >= 0);
-
- Node n1;
- std::stringstream ss;
- //Assert(subTrans->d_children.size() == pf.d_children.size() - 1);
- Debug("pf::arith") << "\nsubtrans has " << subTrans->d_children.size() << " children\n";
- if(pf.d_children.size() > 2) {
- n1 = toStreamRecLFSC(ss, tp, *subTrans, 1, map);
- } else {
- n1 = toStreamRecLFSC(ss, tp, *(subTrans->d_children[0]), 1, map);
- Debug("pf::arith") << "\nsubTrans unique child " << subTrans->d_children[0]->d_id << " was proven\ngot: " << n1 << std::endl;
- }
-
- Node n2 = pf.d_children[neg]->d_node;
- Assert(n2.getKind() == kind::NOT);
- out << "(clausify_false (contra _ ";
- Debug("pf::arith") << "\nhave proven: " << n1 << std::endl;
- Debug("pf::arith") << "n2 is " << n2[0] << std::endl;
-
- if (n2[0].getNumChildren() > 0) { Debug("pf::arith") << "\nn2[0]: " << n2[0][0] << std::endl; }
- if (n1.getNumChildren() > 1) { Debug("pf::arith") << "n1[1]: " << n1[1] << std::endl; }
-
- if(n2[0].getKind() == kind::APPLY_UF) {
- out << "(trans _ _ _ _ ";
- out << "(symm _ _ _ ";
- out << ss.str();
- out << ") (pred_eq_f _ " << ProofManager::getLitName(n2[0]) << ")) t_t_neq_f))" << std::endl;
- } else {
- Assert((n1[0] == n2[0][0] && n1[1] == n2[0][1])
- || (n1[1] == n2[0][0] && n1[0] == n2[0][1]));
- if(n1[1] == n2[0][0]) {
- out << "(symm _ _ _ " << ss.str() << ")";
- } else {
- out << ss.str();
- }
- out << " " << ProofManager::getLitName(n2[0]) << "))" << std::endl;
- }
- return Node();
- }
-
- switch(pf.d_id) {
- case theory::eq::MERGED_THROUGH_CONGRUENCE: {
- Debug("pf::arith") << "\nok, looking at congruence:\n";
- pf.debug_print("pf::arith");
- std::stack<const theory::eq::EqProof*> stk;
- for (const theory::eq::EqProof* pf2 = &pf;
- pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE;
- pf2 = pf2->d_children[0].get()) {
- Assert(!pf2->d_node.isNull());
- Assert(pf2->d_node.getKind() == kind::PARTIAL_APPLY_UF
- || pf2->d_node.getKind() == kind::BUILTIN
- || pf2->d_node.getKind() == kind::APPLY_UF
- || pf2->d_node.getKind() == kind::SELECT
- || pf2->d_node.getKind() == kind::STORE);
- Assert(pf2->d_children.size() == 2);
- out << "(cong _ _ _ _ _ _ ";
- stk.push(pf2);
- }
- Assert(stk.top()->d_children[0]->d_id
- != theory::eq::MERGED_THROUGH_CONGRUENCE);
- NodeBuilder<> b1(kind::PARTIAL_APPLY_UF), b2(kind::PARTIAL_APPLY_UF);
- const theory::eq::EqProof* pf2 = stk.top();
- stk.pop();
- Assert(pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE);
- Node n1 = toStreamRecLFSC(out, tp, *(pf2->d_children[0]), tb + 1, map);
- out << " ";
- std::stringstream ss;
- Node n2 = toStreamRecLFSC(ss, tp, *(pf2->d_children[1]), tb + 1, map);
- Debug("pf::arith") << "\nok, in FIRST cong[" << stk.size() << "]" << "\n";
- pf2->debug_print("pf::arith");
- Debug("pf::arith") << "looking at " << pf2->d_node << "\n";
- Debug("pf::arith") << " " << n1 << "\n";
- Debug("pf::arith") << " " << n2 << "\n";
- int side = 0;
- if(match(pf2->d_node, n1[0])) {
- //if(tb == 1) {
- Debug("pf::arith") << "SIDE IS 0\n";
- //}
- side = 0;
- } else {
- //if(tb == 1) {
- Debug("pf::arith") << "SIDE IS 1\n";
- //}
- if(!match(pf2->d_node, n1[1])) {
- Debug("pf::arith") << "IN BAD CASE, our first subproof is\n";
- pf2->d_children[0]->debug_print("pf::arith");
- }
- Assert(match(pf2->d_node, n1[1]));
- side = 1;
- }
- if(n1[side].getKind() == kind::APPLY_UF || n1[side].getKind() == kind::PARTIAL_APPLY_UF || n1[side].getKind() == kind::SELECT || n1[side].getKind() == kind::STORE) {
- if(n1[side].getKind() == kind::APPLY_UF || n1[side].getKind() == kind::PARTIAL_APPLY_UF) {
- b1 << n1[side].getOperator();
- } else {
- b1 << ProofManager::currentPM()->mkOp(n1[side].getOperator());
- }
- b1.append(n1[side].begin(), n1[side].end());
- } else {
- b1 << n1[side];
- }
- if(n1[1-side].getKind() == kind::PARTIAL_APPLY_UF || n1[1-side].getKind() == kind::APPLY_UF || n1[side].getKind() == kind::SELECT || n1[side].getKind() == kind::STORE) {
- if(n1[1-side].getKind() == kind::PARTIAL_APPLY_UF || n1[1-side].getKind() == kind::APPLY_UF) {
- b2 << n1[1-side].getOperator();
- } else {
- b2 << ProofManager::currentPM()->mkOp(n1[1-side].getOperator());
- }
- b2.append(n1[1-side].begin(), n1[1-side].end());
- } else {
- b2 << n1[1-side];
- }
- Debug("pf::arith") << "pf2->d_node " << pf2->d_node << std::endl;
- Debug("pf::arith") << "b1.getNumChildren() " << b1.getNumChildren() << std::endl;
- Debug("pf::arith") << "n1 " << n1 << std::endl;
- Debug("pf::arith") << "n2 " << n2 << std::endl;
- Debug("pf::arith") << "side " << side << std::endl;
- if(pf2->d_node[b1.getNumChildren() - (pf2->d_node.getMetaKind() == kind::metakind::PARAMETERIZED ? 0 : 1)] == n2[side]) {
- b1 << n2[side];
- b2 << n2[1-side];
- out << ss.str();
- } else {
- Assert(pf2->d_node[b1.getNumChildren()
- - (pf2->d_node.getMetaKind()
- == kind::metakind::PARAMETERIZED
- ? 0
- : 1)]
- == n2[1 - side]);
- b1 << n2[1-side];
- b2 << n2[side];
- out << "(symm _ _ _ " << ss.str() << ")";
- }
- out << ")";
- while(!stk.empty()) {
- if(tb == 1) {
- Debug("pf::arith") << "\nMORE TO DO\n";
- }
- pf2 = stk.top();
- stk.pop();
- Assert(pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE);
- out << " ";
- ss.str("");
- n2 = toStreamRecLFSC(ss, tp, *(pf2->d_children[1]), tb + 1, map);
- Debug("pf::arith") << "\nok, in cong[" << stk.size() << "]" << "\n";
- Debug("pf::arith") << "looking at " << pf2->d_node << "\n";
- Debug("pf::arith") << " " << n1 << "\n";
- Debug("pf::arith") << " " << n2 << "\n";
- Debug("pf::arith") << " " << b1 << "\n";
- Debug("pf::arith") << " " << b2 << "\n";
- if(pf2->d_node[b1.getNumChildren()] == n2[side]) {
- b1 << n2[side];
- b2 << n2[1-side];
- out << ss.str();
- } else {
- Assert(pf2->d_node[b1.getNumChildren()] == n2[1 - side]);
- b1 << n2[1-side];
- b2 << n2[side];
- out << "(symm _ _ _ " << ss.str() << ")";
- }
- out << ")";
- }
- n1 = b1;
- n2 = b2;
- Debug("pf::arith") << "at end assert, got " << pf2->d_node << " and " << n1 << std::endl;
- if(pf2->d_node.getKind() == kind::PARTIAL_APPLY_UF) {
- Assert(n1 == pf2->d_node);
- }
- if(n1.getOperator().getType().getNumChildren() == n1.getNumChildren() + 1) {
- if(ProofManager::currentPM()->hasOp(n1.getOperator())) {
- b1.clear(ProofManager::currentPM()->lookupOp(n2.getOperator()).getConst<Kind>());
- } else {
- b1.clear(kind::APPLY_UF);
- b1 << n1.getOperator();
- }
- b1.append(n1.begin(), n1.end());
- n1 = b1;
- Debug("pf::arith") << "at[2] end assert, got " << pf2->d_node << " and " << n1 << std::endl;
- if(pf2->d_node.getKind() == kind::APPLY_UF) {
- Assert(n1 == pf2->d_node);
- }
- }
- if(n2.getOperator().getType().getNumChildren() == n2.getNumChildren() + 1) {
- if(ProofManager::currentPM()->hasOp(n2.getOperator())) {
- b2.clear(ProofManager::currentPM()->lookupOp(n2.getOperator()).getConst<Kind>());
- } else {
- b2.clear(kind::APPLY_UF);
- b2 << n2.getOperator();
- }
- b2.append(n2.begin(), n2.end());
- n2 = b2;
- }
- Node n = (side == 0 ? eqNode(n1, n2) : eqNode(n2, n1));
- if(tb == 1) {
- Debug("pf::arith") << "\ncong proved: " << n << "\n";
- }
- return n;
- }
-
- case theory::eq::MERGED_THROUGH_REFLEXIVITY:
- Assert(!pf.d_node.isNull());
- Assert(pf.d_children.empty());
- out << "(refl _ ";
- tp->printTerm(NodeManager::currentNM()->toExpr(pf.d_node), out, map);
- out << ")";
- return eqNode(pf.d_node, pf.d_node);
-
- case theory::eq::MERGED_THROUGH_EQUALITY:
- Assert(!pf.d_node.isNull());
- Assert(pf.d_children.empty());
- out << ProofManager::getLitName(pf.d_node.negate());
- return pf.d_node;
-
- case theory::eq::MERGED_THROUGH_TRANS: {
- Assert(!pf.d_node.isNull());
- Assert(pf.d_children.size() >= 2);
- std::stringstream ss;
- Debug("pf::arith") << "\ndoing trans proof[[\n";
- pf.debug_print("pf::arith");
- Debug("pf::arith") << "\n";
- Node n1 = toStreamRecLFSC(ss, tp, *(pf.d_children[0]), tb + 1, map);
- Debug("pf::arith") << "\ndoing trans proof, got n1 " << n1 << "\n";
- if(tb == 1) {
- Debug("pf::arith") << "\ntrans proof[0], got n1 " << n1 << "\n";
- }
-
- bool identicalEqualities = false;
- bool evenLengthSequence;
- Node nodeAfterEqualitySequence;
-
- std::map<size_t, Node> childToStream;
-
- for(size_t i = 1; i < pf.d_children.size(); ++i) {
- std::stringstream ss1(ss.str()), ss2;
- ss.str("");
-
- // It is possible that we've already converted the i'th child to stream. If so,
- // use previously stored result. Otherwise, convert and store.
- Node n2;
- if (childToStream.find(i) != childToStream.end())
- n2 = childToStream[i];
- else {
- n2 = toStreamRecLFSC(ss2, tp, *(pf.d_children[i]), tb + 1, map);
- childToStream[i] = n2;
- }
-
- // The following branch is dedicated to handling sequences of identical equalities,
- // i.e. trans[ a=b, a=b, a=b ].
- //
- // There are two cases:
- // 1. The number of equalities is odd. Then, the sequence can be collapsed to just one equality,
- // i.e. a=b.
- // 2. The number of equalities is even. Now, we have two options: a=a or b=b. To determine this,
- // we look at the node after the equality sequence. If it needs a, we go for a=a; and if it needs
- // b, we go for b=b. If there is no following node, we look at the goal of the transitivity proof,
- // and use it to determine which option we need.
- if(n2.getKind() == kind::EQUAL) {
- if (((n1[0] == n2[0]) && (n1[1] == n2[1])) || ((n1[0] == n2[1]) && (n1[1] == n2[0]))) {
- // We are in a sequence of identical equalities
-
- Debug("pf::arith") << "Detected identical equalities: " << std::endl << "\t" << n1 << std::endl;
-
- if (!identicalEqualities) {
- // The sequence of identical equalities has started just now
- identicalEqualities = true;
-
- Debug("pf::arith") << "The sequence is just beginning. Determining length..." << std::endl;
-
- // Determine whether the length of this sequence is odd or even.
- evenLengthSequence = true;
- bool sequenceOver = false;
- size_t j = i + 1;
-
- while (j < pf.d_children.size() && !sequenceOver) {
- std::stringstream dontCare;
- nodeAfterEqualitySequence = toStreamRecLFSC(
- dontCare, tp, *(pf.d_children[j]), tb + 1, map);
-
- if (((nodeAfterEqualitySequence[0] == n1[0]) && (nodeAfterEqualitySequence[1] == n1[1])) ||
- ((nodeAfterEqualitySequence[0] == n1[1]) && (nodeAfterEqualitySequence[1] == n1[0]))) {
- evenLengthSequence = !evenLengthSequence;
- } else {
- sequenceOver = true;
- }
-
- ++j;
- }
-
- if (evenLengthSequence) {
- // If the length is even, we need to apply transitivity for the "correct" hand of the equality.
-
- Debug("pf::arith") << "Equality sequence of even length" << std::endl;
- Debug("pf::arith") << "n1 is: " << n1 << std::endl;
- Debug("pf::arith") << "n2 is: " << n2 << std::endl;
- Debug("pf::arith") << "pf-d_node is: " << pf.d_node << std::endl;
- Debug("pf::arith") << "Next node is: " << nodeAfterEqualitySequence << std::endl;
-
- ss << "(trans _ _ _ _ ";
-
- // If the sequence is at the very end of the transitivity proof, use pf.d_node to guide us.
- if (!sequenceOver) {
- if (match(n1[0], pf.d_node[0])) {
- n1 = eqNode(n1[0], n1[0]);
- ss << ss1.str() << " (symm _ _ _ " << ss1.str() << ")";
- } else if (match(n1[1], pf.d_node[1])) {
- n1 = eqNode(n1[1], n1[1]);
- ss << " (symm _ _ _ " << ss1.str() << ")" << ss1.str();
- } else {
- Debug("pf::arith") << "Error: identical equalities over, but hands don't match what we're proving."
- << std::endl;
- Assert(false);
- }
- } else {
- // We have a "next node". Use it to guide us.
-
- Assert(nodeAfterEqualitySequence.getKind() == kind::EQUAL);
-
- if ((n1[0] == nodeAfterEqualitySequence[0]) || (n1[0] == nodeAfterEqualitySequence[1])) {
-
- // Eliminate n1[1]
- ss << ss1.str() << " (symm _ _ _ " << ss1.str() << ")";
- n1 = eqNode(n1[0], n1[0]);
-
- } else if ((n1[1] == nodeAfterEqualitySequence[0]) || (n1[1] == nodeAfterEqualitySequence[1])) {
-
- // Eliminate n1[0]
- ss << " (symm _ _ _ " << ss1.str() << ")" << ss1.str();
- n1 = eqNode(n1[1], n1[1]);
-
- } else {
- Debug("pf::arith") << "Error: even length sequence, but I don't know which hand to keep!" << std::endl;
- Assert(false);
- }
- }
-
- ss << ")";
-
- } else {
- Debug("pf::arith") << "Equality sequence length is odd!" << std::endl;
- ss.str(ss1.str());
- }
-
- Debug("pf::arith") << "Have proven: " << n1 << std::endl;
- } else {
- ss.str(ss1.str());
- }
-
- // Ignore the redundancy.
- continue;
- }
- }
-
- if (identicalEqualities) {
- // We were in a sequence of identical equalities, but it has now ended. Resume normal operation.
- identicalEqualities = false;
- }
-
- Debug("pf::arith") << "\ndoing trans proof, got n2 " << n2 << "\n";
- if(tb == 1) {
- Debug("pf::arith") << "\ntrans proof[" << i << "], got n2 " << n2 << "\n";
- Debug("pf::arith") << (n2.getKind() == kind::EQUAL) << "\n";
-
- if ((n1.getNumChildren() >= 2) && (n2.getNumChildren() >= 2)) {
- Debug("pf::arith") << n1[0].getId() << " " << n1[1].getId() << " / " << n2[0].getId() << " " << n2[1].getId() << "\n";
- Debug("pf::arith") << n1[0].getId() << " " << n1[0] << "\n";
- Debug("pf::arith") << n1[1].getId() << " " << n1[1] << "\n";
- Debug("pf::arith") << n2[0].getId() << " " << n2[0] << "\n";
- Debug("pf::arith") << n2[1].getId() << " " << n2[1] << "\n";
- Debug("pf::arith") << (n1[0] == n2[0]) << "\n";
- Debug("pf::arith") << (n1[1] == n2[1]) << "\n";
- Debug("pf::arith") << (n1[0] == n2[1]) << "\n";
- Debug("pf::arith") << (n1[1] == n2[0]) << "\n";
- }
- }
- ss << "(trans _ _ _ _ ";
-
- if((n2.getKind() == kind::EQUAL) && (n1.getKind() == kind::EQUAL))
- // Both elements of the transitivity rule are equalities/iffs
- {
- if(n1[0] == n2[0]) {
- if(tb == 1) { Debug("pf::arith") << "case 1\n"; }
- n1 = eqNode(n1[1], n2[1]);
- ss << "(symm _ _ _ " << ss1.str() << ") " << ss2.str();
- } else if(n1[1] == n2[1]) {
- if(tb == 1) { Debug("pf::arith") << "case 2\n"; }
- n1 = eqNode(n1[0], n2[0]);
- ss << ss1.str() << " (symm _ _ _ " << ss2.str() << ")";
- } else if(n1[0] == n2[1]) {
- if(tb == 1) { Debug("pf::arith") << "case 3\n"; }
- n1 = eqNode(n2[0], n1[1]);
- ss << ss2.str() << " " << ss1.str();
- if(tb == 1) { Debug("pf::arith") << "++ proved " << n1 << "\n"; }
- } else if(n1[1] == n2[0]) {
- if(tb == 1) { Debug("pf::arith") << "case 4\n"; }
- n1 = eqNode(n1[0], n2[1]);
- ss << ss1.str() << " " << ss2.str();
- } else {
- Warning() << "\n\ntrans proof failure at step " << i << "\n\n";
- Warning() << "0 proves " << n1 << "\n";
- Warning() << "1 proves " << n2 << "\n\n";
- pf.debug_print("pf::arith",0);
- //toStreamRec(Warning.getStream(), pf, 0);
- Warning() << "\n\n";
- Unreachable();
- }
- Debug("pf::arith") << "++ trans proof[" << i << "], now have " << n1 << std::endl;
- } else if(n1.getKind() == kind::EQUAL) {
- // n1 is an equality/iff, but n2 is a predicate
- if(n1[0] == n2) {
- n1 = n1[1];
- ss << "(symm _ _ _ " << ss1.str() << ") (pred_eq_t _ " << ss2.str() << ")";
- } else if(n1[1] == n2) {
- n1 = n1[0];
- ss << ss1.str() << " (pred_eq_t _ " << ss2.str() << ")";
- } else {
- Unreachable();
- }
- } else if(n2.getKind() == kind::EQUAL) {
- // n2 is an equality/iff, but n1 is a predicate
- if(n2[0] == n1) {
- n1 = n2[1];
- ss << "(symm _ _ _ " << ss2.str() << ") (pred_eq_t _ " << ss1.str() << ")";
- } else if(n2[1] == n1) {
- n1 = n2[0];
- ss << ss2.str() << " (pred_eq_t _ " << ss1.str() << ")";
- } else {
- Unreachable();
- }
- } else {
- // Both n1 and n2 are prediacates. Don't know what to do...
- Unreachable();
- }
-
- ss << ")";
- }
- out << ss.str();
- Debug("pf::arith") << "\n++ trans proof done, have proven " << n1 << std::endl;
- return n1;
- }
-
- default:
- Assert(!pf.d_node.isNull());
- Assert(pf.d_children.empty());
- Debug("pf::arith") << "theory proof: " << pf.d_node << " by rule " << int(pf.d_id) << std::endl;
- AlwaysAssert(false);
- return pf.d_node;
- }
-}
-
-ArithProof::ArithProof(theory::arith::TheoryArith* arith, TheoryProofEngine* pe)
- : TheoryProof(arith, pe), d_recorder()
-{
- arith->setProofRecorder(&d_recorder);
-}
-
-theory::TheoryId ArithProof::getTheoryId() { return theory::THEORY_ARITH; }
-void ArithProof::registerTerm(Expr term) {
- Debug("pf::arith") << "Arith register term: " << term << ". Kind: " << term.getKind()
- << ". Type: " << term.getType() << std::endl;
-
- if (term.getType().isReal() && !term.getType().isInteger()) {
- Debug("pf::arith") << "Entering real mode" << std::endl;
- }
-
- if (term.isVariable() && !ProofManager::getSkolemizationManager()->isSkolem(term)) {
- d_declarations.insert(term);
- }
-
- // recursively declare all other terms
- for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- // could belong to other theories
- d_proofEngine->registerTerm(term[i]);
- }
-}
-
-void LFSCArithProof::printOwnedTermAsType(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType)
-{
- Debug("pf::arith") << "Arith print term: " << term << ". Kind: " << term.getKind()
- << ". Type: " << term.getType()
- << ". Number of children: " << term.getNumChildren() << std::endl;
-
- // !d_realMode <--> term.getType().isInteger()
-
- Assert (theory::Theory::theoryOf(term) == theory::THEORY_ARITH);
- std::ostringstream closing;
- if (!expectedType.isNull() && !expectedType.isInteger() && term.getType().isInteger()) {
- os << "(term_int_to_real ";
- closing << ")";
- }
- switch (term.getKind())
- {
- case kind::CONST_RATIONAL:
- {
- Assert(term.getNumChildren() == 0);
- Assert(term.getType().isInteger() || term.getType().isReal());
-
- const Rational& r = term.getConst<Rational>();
- bool neg = (r < 0);
-
- os << (term.getType().isInteger() ? "(a_int " : "(a_real ");
- closing << ") ";
-
- if (neg)
- {
- os << "(~ ";
- closing << ")";
- }
-
- if (term.getType().isInteger())
- {
- os << r.abs();
- }
- else
- {
- printRational(os, r.abs());
- }
-
- break;
- }
-
- case kind::PLUS:
- case kind::MINUS:
- case kind::MULT:
- case kind::DIVISION:
- case kind::DIVISION_TOTAL:
- {
- Assert(term.getNumChildren() >= 1);
- TypeNode ty = Node::fromExpr(term).getType();
-
- std::string lfscFunction = getLfscFunction(term);
- for (unsigned i = 0; i < term.getNumChildren() - 1; ++i)
- {
- os << "(" << lfscFunction << " ";
- closing << ")";
- d_proofEngine->printBoundTerm(term[i], os, map, ty);
- os << " ";
- }
-
- d_proofEngine->printBoundTerm(term[term.getNumChildren() - 1], os, map, ty);
- break;
- }
-
- case kind::UMINUS:
- {
- Assert(term.getNumChildren() == 1);
- os << "(" << getLfscFunction(term) << " ";
- closing << ")";
- d_proofEngine->printBoundTerm(term[0], os, map, Node::fromExpr(term).getType());
- break;
- }
-
- case kind::GT:
- case kind::GEQ:
- case kind::LT:
- case kind::LEQ:
- {
- Assert(term.getNumChildren() == 2);
- Assert(term.getType().isBoolean());
-
- std::string lfscFunction = getLfscFunction(term);
- TypeNode realType = NodeManager::currentNM()->realType();
-
- os << "(" << lfscFunction << " ";
- closing << ")";
-
- d_proofEngine->printBoundTerm(term[0], os, map);
- os << " ";
- d_proofEngine->printBoundTerm(term[1], os, map, realType);
- break;
- }
- case kind::EQUAL:
- {
- Assert(term.getType().isBoolean());
- Assert(term.getNumChildren() == 2);
-
- TypeNode eqType = equalityType(term[0], term[1]);
-
- os << "(= " << eqType << " ";
- closing << ")";
-
- d_proofEngine->printBoundTerm(term[0], os, map, eqType);
- d_proofEngine->printBoundTerm(term[1], os, map, eqType);
- break;
- }
-
- case kind::VARIABLE:
- case kind::SKOLEM:
- os << CVC4_ARITH_VAR_TERM_PREFIX << ProofManager::sanitize(term);
- break;
-
- default:
- Debug("pf::arith") << "Default printing of term: " << term << std::endl;
- os << term;
- break;
- }
- os << closing.str();
-}
-
-void LFSCArithProof::printOwnedSort(Type type, std::ostream& os) {
- Debug("pf::arith") << "Arith print sort: " << type << std::endl;
- os << type;
-}
-
-std::string LFSCArithProof::getLfscFunction(const Node & n) {
- Assert(n.getType().isInteger() || n.getType().isReal() || n.getType().isBoolean());
- std::string opString;
- switch (n.getKind()) {
- case kind::UMINUS:
- opString = "u-_";
- break;
- case kind::PLUS:
- opString = "+_";
- break;
- case kind::MINUS:
- opString = "-_";
- break;
- case kind::MULT:
- opString = "*_";
- break;
- case kind::DIVISION:
- case kind::DIVISION_TOTAL:
- opString = "/_";
- break;
- case kind::GT:
- opString = ">_";
- break;
- case kind::GEQ:
- opString = ">=_";
- break;
- case kind::LT:
- opString = "<_";
- break;
- case kind::LEQ:
- opString = "<=_";
- break;
- default:
- Unreachable() << "Tried to get the operator for a non-operator kind: " << n.getKind();
- }
- std::string typeString;
- if (n.getType().isInteger()) {
- typeString = "Int";
- } else if (n.getType().isReal()) {
- typeString = "Real";
- } else { // Boolean
- if (n[0].getType().isInteger()) {
- typeString = "IntReal";
- } else {
- typeString = "Real";
- }
- }
- return opString + typeString;
-}
-
-void LFSCArithProof::printRational(std::ostream& o, const Rational& r)
-{
- if (r.sgn() < 0)
- {
- o << "(~ " << r.getNumerator().abs() << "/" << r.getDenominator().abs()
- << ")";
- }
- else
- {
- o << r.getNumerator() << "/" << r.getDenominator();
- }
-}
-
-void LFSCArithProof::printInteger(std::ostream& o, const Integer& i)
-{
- if (i.sgn() < 0)
- {
- o << "(~ " << i.abs() << ")";
- }
- else
- {
- o << i;
- }
-}
-
-void LFSCArithProof::printLinearPolynomialNormalizer(std::ostream& o,
- const Node& n)
-{
- switch (n.getKind())
- {
- case kind::PLUS:
- {
- // Since our axioms are binary, but n may be n-ary, we rig up
- // a right-associative tree.
- size_t nchildren = n.getNumChildren();
- for (size_t i = 0; i < nchildren; ++i)
- {
- if (i < nchildren - 1)
- {
- o << "\n (is_aff_+ _ _ _ _ _ ";
- }
- printLinearMonomialNormalizer(o, n[i]);
- }
- std::fill_n(std::ostream_iterator<char>(o), nchildren - 1, ')');
- break;
- }
- case kind::MULT:
- case kind::VARIABLE:
- case kind::CONST_RATIONAL:
- case kind::SKOLEM:
- {
- printLinearMonomialNormalizer(o, n);
- break;
- }
- default:
- Unreachable() << "Invalid operation " << n.getKind()
- << " in linear polynomial";
- break;
- }
-}
-
-void LFSCArithProof::printLinearMonomialNormalizer(std::ostream& o,
- const Node& n)
-{
- switch (n.getKind())
- {
- case kind::MULT: {
- Assert((n[0].getKind() == kind::CONST_RATIONAL
- && (n[1].getKind() == kind::VARIABLE
- || n[1].getKind() == kind::SKOLEM)))
- << "node " << n << " is not a linear monomial"
- << " " << n[0].getKind() << " " << n[1].getKind();
-
- o << "\n (is_aff_mul_c_L _ _ _ ";
- printConstRational(o, n[0]);
- o << " ";
- printVariableNormalizer(o, n[1]);
- o << ")";
- break;
- }
- case kind::CONST_RATIONAL:
- {
- o << "\n (is_aff_const ";
- printConstRational(o, n);
- o << ")";
- break;
- }
- case kind::VARIABLE:
- case kind::SKOLEM:
- {
- o << "\n ";
- printVariableNormalizer(o, n);
- break;
- }
- default:
- Unreachable() << "Invalid operation " << n.getKind()
- << " in linear monomial";
- break;
- }
-}
-
-void LFSCArithProof::printConstRational(std::ostream& o, const Node& n)
-{
- Assert(n.getKind() == kind::CONST_RATIONAL);
- const Rational value = n.getConst<Rational>();
- printRational(o, value);
-}
-
-void LFSCArithProof::printVariableNormalizer(std::ostream& o, const Node& n)
-{
- std::ostringstream msg;
- Assert(n.getKind() == kind::VARIABLE || n.getKind() == kind::SKOLEM)
- << "Invalid variable kind " << n.getKind() << " in linear monomial";
- if (n.getType().isInteger()) {
- o << "(is_aff_var_int ";
- } else if (n.getType().isReal()) {
- o << "(is_aff_var_real ";
- } else {
- Unreachable();
- }
- o << n << ")";
-}
-
-void LFSCArithProof::printLinearPolynomialPredicateNormalizer(std::ostream& o,
- const Node& n)
-{
- Assert(n.getKind() == kind::GEQ)
- << "can only print normalization witnesses for (>=) nodes";
- Assert(n[1].getKind() == kind::CONST_RATIONAL);
- o << "\n (is_aff_- _ _ _ _ _ ";
- printLinearPolynomialNormalizer(o, n[0]);
- o << "\n (is_aff_const ";
- printConstRational(o, n[1]);
- o << "))";
-}
-
-std::pair<Node, std::string> LFSCArithProof::printProofAndMaybeTighten(
- const Node& bound)
-{
- const Node & nonNegBound = bound.getKind() == kind::NOT ? bound[0] : bound;
- std::ostringstream pfOfPossiblyTightenedPredicate;
- if (nonNegBound[0].getType().isInteger()) {
- switch(bound.getKind())
- {
- case kind::NOT:
- {
- // Tighten ~[i >= r] to [i < r] to [i <= {r}] to [-i >= -{r}]
- // where
- // * i is an integer
- // * r is a real
- // * {r} denotes the greatest int less than r
- // it is equivalent to (ceil(r) - 1)
- Assert(nonNegBound[1].getKind() == kind::CONST_RATIONAL);
- Rational oldBound = nonNegBound[1].getConst<Rational>();
- Integer newBound = -(oldBound.ceiling() - 1);
- // Since the arith theory rewrites bounds to be purely integral or
- // purely real, mixed bounds should not appear in proofs
- AlwaysAssert(oldBound.isIntegral()) << "Mixed int/real bound in arith proof";
- pfOfPossiblyTightenedPredicate
- << "(tighten_not_>=_IntInt"
- << " _ _ _ _ ("
- << "check_neg_of_greatest_integer_below_int ";
- printInteger(pfOfPossiblyTightenedPredicate, newBound);
- pfOfPossiblyTightenedPredicate << " ";
- printInteger(pfOfPossiblyTightenedPredicate, oldBound.ceiling());
- pfOfPossiblyTightenedPredicate << ") " << ProofManager::getLitName(bound.negate(), "") << ")";
- Node newLeft = (theory::arith::Polynomial::parsePolynomial(nonNegBound[0]) * -1).getNode();
- Node newRight = NodeManager::currentNM()->mkConst(Rational(newBound));
- Node newTerm = NodeManager::currentNM()->mkNode(kind::GEQ, newLeft, newRight);
- return std::make_pair(newTerm, pfOfPossiblyTightenedPredicate.str());
- }
- case kind::GEQ:
- {
- // Tighten [i >= r] to [i >= ceil(r)]
- // where
- // * i is an integer
- // * r is a real
- Assert(nonNegBound[1].getKind() == kind::CONST_RATIONAL);
-
- Rational oldBound = nonNegBound[1].getConst<Rational>();
- // Since the arith theory rewrites bounds to be purely integral or
- // purely real, mixed bounds should not appear in proofs
- AlwaysAssert(oldBound.isIntegral()) << "Mixed int/real bound in arith proof";
- pfOfPossiblyTightenedPredicate << ProofManager::getLitName(bound.negate(), "");
- return std::make_pair(bound, pfOfPossiblyTightenedPredicate.str());
- }
- default: Unreachable();
- }
- } else {
- return std::make_pair(bound, ProofManager::getLitName(bound.negate(), ""));
- }
- // Silence compiler warnings about missing a return.
- Unreachable();
-}
-
-void LFSCArithProof::printTheoryLemmaProof(std::vector<Expr>& lemma,
- std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& map)
-{
- Debug("pf::arith") << "Printing proof for lemma " << lemma << std::endl;
- if (Debug.isOn("pf::arith::printTheoryLemmaProof")) {
- Debug("pf::arith::printTheoryLemmaProof") << "Printing proof for lemma:" << std::endl;
- for (const auto & conjunct : lemma) {
- Debug("pf::arith::printTheoryLemmaProof") << " " << conjunct << std::endl;
- }
- }
- // Prefixes for the names of linearity witnesses
- const char* linearizedProofPrefix = "pf_aff";
- std::ostringstream lemmaParen;
-
- // Construct the set of conflicting literals
- std::set<Node> conflictSet;
- std::transform(lemma.begin(),
- lemma.end(),
- std::inserter(conflictSet, conflictSet.begin()),
- [](const Expr& e) {
- return NodeManager::currentNM()->fromExpr(e).negate();
- });
-
- // If we have Farkas coefficients stored for this lemma, use them to write a
- // proof. Otherwise, just `trust` the lemma.
- if (d_recorder.hasFarkasCoefficients(conflictSet))
- {
- // Get farkas coefficients & literal order
- const auto& farkasInfo = d_recorder.getFarkasCoefficients(conflictSet);
- const Node& conflict = farkasInfo.first;
- theory::arith::RationalVectorCP farkasCoefficients = farkasInfo.second;
- Assert(farkasCoefficients != theory::arith::RationalVectorCPSentinel);
- Assert(conflict.getNumChildren() == farkasCoefficients->size());
- const size_t nAntecedents = conflict.getNumChildren();
-
- // Print proof
- if (Debug.isOn("pf::arith::printTheoryLemmaProof")) {
- os << "Farkas:" << std::endl;
- for (const auto & n : *farkasCoefficients) {
- os << " " << n << std::endl;
- }
- }
-
- // Prove affine function bounds from term bounds
- os << "\n;; Farkas Proof ;;" << std::endl;
- os << "\n; Linear Polynomial Proof Conversions";
- for (size_t i = 0; i != nAntecedents; ++i)
- {
- const Node& antecedent = conflict[i];
- os << "\n (@ "
- << ProofManager::getLitName(antecedent.negate(), linearizedProofPrefix)
- << " ";
- lemmaParen << ")";
- const std::pair<Node, std::string> tightened = printProofAndMaybeTighten(antecedent);
- switch (tightened.first.getKind())
- {
- case kind::NOT:
- {
- Assert(conflict[i][0].getKind() == kind::GEQ);
- os << "(aff_>_from_term _ _ _ _ ";
- break;
- }
- case kind::GEQ:
- {
- os << "(aff_>=_from_term _ _ _ ";
- break;
- }
- default: Unreachable();
- }
- const Node& nonNegTightened = tightened.first.getKind() == kind::NOT ? tightened.first[0] : tightened.first;
- printLinearPolynomialPredicateNormalizer(os, nonNegTightened);
- os << " (pf_reified_arith_pred _ _ " << tightened.second << "))";
- }
-
- // Now, print the proof of bottom, from affine function bounds
- os << "\n; Farkas Combination";
- os << "\n (clausify_false (bounded_aff_contra _ _";
- lemmaParen << "))";
- for (size_t i = 0; i != nAntecedents; ++i)
- {
- const Node& lit = conflict[i];
- os << "\n (bounded_aff_add _ _ _ _ _";
- os << "\n (bounded_aff_mul_c _ _ _ ";
- printRational(os, (*farkasCoefficients)[i].abs());
- os << " " << ProofManager::getLitName(lit.negate(), linearizedProofPrefix)
- << ")"
- << " ; " << lit;
- lemmaParen << ")";
- }
-
- os << "\n bounded_aff_ax_0_>=_0";
- os << lemmaParen.str(); // Close lemma proof
- }
- else
- {
- os << "\n; Arithmetic proofs which use reasoning more complex than Farkas "
- "proofs and bound tightening are currently unsupported\n"
- "(clausify_false trust)\n";
- }
-}
-
-void LFSCArithProof::printSortDeclarations(std::ostream& os, std::ostream& paren) {
- // Nothing to do here at this point.
-}
-
-void LFSCArithProof::printTermDeclarations(std::ostream& os, std::ostream& paren) {
- for (ExprSet::const_iterator it = d_declarations.begin();
- it != d_declarations.end();
- ++it)
- {
- Expr term = *it;
- Assert(term.isVariable());
- bool isInt = term.getType().isInteger();
- const char * var_type = isInt ? "int_var" : "real_var";
- os << "(% " << ProofManager::sanitize(term) << " " << var_type << "\n";
- os << "(@ " << CVC4_ARITH_VAR_TERM_PREFIX << ProofManager::sanitize(term)
- << " ";
- os << "(term_" << var_type << " " << ProofManager::sanitize(term) << ")\n";
- paren << ")";
- paren << ")";
- }
-}
-
-void LFSCArithProof::printDeferredDeclarations(std::ostream& os, std::ostream& paren) {
- // Nothing to do here at this point.
-}
-
-void LFSCArithProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) {
- // Nothing to do here at this point.
-}
-
-bool LFSCArithProof::printsAsBool(const Node& n)
-{
- // Our boolean variables and constants print as sort Bool.
- // All complex booleans print as formulas.
- return n.getType().isBoolean() and (n.isVar() or n.isConst());
-}
-
-TypeNode LFSCArithProof::equalityType(const Expr& left, const Expr& right)
-{
- return TypeNode::fromType(!left.getType().isInteger() ? left.getType() : right.getType());
-}
-
-} /* CVC4 namespace */
diff --git a/src/proof/arith_proof.h b/src/proof/arith_proof.h
deleted file mode 100644
index 832afcae0..000000000
--- a/src/proof/arith_proof.h
+++ /dev/null
@@ -1,217 +0,0 @@
-/********************* */
-/*! \file arith_proof.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Alex Ozdemir, Guy Katz, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Arith proof
- **
- ** Arith proof
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__ARITH__PROOF_H
-#define CVC4__ARITH__PROOF_H
-
-#include <memory>
-#include <unordered_set>
-
-#include "expr/expr.h"
-#include "proof/arith_proof_recorder.h"
-#include "proof/proof_manager.h"
-#include "proof/theory_proof.h"
-#include "theory/uf/equality_engine.h"
-
-namespace CVC4 {
-
-//proof object outputted by TheoryArith
-class ProofArith : public Proof {
- public:
- ProofArith(std::shared_ptr<theory::eq::EqProof> pf) : d_proof(pf) {}
- void toStream(std::ostream& out) const override;
-
- private:
- static void toStreamLFSC(std::ostream& out, TheoryProof* tp,
- const theory::eq::EqProof& pf,
- const ProofLetMap& map);
- static Node toStreamRecLFSC(std::ostream& out, TheoryProof* tp,
- const theory::eq::EqProof& pf,
- unsigned tb, const ProofLetMap& map);
- // it is simply an equality engine proof
- std::shared_ptr<theory::eq::EqProof> d_proof;
-};
-
-namespace theory {
-namespace arith {
-class TheoryArith;
-}
-}
-
-typedef std::unordered_set<Type, TypeHashFunction > TypeSet;
-
-
-class ArithProof : public TheoryProof {
-protected:
- // std::map<Expr, std::string> d_constRationalString; // all the variable/function declarations
-
- // TypeSet d_sorts; // all the uninterpreted sorts in this theory
- ExprSet d_declarations; // all the variable/function declarations
-
- /**
- * Where farkas proofs of lemmas are stored.
- */
- proof::ArithProofRecorder d_recorder;
-
- theory::TheoryId getTheoryId() override;
-
- public:
- ArithProof(theory::arith::TheoryArith* arith, TheoryProofEngine* proofEngine);
-
- void registerTerm(Expr term) override;
-};
-
-class LFSCArithProof : public ArithProof {
-public:
- LFSCArithProof(theory::arith::TheoryArith* arith, TheoryProofEngine* proofEngine)
- : ArithProof(arith, proofEngine)
- {}
- void printOwnedTermAsType(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType) override;
- void printOwnedSort(Type type, std::ostream& os) override;
-
- /**
- * Returns the LFSC identifier for the operator of this node.
- *
- * e.g. "+_Real".
- *
- * Does not include any parens.
- *
- * Even if the operator is a comparison (e.g. >=) on integers, will not
- * return a purely `Int` predicate like ">=_Int". Instead this treats the
- * right hand side as a real.
- */
- static std::string getLfscFunction(const Node& n);
-
- /**
- * Print a rational number in LFSC format.
- * e.g. 5/8 or (~ 1/1)
- *
- * @param o ostream to print to.
- * @param r the rational to print
- */
- static void printRational(std::ostream& o, const Rational& r);
-
- /**
- * Print an integer in LFSC format.
- * e.g. 5 or (~ 1)
- *
- * @param o ostream to print to.
- * @param i the integer to print
- */
- static void printInteger(std::ostream& o, const Integer& i);
-
- /**
- * Print a value of type poly_formula_norm
- *
- * @param o ostream to print to
- * @param n node (asserted to be of the form [linear polynomial >= constant])
- */
- static void printLinearPolynomialPredicateNormalizer(std::ostream& o,
- const Node& n);
-
- /**
- * Print a value of type poly_norm
- *
- * @param o ostream to print to
- * @param n node (asserted to be a linear polynomial)
- */
- static void printLinearPolynomialNormalizer(std::ostream& o, const Node& n);
-
- /**
- * Print a value of type poly_norm
- *
- * @param o ostream to print to
- * @param n node (asserted to be a linear monomial)
- */
- static void printLinearMonomialNormalizer(std::ostream& o, const Node& n);
-
- /**
- * Print a LFSC rational
- *
- * @param o ostream to print to
- * @param n node (asserted to be a const rational)
- */
- static void printConstRational(std::ostream& o, const Node& n);
-
- /**
- * print the pn_var normalizer for n (type poly_norm)
- *
- * @param o the ostream to print to
- * @param n the node to print (asserted to be a variable)
- */
- static void printVariableNormalizer(std::ostream& o, const Node& n);
- /**
- * print a proof of the lemma
- *
- * First, we print linearity witnesses, i.e. witnesses that each literal has
- * the form:
- * [linear polynomial] >= 0 OR
- * [linear polynomial] > 0
- *
- * Then we use those witnesses to prove that the above linearized constraints
- * hold.
- *
- * Then we use the farkas coefficients to combine the literals into a
- * variable-free contradiction. The literals may be a mix of strict and
- * relaxed inequalities.
- *
- * @param lemma the set of literals disjoined in the lemma
- * @param os stream to print the proof to
- * @param paren global closing stream (unused)
- * @param map let map (unused)
- */
- void printTheoryLemmaProof(std::vector<Expr>& lemma,
- std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& map) override;
- void printSortDeclarations(std::ostream& os, std::ostream& paren) override;
- void printTermDeclarations(std::ostream& os, std::ostream& paren) override;
- void printDeferredDeclarations(std::ostream& os,
- std::ostream& paren) override;
- void printAliasingDeclarations(std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& globalLetMap) override;
-
- /**
- * Given a node that is an arith literal (an arith comparison or negation
- * thereof), prints a proof of that literal.
- *
- * If the node represents a tightenable bound (e.g. [Int] < 3) then it prints
- * a proof of the tightening instead. (e.g. [Int] <= 2).
- *
- * @return a pair comprising:
- * * the new node (after tightening) and
- * * a string proving it.
- */
- std::pair<Node, std::string> printProofAndMaybeTighten(const Node& bound);
-
- /**
- * Return whether this node, when serialized to LFSC, has sort `Bool`. Otherwise, the sort is `formula`.
- */
- bool printsAsBool(const Node& n) override;
-
- TypeNode equalityType(const Expr& left, const Expr& right) override;
-};
-
-
-}/* CVC4 namespace */
-
-#endif /* CVC4__ARITH__PROOF_H */
diff --git a/src/proof/arith_proof_recorder.cpp b/src/proof/arith_proof_recorder.cpp
deleted file mode 100644
index 01da402c9..000000000
--- a/src/proof/arith_proof_recorder.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-/********************* */
-/*! \file arith_proof_recorder.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Alex Ozdemir
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief A class for recording the skeletons of arithmetic proofs at solve
- ** time so they can later be used during proof-production time.
- **/
-
-#include "proof/arith_proof_recorder.h"
-
-#include <algorithm>
-#include <vector>
-
-#include "base/map_util.h"
-
-namespace CVC4 {
-namespace proof {
-
-ArithProofRecorder::ArithProofRecorder() : d_lemmasToFarkasCoefficients()
-{
- // Nothing else
-}
-void ArithProofRecorder::saveFarkasCoefficients(
- Node conflict, theory::arith::RationalVectorCP farkasCoefficients)
-{
- // Verify that the conflict is a conjuction of (possibly negated) real bounds
- // Verify that the conflict is a conjunciton ...
- Assert(conflict.getKind() == kind::AND);
- Assert(conflict.getNumChildren() == farkasCoefficients->size());
- for (size_t i = 0, nchildren = conflict.getNumChildren(); i < nchildren; ++i)
- {
- const Node& child = conflict[i];
- // ... of possibly negated ...
- const Node& nonNegativeChild =
- child.getKind() == kind::NOT ? child[0] : child;
- // ... real bounds
- Assert(nonNegativeChild.getType().isBoolean()
- && nonNegativeChild[0].getType().isReal());
- }
- Debug("pf::arith") << "Saved Farkas Coefficients:" << std::endl;
- if (Debug.isOn("pf::arith"))
- {
- for (size_t i = 0, nchildren = conflict.getNumChildren(); i < nchildren;
- ++i)
- {
- const Node& child = conflict[i];
- const Rational& r = (*farkasCoefficients)[i];
- Debug("pf::arith") << " " << std::setw(8) << r;
- Debug("pf::arith") << " " << child << std::endl;
- }
- }
-
- std::set<Node> lits;
- std::copy(
- conflict.begin(), conflict.end(), std::inserter(lits, lits.begin()));
-
- d_lemmasToFarkasCoefficients[lits] =
- std::make_pair(std::move(conflict), *farkasCoefficients);
-}
-
-bool ArithProofRecorder::hasFarkasCoefficients(
- const std::set<Node>& conflict) const
-{
- return d_lemmasToFarkasCoefficients.find(conflict)
- != d_lemmasToFarkasCoefficients.end();
-}
-
-std::pair<Node, theory::arith::RationalVectorCP>
-ArithProofRecorder::getFarkasCoefficients(const std::set<Node>& conflict) const
-{
- if (auto *p = FindOrNull(d_lemmasToFarkasCoefficients, conflict))
- {
- return std::make_pair(p->first, &p->second);
- }
- else
- {
- return std::make_pair(Node(), theory::arith::RationalVectorCPSentinel);
- }
-}
-
-} // namespace proof
-} // namespace CVC4
diff --git a/src/proof/arith_proof_recorder.h b/src/proof/arith_proof_recorder.h
deleted file mode 100644
index 0669e5d16..000000000
--- a/src/proof/arith_proof_recorder.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/********************* */
-/*! \file arith_proof_recorder.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Alex Ozdemir, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief A class for recording the skeletons of arithmetic proofs at solve
- ** time so they can later be used during proof-production time.
- **
- ** In particular, we're interested in proving bottom from a conjunction of
- ** theory literals.
- **
- ** For now, we assume that this can be done using a Farkas combination, and if
- ** that doesn't work for some reason, then we give up and "trust" the lemma.
- ** In the future we'll build support for more sophisticated reasoning.
- **
- ** Given this scope, our task is to...
- ** for each lemma (a set of literals)
- ** save the Farkas coefficients for those literals
- ** which requires we save an ordering of the literals
- ** and a parallel ordering of Farkas coefficients.
- **
- ** Farkas proofs have the following core structure:
- ** For a list of affine bounds: c[i] dot x >= b[i]
- ** (x is a vector of variables)
- ** (c[i] is a vector of coefficients)
- ** and a list of non-negative coefficients: f[i],
- ** compute
- **
- ** sum_i{ (c[i] dot x) * f[i] } and sum_i{b[i]*f[i]}
- **
- ** and then verify that the left is actually < the right, a contradiction
- **
- ** To be clear: this code does not check Farkas proofs, it just stores the
- ** information needed to write them.
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__PROOF__ARITH_PROOF_RECORDER_H
-#define CVC4__PROOF__ARITH_PROOF_RECORDER_H
-
-#include <map>
-#include <set>
-
-#include "expr/node.h"
-#include "theory/arith/constraint_forward.h"
-
-namespace CVC4 {
-namespace proof {
-
-class ArithProofRecorder
-{
- public:
- ArithProofRecorder();
-
- /**
- * @brief For a set of incompatible literals, save the Farkas coefficients
- * demonstrating their incompatibility
- *
- * @param conflict a conjunction of conflicting literals
- * @param farkasCoefficients a list of rational coefficients which the literals
- * should be multiplied by (pairwise) to produce a contradiction.
- *
- * The orders of the two vectors must agree!
- */
- void saveFarkasCoefficients(
- Node conflict, theory::arith::RationalVectorCP farkasCoefficients);
-
- /**
- * @brief Determine whether some literals have a Farkas proof of their
- * incompatibility
- *
- * @param conflict a conjunction of (putatively) conflicting literals
- *
- * @return whether or not there is actually a proof for them.
- */
- bool hasFarkasCoefficients(const std::set<Node>& conflict) const;
-
- /**
- * @brief Get the Farkas Coefficients object
- *
- * @param conflict a conjunction of conflicting literals
- * @return theory::arith::RationalVectorCP -- the Farkas coefficients
- * Node -- a conjunction of the problem literals in coefficient order
- *
- * theory::arith::RationalVectorCPSentinel if there is no entry for
- * these lits
- */
- std::pair<Node, theory::arith::RationalVectorCP> getFarkasCoefficients(
- const std::set<Node>& conflict) const;
-
- protected:
- // For each lemma, save the Farkas coefficients of that lemma
- std::map<std::set<Node>, std::pair<Node, theory::arith::RationalVector>>
- d_lemmasToFarkasCoefficients;
-};
-
-} // namespace proof
-} // namespace CVC4
-
-#endif
diff --git a/src/proof/array_proof.cpp b/src/proof/array_proof.cpp
deleted file mode 100644
index 2d42a7489..000000000
--- a/src/proof/array_proof.cpp
+++ /dev/null
@@ -1,1350 +0,0 @@
-/********************* */
-/*! \file array_proof.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Guy Katz, Yoni Zohar, Liana Hadarean
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** [[ Add lengthier description here ]]
-
- ** \todo document this file
-
-**/
-
-#include "proof/array_proof.h"
-
-#include <stack>
-
-#include "proof/proof_manager.h"
-#include "proof/simplify_boolean_node.h"
-#include "proof/theory_proof.h"
-#include "theory/arrays/theory_arrays.h"
-
-namespace CVC4 {
-
-namespace {
-
-class ArrayProofPrinter : public theory::eq::EqProof::PrettyPrinter {
- public:
- ArrayProofPrinter(unsigned row, unsigned row1, unsigned ext)
- : d_row(row), d_row1(row1), d_ext(ext) {}
-
- std::string printTag(unsigned tag) override;
-
- private:
- const unsigned d_row;
- const unsigned d_row1;
- const unsigned d_ext;
-}; // class ArrayProofPrinter
-
-std::string ArrayProofPrinter::printTag(unsigned tag) {
- if (tag == theory::eq::MERGED_THROUGH_CONGRUENCE) return "Congruence";
- if (tag == theory::eq::MERGED_THROUGH_EQUALITY) return "Pure Equality";
- if (tag == theory::eq::MERGED_THROUGH_REFLEXIVITY) return "Reflexivity";
- if (tag == theory::eq::MERGED_THROUGH_CONSTANTS) return "Constants";
- if (tag == theory::eq::MERGED_THROUGH_TRANS) return "Transitivity";
-
- if (tag == d_row) return "Read Over Write";
- if (tag == d_row1) return "Read Over Write (1)";
- if (tag == d_ext) return "Extensionality";
-
- std::ostringstream result;
- result << tag;
- return result.str();
-}
-
-} // namespace
-
-
-
-ProofArray::ProofArray(std::shared_ptr<theory::eq::EqProof> pf,
- unsigned row,
- unsigned row1,
- unsigned ext)
- : d_proof(pf), d_reasonRow(row), d_reasonRow1(row1), d_reasonExt(ext)
-{
-}
-
-void ProofArray::toStream(std::ostream& out) const
-{
- ProofLetMap map;
- toStream(out, map);
-}
-
-void ProofArray::toStream(std::ostream& out, const ProofLetMap& map) const
-{
- Trace("pf::array") << "; Print Array proof..." << std::endl;
- toStreamLFSC(out, ProofManager::getArrayProof(), *d_proof, map);
- Debug("pf::array") << "; Print Array proof done!" << std::endl;
-}
-
-void ProofArray::toStreamLFSC(std::ostream& out,
- TheoryProof* tp,
- const theory::eq::EqProof& pf,
- const ProofLetMap& map) const
-{
- Debug("pf::array") << "Printing array proof in LFSC : " << std::endl;
- ArrayProofPrinter proofPrinter(d_reasonRow, d_reasonRow1, d_reasonExt);
- pf.debug_print("pf::array", 0, &proofPrinter);
- Debug("pf::array") << std::endl;
- toStreamRecLFSC(out, tp, pf, 0, map);
- Debug("pf::array") << "Printing array proof in LFSC DONE" << std::endl;
-}
-
-Node ProofArray::toStreamRecLFSC(std::ostream& out,
- TheoryProof* tp,
- const theory::eq::EqProof& pf,
- unsigned tb,
- const ProofLetMap& map) const
-{
- Debug("pf::array") << std::endl
- << std::endl
- << "toStreamRecLFSC called. tb = " << tb
- << " . proof:" << std::endl;
- ArrayProofPrinter proofPrinter(d_reasonRow, d_reasonRow1, d_reasonExt);
- if(tb == 0) {
- std::shared_ptr<theory::eq::EqProof> subTrans =
- std::make_shared<theory::eq::EqProof>();
-
- int neg = tp->assertAndPrint(pf, map, subTrans, &proofPrinter);
-
- Node n1;
- std::stringstream ss, ss2;
- Debug("mgdx") << "\nsubtrans has " << subTrans->d_children.size() << " children\n";
- bool disequalityFound = (neg >= 0);
-
- if (!disequalityFound || pf.d_children.size() > 2)
- {
- n1 = toStreamRecLFSC(ss, tp, *subTrans, 1, map);
- } else {
- n1 = toStreamRecLFSC(ss, tp, *(subTrans->d_children[0]), 1, map);
- Debug("mgdx") << "\nsubTrans unique child "
- << subTrans->d_children[0]->d_id
- << " was proven\ngot: " << n1 << std::endl;
- }
-
- out << "(clausify_false (contra _ ";
- if (disequalityFound) {
- Node n2 = pf.d_children[neg]->d_node;
- Assert(n2.getKind() == kind::NOT);
- Debug("mgdx") << "\nhave proven: " << n1 << std::endl;
- Debug("mgdx") << "n2 is " << n2 << std::endl;
- Debug("mgdx") << "n2->d_id is " << pf.d_children[neg]->d_id << std::endl;
- Debug("mgdx") << "n2[0] is " << n2[0] << std::endl;
-
- if (n2[0].getNumChildren() > 0) { Debug("mgdx") << "\nn2[0]: " << n2[0][0] << std::endl; }
- if (n1.getNumChildren() > 1) { Debug("mgdx") << "n1[1]: " << n1[1] << std::endl; }
-
- if ((pf.d_children[neg]->d_id == d_reasonExt) ||
- (pf.d_children[neg]->d_id == theory::eq::MERGED_THROUGH_TRANS)) {
- // Ext case: The negative node was created by an EXT rule; e.g. it is a[k]!=b[k], due to a!=b.
- out << ss.str();
- out << " ";
- toStreamRecLFSC(ss2, tp, *pf.d_children[neg], 1, map);
- out << ss2.str();
- } else if (n2[0].getKind() == kind::APPLY_UF) {
- out << "(trans _ _ _ _ ";
- out << "(symm _ _ _ ";
- out << ss.str();
- out << ") (pred_eq_f _ " << ProofManager::getLitName(n2[0]) << ")) t_t_neq_f))" << std::endl;
- } else {
- Assert((n1[0] == n2[0][0] && n1[1] == n2[0][1])
- || (n1[1] == n2[0][0] && n1[0] == n2[0][1]));
- if(n1[1] == n2[0][0]) {
- out << "(symm _ _ _ " << ss.str() << ")";
- } else {
- out << ss.str();
- }
- Debug("pf::array") << "ArrayProof::toStream: getLitName( " << n2[0] << " ) = " <<
- ProofManager::getLitName(n2[0]) << std::endl;
-
- out << " " << ProofManager::getLitName(n2[0]);
- }
- } else {
- Node n2 = pf.d_node;
- Assert(n2.getKind() == kind::EQUAL);
- Assert((n1[0] == n2[0] && n1[1] == n2[1])
- || (n1[1] == n2[0] && n1[0] == n2[1]));
-
- out << ss.str();
- out << " ";
- ProofManager::getTheoryProofEngine()->printConstantDisequalityProof(out,
- n1[0].toExpr(),
- n1[1].toExpr(),
- map);
- }
-
- out << "))" << std::endl;
- return Node();
- }
-
- switch (pf.d_id)
- {
- case theory::eq::MERGED_THROUGH_CONGRUENCE:
- {
- Debug("mgd") << "\nok, looking at congruence:\n";
- pf.debug_print("mgd", 0, &proofPrinter);
- std::stack<const theory::eq::EqProof*> stk;
- for (const theory::eq::EqProof* pf2 = &pf;
- pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE;
- pf2 = pf2->d_children[0].get())
- {
- Debug("mgd") << "Looking at pf2 with d_node: " << pf2->d_node
- << std::endl;
- Assert(!pf2->d_node.isNull());
- Assert(pf2->d_node.getKind() == kind::PARTIAL_APPLY_UF
- || pf2->d_node.getKind() == kind::BUILTIN
- || pf2->d_node.getKind() == kind::APPLY_UF
- || pf2->d_node.getKind() == kind::SELECT
- || pf2->d_node.getKind() == kind::PARTIAL_SELECT_0
- || pf2->d_node.getKind() == kind::PARTIAL_SELECT_1
- || pf2->d_node.getKind() == kind::STORE);
-
- Assert(pf2->d_children.size() == 2);
- out << "(cong _ _ _ _ _ _ ";
- stk.push(pf2);
- }
- Assert(stk.top()->d_children[0]->d_id
- != theory::eq::MERGED_THROUGH_CONGRUENCE);
- // NodeBuilder<> b1(kind::PARTIAL_APPLY_UF),
- // b2(kind::PARTIAL_APPLY_UF);
- NodeBuilder<> b1, b2;
-
- const theory::eq::EqProof* pf2 = stk.top();
- stk.pop();
- Assert(pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE);
- Node n1 = toStreamRecLFSC(out, tp, *(pf2->d_children[0]), tb + 1, map);
- out << " ";
- std::stringstream ss;
- Node n2 = toStreamRecLFSC(ss, tp, *(pf2->d_children[1]), tb + 1, map);
-
- Debug("mgd") << "\nok, in FIRST cong[" << stk.size() << "]"
- << "\n";
- pf2->debug_print("mgd", 0, &proofPrinter);
- // Temp
- Debug("mgd") << "n1 is a proof for: " << pf2->d_children[0]->d_node
- << ". It is: " << n1 << std::endl;
- Debug("mgd") << "n2 is a proof for: " << pf2->d_children[1]->d_node
- << ". It is: " << n2 << std::endl;
- //
- Debug("mgd") << "looking at " << pf2->d_node << "\n";
- Debug("mgd") << " " << n1 << "\n";
- Debug("mgd") << " " << n2 << "\n";
-
- int side = 0;
- if (tp->match(pf2->d_node, n1[0]))
- {
- Debug("mgd") << "SIDE IS 0\n";
- side = 0;
- }
- else
- {
- Debug("mgd") << "SIDE IS 1\n";
- if (!tp->match(pf2->d_node, n1[1]))
- {
- Debug("mgd") << "IN BAD CASE, our first subproof is\n";
- pf2->d_children[0]->debug_print("mgd", 0, &proofPrinter);
- }
- Assert(tp->match(pf2->d_node, n1[1]));
- side = 1;
- }
-
- if (n1[side].getKind() == kind::APPLY_UF
- || n1[side].getKind() == kind::PARTIAL_APPLY_UF
- || n1[side].getKind() == kind::SELECT
- || n1[side].getKind() == kind::PARTIAL_SELECT_1
- || n1[side].getKind() == kind::STORE)
- {
- if (n1[side].getKind() == kind::APPLY_UF
- || n1[side].getKind() == kind::PARTIAL_APPLY_UF)
- {
- b1 << kind::PARTIAL_APPLY_UF;
- b1 << n1[side].getOperator();
- }
- else if (n1[side].getKind() == kind::SELECT
- || n1[side].getKind() == kind::PARTIAL_SELECT_1)
- {
- // b1 << n1[side].getKind();
- b1 << kind::SELECT;
- } else {
- b1 << kind::PARTIAL_APPLY_UF;
- b1 << ProofManager::currentPM()->mkOp(n1[side].getOperator());
- }
- b1.append(n1[side].begin(), n1[side].end());
- }
- else if (n1[side].getKind() == kind::PARTIAL_SELECT_0) {
- b1 << kind::PARTIAL_SELECT_1;
- } else {
- b1 << n1[side];
- }
-
- if(n1[1-side].getKind() == kind::PARTIAL_APPLY_UF ||
- n1[1-side].getKind() == kind::APPLY_UF ||
- n1[1-side].getKind() == kind::SELECT ||
- n1[1-side].getKind() == kind::PARTIAL_SELECT_1 ||
- n1[1-side].getKind() == kind::STORE) {
- if(n1[1-side].getKind() == kind::APPLY_UF ||
- n1[1-side].getKind() == kind::PARTIAL_APPLY_UF) {
- b2 << kind::PARTIAL_APPLY_UF;
- b2 << n1[1-side].getOperator();
- } else if (n1[1-side].getKind() == kind::SELECT || n1[1-side].getKind() == kind::PARTIAL_SELECT_1) {
- // b2 << n1[1-side].getKind();
- b2 << kind::SELECT;
- } else {
- b2 << kind::PARTIAL_APPLY_UF;
- b2 << ProofManager::currentPM()->mkOp(n1[1-side].getOperator());
- }
- b2.append(n1[1-side].begin(), n1[1-side].end());
- } else if (n1[1-side].getKind() == kind::PARTIAL_SELECT_0) {
- b2 << kind::PARTIAL_SELECT_1;
- } else {
- b2 << n1[1-side];
- }
- Debug("mgd") << "pf2->d_node " << pf2->d_node << std::endl;
- Debug("mgd") << "b1.getNumChildren() " << b1.getNumChildren() << std::endl;
- Debug("mgd") << "n1 " << n1 << std::endl;
- Debug("mgd") << "n2 " << n2 << std::endl;
- // These debug prints can cause a problem if we're constructing a SELECT node and it doesn't have enough
- // children yet.
- // Debug("mgd") << "b1 " << b1 << std::endl;
- // Debug("mgd") << "b2 " << b2 << std::endl;
- Debug("mgd") << "side " << side << std::endl;
- Debug("mgd") << "pf2->d_node's number of children: " << pf2->d_node.getNumChildren() << std::endl;
- Debug("mgd") << "pf2->d_node's meta kind: " << pf2->d_node.getMetaKind() << std::endl;
- Debug("mgd") << "Is this meta kind considered parameterized? " << (pf2->d_node.getMetaKind() == kind::metakind::PARAMETERIZED) << std::endl;
-
- if(pf2->d_node[b1.getNumChildren() +
- (n1[side].getKind() == kind::PARTIAL_SELECT_0 ? 1 : 0) +
- (n1[side].getKind() == kind::PARTIAL_SELECT_1 ? 1 : 0) -
- (pf2->d_node.getMetaKind() == kind::metakind::PARAMETERIZED ? 0 : 1)] == n2[side]) {
- b1 << n2[side];
- b2 << n2[1-side];
- out << ss.str();
- } else {
- Assert(
- pf2->d_node[b1.getNumChildren()
- + (n1[side].getKind() == kind::PARTIAL_SELECT_0 ? 1 : 0)
- + (n1[side].getKind() == kind::PARTIAL_SELECT_1 ? 1 : 0)
- - (pf2->d_node.getMetaKind()
- == kind::metakind::PARAMETERIZED
- ? 0
- : 1)]
- == n2[1 - side]);
- b1 << n2[1-side];
- b2 << n2[side];
- out << "(symm _ _ _ " << ss.str() << ")";
- }
-
- Debug("mgd") << "After first insertion:" << std::endl;
- Debug("mgd") << "b1 " << b1 << std::endl;
- Debug("mgd") << "b2 " << b2 << std::endl;
-
- out << ")";
- while(!stk.empty()) {
-
- Debug("mgd") << "\nMORE TO DO\n";
-
- pf2 = stk.top();
- stk.pop();
- Assert(pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE);
- out << " ";
- ss.str("");
- n2 = toStreamRecLFSC(ss, tp, *(pf2->d_children[1]), tb + 1, map);
-
- Debug("mgd") << "\nok, in cong[" << stk.size() << "]" << "\n";
- Debug("mgd") << "looking at " << pf2->d_node << "\n";
- Debug("mgd") << " " << n1 << "\n";
- Debug("mgd") << " " << n2 << "\n";
- Debug("mgd") << " " << b1 << "\n";
- Debug("mgd") << " " << b2 << "\n";
- if(pf2->d_node[b1.getNumChildren()] == n2[side]) {
- b1 << n2[side];
- b2 << n2[1-side];
- out << ss.str();
- } else {
- Assert(pf2->d_node[b1.getNumChildren()] == n2[1 - side]);
- b1 << n2[1-side];
- b2 << n2[side];
- out << "(symm _ _ _ " << ss.str() << ")";
- }
- out << ")";
- }
- n1 = b1;
- n2 = b2;
-
- Debug("mgd") << "at end assert!" << std::endl
- << "pf2->d_node = " << pf2->d_node << std::endl
- << "n1 (assigned from b1) = " << n1 << std::endl
- << "n2 (assigned from b2) = " << n2 << std::endl;
-
- if(pf2->d_node.getKind() == kind::PARTIAL_APPLY_UF) {
- Assert(n1 == pf2->d_node);
- }
-
- Debug("mgd") << "n1.getOperator().getType().getNumChildren() = "
- << n1.getOperator().getType().getNumChildren() << std::endl;
- Debug("mgd") << "n1.getNumChildren() + 1 = "
- << n1.getNumChildren() + 1 << std::endl;
-
- Assert(!(
- (n1.getKind() == kind::PARTIAL_SELECT_0 && n1.getNumChildren() == 2)));
- if (n1.getKind() == kind::PARTIAL_SELECT_1 && n1.getNumChildren() == 2) {
- Debug("mgd") << "Finished a SELECT. Updating.." << std::endl;
- b1.clear(kind::SELECT);
- b1.append(n1.begin(), n1.end());
- n1 = b1;
- Debug("mgd") << "New n1: " << n1 << std::endl;
- } else if(n1.getOperator().getType().getNumChildren() == n1.getNumChildren() + 1) {
- if(ProofManager::currentPM()->hasOp(n1.getOperator())) {
- b1.clear(ProofManager::currentPM()->lookupOp(n2.getOperator()).getConst<Kind>());
- } else {
- b1.clear(kind::APPLY_UF);
- b1 << n1.getOperator();
- }
- b1.append(n1.begin(), n1.end());
- n1 = b1;
- Debug("mgd") << "at[2] end assert, got " << pf2->d_node << " and " << n1 << std::endl;
- if(pf2->d_node.getKind() == kind::APPLY_UF) {
- Assert(n1 == pf2->d_node);
- }
- }
-
- Debug("mgd") << "n2.getOperator().getType().getNumChildren() = "
- << n2.getOperator().getType().getNumChildren() << std::endl;
- Debug("mgd") << "n2.getNumChildren() + 1 = "
- << n2.getNumChildren() + 1 << std::endl;
-
- Assert(!(
- (n2.getKind() == kind::PARTIAL_SELECT_0 && n2.getNumChildren() == 2)));
- if (n2.getKind() == kind::PARTIAL_SELECT_1 && n2.getNumChildren() == 2) {
- Debug("mgd") << "Finished a SELECT. Updating.." << std::endl;
- b2.clear(kind::SELECT);
- b2.append(n2.begin(), n2.end());
- n2 = b2;
- Debug("mgd") << "New n2: " << n2 << std::endl;
- } else if(n2.getOperator().getType().getNumChildren() == n2.getNumChildren() + 1) {
- if(ProofManager::currentPM()->hasOp(n2.getOperator())) {
- b2.clear(ProofManager::currentPM()->lookupOp(n2.getOperator()).getConst<Kind>());
- } else {
- b2.clear(kind::APPLY_UF);
- b2 << n2.getOperator();
- }
- b2.append(n2.begin(), n2.end());
- n2 = b2;
- }
- Node n = (side == 0 ? n1.eqNode(n2) : n2.eqNode(n1));
-
- Debug("mgdx") << "\ncong proved: " << n << "\n";
- return n;
- }
- case theory::eq::MERGED_THROUGH_REFLEXIVITY:
- {
- Assert(!pf.d_node.isNull());
- Assert(pf.d_children.empty());
- out << "(refl _ ";
- tp->printTerm(NodeManager::currentNM()->toExpr(pf.d_node), out, map);
- out << ")";
- return pf.d_node.eqNode(pf.d_node);
- }
- case theory::eq::MERGED_THROUGH_EQUALITY:
- {
- Assert(!pf.d_node.isNull());
- Assert(pf.d_children.empty());
- Debug("pf::array") << "ArrayProof::toStream: getLitName( " << pf.d_node.negate() << " ) = " <<
- ProofManager::getLitName(pf.d_node.negate()) << std::endl;
- out << ProofManager::getLitName(pf.d_node.negate());
- return pf.d_node;
- }
-
- case theory::eq::MERGED_THROUGH_TRANS:
- {
- bool firstNeg = false;
- bool secondNeg = false;
-
- Assert(!pf.d_node.isNull());
- Assert(pf.d_children.size() >= 2);
- std::stringstream ss;
- Debug("mgd") << "\ndoing trans proof[[\n";
- pf.debug_print("mgd", 0, &proofPrinter);
- Debug("mgd") << "\n";
-
- pf.d_children[0]->d_node = simplifyBooleanNode(pf.d_children[0]->d_node);
-
- Node n1 = toStreamRecLFSC(ss, tp, *(pf.d_children[0]), tb + 1, map);
- Debug("mgd") << "\ndoing trans proof, got n1 " << n1 << "\n";
- if(tb == 1) {
- Debug("mgdx") << "\ntrans proof[0], got n1 " << n1 << "\n";
- }
-
- bool identicalEqualities = false;
- bool evenLengthSequence;
- std::stringstream dontCare;
- Node nodeAfterEqualitySequence =
- toStreamRecLFSC(dontCare, tp, *(pf.d_children[0]), tb + 1, map);
-
- std::map<size_t, Node> childToStream;
-
- std::pair<Node, Node> nodePair;
- for (size_t i = 1; i < pf.d_children.size(); ++i)
- {
- std::stringstream ss1(ss.str()), ss2;
- ss.str("");
-
- // In congruences, we can have something like a[x] - it's important to
- // keep these,
- // and not turn them into (a[x]=true), because that will mess up the
- // congruence application
- // later.
-
- if (pf.d_children[i]->d_id != theory::eq::MERGED_THROUGH_CONGRUENCE)
- pf.d_children[i]->d_node =
- simplifyBooleanNode(pf.d_children[i]->d_node);
-
- // It is possible that we've already converted the i'th child to stream.
- // If so,
- // use previously stored result. Otherwise, convert and store.
- Node n2;
- if (childToStream.find(i) != childToStream.end())
- n2 = childToStream[i];
- else
- {
- n2 = toStreamRecLFSC(ss2, tp, *(pf.d_children[i]), tb + 1, map);
- childToStream[i] = n2;
- }
-
- Debug("mgd") << "\ndoing trans proof, got (first) n2 " << n2 << "\n";
-
- // The following branch is dedicated to handling sequences of identical
- // equalities,
- // i.e. trans[ a=b, a=b, a=b ].
- //
- // There are two cases:
- // 1. The number of equalities is odd. Then, the sequence can be
- // collapsed to just one equality,
- // i.e. a=b.
- // 2. The number of equalities is even. Now, we have two options: a=a
- // or b=b. To determine this,
- // we look at the node after the equality sequence. If it needs a,
- // we go for a=a; and if it needs
- // b, we go for b=b. If there is no following node, we look at the
- // goal of the transitivity proof,
- // and use it to determine which option we need.
-
- if (n2.getKind() == kind::EQUAL)
- {
- if (((n1[0] == n2[0]) && (n1[1] == n2[1]))
- || ((n1[0] == n2[1]) && (n1[1] == n2[0])))
- {
- // We are in a sequence of identical equalities
-
- Debug("pf::array") << "Detected identical equalities: " << std::endl
- << "\t" << n1 << std::endl;
-
- if (!identicalEqualities)
- {
- // The sequence of identical equalities has started just now
- identicalEqualities = true;
-
- Debug("pf::array")
- << "The sequence is just beginning. Determining length..."
- << std::endl;
-
- // Determine whether the length of this sequence is odd or even.
- evenLengthSequence = true;
- bool sequenceOver = false;
- size_t j = i + 1;
-
- while (j < pf.d_children.size() && !sequenceOver)
- {
- std::stringstream ignore;
- nodeAfterEqualitySequence =
- toStreamRecLFSC(ignore, tp, *(pf.d_children[j]), tb + 1, map);
- if (((nodeAfterEqualitySequence[0] == n1[0])
- && (nodeAfterEqualitySequence[1] == n1[1]))
- || ((nodeAfterEqualitySequence[0] == n1[1])
- && (nodeAfterEqualitySequence[1] == n1[0])))
- {
- evenLengthSequence = !evenLengthSequence;
- }
- else
- {
- sequenceOver = true;
- }
-
- ++j;
- }
-
- nodePair =
- tp->identicalEqualitiesPrinterHelper(evenLengthSequence,
- sequenceOver,
- pf,
- map,
- ss1.str(),
- &ss,
- n1,
- nodeAfterEqualitySequence);
- n1 = nodePair.first;
- nodeAfterEqualitySequence = nodePair.second;
- }
- else
- {
- ss.str(ss1.str());
- }
-
- // Ignore the redundancy.
- continue;
- }
- }
-
- if (identicalEqualities)
- {
- // We were in a sequence of identical equalities, but it has now ended.
- // Resume normal operation.
- identicalEqualities = false;
- }
-
- Debug("mgd") << "\ndoing trans proof, got n2 " << n2 << "\n";
- if (tb == 1)
- {
- Debug("mgdx") << "\ntrans proof[" << i << "], got n2 " << n2 << "\n";
- Debug("mgdx") << (n2.getKind() == kind::EQUAL) << "\n";
-
- if ((n1.getNumChildren() >= 2) && (n2.getNumChildren() >= 2))
- {
- Debug("mgdx") << n1[0].getId() << " " << n1[1].getId() << " / "
- << n2[0].getId() << " " << n2[1].getId() << "\n";
- Debug("mgdx") << n1[0].getId() << " " << n1[0] << "\n";
- Debug("mgdx") << n1[1].getId() << " " << n1[1] << "\n";
- Debug("mgdx") << n2[0].getId() << " " << n2[0] << "\n";
- Debug("mgdx") << n2[1].getId() << " " << n2[1] << "\n";
- Debug("mgdx") << (n1[0] == n2[0]) << "\n";
- Debug("mgdx") << (n1[1] == n2[1]) << "\n";
- Debug("mgdx") << (n1[0] == n2[1]) << "\n";
- Debug("mgdx") << (n1[1] == n2[0]) << "\n";
- }
- }
-
- // We can hadnle one of the equalities being negative, but not both
- Assert((n1.getKind() != kind::NOT) || (n2.getKind() != kind::NOT));
-
- firstNeg = false;
- secondNeg = false;
-
- if (n1.getKind() == kind::NOT) {
- Debug("mgdx") << "n1 is negative" << std::endl;
- Debug("pf::array") << "n1 = " << n1 << ", n2 = " << n2 << std::endl;
- firstNeg = true;
- ss << "(negtrans1 _ _ _ _ ";
- n1 = n1[0];
- } else if (n2.getKind() == kind::NOT) {
- Debug("mgdx") << "n2 is negative" << std::endl;
- Debug("pf::array") << "n1 = " << n1 << ", n2 = " << n2 << std::endl;
- secondNeg = true;
- ss << "(negtrans2 _ _ _ _ ";
- n2 = n2[0];
- } else {
- ss << "(trans _ _ _ _ ";
- }
-
- if((n2.getKind() == kind::EQUAL) && (n1.getKind() == kind::EQUAL))
- // Both elements of the transitivity rule are equalities/iffs
- {
- if(n1[0] == n2[0]) {
- if(tb == 1) { Debug("mgdx") << "case 1\n"; }
- n1 = n1[1].eqNode(n2[1]);
- ss << (firstNeg ? "(negsymm _ _ _ " : "(symm _ _ _ ") << ss1.str() << ") " << ss2.str();
- } else if(n1[1] == n2[1]) {
- if(tb == 1) { Debug("mgdx") << "case 2\n"; }
- n1 = n1[0].eqNode(n2[0]);
- ss << ss1.str() << (secondNeg ? " (negsymm _ _ _ " : " (symm _ _ _ " ) << ss2.str() << ")";
- } else if(n1[0] == n2[1]) {
- if(tb == 1) { Debug("mgdx") << "case 3\n"; }
- if(!firstNeg && !secondNeg) {
- n1 = n2[0].eqNode(n1[1]);
- ss << ss2.str() << " " << ss1.str();
- } else if (firstNeg) {
- n1 = n1[1].eqNode(n2[0]);
- ss << " (negsymm _ _ _ " << ss1.str() << ") (symm _ _ _ " << ss2.str() << ")";
- } else {
- Assert(secondNeg);
- n1 = n1[1].eqNode(n2[0]);
- ss << " (symm _ _ _ " << ss1.str() << ") (negsymm _ _ _ " << ss2.str() << ")";
- }
- if(tb == 1) { Debug("mgdx") << "++ proved " << n1 << "\n"; }
- } else if(n1[1] == n2[0]) {
- if(tb == 1) { Debug("mgdx") << "case 4\n"; }
- n1 = n1[0].eqNode(n2[1]);
- ss << ss1.str() << " " << ss2.str();
- } else {
- Warning() << "\n\ntrans proof failure at step " << i << "\n\n";
- Warning() << "0 proves " << n1 << "\n";
- Warning() << "1 proves " << n2 << "\n\n";
- pf.debug_print("mgdx", 0, &proofPrinter);
- //toStreamRec(Warning.getStream(), pf, 0);
- Warning() << "\n\n";
- Unreachable();
- }
- Debug("mgd") << "++ trans proof[" << i << "], now have " << n1 << std::endl;
- } else if(n1.getKind() == kind::EQUAL) {
- // n1 is an equality/iff, but n2 is a predicate
- if(n1[0] == n2) {
- n1 = n1[1];
- ss << (firstNeg ? "(negsymm _ _ _ " : "(symm _ _ _ ")
- << ss1.str() << ") (pred_eq_t _ " << ss2.str() << ")";
- } else if(n1[1] == n2) {
- n1 = n1[0];
- ss << ss1.str() << " (pred_eq_t _ " << ss2.str() << ")";
- } else {
- Unreachable();
- }
- } else if(n2.getKind() == kind::EQUAL) {
- // n2 is an equality/iff, but n1 is a predicate
- if(n2[0] == n1) {
- n1 = n2[1];
- ss << (secondNeg ? "(negsymm _ _ _ " : "(symm _ _ _ ")
- << ss2.str() << ") (pred_eq_t _ " << ss1.str() << ")";
- } else if(n2[1] == n1) {
- n1 = n2[0];
- ss << ss2.str() << " (pred_eq_t _ " << ss1.str() << ")";
- } else {
- Unreachable();
- }
- } else {
- // Both n1 and n2 are prediacates. Don't know what to do...
- Unreachable();
- }
-
- ss << ")";
-
- if (firstNeg || secondNeg) {
- n1 = (n1.getKind() == kind::NOT) ? n1[0] : n1.notNode();
- }
- }
-
- out << ss.str();
- Debug("mgd") << "\n++ trans proof done, have proven " << n1 << std::endl;
- //return (firstNeg || secondNeg) ? n1.notNode() : n1;
- return n1;
- }
-
- case theory::eq::MERGED_THROUGH_CONSTANTS:
- {
- Debug("pf::array") << "Proof for: " << pf.d_node << std::endl;
- Assert(pf.d_node.getKind() == kind::NOT);
- Node n = pf.d_node[0];
- Assert(n.getKind() == kind::EQUAL);
- Assert(n.getNumChildren() == 2);
- Assert(n[0].isConst() && n[1].isConst());
-
- ProofManager::getTheoryProofEngine()->printConstantDisequalityProof(
- out, n[0].toExpr(), n[1].toExpr(), map);
- return pf.d_node;
- }
-
- default:
- {
- if (pf.d_id == d_reasonRow)
- {
- Debug("mgd") << "row lemma: " << pf.d_node << std::endl;
- Assert(pf.d_node.getKind() == kind::EQUAL);
-
- if (pf.d_node[1].getKind() == kind::SELECT)
- {
- // This is the case where ((a[i]:=t)[k] == a[k]), and the sub-proof
- // explains why (i != k).
- TNode t1, t2, t3, t4;
- Node ret;
- if (pf.d_node[1].getKind() == kind::SELECT
- && pf.d_node[1][0].getKind() == kind::STORE
- && pf.d_node[0].getKind() == kind::SELECT
- && pf.d_node[0][0] == pf.d_node[1][0][0]
- && pf.d_node[0][1] == pf.d_node[1][1])
- {
- t2 = pf.d_node[1][0][1];
- t3 = pf.d_node[1][1];
- t1 = pf.d_node[0][0];
- t4 = pf.d_node[1][0][2];
- ret = pf.d_node[1].eqNode(pf.d_node[0]);
- Debug("mgd") << "t1 " << t1 << "\nt2 " << t2 << "\nt3 " << t3
- << "\nt4 " << t4 << "\n";
- }
- else
- {
- Assert(pf.d_node[0].getKind() == kind::SELECT
- && pf.d_node[0][0].getKind() == kind::STORE
- && pf.d_node[1].getKind() == kind::SELECT
- && pf.d_node[1][0] == pf.d_node[0][0][0]
- && pf.d_node[1][1] == pf.d_node[0][1]);
- t2 = pf.d_node[0][0][1];
- t3 = pf.d_node[0][1];
- t1 = pf.d_node[1][0];
- t4 = pf.d_node[0][0][2];
- ret = pf.d_node;
- Debug("mgd") << "t1 " << t1 << "\nt2 " << t2 << "\nt3 " << t3
- << "\nt4 " << t4 << "\n";
- }
-
- // inner index != outer index
- // t3 is the outer index
-
- Assert(pf.d_children.size() == 1);
- std::stringstream ss;
- Node subproof =
- toStreamRecLFSC(ss, tp, *(pf.d_children[0]), tb + 1, map);
-
- out << "(row _ _ ";
- tp->printTerm(t2.toExpr(), out, map);
- out << " ";
- tp->printTerm(t3.toExpr(), out, map);
- out << " ";
- tp->printTerm(t1.toExpr(), out, map);
- out << " ";
- tp->printTerm(t4.toExpr(), out, map);
- out << " ";
-
- Debug("pf::array") << "pf.d_children[0]->d_node is: "
- << pf.d_children[0]->d_node << ". t3 is: " << t3
- << std::endl
- << "subproof is: " << subproof << std::endl;
-
- Debug("pf::array") << "Subproof is: " << ss.str() << std::endl;
-
- // The subproof needs to show that t2 != t3. This can either be a direct
- // disequality,
- // or, if (wlog) t2 is constant, it can show that t3 is equal to another
- // constant.
- if (subproof.getKind() == kind::NOT)
- {
- // The subproof is for t2 != t3 (or t3 != t2)
- if (subproof[0][1] == t3)
- {
- Debug("pf::array") << "Dont need symmetry!" << std::endl;
- out << ss.str();
- }
- else
- {
- Debug("pf::array") << "Need symmetry!" << std::endl;
- out << "(negsymm _ _ _ " << ss.str() << ")";
- }
- }
- else
- {
- // Either t2 or t3 is a constant.
- Assert(subproof.getKind() == kind::EQUAL);
- Assert(subproof[0].isConst() || subproof[1].isConst());
- Assert(t2.isConst() || t3.isConst());
- Assert(!(t2.isConst() && t3.isConst()));
-
- bool t2IsConst = t2.isConst();
- if (subproof[0].isConst())
- {
- if (t2IsConst)
- {
- // (t3 == subproof[1]) == subproof[0] != t2
- // goal is t2 != t3
- // subproof already shows constant = t3
- Assert(t3 == subproof[1]);
- out << "(negtrans _ _ _ _ ";
- tp->printConstantDisequalityProof(
- out, t2.toExpr(), subproof[0].toExpr(), map);
- out << " ";
- out << ss.str();
- out << ")";
- }
- else
- {
- Assert(t2 == subproof[1]);
- out << "(negsymm _ _ _ ";
- out << "(negtrans _ _ _ _ ";
- tp->printConstantDisequalityProof(
- out, t3.toExpr(), subproof[0].toExpr(), map);
- out << " ";
- out << ss.str();
- out << "))";
- }
- }
- else
- {
- if (t2IsConst)
- {
- // (t3 == subproof[0]) == subproof[1] != t2
- // goal is t2 != t3
- // subproof already shows constant = t3
- Assert(t3 == subproof[0]);
- out << "(negtrans _ _ _ _ ";
- tp->printConstantDisequalityProof(
- out, t2.toExpr(), subproof[1].toExpr(), map);
- out << " ";
- out << "(symm _ _ _ " << ss.str() << ")";
- out << ")";
- }
- else
- {
- Assert(t2 == subproof[0]);
- out << "(negsymm _ _ _ ";
- out << "(negtrans _ _ _ _ ";
- tp->printConstantDisequalityProof(
- out, t3.toExpr(), subproof[1].toExpr(), map);
- out << " ";
- out << "(symm _ _ _ " << ss.str() << ")";
- out << "))";
- }
- }
- }
-
- out << ")";
- return ret;
- }
- else
- {
- Debug("pf::array") << "In the case of NEGATIVE ROW" << std::endl;
-
- Debug("pf::array") << "pf.d_children[0]->d_node is: "
- << pf.d_children[0]->d_node << std::endl;
-
- // This is the case where (i == k), and the sub-proof explains why
- // ((a[i]:=t)[k] != a[k])
-
- // If we wanted to remove the need for "negativerow", we would need to
- // prove i==k using a new satlem. We would:
- // 1. Create a new satlem.
- // 2. Assume that i != k
- // 3. Apply ROW to show that ((a[i]:=t)[k] == a[k])
- // 4. Contradict this with the fact that ((a[i]:=t)[k] != a[k]),
- // obtaining our contradiction
-
- TNode t1, t2, t3, t4;
- Node ret;
-
- // pf.d_node is an equality, i==k.
- t1 = pf.d_node[0];
- t2 = pf.d_node[1];
-
- // pf.d_children[0]->d_node will have the form: (not (= (select (store
- // a_565 i7 e_566) i1) (select a_565 i1))),
- // or its symmetrical version.
-
- unsigned side;
- if (pf.d_children[0]->d_node[0][0].getKind() == kind::SELECT
- && pf.d_children[0]->d_node[0][0][0].getKind() == kind::STORE)
- {
- side = 0;
- }
- else if (pf.d_children[0]->d_node[0][1].getKind() == kind::SELECT
- && pf.d_children[0]->d_node[0][1][0].getKind() == kind::STORE)
- {
- side = 1;
- }
- else
- {
- Unreachable();
- }
-
- Debug("pf::array") << "Side is: " << side << std::endl;
-
- // The array's index and element types will come from the subproof...
- t3 = pf.d_children[0]->d_node[0][side][0][0];
- t4 = pf.d_children[0]->d_node[0][side][0][2];
- ret = pf.d_node;
-
- // The order of indices needs to match; we might have to swap t1 and t2
- // and then apply symmetry.
- bool swap = (t2 == pf.d_children[0]->d_node[0][side][0][1]);
-
- Debug("mgd") << "t1 " << t1 << "\nt2 " << t2 << "\nt3 " << t3 << "\nt4 "
- << t4 << "\n";
-
- Assert(pf.d_children.size() == 1);
- std::stringstream ss;
- Node subproof =
- toStreamRecLFSC(ss, tp, *(pf.d_children[0]), tb + 1, map);
-
- Debug("pf::array") << "Subproof is: " << ss.str() << std::endl;
-
- if (swap)
- {
- out << "(symm _ _ _ ";
- }
-
- out << "(negativerow _ _ ";
- tp->printTerm(swap ? t2.toExpr() : t1.toExpr(), out, map);
- out << " ";
- tp->printTerm(swap ? t1.toExpr() : t2.toExpr(), out, map);
- out << " ";
- tp->printTerm(t3.toExpr(), out, map);
- out << " ";
- tp->printTerm(t4.toExpr(), out, map);
- out << " ";
-
- if (side != 0)
- {
- out << "(negsymm _ _ _ " << ss.str() << ")";
- }
- else
- {
- out << ss.str();
- }
-
- out << ")";
-
- if (swap)
- {
- out << ") ";
- }
-
- return ret;
- }
- }
- else if (pf.d_id == d_reasonRow1)
- {
- Debug("mgd") << "row1 lemma: " << pf.d_node << std::endl;
- Assert(pf.d_node.getKind() == kind::EQUAL);
- TNode t1, t2, t3;
- Node ret;
- if (pf.d_node[1].getKind() == kind::SELECT
- && pf.d_node[1][0].getKind() == kind::STORE
- && pf.d_node[1][0][1] == pf.d_node[1][1]
- && pf.d_node[1][0][2] == pf.d_node[0])
- {
- t1 = pf.d_node[1][0][0];
- t2 = pf.d_node[1][0][1];
- t3 = pf.d_node[0];
- ret = pf.d_node[1].eqNode(pf.d_node[0]);
- Debug("mgd") << "t1 " << t1 << "\nt2 " << t2 << "\nt3 " << t3 << "\n";
- }
- else
- {
- Assert(pf.d_node[0].getKind() == kind::SELECT
- && pf.d_node[0][0].getKind() == kind::STORE
- && pf.d_node[0][0][1] == pf.d_node[0][1]
- && pf.d_node[0][0][2] == pf.d_node[1]);
- t1 = pf.d_node[0][0][0];
- t2 = pf.d_node[0][0][1];
- t3 = pf.d_node[1];
- ret = pf.d_node;
- Debug("mgd") << "t1 " << t1 << "\nt2 " << t2 << "\nt3 " << t3 << "\n";
- }
- out << "(row1 _ _ ";
- tp->printTerm(t1.toExpr(), out, map);
- out << " ";
- tp->printTerm(t2.toExpr(), out, map);
- out << " ";
- tp->printTerm(t3.toExpr(), out, map);
- out << ")";
- return ret;
- }
- else if (pf.d_id == d_reasonExt) {
- Assert(pf.d_node.getKind() == kind::NOT);
- Assert(pf.d_node[0].getKind() == kind::EQUAL);
- Assert(pf.d_children.size() == 1);
- std::shared_ptr<theory::eq::EqProof> child_proof = pf.d_children[0];
- Assert(child_proof->d_node.getKind() == kind::NOT);
- Assert(child_proof->d_node[0].getKind() == kind::EQUAL);
-
- Debug("mgd") << "EXT lemma: " << pf.d_node << std::endl;
-
- TNode t1, t2, t3;
- t1 = child_proof->d_node[0][0];
- t2 = child_proof->d_node[0][1];
- t3 = pf.d_node[0][0][1];
-
- Debug("mgd") << "t1 " << t1 << "\nt2 " << t2 << "\nt3 " << t3 << "\n";
-
- out << "(or_elim_1 _ _ ";
- out << ProofManager::getLitName(child_proof->d_node[0]);
- out << " ";
- out << ProofManager::getArrayProof()->skolemToLiteral(t3.toExpr());
- out << ")";
-
- return pf.d_node;
- }
-
- else {
- Assert(!pf.d_node.isNull());
- Assert(pf.d_children.empty());
- Debug("mgd") << "theory proof: " << pf.d_node << " by rule " << int(pf.d_id) << std::endl;
- AlwaysAssert(false);
- return pf.d_node;
- }
-}
- }
-}
-
-ArrayProof::ArrayProof(theory::arrays::TheoryArrays* arrays, TheoryProofEngine* pe)
- : TheoryProof(arrays, pe)
-{}
-
-theory::TheoryId ArrayProof::getTheoryId() { return theory::THEORY_ARRAYS; }
-void ArrayProof::registerTerm(Expr term) {
- // already registered
- if (d_declarations.find(term) != d_declarations.end())
- return;
-
- Type type = term.getType();
- if (type.isSort()) {
- // declare uninterpreted sorts
- d_sorts.insert(type);
- }
-
- if (term.getKind() == kind::APPLY_UF) {
- Expr function = term.getOperator();
- d_declarations.insert(function);
- }
-
- if (term.isVariable()) {
- d_declarations.insert(term);
- }
-
- if (term.getKind() == kind::SELECT && term.getType().isBoolean()) {
- // Ensure cnf literals
- Node asNode(term);
- ProofManager::currentPM()->ensureLiteral(
- asNode.eqNode(NodeManager::currentNM()->mkConst(true)));
- ProofManager::currentPM()->ensureLiteral(
- asNode.eqNode(NodeManager::currentNM()->mkConst(false)));
- }
-
- // recursively declare all other terms
- for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- // could belong to other theories
- d_proofEngine->registerTerm(term[i]);
- }
-}
-
-std::string ArrayProof::skolemToLiteral(Expr skolem) {
- Debug("pf::array") << "ArrayProof::skolemToLiteral( " << skolem << ")" << std::endl;
- Assert(d_skolemToLiteral.find(skolem) != d_skolemToLiteral.end());
- return d_skolemToLiteral[skolem];
-}
-
-void LFSCArrayProof::printOwnedTermAsType(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType)
-{
- Assert(theory::Theory::theoryOf(term) == theory::THEORY_ARRAYS);
-
- if (theory::Theory::theoryOf(term) != theory::THEORY_ARRAYS) {
- // We can get here, for instance, if there's a (select ite ...), e.g. a non-array term
- // hiding as a subterm of an array term. In that case, send it back to the dispatcher.
- d_proofEngine->printBoundTerm(term, os, map);
- return;
- }
-
- if (term.getKind() == kind::VARIABLE || term.getKind() == kind::SKOLEM) {
- os << term;
- return;
- }
-
- Assert((term.getKind() == kind::SELECT)
- || (term.getKind() == kind::PARTIAL_SELECT_0)
- || (term.getKind() == kind::PARTIAL_SELECT_1)
- || (term.getKind() == kind::STORE));
-
- switch (term.getKind()) {
- case kind::SELECT: {
- Assert(term.getNumChildren() == 2);
-
- bool convertToBool = (term[1].getType().isBoolean() && !d_proofEngine->printsAsBool(term[1]));
-
- os << "(apply _ _ (apply _ _ (read ";
- printSort(ArrayType(term[0].getType()).getIndexType(), os);
- os << " ";
- printSort(ArrayType(term[0].getType()).getConstituentType(), os);
- os << ") ";
- printTerm(term[0], os, map);
- os << ") ";
- if (convertToBool) os << "(f_to_b ";
- printTerm(term[1], os, map);
- if (convertToBool) os << ")";
- os << ") ";
- return;
- }
-
- case kind::PARTIAL_SELECT_0:
- Assert(term.getNumChildren() == 1);
- os << "(read ";
- printSort(ArrayType(term[0].getType()).getIndexType(), os);
- os << " ";
- printSort(ArrayType(term[0].getType()).getConstituentType(), os);
- os << ") ";
- return;
-
- case kind::PARTIAL_SELECT_1:
- Debug("pf::array") << "This branch has not beed tested yet." << std::endl;
- Unreachable();
-
- Assert(term.getNumChildren() == 1);
- os << "(apply _ _ (read ";
- printSort(ArrayType(term[0].getType()).getIndexType(), os);
- os << " ";
- printSort(ArrayType(term[0].getType()).getConstituentType(), os);
- os << ") ";
- printTerm(term[0], os, map);
- os << ") ";
- return;
-
- case kind::STORE:
- os << "(apply _ _ (apply _ _ (apply _ _ (write ";
- printSort(ArrayType(term[0].getType()).getIndexType(), os);
- os << " ";
- printSort(ArrayType(term[0].getType()).getConstituentType(), os);
- os << ") ";
- printTerm(term[0], os, map);
- os << ") ";
- printTerm(term[1], os, map);
- os << ") ";
- printTerm(term[2], os, map);
- os << ") ";
- return;
-
- default:
- Unreachable();
- return;
- }
-}
-
-void LFSCArrayProof::printOwnedSort(Type type, std::ostream& os) {
- Debug("pf::array") << std::endl << "(pf::array) LFSCArrayProof::printOwnedSort: type is: " << type << std::endl;
- Assert(type.isArray() || type.isSort());
- if (type.isArray()){
- ArrayType array_type(type);
-
- Debug("pf::array") << "LFSCArrayProof::printOwnedSort: type is an array. Index type: "
- << array_type.getIndexType()
- << ", element type: " << array_type.getConstituentType() << std::endl;
-
- os << "(Array ";
- printSort(array_type.getIndexType(), os);
- os << " ";
- printSort(array_type.getConstituentType(), os);
- os << ")";
- } else {
- os << type;
- }
-}
-
-void LFSCArrayProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren, const ProofLetMap& map) {
- os << " ;; Array Theory Lemma \n;;";
- for (unsigned i = 0; i < lemma.size(); ++i) {
- os << lemma[i] <<" ";
- }
- os <<"\n";
- //os << " (clausify_false trust)";
- ArrayProof::printTheoryLemmaProof(lemma, os, paren, map);
-}
-
-void LFSCArrayProof::printSortDeclarations(std::ostream& os, std::ostream& paren) {
- // declaring the sorts
- for (TypeSet::const_iterator it = d_sorts.begin(); it != d_sorts.end(); ++it) {
- if (!ProofManager::currentPM()->wasPrinted(*it)) {
- os << "(% " << *it << " sort\n";
- paren << ")";
- ProofManager::currentPM()->markPrinted(*it);
- }
- }
-}
-
-void LFSCArrayProof::printTermDeclarations(std::ostream& os, std::ostream& paren) {
- Debug("pf::array") << "Arrays declaring terms..." << std::endl;
-
- for (ExprSet::const_iterator it = d_declarations.begin(); it != d_declarations.end(); ++it) {
- Expr term = *it;
-
- Assert(term.getType().isArray() || term.isVariable());
-
- Debug("pf::array") << "LFSCArrayProof::printDeclarations: term is: " << term
- << ". It's type is: " << term.getType()
- << std::endl;
-
- if (term.getType().isArray()){
- ArrayType array_type(term.getType());
-
- Debug("pf::array") << "LFSCArrayProof::printDeclarations: term is an array. Index type: "
- << array_type.getIndexType()
- << ", element type: " << array_type.getConstituentType() << std::endl;
-
- os << "(% " << ProofManager::sanitize(term) << " ";
- os << "(term ";
- os << "(Array ";
-
- printSort(array_type.getIndexType(), os);
- os << " ";
- printSort(array_type.getConstituentType(), os);
-
- os << "))\n";
- paren << ")";
- } else {
- Assert(term.isVariable());
- if (ProofManager::getSkolemizationManager()->isSkolem(*it)) {
- Debug("pf::array") << "This term is a skoelm!" << std::endl;
- d_skolemDeclarations.insert(*it);
- } else {
- os << "(% " << ProofManager::sanitize(term) << " ";
- os << "(term ";
- os << term.getType() << ")\n";
- paren << ")";
- }
- }
- }
-
- Debug("pf::array") << "Declaring terms done!" << std::endl;
-}
-
-void LFSCArrayProof::printDeferredDeclarations(std::ostream& os, std::ostream& paren) {
- Debug("pf::array") << "Array: print deferred declarations called" << std::endl;
-
- unsigned count = 1;
- for (ExprSet::const_iterator it = d_skolemDeclarations.begin(); it != d_skolemDeclarations.end(); ++it) {
- Expr term = *it;
- Node equality = ProofManager::getSkolemizationManager()->getDisequality(*it);
-
- Debug("pf::array") << "LFSCArrayProof::printDeferredDeclarations: term is: " << *it << std::endl
- << "It is a witness for: " << equality << std::endl;
-
- std::ostringstream newSkolemLiteral;
- newSkolemLiteral << ".sl" << count++;
- std::string skolemLiteral = newSkolemLiteral.str();
-
- d_skolemToLiteral[*it] = skolemLiteral;
-
- Debug("pf::array") << "LFSCArrayProof::printDeferredDeclarations: new skolem literal is: " << skolemLiteral << std::endl;
-
- Assert(equality.getKind() == kind::NOT);
- Assert(equality[0].getKind() == kind::EQUAL);
-
- Node array_one = equality[0][0];
- Node array_two = equality[0][1];
-
- ProofLetMap map;
- os << "(ext _ _ ";
- printTerm(array_one.toExpr(), os, map);
- os << " ";
- printTerm(array_two.toExpr(), os, map);
- os << " (\\ ";
- os << ProofManager::sanitize(*it);
- os << " (\\ ";
- os << skolemLiteral.c_str();
- os << "\n";
-
- paren << ")))";
- }
-}
-
-void LFSCArrayProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) {
- // Nothing to do here at this point.
-}
-
-bool LFSCArrayProof::printsAsBool(const Node &n)
-{
- if (n.getKind() == kind::SELECT)
- return true;
-
- return false;
-}
-
-} /* CVC4 namespace */
diff --git a/src/proof/array_proof.h b/src/proof/array_proof.h
deleted file mode 100644
index ffcff165a..000000000
--- a/src/proof/array_proof.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/********************* */
-/*! \file array_proof.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Tim King, Mathias Preiner, Guy Katz
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Arrray proof
- **
- ** Arrau proof
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__ARRAY__PROOF_H
-#define CVC4__ARRAY__PROOF_H
-
-#include <memory>
-#include <unordered_set>
-
-#include "expr/expr.h"
-#include "proof/proof_manager.h"
-#include "proof/theory_proof.h"
-#include "theory/arrays/theory_arrays.h"
-#include "theory/uf/equality_engine.h"
-
-namespace CVC4 {
-
-// Proof object outputted by TheoryARRAY.
-class ProofArray : public Proof {
- public:
- ProofArray(std::shared_ptr<theory::eq::EqProof> pf, unsigned row,
- unsigned row1, unsigned ext);
-
- void registerSkolem(Node equality, Node skolem);
-
- void toStream(std::ostream& out) const override;
- void toStream(std::ostream& out, const ProofLetMap& map) const override;
-
- private:
- void toStreamLFSC(std::ostream& out,
- TheoryProof* tp,
- const theory::eq::EqProof& pf,
- const ProofLetMap& map) const;
-
- Node toStreamRecLFSC(std::ostream& out,
- TheoryProof* tp,
- const theory::eq::EqProof& pf,
- unsigned tb,
- const ProofLetMap& map) const;
-
- // It is simply an equality engine proof.
- std::shared_ptr<theory::eq::EqProof> d_proof;
-
- /** Merge tag for ROW applications */
- unsigned d_reasonRow;
- /** Merge tag for ROW1 applications */
- unsigned d_reasonRow1;
- /** Merge tag for EXT applications */
- unsigned d_reasonExt;
-};
-
-namespace theory {
-namespace arrays{
-class TheoryArrays;
-} /* namespace CVC4::theory::arrays */
-} /* namespace CVC4::theory */
-
-typedef std::unordered_set<Type, TypeHashFunction > TypeSet;
-
-class ArrayProof : public TheoryProof {
- // TODO: whatever goes in this theory
-protected:
- TypeSet d_sorts; // all the uninterpreted sorts in this theory
- ExprSet d_declarations; // all the variable/function declarations
- ExprSet d_skolemDeclarations; // all the skolem variable declarations
- std::map<Expr, std::string> d_skolemToLiteral;
- theory::TheoryId getTheoryId() override;
-
- public:
- ArrayProof(theory::arrays::TheoryArrays* arrays, TheoryProofEngine* proofEngine);
-
- std::string skolemToLiteral(Expr skolem);
-
- void registerTerm(Expr term) override;
-};
-
-class LFSCArrayProof : public ArrayProof {
-public:
- LFSCArrayProof(theory::arrays::TheoryArrays* arrays, TheoryProofEngine* proofEngine)
- : ArrayProof(arrays, proofEngine)
- {}
-
- void printOwnedTermAsType(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType) override;
- void printOwnedSort(Type type, std::ostream& os) override;
- void printTheoryLemmaProof(std::vector<Expr>& lemma,
- std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& map) override;
- void printSortDeclarations(std::ostream& os, std::ostream& paren) override;
- void printTermDeclarations(std::ostream& os, std::ostream& paren) override;
- void printDeferredDeclarations(std::ostream& os,
- std::ostream& paren) override;
- void printAliasingDeclarations(std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& globalLetMap) override;
-
- bool printsAsBool(const Node& n) override;
-};
-
-
-}/* CVC4 namespace */
-
-#endif /* CVC4__ARRAY__PROOF_H */
diff --git a/src/proof/bitvector_proof.cpp b/src/proof/bitvector_proof.cpp
deleted file mode 100644
index 98e3300f5..000000000
--- a/src/proof/bitvector_proof.cpp
+++ /dev/null
@@ -1,792 +0,0 @@
-/********************* */
-/*! \file bitvector_proof.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Liana Hadarean, Guy Katz, Alex Ozdemir
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** Contains implementions (e.g. code for printing bitblasting bindings that is
- ** common to all kinds of bitvector proofs.
- **/
-
-#include "proof/bitvector_proof.h"
-#include "options/bv_options.h"
-#include "options/proof_options.h"
-#include "proof/proof_output_channel.h"
-#include "proof/theory_proof.h"
-#include "prop/sat_solver_types.h"
-#include "theory/bv/bitblast/bitblaster.h"
-#include "theory/bv/theory_bv.h"
-
-namespace CVC4 {
-
-namespace proof {
-BitVectorProof::BitVectorProof(theory::bv::TheoryBV* bv,
- TheoryProofEngine* proofEngine)
- : TheoryProof(bv, proofEngine),
- d_declarations(),
- d_seenBBTerms(),
- d_bbTerms(),
- d_bbAtoms(),
- d_bitblaster(nullptr),
- d_useConstantLetification(false),
- d_cnfProof()
-{
-}
-
-void BitVectorProof::setBitblaster(theory::bv::TBitblaster<Node>* bb)
-{
- Assert(d_bitblaster == NULL);
- d_bitblaster = bb;
-}
-
-void BitVectorProof::registerTermBB(Expr term)
-{
- Debug("pf::bv") << "BitVectorProof::registerTermBB( " << term
- << " )" << std::endl;
-
- if (d_seenBBTerms.find(term) != d_seenBBTerms.end()) return;
-
- d_seenBBTerms.insert(term);
- d_bbTerms.push_back(term);
-
- // If this term gets used in the final proof, we will want to register it.
- // However, we don't know this at this point; and when the theory proof engine
- // sees it, if it belongs to another theory, it won't register it with this
- // proof. So, we need to tell the engine to inform us.
-
- if (theory::Theory::theoryOf(term) != theory::THEORY_BV)
- {
- Debug("pf::bv") << "\tMarking term " << term
- << " for future BV registration" << std::endl;
- d_proofEngine->markTermForFutureRegistration(term, theory::THEORY_BV);
- }
-}
-
-void BitVectorProof::registerAtomBB(Expr atom, Expr atom_bb) {
- Debug("pf::bv") << "BitVectorProof::registerAtomBB( " << atom
- << ", " << atom_bb << " )" << std::endl;
-
- Expr def = atom.eqExpr(atom_bb);
- d_bbAtoms.insert(std::make_pair(atom, def));
- registerTerm(atom);
-
- // Register the atom's terms for bitblasting
- registerTermBB(atom[0]);
- registerTermBB(atom[1]);
-}
-
-void BitVectorProof::registerTerm(Expr term) {
- Debug("pf::bv") << "BitVectorProof::registerTerm( " << term << " )"
- << std::endl;
-
- if (options::lfscLetification() && term.isConst()
- && term.getType().isBitVector())
- {
- if (d_constantLetMap.find(term) == d_constantLetMap.end()) {
- std::ostringstream name;
- name << "letBvc" << d_constantLetMap.size();
- d_constantLetMap[term] = name.str();
- }
- }
-
- d_usedBB.insert(term);
-
- if (theory::Theory::isLeafOf(term, theory::THEORY_BV) && !term.isConst())
- {
- d_declarations.insert(term);
- }
-
- Debug("pf::bv") << "Going to register children: " << std::endl;
- for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- Debug("pf::bv") << "\t" << term[i] << std::endl;
- }
-
- // don't care about parametric operators for bv?
- for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- d_proofEngine->registerTerm(term[i]);
- }
-}
-
-std::string BitVectorProof::getBBTermName(Expr expr)
-{
- Debug("pf::bv") << "BitVectorProof::getBBTermName( " << expr << " ) = bt"
- << expr.getId() << std::endl;
- std::ostringstream os;
- os << "bt" << expr.getId();
- return os.str();
-}
-
-void BitVectorProof::printOwnedTermAsType(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType)
-{
- Debug("pf::bv") << std::endl
- << "(pf::bv) BitVectorProof::printOwnedTerm( " << term
- << " ), theory is: " << theory::Theory::theoryOf(term)
- << std::endl;
-
- Assert(theory::Theory::theoryOf(term) == theory::THEORY_BV);
-
- // peel off eager bit-blasting trick
- if (term.getKind() == kind::BITVECTOR_EAGER_ATOM) {
- d_proofEngine->printBoundTerm(term[0], os, map);
- return;
- }
-
- switch (term.getKind()) {
- case kind::CONST_BITVECTOR : {
- printConstant(term, os);
- return;
- }
- case kind::BITVECTOR_AND :
- case kind::BITVECTOR_OR :
- case kind::BITVECTOR_XOR :
- case kind::BITVECTOR_NAND :
- case kind::BITVECTOR_NOR :
- case kind::BITVECTOR_XNOR :
- case kind::BITVECTOR_COMP :
- case kind::BITVECTOR_MULT :
- case kind::BITVECTOR_PLUS :
- case kind::BITVECTOR_SUB :
- case kind::BITVECTOR_UDIV :
- case kind::BITVECTOR_UREM :
- case kind::BITVECTOR_UDIV_TOTAL :
- case kind::BITVECTOR_UREM_TOTAL :
- case kind::BITVECTOR_SDIV :
- case kind::BITVECTOR_SREM :
- case kind::BITVECTOR_SMOD :
- case kind::BITVECTOR_SHL :
- case kind::BITVECTOR_LSHR :
- case kind::BITVECTOR_ASHR :
- case kind::BITVECTOR_CONCAT : {
- printOperatorNary(term, os, map);
- return;
- }
- case kind::BITVECTOR_NEG :
- case kind::BITVECTOR_NOT :
- case kind::BITVECTOR_ROTATE_LEFT :
- case kind::BITVECTOR_ROTATE_RIGHT : {
- printOperatorUnary(term, os, map);
- return;
- }
- case kind::EQUAL :
- case kind::BITVECTOR_ULT :
- case kind::BITVECTOR_ULE :
- case kind::BITVECTOR_UGT :
- case kind::BITVECTOR_UGE :
- case kind::BITVECTOR_SLT :
- case kind::BITVECTOR_SLE :
- case kind::BITVECTOR_SGT :
- case kind::BITVECTOR_SGE : {
- printPredicate(term, os, map);
- return;
- }
- case kind::BITVECTOR_EXTRACT :
- case kind::BITVECTOR_REPEAT :
- case kind::BITVECTOR_ZERO_EXTEND :
- case kind::BITVECTOR_SIGN_EXTEND : {
- printOperatorParametric(term, os, map);
- return;
- }
- case kind::BITVECTOR_BITOF : {
- printBitOf(term, os, map);
- return;
- }
-
- case kind::VARIABLE: {
- os << "(a_var_bv " << utils::getSize(term)<< " " << ProofManager::sanitize(term) << ")";
- return;
- }
-
- case kind::SKOLEM: {
-
- // TODO: we need to distinguish between "real" skolems (e.g. from array) and "fake" skolems,
- // like ITE terms. Is there a more elegant way?
-
- if (ProofManager::getSkolemizationManager()->isSkolem(term)) {
- os << ProofManager::sanitize(term);
- } else {
- os << "(a_var_bv " << utils::getSize(term)<< " " << ProofManager::sanitize(term) << ")";
- }
- return;
- }
-
- default:
- Unreachable();
- }
-}
-
-void BitVectorProof::printEmptyClauseProof(std::ostream& os,
- std::ostream& paren)
-{
- Assert(options::bitblastMode() == options::BitblastMode::EAGER)
- << "the BV theory should only be proving bottom directly in the eager "
- "bitblasting mode";
-}
-
-void BitVectorProof::printBitOf(Expr term,
- std::ostream& os,
- const ProofLetMap& map)
-{
- Assert(term.getKind() == kind::BITVECTOR_BITOF);
- unsigned bit = term.getOperator().getConst<BitVectorBitOf>().d_bitIndex;
- Expr var = term[0];
-
- Debug("pf::bv") << "BitVectorProof::printBitOf( " << term << " ), "
- << "bit = " << bit << ", var = " << var << std::endl;
-
- os << "(bitof ";
- os << d_exprToVariableName[var];
- os << " " << bit << ")";
-}
-
-void BitVectorProof::printConstant(Expr term, std::ostream& os)
-{
- Assert(term.isConst());
- os << "(a_bv " << utils::getSize(term) << " ";
-
- if (d_useConstantLetification) {
- os << d_constantLetMap[term] << ")";
- } else {
- std::ostringstream paren;
- int size = utils::getSize(term);
- for (int i = size - 1; i >= 0; --i) {
- os << "(bvc ";
- os << (utils::getBit(term, i) ? "b1" : "b0") <<" ";
- paren << ")";
- }
- os << " bvn)";
- os << paren.str();
- }
-}
-
-void BitVectorProof::printOperatorNary(Expr term,
- std::ostream& os,
- const ProofLetMap& map)
-{
- std::string op = utils::toLFSCKindTerm(term);
- std::ostringstream paren;
- std::string holes = term.getKind() == kind::BITVECTOR_CONCAT ? "_ _ " : "";
- unsigned size = term.getKind() == kind::BITVECTOR_CONCAT? utils::getSize(term) :
- utils::getSize(term[0]); // cause of COMP
-
- for (unsigned i = 0; i < term.getNumChildren() - 1; ++i) {
- os <<"("<< op <<" " << size <<" " << holes;
- }
- d_proofEngine->printBoundTerm(term[0], os, map);
- os <<" ";
- for (unsigned i = 1; i < term.getNumChildren(); ++i) {
- d_proofEngine->printBoundTerm(term[i], os, map);
- os << ")";
- }
-}
-
-void BitVectorProof::printOperatorUnary(Expr term,
- std::ostream& os,
- const ProofLetMap& map)
-{
- os <<"(";
- os << utils::toLFSCKindTerm(term) << " " << utils::getSize(term) <<" ";
- os << " ";
- d_proofEngine->printBoundTerm(term[0], os, map);
- os <<")";
-}
-
-void BitVectorProof::printPredicate(Expr term,
- std::ostream& os,
- const ProofLetMap& map)
-{
- os <<"(";
- os << utils::toLFSCKindTerm(term) << " " << utils::getSize(term[0]) <<" ";
- os << " ";
- d_proofEngine->printBoundTerm(term[0], os, map);
- os << " ";
- d_proofEngine->printBoundTerm(term[1], os, map);
- os <<")";
-}
-
-void BitVectorProof::printOperatorParametric(Expr term,
- std::ostream& os,
- const ProofLetMap& map)
-{
- os <<"(";
- os << utils::toLFSCKindTerm(term) << " " << utils::getSize(term) <<" ";
- os <<" ";
- if (term.getKind() == kind::BITVECTOR_REPEAT) {
- unsigned amount =
- term.getOperator().getConst<BitVectorRepeat>().d_repeatAmount;
- os << amount <<" _ ";
- }
- if (term.getKind() == kind::BITVECTOR_SIGN_EXTEND) {
- unsigned amount =
- term.getOperator().getConst<BitVectorSignExtend>().d_signExtendAmount;
- os << amount <<" _ ";
- }
-
- if (term.getKind() == kind::BITVECTOR_ZERO_EXTEND) {
- unsigned amount =
- term.getOperator().getConst<BitVectorZeroExtend>().d_zeroExtendAmount;
- os << amount<<" _ ";
- }
- if (term.getKind() == kind::BITVECTOR_EXTRACT) {
- unsigned low = utils::getExtractLow(term);
- unsigned high = utils::getExtractHigh(term);
- os << high <<" " << low << " " << utils::getSize(term[0]);
- }
- os <<" ";
- Assert(term.getNumChildren() == 1);
- d_proofEngine->printBoundTerm(term[0], os, map);
- os <<")";
-}
-
-void BitVectorProof::printOwnedSort(Type type, std::ostream& os)
-{
- Debug("pf::bv") << std::endl
- << "(pf::bv) BitVectorProof::printOwnedSort( " << type << " )"
- << std::endl;
- Assert(type.isBitVector());
- unsigned width = utils::getSize(type);
- os << "(BitVec " << width << ")";
-}
-
-void BitVectorProof::printSortDeclarations(std::ostream& os,
- std::ostream& paren)
-{
- // Nothing to do here at this point.
-}
-
-void BitVectorProof::printTermDeclarations(std::ostream& os,
- std::ostream& paren)
-{
- ExprSet::const_iterator it = d_declarations.begin();
- ExprSet::const_iterator end = d_declarations.end();
- for (; it != end; ++it) {
- if ((it->isVariable() || it->isConst()) && !ProofManager::getSkolemizationManager()->isSkolem(*it)) {
- d_exprToVariableName[*it] = ProofManager::sanitize(*it);
- } else {
- std::string newAlias = assignAlias(*it);
- d_exprToVariableName[*it] = newAlias;
- }
-
- os << "(% " << d_exprToVariableName[*it] <<" var_bv" << "\n";
- paren <<")";
- }
-}
-
-void BitVectorProof::printDeferredDeclarations(std::ostream& os,
- std::ostream& paren)
-{
- if (options::lfscLetification()) {
- os << std::endl << ";; BV const letification\n" << std::endl;
- std::map<Expr,std::string>::const_iterator it;
- for (it = d_constantLetMap.begin(); it != d_constantLetMap.end(); ++it) {
- os << "\n(@ " << it->second << " ";
- std::ostringstream localParen;
- int size = utils::getSize(it->first);
- for (int i = size - 1; i >= 0; --i) {
- os << "(bvc ";
- os << (utils::getBit(it->first, i) ? "b1" : "b0") << " ";
- localParen << ")";
- }
- os << "bvn";
- os << localParen.str();
- paren << ")";
- }
- os << std::endl;
-
- d_useConstantLetification = true;
- }
-}
-
-void BitVectorProof::printAliasingDeclarations(std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& globalLetMap)
-{
- // Print "trust" statements to bind complex bv variables to their associated terms
-
- ExprToString::const_iterator it = d_assignedAliases.begin();
- ExprToString::const_iterator end = d_assignedAliases.end();
-
- for (; it != end; ++it) {
- Debug("pf::bv") << "Printing aliasing declaration for: " << *it << std::endl;
- std::stringstream declaration;
- declaration << ".fbvd" << d_aliasToBindDeclaration.size();
- d_aliasToBindDeclaration[it->second] = declaration.str();
-
- os << "(th_let_pf _ ";
-
- os << "(trust_f ";
- os << "(= (BitVec " << utils::getSize(it->first) << ") ";
- os << "(a_var_bv " << utils::getSize(it->first) << " " << it->second << ") ";
- d_proofEngine->printBoundTerm(it->first, os, globalLetMap);
- os << ")) ";
- os << "(\\ "<< d_aliasToBindDeclaration[it->second] << "\n";
- paren << "))";
- }
-
- os << "\n";
-}
-
-void BitVectorProof::printTermBitblasting(Expr term, std::ostream& os)
-{
- // TODO: once we have the operator elimination rules remove those that we
- // eliminated
- Assert(term.getType().isBitVector());
- Kind kind = term.getKind();
-
- if (theory::Theory::isLeafOf(term, theory::THEORY_BV) && !term.isConst())
- {
- // A term is a leaf if it has no children, or if it belongs to another theory
- os << "(bv_bbl_var " << utils::getSize(term) << " " << d_exprToVariableName[term];
- os << " _)";
- return;
- }
-
- switch(kind) {
- case kind::CONST_BITVECTOR : {
- os << "(bv_bbl_const "<< utils::getSize(term) <<" _ ";
- std::ostringstream paren;
- int size = utils::getSize(term);
- if (d_useConstantLetification) {
- os << d_constantLetMap[term] << ")";
- } else {
- for (int i = size - 1; i>= 0; --i) {
- os << "(bvc ";
- os << (utils::getBit(term, i) ? "b1" : "b0") <<" ";
- paren << ")";
- }
- os << " bvn)";
- os << paren.str();
- }
- return;
- }
-
- case kind::BITVECTOR_AND :
- case kind::BITVECTOR_OR :
- case kind::BITVECTOR_XOR :
- case kind::BITVECTOR_NAND :
- case kind::BITVECTOR_NOR :
- case kind::BITVECTOR_XNOR :
- case kind::BITVECTOR_COMP :
- case kind::BITVECTOR_MULT :
- case kind::BITVECTOR_PLUS :
- case kind::BITVECTOR_SUB :
- case kind::BITVECTOR_CONCAT : {
- Debug("pf::bv") << "Bitblasing kind = " << kind << std::endl;
-
- for (int i = term.getNumChildren() - 1; i > 0; --i) {
- os <<"(bv_bbl_"<< utils::toLFSCKind(kind);
-
- if (kind == kind::BITVECTOR_CONCAT) {
- os << " " << utils::getSize(term) << " _";
- }
- os << " _ _ _ _ _ _ ";
- }
-
- os << getBBTermName(term[0]) << " ";
-
- for (unsigned i = 1; i < term.getNumChildren(); ++i) {
- os << getBBTermName(term[i]);
- os << ") ";
- }
- return;
- }
-
- case kind::BITVECTOR_NEG :
- case kind::BITVECTOR_NOT :
- case kind::BITVECTOR_ROTATE_LEFT :
- case kind::BITVECTOR_ROTATE_RIGHT : {
- os << "(bv_bbl_"<<utils::toLFSCKind(kind);
- os << " _ _ _ _ ";
- os << getBBTermName(term[0]);
- os << ")";
- return;
- }
- case kind::BITVECTOR_EXTRACT : {
- os <<"(bv_bbl_"<<utils::toLFSCKind(kind);
-
- os << " " << utils::getSize(term) << " ";
- os << utils::getExtractHigh(term) << " ";
- os << utils::getExtractLow(term) << " ";
- os << " _ _ _ _ ";
-
- os << getBBTermName(term[0]);
- os <<")";
- return;
- }
- case kind::BITVECTOR_REPEAT :
- case kind::BITVECTOR_ZERO_EXTEND :
- case kind::BITVECTOR_SIGN_EXTEND : {
- os << "(bv_bbl_" << utils::toLFSCKind(kind) << " ";
- os << utils::getSize(term) << " ";
- if (term.getKind() == kind::BITVECTOR_REPEAT) {
- unsigned amount =
- term.getOperator().getConst<BitVectorRepeat>().d_repeatAmount;
- os << amount;
- }
- if (term.getKind() == kind::BITVECTOR_SIGN_EXTEND) {
- unsigned amount =
- term.getOperator().getConst<BitVectorSignExtend>().d_signExtendAmount;
- os << amount;
- }
-
- if (term.getKind() == kind::BITVECTOR_ZERO_EXTEND) {
- unsigned amount =
- term.getOperator().getConst<BitVectorZeroExtend>().d_zeroExtendAmount;
- os << amount;
- }
-
- os <<" _ _ _ _ ";
- os << getBBTermName(term[0]);
- os <<")";
- return;
- }
- case kind::BITVECTOR_UDIV :
- case kind::BITVECTOR_UREM :
- case kind::BITVECTOR_UDIV_TOTAL :
- case kind::BITVECTOR_UREM_TOTAL :
- case kind::BITVECTOR_SDIV :
- case kind::BITVECTOR_SREM :
- case kind::BITVECTOR_SMOD :
- case kind::BITVECTOR_SHL :
- case kind::BITVECTOR_LSHR :
- case kind::BITVECTOR_ASHR : {
- // these are terms for which bit-blasting is not supported yet
- std::ostringstream paren;
- os <<"(trust_bblast_term _ ";
- paren <<")";
- d_proofEngine->printLetTerm(term, os);
- os <<" ";
- std::vector<Node> bits;
- d_bitblaster->bbTerm(term, bits);
-
- for (int i = utils::getSize(term) - 1; i >= 0; --i) {
- os << "(bbltc ";
- d_proofEngine->printLetTerm((bits[i]).toExpr(), os);
- paren << ")";
- }
- os << "bbltn" << paren.str();
- return;
- }
-
- default: Unreachable() << "BitVectorProof Unknown operator";
- }
-}
-
-void BitVectorProof::printAtomBitblasting(Expr atom,
- std::ostream& os,
- bool swap)
-{
- Kind kind = atom.getKind();
- switch(kind) {
- case kind::BITVECTOR_ULT :
- case kind::BITVECTOR_ULE :
- case kind::BITVECTOR_UGT :
- case kind::BITVECTOR_UGE :
- case kind::BITVECTOR_SLT :
- case kind::BITVECTOR_SLE :
- case kind::BITVECTOR_SGT :
- case kind::BITVECTOR_SGE :
- case kind::EQUAL: {
- Debug("pf::bv") << "Bitblasing kind = " << kind << std::endl;
-
- os << "(bv_bbl_" << utils::toLFSCKindTerm(atom);
-
- if (swap) {os << "_swap";}
-
- os << " _ _ _ _ _ _ ";
- os << getBBTermName(atom[0]);
- os << " ";
- os << getBBTermName(atom[1]);
- os << ")";
-
- return;
- }
- default: Unreachable() << "BitVectorProof Unknown atom kind";
- }
-}
-
-void BitVectorProof::printAtomBitblastingToFalse(Expr atom, std::ostream& os)
-{
- Assert(atom.getKind() == kind::EQUAL);
-
- os << "(bv_bbl_=_false";
- os << " _ _ _ _ _ _ ";
- os << getBBTermName(atom[0]);
-
- os << " ";
-
- os << getBBTermName(atom[1]);
-
- os << ")";
-}
-
-void BitVectorProof::printBitblasting(std::ostream& os, std::ostream& paren)
-{
- // bit-blast terms
- {
- Debug("pf::bv")
- << "BitVectorProof::printBitblasting: the bitblasted terms are: "
- << std::endl;
- std::vector<Expr>::const_iterator it = d_bbTerms.begin();
- std::vector<Expr>::const_iterator end = d_bbTerms.end();
-
- for (; it != end; ++it) {
- if (d_usedBB.find(*it) == d_usedBB.end()) {
- Debug("pf::bv") << "\t" << *it << "\t(UNUSED)" << std::endl;
- } else {
- Debug("pf::bv") << "\t" << *it << std::endl;
- }
- }
-
- Debug("pf::bv") << std::endl;
- }
-
- std::vector<Expr>::const_iterator it = d_bbTerms.begin();
- std::vector<Expr>::const_iterator end = d_bbTerms.end();
- for (; it != end; ++it) {
- if (d_usedBB.find(*it) == d_usedBB.end()
- && options::bitblastMode() != options::BitblastMode::EAGER)
- continue;
-
- // Is this term has an alias, we inject it through the decl_bblast statement
- if (hasAlias(*it)) {
- os << "(decl_bblast_with_alias _ _ _ _ ";
- printTermBitblasting(*it, os);
- os << " " << d_aliasToBindDeclaration[d_assignedAliases[*it]] << " ";
- os << "(\\ "<< getBBTermName(*it);
- os << "\n";
- paren <<"))";
- } else {
- os << "(decl_bblast _ _ _ ";
- printTermBitblasting(*it, os);
- os << "(\\ "<< getBBTermName(*it);
- os << "\n";
- paren <<"))";
- }
- }
- // bit-blast atoms
- ExprToExpr::const_iterator ait = d_bbAtoms.begin();
- ExprToExpr::const_iterator aend = d_bbAtoms.end();
- for (; ait != aend; ++ait) {
- if (d_usedBB.find(ait->first) == d_usedBB.end()
- && options::bitblastMode() != options::BitblastMode::EAGER)
- continue;
-
- os << "(th_let_pf _ ";
- if (ait->first.getKind() == kind::CONST_BOOLEAN) {
- bool val = ait->first.getConst<bool>();
- os << "(iff_symm " << (val ? "true" : "false" ) << ")";
- } else {
- Assert(ait->first == ait->second[0]);
-
- bool swap = false;
- if (ait->first.getKind() == kind::EQUAL) {
- Expr bitwiseEquivalence = ait->second[1];
- if ((bitwiseEquivalence.getKind() == kind::CONST_BOOLEAN) && !bitwiseEquivalence.getConst<bool>()) {
- printAtomBitblastingToFalse(ait->first, os);
- } else {
- if (bitwiseEquivalence.getKind() != kind::AND) {
- // Just one bit
- if (bitwiseEquivalence.getNumChildren() > 0 && bitwiseEquivalence[0].getKind() == kind::BITVECTOR_BITOF) {
- swap = (ait->first[1] == bitwiseEquivalence[0][0]);
- }
- } else {
- // Multiple bits
- if (bitwiseEquivalence[0].getNumChildren() > 0 &&
- bitwiseEquivalence[0][0].getKind() == kind::BITVECTOR_BITOF) {
- swap = (ait->first[1] == bitwiseEquivalence[0][0][0]);
- } else if (bitwiseEquivalence[0].getNumChildren() > 0 &&
- bitwiseEquivalence[0][1].getKind() == kind::BITVECTOR_BITOF) {
- swap = (ait->first[0] == bitwiseEquivalence[0][1][0]);
- }
- }
-
- printAtomBitblasting(ait->first, os, swap);
- }
- } else {
- printAtomBitblasting(ait->first, os, swap);
- }
- }
-
- os <<"(\\ " << ProofManager::getPreprocessedAssertionName(ait->second) <<"\n";
- paren <<"))";
- }
-}
-
-theory::TheoryId BitVectorProof::getTheoryId() { return theory::THEORY_BV; }
-
-const std::set<Node>* BitVectorProof::getAtomsInBitblastingProof()
-{
- return &d_atomsInBitblastingProof;
-}
-
-std::string BitVectorProof::assignAlias(Expr expr)
-{
- Assert(d_exprToVariableName.find(expr) == d_exprToVariableName.end());
-
- std::stringstream ss;
- ss << "fbv" << d_assignedAliases.size();
- Debug("pf::bv") << "assignAlias( " << expr << ") = " << ss.str() << std::endl;
- d_assignedAliases[expr] = ss.str();
- return ss.str();
-}
-
-bool BitVectorProof::hasAlias(Expr expr)
-{
- return d_assignedAliases.find(expr) != d_assignedAliases.end();
-}
-
-void BitVectorProof::printConstantDisequalityProof(
- std::ostream& os, Expr c1, Expr c2, const ProofLetMap& globalLetMap)
-{
- Assert(c1.isConst());
- Assert(c2.isConst());
- Assert(utils::getSize(c1) == utils::getSize(c2));
-
- os << "(bv_disequal_constants " << utils::getSize(c1) << " ";
-
- std::ostringstream paren;
-
- for (int i = utils::getSize(c1) - 1; i >= 0; --i) {
- os << "(bvc ";
- os << (utils::getBit(c1, i) ? "b1" : "b0") << " ";
- paren << ")";
- }
- os << "bvn";
- os << paren.str();
-
- os << " ";
-
- for (int i = utils::getSize(c2) - 1; i >= 0; --i) {
- os << "(bvc ";
- os << (utils::getBit(c2, i) ? "b1" : "b0") << " ";
-
- }
- os << "bvn";
- os << paren.str();
-
- os << ")";
-}
-
-void BitVectorProof::printRewriteProof(std::ostream& os,
- const Node& n1,
- const Node& n2)
-{
- ProofLetMap emptyMap;
- os << "(rr_bv_default ";
- d_proofEngine->printBoundTerm(n2.toExpr(), os, emptyMap);
- os << " ";
- d_proofEngine->printBoundTerm(n1.toExpr(), os, emptyMap);
- os << ")";
-}
-
-} // namespace proof
-
-} // namespace CVC4
diff --git a/src/proof/bitvector_proof.h b/src/proof/bitvector_proof.h
deleted file mode 100644
index 9a9071e58..000000000
--- a/src/proof/bitvector_proof.h
+++ /dev/null
@@ -1,280 +0,0 @@
-/********************* */
-/*! \file bitvector_proof.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Alex Ozdemir, Mathias Preiner, Liana Hadarean
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Bitvector proof base class
- **
- ** Contains code (e.g. proof printing code) which is common to all bitvector
- *proofs.
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__BITVECTOR_PROOF_H
-#define CVC4__BITVECTOR_PROOF_H
-
-#include <set>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-#include "expr/expr.h"
-#include "proof/cnf_proof.h"
-#include "proof/theory_proof.h"
-#include "prop/sat_solver.h"
-#include "theory/bv/theory_bv.h"
-
-// Since TBitblaster and BitVectorProof are cyclically dependent, we need this
-// forward declaration
-namespace CVC4 {
-namespace theory {
-namespace bv {
-template <class T>
-class TBitblaster;
-}
-} // namespace theory
-} // namespace CVC4
-
-namespace CVC4 {
-
-namespace proof {
-
-typedef std::unordered_set<Expr, ExprHashFunction> ExprSet;
-typedef std::unordered_map<Expr, ClauseId, ExprHashFunction> ExprToClauseId;
-typedef std::unordered_map<Expr, unsigned, ExprHashFunction> ExprToId;
-typedef std::unordered_map<Expr, Expr, ExprHashFunction> ExprToExpr;
-typedef std::unordered_map<Expr, std::string, ExprHashFunction> ExprToString;
-
-/**
- * A bitvector proof is best understood as having
- *
- * 1. A declaration of a "bitblasted formulas" -- boolean formulas
- * that are each translations of a BV-literal (a comparison between BVs).
- *
- * (and a proof that each "bitblasted formula" is implied by the
- * corresponding BV literal)
- *
- * 2. A declaration of a cnf formula equisatisfiable to the bitblasted
- * formula
- *
- * (and a proof that each clause is implied by some bitblasted formula)
- *
- * 3. A proof of UNSAT from the clauses.
- *
- * This class is responsible for 1 & 2. The proof of UNSAT is delegated to a
- * subclass.
- */
-class BitVectorProof : public TheoryProof
-{
- protected:
- BitVectorProof(theory::bv::TheoryBV* bv, TheoryProofEngine* proofEngine);
- virtual ~BitVectorProof(){};
-
- // Set of BV variables in the input. (e.g. "a" in [ a = 000 ] ^ [ a == 001 ])
- ExprSet d_declarations;
-
- // terms and formulas that are actually relevant to the proof
- ExprSet d_usedBB;
-
- ExprSet d_seenBBTerms; // terms that need to be bit-blasted
- std::vector<Expr> d_bbTerms; // order of bit-blasting
-
- /** atoms that need to be bit-blasted,
- * BV-literals -> (BV-literals <=> bool formula)
- * where a BV literal is a signed or unsigned comparison.
- */
- ExprToExpr d_bbAtoms;
-
- // map from Expr representing normalized lemma to ClauseId in SAT solver
- ExprToClauseId d_bbConflictMap;
-
- theory::bv::TBitblaster<Node>* d_bitblaster;
-
- /** In an LFSC proof the manifestation of this expression bit-level
- * representation will have a string name. This method returns that name.
- */
- std::string getBBTermName(Expr expr);
-
- /** A mapping from constant BV terms to identifiers that will refer to them in
- * an LFSC proof, if constant-letification is enabled.
- */
- std::map<Expr, std::string> d_constantLetMap;
-
- /** Should we introduced identifiers to refer to BV constant terms? It may
- * reduce the textual size of a proof!
- */
- bool d_useConstantLetification;
-
- /** Temporary storage for the set of nodes in the bitblasted formula which
- * correspond to CNF variables eventually used in the proof of unsat on the
- * CNF formula
- */
- std::set<Node> d_atomsInBitblastingProof;
-
- /**
- * Prints out
- * (a) a declaration of bit-level interpretations corresponding to bits in
- * the input BV terms.
- * (b) a proof that the each BV literal entails a boolean formula on
- * bitof expressions.
- */
- void printBitblasting(std::ostream& os, std::ostream& paren);
-
- /**
- * The proof that the bit-blasted SAT formula is correctly converted to CNF
- */
- std::unique_ptr<CnfProof> d_cnfProof;
-
- theory::TheoryId getTheoryId() override;
-
- public:
- void printOwnedTermAsType(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType) override;
-
- void printOwnedSort(Type type, std::ostream& os) override;
-
- /**
- * Populate the d_atomsInBitblastingProof member.
- * See its documentation
- */
- virtual void calculateAtomsInBitblastingProof() = 0;
-
- /**
- * Prints out a declaration of the bit-blasting, and the subsequent
- * conversion of the result to CNF
- *
- * @param os the stream to print to
- * @param paren a stream that will be placed at the back of the proof (for
- * closing parens)
- * @param letMap The let-map, which contains information about LFSC
- * identifiers and the values they reference.
- */
- virtual void printBBDeclarationAndCnf(std::ostream& os,
- std::ostream& paren,
- ProofLetMap& letMap) = 0;
-
- /**
- * Prints a proof of the empty clause.
- *
- * @param os the stream to print to
- * @param paren any parentheses to add to the end of the global proof
- */
- virtual void printEmptyClauseProof(std::ostream& os, std::ostream& paren);
-
- /**
- * Read the d_atomsInBitblastingProof member.
- * See its documentation.
- */
- const std::set<Node>* getAtomsInBitblastingProof();
-
- void registerTermBB(Expr term);
-
- /**
- * Informs the proof that the `atom` predicate was bitblasted into the
- * `atom_bb` term.
- *
- * The `atom` term must be a comparison of bitvectors, and the `atom_bb` term
- * a boolean formula on bitof expressions
- */
- void registerAtomBB(Expr atom, Expr atom_bb);
-
- void registerTerm(Expr term) override;
-
- /**
- * This must be done before registering any terms or atoms, since the CNF
- * proof must reflect the result of bitblasting those
- *
- * Feeds the SAT solver's true and false variables into the CNF stream.
- */
- virtual void initCnfProof(prop::CnfStream* cnfStream,
- context::Context* cnf,
- prop::SatVariable trueVar,
- prop::SatVariable falseVar) = 0;
-
- CnfProof* getCnfProof() { return d_cnfProof.get(); }
-
- /**
- * Attaches this BVP to the given SAT solver, initializing a SAT proof.
- *
- * This must be invoked before `initCnfProof` because a SAT proof must already
- * exist to initialize a CNF proof.
- */
- virtual void attachToSatSolver(prop::SatSolver& sat_solver) = 0;
-
- void setBitblaster(theory::bv::TBitblaster<Node>* bb);
-
- /**
- * Kind of a mess. Used for resulution-based BVP's, where in eager mode this
- * must be invoked before printing a proof of the empty clause. In lazy mode
- * the behavior and purpose are both highly unclear.
- *
- * This exists as a virtual method of BitVectorProof, and not
- * ResolutionBitVectorProof, because the machinery that invokes it is
- * high-level enough that it doesn't know the difference between clausal and
- * resolution proofs.
- *
- * TODO(aozdemir) figure out what is going on and clean this up
- * Issue: https://github.com/CVC4/CVC4/issues/2789
- */
- virtual void finalizeConflicts(std::vector<Expr>& conflicts){};
-
- private:
- ExprToString d_exprToVariableName;
-
- ExprToString d_assignedAliases;
- std::map<std::string, std::string> d_aliasToBindDeclaration;
- std::string assignAlias(Expr expr);
- bool hasAlias(Expr expr);
-
- // Functions for printing various BV terms. Helpers for BV's `printOwnedTerm`
- void printConstant(Expr term, std::ostream& os);
- void printOperatorNary(Expr term, std::ostream& os, const ProofLetMap& map);
- void printOperatorUnary(Expr term, std::ostream& os, const ProofLetMap& map);
- void printPredicate(Expr term, std::ostream& os, const ProofLetMap& map);
- void printOperatorParametric(Expr term, std::ostream& os, const ProofLetMap& map);
- void printBitOf(Expr term, std::ostream& os, const ProofLetMap& map);
-
- /**
- * Prints the LFSC construction of a bblast_term for `term`
- */
- void printTermBitblasting(Expr term, std::ostream& os);
-
- /**
- * For a given BV-atom (a comparison), prints a proof that that comparison
- * holds iff the bitblasted equivalent of it holds.
- * Uses a side-condidition to do the bit-blasting.
- */
- void printAtomBitblasting(Expr term, std::ostream& os, bool swap);
- void printAtomBitblastingToFalse(Expr term, std::ostream& os);
-
- void printSortDeclarations(std::ostream& os, std::ostream& paren) override;
- void printTermDeclarations(std::ostream& os, std::ostream& paren) override;
- void printDeferredDeclarations(std::ostream& os,
- std::ostream& paren) override;
- void printAliasingDeclarations(std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& globalLetMap) override;
-
- void printConstantDisequalityProof(std::ostream& os,
- Expr c1,
- Expr c2,
- const ProofLetMap& globalLetMap) override;
- void printRewriteProof(std::ostream& os,
- const Node& n1,
- const Node& n2) override;
-};
-
-} // namespace proof
-
-}/* CVC4 namespace */
-
-#endif /* CVC4__BITVECTOR__PROOF_H */
diff --git a/src/proof/clausal_bitvector_proof.cpp b/src/proof/clausal_bitvector_proof.cpp
deleted file mode 100644
index 21e8056ca..000000000
--- a/src/proof/clausal_bitvector_proof.cpp
+++ /dev/null
@@ -1,412 +0,0 @@
-/********************* */
-/*! \file clausal_bitvector_proof.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Alex Ozdemir, Mathias Preiner, Andres Noetzli
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Bitvector proof using the DRAT proof format
- **
- ** Contains DRAT-specific printing logic.
- **/
-
-#include "cvc4_private.h"
-
-#include <algorithm>
-#include <iostream>
-#include <iterator>
-#include <map>
-
-#include "options/bv_options.h"
-#include "proof/clausal_bitvector_proof.h"
-#include "proof/dimacs.h"
-#include "proof/drat/drat_proof.h"
-#include "proof/er/er_proof.h"
-#include "proof/lfsc_proof_printer.h"
-#include "proof/lrat/lrat_proof.h"
-#include "prop/sat_solver_types.h"
-#include "smt/smt_statistics_registry.h"
-#include "theory/bv/theory_bv.h"
-
-#if CVC4_USE_DRAT2ER
-#include "drat2er_options.h"
-#include "drat_trim_interface.h"
-#endif
-
-namespace CVC4 {
-
-namespace proof {
-
-ClausalBitVectorProof::ClausalBitVectorProof(theory::bv::TheoryBV* bv,
- TheoryProofEngine* proofEngine)
- : BitVectorProof(bv, proofEngine),
- d_clauses(),
- d_originalClauseIndices(),
- d_binaryDratProof(),
- d_coreClauseIndices(),
- d_dratTranslationStatistics(),
- d_dratOptimizationStatistics()
-{
-}
-
-void ClausalBitVectorProof::attachToSatSolver(prop::SatSolver& sat_solver)
-{
- sat_solver.setClausalProofLog(this);
-}
-
-void ClausalBitVectorProof::initCnfProof(prop::CnfStream* cnfStream,
- context::Context* cnf,
- prop::SatVariable trueVar,
- prop::SatVariable falseVar)
-{
- Assert(d_cnfProof == nullptr);
- d_cnfProof.reset(new LFSCCnfProof(cnfStream, cnf, "bb"));
-
- // Create a clause which forces the true variable to be true, and register it
- int trueClauseId = ClauseId(ProofManager::currentPM()->nextId());
- // with the CNF proof
- d_cnfProof->registerTrueUnitClause(trueClauseId);
- // and with (this) bit-vector proof
- prop::SatClause c{prop::SatLiteral(trueVar, false)};
- registerUsedClause(trueClauseId, c);
-
- // The same for false.
- int falseClauseId = ClauseId(ProofManager::currentPM()->nextId());
- d_cnfProof->registerFalseUnitClause(falseClauseId);
- c[0] = prop::SatLiteral(falseVar, true);
- registerUsedClause(falseClauseId, c);
-}
-
-void ClausalBitVectorProof::registerUsedClause(ClauseId id,
- prop::SatClause& clause)
-{
- prop::SatClause& emplaced_clause =
- d_clauses.emplace(id, clause).first->second;
- canonicalizeClause(emplaced_clause);
- d_originalClauseIndices.push_back(id);
-};
-
-void ClausalBitVectorProof::calculateAtomsInBitblastingProof()
-{
- optimizeDratProof();
-
- // Debug dump of DRAT Proof
- if (Debug.isOn("bv::clausal"))
- {
- std::string serializedDratProof = d_binaryDratProof.str();
- Debug("bv::clausal") << "option: " << options::bvOptimizeSatProof()
- << std::endl;
- Debug("bv::clausal") << "binary DRAT proof byte count: "
- << serializedDratProof.size() << std::endl;
- Debug("bv::clausal") << "clause count: " << d_coreClauseIndices.size()
- << std::endl;
- }
-
- // Empty any old record of which atoms were used
- d_atomsInBitblastingProof.clear();
- Assert(d_atomsInBitblastingProof.size() == 0);
-
- // For each used clause, ask the CNF proof which atoms are used in it
- for (const ClauseId usedIdx : d_coreClauseIndices)
- {
- d_cnfProof->collectAtoms(&d_clauses.at(usedIdx), d_atomsInBitblastingProof);
- }
-}
-
-struct SatClausePointerComparator
-{
- inline bool operator()(const prop::SatClause* const& l,
- const prop::SatClause* const& r) const
- {
- prop::SatClauseLessThan cmp;
- return cmp(*l, *r);
- }
-};
-
-void ClausalBitVectorProof::optimizeDratProof()
-{
- TimerStat::CodeTimer optimizeDratProofTimer{
- d_dratOptimizationStatistics.d_totalTime};
- if (options::bvOptimizeSatProof() == options::BvOptimizeSatProof::PROOF
- || options::bvOptimizeSatProof() == options::BvOptimizeSatProof::FORMULA)
- {
- Debug("bv::clausal") << "Optimizing DRAT" << std::endl;
- std::string formulaFilename("cvc4-dimacs-XXXXXX");
- std::string dratFilename("cvc4-drat-XXXXXX");
- std::string optDratFilename("cvc4-optimized-drat-XXXXXX");
- std::string optFormulaFilename("cvc4-optimized-formula-XXXXXX");
-
- {
- std::unique_ptr<std::fstream> formStream = openTmpFile(&formulaFilename);
- const int64_t startPos = static_cast<int64_t>(formStream->tellp());
- printDimacs(*formStream, d_clauses, d_originalClauseIndices);
- d_dratOptimizationStatistics.d_initialFormulaSize.setData(
- static_cast<int64_t>(formStream->tellp()) - startPos);
- formStream->close();
- }
-
- {
- std::unique_ptr<std::fstream> dratStream = openTmpFile(&dratFilename);
- const int64_t startPos = static_cast<int64_t>(dratStream->tellp());
- (*dratStream) << d_binaryDratProof.str();
- d_dratOptimizationStatistics.d_initialDratSize.setData(
- static_cast<int64_t>(dratStream->tellp()) - startPos);
- dratStream->close();
- }
-
- std::unique_ptr<std::fstream> optDratStream = openTmpFile(&optDratFilename);
- std::unique_ptr<std::fstream> optFormulaStream =
- openTmpFile(&optFormulaFilename);
-
-#if CVC4_USE_DRAT2ER
- {
- TimerStat::CodeTimer runDratTimeOptimizationTimer{
- d_dratOptimizationStatistics.d_toolTime};
- int dratTrimExitCode =
- drat2er::drat_trim::OptimizeWithDratTrim(formulaFilename,
- dratFilename,
- optFormulaFilename,
- optDratFilename,
- drat2er::options::QUIET);
- AlwaysAssert(dratTrimExitCode == 0)
- << "drat-trim exited with " << dratTrimExitCode;
- }
-#else
- Unimplemented()
- << "Proof production when using CryptoMiniSat requires drat2er.\n"
- << "Run contrib/get-drat2er, reconfigure with --drat2er, and rebuild";
-#endif
-
- {
- d_binaryDratProof.str("");
- Assert(d_binaryDratProof.str().size() == 0);
-
- const int64_t startPos = static_cast<int64_t>(d_binaryDratProof.tellp());
- std::ifstream lratStream(optDratFilename);
- std::copy(std::istreambuf_iterator<char>(lratStream),
- std::istreambuf_iterator<char>(),
- std::ostreambuf_iterator<char>(d_binaryDratProof));
- d_dratOptimizationStatistics.d_optimizedDratSize.setData(
- static_cast<int64_t>(d_binaryDratProof.tellp()) - startPos);
- }
-
- if (options::bvOptimizeSatProof() == options::BvOptimizeSatProof::FORMULA)
- {
- std::ifstream optFormulaInStream{optFormulaFilename};
- const int64_t startPos = static_cast<int64_t>(optFormulaInStream.tellg());
- std::vector<prop::SatClause> core = parseDimacs(optFormulaInStream);
- d_dratOptimizationStatistics.d_optimizedFormulaSize.setData(
- static_cast<int64_t>(optFormulaInStream.tellg()) - startPos);
-
- CodeTimer clauseMatchingTimer{
- d_dratOptimizationStatistics.d_clauseMatchingTime};
-
- // Now we need to compute the clause indices for the UNSAT core. This is a
- // bit difficult because drat-trim may have reordered clauses, and/or
- // removed duplicate literals. We use literal sets as the canonical clause
- // form.
- //
- // TODO (aozdemir) It may be better to use a hash map instead of a tree
- // map here.
- std::map<const prop::SatClause*, ClauseId, SatClausePointerComparator>
- cannonicalClausesToIndices;
- for (const auto& kv : d_clauses)
- {
- cannonicalClausesToIndices[&kv.second] = kv.first;
- }
-
- d_coreClauseIndices.clear();
-
- for (prop::SatClause& coreClause : core)
- {
- canonicalizeClause(coreClause);
- d_coreClauseIndices.push_back(
- cannonicalClausesToIndices.at(&coreClause));
- }
- Debug("bv::clausal") << "Optimizing the DRAT proof and the formula"
- << std::endl;
- }
- else
- {
- Debug("bv::clausal") << "Optimizing the DRAT proof but not the formula"
- << std::endl;
- d_coreClauseIndices = d_originalClauseIndices;
- }
-
- optFormulaStream->close();
-
- Assert(d_coreClauseIndices.size() > 0);
- remove(formulaFilename.c_str());
- remove(dratFilename.c_str());
- remove(optDratFilename.c_str());
- remove(optFormulaFilename.c_str());
- Debug("bv::clausal") << "Optimized DRAT" << std::endl;
- }
- else
- {
- Debug("bv::clausal") << "Not optimizing the formula or the DRAT proof"
- << std::endl;
- d_coreClauseIndices = d_originalClauseIndices;
- }
-}
-
-void ClausalBitVectorProof::canonicalizeClause(prop::SatClause& clause)
-{
- std::sort(clause.begin(), clause.end());
- clause.erase(std::unique(clause.begin(), clause.end()), clause.end());
-}
-
-ClausalBitVectorProof::DratTranslationStatistics::DratTranslationStatistics()
- : d_totalTime("proof::bv::dratTranslation::totalTime"),
- d_toolTime("proof::bv::dratTranslation::toolTime")
-{
- smtStatisticsRegistry()->registerStat(&d_totalTime);
- smtStatisticsRegistry()->registerStat(&d_toolTime);
-}
-
-ClausalBitVectorProof::DratTranslationStatistics::~DratTranslationStatistics()
-{
- smtStatisticsRegistry()->unregisterStat(&d_totalTime);
- smtStatisticsRegistry()->unregisterStat(&d_toolTime);
-}
-
-ClausalBitVectorProof::DratOptimizationStatistics::DratOptimizationStatistics()
- : d_totalTime("proof::bv::dratOptimization::totalTime"),
- d_toolTime("proof::bv::dratOptimization::toolTime"),
- d_clauseMatchingTime("proof::bv::dratOptimization::clauseMatchingTime"),
- d_initialDratSize("proof::bv::dratOptimization::initialDratSize", 0),
- d_optimizedDratSize("proof::bv::dratOptimization::optimizedDratSize", 0),
- d_initialFormulaSize("proof::bv::dratOptimization::initialFormulaSize",
- 0),
- d_optimizedFormulaSize(
- "proof::bv::dratOptimization::optimizedFormulaSize", 0)
-{
- smtStatisticsRegistry()->registerStat(&d_totalTime);
- smtStatisticsRegistry()->registerStat(&d_toolTime);
- smtStatisticsRegistry()->registerStat(&d_clauseMatchingTime);
- smtStatisticsRegistry()->registerStat(&d_initialDratSize);
- smtStatisticsRegistry()->registerStat(&d_optimizedDratSize);
- smtStatisticsRegistry()->registerStat(&d_initialFormulaSize);
- smtStatisticsRegistry()->registerStat(&d_optimizedFormulaSize);
-}
-
-ClausalBitVectorProof::DratOptimizationStatistics::~DratOptimizationStatistics()
-{
- smtStatisticsRegistry()->unregisterStat(&d_totalTime);
- smtStatisticsRegistry()->unregisterStat(&d_toolTime);
- smtStatisticsRegistry()->unregisterStat(&d_clauseMatchingTime);
- smtStatisticsRegistry()->unregisterStat(&d_initialDratSize);
- smtStatisticsRegistry()->unregisterStat(&d_optimizedDratSize);
- smtStatisticsRegistry()->unregisterStat(&d_initialFormulaSize);
- smtStatisticsRegistry()->unregisterStat(&d_optimizedFormulaSize);
-}
-
-void LfscClausalBitVectorProof::printTheoryLemmaProof(std::vector<Expr>& lemma,
- std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& map)
-{
- Unreachable() << "Clausal bit-vector proofs should only be used in "
- "combination with eager "
- "bitblasting, which **does not use theory lemmas**";
-}
-
-void LfscClausalBitVectorProof::printBBDeclarationAndCnf(std::ostream& os,
- std::ostream& paren,
- ProofLetMap& letMap)
-{
- os << "\n;; Bitblasting mappings\n";
- printBitblasting(os, paren);
-
- os << "\n;; BB-CNF mappings\n";
- d_cnfProof->printAtomMapping(d_atomsInBitblastingProof, os, paren, letMap);
-
- os << "\n;; BB-CNF proofs\n";
- for (const ClauseId id : d_coreClauseIndices)
- {
- d_cnfProof->printCnfProofForClause(id, &d_clauses.at(id), os, paren);
- }
-}
-
-void LfscDratBitVectorProof::printEmptyClauseProof(std::ostream& os,
- std::ostream& paren)
-{
- Assert(options::bitblastMode() == options::BitblastMode::EAGER)
- << "the BV theory should only be proving bottom directly in the eager "
- "bitblasting mode";
-
- os << "\n;; Proof of input to SAT solver\n";
- os << "(@ proofOfSatInput ";
- paren << ")";
-
- LFSCProofPrinter::printSatInputProof(d_coreClauseIndices, os, "bb");
-
- os << "\n;; DRAT Proof Value\n";
- os << "(@ dratProof ";
- paren << ")";
- d_dratTranslationStatistics.d_totalTime.start();
- drat::DratProof pf = drat::DratProof::fromBinary(d_binaryDratProof.str());
- d_dratTranslationStatistics.d_totalTime.stop();
- pf.outputAsLfsc(os, 2);
- os << "\n";
-
- os << "\n;; Verification of DRAT Proof\n";
- os << "(drat_proof_of_bottom _ proofOfSatInput dratProof "
- << "\n)";
-}
-
-void LfscLratBitVectorProof::printEmptyClauseProof(std::ostream& os,
- std::ostream& paren)
-{
- Assert(options::bitblastMode() == options::BitblastMode::EAGER)
- << "the BV theory should only be proving bottom directly in the eager "
- "bitblasting mode";
-
- os << "\n;; Proof of input to SAT solver\n";
- os << "(@ proofOfCMap ";
- paren << ")";
- LFSCProofPrinter::printCMapProof(d_coreClauseIndices, os, "bb");
-
- os << "\n;; DRAT Proof Value\n";
- os << "(@ lratProof ";
- paren << ")";
- d_dratTranslationStatistics.d_totalTime.start();
- lrat::LratProof pf =
- lrat::LratProof::fromDratProof(d_clauses,
- d_coreClauseIndices,
- d_binaryDratProof.str(),
- d_dratTranslationStatistics.d_toolTime);
- d_dratTranslationStatistics.d_totalTime.stop();
- pf.outputAsLfsc(os);
- os << "\n";
-
- os << "\n;; Verification of DRAT Proof\n";
- os << "(lrat_proof_of_bottom _ proofOfCMap lratProof "
- << "\n)";
-}
-
-void LfscErBitVectorProof::printEmptyClauseProof(std::ostream& os,
- std::ostream& paren)
-{
- Assert(options::bitblastMode() == options::BitblastMode::EAGER)
- << "the BV theory should only be proving bottom directly in the eager "
- "bitblasting mode";
-
- d_dratTranslationStatistics.d_totalTime.start();
- er::ErProof pf =
- er::ErProof::fromBinaryDratProof(d_clauses,
- d_coreClauseIndices,
- d_binaryDratProof.str(),
- d_dratTranslationStatistics.d_toolTime);
- d_dratTranslationStatistics.d_totalTime.stop();
-
- pf.outputAsLfsc(os);
-}
-
-} // namespace proof
-
-}; // namespace CVC4
diff --git a/src/proof/clausal_bitvector_proof.h b/src/proof/clausal_bitvector_proof.h
deleted file mode 100644
index 28a53c90c..000000000
--- a/src/proof/clausal_bitvector_proof.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/********************* */
-/*! \file clausal_bitvector_proof.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Alex Ozdemir, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Bitvector proof for clausal (DRAT/LRAT) formats
- **
- ** An internal string stream is hooked up to CryptoMiniSat, which spits out a
- ** binary DRAT proof. Depending on which kind of proof we're going to turn
- ** that into, we process it in different ways.
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__PROOF__CLAUSAL_BITVECTOR_PROOF_H
-#define CVC4__PROOF__CLAUSAL_BITVECTOR_PROOF_H
-
-#include <iostream>
-#include <sstream>
-#include <unordered_map>
-
-#include "expr/expr.h"
-#include "proof/bitvector_proof.h"
-#include "proof/drat/drat_proof.h"
-#include "proof/lrat/lrat_proof.h"
-#include "proof/theory_proof.h"
-#include "prop/cnf_stream.h"
-#include "prop/sat_solver_types.h"
-#include "theory/bv/theory_bv.h"
-#include "util/statistics_registry.h"
-
-namespace CVC4 {
-
-namespace proof {
-
-class ClausalBitVectorProof : public BitVectorProof
-{
- public:
- ClausalBitVectorProof(theory::bv::TheoryBV* bv,
- TheoryProofEngine* proofEngine);
-
- ~ClausalBitVectorProof() = default;
-
- void attachToSatSolver(prop::SatSolver& sat_solver) override;
-
- void initCnfProof(prop::CnfStream* cnfStream,
- context::Context* cnf,
- prop::SatVariable trueVar,
- prop::SatVariable falseVar) override;
-
- std::ostream& getDratOstream() { return d_binaryDratProof; }
-
- void registerUsedClause(ClauseId id, prop::SatClause& clause);
-
- void calculateAtomsInBitblastingProof() override;
-
- protected:
- // A list of all clauses and their ids which are passed into the SAT solver
- std::unordered_map<ClauseId, prop::SatClause> d_clauses{};
- std::vector<ClauseId> d_originalClauseIndices{};
- // Stores the proof recieved from the SAT solver.
- std::ostringstream d_binaryDratProof{};
- std::vector<ClauseId> d_coreClauseIndices{};
-
- struct DratTranslationStatistics
- {
- DratTranslationStatistics();
- ~DratTranslationStatistics();
-
- // Total time spent doing translation (optimized binary DRAT -> in memory
- // target format including IO, postprocessing, etc.)
- TimerStat d_totalTime;
- // Time that the external tool actually spent
- TimerStat d_toolTime;
- };
-
- DratTranslationStatistics d_dratTranslationStatistics;
-
- private:
- // Optimizes the DRAT proof stored in `d_binaryDratProof` and returns a list
- // of clause actually needed to check that proof (a smaller UNSAT core)
- void optimizeDratProof();
-
- // Given reference to a SAT clause encoded as a vector of literals, puts the
- // literals into a canonical order
- static void canonicalizeClause(prop::SatClause& clause);
-
- struct DratOptimizationStatistics
- {
- DratOptimizationStatistics();
- ~DratOptimizationStatistics();
-
- // Total time spent using drat-trim to optimize the DRAT proof/formula
- // (including IO, etc.)
- TimerStat d_totalTime;
- // Time that drat-trim actually spent optimizing the DRAT proof/formula
- TimerStat d_toolTime;
- // Time that was spent matching clauses in drat-trim's output to clauses in
- // its input
- TimerStat d_clauseMatchingTime;
- // Bytes in binary DRAT proof before optimization
- IntStat d_initialDratSize;
- // Bytes in binary DRAT proof after optimization
- IntStat d_optimizedDratSize;
- // Bytes in textual DIMACS bitblasted formula before optimization
- IntStat d_initialFormulaSize;
- // Bytes in textual DIMACS bitblasted formula after optimization
- IntStat d_optimizedFormulaSize;
- };
-
- DratOptimizationStatistics d_dratOptimizationStatistics;
-};
-
-/**
- * A representation of a clausal proof of a bitvector problem's UNSAT nature
- */
-class LfscClausalBitVectorProof : public ClausalBitVectorProof
-{
- public:
- LfscClausalBitVectorProof(theory::bv::TheoryBV* bv,
- TheoryProofEngine* proofEngine)
- : ClausalBitVectorProof(bv, proofEngine)
- {
- }
-
- void printTheoryLemmaProof(std::vector<Expr>& lemma,
- std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& map) override;
- void printBBDeclarationAndCnf(std::ostream& os,
- std::ostream& paren,
- ProofLetMap& letMap) override;
-};
-
-/**
- * A DRAT proof for a bit-vector problem
- */
-class LfscDratBitVectorProof : public LfscClausalBitVectorProof
-{
- public:
- LfscDratBitVectorProof(theory::bv::TheoryBV* bv,
- TheoryProofEngine* proofEngine)
- : LfscClausalBitVectorProof(bv, proofEngine)
- {
- }
-
- void printEmptyClauseProof(std::ostream& os, std::ostream& paren) override;
-};
-
-/**
- * An LRAT proof for a bit-vector problem
- */
-class LfscLratBitVectorProof : public LfscClausalBitVectorProof
-{
- public:
- LfscLratBitVectorProof(theory::bv::TheoryBV* bv,
- TheoryProofEngine* proofEngine)
- : LfscClausalBitVectorProof(bv, proofEngine)
- {
- }
-
- void printEmptyClauseProof(std::ostream& os, std::ostream& paren) override;
-};
-
-/**
- * An Extended Resolution proof for a bit-vector problem
- */
-class LfscErBitVectorProof : public LfscClausalBitVectorProof
-{
- public:
- LfscErBitVectorProof(theory::bv::TheoryBV* bv, TheoryProofEngine* proofEngine)
- : LfscClausalBitVectorProof(bv, proofEngine)
- {
- }
-
- void printEmptyClauseProof(std::ostream& os, std::ostream& paren) override;
-};
-
-} // namespace proof
-
-} // namespace CVC4
-
-#endif /* CVC4__PROOF__CLAUSAL_BITVECTOR_PROOF_H */
diff --git a/src/proof/clause_id.h b/src/proof/clause_id.h
index b2d36c9cb..e2dff2559 100644
--- a/src/proof/clause_id.h
+++ b/src/proof/clause_id.h
@@ -2,10 +2,10 @@
/*! \file clause_id.h
** \verbatim
** Top contributors (to current version):
- ** Paul Meng, Mathias Preiner
+ ** Paul Meng, Mathias Preiner, Liana Hadarean
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -28,6 +28,13 @@ namespace CVC4 {
*/
typedef unsigned ClauseId;
+/** Reserved clauseId values used in the resolution proof. The represent,
+ * respectively, the empty clause, that adding the clause to the SAT solver was
+ * a no-op, and that an error occurred when trying to add. */
+const ClauseId ClauseIdEmpty(-1);
+const ClauseId ClauseIdUndef(-2);
+const ClauseId ClauseIdError(-3);
+
}/* CVC4 namespace */
#endif /* CVC4__PROOF__CLAUSE_ID_H */
diff --git a/src/proof/cnf_proof.cpp b/src/proof/cnf_proof.cpp
index 677bf2f8c..c5e4dfb22 100644
--- a/src/proof/cnf_proof.cpp
+++ b/src/proof/cnf_proof.cpp
@@ -2,10 +2,10 @@
/*! \file cnf_proof.cpp
** \verbatim
** Top contributors (to current version):
- ** Liana Hadarean, Andrew Reynolds, Alex Ozdemir
+ ** Liana Hadarean, Andres Noetzli, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,8 +19,6 @@
#include "proof/clause_id.h"
#include "proof/proof_manager.h"
-#include "proof/proof_utils.h"
-#include "proof/theory_proof.h"
#include "prop/cnf_stream.h"
#include "prop/minisat/minisat.h"
#include "prop/sat_solver_types.h"
@@ -32,11 +30,7 @@ CnfProof::CnfProof(prop::CnfStream* stream,
const std::string& name)
: d_cnfStream(stream)
, d_clauseToAssertion(ctx)
- , d_assertionToProofRule(ctx)
, d_currentAssertionStack()
- , d_currentDefinitionStack()
- , d_clauseToDefinition(ctx)
- , d_definitions()
, d_cnfDeps()
, d_name(name)
{
@@ -46,86 +40,22 @@ CnfProof::CnfProof(prop::CnfStream* stream,
CnfProof::~CnfProof() {}
-bool CnfProof::isAssertion(Node node) {
- return d_assertionToProofRule.find(node) !=
- d_assertionToProofRule.end();
-}
-
-bool CnfProof::isDefinition(Node node) {
- return d_definitions.find(node) !=
- d_definitions.end();
-}
-
-ProofRule CnfProof::getProofRule(Node node) {
- Assert(isAssertion(node));
- NodeToProofRule::iterator it = d_assertionToProofRule.find(node);
- return (*it).second;
-}
-
-ProofRule CnfProof::getProofRule(ClauseId clause) {
- TNode assertion = getAssertionForClause(clause);
- return getProofRule(assertion);
-}
-
Node CnfProof::getAssertionForClause(ClauseId clause) {
ClauseIdToNode::const_iterator it = d_clauseToAssertion.find(clause);
Assert(it != d_clauseToAssertion.end() && !(*it).second.isNull());
return (*it).second;
}
-Node CnfProof::getDefinitionForClause(ClauseId clause) {
- ClauseIdToNode::const_iterator it = d_clauseToDefinition.find(clause);
- Assert(it != d_clauseToDefinition.end());
- return (*it).second;
-}
-
-void CnfProof::registerConvertedClause(ClauseId clause, bool explanation) {
+void CnfProof::registerConvertedClause(ClauseId clause)
+{
Assert(clause != ClauseIdUndef && clause != ClauseIdError
&& clause != ClauseIdEmpty);
-
- // Explanations do not need a CNF conversion proof since they are in CNF
- // (they will only need a theory proof as they are theory valid)
- if (explanation) {
- Debug("proof:cnf") << "CnfProof::registerConvertedClause "
- << clause << " explanation? " << explanation << std::endl;
- Assert(d_explanations.find(clause) == d_explanations.end());
- d_explanations.insert(clause);
- return;
- }
-
Node current_assertion = getCurrentAssertion();
- Node current_expr = getCurrentDefinition();
- Debug("proof:cnf") << "CnfProof::registerConvertedClause "
- << clause << " assertion = " << current_assertion
- << clause << " definition = " << current_expr << std::endl;
+ Debug("proof:cnf") << "CnfProof::registerConvertedClause " << clause
+ << " assertion = " << current_assertion << std::endl;
setClauseAssertion(clause, current_assertion);
- setClauseDefinition(clause, current_expr);
-}
-
-void CnfProof::registerTrueUnitClause(ClauseId clauseId)
-{
- Node trueNode = NodeManager::currentNM()->mkConst<bool>(true);
- pushCurrentAssertion(trueNode);
- pushCurrentDefinition(trueNode);
- registerConvertedClause(clauseId);
- popCurrentAssertion();
- popCurrentDefinition();
- d_cnfStream->ensureLiteral(trueNode);
- d_trueUnitClause = clauseId;
-}
-
-void CnfProof::registerFalseUnitClause(ClauseId clauseId)
-{
- Node falseNode = NodeManager::currentNM()->mkConst<bool>(false).notNode();
- pushCurrentAssertion(falseNode);
- pushCurrentDefinition(falseNode);
- registerConvertedClause(clauseId);
- popCurrentAssertion();
- popCurrentDefinition();
- d_cnfStream->ensureLiteral(falseNode);
- d_falseUnitClause = clauseId;
}
void CnfProof::setClauseAssertion(ClauseId clause, Node expr) {
@@ -145,56 +75,15 @@ void CnfProof::setClauseAssertion(ClauseId clause, Node expr) {
return;
}
- d_clauseToAssertion.insert (clause, expr);
+ d_clauseToAssertion.insert(clause, expr);
}
-void CnfProof::setClauseDefinition(ClauseId clause, Node definition) {
- Debug("proof:cnf") << "CnfProof::setClauseDefinition "
- << clause << " definition " << definition << std::endl;
- // We keep the first definition
- if (d_clauseToDefinition.find(clause) != d_clauseToDefinition.end())
- return;
-
- d_clauseToDefinition.insert(clause, definition);
- d_definitions.insert(definition);
-}
-
-void CnfProof::registerAssertion(Node assertion, ProofRule reason) {
- Debug("proof:cnf") << "CnfProof::registerAssertion "
- << assertion << " reason " << reason << std::endl;
- // We can obtain the assertion from different reasons (e.g. if the
- // assertion is a lemma over shared terms both theories can generate
- // the same lemma) We only need to prove the lemma in one way, so we
- // keep the first reason.
- if (isAssertion(assertion)) {
- return;
- }
- d_assertionToProofRule.insert(assertion, reason);
-}
-
-LemmaProofRecipe CnfProof::getProofRecipe(const std::set<Node> &lemma) {
- Assert(d_lemmaToProofRecipe.find(lemma) != d_lemmaToProofRecipe.end());
- return d_lemmaToProofRecipe[lemma];
-}
-
-bool CnfProof::haveProofRecipe(const std::set<Node> &lemma) {
- return d_lemmaToProofRecipe.find(lemma) != d_lemmaToProofRecipe.end();
-}
-
-void CnfProof::setCnfDependence(Node from, Node to) {
- Debug("proof:cnf") << "CnfProof::setCnfDependence "
- << "from " << from << std::endl
- << " to " << to << std::endl;
-
- Assert(from != to);
- d_cnfDeps.insert(std::make_pair(from, to));
-}
-
-void CnfProof::pushCurrentAssertion(Node assertion) {
+void CnfProof::pushCurrentAssertion(Node assertion, bool isInput)
+{
Debug("proof:cnf") << "CnfProof::pushCurrentAssertion " << assertion
<< std::endl;
- d_currentAssertionStack.push_back(assertion);
+ d_currentAssertionStack.push_back(std::pair<Node, bool>(assertion, isInput));
Debug("proof:cnf") << "CnfProof::pushCurrentAssertion "
<< "new stack size = " << d_currentAssertionStack.size()
@@ -205,7 +94,7 @@ void CnfProof::popCurrentAssertion() {
Assert(d_currentAssertionStack.size());
Debug("proof:cnf") << "CnfProof::popCurrentAssertion "
- << d_currentAssertionStack.back() << std::endl;
+ << d_currentAssertionStack.back().first << std::endl;
d_currentAssertionStack.pop_back();
@@ -216,740 +105,12 @@ void CnfProof::popCurrentAssertion() {
Node CnfProof::getCurrentAssertion() {
Assert(d_currentAssertionStack.size());
- return d_currentAssertionStack.back();
+ return d_currentAssertionStack.back().first;
}
-void CnfProof::setProofRecipe(LemmaProofRecipe* proofRecipe) {
- Assert(proofRecipe);
- Assert(proofRecipe->getNumSteps() > 0);
- d_lemmaToProofRecipe[proofRecipe->getBaseAssertions()] = *proofRecipe;
-}
-
-void CnfProof::pushCurrentDefinition(Node definition) {
- Debug("proof:cnf") << "CnfProof::pushCurrentDefinition "
- << definition << std::endl;
-
- d_currentDefinitionStack.push_back(definition);
-}
-
-void CnfProof::popCurrentDefinition() {
- Assert(d_currentDefinitionStack.size());
-
- Debug("proof:cnf") << "CnfProof::popCurrentDefinition "
- << d_currentDefinitionStack.back() << std::endl;
-
- d_currentDefinitionStack.pop_back();
-}
-
-Node CnfProof::getCurrentDefinition() {
- Assert(d_currentDefinitionStack.size());
- return d_currentDefinitionStack.back();
-}
-
-Node CnfProof::getAtom(prop::SatVariable var) {
- prop::SatLiteral lit (var);
- Node node = d_cnfStream->getNode(lit);
- return node;
-}
-
-void CnfProof::collectAtoms(const prop::SatClause* clause,
- std::set<Node>& atoms) {
- for (unsigned i = 0; i < clause->size(); ++i) {
- prop::SatLiteral lit = clause->operator[](i);
- prop::SatVariable var = lit.getSatVariable();
- TNode atom = getAtom(var);
- if (atoms.find(atom) == atoms.end()) {
- atoms.insert(atom);
- }
- }
-}
-
-prop::SatLiteral CnfProof::getLiteral(TNode atom) {
- return d_cnfStream->getLiteral(atom);
-}
-
-bool CnfProof::hasLiteral(TNode atom) {
- return d_cnfStream->hasLiteral(atom);
-}
-
-void CnfProof::ensureLiteral(TNode atom, bool noPreregistration) {
- d_cnfStream->ensureLiteral(atom, noPreregistration);
-}
-
-void CnfProof::collectAtomsForClauses(const IdToSatClause& clauses,
- std::set<Node>& atoms) {
- IdToSatClause::const_iterator it = clauses.begin();
- for (; it != clauses.end(); ++it) {
- const prop::SatClause* clause = it->second;
- collectAtoms(clause, atoms);
- }
-}
-
-void CnfProof::collectAtomsAndRewritesForLemmas(const IdToSatClause& lemmaClauses,
- std::set<Node>& atoms,
- NodePairSet& rewrites) {
- IdToSatClause::const_iterator it = lemmaClauses.begin();
- for (; it != lemmaClauses.end(); ++it) {
- const prop::SatClause* clause = it->second;
-
- // TODO: just calculate the map from ID to recipe once,
- // instead of redoing this over and over again
- std::vector<Expr> clause_expr;
- std::set<Node> clause_expr_nodes;
- for(unsigned i = 0; i < clause->size(); ++i) {
- prop::SatLiteral lit = (*clause)[i];
- Node node = getAtom(lit.getSatVariable());
- Expr atom = node.toExpr();
- if (atom.isConst()) {
- Assert(atom == utils::mkTrue());
- continue;
- }
- clause_expr_nodes.insert(lit.isNegated() ? node.notNode() : node);
- }
-
- LemmaProofRecipe recipe = getProofRecipe(clause_expr_nodes);
-
- for (unsigned i = 0; i < recipe.getNumSteps(); ++i) {
- const LemmaProofRecipe::ProofStep* proofStep = recipe.getStep(i);
- Node atom = proofStep->getLiteral();
-
- if (atom == Node()) {
- // The last proof step always has the empty node as its target...
- continue;
- }
-
- if (atom.getKind() == kind::NOT) {
- atom = atom[0];
- }
-
- atoms.insert(atom);
- }
-
- LemmaProofRecipe::RewriteIterator rewriteIt;
- for (rewriteIt = recipe.rewriteBegin(); rewriteIt != recipe.rewriteEnd(); ++rewriteIt) {
- rewrites.insert(NodePair(rewriteIt->first, rewriteIt->second));
-
- // The unrewritten terms also need to have literals, so insert them into atoms
- Node rewritten = rewriteIt->first;
- if (rewritten.getKind() == kind::NOT) {
- rewritten = rewritten[0];
- }
- atoms.insert(rewritten);
- }
- }
-}
-
-void CnfProof::collectAssertionsForClauses(const IdToSatClause& clauses,
- NodeSet& assertions) {
- IdToSatClause::const_iterator it = clauses.begin();
- for (; it != clauses.end(); ++it) {
- TNode used_assertion = getAssertionForClause(it->first);
- assertions.insert(used_assertion);
- // it can be the case that a definition for a clause is an assertion
- // but it is not the assertion for the clause
- // e.g. the assertions [(and a b), a]
- TNode used_definition = getDefinitionForClause(it->first);
- if (isAssertion(used_definition)) {
- assertions.insert(used_definition);
- }
- }
-}
-
-// Detects whether a clause has x v ~x for some x
-// If so, returns the positive occurence's idx first, then the negative's
-Maybe<std::pair<size_t, size_t>> CnfProof::detectTrivialTautology(
- const prop::SatClause& clause)
+bool CnfProof::getCurrentAssertionKind()
{
- // a map from a SatVariable to its previous occurence's polarity and location
- std::map<prop::SatVariable, std::pair<bool, size_t>> varsToPolsAndIndices;
- for (size_t i = 0; i < clause.size(); ++i)
- {
- prop::SatLiteral lit = clause[i];
- prop::SatVariable var = lit.getSatVariable();
- bool polarity = !lit.isNegated();
-
- // Check if this var has already occured w/ opposite polarity
- auto iter = varsToPolsAndIndices.find(var);
- if (iter != varsToPolsAndIndices.end() && iter->second.first != polarity)
- {
- if (iter->second.first)
- {
- return Maybe<std::pair<size_t, size_t>>{
- std::make_pair(iter->second.second, i)};
- }
- else
- {
- return Maybe<std::pair<size_t, size_t>>{
- std::make_pair(i, iter->second.second)};
- }
- }
- varsToPolsAndIndices[var] = std::make_pair(polarity, i);
- }
- return Maybe<std::pair<size_t, size_t>>{};
-}
-
-void LFSCCnfProof::printAtomMapping(const std::set<Node>& atoms,
- std::ostream& os,
- std::ostream& paren) {
- std::set<Node>::const_iterator it = atoms.begin();
- std::set<Node>::const_iterator end = atoms.end();
-
- for (;it != end; ++it) {
- os << "(decl_atom ";
- Node atom = *it;
- prop::SatVariable var = getLiteral(atom).getSatVariable();
- //FIXME hideous
- LFSCTheoryProofEngine* pe = (LFSCTheoryProofEngine*)ProofManager::currentPM()->getTheoryProofEngine();
- pe->printLetTerm(atom.toExpr(), os);
-
- os << " (\\ " << ProofManager::getVarName(var, d_name);
- os << " (\\ " << ProofManager::getAtomName(var, d_name) << "\n";
- paren << ")))";
- }
-}
-
-void LFSCCnfProof::printAtomMapping(const std::set<Node>& atoms,
- std::ostream& os,
- std::ostream& paren,
- ProofLetMap &letMap) {
- std::set<Node>::const_iterator it = atoms.begin();
- std::set<Node>::const_iterator end = atoms.end();
-
- for (;it != end; ++it) {
- os << "(decl_atom ";
- Node atom = *it;
- prop::SatVariable var = getLiteral(atom).getSatVariable();
- //FIXME hideous
- LFSCTheoryProofEngine* pe = (LFSCTheoryProofEngine*)ProofManager::currentPM()->getTheoryProofEngine();
- if (pe->printsAsBool(atom.toExpr())) os << "(p_app ";
- pe->printBoundTerm(atom.toExpr(), os, letMap);
- if (pe->printsAsBool(atom.toExpr())) os << ")";
-
- os << " (\\ " << ProofManager::getVarName(var, d_name);
- os << " (\\ " << ProofManager::getAtomName(var, d_name) << "\n";
- paren << ")))";
- }
-}
-
-// maps each expr to the position it had in the clause and the polarity it had
-Node LFSCCnfProof::clauseToNode(const prop::SatClause& clause,
- std::map<Node, unsigned>& childIndex,
- std::map<Node, bool>& childPol ) {
- std::vector< Node > children;
- for (unsigned i = 0; i < clause.size(); ++i) {
- prop::SatLiteral lit = clause[i];
- prop::SatVariable var = lit.getSatVariable();
- Node atom = getAtom(var);
- children.push_back( lit.isNegated() ? atom.negate() : atom );
- childIndex[atom] = i;
- childPol[atom] = !lit.isNegated();
- }
- return children.size()==1 ? children[0] :
- NodeManager::currentNM()->mkNode(kind::OR, children );
-}
-
-void LFSCCnfProof::printCnfProofForClause(ClauseId id,
- const prop::SatClause* clause,
- std::ostream& os,
- std::ostream& paren) {
- Debug("cnf-pf") << std::endl << std::endl << "LFSCCnfProof::printCnfProofForClause( " << id << " ) starting "
- << std::endl;
-
- os << "(satlem _ _ ";
- std::ostringstream clause_paren;
- printClause(*clause, os, clause_paren);
- os << "(clausify_false ";
-
- // FIXMEEEEEEEEEEEE
- // os <<"trust)";
- // os << clause_paren.str()
- // << " (\\ " << ProofManager::getInputClauseName(id, d_name) << "\n";
- // paren << "))";
-
- // return;
-
- Assert(clause->size() > 0);
-
- // If the clause contains x v ~x, it's easy!
- //
- // It's important to check for this case, because our other logic for
- // recording the location of variables in the clause assumes the clause is
- // not tautological
- Maybe<std::pair<size_t, size_t>> isTrivialTaut =
- detectTrivialTautology(*clause);
- if (isTrivialTaut.just())
- {
- size_t posIndexInClause = isTrivialTaut.value().first;
- size_t negIndexInClause = isTrivialTaut.value().second;
- Trace("cnf-pf") << "; Indices " << posIndexInClause << " (+) and "
- << negIndexInClause << " (-) make this clause a tautology"
- << std::endl;
-
- std::string proofOfPos =
- ProofManager::getLitName((*clause)[negIndexInClause], d_name);
- std::string proofOfNeg =
- ProofManager::getLitName((*clause)[posIndexInClause], d_name);
- os << "(contra _ " << proofOfPos << " " << proofOfNeg << ")";
- }
- else
- {
- Node base_assertion = getDefinitionForClause(id);
-
- // get the assertion for the clause id
- std::map<Node, unsigned> childIndex;
- std::map<Node, bool> childPol;
- Node assertion = clauseToNode(*clause, childIndex, childPol);
- // if there is no reason, construct assertion directly. This can happen
- // for unit clauses.
- if (base_assertion.isNull())
- {
- base_assertion = assertion;
- }
- // os_base is proof of base_assertion
- std::stringstream os_base;
-
- // checks if tautological definitional clause or top-level clause
- // and prints the proof of the top-level formula
- bool is_input = printProofTopLevel(base_assertion, os_base);
-
- if (is_input)
- {
- Debug("cnf-pf") << std::endl
- << "; base assertion is input. proof: " << os_base.str()
- << std::endl;
- }
-
- // get base assertion with polarity
- bool base_pol = base_assertion.getKind() != kind::NOT;
- base_assertion = base_assertion.getKind() == kind::NOT ? base_assertion[0]
- : base_assertion;
-
- std::map<Node, unsigned>::iterator itci = childIndex.find(base_assertion);
- bool is_in_clause = itci != childIndex.end();
- unsigned base_index = is_in_clause ? itci->second : 0;
- Trace("cnf-pf") << std::endl;
- Trace("cnf-pf") << "; input = " << is_input
- << ", is_in_clause = " << is_in_clause << ", id = " << id
- << ", assertion = " << assertion
- << ", base assertion = " << base_assertion << std::endl;
- if (!is_input)
- {
- Assert(is_in_clause);
- prop::SatLiteral blit = (*clause)[base_index];
- os_base << ProofManager::getLitName(blit, d_name);
- base_pol = !childPol[base_assertion]; // WHY? if the case is =>
- }
- Trace("cnf-pf") << "; polarity of base assertion = " << base_pol
- << std::endl;
- Trace("cnf-pf") << "; proof of base : " << os_base.str() << std::endl;
-
- bool success = false;
- if (is_input && is_in_clause && childPol[base_assertion] == base_pol)
- {
- // if both in input and in clause, the proof is trivial. this is the case
- // for unit clauses.
- Trace("cnf-pf") << "; trivial" << std::endl;
- os << "(contra _ ";
- success = true;
- prop::SatLiteral lit = (*clause)[itci->second];
- if (base_pol)
- {
- os << os_base.str() << " " << ProofManager::getLitName(lit, d_name);
- }
- else
- {
- os << ProofManager::getLitName(lit, d_name) << " " << os_base.str();
- }
- os << ")";
- } else if ((base_assertion.getKind()==kind::AND && !base_pol) ||
- ((base_assertion.getKind()==kind::OR ||
- base_assertion.getKind()==kind::IMPLIES) && base_pol)) {
- Trace("cnf-pf") << "; and/or case 1" << std::endl;
- success = true;
- std::stringstream os_main;
- std::stringstream os_paren;
- //eliminate each one
- for (int j = base_assertion.getNumChildren()-2; j >= 0; j--) {
- Trace("cnf-pf-debug") << "; base_assertion[" << j << "] is: " << base_assertion[j]
- << ", and its kind is: " << base_assertion[j].getKind() << std::endl ;
-
- Node child_base = base_assertion[j].getKind()==kind::NOT ?
- base_assertion[j][0] : base_assertion[j];
- bool child_pol = base_assertion[j].getKind()!=kind::NOT;
-
- Trace("cnf-pf-debug") << "; child " << j << " "
- << ", child base: " << child_base
- << ", child pol: " << child_pol
- << ", childPol[child_base] "
- << childPol[child_base] << ", base pol: " << base_pol << std::endl;
-
- std::map< Node, unsigned >::iterator itcic = childIndex.find( child_base );
-
- if( itcic!=childIndex.end() ){
- //Assert( child_pol==childPol[child_base] );
- os_main << "(or_elim_1 _ _ ";
- prop::SatLiteral lit = (*clause)[itcic->second];
- // Should be if in the original formula it was negated
- // if( childPol[child_base] && base_pol ){
-
- // Adding the below to catch a specific case where the first child of an IMPLIES is negative,
- // in which case we need not_not introduction.
- if (base_assertion.getKind() == kind::IMPLIES && !child_pol && base_pol) {
- os_main << "(not_not_intro _ " << ProofManager::getLitName(lit, d_name) << ") ";
- } else if (childPol[child_base] && base_pol) {
- os_main << ProofManager::getLitName(lit, d_name) << " ";
- }else{
- os_main << "(not_not_intro _ " << ProofManager::getLitName(lit, d_name) << ") ";
- }
- if( base_assertion.getKind()==kind::AND ){
- os_main << "(not_and_elim _ _ ";
- os_paren << ")";
- }
- os_paren << ")";
- }else{
- success = false;
- }
- }
-
- if( success ){
- if( base_assertion.getKind()==kind::IMPLIES ){
- os_main << "(impl_elim _ _ ";
- }
- os_main << os_base.str();
- if( base_assertion.getKind()==kind::IMPLIES ){
- os_main << ")";
- }
- os_main << os_paren.str();
- int last_index = base_assertion.getNumChildren()-1;
- Node child_base = base_assertion[last_index].getKind()==kind::NOT ? base_assertion[last_index][0] : base_assertion[last_index];
- //bool child_pol = base_assertion[last_index].getKind()!=kind::NOT;
- std::map< Node, unsigned >::iterator itcic = childIndex.find( child_base );
- if( itcic!=childIndex.end() ){
- os << "(contra _ ";
- prop::SatLiteral lit = (*clause)[itcic->second];
- if( childPol[child_base] && base_pol){
- os << os_main.str() << " " << ProofManager::getLitName(lit, d_name);
- }else{
- os << ProofManager::getLitName(lit, d_name) << " " << os_main.str();
- }
- os << ")";
- }else{
- success = false;
- }
- }
- }else if ((base_assertion.getKind()==kind::AND && base_pol) ||
- ((base_assertion.getKind()==kind::OR ||
- base_assertion.getKind()==kind::IMPLIES) && !base_pol)) {
-
- std::stringstream os_main;
-
- Node iatom;
- if (is_in_clause) {
- Assert(assertion.getNumChildren() == 2);
- iatom = assertion[ base_index==0 ? 1 : 0];
- } else {
- Assert(assertion.getNumChildren() == 1);
- iatom = assertion[0];
- }
-
- Trace("cnf-pf") << "; and/or case 2, iatom = " << iatom << std::endl;
- Node e_base = iatom.getKind()==kind::NOT ? iatom[0] : iatom;
- bool e_pol = iatom.getKind()!=kind::NOT;
- std::map< Node, unsigned >::iterator itcic = childIndex.find( e_base );
- if( itcic!=childIndex.end() ){
- prop::SatLiteral lit = (*clause)[itcic->second];
- //eliminate until we find iatom
- for( unsigned j=0; j<base_assertion.getNumChildren(); j++ ){
- Node child_base = base_assertion[j].getKind()==kind::NOT ? base_assertion[j][0] : base_assertion[j];
- bool child_pol = base_assertion[j].getKind()!=kind::NOT;
- if( j==0 && base_assertion.getKind()==kind::IMPLIES ){
- child_pol = !child_pol;
- }
- if( e_base==child_base && (e_pol==child_pol)==(base_assertion.getKind()==kind::AND) ){
- success = true;
- bool elimNn =( ( base_assertion.getKind()==kind::OR || ( base_assertion.getKind()==kind::IMPLIES && j==1 ) ) && e_pol );
- if( elimNn ){
- os_main << "(not_not_elim _ ";
- }
- std::stringstream os_paren;
- if( j+1<base_assertion.getNumChildren() ){
- os_main << "(and_elim_1 _ _ ";
- if( base_assertion.getKind()==kind::OR || base_assertion.getKind()==kind::IMPLIES ){
- os_main << "(not_" << ( base_assertion.getKind()==kind::OR ? "or" : "impl" ) << "_elim _ _ ";
- os_paren << ")";
- }
- os_paren << ")";
- }
- for( unsigned k=0; k<j; k++ ){
- os_main << "(and_elim_2 _ _ ";
- if( base_assertion.getKind()==kind::OR || base_assertion.getKind()==kind::IMPLIES ){
- os_main << "(not_" << ( base_assertion.getKind()==kind::OR ? "or" : "impl" ) << "_elim _ _ ";
- os_paren << ")";
- }
- os_paren << ")";
- }
- os_main << os_base.str() << os_paren.str();
- if( elimNn ){
- os_main << ")";
- }
- break;
- }
- }
- if( success ){
- os << "(contra _ ";
- if( !e_pol ){
- os << ProofManager::getLitName(lit, d_name) << " " << os_main.str();
- }else{
- os << os_main.str() << " " << ProofManager::getLitName(lit, d_name);
- }
- os << ")";
- }
- }
- }else if( base_assertion.getKind()==kind::XOR || ( base_assertion.getKind()==kind::EQUAL && base_assertion[0].getType().isBoolean() ) ){
- //eliminate negation
- int num_nots_2 = 0;
- int num_nots_1 = 0;
- Kind k;
- if( !base_pol ){
- if( base_assertion.getKind()==kind::EQUAL ){
- num_nots_2 = 1;
- }
- k = kind::EQUAL;
- }else{
- k = base_assertion.getKind();
- }
- std::vector< unsigned > indices;
- std::vector< bool > pols;
- success = true;
- int elimNum = 0;
- for( unsigned i=0; i<2; i++ ){
- Node child_base = base_assertion[i].getKind()==kind::NOT ? base_assertion[i][0] : base_assertion[i];
- bool child_pol = base_assertion[i].getKind()!=kind::NOT;
- std::map< Node, unsigned >::iterator itcic = childIndex.find( child_base );
- if( itcic!=childIndex.end() ){
- indices.push_back( itcic->second );
- pols.push_back( childPol[child_base] );
- if( i==0 ){
- //figure out which way to elim
- elimNum = child_pol==childPol[child_base] ? 2 : 1;
- if( (elimNum==2)==(k==kind::EQUAL) ){
- num_nots_2++;
- }
- if( elimNum==1 ){
- num_nots_1++;
- }
- }
- }else{
- success = false;
- break;
- }
- }
- Trace("cnf-pf") << std::endl << "; num nots = " << num_nots_2 << std::endl;
- if( success ){
- os << "(contra _ ";
- std::stringstream os_base_n;
- if( num_nots_2==2 ){
- os_base_n << "(not_not_elim _ ";
- }
- os_base_n << "(or_elim_1 _ _ ";
- prop::SatLiteral lit1 = (*clause)[indices[0]];
- if( !pols[0] || num_nots_1==1 ){
- os_base_n << "(not_not_intro _ " << ProofManager::getLitName(lit1, d_name) << ") ";
- }else{
- Trace("cnf-pf-debug") << "CALLING getlitname" << std::endl;
- os_base_n << ProofManager::getLitName(lit1, d_name) << " ";
- }
- Assert(elimNum != 0);
- os_base_n << "(" << ( k==kind::EQUAL ? "iff" : "xor" ) << "_elim_" << elimNum << " _ _ ";
- if( !base_pol ){
- os_base_n << "(not_" << ( base_assertion.getKind()==kind::EQUAL ? "iff" : "xor" ) << "_elim _ _ " << os_base.str() << ")";
- }else{
- os_base_n << os_base.str();
- }
- os_base_n << "))";
- if( num_nots_2==2 ){
- os_base_n << ")";
- num_nots_2 = 0;
- }
- prop::SatLiteral lit2 = (*clause)[indices[1]];
- if( pols[1]==(num_nots_2==0) ){
- os << os_base_n.str() << " ";
- if( num_nots_2==1 ){
- os << "(not_not_intro _ " << ProofManager::getLitName(lit2, d_name) << ")";
- }else{
- os << ProofManager::getLitName(lit2, d_name);
- }
- }else{
- os << ProofManager::getLitName(lit2, d_name) << " " << os_base_n.str();
- }
- os << ")";
- }
- }else if( base_assertion.getKind()==kind::ITE ){
- std::map< unsigned, unsigned > appears;
- std::map< unsigned, Node > appears_expr;
- unsigned appears_count = 0;
- for( unsigned r=0; r<3; r++ ){
- Node child_base = base_assertion[r].getKind()==kind::NOT ? base_assertion[r][0] : base_assertion[r];
- std::map< Node, unsigned >::iterator itcic = childIndex.find( child_base );
- if( itcic!=childIndex.end() ){
- appears[r] = itcic->second;
- appears_expr[r] = child_base;
- appears_count++;
- }
- }
- if( appears_count==2 ){
- success = true;
- int elimNum = 1;
- unsigned index1 = 0;
- unsigned index2 = 1;
- if( appears.find( 0 )==appears.end() ){
- elimNum = 3;
- index1 = 1;
- index2 = 2;
- }else if( appears.find( 1 )==appears.end() ){
- elimNum = 2;
- index1 = 0;
- index2 = 2;
- }
- std::stringstream os_main;
- os_main << "(or_elim_1 _ _ ";
- prop::SatLiteral lit1 = (*clause)[appears[index1]];
- if( !childPol[appears_expr[index1]] || elimNum==1 || ( elimNum==3 && !base_pol ) ){
- os_main << "(not_not_intro _ " << ProofManager::getLitName(lit1, d_name) << ") ";
- }else{
- os_main << ProofManager::getLitName(lit1, d_name) << " ";
- }
- os_main << "(" << ( base_pol ? "" : "not_" ) << "ite_elim_" << elimNum << " _ _ _ ";
- os_main << os_base.str() << "))";
- os << "(contra _ ";
- prop::SatLiteral lit2 = (*clause)[appears[index2]];
- if( !childPol[appears_expr[index2]] || !base_pol ){
- os << ProofManager::getLitName(lit2, d_name) << " " << os_main.str();
- }else{
- os << os_main.str() << " " << ProofManager::getLitName(lit2, d_name);
- }
- os << ")";
- }
- }else if( base_assertion.isConst() ){
- bool pol = base_assertion==NodeManager::currentNM()->mkConst( true );
- if( pol!=base_pol ){
- success = true;
- if( pol ){
- os << "(contra _ truth " << os_base.str() << ")";
- }else{
- os << os_base.str();
- }
- }
- }
-
- if( !success ){
- Trace("cnf-pf") << std::endl;
- Trace("cnf-pf") << ";!!!!!!!!! CnfProof : Can't process " << assertion << ", base = " << base_assertion << ", id = " << id << std::endl;
- Trace("cnf-pf") << ";!!!!!!!!! Clause is : ";
- for (unsigned i = 0; i < clause->size(); ++i) {
- Trace("cnf-pf") << (*clause)[i] << " ";
- }
- Trace("cnf-pf") << std::endl;
- os << "trust-bad";
- }
- }
-
- os << ")" << clause_paren.str()
- << " (\\ " << ProofManager::getInputClauseName(id, d_name) << "\n";
-
- paren << "))";
-}
-
-void LFSCCnfProof::printClause(const prop::SatClause& clause,
- std::ostream& os,
- std::ostream& paren) {
- for (unsigned i = 0; i < clause.size(); ++i) {
- prop::SatLiteral lit = clause[i];
- prop::SatVariable var = lit.getSatVariable();
- if (lit.isNegated()) {
- os << "(ast _ _ _ " << ProofManager::getAtomName(var, d_name) <<" (\\ " << ProofManager::getLitName(lit, d_name) << " ";
- paren << "))";
- } else {
- os << "(asf _ _ _ " << ProofManager::getAtomName(var, d_name) <<" (\\ " << ProofManager::getLitName(lit, d_name) << " ";
- paren << "))";
- }
- }
-}
-
-// print a proof of the top-level formula e, based on the input assertions
-bool LFSCCnfProof::printProofTopLevel(Node e, std::ostream& out) {
- if (!isAssertion(e)) {
- // check if deduced by CNF
- // dependence on top level fact i.e. a depends on (a and b)
- NodeToNode::const_iterator itd = d_cnfDeps.find(e);
- if (itd != d_cnfDeps.end()) {
- TNode parent = itd->second;
- //check if parent is an input assertion
- std::stringstream out_parent;
- if (printProofTopLevel(parent, out_parent)) {
- if(parent.getKind()==kind::AND ||
- (parent.getKind()==kind::NOT && (parent[0].getKind()==kind::IMPLIES ||
- parent[0].getKind()==kind::OR))) {
- Node parent_base = parent.getKind()==kind::NOT ? parent[0] : parent;
- Node e_base = e.getKind()==kind::NOT ? e[0] : e;
- bool e_pol = e.getKind()!=kind::NOT;
- for( unsigned i=0; i<parent_base.getNumChildren(); i++ ){
- Node child_base = parent_base[i].getKind()==kind::NOT ? parent_base[i][0] : parent_base[i];
- bool child_pol = parent_base[i].getKind()!=kind::NOT;
- if( parent_base.getKind()==kind::IMPLIES && i==0 ){
- child_pol = !child_pol;
- }
- if (e_base==child_base &&
- (e_pol==child_pol)==(parent_base.getKind()==kind::AND)) {
- bool elimNn = ((parent_base.getKind()==kind::OR ||
- (parent_base.getKind()==kind::IMPLIES && i==1)) && e_pol);
- if (elimNn) {
- out << "(not_not_elim _ ";
- }
- std::stringstream out_paren;
- if (i+1 < parent_base.getNumChildren()) {
- out << "(and_elim_1 _ _ ";
- if( parent_base.getKind()==kind::OR ||
- parent_base.getKind()==kind::IMPLIES ){
- out << "(not_" << ( parent_base.getKind()==kind::OR ? "or" : "impl" )
- << "_elim _ _ ";
- out_paren << ")";
- }
- out_paren << ")";
- }
- for( unsigned j=0; j<i; j++ ){
- out << "(and_elim_2 _ _ ";
- if( parent_base.getKind()==kind::OR || parent_base.getKind()==kind::IMPLIES ){
- out << "(not_" << ( parent_base.getKind()==kind::OR ? "or" : "impl" ) << "_elim _ _ ";
- out_paren << ")";
- }
- out_paren << ")";
- }
- out << out_parent.str();
- out << out_paren.str();
- if( elimNn ){
- out << ")";
- }
- return true;
- }
- }
- } else {
- Trace("cnf-pf-debug") << "; isInputAssertion : parent of " << e
- << " is not correct type (" << parent << ")" << std::endl;
- }
- } else {
- Trace("cnf-pf-debug") << "; isInputAssertion : parent of " << e
- << " is not input" << std::endl;
- }
- } else {
- Trace("cnf-pf-debug") << "; isInputAssertion : " << e
- << " has no parent" << std::endl;
- }
- return false;
- } else {
- out << ProofManager::getPreprocessedAssertionName(e);
- return true;
- }
+ return d_currentAssertionStack.back().second;
}
} /* CVC4 namespace */
diff --git a/src/proof/cnf_proof.h b/src/proof/cnf_proof.h
index 56993583e..286c4e0bf 100644
--- a/src/proof/cnf_proof.h
+++ b/src/proof/cnf_proof.h
@@ -2,10 +2,10 @@
/*! \file cnf_proof.h
** \verbatim
** Top contributors (to current version):
- ** Liana Hadarean, Guy Katz, Alex Ozdemir
+ ** Liana Hadarean, Haniel Barbosa, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -27,10 +27,8 @@
#include "context/cdhashmap.h"
#include "proof/clause_id.h"
-#include "proof/lemma_proof.h"
#include "proof/sat_proof.h"
#include "util/maybe.h"
-#include "util/proof.h"
namespace CVC4 {
namespace prop {
@@ -44,11 +42,11 @@ typedef std::unordered_map<Node, Node, NodeHashFunction> NodeToNode;
typedef std::unordered_set<ClauseId> ClauseIdSet;
typedef context::CDHashMap<ClauseId, Node> ClauseIdToNode;
-typedef context::CDHashMap<Node, ProofRule, NodeHashFunction> NodeToProofRule;
-typedef std::map<std::set<Node>, LemmaProofRecipe> LemmaToRecipe;
typedef std::pair<Node, Node> NodePair;
typedef std::set<NodePair> NodePairSet;
+typedef std::unordered_set<Node, NodeHashFunction> NodeSet;
+
class CnfProof {
protected:
CVC4::prop::CnfStream* d_cnfStream;
@@ -56,23 +54,9 @@ protected:
/** Map from ClauseId to the assertion that lead to adding this clause **/
ClauseIdToNode d_clauseToAssertion;
- /** Map from assertion to reason for adding assertion **/
- NodeToProofRule d_assertionToProofRule;
-
- /** Map from lemma to the recipe for proving it **/
- LemmaToRecipe d_lemmaToProofRecipe;
-
- /** Top of stack is assertion currently being converted to CNF **/
- std::vector<Node> d_currentAssertionStack;
-
- /** Top of stack is top-level fact currently being converted to CNF **/
- std::vector<Node> d_currentDefinitionStack;
-
- /** Map from ClauseId to the top-level fact that lead to adding this clause **/
- ClauseIdToNode d_clauseToDefinition;
-
- /** Top-level facts that follow from assertions during convertAndAssert **/
- NodeSet d_definitions;
+ /** Top of stack is assertion currently being converted to CNF. Also saves
+ * whether it is input (rather than a lemma). **/
+ std::vector<std::pair<Node, bool>> d_currentAssertionStack;
/** Map from top-level fact to facts/assertion that it follows from **/
NodeToNode d_cnfDeps;
@@ -84,132 +68,36 @@ protected:
// The clause ID of the unit clause defining the false SAT literal.
ClauseId d_falseUnitClause;
- bool isDefinition(Node node);
-
- Node getDefinitionForClause(ClauseId clause);
-
std::string d_name;
public:
CnfProof(CVC4::prop::CnfStream* cnfStream,
context::Context* ctx,
const std::string& name);
-
-
- Node getAtom(prop::SatVariable var);
- prop::SatLiteral getLiteral(TNode node);
- bool hasLiteral(TNode node);
- void ensureLiteral(TNode node, bool noPreregistration = false);
-
- void collectAtoms(const prop::SatClause* clause,
- std::set<Node>& atoms);
- void collectAtomsForClauses(const IdToSatClause& clauses,
- std::set<Node>& atoms);
- void collectAtomsAndRewritesForLemmas(const IdToSatClause& lemmaClauses,
- std::set<Node>& atoms,
- NodePairSet& rewrites);
- void collectAssertionsForClauses(const IdToSatClause& clauses,
- NodeSet& assertions);
+ ~CnfProof();
/** Methods for logging what the CnfStream does **/
// map the clause back to the current assertion where it came from
- // if it is an explanation, it does not have a CNF proof since it is
- // already in CNF
- void registerConvertedClause(ClauseId clause, bool explanation=false);
-
- // The CNF proof has a special relationship to true and false.
- // In particular, it need to know the identity of clauses defining
- // canonical true and false literals in the underlying SAT solver.
- void registerTrueUnitClause(ClauseId clauseId);
- void registerFalseUnitClause(ClauseId clauseId);
- inline ClauseId getTrueUnitClause() { return d_trueUnitClause; };
- inline ClauseId getFalseUnitClause() { return d_falseUnitClause; };
-
- /** Clause is one of the clauses defining the node expression*/
- void setClauseDefinition(ClauseId clause, Node node);
+ void registerConvertedClause(ClauseId clause);
/** Clause is one of the clauses defining top-level assertion node*/
void setClauseAssertion(ClauseId clause, Node node);
- void registerAssertion(Node assertion, ProofRule reason);
- void setCnfDependence(Node from, Node to);
-
- void pushCurrentAssertion(Node assertion); // the current assertion being converted
+ /** Current assertion being converted and whether it is an input (rather than
+ * a lemma) */
+ void pushCurrentAssertion(Node assertion, bool isInput = false);
void popCurrentAssertion();
Node getCurrentAssertion();
-
- void pushCurrentDefinition(Node assertion); // the current Tseitin definition being converted
- void popCurrentDefinition();
- Node getCurrentDefinition();
+ bool getCurrentAssertionKind();
/**
* Checks whether the assertion stack is empty.
*/
bool isAssertionStackEmpty() const { return d_currentAssertionStack.empty(); }
- void setProofRecipe(LemmaProofRecipe* proofRecipe);
- LemmaProofRecipe getProofRecipe(const std::set<Node> &lemma);
- bool haveProofRecipe(const std::set<Node> &lemma);
-
// accessors for the leaf assertions that are being converted to CNF
- bool isAssertion(Node node);
- ProofRule getProofRule(Node assertion);
- ProofRule getProofRule(ClauseId clause);
Node getAssertionForClause(ClauseId clause);
-
- /** Virtual methods for printing things **/
- virtual void printAtomMapping(const std::set<Node>& atoms,
- std::ostream& os,
- std::ostream& paren) = 0;
- virtual void printAtomMapping(const std::set<Node>& atoms,
- std::ostream& os,
- std::ostream& paren,
- ProofLetMap &letMap) = 0;
-
- // Detects whether a clause has x v ~x for some x
- // If so, returns the positive occurence's idx first, then the negative's
- static Maybe<std::pair<size_t, size_t>> detectTrivialTautology(
- const prop::SatClause& clause);
- virtual void printClause(const prop::SatClause& clause,
- std::ostream& os,
- std::ostream& paren) = 0;
- virtual void printCnfProofForClause(ClauseId id,
- const prop::SatClause* clause,
- std::ostream& os,
- std::ostream& paren) = 0;
- virtual ~CnfProof();
};/* class CnfProof */
-class LFSCCnfProof : public CnfProof {
- Node clauseToNode( const prop::SatClause& clause,
- std::map<Node, unsigned>& childIndex,
- std::map<Node, bool>& childPol );
- bool printProofTopLevel(Node e, std::ostream& out);
-public:
- LFSCCnfProof(CVC4::prop::CnfStream* cnfStream,
- context::Context* ctx,
- const std::string& name)
- : CnfProof(cnfStream, ctx, name)
- {}
- ~LFSCCnfProof() {}
-
- void printAtomMapping(const std::set<Node>& atoms,
- std::ostream& os,
- std::ostream& paren) override;
-
- void printAtomMapping(const std::set<Node>& atoms,
- std::ostream& os,
- std::ostream& paren,
- ProofLetMap& letMap) override;
-
- void printClause(const prop::SatClause& clause,
- std::ostream& os,
- std::ostream& paren) override;
- void printCnfProofForClause(ClauseId id,
- const prop::SatClause* clause,
- std::ostream& os,
- std::ostream& paren) override;
-};/* class LFSCCnfProof */
-
} /* CVC4 namespace */
#endif /* CVC4__CNF_PROOF_H */
diff --git a/src/proof/dimacs.cpp b/src/proof/dimacs.cpp
deleted file mode 100644
index d9d9f8c1c..000000000
--- a/src/proof/dimacs.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-/********************* */
-/*! \file dimacs.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Alex Ozdemir
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief DIMACS SAT Problem Format
- **
- ** Defines serialization for SAT problems as DIMACS
- **/
-
-#include "proof/dimacs.h"
-
-#include "base/check.h"
-
-#include <iostream>
-
-namespace CVC4 {
-namespace proof {
-
-// Prints the literal as a (+) or (-) int
-// Not operator<< b/c that represents negation as ~
-std::ostream& textOut(std::ostream& o, const prop::SatLiteral& l)
-{
- if (l.isNegated())
- {
- o << "-";
- }
- return o << l.getSatVariable() + 1;
-}
-
-// Prints the clause as a space-separated list of ints
-// Not operator<< b/c that represents negation as ~
-std::ostream& textOut(std::ostream& o, const prop::SatClause& c)
-{
- for (const auto& l : c)
- {
- textOut(o, l) << " ";
- }
- return o << "0";
-}
-
-void printDimacs(std::ostream& o,
- const std::unordered_map<ClauseId, prop::SatClause>& clauses,
- const std::vector<ClauseId>& usedIndices)
-{
- size_t maxVar = 0;
- for (const ClauseId i : usedIndices)
- {
- const prop::SatClause& c = clauses.at(i);
- for (const auto& l : c)
- {
- if (l.getSatVariable() + 1 > maxVar)
- {
- maxVar = l.getSatVariable() + 1;
- }
- }
- }
- o << "p cnf " << maxVar << " " << usedIndices.size() << '\n';
- for (const ClauseId i : usedIndices)
- {
- const prop::SatClause& c = clauses.at(i);
- for (const auto& l : c)
- {
- if (l.isNegated())
- {
- o << '-';
- }
- o << l.getSatVariable() + 1 << " ";
- }
- o << "0\n";
- }
-}
-
-std::vector<prop::SatClause> parseDimacs(std::istream& in)
-{
- std::string tag;
- uint64_t nVars;
- uint64_t nClauses;
-
- in >> tag;
- Assert(in.good());
- Assert(tag == "p");
-
- in >> tag;
- Assert(in.good());
- Assert(tag == "cnf");
-
- in >> nVars;
- Assert(nVars >= 0);
-
- in >> nClauses;
- Assert(nClauses >= 0);
-
- std::vector<prop::SatClause> cnf;
- for (uint64_t i = 0; i < nClauses; ++i)
- {
- cnf.emplace_back();
- int64_t lit;
- in >> lit;
- Assert(in.good());
- while (lit != 0)
- {
- cnf.back().emplace_back(std::abs(lit) - 1, lit < 0);
- in >> lit;
- Assert(static_cast<uint64_t>(std::abs(lit)) <= nVars);
- Assert(in.good());
- }
- }
-
- return cnf;
-}
-
-} // namespace proof
-} // namespace CVC4
diff --git a/src/proof/dimacs.h b/src/proof/dimacs.h
deleted file mode 100644
index 405b33208..000000000
--- a/src/proof/dimacs.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/********************* */
-/*! \file dimacs.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Alex Ozdemir
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief DIMACS SAT Problem Format
- **
- ** Defines serialization/deserialization for SAT problems as DIMACS
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__PROOF__DIMACS_H
-#define CVC4__PROOF__DIMACS_H
-
-#include <iosfwd>
-#include <memory>
-#include <unordered_map>
-
-#include "proof/clause_id.h"
-#include "prop/sat_solver_types.h"
-
-namespace CVC4 {
-namespace proof {
-
-/**
- * Prints the literal as a (+) or (-) int
- * Not operator<< b/c that represents negation as ~
- *
- * @param o where to print
- * @param l the literal to print
- *
- * @return the original stream
- */
-std::ostream& textOut(std::ostream& o, const prop::SatLiteral& l);
-
-/**
- * Prints the clause as a space-separated list of ints
- * Not operator<< b/c that represents literal negation as ~
- *
- * @param o where to print
- * @param c the clause to print
- *
- * @return the original stream
- */
-std::ostream& textOut(std::ostream& o, const prop::SatClause& c);
-
-/**
- * Prints a CNF formula in DIMACS format
- *
- * @param o where to print to
- * @param usedClauses the CNF formula
- */
-void printDimacs(std::ostream& o,
- const std::unordered_map<ClauseId, prop::SatClause>& clauses,
- const std::vector<ClauseId>& usedIndices);
-
-std::vector<prop::SatClause> parseDimacs(std::istream& i);
-
-} // namespace proof
-} // namespace CVC4
-
-#endif // CVC4__PROOF__DIMACS_H
diff --git a/src/proof/drat/drat_proof.cpp b/src/proof/drat/drat_proof.cpp
deleted file mode 100644
index ee9c42d77..000000000
--- a/src/proof/drat/drat_proof.cpp
+++ /dev/null
@@ -1,291 +0,0 @@
-/********************* */
-/*! \file drat_proof.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Alex Ozdemir, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief DRAT Proof Format
- **
- ** Defines deserialization for DRAT proofs.
- **/
-
-#include "proof/drat/drat_proof.h"
-
-#include <algorithm>
-#include <bitset>
-#include <iostream>
-
-#include "proof/proof_manager.h"
-
-namespace CVC4 {
-namespace proof {
-namespace drat {
-
-// helper functions for parsing the binary DRAT format.
-
-/**
- * Parses a binary literal which starts at `start` and must not go beyond `end`
- *
- * Leaves the iterator one past the last byte that is a part of the clause.
- *
- * If the literal overruns `end`, then raises a `InvalidDratProofException`.
- */
-SatLiteral parse_binary_literal(std::string::const_iterator& start,
- const std::string::const_iterator& proof_end)
-{
- // lit is encoded as uint represented by a variable-length byte sequence
- uint64_t literal_represented_as_uint = 0;
- for (uint8_t shift = 0; start != proof_end; ++start, shift += 7)
- {
- // Check whether shift is so large that we're going to lose some
- // information
- if (shift + 7 >= 64)
- {
- throw InvalidDratProofException(
- "While parsing a DRAT proof, encountered a literal that was too "
- "long");
- }
- unsigned char byte = *start;
- // The MSB of the byte is an indicator of whether the sequence continues
- bool continued = (byte >> 7) & 1;
- uint64_t numeric_part = byte & 0x7f;
- literal_represented_as_uint |= numeric_part << shift;
- if (!continued)
- {
- // LSB of `literal_represented_as_uint` indicates negation.
- bool negated = literal_represented_as_uint & 1;
- // Rest is the literal number
- SatVariable var_number = literal_represented_as_uint >> 1;
- ++start;
- // Internal clauses start at 0, external ones start at 1.
- return SatLiteral(var_number - 1, negated);
- }
- }
- throw InvalidDratProofException(
- "Literal in DRAT proof was not done when "
- "EOF was encountered");
-}
-
-/**
- * Parses a binary clause which starts at `start` and must not go beyond `end`
- *
- * Leaves the iterator one past the last byte that is a part of the clause.
- * That is, one past the null byte.
- *
- * If the clause overruns `end`, then raises a `InvalidDratProofException`.
- */
-SatClause parse_binary_clause(std::string::const_iterator& start,
- const std::string::const_iterator& proof_end)
-{
- SatClause clause;
- // A clause is a 0-terminated sequence of literals
- while (start != proof_end)
- {
- // Is the clause done?
- if (*start == 0)
- {
- ++start;
- return clause;
- }
- else
- {
- // If not, parse another literal
- clause.emplace_back(parse_binary_literal(start, proof_end));
- }
- }
- // We've overrun the end of the byte stream.
- throw InvalidDratProofException(
- "Clause in DRAT proof was not done when "
- "EOF was encountered");
-}
-
-/**
- * Writes this SAT literal in the textual DIMACS format. i.e. as a non-zero
- * integer.
- *
- * Since internally +0 and -0 are valid literals, we add one to each
- * literal's number (SAT variable) when outputtting it.
- *
- * @param os the stream to write to
- * @param l the literal to write
- */
-void outputLiteralAsDimacs(std::ostream& os, SatLiteral l)
-{
- if (l.isNegated())
- {
- os << '-';
- }
- // add 1 to convert between internal literals and their DIMACS
- // representaations.
- os << l.getSatVariable() + 1;
-}
-
-// DratInstruction implementation
-
-DratInstruction::DratInstruction(DratInstructionKind kind, SatClause clause)
- : d_kind(kind), d_clause(clause)
-{
- // All intialized
-}
-
-void DratInstruction::outputAsText(std::ostream& os) const
-{
- switch (d_kind)
- {
- case DratInstructionKind::ADDITION:
- {
- for (const SatLiteral& l : d_clause)
- {
- outputLiteralAsDimacs(os, l);
- os << ' ';
- }
- os << '0' << std::endl;
- break;
- }
- case DratInstructionKind::DELETION:
- {
- os << "d ";
- for (const SatLiteral& l : d_clause)
- {
- outputLiteralAsDimacs(os, l);
- os << ' ';
- }
- os << '0' << std::endl;
- break;
- }
- default:
- {
- Unreachable() << "Unknown DRAT instruction kind";
- }
- }
-}
-
-// DratProof implementation
-
-DratProof::DratProof() : d_instructions() {}
-
-// See the "binary format" section of
-// https://www.cs.utexas.edu/~marijn/drat-trim/
-DratProof DratProof::fromBinary(const std::string& s)
-{
- DratProof proof;
- if (Debug.isOn("pf::drat"))
- {
- Debug("pf::drat") << "Parsing binary DRAT proof" << std::endl;
- Debug("pf::drat") << "proof length: " << s.length() << " bytes"
- << std::endl;
- Debug("pf::drat") << "proof as bytes: ";
- for (char i : s)
- {
- if (i == 'a' || i == 'd')
- {
- Debug("pf::drat") << std::endl << " " << std::bitset<8>(i);
- }
- else
- {
- Debug("pf::drat") << " " << std::bitset<8>(i);
- }
- }
- Debug("pf::drat") << std::endl << "parsing proof..." << std::endl;
- }
-
- // For each instruction
- for (auto i = s.cbegin(), end = s.cend(); i != end;)
- {
- switch (*i)
- {
- case 'a':
- {
- ++i;
- proof.d_instructions.emplace_back(ADDITION,
- parse_binary_clause(i, end));
- break;
- }
- case 'd':
- {
- ++i;
- proof.d_instructions.emplace_back(DELETION,
- parse_binary_clause(i, end));
- break;
- }
- default:
- {
- std::ostringstream errmsg;
- errmsg << "Invalid instruction in Drat proof. Instruction bits: "
- << std::bitset<8>(*i)
- << ". Expected 'a' (01100001) or 'd' "
- "(01100100).";
- throw InvalidDratProofException(errmsg.str());
- }
- }
- }
-
- if (Debug.isOn("pf::drat"))
- {
- Debug("pf::drat") << "Printing out DRAT in textual format:" << std::endl;
- proof.outputAsText(Debug("pf::drat"));
- }
-
- return proof;
-};
-
-const std::vector<DratInstruction>& DratProof::getInstructions() const
-{
- return d_instructions;
-};
-
-void DratProof::outputAsText(std::ostream& os) const
-{
- for (const DratInstruction& instruction : d_instructions)
- {
- instruction.outputAsText(os);
- os << "\n";
- }
-};
-
-void DratProof::outputAsLfsc(std::ostream& os, uint8_t indentation) const
-{
- for (const DratInstruction& i : d_instructions)
- {
- if (indentation > 0)
- {
- std::fill_n(std::ostream_iterator<char>(os), indentation, ' ');
- }
- os << "(";
- switch (i.d_kind)
- {
- case ADDITION:
- {
- os << "DRATProofa ";
- break;
- }
- case DELETION:
- {
- os << "DRATProofd ";
- break;
- }
- default:
- {
- Unreachable() << "Unrecognized DRAT instruction kind";
- }
- }
- for (const SatLiteral& l : i.d_clause)
- {
- os << "(clc (" << (l.isNegated() ? "neg " : "pos ")
- << ProofManager::getVarName(l.getSatVariable(), "bb") << ") ";
- }
- os << "cln";
- std::fill_n(std::ostream_iterator<char>(os), i.d_clause.size(), ')');
- os << "\n";
- }
- os << "DRATProofn";
- std::fill_n(std::ostream_iterator<char>(os), d_instructions.size(), ')');
-}
-} // namespace drat
-} // namespace proof
-} // namespace CVC4
diff --git a/src/proof/drat/drat_proof.h b/src/proof/drat/drat_proof.h
deleted file mode 100644
index 1213c80c7..000000000
--- a/src/proof/drat/drat_proof.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/********************* */
-/*! \file drat_proof.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Alex Ozdemir, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief DRAT Proof Format
- **
- ** Declares C++ types that represent a DRAT proof.
- ** Defines serialization for these types.
- **
- ** You can find an introduction to DRAT in the drat-trim paper:
- ** http://www.cs.utexas.edu/~marijn/publications/drat-trim.pdf
- **
- **/
-
-#ifndef CVC4__PROOF__DRAT__DRAT_PROOF_H
-#define CVC4__PROOF__DRAT__DRAT_PROOF_H
-
-#include "cvc4_private.h"
-#include "prop/sat_solver.h"
-#include "prop/sat_solver_types.h"
-
-namespace CVC4 {
-namespace proof {
-namespace drat {
-
-using CVC4::prop::SatClause;
-using CVC4::prop::SatLiteral;
-using CVC4::prop::SatVariable;
-
-class CVC4_PUBLIC InvalidDratProofException : public CVC4::Exception
-{
- public:
- InvalidDratProofException() : Exception("Invalid DRAT Proof") {}
-
- InvalidDratProofException(const std::string& msg) : Exception(msg) {}
-
- InvalidDratProofException(const char* msg) : Exception(msg) {}
-}; /* class InvalidDratProofException */
-
-enum DratInstructionKind
-{
- ADDITION,
- DELETION
-};
-
-struct DratInstruction
-{
- DratInstruction(DratInstructionKind kind, SatClause clause);
-
- /**
- * Write the DRAT instruction in textual format.
- * The format is described in:
- * http://www.cs.utexas.edu/~marijn/publications/drat-trim.pdf
- *
- * @param os the stream to write to
- */
- void outputAsText(std::ostream& os) const;
-
- DratInstructionKind d_kind;
- SatClause d_clause;
-};
-
-class DratProof
-{
- public:
- DratProof(const DratProof&) = default;
-
- DratProof(DratProof&&) = default;
-
- ~DratProof() = default;
-
- /**
- * Parses a DRAT proof from the **binary format**.
- * The format is described at:
- * https://www.cs.utexas.edu/~marijn/drat-trim/#contact
- *
- * What do the standard authors mean by the format being "binary"?
- * They just mean that proofs in this format should be understood as
- * sequences of bytes, not sequences of ASCII/Unicode/your favorite character
- * set characters.
- *
- * @param binaryProof a string containing the bytes of the binary proof.
- * Even though the proof isn't text, it's safe to store it in a string
- * because C++ strings don't make any gaurantees about the encoding of
- * their contents. This makes them (effectively) just byte sequences.
- *
- * @return the parsed proof
- */
- static DratProof fromBinary(const std::string& binaryProof);
-
- /**
- * @return The instructions in this proof
- */
- const std::vector<DratInstruction>& getInstructions() const;
-
- /**
- * Write the DRAT proof in textual format.
- * The format is described in:
- * http://www.cs.utexas.edu/~marijn/publications/drat-trim.pdf
- *
- * @param os the stream to write to
- */
- void outputAsText(std::ostream& os) const;
-
- /**
- * Write the DRAT proof as an LFSC value
- * The format is from the LFSC signature drat.plf
- *
- * Reads the current `ProofManager` to determine what the variables should be
- * named.
- *
- * @param os the stream to write to
- * @param indentation the number of spaces to indent each proof instruction
- */
- void outputAsLfsc(std::ostream& os, uint8_t indentation) const;
-
- private:
- /**
- * Create an DRAT proof with no instructions.
- */
- DratProof();
-
- /**
- * The instructions of the DRAT proof.
- */
- std::vector<DratInstruction> d_instructions;
-};
-
-} // namespace drat
-} // namespace proof
-} // namespace CVC4
-
-#endif // CVC4__PROOF__DRAT__DRAT_PROOF_H
diff --git a/src/proof/er/er_proof.cpp b/src/proof/er/er_proof.cpp
deleted file mode 100644
index 54b0fd879..000000000
--- a/src/proof/er/er_proof.cpp
+++ /dev/null
@@ -1,399 +0,0 @@
-/********************* */
-/*! \file er_proof.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Alex Ozdemir, Andres Noetzli, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief ER Proof Format
- **
- ** Declares C++ types that represent an ER/TRACECHECK proof.
- ** Defines serialization for these types.
- **
- ** You can find details about the way ER is encoded in the TRACECHECK
- ** format at these locations:
- ** https://github.com/benjaminkiesl/drat2er
- ** http://www.cs.utexas.edu/users/marijn/publications/ijcar18.pdf
- **/
-
-#include "proof/er/er_proof.h"
-
-#include <unistd.h>
-#include <algorithm>
-#include <fstream>
-#include <iostream>
-#include <iterator>
-#include <sstream>
-#include <unordered_set>
-
-#include "base/check.h"
-#include "base/map_util.h"
-#include "proof/dimacs.h"
-#include "proof/lfsc_proof_printer.h"
-#include "proof/proof_manager.h"
-
-#if CVC4_USE_DRAT2ER
-#include "drat2er.h"
-#include "drat2er_options.h"
-#endif
-
-namespace CVC4 {
-namespace proof {
-namespace er {
-
-TraceCheckProof TraceCheckProof::fromText(std::istream& in)
-{
- TraceCheckProof pf;
- TraceCheckIdx idx = 0;
- int64_t token = 0;
-
- // For each line of the proof, start with the idx
- // If there is no idx, then you're done!
- in >> idx;
- for (; !in.eof(); in >> idx)
- {
- Assert(in.good());
-
- // Then parse the clause (it's 0-terminated)
- std::vector<prop::SatLiteral> clause;
- in >> token;
- for (; token != 0; in >> token)
- {
- clause.emplace_back(std::abs(token) - 1, token < 0);
- }
-
- // Then parse the chain of literals (it's also 0-terminated)
- std::vector<TraceCheckIdx> chain;
- in >> token;
- for (; token != 0; in >> token)
- {
- Assert(token > 0);
- chain.push_back(token);
- }
-
- // Add the line to the proof
- pf.d_lines.emplace_back(idx, std::move(clause), std::move(chain));
- }
- return pf;
-}
-
-ErProof ErProof::fromBinaryDratProof(
- const std::unordered_map<ClauseId, prop::SatClause>& clauses,
- const std::vector<ClauseId>& usedIds,
- const std::string& dratBinary,
- TimerStat& toolTimer)
-{
- std::string formulaFilename("cvc4-dimacs-XXXXXX");
- std::string dratFilename("cvc4-drat-XXXXXX");
- std::string tracecheckFilename("cvc4-tracecheck-er-XXXXXX");
-
- // Write the formula
- std::unique_ptr<std::fstream> formStream = openTmpFile(&formulaFilename);
- printDimacs(*formStream, clauses, usedIds);
- formStream->close();
-
- // Write the (binary) DRAT proof
- std::unique_ptr<std::fstream> dratStream = openTmpFile(&dratFilename);
- (*dratStream) << dratBinary;
- dratStream->close();
-
- std::unique_ptr<std::fstream> tracecheckStream =
- openTmpFile(&tracecheckFilename);
-
- // Invoke drat2er
- {
- CodeTimer blockTimer{toolTimer};
-#if CVC4_USE_DRAT2ER
- drat2er::TransformDRATToExtendedResolution(formulaFilename,
- dratFilename,
- tracecheckFilename,
- false,
- drat2er::options::QUIET,
- false);
-#else
- Unimplemented()
- << "ER proof production requires drat2er.\n"
- << "Run contrib/get-drat2er, reconfigure with --drat2er, and rebuild";
-#endif
- }
-
- // Parse the resulting TRACECHECK proof into an ER proof.
- TraceCheckProof pf = TraceCheckProof::fromText(*tracecheckStream);
- ErProof proof(clauses, usedIds, std::move(pf));
- tracecheckStream->close();
-
- remove(formulaFilename.c_str());
- remove(dratFilename.c_str());
- remove(tracecheckFilename.c_str());
-
- return proof;
-}
-
-ErProof::ErProof(const std::unordered_map<ClauseId, prop::SatClause>& clauses,
- const std::vector<ClauseId>& usedIds,
- TraceCheckProof&& tracecheck)
- : d_inputClauseIds(), d_definitions(), d_tracecheck(tracecheck)
-{
- // Step zero, save input clause Ids for future printing
- d_inputClauseIds = usedIds;
-
- // Make a list of (idx, clause pairs), the used ones.
- std::vector<std::pair<ClauseId, prop::SatClause>> usedClauses;
- std::transform(
- usedIds.begin(),
- usedIds.end(),
- std::back_inserter(usedClauses),
- [&](const ClauseId& i) { return make_pair(i, clauses.at(i)); });
-
- // Step one, verify the formula starts the proof
- if (Configuration::isAssertionBuild())
- {
- for (size_t i = 0, n = usedClauses.size(); i < n; ++i)
- {
- Assert(d_tracecheck.d_lines[i].d_idx = i + 1);
- Assert(d_tracecheck.d_lines[i].d_chain.size() == 0);
- std::unordered_set<prop::SatLiteral, prop::SatLiteralHashFunction>
- traceCheckClause{d_tracecheck.d_lines[i].d_clause.begin(),
- d_tracecheck.d_lines[i].d_clause.end()};
- std::unordered_set<prop::SatLiteral, prop::SatLiteralHashFunction>
- originalClause{usedClauses[i].second.begin(),
- usedClauses[i].second.end()};
- Assert(traceCheckClause == originalClause);
- }
- }
-
- // Step two, identify definitions. They correspond to lines that follow the
- // input lines, are in bounds, and have no justifying chain.
- for (size_t i = usedClauses.size(), n = d_tracecheck.d_lines.size();
- i < n && d_tracecheck.d_lines[i].d_chain.size() == 0;)
- {
- prop::SatClause c = d_tracecheck.d_lines[i].d_clause;
- Assert(c.size() > 0);
- Assert(!c[0].isNegated());
-
- // Get the new variable of the definition -- the first variable of the
- // first clause
- prop::SatVariable newVar = c[0].getSatVariable();
-
- // The rest of the literals in the clause of the 'other literals' of the def
- std::vector<prop::SatLiteral> otherLiterals{++c.begin(), c.end()};
-
- size_t nLinesForThisDef = 2 + otherLiterals.size();
- // Look at the negation of the second literal in the second clause to get
- // the old literal
- AlwaysAssert(d_tracecheck.d_lines.size() > i + 1)
- << "Malformed definition in TRACECHECK proof from drat2er";
- d_definitions.emplace_back(newVar,
- ~d_tracecheck.d_lines[i + 1].d_clause[1],
- std::move(otherLiterals));
-
- // Advance over the lines for this definition
- i += nLinesForThisDef;
- }
-}
-
-void ErProof::outputAsLfsc(std::ostream& os) const
-{
- // How many parens to close?
- size_t parenCount = 0;
- std::unordered_set<prop::SatVariable> newVariables;
-
- // Print Definitions
- for (const ErDefinition& def : d_definitions)
- {
- os << "\n (decl_definition ("
- << (def.d_oldLiteral.isNegated() ? "neg " : "pos ")
- << ProofManager::getVarName(def.d_oldLiteral.getSatVariable(), "bb")
- << ") ";
- LFSCProofPrinter::printSatClause(def.d_otherLiterals, os, "bb");
- os << " (\\ er.v" << def.d_newVariable << " (\\ er.def"
- << def.d_newVariable;
- newVariables.insert(def.d_newVariable);
- }
- parenCount += 3 * d_definitions.size();
-
- // Clausify Definitions
- TraceCheckIdx firstDefClause = d_inputClauseIds.size() + 1;
- for (const ErDefinition& def : d_definitions)
- {
- os << "\n (clausify_definition _ _ _ "
- << "er.def" << def.d_newVariable << " _ (\\ er.c" << firstDefClause
- << " (\\ er.c" << (firstDefClause + 1) << " (\\ er.cnf"
- << def.d_newVariable;
-
- firstDefClause += 2 + def.d_otherLiterals.size();
- }
- parenCount += 4 * d_definitions.size();
-
- // Unroll proofs of CNF to proofs of clauses
- firstDefClause = d_inputClauseIds.size() + 1;
- for (const ErDefinition& def : d_definitions)
- {
- for (size_t i = 0, n = def.d_otherLiterals.size(); i < n; ++i)
- {
- // Compute the name of the CNF proof we're unrolling in this step
- std::ostringstream previousCnfProof;
- previousCnfProof << "er.cnf" << def.d_newVariable;
- if (i != 0)
- {
- // For all but the first unrolling, the previous CNF has an unrolling
- // number attached
- previousCnfProof << ".u" << i;
- }
-
- // Prove the first clause in the CNF
- os << "\n (@ ";
- os << "er.c" << (firstDefClause + 2 + i);
- os << " (common_tail_cnf_prove_head _ _ _ " << previousCnfProof.str()
- << ")";
-
- // Prove the rest of the CNF
- os << "\n (@ ";
- os << "er.cnf" << def.d_newVariable << ".u" << (i + 1);
- os << " (common_tail_cnf_prove_tail _ _ _ " << previousCnfProof.str()
- << ")";
- }
- parenCount += 2 * def.d_otherLiterals.size();
-
- firstDefClause += 2 + def.d_otherLiterals.size();
- }
-
- // NB: At this point `firstDefClause` points to the first clause resulting
- // from a resolution chain
-
- // Now, elaborate each resolution chain
- for (size_t cId = firstDefClause, nLines = d_tracecheck.d_lines.size();
- cId <= nLines;
- ++cId)
- {
- const std::vector<TraceCheckIdx>& chain =
- d_tracecheck.d_lines[cId - 1].d_chain;
- const std::vector<prop::SatLiteral> pivots = computePivotsForChain(chain);
- Assert(chain.size() > 0);
- Assert(chain.size() == pivots.size() + 1);
-
- os << "\n (satlem_simplify _ _ _ ";
- parenCount += 1;
-
- // Print resolution openings (reverse order)
- for (int64_t i = pivots.size() - 1; i >= 0; --i)
- {
- prop::SatLiteral pivot = pivots[i];
- os << "(" << (pivot.isNegated() ? 'Q' : 'R') << " _ _ ";
- }
-
- // Print resolution start
- writeIdForClauseProof(os, chain[0]);
- os << " ";
-
- // Print resolution closings (forward order)
- for (size_t i = 0, n = pivots.size(); i < n; ++i)
- {
- prop::SatVariable pivotVar = pivots[i].getSatVariable();
- TraceCheckIdx clauseId = chain[i + 1];
- writeIdForClauseProof(os, clauseId);
- os << " ";
- if (ContainsKey(newVariables, pivotVar))
- {
- // This is a defined variable
- os << "er.v" << pivotVar;
- }
- else
- {
- os << ProofManager::getVarName(pivotVar, "bb");
- }
- os << ") ";
- }
- os << "(\\ er.c" << cId;
- parenCount += 1;
- }
-
- // Write proof of bottom
- Assert(d_tracecheck.d_lines.back().d_clause.size() == 0)
- << "The TRACECHECK proof from drat2er did not prove bottom.";
- os << "\n er.c" << d_tracecheck.d_lines.back().d_idx
- << " ; (holds cln)\n";
-
- // Finally, close the parentheses!
- std::fill_n(std::ostream_iterator<char>(os), parenCount, ')');
-}
-
-namespace {
-/**
- * Resolves two clauses
- *
- * @param dest one of the inputs, and the output too. **This is an input and
- * output**
- * @param src the other input
- *
- * @return the unique literal that was resolved on, with the polarization that
- * it originally had in `dest`.
- *
- * For example, if dest = (1 3 -4 5) and src = (1 -3 5), then 3 is returned and
- * after the call dest = (1 -4 5).
- */
-prop::SatLiteral resolveModify(
- std::unordered_set<prop::SatLiteral, prop::SatLiteralHashFunction>& dest,
- const prop::SatClause& src)
-{
- CVC4_UNUSED bool foundPivot = false;
- prop::SatLiteral pivot(0, false);
-
- for (prop::SatLiteral lit : src)
- {
- auto negationLocation = dest.find(~lit);
- if (negationLocation != dest.end())
- {
-#ifdef CVC4_ASSERTIONS
- Assert(!foundPivot);
- foundPivot = true;
-#endif
- dest.erase(negationLocation);
- pivot = ~lit;
- }
- dest.insert(lit);
- }
-
- Assert(foundPivot);
- return pivot;
-}
-} // namespace
-
-std::vector<prop::SatLiteral> ErProof::computePivotsForChain(
- const std::vector<TraceCheckIdx>& chain) const
-{
- std::vector<prop::SatLiteral> pivots;
-
- const prop::SatClause& first = d_tracecheck.d_lines[chain[0] - 1].d_clause;
- std::unordered_set<prop::SatLiteral, prop::SatLiteralHashFunction>
- runningClause{first.begin(), first.end()};
-
- for (auto idx = ++chain.cbegin(), end = chain.cend(); idx != end; ++idx)
- {
- pivots.push_back(
- resolveModify(runningClause, d_tracecheck.d_lines[*idx - 1].d_clause));
- }
- return pivots;
-}
-
-void ErProof::writeIdForClauseProof(std::ostream& o, TraceCheckIdx i) const
-{
- if (i <= d_inputClauseIds.size())
- {
- // This clause is an input clause! Ask the ProofManager for its name
- o << ProofManager::getInputClauseName(d_inputClauseIds[i - 1], "bb");
- }
- else
- {
- // This clause was introduced by a definition or resolution chain
- o << "er.c" << i;
- }
-}
-
-} // namespace er
-} // namespace proof
-} // namespace CVC4
diff --git a/src/proof/er/er_proof.h b/src/proof/er/er_proof.h
deleted file mode 100644
index 6f7239ef2..000000000
--- a/src/proof/er/er_proof.h
+++ /dev/null
@@ -1,218 +0,0 @@
-/********************* */
-/*! \file er_proof.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Alex Ozdemir, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief ER Proof Format
- **
- ** Declares C++ types that represent an ER/TRACECHECK proof.
- ** Defines serialization for these types.
- **
- ** You can find details about the way ER is encoded in the TRACECHECK
- ** format at these locations:
- ** https://github.com/benjaminkiesl/drat2er
- ** http://www.cs.utexas.edu/users/marijn/publications/ijcar18.pdf
- **
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__PROOF__ER__ER_PROOF_H
-#define CVC4__PROOF__ER__ER_PROOF_H
-
-#include <memory>
-#include <unordered_map>
-#include <vector>
-
-#include "proof/clause_id.h"
-#include "prop/sat_solver_types.h"
-#include "util/statistics_registry.h"
-
-namespace CVC4 {
-namespace proof {
-namespace er {
-
-/**
- * A definition of the form:
- * newVar <-> p v (~x_1 ^ ~x_2 ^ ... ^ ~x_n)
- */
-struct ErDefinition
-{
- ErDefinition(prop::SatVariable newVariable,
- prop::SatLiteral oldLiteral,
- std::vector<prop::SatLiteral>&& otherLiterals)
- : d_newVariable(newVariable),
- d_oldLiteral(oldLiteral),
- d_otherLiterals(otherLiterals)
- {
- }
-
- // newVar
- prop::SatVariable d_newVariable;
- // p
- prop::SatLiteral d_oldLiteral;
- // A list of the x_i's
- std::vector<prop::SatLiteral> d_otherLiterals;
-};
-
-// For representing a clause's index within a TRACECHECK proof.
-using TraceCheckIdx = size_t;
-
-/**
- * A single line in a TRACECHECK proof.
- *
- * Consists of the index of a new clause, the literals of that clause, and the
- * indices for preceding clauses which can be combined in a resolution chain to
- * produce this new clause.
- */
-struct TraceCheckLine
-{
- TraceCheckLine(TraceCheckIdx idx,
- std::vector<prop::SatLiteral>&& clause,
- std::vector<TraceCheckIdx>&& chain)
- : d_idx(idx), d_clause(clause), d_chain(chain)
- {
- }
-
- // The index of the new clause
- TraceCheckIdx d_idx;
- // The new clause
- std::vector<prop::SatLiteral> d_clause;
- /**
- * Indices of clauses which must be resolved to produce this new clause.
- * While the TRACECHECK format does not specify the order, we require them to
- * be in resolution-order.
- */
- std::vector<TraceCheckIdx> d_chain;
-};
-
-/**
- * A TRACECHECK proof -- just a list of lines
- */
-struct TraceCheckProof
-{
- static TraceCheckProof fromText(std::istream& in);
- TraceCheckProof() : d_lines() {}
-
- // The lines of this proof.
- std::vector<TraceCheckLine> d_lines;
-};
-
-/**
- * An extended resolution proof.
- * It supports resolution, along with extensions of the form
- *
- * newVar <-> p v (~x_1 ^ ~x_2 ^ ... ^ ~x_n)
- */
-class ErProof
-{
- public:
- /**
- * Construct an ER proof from a DRAT proof, using drat2er
- *
- * @param clauses A store of clauses that might be in our formula
- * @param usedIds the ids of clauses that are actually in our formula
- * @param dratBinary The DRAT proof from the SAT solver, as a binary stream
- *
- * @return the Er proof and a timer of the execution of drat2er
- */
- static ErProof fromBinaryDratProof(
- const std::unordered_map<ClauseId, prop::SatClause>& clauses,
- const std::vector<ClauseId>& usedIds,
- const std::string& dratBinary,
- TimerStat& toolTimer
- );
-
- /**
- * Construct an ER proof from a TRACECHECK ER proof
- *
- * This basically just identifies groups of lines which correspond to
- * definitions, and extracts them.
- *
- * @param clauses A store of clauses that might be in our formula
- * @param usedIds the ids of clauses that are actually in our formula
- * @param tracecheck The TRACECHECK proof, as a stream.
- */
- ErProof(const std::unordered_map<ClauseId, prop::SatClause>& clauses,
- const std::vector<ClauseId>& usedIds,
- TraceCheckProof&& tracecheck);
-
- /**
- * Write the ER proof as an LFSC value of type (holds cln).
- * The format is from the LFSC signature er.plf
- *
- * Reads the current `ProofManager` to determine what the variables should be
- * named.
- *
- * @param os the stream to write to
- */
- void outputAsLfsc(std::ostream& os) const;
-
- const std::vector<ClauseId>& getInputClauseIds() const
- {
- return d_inputClauseIds;
- }
-
- const std::vector<ErDefinition>& getDefinitions() const
- {
- return d_definitions;
- }
-
- const TraceCheckProof& getTraceCheckProof() const { return d_tracecheck; }
-
- private:
- /**
- * Creates an empty ErProof.
- */
- ErProof() : d_inputClauseIds(), d_definitions(), d_tracecheck() {}
-
- /**
- * Computes the pivots on the basis of which an in-order resolution chain is
- * resolved.
- *
- * c0 c1
- * \ / Clauses c_i being resolved in a chain around
- * v1 c2 pivots v_i.
- * \ /
- * v2 c3
- * \ /
- * v3 c4
- * \ /
- * v4
- *
- *
- * @param chain the chain, of N clause indices
- *
- * @return a list of N - 1 variables, the list ( v_i ) from i = 1 to N - 1
- */
- std::vector<prop::SatLiteral> computePivotsForChain(
- const std::vector<TraceCheckIdx>& chain) const;
-
- /**
- * Write the LFSC identifier for the proof of a clause
- *
- * @param o where to write to
- * @param i the TRACECHECK index for the clause whose proof identifier to
- * print
- */
- void writeIdForClauseProof(std::ostream& o, TraceCheckIdx i) const;
-
- // A list of the Ids for the input clauses, in order.
- std::vector<ClauseId> d_inputClauseIds;
- // A list of new variable definitions, in order.
- std::vector<ErDefinition> d_definitions;
- // The underlying TRACECHECK proof.
- TraceCheckProof d_tracecheck;
-};
-
-} // namespace er
-} // namespace proof
-} // namespace CVC4
-
-#endif // CVC4__PROOF__ER__ER_PROOF_H
diff --git a/src/proof/lemma_proof.cpp b/src/proof/lemma_proof.cpp
deleted file mode 100644
index bdebb6cfc..000000000
--- a/src/proof/lemma_proof.cpp
+++ /dev/null
@@ -1,254 +0,0 @@
-/********************* */
-/*! \file lemma_proof.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Guy Katz, Alex Ozdemir, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** A class for recoding the steps required in order to prove a theory lemma.
-
-**/
-
-#include "proof/lemma_proof.h"
-#include "theory/rewriter.h"
-
-namespace CVC4 {
-
-LemmaProofRecipe::ProofStep::ProofStep(theory::TheoryId theory, Node literalToProve) :
- d_theory(theory), d_literalToProve(literalToProve) {
-}
-
-theory::TheoryId LemmaProofRecipe::ProofStep::getTheory() const {
- return d_theory;
-}
-
-Node LemmaProofRecipe::ProofStep::getLiteral() const {
- return d_literalToProve;
-}
-
-void LemmaProofRecipe::ProofStep::addAssertion(const Node& assertion) {
- d_assertions.insert(assertion);
-}
-
-std::set<Node> LemmaProofRecipe::ProofStep::getAssertions() const {
- return d_assertions;
-}
-
-void LemmaProofRecipe::addStep(ProofStep& proofStep) {
- d_proofSteps.push_back(proofStep);
-}
-
-std::set<Node> LemmaProofRecipe::getMissingAssertionsForStep(unsigned index) const {
- Assert(index < d_proofSteps.size());
-
- std::set<Node> existingAssertions = getBaseAssertions();
-
- // The literals for all the steps "before" (i.e. behind) the step indicated
- // by the index are considered "existing"
- size_t revIndex = d_proofSteps.size() - 1 - index;
- for (size_t i = d_proofSteps.size() - 1; i != revIndex; --i)
- {
- existingAssertions.insert(d_proofSteps[i].getLiteral().negate());
- }
-
- std::set<Node> neededAssertions = d_proofSteps[revIndex].getAssertions();
-
- std::set<Node> result;
- std::set_difference(neededAssertions.begin(), neededAssertions.end(),
- existingAssertions.begin(), existingAssertions.end(),
- std::inserter(result, result.begin()));
- return result;
-}
-
-void LemmaProofRecipe::dump(const char *tag) const {
-
- if (d_proofSteps.size() == 1) {
- Debug(tag) << std::endl << "[Simple lemma]" << std::endl << std::endl;
- }
-
- if (d_originalLemma != Node()) {
- Debug(tag) << std::endl << "Original lemma: " << d_originalLemma << std::endl << std::endl;
- }
-
- unsigned count = 1;
- Debug(tag) << "Base assertions:" << std::endl;
- for (std::set<Node>::iterator baseIt = d_baseAssertions.begin();
- baseIt != d_baseAssertions.end();
- ++baseIt) {
- Debug(tag) << "\t#" << count << ": " << "\t" << *baseIt << std::endl;
- ++count;
- }
-
- Debug(tag) << std::endl << std::endl << "Proof steps:" << std::endl;
-
- count = 1;
- for (const auto& step : (*this)) {
- Debug(tag) << "\tStep #" << count << ": " << "\t[" << step.getTheory() << "] ";
- if (step.getLiteral() == Node()) {
- Debug(tag) << "Contradiction";
- } else {
- Debug(tag) << step.getLiteral();
- }
-
- Debug(tag) << std::endl;
-
- std::set<Node> missingAssertions = getMissingAssertionsForStep(count - 1);
- for (std::set<Node>::const_iterator it = missingAssertions.begin(); it != missingAssertions.end(); ++it) {
- Debug(tag) << "\t\t\tMissing assertion for step: " << *it << std::endl;
- }
-
- Debug(tag) << std::endl;
- ++count;
- }
-
- if (!d_assertionToExplanation.empty()) {
- Debug(tag) << std::endl << "Rewrites used:" << std::endl;
- count = 1;
- for (std::map<Node, Node>::const_iterator rewrite = d_assertionToExplanation.begin();
- rewrite != d_assertionToExplanation.end();
- ++rewrite) {
- Debug(tag) << "\tRewrite #" << count << ":" << std::endl
- << "\t\t" << rewrite->first
- << std::endl << "\t\trewritten into" << std::endl
- << "\t\t" << rewrite->second
- << std::endl << std::endl;
- ++count;
- }
- }
-}
-
-void LemmaProofRecipe::addBaseAssertion(Node baseAssertion) {
- d_baseAssertions.insert(baseAssertion);
-}
-
-std::set<Node> LemmaProofRecipe::getBaseAssertions() const {
- return d_baseAssertions;
-}
-
-theory::TheoryId LemmaProofRecipe::getTheory() const {
- Assert(d_proofSteps.size() > 0);
- return d_proofSteps.back().getTheory();
-}
-
-void LemmaProofRecipe::addRewriteRule(Node assertion, Node explanation) {
- if (d_assertionToExplanation.find(assertion) != d_assertionToExplanation.end()) {
- Assert(d_assertionToExplanation[assertion] == explanation);
- }
-
- d_assertionToExplanation[assertion] = explanation;
-}
-
-bool LemmaProofRecipe::wasRewritten(Node assertion) const {
- return d_assertionToExplanation.find(assertion) != d_assertionToExplanation.end();
-}
-
-Node LemmaProofRecipe::getExplanation(Node assertion) const {
- Assert(d_assertionToExplanation.find(assertion)
- != d_assertionToExplanation.end());
- return d_assertionToExplanation.find(assertion)->second;
-}
-
-LemmaProofRecipe::RewriteIterator LemmaProofRecipe::rewriteBegin() const {
- return d_assertionToExplanation.begin();
-}
-
-LemmaProofRecipe::RewriteIterator LemmaProofRecipe::rewriteEnd() const {
- return d_assertionToExplanation.end();
-}
-
-LemmaProofRecipe::iterator LemmaProofRecipe::begin() {
- return d_proofSteps.rbegin();
-}
-
-LemmaProofRecipe::iterator LemmaProofRecipe::end() {
- return d_proofSteps.rend();
-}
-
-LemmaProofRecipe::const_iterator LemmaProofRecipe::begin() const {
- return d_proofSteps.crbegin();
-}
-
-LemmaProofRecipe::const_iterator LemmaProofRecipe::end() const {
- return d_proofSteps.crend();
-}
-
-bool LemmaProofRecipe::operator<(const LemmaProofRecipe& other) const {
- return d_baseAssertions < other.d_baseAssertions;
- }
-
-bool LemmaProofRecipe::simpleLemma() const {
- return d_proofSteps.size() == 1;
-}
-
-bool LemmaProofRecipe::compositeLemma() const {
- return !simpleLemma();
-}
-
-const LemmaProofRecipe::ProofStep* LemmaProofRecipe::getStep(unsigned index) const {
- Assert(index < d_proofSteps.size());
-
- size_t revIndex = d_proofSteps.size() - 1 - index;
-
- return &d_proofSteps[revIndex];
-}
-
-LemmaProofRecipe::ProofStep* LemmaProofRecipe::getStep(unsigned index) {
- Assert(index < d_proofSteps.size());
-
- size_t revIndex = d_proofSteps.size() - 1 - index;
-
- return &d_proofSteps[revIndex];
-}
-
-unsigned LemmaProofRecipe::getNumSteps() const {
- return d_proofSteps.size();
-}
-
-void LemmaProofRecipe::setOriginalLemma(Node lemma) {
- d_originalLemma = lemma;
-}
-
-Node LemmaProofRecipe::getOriginalLemma() const {
- return d_originalLemma;
-}
-
-std::ostream& operator<<(std::ostream& out,
- const LemmaProofRecipe::ProofStep& step)
-{
- out << "Proof Step(";
- out << " lit = " << step.getLiteral() << ",";
- out << " assertions = " << step.getAssertions() << ",";
- out << " theory = " << step.getTheory();
- out << " )";
- return out;
-}
-
-std::ostream& operator<<(std::ostream& out, const LemmaProofRecipe& recipe)
-{
- out << "LemmaProofRecipe(";
- out << "\n original lemma = " << recipe.getOriginalLemma();
- out << "\n actual clause = " << recipe.getBaseAssertions();
- out << "\n theory = " << recipe.getTheory();
- out << "\n steps = ";
- for (const auto& step : recipe)
- {
- out << "\n " << step;
- }
- out << "\n rewrites = ";
- for (LemmaProofRecipe::RewriteIterator i = recipe.rewriteBegin(),
- end = recipe.rewriteEnd();
- i != end;
- ++i)
- {
- out << "\n Rewrite(" << i->first << ", explanation = " << i->second
- << ")";
- }
- out << "\n)";
- return out;
-}
-
-} /* namespace CVC4 */
diff --git a/src/proof/lemma_proof.h b/src/proof/lemma_proof.h
deleted file mode 100644
index ffc6655a6..000000000
--- a/src/proof/lemma_proof.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/********************* */
-/*! \file lemma_proof.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Guy Katz, Alex Ozdemir, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** A class for recoding the steps required in order to prove a theory lemma.
-
-**/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__LEMMA_PROOF_H
-#define CVC4__LEMMA_PROOF_H
-
-#include "expr/expr.h"
-#include "proof/clause_id.h"
-#include "prop/sat_solver_types.h"
-#include "util/proof.h"
-#include "expr/node.h"
-#include <iosfwd>
-
-namespace CVC4 {
-
-class LemmaProofRecipe {
-public:
- class ProofStep {
- public:
- ProofStep(theory::TheoryId theory, Node literalToProve);
- theory::TheoryId getTheory() const;
- Node getLiteral() const;
- void addAssertion(const Node& assertion);
- std::set<Node> getAssertions() const;
-
- private:
- theory::TheoryId d_theory;
- Node d_literalToProve;
- std::set<Node> d_assertions;
- };
-
- //* The lemma assertions and owner */
- void addBaseAssertion(Node baseAssertion);
- std::set<Node> getBaseAssertions() const;
- theory::TheoryId getTheory() const;
-
- //* Rewrite rules */
- using RewriteIterator = std::map<Node, Node>::const_iterator;
- RewriteIterator rewriteBegin() const;
- RewriteIterator rewriteEnd() const;
-
- // Steps iterator
- // The default iterator for a LemmaProofRecipe
- using iterator = std::vector<ProofStep>::reverse_iterator;
- std::vector<ProofStep>::reverse_iterator begin();
- std::vector<ProofStep>::reverse_iterator end();
-
- using const_iterator = std::vector<ProofStep>::const_reverse_iterator;
- std::vector<ProofStep>::const_reverse_iterator begin() const;
- std::vector<ProofStep>::const_reverse_iterator end() const;
-
- using difference_type = ptrdiff_t;
- using size_type = size_t;
- using value_type = ProofStep;
- using pointer = ProofStep *;
- using const_pointer = const ProofStep *;
- using reference = ProofStep &;
- using const_reference = const ProofStep &;
-
- void addRewriteRule(Node assertion, Node explanation);
- bool wasRewritten(Node assertion) const;
- Node getExplanation(Node assertion) const;
-
- //* Original lemma */
- void setOriginalLemma(Node lemma);
- Node getOriginalLemma() const;
-
- //* Proof Steps */
- void addStep(ProofStep& proofStep);
- const ProofStep* getStep(unsigned index) const;
- ProofStep* getStep(unsigned index);
- unsigned getNumSteps() const;
- std::set<Node> getMissingAssertionsForStep(unsigned index) const;
- bool simpleLemma() const;
- bool compositeLemma() const;
-
- void dump(const char *tag) const;
- bool operator<(const LemmaProofRecipe& other) const;
-
-private:
- //* The list of assertions for this lemma */
- std::set<Node> d_baseAssertions;
-
- //* The various steps needed to derive the empty clause */
- // The "first" step is actually at the back.
- std::vector<ProofStep> d_proofSteps;
-
- //* A map from assertions to their rewritten explanations (toAssert --> toExplain) */
- std::map<Node, Node> d_assertionToExplanation;
-
- //* The original lemma, as asserted by the owner theory solver */
- Node d_originalLemma;
-};
-
-std::ostream& operator<<(std::ostream & out, const LemmaProofRecipe::ProofStep & step);
-
-std::ostream& operator<<(std::ostream & out, const LemmaProofRecipe & recipe);
-
-} /* CVC4 namespace */
-
-#endif /* CVC4__LEMMA_PROOF_H */
diff --git a/src/proof/lfsc_proof_printer.cpp b/src/proof/lfsc_proof_printer.cpp
deleted file mode 100644
index 464083841..000000000
--- a/src/proof/lfsc_proof_printer.cpp
+++ /dev/null
@@ -1,217 +0,0 @@
-/********************* */
-/*! \file lfsc_proof_printer.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Andres Noetzli, Alex Ozdemir, Liana Hadarean
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Prints proofs in the LFSC format
- **
- ** Prints proofs in the LFSC format.
- **/
-
-#include "proof/lfsc_proof_printer.h"
-
-#include <algorithm>
-#include <iostream>
-#include <iterator>
-
-#include "prop/bvminisat/core/Solver.h"
-#include "prop/minisat/core/Solver.h"
-
-namespace CVC4 {
-namespace proof {
-
-template <class Solver>
-std::string LFSCProofPrinter::clauseName(TSatProof<Solver>* satProof,
- ClauseId id)
-{
- std::ostringstream os;
- if (satProof->isInputClause(id))
- {
- os << ProofManager::getInputClauseName(id, satProof->getName());
- }
- else if (satProof->isLemmaClause(id))
- {
- os << ProofManager::getLemmaClauseName(id, satProof->getName());
- }
- else
- {
- os << ProofManager::getLearntClauseName(id, satProof->getName());
- }
- return os.str();
-}
-
-template <class Solver>
-void LFSCProofPrinter::printResolution(TSatProof<Solver>* satProof,
- ClauseId id,
- std::ostream& out,
- std::ostream& paren)
-{
- out << "(satlem_simplify _ _ _";
- paren << ")";
-
- const ResChain<Solver>& res = satProof->getResolutionChain(id);
- const typename ResChain<Solver>::ResSteps& steps = res.getSteps();
-
- for (int i = steps.size() - 1; i >= 0; i--)
- {
- out << " (";
- out << (steps[i].sign ? "R" : "Q") << " _ _";
- }
-
- ClauseId start_id = res.getStart();
- out << " " << clauseName(satProof, start_id);
-
- for (unsigned i = 0; i < steps.size(); i++)
- {
- prop::SatVariable v =
- prop::MinisatSatSolver::toSatVariable(var(steps[i].lit));
- out << " " << clauseName(satProof, steps[i].id) << " "
- << ProofManager::getVarName(v, satProof->getName()) << ")";
- }
-
- if (id == satProof->getEmptyClauseId())
- {
- out << " (\\ empty empty)";
- return;
- }
-
- out << " (\\ " << clauseName(satProof, id) << "\n"; // bind to lemma name
- paren << ")";
-}
-
-template <class Solver>
-void LFSCProofPrinter::printAssumptionsResolution(TSatProof<Solver>* satProof,
- ClauseId id,
- std::ostream& out,
- std::ostream& paren)
-{
- Assert(satProof->isAssumptionConflict(id));
- // print the resolution proving the assumption conflict
- printResolution(satProof, id, out, paren);
- // resolve out assumptions to prove empty clause
- out << "(satlem_simplify _ _ _ ";
- const std::vector<typename Solver::TLit>& confl =
- *(satProof->getAssumptionConflicts().at(id));
-
- Assert(confl.size());
-
- for (unsigned i = 0; i < confl.size(); ++i)
- {
- prop::SatLiteral lit = toSatLiteral<Solver>(confl[i]);
- out << "(";
- out << (lit.isNegated() ? "Q" : "R") << " _ _ ";
- }
-
- out << clauseName(satProof, id) << " ";
- for (int i = confl.size() - 1; i >= 0; --i)
- {
- prop::SatLiteral lit = toSatLiteral<Solver>(confl[i]);
- prop::SatVariable v = lit.getSatVariable();
- out << "unit" << v << " ";
- out << ProofManager::getVarName(v, satProof->getName()) << ")";
- }
- out << "(\\ e e)\n";
- paren << ")";
-}
-
-template <class Solver>
-void LFSCProofPrinter::printResolutions(TSatProof<Solver>* satProof,
- std::ostream& out,
- std::ostream& paren)
-{
- Debug("bv-proof") << "; print resolutions" << std::endl;
- std::set<ClauseId>::iterator it = satProof->getSeenLearnt().begin();
- for (; it != satProof->getSeenLearnt().end(); ++it)
- {
- if (*it != satProof->getEmptyClauseId())
- {
- Debug("bv-proof") << "; print resolution for " << *it << std::endl;
- printResolution(satProof, *it, out, paren);
- }
- }
- Debug("bv-proof") << "; done print resolutions" << std::endl;
-}
-
-template <class Solver>
-void LFSCProofPrinter::printResolutionEmptyClause(TSatProof<Solver>* satProof,
- std::ostream& out,
- std::ostream& paren)
-{
- printResolution(satProof, satProof->getEmptyClauseId(), out, paren);
-}
-
-void LFSCProofPrinter::printSatInputProof(const std::vector<ClauseId>& clauses,
- std::ostream& out,
- const std::string& namingPrefix)
-{
- for (auto i = clauses.begin(), end = clauses.end(); i != end; ++i)
- {
- out << "\n (cnfc_proof _ _ _ "
- << ProofManager::getInputClauseName(*i, namingPrefix) << " ";
- }
- out << "cnfn_proof";
- std::fill_n(std::ostream_iterator<char>(out), clauses.size(), ')');
-}
-
-void LFSCProofPrinter::printCMapProof(const std::vector<ClauseId>& clauses,
- std::ostream& out,
- const std::string& namingPrefix)
-{
- for (size_t i = 0, n = clauses.size(); i < n; ++i)
- {
- out << "\n (CMapc_proof " << (i + 1) << " _ _ _ "
- << ProofManager::getInputClauseName(clauses[i], namingPrefix) << " ";
- }
- out << "CMapn_proof";
- std::fill_n(std::ostream_iterator<char>(out), clauses.size(), ')');
-}
-
-void LFSCProofPrinter::printSatClause(const prop::SatClause& clause,
- std::ostream& out,
- const std::string& namingPrefix)
-{
- for (auto i = clause.cbegin(); i != clause.cend(); ++i)
- {
- out << "(clc " << (i->isNegated() ? "(neg " : "(pos ")
- << ProofManager::getVarName(i->getSatVariable(), namingPrefix) << ") ";
- }
- out << "cln";
- std::fill_n(std::ostream_iterator<char>(out), clause.size(), ')');
-}
-
-// Template specializations
-template void LFSCProofPrinter::printAssumptionsResolution(
- TSatProof<CVC4::Minisat::Solver>* satProof,
- ClauseId id,
- std::ostream& out,
- std::ostream& paren);
-template void LFSCProofPrinter::printResolutions(
- TSatProof<CVC4::Minisat::Solver>* satProof,
- std::ostream& out,
- std::ostream& paren);
-template void LFSCProofPrinter::printResolutionEmptyClause(
- TSatProof<CVC4::Minisat::Solver>* satProof,
- std::ostream& out,
- std::ostream& paren);
-
-template void LFSCProofPrinter::printAssumptionsResolution(
- TSatProof<CVC4::BVMinisat::Solver>* satProof,
- ClauseId id,
- std::ostream& out,
- std::ostream& paren);
-template void LFSCProofPrinter::printResolutions(
- TSatProof<CVC4::BVMinisat::Solver>* satProof,
- std::ostream& out,
- std::ostream& paren);
-template void LFSCProofPrinter::printResolutionEmptyClause(
- TSatProof<CVC4::BVMinisat::Solver>* satProof,
- std::ostream& out,
- std::ostream& paren);
-} // namespace proof
-} // namespace CVC4
diff --git a/src/proof/lfsc_proof_printer.h b/src/proof/lfsc_proof_printer.h
deleted file mode 100644
index 62547676f..000000000
--- a/src/proof/lfsc_proof_printer.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/********************* */
-/*! \file lfsc_proof_printer.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Andres Noetzli, Alex Ozdemir, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Prints proofs in the LFSC format
- **
- ** Prints proofs in the LFSC format.
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__PROOF__LFSC_PROOF_PRINTER_H
-#define CVC4__PROOF__LFSC_PROOF_PRINTER_H
-
-#include <iosfwd>
-#include <string>
-#include <vector>
-
-#include "proof/clause_id.h"
-#include "proof/proof_manager.h"
-#include "proof/sat_proof.h"
-#include "proof/sat_proof_implementation.h"
-#include "util/proof.h"
-
-namespace CVC4 {
-namespace proof {
-
-class LFSCProofPrinter
-{
- public:
- /**
- * Prints the resolution proof for an assumption conflict.
- *
- * @param satProof The record of the reasoning done by the SAT solver
- * @param id The clause to print a proof for
- * @param out The stream to print to
- * @param paren A stream for the closing parentheses
- */
- template <class Solver>
- static void printAssumptionsResolution(TSatProof<Solver>* satProof,
- ClauseId id,
- std::ostream& out,
- std::ostream& paren);
-
- /**
- * Prints the resolution proofs for learned clauses that have been used to
- * deduce unsat.
- *
- * @param satProof The record of the reasoning done by the SAT solver
- * @param out The stream to print to
- * @param paren A stream for the closing parentheses
- */
- template <class Solver>
- static void printResolutions(TSatProof<Solver>* satProof,
- std::ostream& out,
- std::ostream& paren);
-
- /**
- * Prints the resolution proof for the empty clause.
- *
- * @param satProof The record of the reasoning done by the SAT solver
- * @param out The stream to print to
- * @param paren A stream for the closing parentheses
- */
- template <class Solver>
- static void printResolutionEmptyClause(TSatProof<Solver>* satProof,
- std::ostream& out,
- std::ostream& paren);
-
- /**
- * The SAT solver is given a list of clauses.
- * Assuming that each clause has alreay been individually proven,
- * defines a proof of the input to the SAT solver.
- *
- * Prints an LFSC value corresponding to the proof, i.e. a value of type
- * (cnf_holds ...)
- *
- * @param clauses The clauses to print a proof of
- * @param out The stream to print to
- * @param namingPrefix The prefix for LFSC names
- */
- static void printSatInputProof(const std::vector<ClauseId>& clauses,
- std::ostream& out,
- const std::string& namingPrefix);
-
- /**
- * The LRAT proof signature uses the concept of a _clause map_ (CMap), which
- * represents an indexed collection of (conjoined) clauses.
- *
- * Specifically, the signatures rely on a proof that a CMap containing the
- * clauses given to the SAT solver hold.
- *
- * Assuming that the individual clauses already have proofs, this function
- * prints a proof of the CMap mapping 1 to the first clause, 2 to the second,
- * and so on.
- *
- * That is, it prints a value of type (CMap_holds ...)
- *
- * @param clauses The clauses to print a proof of
- * @param out The stream to print to
- * @param namingPrefix The prefix for LFSC names
- */
- static void printCMapProof(const std::vector<ClauseId>& clauses,
- std::ostream& out,
- const std::string& namingPrefix);
-
- /**
- * Prints a clause
- *
- * @param clause The clause to print
- * @param out The stream to print to
- * @param namingPrefix The prefix for LFSC names
- */
- static void printSatClause(const prop::SatClause& clause,
- std::ostream& out,
- const std::string& namingPrefix);
-
- private:
-
- /**
- * Maps a clause id to a string identifier used in the LFSC proof.
- *
- * @param satProof The record of the reasoning done by the SAT solver
- * @param id The clause to map to a string
- */
- template <class Solver>
- static std::string clauseName(TSatProof<Solver>* satProof, ClauseId id);
-
- /**
- * Prints the resolution proof for a given clause.
- *
- * @param satProof The record of the reasoning done by the SAT solver
- * @param id The clause to print a proof for
- * @param out The stream to print to
- * @param paren A stream for the closing parentheses
- */
- template <class Solver>
- static void printResolution(TSatProof<Solver>* satProof,
- ClauseId id,
- std::ostream& out,
- std::ostream& paren);
-};
-
-} // namespace proof
-} // namespace CVC4
-
-#endif /* CVC4__PROOF__LFSC_PROOF_PRINTER_H */
diff --git a/src/proof/lrat/lrat_proof.cpp b/src/proof/lrat/lrat_proof.cpp
deleted file mode 100644
index 69ffa623a..000000000
--- a/src/proof/lrat/lrat_proof.cpp
+++ /dev/null
@@ -1,343 +0,0 @@
-/********************* */
-/*! \file lrat_proof.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Alex Ozdemir, Andres Noetzli, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief DRAT Proof Format
- **
- ** Defines deserialization for DRAT proofs.
- **/
-
-#include "proof/lrat/lrat_proof.h"
-
-#include <algorithm>
-#include <cstdlib>
-#include <fstream>
-#include <iostream>
-#include <memory>
-#include <sstream>
-#include <unordered_map>
-
-#include "base/check.h"
-#include "base/output.h"
-#include "proof/dimacs.h"
-#include "proof/lfsc_proof_printer.h"
-#include "util/utility.h"
-
-#if CVC4_USE_DRAT2ER
-#include "drat2er_options.h"
-#include "drat_trim_interface.h"
-#endif
-
-namespace CVC4 {
-namespace proof {
-namespace lrat {
-
-using prop::SatClause;
-using prop::SatLiteral;
-using prop::SatVariable;
-
-namespace {
-
-// Prints the trace as a space-separated list of (+) ints with a space at the
-// end.
-std::ostream& operator<<(std::ostream& o, const LratUPTrace& trace)
-{
- for (const auto& i : trace)
- {
- o << i << " ";
- }
- return o;
-}
-
-/**
- * Print a list of clause indices to go to while doing UP.
- *
- * i.e. a value of type Trace
- *
- * @param o where to print to
- * @param trace the trace (list of clauses) to print
- */
-void printTrace(std::ostream& o, const LratUPTrace& trace)
-{
- for (ClauseIdx idx : trace)
- {
- o << "(Tracec " << idx << " ";
- }
- o << "Tracen";
- std::fill_n(std::ostream_iterator<char>(o), trace.size(), ')');
-}
-
-/**
- * Print the RAT hints for a clause addition.
- *
- * i.e. prints an LFSC value of type RATHints
- *
- * @param o where to print to
- * @param hints the RAT hints to print
- */
-void printHints(std::ostream& o,
- const std::vector<std::pair<ClauseIdx, LratUPTrace>>& hints)
-{
- for (auto& hint : hints)
- {
- o << "\n (RATHintsc " << hint.first << " ";
- printTrace(o, hint.second);
- o << " ";
- }
- o << "RATHintsn";
- std::fill_n(std::ostream_iterator<char>(o), hints.size(), ')');
-}
-
-/**
- * Print an index list
- *
- * i.e. prints an LFSC value of type CIList
- *
- * @param o where to print to
- * @param indices the list of indices to print
- */
-void printIndices(std::ostream& o, const std::vector<ClauseIdx>& indices)
-{
- Assert(indices.size() > 0);
- // Verify that the indices are sorted!
- for (size_t i = 0, n = indices.size() - 1; i < n; ++i)
- {
- Assert(indices[i] < indices[i + 1]);
- }
-
- for (ClauseIdx idx : indices)
- {
- o << "(CIListc " << idx << " ";
- }
- o << "CIListn";
- std::fill_n(std::ostream_iterator<char>(o), indices.size(), ')');
-}
-
-} // namespace
-
-// Prints the LRAT addition line in textual format
-
-LratProof LratProof::fromDratProof(
- const std::unordered_map<ClauseId, prop::SatClause>& clauses,
- const std::vector<ClauseId> usedIds,
- const std::string& dratBinary,
- TimerStat& toolTimer)
-{
- std::ostringstream cmd;
- std::string formulaFilename("cvc4-dimacs-XXXXXX");
- std::string dratFilename("cvc4-drat-XXXXXX");
- std::string lratFilename("cvc4-lrat-XXXXXX");
-
- std::unique_ptr<std::fstream> formStream = openTmpFile(&formulaFilename);
- printDimacs(*formStream, clauses, usedIds);
- formStream->close();
-
- std::unique_ptr<std::fstream> dratStream = openTmpFile(&dratFilename);
- (*dratStream) << dratBinary;
- dratStream->close();
-
- std::unique_ptr<std::fstream> lratStream = openTmpFile(&lratFilename);
-
- {
- CodeTimer blockTimer{toolTimer};
-#if CVC4_USE_DRAT2ER
- drat2er::drat_trim::CheckAndConvertToLRAT(
- formulaFilename, dratFilename, lratFilename, drat2er::options::QUIET);
-#else
- Unimplemented()
- << "LRAT proof production requires drat2er.\n"
- << "Run contrib/get-drat2er, reconfigure with --drat2er, and rebuild";
-#endif
- }
-
- LratProof lrat(*lratStream);
- remove(formulaFilename.c_str());
- remove(dratFilename.c_str());
- remove(lratFilename.c_str());
- return lrat;
-}
-
-std::istream& operator>>(std::istream& in, SatLiteral& l)
-{
- int64_t i;
- in >> i;
- l = SatLiteral(std::abs(i), i < 0);
- return in;
-}
-
-// This parser is implemented to parse the textual RAT format found in
-// "Efficient Certified RAT Verification", by Cruz-Filipe et. All
-LratProof::LratProof(std::istream& textualProof)
-{
- for (size_t line = 0;; ++line)
- {
- // Read beginning of instruction. EOF indicates that we're done.
- size_t clauseIdx;
- textualProof >> clauseIdx;
- if (textualProof.eof())
- {
- return;
- }
-
- // Read the first word of the instruction. A 'd' indicates deletion.
- std::string first;
- textualProof >> first;
- Trace("pf::lrat") << "First word: " << first << std::endl;
- Assert(textualProof.good());
- if (first == "d")
- {
- std::vector<ClauseIdx> clauses;
- while (true)
- {
- ClauseIdx di;
- textualProof >> di;
- Assert(textualProof.good());
- if (di == 0)
- {
- break;
- }
- clauses.push_back(di);
- }
- if (clauses.size() > 0)
- {
- std::sort(clauses.begin(), clauses.end());
- std::unique_ptr<LratInstruction> instr(
- new LratDeletion(clauseIdx, std::move(clauses)));
- d_instructions.push_back(std::move(instr));
- }
- }
- else
- {
- // We need to reparse the first word as a literal to read the clause
- // we're parsing. It ends with a 0;
- std::istringstream firstS(first);
- SatLiteral lit;
- firstS >> lit;
- Trace("pf::lrat") << "First lit: " << lit << std::endl;
- Assert(!firstS.fail())
- << "Couldn't parse first literal from addition line";
-
- SatClause clause;
- for (; lit != 0; textualProof >> lit)
- {
- Assert(textualProof.good());
- clause.emplace_back(lit.getSatVariable() - 1, lit.isNegated());
- }
-
- // Now we read the AT UP trace. It ends at the first non-(+) #
- std::vector<ClauseIdx> atTrace;
- int64_t i;
- textualProof >> i;
- for (; i > 0; textualProof >> i)
- {
- Assert(textualProof.good());
- atTrace.push_back(i);
- }
-
- // For each RAT hint... (each RAT hint starts with a (-)).
- std::vector<std::pair<ClauseIdx, LratUPTrace>> resolvants;
- for (; i<0; textualProof>> i)
- {
- Assert(textualProof.good());
- // Create an entry in the RAT hint list
- resolvants.emplace_back(-i, std::vector<ClauseIdx>());
-
- // Record the UP trace. It ends with a (-) or 0.
- textualProof >> i;
- for (; i > 0; textualProof >> i)
- {
- resolvants.back().second.push_back(i);
- }
- }
- // Pairs compare based on the first element, so this sorts by the
- // resolution target index
- std::sort(resolvants.begin(), resolvants.end());
- std::unique_ptr<LratInstruction> instr(
- new LratAddition(clauseIdx,
- std::move(clause),
- std::move(atTrace),
- std::move(resolvants)));
- d_instructions.push_back(std::move(instr));
- }
- }
-}
-
-void LratProof::outputAsLfsc(std::ostream& o) const
-{
- std::ostringstream closeParen;
- for (const auto& i : d_instructions)
- {
- i->outputAsLfsc(o, closeParen);
- }
- o << "LRATProofn";
- o << closeParen.str();
-}
-
-void LratAddition::outputAsText(std::ostream& o) const
-{
- o << d_idxOfClause << " ";
- textOut(o, d_clause) << " ";
- o << d_atTrace; // Inludes a space at the end.
- for (const auto& rat : d_resolvants)
- {
- o << "-" << rat.first << " ";
- o << rat.second; // Includes a space at the end.
- }
- o << "0\n";
-}
-
-void LratAddition::outputAsLfsc(std::ostream& o, std::ostream& closeParen) const
-{
- o << "\n (LRATProofa " << d_idxOfClause << " ";
- closeParen << ")";
- LFSCProofPrinter::printSatClause(d_clause, o, "bb");
- o << " ";
- printTrace(o, d_atTrace);
- o << " ";
- printHints(o, d_resolvants);
- o << " ";
-}
-
-void LratDeletion::outputAsText(std::ostream& o) const
-{
- o << d_idxOfClause << " d ";
- for (const auto& idx : d_clauses)
- {
- o << idx << " ";
- }
- o << "0\n";
-}
-
-void LratDeletion::outputAsLfsc(std::ostream& o, std::ostream& closeParen) const
-{
- o << "\n (LRATProofd ";
- closeParen << ")";
- printIndices(o, d_clauses);
- o << " ";
-}
-
-std::ostream& operator<<(std::ostream& o, const LratProof& p)
-{
- for (const auto& instr : p.getInstructions())
- {
- o << *instr;
- }
- return o;
-}
-
-std::ostream& operator<<(std::ostream& o, const LratInstruction& i)
-{
- i.outputAsText(o);
- return o;
-}
-
-} // namespace lrat
-} // namespace proof
-} // namespace CVC4
diff --git a/src/proof/lrat/lrat_proof.h b/src/proof/lrat/lrat_proof.h
deleted file mode 100644
index 1c065a08e..000000000
--- a/src/proof/lrat/lrat_proof.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/********************* */
-/*! \file lrat_proof.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Alex Ozdemir, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief LRAT Proof Format
- **
- ** Declares C++ types that represent a LRAT proof.
- ** Defines serialization for these types.
- **
- ** Represents an **abstract** LRAT proof.
- ** Does **not** represent an LFSC LRAT proof, or an LRAT proof being used to
- ** prove things about bit-vectors.
- **
- ** Paper on LRAT: https://www.cs.utexas.edu/~marijn/publications/lrat.pdf
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__PROOF__LRAT__LRAT_PROOF_H
-#define CVC4__PROOF__LRAT__LRAT_PROOF_H
-
-#include <iosfwd>
-#include <string>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-#include "proof/clause_id.h"
-// Included because we need operator<< for the SAT types
-#include "prop/sat_solver.h"
-#include "util/statistics_registry.h"
-
-namespace CVC4 {
-namespace proof {
-namespace lrat {
-
-// Refers to clause position within an LRAT proof
-using ClauseIdx = size_t;
-
-// This is conceptually an Either<Addition,Deletion>
-class LratInstruction
-{
- public:
- /**
- * Write this LRAT instruction in textual format
- *
- * @param out the stream to write to
- */
- virtual void outputAsText(std::ostream& out) const = 0;
- /**
- * Write this LRAT instruction as an LFSC value
- *
- * @param out the stream to write to
- * @param closeParen the stream to write any closing parentheses to
- *
- */
- virtual void outputAsLfsc(std::ostream& o,
- std::ostream& closeParen) const = 0;
- virtual ~LratInstruction() = default;
-};
-
-class LratDeletion : public LratInstruction
-{
- public:
- LratDeletion(ClauseIdx idxOfClause, std::vector<ClauseIdx>&& clauses)
- : d_idxOfClause(idxOfClause), d_clauses(clauses)
- {
- // Nothing left to do
- }
-
- LratDeletion() = default;
-
- void outputAsText(std::ostream& out) const override;
- void outputAsLfsc(std::ostream& o, std::ostream& closeParen) const override;
-
- private:
- // This idx doesn't really matter, but it's in the format anyway, so we parse
- // it.
- ClauseIdx d_idxOfClause;
-
- // Clauses to delete
- std::vector<ClauseIdx> d_clauses;
-};
-
-// A sequence of locations that will contain unit clauses during unit
-// propegation
-using LratUPTrace = std::vector<ClauseIdx>;
-
-class LratAddition : public LratInstruction
-{
- public:
- LratAddition(ClauseIdx idxOfClause,
- prop::SatClause&& clause,
- LratUPTrace&& atTrace,
- std::vector<std::pair<ClauseIdx, LratUPTrace>> resolvants)
- : d_idxOfClause(idxOfClause),
- d_clause(clause),
- d_atTrace(atTrace),
- d_resolvants(resolvants)
- {
- // Nothing left to do
- }
-
- void outputAsText(std::ostream& out) const override;
- void outputAsLfsc(std::ostream& o, std::ostream& closeParen) const override;
-
- private:
- // The idx for the new clause
- ClauseIdx d_idxOfClause;
- // The new clause
- prop::SatClause d_clause;
- // UP trace based on the negation of that clause
- LratUPTrace d_atTrace;
-
- // Clauses that can resolve with `clause` on its first variable,
- // together with a UP trace after that resolution.
- // Used for RAT checks.
- std::vector<std::pair<ClauseIdx, LratUPTrace>> d_resolvants;
-};
-
-class LratProof
-{
- public:
- /**
- * @brief Construct an LRAT proof from a DRAT proof, using drat-trim
- *
- * @param clauses A store of clauses that might be in our formula
- * @param usedIds the ids of clauses that are actually in our formula
- * @param dratBinary The DRAT proof from the SAT solver, as a binary stream.
- *
- * @return an LRAT proof an a timer for how long it took to run drat-trim
- */
- static LratProof fromDratProof(
- const std::unordered_map<ClauseId, prop::SatClause>& clauses,
- const std::vector<ClauseId> usedIds,
- const std::string& dratBinary,
- TimerStat& toolTimer);
- /**
- * @brief Construct an LRAT proof from its textual representation
- *
- * @param textualProof the textual encoding of the LRAT proof. See the paper
- * in the file's header comment.
- */
- LratProof(std::istream& textualProof);
-
- /**
- * Construct a LRAT proof from an explicit instruction list
- *
- * @param instructions
- */
- LratProof(std::vector<std::unique_ptr<LratInstruction>>&& instructions)
- : d_instructions(std::move(instructions))
- {
- // Nothing else
- }
-
- const std::vector<std::unique_ptr<LratInstruction>>& getInstructions() const
- {
- return d_instructions;
- }
-
- void outputAsLfsc(std::ostream& o) const;
-
- private:
- // The instructions in the proof. Each is a deletion or addition.
- std::vector<std::unique_ptr<LratInstruction>> d_instructions;
-};
-
-// Prints the LRAT proof in textual format
-std::ostream& operator<<(std::ostream& o, const LratProof& p);
-std::ostream& operator<<(std::ostream& o, const LratInstruction& i);
-
-} // namespace lrat
-} // namespace proof
-} // namespace CVC4
-
-#endif
diff --git a/src/proof/proof.h b/src/proof/proof.h
deleted file mode 100644
index be5af32db..000000000
--- a/src/proof/proof.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/********************* */
-/*! \file proof.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Tim King, Liana Hadarean, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Proof macros
- **
- ** Proof macros
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__PROOF__PROOF_H
-#define CVC4__PROOF__PROOF_H
-
-#include "options/smt_options.h"
-
-
-/* Do NOT use #ifdef CVC4_PROOF to check if proofs are enabled.
- * We cannot assume users will use -DCVC4_PROOFS if they have a proofs build.
- * The preferred way of checking that proofs are enabled is to use:
- * #if IS_PROOFS_BUILD
- * ...
- * #endif
- *
- * The macro IS_PROOFS_BUILD is defined in base/configuration_private.h
- *
- * This has the effect of forcing that location to have included this header
- * *before* performing this test. This includes C preprocessing expansion.
- * This forces the inclusion of "cvc4_private.h". This is intentional!
- *
- * See bug 688 for more details:
- * https://github.com/CVC4/CVC4/issues/907
- *
- * If you want to check CVC4_PROOF, you should have a very good reason
- * and should list the exceptions here:
- * - Makefile.am
- * - proof/proofs.h
- * - base/configuration_private.h
- */
-
-#ifdef CVC4_PROOF
-# define PROOF(x) if(CVC4::options::proof() || CVC4::options::unsatCores()) { x; }
-# define NULLPROOF(x) (CVC4::options::proof() || CVC4::options::unsatCores()) ? x : NULL
-# define PROOF_ON() (CVC4::options::proof() || CVC4::options::unsatCores())
-# define THEORY_PROOF(x) if(CVC4::options::proof()) { x; }
-# define THEORY_NULLPROOF(x) CVC4::options::proof() ? x : NULL
-# define THEORY_PROOF_ON() CVC4::options::proof()
-#else /* CVC4_PROOF */
-# define PROOF(x)
-# define NULLPROOF(x) NULL
-# define PROOF_ON() false
-# define THEORY_PROOF(x)
-# define THEORY_NULLPROOF(x) NULL
-# define THEORY_PROOF_ON() false
-#endif /* CVC4_PROOF */
-
-#ifdef CVC4_PROOF_STATS /* CVC4_PROOF_STATS */
-# define PSTATS(x) { x; }
-#else
-# define PSTATS(x)
-#endif /* CVC4_PROOF_STATS */
-
-#endif /* CVC4__PROOF__PROOF_H */
diff --git a/src/proof/proof_manager.cpp b/src/proof/proof_manager.cpp
index 99e3010b4..20b0e8a92 100644
--- a/src/proof/proof_manager.cpp
+++ b/src/proof/proof_manager.cpp
@@ -2,10 +2,10 @@
/*! \file proof_manager.cpp
** \verbatim
** Top contributors (to current version):
- ** Guy Katz, Liana Hadarean, Andres Noetzli
+ ** Liana Hadarean, Morgan Deters, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,14 +21,10 @@
#include "context/context.h"
#include "expr/node_visitor.h"
#include "options/bv_options.h"
-#include "options/proof_options.h"
+#include "options/smt_options.h"
#include "proof/clause_id.h"
#include "proof/cnf_proof.h"
-#include "proof/lfsc_proof_printer.h"
-#include "proof/proof_utils.h"
-#include "proof/resolution_bitvector_proof.h"
#include "proof/sat_proof_implementation.h"
-#include "proof/theory_proof.h"
#include "smt/smt_engine.h"
#include "smt/smt_engine_scope.h"
#include "smt/smt_statistics_registry.h"
@@ -39,36 +35,16 @@
#include "theory/uf/theory_uf.h"
#include "theory/valuation.h"
#include "util/hash.h"
-#include "util/proof.h"
namespace CVC4 {
-std::string nodeSetToString(const std::set<Node>& nodes) {
- std::ostringstream os;
- std::set<Node>::const_iterator it;
- for (it = nodes.begin(); it != nodes.end(); ++it) {
- os << *it << " ";
- }
- return os.str();
-}
-
-std::string append(const std::string& str, uint64_t num) {
- std::ostringstream os;
- os << str << num;
- return os.str();
-}
-
-ProofManager::ProofManager(context::Context* context, ProofFormat format)
+ProofManager::ProofManager(context::Context* context)
: d_context(context),
d_satProof(nullptr),
d_cnfProof(nullptr),
- d_theoryProof(nullptr),
- d_inputFormulas(),
d_inputCoreFormulas(context),
d_outputCoreFormulas(context),
d_nextId(0),
- d_fullProof(),
- d_format(format),
d_deps(context)
{
}
@@ -78,19 +54,6 @@ ProofManager::~ProofManager() {}
ProofManager* ProofManager::currentPM() {
return smt::currentProofManager();
}
-const Proof& ProofManager::getProof(SmtEngine* smt)
-{
- if (!currentPM()->d_fullProof)
- {
- Assert(currentPM()->d_format == LFSC);
- currentPM()->d_fullProof.reset(new LFSCProof(
- smt,
- getSatProof(),
- static_cast<LFSCCnfProof*>(getCnfProof()),
- static_cast<LFSCTheoryProofEngine*>(getTheoryProofEngine())));
- }
- return *(currentPM()->d_fullProof);
-}
CoreSatProof* ProofManager::getSatProof()
{
@@ -104,45 +67,8 @@ CnfProof* ProofManager::getCnfProof()
return currentPM()->d_cnfProof.get();
}
-TheoryProofEngine* ProofManager::getTheoryProofEngine()
-{
- Assert(currentPM()->d_theoryProof != NULL);
- return currentPM()->d_theoryProof.get();
-}
-
-UFProof* ProofManager::getUfProof() {
- Assert(options::proof());
- TheoryProof* pf = getTheoryProofEngine()->getTheoryProof(theory::THEORY_UF);
- return (UFProof*)pf;
-}
-
-proof::ResolutionBitVectorProof* ProofManager::getBitVectorProof()
-{
- Assert(options::proof());
- TheoryProof* pf = getTheoryProofEngine()->getTheoryProof(theory::THEORY_BV);
- return static_cast<proof::ResolutionBitVectorProof*>(pf);
-}
-
-ArrayProof* ProofManager::getArrayProof() {
- Assert(options::proof());
- TheoryProof* pf = getTheoryProofEngine()->getTheoryProof(theory::THEORY_ARRAYS);
- return (ArrayProof*)pf;
-}
-
-ArithProof* ProofManager::getArithProof() {
- Assert(options::proof());
- TheoryProof* pf = getTheoryProofEngine()->getTheoryProof(theory::THEORY_ARITH);
- return (ArithProof*)pf;
-}
-
-SkolemizationManager* ProofManager::getSkolemizationManager() {
- Assert(options::proof() || options::unsatCores());
- return &(currentPM()->d_skolemizationManager);
-}
-
void ProofManager::initSatProof(Minisat::Solver* solver)
{
- Assert(d_format == LFSC);
// Destroy old instance before initializing new one to avoid issues with
// registering stats
d_satProof.reset();
@@ -153,168 +79,37 @@ void ProofManager::initCnfProof(prop::CnfStream* cnfStream,
context::Context* ctx)
{
Assert(d_satProof != nullptr);
- Assert(d_format == LFSC);
- d_cnfProof.reset(new LFSCCnfProof(cnfStream, ctx, ""));
+ d_cnfProof.reset(new CnfProof(cnfStream, ctx, ""));
// true and false have to be setup in a special way
Node true_node = NodeManager::currentNM()->mkConst<bool>(true);
Node false_node = NodeManager::currentNM()->mkConst<bool>(false).notNode();
d_cnfProof->pushCurrentAssertion(true_node);
- d_cnfProof->pushCurrentDefinition(true_node);
d_cnfProof->registerConvertedClause(d_satProof->getTrueUnit());
d_cnfProof->popCurrentAssertion();
- d_cnfProof->popCurrentDefinition();
d_cnfProof->pushCurrentAssertion(false_node);
- d_cnfProof->pushCurrentDefinition(false_node);
d_cnfProof->registerConvertedClause(d_satProof->getFalseUnit());
d_cnfProof->popCurrentAssertion();
- d_cnfProof->popCurrentDefinition();
}
-void ProofManager::initTheoryProofEngine()
+void ProofManager::traceDeps(TNode n, CDNodeSet* coreAssertions)
{
- Assert(d_theoryProof == NULL);
- Assert(d_format == LFSC);
- d_theoryProof.reset(new LFSCTheoryProofEngine());
-}
-
-std::string ProofManager::getInputClauseName(ClauseId id,
- const std::string& prefix) {
- return append(prefix+".pb", id);
-}
-
-std::string ProofManager::getLemmaClauseName(ClauseId id,
- const std::string& prefix) {
- return append(prefix+".lemc", id);
-}
-
-std::string ProofManager::getLemmaName(ClauseId id, const std::string& prefix) {
- return append(prefix+"lem", id);
-}
-
-std::string ProofManager::getLearntClauseName(ClauseId id,
- const std::string& prefix) {
- return append(prefix+".cl", id);
-}
-std::string ProofManager::getVarName(prop::SatVariable var,
- const std::string& prefix) {
- return append(prefix+".v", var);
-}
-std::string ProofManager::getAtomName(prop::SatVariable var,
- const std::string& prefix) {
- return append(prefix+".a", var);
-}
-std::string ProofManager::getLitName(prop::SatLiteral lit,
- const std::string& prefix) {
- return append(prefix+".l", lit.toInt());
-}
-
-std::string ProofManager::getPreprocessedAssertionName(Node node,
- const std::string& prefix) {
- if (currentPM()->d_assertionFilters.find(node) != currentPM()->d_assertionFilters.end()) {
- return currentPM()->d_assertionFilters[node];
- }
-
- node = node.getKind() == kind::BITVECTOR_EAGER_ATOM ? node[0] : node;
- return append(prefix+".PA", node.getId());
-}
-std::string ProofManager::getAssertionName(Node node,
- const std::string& prefix) {
- return append(prefix+".A", node.getId());
-}
-std::string ProofManager::getInputFormulaName(const Expr& expr) {
- return currentPM()->d_inputFormulaToName[expr];
-}
-
-std::string ProofManager::getAtomName(TNode atom,
- const std::string& prefix) {
- prop::SatLiteral lit = currentPM()->d_cnfProof->getLiteral(atom);
- Assert(!lit.isNegated());
- return getAtomName(lit.getSatVariable(), prefix);
-}
-
-std::string ProofManager::getLitName(TNode lit,
- const std::string& prefix) {
- std::string litName = getLitName(currentPM()->d_cnfProof->getLiteral(lit), prefix);
- if (currentPM()->d_rewriteFilters.find(litName) != currentPM()->d_rewriteFilters.end()) {
- return currentPM()->d_rewriteFilters[litName];
- }
-
- return litName;
-}
-
-bool ProofManager::hasLitName(TNode lit) {
- return currentPM()->d_cnfProof->hasLiteral(lit);
-}
-
-std::string ProofManager::sanitize(TNode node) {
- Assert(node.isVar() || node.isConst());
-
- std::string name = node.toString();
- if (node.isVar()) {
- std::replace(name.begin(), name.end(), ' ', '_');
- } else if (node.isConst()) {
- name.erase(std::remove(name.begin(), name.end(), '('), name.end());
- name.erase(std::remove(name.begin(), name.end(), ')'), name.end());
- name.erase(std::remove(name.begin(), name.end(), ' '), name.end());
- name = "const" + name;
- }
-
- return name;
-}
-
-void ProofManager::traceDeps(TNode n, ExprSet* coreAssertions) {
- Debug("cores") << "trace deps " << n << std::endl;
- if ((n.isConst() && n == NodeManager::currentNM()->mkConst<bool>(true)) ||
- (n.getKind() == kind::NOT && n[0] == NodeManager::currentNM()->mkConst<bool>(false))) {
- return;
- }
- if(d_inputCoreFormulas.find(n.toExpr()) != d_inputCoreFormulas.end()) {
- // originating formula was in core set
- Debug("cores") << " -- IN INPUT CORE LIST!" << std::endl;
- coreAssertions->insert(n.toExpr());
- } else {
- Debug("cores") << " -- NOT IN INPUT CORE LIST!" << std::endl;
- if(d_deps.find(n) == d_deps.end()) {
- if (options::allowEmptyDependencies()) {
- Debug("cores") << " -- Could not track cause assertion. Failing silently." << std::endl;
- return;
- }
- InternalError()
- << "Cannot trace dependence information back to input assertion:\n`"
- << n << "'";
- }
- Assert(d_deps.find(n) != d_deps.end());
- std::vector<Node> deps = (*d_deps.find(n)).second;
- for(std::vector<Node>::const_iterator i = deps.begin(); i != deps.end(); ++i) {
- Debug("cores") << " + tracing deps: " << n << " -deps-on- " << *i << std::endl;
- if( !(*i).isNull() ){
- traceDeps(*i, coreAssertions);
- }
- }
- }
-}
-
-void ProofManager::traceDeps(TNode n, CDExprSet* coreAssertions) {
Debug("cores") << "trace deps " << n << std::endl;
if ((n.isConst() && n == NodeManager::currentNM()->mkConst<bool>(true)) ||
(n.getKind() == kind::NOT && n[0] == NodeManager::currentNM()->mkConst<bool>(false))) {
return;
}
- if(d_inputCoreFormulas.find(n.toExpr()) != d_inputCoreFormulas.end()) {
+ if (d_inputCoreFormulas.find(n) != d_inputCoreFormulas.end())
+ {
// originating formula was in core set
Debug("cores") << " -- IN INPUT CORE LIST!" << std::endl;
- coreAssertions->insert(n.toExpr());
+ coreAssertions->insert(n);
} else {
Debug("cores") << " -- NOT IN INPUT CORE LIST!" << std::endl;
if(d_deps.find(n) == d_deps.end()) {
- if (options::allowEmptyDependencies()) {
- Debug("cores") << " -- Could not track cause assertion. Failing silently." << std::endl;
- return;
- }
InternalError()
<< "Cannot trace dependence information back to input assertion:\n`"
<< n << "'";
@@ -345,16 +140,11 @@ void ProofManager::traceUnsatCore() {
IdToSatClause::const_iterator it = used_inputs.begin();
for(; it != used_inputs.end(); ++it) {
Node node = d_cnfProof->getAssertionForClause(it->first);
- ProofRule rule = d_cnfProof->getProofRule(node);
- Debug("cores") << "core input assertion " << node << std::endl;
- Debug("cores") << "with proof rule " << rule << std::endl;
- if (rule == RULE_TSEITIN ||
- rule == RULE_GIVEN) {
- // trace dependences back to actual assertions
- // (this adds them to the unsat core)
- traceDeps(node, &d_outputCoreFormulas);
- }
+ Debug("cores") << "core input assertion " << node << "\n";
+ // trace dependences back to actual assertions
+ // (this adds them to the unsat core)
+ traceDeps(node, &d_outputCoreFormulas);
}
}
@@ -362,8 +152,9 @@ bool ProofManager::unsatCoreAvailable() const {
return d_satProof->derivedEmptyClause();
}
-std::vector<Expr> ProofManager::extractUnsatCore() {
- std::vector<Expr> result;
+std::vector<Node> ProofManager::extractUnsatCore()
+{
+ std::vector<Node> result;
output_core_iterator it = begin_unsat_core();
output_core_iterator end = end_unsat_core();
while ( it != end ) {
@@ -373,155 +164,38 @@ std::vector<Expr> ProofManager::extractUnsatCore() {
return result;
}
-void ProofManager::constructSatProof() {
- if (!d_satProof->proofConstructed()) {
+void ProofManager::constructSatProof()
+{
+ if (!d_satProof->proofConstructed())
+ {
d_satProof->constructProof();
}
}
-void ProofManager::getLemmasInUnsatCore(theory::TheoryId theory, std::vector<Node> &lemmas) {
- Assert(PROOF_ON()) << "Cannot compute unsat core when proofs are off";
- Assert(unsatCoreAvailable())
- << "Cannot get unsat core at this time. Mabye the input is SAT?";
-
- constructSatProof();
-
- IdToSatClause used_lemmas;
- IdToSatClause used_inputs;
- d_satProof->collectClausesUsed(used_inputs, used_lemmas);
-
- IdToSatClause::const_iterator it;
- std::set<Node> seen;
-
- Debug("pf::lemmasUnsatCore") << "Dumping all lemmas in unsat core" << std::endl;
- for (it = used_lemmas.begin(); it != used_lemmas.end(); ++it) {
- std::set<Node> lemma = satClauseToNodeSet(it->second);
- Debug("pf::lemmasUnsatCore") << nodeSetToString(lemma);
-
- // TODO: we should be able to drop the "haveProofRecipe" check.
- // however, there are some rewrite issues with the arith solver, resulting
- // in non-registered recipes. For now we assume no one is requesting arith lemmas.
- LemmaProofRecipe recipe;
- if (!getCnfProof()->haveProofRecipe(lemma)) {
- Debug("pf::lemmasUnsatCore") << "\t[no recipe]" << std::endl;
- continue;
- }
-
- recipe = getCnfProof()->getProofRecipe(lemma);
- Debug("pf::lemmasUnsatCore") << "\t[owner = " << recipe.getTheory()
- << ", original = " << recipe.getOriginalLemma() << "]" << std::endl;
- if (recipe.simpleLemma() && recipe.getTheory() == theory && seen.find(recipe.getOriginalLemma()) == seen.end()) {
- lemmas.push_back(recipe.getOriginalLemma());
- seen.insert(recipe.getOriginalLemma());
- }
- }
-}
-
-std::set<Node> ProofManager::satClauseToNodeSet(prop::SatClause* clause) {
- std::set<Node> result;
- for (unsigned i = 0; i < clause->size(); ++i) {
- prop::SatLiteral lit = (*clause)[i];
- Node node = getCnfProof()->getAtom(lit.getSatVariable());
- Expr atom = node.toExpr();
- if (atom != utils::mkTrue())
- result.insert(lit.isNegated() ? node.notNode() : node);
- }
-
- return result;
-}
-
-Node ProofManager::getWeakestImplicantInUnsatCore(Node lemma) {
- Assert(PROOF_ON()) << "Cannot compute unsat core when proofs are off";
+void ProofManager::getLemmasInUnsatCore(std::vector<Node>& lemmas)
+{
+ Assert(options::unsatCores())
+ << "Cannot compute unsat core when proofs are off";
Assert(unsatCoreAvailable())
<< "Cannot get unsat core at this time. Mabye the input is SAT?";
-
- // If we're doing aggressive minimization, work on all lemmas, not just conjunctions.
- if (!options::aggressiveCoreMin() && (lemma.getKind() != kind::AND))
- return lemma;
-
constructSatProof();
-
- NodeBuilder<> builder(kind::AND);
-
IdToSatClause used_lemmas;
IdToSatClause used_inputs;
d_satProof->collectClausesUsed(used_inputs, used_lemmas);
-
+ Debug("pf::lemmasUnsatCore") << "Retrieving all lemmas in unsat core\n";
IdToSatClause::const_iterator it;
- std::set<Node>::iterator lemmaIt;
-
- if (!options::aggressiveCoreMin()) {
- for (it = used_lemmas.begin(); it != used_lemmas.end(); ++it) {
- std::set<Node> currentLemma = satClauseToNodeSet(it->second);
-
- // TODO: we should be able to drop the "haveProofRecipe" check.
- // however, there are some rewrite issues with the arith solver, resulting
- // in non-registered recipes. For now we assume no one is requesting arith lemmas.
- LemmaProofRecipe recipe;
- if (!getCnfProof()->haveProofRecipe(currentLemma))
- continue;
-
- recipe = getCnfProof()->getProofRecipe(currentLemma);
- if (recipe.getOriginalLemma() == lemma) {
- for (lemmaIt = currentLemma.begin(); lemmaIt != currentLemma.end(); ++lemmaIt) {
- builder << *lemmaIt;
-
- // Check that each conjunct appears in the original lemma.
- bool found = false;
- for (unsigned i = 0; i < lemma.getNumChildren(); ++i) {
- if (lemma[i] == *lemmaIt)
- found = true;
- }
-
- if (!found)
- return lemma;
- }
- }
- }
- } else {
- // Aggressive mode
- for (it = used_lemmas.begin(); it != used_lemmas.end(); ++it) {
- std::set<Node> currentLemma = satClauseToNodeSet(it->second);
-
- // TODO: we should be able to drop the "haveProofRecipe" check.
- // however, there are some rewrite issues with the arith solver, resulting
- // in non-registered recipes. For now we assume no one is requesting arith lemmas.
- LemmaProofRecipe recipe;
- if (!getCnfProof()->haveProofRecipe(currentLemma))
- continue;
-
- recipe = getCnfProof()->getProofRecipe(currentLemma);
- if (recipe.getOriginalLemma() == lemma) {
- NodeBuilder<> disjunction(kind::OR);
- for (lemmaIt = currentLemma.begin(); lemmaIt != currentLemma.end(); ++lemmaIt) {
- disjunction << *lemmaIt;
- }
-
- Node conjunct = (disjunction.getNumChildren() == 1) ? disjunction[0] : disjunction;
- builder << conjunct;
- }
- }
+ for (it = used_lemmas.begin(); it != used_lemmas.end(); ++it)
+ {
+ Node lemma = d_cnfProof->getAssertionForClause(it->first);
+ Debug("pf::lemmasUnsatCore") << "Retrieved lemma " << lemma << "\n";
+ lemmas.push_back(lemma);
}
-
- AlwaysAssert(builder.getNumChildren() != 0);
-
- if (builder.getNumChildren() == 1)
- return builder[0];
-
- return builder;
-}
-
-void ProofManager::addAssertion(Expr formula) {
- Debug("proof:pm") << "assert: " << formula << std::endl;
- d_inputFormulas.insert(formula);
- std::ostringstream name;
- name << "A" << d_inputFormulaToName.size();
- d_inputFormulaToName[formula] = name.str();
}
-void ProofManager::addCoreAssertion(Expr formula) {
+void ProofManager::addCoreAssertion(Node formula)
+{
Debug("cores") << "assert: " << formula << std::endl;
- d_deps[Node::fromExpr(formula)]; // empty vector of deps
+ d_deps[formula]; // empty vector of deps
d_inputCoreFormulas.insert(formula);
}
@@ -537,670 +211,10 @@ void ProofManager::addDependence(TNode n, TNode dep) {
}
}
-void ProofManager::addUnsatCore(Expr formula) {
+void ProofManager::addUnsatCore(Node formula)
+{
Assert(d_inputCoreFormulas.find(formula) != d_inputCoreFormulas.end());
d_outputCoreFormulas.insert(formula);
}
-void ProofManager::addAssertionFilter(const Node& node, const std::string& rewritten) {
- d_assertionFilters[node] = rewritten;
-}
-
-void ProofManager::setLogic(const LogicInfo& logic) {
- d_logic = logic;
-}
-
-LFSCProof::LFSCProof(SmtEngine* smtEngine,
- CoreSatProof* sat,
- LFSCCnfProof* cnf,
- LFSCTheoryProofEngine* theory)
- : d_satProof(sat),
- d_cnfProof(cnf),
- d_theoryProof(theory),
- d_smtEngine(smtEngine)
-{}
-
-void LFSCProof::toStream(std::ostream& out, const ProofLetMap& map) const
-{
- Unreachable();
-}
-
-void collectAtoms(TNode node, std::set<Node>& seen, CnfProof* cnfProof)
-{
- Debug("pf::pm::atoms") << "collectAtoms: Colleting atoms from " << node
- << "\n";
- if (seen.find(node) != seen.end())
- {
- Debug("pf::pm::atoms") << "collectAtoms:\t already seen\n";
- return;
- }
- // if I have a SAT literal for a node, save it, unless this node is a
- // negation, in which case its underlying will be collected downstream
- if (cnfProof->hasLiteral(node) && node.getKind() != kind::NOT)
- {
- Debug("pf::pm::atoms") << "collectAtoms: has SAT literal, save\n";
- seen.insert(node);
- }
- for (unsigned i = 0; i < node.getNumChildren(); ++i)
- {
- Debug("pf::pm::atoms") << push;
- collectAtoms(node[i], seen, cnfProof);
- Debug("pf::pm::atoms") << pop;
- }
-}
-
-void LFSCProof::toStream(std::ostream& out) const
-{
- TimerStat::CodeTimer proofProductionTimer(
- ProofManager::currentPM()->getStats().d_proofProductionTime);
-
- IdToSatClause used_lemmas;
- IdToSatClause used_inputs;
- std::set<Node> atoms;
- NodePairSet rewrites;
- NodeSet used_assertions;
-
- {
- CodeTimer skeletonProofTimer{
- ProofManager::currentPM()->getStats().d_skeletonProofTraceTime};
- Assert(!d_satProof->proofConstructed());
-
- // Here we give our SAT solver a chance to flesh out the resolution proof.
- // It proves bottom from a set of clauses.
- d_satProof->constructProof();
-
- // We ask the SAT solver which clauses are used in that proof.
- // For a resolution proof, these are the leaves of the tree.
- d_satProof->collectClausesUsed(used_inputs, used_lemmas);
-
- IdToSatClause::iterator it2;
- Debug("pf::pm") << std::endl << "Used inputs: " << std::endl;
- for (it2 = used_inputs.begin(); it2 != used_inputs.end(); ++it2)
- {
- Debug("pf::pm") << "\t input = " << *(it2->second) << std::endl;
- }
- Debug("pf::pm") << std::endl;
-
- Debug("pf::pm") << std::endl << "Used lemmas: " << std::endl;
- for (it2 = used_lemmas.begin(); it2 != used_lemmas.end(); ++it2)
- {
- std::vector<Expr> clause_expr;
- for (unsigned i = 0; i < it2->second->size(); ++i)
- {
- prop::SatLiteral lit = (*(it2->second))[i];
- Expr atom = d_cnfProof->getAtom(lit.getSatVariable()).toExpr();
- if (atom.isConst())
- {
- Assert(atom == utils::mkTrue());
- continue;
- }
- Expr expr_lit = lit.isNegated() ? atom.notExpr() : atom;
- clause_expr.push_back(expr_lit);
- }
-
- Debug("pf::pm") << "\t lemma " << it2->first << " = " << *(it2->second)
- << std::endl;
- Debug("pf::pm") << "\t";
- for (unsigned i = 0; i < clause_expr.size(); ++i)
- {
- Debug("pf::pm") << clause_expr[i] << " ";
- }
- Debug("pf::pm") << std::endl;
- }
- Debug("pf::pm") << std::endl;
-
- // collecting assertions that lead to the clauses being asserted
- d_cnfProof->collectAssertionsForClauses(used_inputs, used_assertions);
-
- NodeSet::iterator it3;
- Debug("pf::pm") << std::endl << "Used assertions: " << std::endl;
- for (it3 = used_assertions.begin(); it3 != used_assertions.end(); ++it3)
- Debug("pf::pm") << "\t assertion = " << *it3 << std::endl;
-
- // collects the atoms in the clauses
- d_cnfProof->collectAtomsAndRewritesForLemmas(used_lemmas, atoms, rewrites);
-
- if (!rewrites.empty())
- {
- Debug("pf::pm") << std::endl << "Rewrites used in lemmas: " << std::endl;
- NodePairSet::const_iterator rewriteIt;
- for (rewriteIt = rewrites.begin(); rewriteIt != rewrites.end();
- ++rewriteIt)
- {
- Debug("pf::pm") << "\t" << rewriteIt->first << " --> "
- << rewriteIt->second << std::endl;
- }
- Debug("pf::pm") << std::endl << "Rewrite printing done" << std::endl;
- }
- else
- {
- Debug("pf::pm") << "No rewrites in lemmas found" << std::endl;
- }
-
- // The derived/unrewritten atoms may not have CNF literals required later
- // on. If they don't, add them.
- std::set<Node>::const_iterator it;
- for (it = atoms.begin(); it != atoms.end(); ++it)
- {
- Debug("pf::pm") << "Ensure literal for atom: " << *it << std::endl;
- if (!d_cnfProof->hasLiteral(*it))
- {
- // For arithmetic: these literals are not normalized, causing an error
- // in Arith.
- if (theory::Theory::theoryOf(*it) == theory::THEORY_ARITH)
- {
- d_cnfProof->ensureLiteral(
- *it,
- true); // This disables preregistration with the theory solver.
- }
- else
- {
- d_cnfProof->ensureLiteral(
- *it); // Normal method, with theory solver preregisteration.
- }
- }
- }
-
- // From the clauses, compute the atoms (atomic theory predicates in
- // assertions and lemmas).
- d_cnfProof->collectAtomsForClauses(used_inputs, atoms);
- d_cnfProof->collectAtomsForClauses(used_lemmas, atoms);
-
- // collects the atoms in the assertions
- Debug("pf::pm") << std::endl
- << "LFSCProof::toStream: Colleting atoms from assertions "
- << used_assertions << "\n"
- << push;
- for (TNode used_assertion : used_assertions)
- {
- collectAtoms(used_assertion, atoms, d_cnfProof);
- }
- Debug("pf::pm") << pop;
-
- std::set<Node>::iterator atomIt;
- Debug("pf::pm") << std::endl
- << "Dumping atoms from lemmas, inputs and assertions: "
- << std::endl
- << std::endl;
- for (atomIt = atoms.begin(); atomIt != atoms.end(); ++atomIt)
- {
- Debug("pf::pm") << "\tAtom: " << *atomIt << std::endl;
- }
- }
-
- smt::SmtScope scope(d_smtEngine);
- ProofLetMap globalLetMap;
- std::ostringstream paren;
- {
- CodeTimer declTimer{
- ProofManager::currentPM()->getStats().d_proofDeclarationsTime};
- out << "(check\n";
- paren << ")";
- out << " ;; Declarations\n";
-
- // declare the theory atoms
- Debug("pf::pm") << "LFSCProof::toStream: registering terms:" << std::endl;
- for (std::set<Node>::const_iterator it = atoms.begin(); it != atoms.end(); ++it)
- {
- Debug("pf::pm") << "\tTerm: " << (*it).toExpr() << std::endl;
- d_theoryProof->registerTerm((*it).toExpr());
- }
-
- Debug("pf::pm") << std::endl
- << "Term registration done!" << std::endl
- << std::endl;
-
- Debug("pf::pm") << std::endl
- << "LFSCProof::toStream: starting to print assertions"
- << std::endl;
-
- // print out all the original assertions
- d_theoryProof->registerTermsFromAssertions();
- d_theoryProof->printSortDeclarations(out, paren);
- d_theoryProof->printTermDeclarations(out, paren);
- d_theoryProof->printAssertions(out, paren);
-
- Debug("pf::pm") << std::endl
- << "LFSCProof::toStream: print assertions DONE"
- << std::endl;
-
- out << "(: (holds cln)\n\n";
- paren << ")";
-
- // Have the theory proofs print deferred declarations, e.g. for skolem
- // variables.
- out << " ;; Printing deferred declarations \n\n";
- d_theoryProof->printDeferredDeclarations(out, paren);
-
- out << "\n ;; Printing the global let map";
- d_theoryProof->finalizeBvConflicts(used_lemmas, out);
- ProofManager::getBitVectorProof()->calculateAtomsInBitblastingProof();
- if (options::lfscLetification())
- {
- ProofManager::currentPM()->printGlobalLetMap(
- atoms, globalLetMap, out, paren);
- }
-
- out << " ;; Printing aliasing declarations \n\n";
- d_theoryProof->printAliasingDeclarations(out, paren, globalLetMap);
-
- out << " ;; Rewrites for Lemmas \n";
- d_theoryProof->printLemmaRewrites(rewrites, out, paren);
-
- // print trust that input assertions are their preprocessed form
- printPreprocessedAssertions(used_assertions, out, paren, globalLetMap);
- }
-
- {
- CodeTimer cnfProofTimer{
- ProofManager::currentPM()->getStats().d_cnfProofTime};
- // print mapping between theory atoms and internal SAT variables
- out << ";; Printing mapping from preprocessed assertions into atoms \n";
- d_cnfProof->printAtomMapping(atoms, out, paren, globalLetMap);
-
- Debug("pf::pm") << std::endl
- << "Printing cnf proof for clauses" << std::endl;
-
- IdToSatClause::const_iterator cl_it = used_inputs.begin();
- // print CNF conversion proof for each clause
- for (; cl_it != used_inputs.end(); ++cl_it)
- {
- d_cnfProof->printCnfProofForClause(
- cl_it->first, cl_it->second, out, paren);
- }
- }
-
- {
- CodeTimer theoryLemmaTimer{
- ProofManager::currentPM()->getStats().d_theoryLemmaTime};
- Debug("pf::pm") << std::endl
- << "Printing cnf proof for clauses DONE" << std::endl;
-
- Debug("pf::pm") << "Proof manager: printing theory lemmas" << std::endl;
- d_theoryProof->printTheoryLemmas(used_lemmas, out, paren, globalLetMap);
- Debug("pf::pm") << "Proof manager: printing theory lemmas DONE!"
- << std::endl;
- }
-
- {
- CodeTimer finalProofTimer{
- ProofManager::currentPM()->getStats().d_finalProofTime};
- out << ";; Printing final unsat proof \n";
- if (options::bitblastMode() == options::BitblastMode::EAGER
- && ProofManager::getBitVectorProof())
- {
- ProofManager::getBitVectorProof()->printEmptyClauseProof(out, paren);
- }
- else
- {
- // print actual resolution proof
- proof::LFSCProofPrinter::printResolutions(d_satProof, out, paren);
- proof::LFSCProofPrinter::printResolutionEmptyClause(
- d_satProof, out, paren);
- }
- }
-
- out << paren.str();
- out << "\n;;\n";
-}
-
-void LFSCProof::printPreprocessedAssertions(const NodeSet& assertions,
- std::ostream& os,
- std::ostream& paren,
- ProofLetMap& globalLetMap) const
-{
- os << "\n ;; In the preprocessor we trust \n";
- NodeSet::const_iterator it = assertions.begin();
- NodeSet::const_iterator end = assertions.end();
-
- Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions starting" << std::endl;
-
- if (options::fewerPreprocessingHoles()) {
- // Check for assertions that did not get rewritten, and update the printing filter.
- checkUnrewrittenAssertion(assertions);
-
- // For the remaining assertions, bind them to input assertions.
- for (; it != end; ++it) {
- // Rewrite preprocessing step if it cannot be eliminated
- if (!ProofManager::currentPM()->have_input_assertion((*it).toExpr())) {
- os << "(th_let_pf _ (trust_f (iff ";
-
- Expr inputAssertion;
-
- if (((*it).isConst() && *it == NodeManager::currentNM()->mkConst<bool>(true)) ||
- ((*it).getKind() == kind::NOT && (*it)[0] == NodeManager::currentNM()->mkConst<bool>(false))) {
- inputAssertion = NodeManager::currentNM()->mkConst<bool>(true).toExpr();
- } else {
- // Figure out which input assertion led to this assertion
- ExprSet inputAssertions;
- ProofManager::currentPM()->traceDeps(*it, &inputAssertions);
-
- Debug("pf::pm") << "Original assertions for " << *it << " are: " << std::endl;
-
- ProofManager::assertions_iterator assertionIt;
- for (assertionIt = inputAssertions.begin(); assertionIt != inputAssertions.end(); ++assertionIt) {
- Debug("pf::pm") << "\t" << *assertionIt << std::endl;
- }
-
- if (inputAssertions.size() == 0) {
- Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions: Count NOT find the assertion that caused this PA. Picking an arbitrary one..." << std::endl;
- // For now just use the first assertion...
- inputAssertion = *(ProofManager::currentPM()->begin_assertions());
- } else {
- if (inputAssertions.size() != 1) {
- Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions: Attention: more than one original assertion was found. Picking just one." << std::endl;
- }
- inputAssertion = *inputAssertions.begin();
- }
- }
-
- if (!ProofManager::currentPM()->have_input_assertion(inputAssertion)) {
- // The thing returned by traceDeps does not appear in the input assertions...
- Debug("pf::pm") << "LFSCProof::printPreprocessedAssertions: Count NOT find the assertion that caused this PA. Picking an arbitrary one..." << std::endl;
- // For now just use the first assertion...
- inputAssertion = *(ProofManager::currentPM()->begin_assertions());
- }
-
- Debug("pf::pm") << "Original assertion for " << *it
- << " is: "
- << inputAssertion
- << ", AKA "
- << ProofManager::currentPM()->getInputFormulaName(inputAssertion)
- << std::endl;
-
- ProofManager::currentPM()->getTheoryProofEngine()->printTheoryTerm(inputAssertion, os, globalLetMap);
- os << " ";
- ProofManager::currentPM()->printTrustedTerm(*it, os, globalLetMap);
- os << "))";
- os << "(\\ "<< ProofManager::getPreprocessedAssertionName(*it, "") << "\n";
- paren << "))";
-
- std::ostringstream rewritten;
-
- rewritten << "(or_elim_1 _ _ ";
- rewritten << "(not_not_intro _ ";
- rewritten << ProofManager::currentPM()->getInputFormulaName(inputAssertion);
- rewritten << ") (iff_elim_1 _ _ ";
- rewritten << ProofManager::getPreprocessedAssertionName(*it, "");
- rewritten << "))";
-
- ProofManager::currentPM()->addAssertionFilter(*it, rewritten.str());
- }
- }
- } else {
- for (; it != end; ++it) {
- os << "(th_let_pf _ ";
-
- //TODO
- os << "(trust_f ";
- ProofManager::currentPM()->printTrustedTerm(*it, os, globalLetMap);
- os << ") ";
-
- os << "(\\ "<< ProofManager::getPreprocessedAssertionName(*it, "") << "\n";
- paren << "))";
- }
- }
-
- os << "\n";
-}
-
-void LFSCProof::checkUnrewrittenAssertion(const NodeSet& rewrites) const
-{
- Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion starting" << std::endl;
-
- NodeSet::const_iterator rewrite;
- for (rewrite = rewrites.begin(); rewrite != rewrites.end(); ++rewrite) {
- Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion: handling " << *rewrite << std::endl;
- if (ProofManager::currentPM()->have_input_assertion((*rewrite).toExpr())) {
- Assert(
- ProofManager::currentPM()->have_input_assertion((*rewrite).toExpr()));
- Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion: this assertion was NOT rewritten!" << std::endl
- << "\tAdding filter: "
- << ProofManager::getPreprocessedAssertionName(*rewrite, "")
- << " --> "
- << ProofManager::currentPM()->getInputFormulaName((*rewrite).toExpr())
- << std::endl;
- ProofManager::currentPM()->addAssertionFilter(*rewrite,
- ProofManager::currentPM()->getInputFormulaName((*rewrite).toExpr()));
- } else {
- Debug("pf::pm") << "LFSCProof::checkUnrewrittenAssertion: this assertion WAS rewritten! " << *rewrite << std::endl;
- }
- }
-}
-
-//---from Morgan---
-
-bool ProofManager::hasOp(TNode n) const {
- return d_bops.find(n) != d_bops.end();
-}
-
-Node ProofManager::lookupOp(TNode n) const {
- std::map<Node, Node>::const_iterator i = d_bops.find(n);
- Assert(i != d_bops.end());
- return (*i).second;
-}
-
-Node ProofManager::mkOp(TNode n) {
- Trace("mgd-pm-mkop") << "MkOp : " << n << " " << n.getKind() << std::endl;
- if(n.getKind() != kind::BUILTIN) {
- return n;
- }
-
- Node& op = d_ops[n];
- if(op.isNull()) {
- Assert((n.getConst<Kind>() == kind::SELECT)
- || (n.getConst<Kind>() == kind::STORE));
-
- Debug("mgd-pm-mkop") << "making an op for " << n << "\n";
-
- std::stringstream ss;
- ss << n;
- std::string s = ss.str();
- Debug("mgd-pm-mkop") << " : " << s << std::endl;
- std::vector<TypeNode> v;
- v.push_back(NodeManager::currentNM()->integerType());
- if(n.getConst<Kind>() == kind::SELECT) {
- v.push_back(NodeManager::currentNM()->integerType());
- v.push_back(NodeManager::currentNM()->integerType());
- } else if(n.getConst<Kind>() == kind::STORE) {
- v.push_back(NodeManager::currentNM()->integerType());
- v.push_back(NodeManager::currentNM()->integerType());
- v.push_back(NodeManager::currentNM()->integerType());
- }
- TypeNode type = NodeManager::currentNM()->mkFunctionType(v);
- Debug("mgd-pm-mkop") << "typenode is: " << type << "\n";
- op = NodeManager::currentNM()->mkSkolem(s, type, " ignore", NodeManager::SKOLEM_NO_NOTIFY);
- d_bops[op] = n;
- }
- Debug("mgd-pm-mkop") << "returning the op: " << op << "\n";
- return op;
-}
-//---end from Morgan---
-
-bool ProofManager::wasPrinted(const Type& type) const {
- return d_printedTypes.find(type) != d_printedTypes.end();
-}
-
-void ProofManager::markPrinted(const Type& type) {
- d_printedTypes.insert(type);
-}
-
-void ProofManager::addRewriteFilter(const std::string &original, const std::string &substitute) {
- d_rewriteFilters[original] = substitute;
-}
-
-bool ProofManager::haveRewriteFilter(TNode lit) {
- std::string litName = getLitName(currentPM()->d_cnfProof->getLiteral(lit));
- return d_rewriteFilters.find(litName) != d_rewriteFilters.end();
-}
-
-void ProofManager::clearRewriteFilters() {
- d_rewriteFilters.clear();
-}
-
-std::ostream& operator<<(std::ostream& out, CVC4::ProofRule k) {
- switch(k) {
- case RULE_GIVEN:
- out << "RULE_GIVEN";
- break;
- case RULE_DERIVED:
- out << "RULE_DERIVED";
- break;
- case RULE_RECONSTRUCT:
- out << "RULE_RECONSTRUCT";
- break;
- case RULE_TRUST:
- out << "RULE_TRUST";
- break;
- case RULE_INVALID:
- out << "RULE_INVALID";
- break;
- case RULE_CONFLICT:
- out << "RULE_CONFLICT";
- break;
- case RULE_TSEITIN:
- out << "RULE_TSEITIN";
- break;
- case RULE_SPLIT:
- out << "RULE_SPLIT";
- break;
- case RULE_ARRAYS_EXT:
- out << "RULE_ARRAYS";
- break;
- case RULE_ARRAYS_ROW:
- out << "RULE_ARRAYS";
- break;
- default:
- out << "ProofRule Unknown! [" << unsigned(k) << "]";
- }
-
- return out;
-}
-
-void ProofManager::registerRewrite(unsigned ruleId, Node original, Node result){
- Assert(currentPM()->d_theoryProof != NULL);
- currentPM()->d_rewriteLog.push_back(RewriteLogEntry(ruleId, original, result));
-}
-
-void ProofManager::clearRewriteLog() {
- Assert(currentPM()->d_theoryProof != NULL);
- currentPM()->d_rewriteLog.clear();
-}
-
-std::vector<RewriteLogEntry> ProofManager::getRewriteLog() {
- return currentPM()->d_rewriteLog;
-}
-
-void ProofManager::dumpRewriteLog() const {
- Debug("pf::rr") << "Dumpign rewrite log:" << std::endl;
-
- for (unsigned i = 0; i < d_rewriteLog.size(); ++i) {
- Debug("pf::rr") << "\tRule " << d_rewriteLog[i].getRuleId()
- << ": "
- << d_rewriteLog[i].getOriginal()
- << " --> "
- << d_rewriteLog[i].getResult() << std::endl;
- }
-}
-
-void bind(Expr term, ProofLetMap& map, Bindings& letOrder) {
- ProofLetMap::iterator it = map.find(term);
- if (it != map.end())
- return;
-
- for (unsigned i = 0; i < term.getNumChildren(); ++i)
- bind(term[i], map, letOrder);
-
- // Special case: chain operators. If we have and(a,b,c), it will be prineted as and(a,and(b,c)).
- // The subterm and(b,c) may repeat elsewhere, so we need to bind it, too.
- Kind k = term.getKind();
- if (((k == kind::OR) || (k == kind::AND)) && term.getNumChildren() > 2) {
- Node currentExpression = term[term.getNumChildren() - 1];
- for (int i = term.getNumChildren() - 2; i >= 0; --i) {
- NodeBuilder<> builder(k);
- builder << term[i];
- builder << currentExpression.toExpr();
- currentExpression = builder;
- bind(currentExpression.toExpr(), map, letOrder);
- }
- } else {
- unsigned newId = ProofLetCount::newId();
- ProofLetCount letCount(newId);
- map[term] = letCount;
- letOrder.push_back(LetOrderElement(term, newId));
- }
-}
-
-void ProofManager::printGlobalLetMap(std::set<Node>& atoms,
- ProofLetMap& letMap,
- std::ostream& out,
- std::ostringstream& paren) {
- Bindings letOrder;
- std::set<Node>::const_iterator atom;
- for (atom = atoms.begin(); atom != atoms.end(); ++atom) {
- bind(atom->toExpr(), letMap, letOrder);
- }
-
- // TODO: give each theory a chance to add atoms. For now, just query BV directly...
- const std::set<Node>* additionalAtoms = ProofManager::getBitVectorProof()->getAtomsInBitblastingProof();
- for (atom = additionalAtoms->begin(); atom != additionalAtoms->end(); ++atom) {
- bind(atom->toExpr(), letMap, letOrder);
- }
-
- for (unsigned i = 0; i < letOrder.size(); ++i) {
- Expr currentExpr = letOrder[i].expr;
- unsigned letId = letOrder[i].id;
- ProofLetMap::iterator it = letMap.find(currentExpr);
- Assert(it != letMap.end());
- out << "\n(@ let" << letId << " ";
- d_theoryProof->printBoundTerm(currentExpr, out, letMap);
- paren << ")";
- it->second.increment();
- }
-
- out << std::endl << std::endl;
-}
-
-void ProofManager::ensureLiteral(Node node) {
- d_cnfProof->ensureLiteral(node);
-}
-void ProofManager::printTrustedTerm(Node term,
- std::ostream& os,
- ProofLetMap& globalLetMap)
-{
- TheoryProofEngine* tpe = ProofManager::currentPM()->getTheoryProofEngine();
- if (tpe->printsAsBool(term)) os << "(p_app ";
- tpe->printTheoryTerm(term.toExpr(), os, globalLetMap);
- if (tpe->printsAsBool(term)) os << ")";
-}
-
-ProofManager::ProofManagerStatistics::ProofManagerStatistics()
- : d_proofProductionTime("proof::ProofManager::proofProductionTime"),
- d_theoryLemmaTime(
- "proof::ProofManager::proofProduction::theoryLemmaTime"),
- d_skeletonProofTraceTime(
- "proof::ProofManager::proofProduction::skeletonProofTraceTime"),
- d_proofDeclarationsTime(
- "proof::ProofManager::proofProduction::proofDeclarationsTime"),
- d_cnfProofTime("proof::ProofManager::proofProduction::cnfProofTime"),
- d_finalProofTime("proof::ProofManager::proofProduction::finalProofTime")
-{
- smtStatisticsRegistry()->registerStat(&d_proofProductionTime);
- smtStatisticsRegistry()->registerStat(&d_theoryLemmaTime);
- smtStatisticsRegistry()->registerStat(&d_skeletonProofTraceTime);
- smtStatisticsRegistry()->registerStat(&d_proofDeclarationsTime);
- smtStatisticsRegistry()->registerStat(&d_cnfProofTime);
- smtStatisticsRegistry()->registerStat(&d_finalProofTime);
-}
-
-ProofManager::ProofManagerStatistics::~ProofManagerStatistics()
-{
- smtStatisticsRegistry()->unregisterStat(&d_proofProductionTime);
- smtStatisticsRegistry()->unregisterStat(&d_theoryLemmaTime);
- smtStatisticsRegistry()->unregisterStat(&d_skeletonProofTraceTime);
- smtStatisticsRegistry()->unregisterStat(&d_proofDeclarationsTime);
- smtStatisticsRegistry()->unregisterStat(&d_cnfProofTime);
- smtStatisticsRegistry()->unregisterStat(&d_finalProofTime);
-}
-
} /* CVC4 namespace */
diff --git a/src/proof/proof_manager.h b/src/proof/proof_manager.h
index 45bde4dcb..7276f6402 100644
--- a/src/proof/proof_manager.h
+++ b/src/proof/proof_manager.h
@@ -2,10 +2,10 @@
/*! \file proof_manager.h
** \verbatim
** Top contributors (to current version):
- ** Liana Hadarean, Guy Katz, Andres Noetzli
+ ** Liana Hadarean, Guy Katz, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -28,59 +28,27 @@
#include "context/cdhashset.h"
#include "expr/node.h"
#include "proof/clause_id.h"
-#include "proof/proof.h"
-#include "proof/proof_utils.h"
-#include "proof/skolemization_manager.h"
-#include "theory/logic_info.h"
-#include "theory/substitutions.h"
-#include "util/proof.h"
#include "util/statistics_registry.h"
namespace CVC4 {
-class SmtGlobals;
-
// forward declarations
namespace Minisat {
class Solver;
}/* Minisat namespace */
-namespace BVMinisat {
- class Solver;
-}/* BVMinisat namespace */
-
namespace prop {
class CnfStream;
}/* CVC4::prop namespace */
class SmtEngine;
-const ClauseId ClauseIdEmpty(-1);
-const ClauseId ClauseIdUndef(-2);
-const ClauseId ClauseIdError(-3);
-
template <class Solver> class TSatProof;
typedef TSatProof< CVC4::Minisat::Solver> CoreSatProof;
class CnfProof;
-class RewriterProof;
-class TheoryProofEngine;
-class TheoryProof;
-class UFProof;
-class ArithProof;
-class ArrayProof;
-
-namespace proof {
-class ResolutionBitVectorProof;
-}
-
-template <class Solver> class LFSCSatProof;
-typedef TSatProof<CVC4::Minisat::Solver> CoreSatProof;
-class LFSCCnfProof;
-class LFSCTheoryProofEngine;
-class LFSCUFProof;
-class LFSCRewriterProof;
+typedef TSatProof<CVC4::Minisat::Solver> CoreSatProof;
namespace prop {
typedef uint64_t SatVariable;
@@ -88,291 +56,72 @@ namespace prop {
typedef std::vector<SatLiteral> SatClause;
}/* CVC4::prop namespace */
-// different proof modes
-enum ProofFormat {
- LFSC,
- NATIVE
-};/* enum ProofFormat */
-
-std::string append(const std::string& str, uint64_t num);
-
typedef std::unordered_map<ClauseId, prop::SatClause*> IdToSatClause;
-typedef context::CDHashSet<Expr, ExprHashFunction> CDExprSet;
-typedef std::unordered_map<Node, std::vector<Node>, NodeHashFunction> NodeToNodes;
+typedef context::CDHashSet<Node, NodeHashFunction> CDNodeSet;
typedef context::CDHashMap<Node, std::vector<Node>, NodeHashFunction> CDNodeToNodes;
typedef std::unordered_set<ClauseId> IdHashSet;
-enum ProofRule {
- RULE_GIVEN, /* input assertion */
- RULE_DERIVED, /* a "macro" rule */
- RULE_RECONSTRUCT, /* prove equivalence using another method */
- RULE_TRUST, /* trust without evidence (escape hatch until proofs are fully supported) */
- RULE_INVALID, /* assert-fail if this is ever needed in proof; use e.g. for split lemmas */
- RULE_CONFLICT, /* re-construct as a conflict */
- RULE_TSEITIN, /* Tseitin CNF transformation */
- RULE_SPLIT, /* A splitting lemma of the form a v ~ a*/
-
- RULE_ARRAYS_EXT, /* arrays, extensional */
- RULE_ARRAYS_ROW, /* arrays, read-over-write */
-};/* enum ProofRules */
-
-class RewriteLogEntry {
-public:
- RewriteLogEntry(unsigned ruleId, Node original, Node result)
- : d_ruleId(ruleId), d_original(original), d_result(result) {
- }
-
- unsigned getRuleId() const {
- return d_ruleId;
- }
-
- Node getOriginal() const {
- return d_original;
- }
-
- Node getResult() const {
- return d_result;
- }
-
-private:
- unsigned d_ruleId;
- Node d_original;
- Node d_result;
-};
-
class ProofManager {
context::Context* d_context;
std::unique_ptr<CoreSatProof> d_satProof;
std::unique_ptr<CnfProof> d_cnfProof;
- std::unique_ptr<TheoryProofEngine> d_theoryProof;
// information that will need to be shared across proofs
- ExprSet d_inputFormulas;
- std::map<Expr, std::string> d_inputFormulaToName;
- CDExprSet d_inputCoreFormulas;
- CDExprSet d_outputCoreFormulas;
-
- SkolemizationManager d_skolemizationManager;
+ CDNodeSet d_inputCoreFormulas;
+ CDNodeSet d_outputCoreFormulas;
int d_nextId;
- std::unique_ptr<Proof> d_fullProof;
- ProofFormat d_format; // used for now only in debug builds
-
CDNodeToNodes d_deps;
- std::set<Type> d_printedTypes;
-
- std::map<std::string, std::string> d_rewriteFilters;
- std::map<Node, std::string> d_assertionFilters;
-
- std::vector<RewriteLogEntry> d_rewriteLog;
-
-protected:
- LogicInfo d_logic;
-
public:
- ProofManager(context::Context* context, ProofFormat format = LFSC);
- ~ProofManager();
-
- static ProofManager* currentPM();
-
- // initialization
- void initSatProof(Minisat::Solver* solver);
- void initCnfProof(CVC4::prop::CnfStream* cnfStream, context::Context* ctx);
- void initTheoryProofEngine();
-
- // getting various proofs
- static const Proof& getProof(SmtEngine* smt);
- static CoreSatProof* getSatProof();
- static CnfProof* getCnfProof();
- static TheoryProofEngine* getTheoryProofEngine();
- static TheoryProof* getTheoryProof( theory::TheoryId id );
- static UFProof* getUfProof();
- static proof::ResolutionBitVectorProof* getBitVectorProof();
- static ArrayProof* getArrayProof();
- static ArithProof* getArithProof();
-
- static SkolemizationManager *getSkolemizationManager();
-
- // iterators over data shared by proofs
- typedef ExprSet::const_iterator assertions_iterator;
-
- // iterate over the assertions (these are arbitrary boolean formulas)
- assertions_iterator begin_assertions() const {
- return d_inputFormulas.begin();
- }
- assertions_iterator end_assertions() const { return d_inputFormulas.end(); }
- size_t num_assertions() const { return d_inputFormulas.size(); }
- bool have_input_assertion(const Expr& assertion) {
- return d_inputFormulas.find(assertion) != d_inputFormulas.end();
- }
-
- void ensureLiteral(Node node);
-
-//---from Morgan---
- Node mkOp(TNode n);
- Node lookupOp(TNode n) const;
- bool hasOp(TNode n) const;
-
- std::map<Node, Node> d_ops;
- std::map<Node, Node> d_bops;
-//---end from Morgan---
-
-
- // variable prefixes
- static std::string getInputClauseName(ClauseId id, const std::string& prefix = "");
- static std::string getLemmaClauseName(ClauseId id, const std::string& prefix = "");
- static std::string getLemmaName(ClauseId id, const std::string& prefix = "");
- static std::string getLearntClauseName(ClauseId id, const std::string& prefix = "");
- static std::string getPreprocessedAssertionName(Node node, const std::string& prefix = "");
- static std::string getAssertionName(Node node, const std::string& prefix = "");
- static std::string getInputFormulaName(const Expr& expr);
-
- static std::string getVarName(prop::SatVariable var, const std::string& prefix = "");
- static std::string getAtomName(prop::SatVariable var, const std::string& prefix = "");
- static std::string getAtomName(TNode atom, const std::string& prefix = "");
- static std::string getLitName(prop::SatLiteral lit, const std::string& prefix = "");
- static std::string getLitName(TNode lit, const std::string& prefix = "");
- static bool hasLitName(TNode lit);
-
- // for SMT variable names that have spaces and other things
- static std::string sanitize(TNode var);
-
- // wrap term with (p_app ... ) if the term is printed as a boolean, and print
- // used for "trust" assertions
- static void printTrustedTerm(Node term,
- std::ostream& os,
- ProofLetMap& globalLetMap);
-
- /** Add proof assertion - unlike addCoreAssertion this is post definition expansion **/
- void addAssertion(Expr formula);
-
- /** Public unsat core methods **/
- void addCoreAssertion(Expr formula);
-
- void addDependence(TNode n, TNode dep);
- void addUnsatCore(Expr formula);
-
- // trace dependences back to unsat core
- void traceDeps(TNode n, ExprSet* coreAssertions);
- void traceDeps(TNode n, CDExprSet* coreAssertions);
- void traceUnsatCore();
-
- typedef CDExprSet::const_iterator output_core_iterator;
-
- output_core_iterator begin_unsat_core() const { return d_outputCoreFormulas.begin(); }
- output_core_iterator end_unsat_core() const { return d_outputCoreFormulas.end(); }
- size_t size_unsat_core() const { return d_outputCoreFormulas.size(); }
- std::vector<Expr> extractUnsatCore();
-
- bool unsatCoreAvailable() const;
- void getLemmasInUnsatCore(theory::TheoryId theory, std::vector<Node> &lemmas);
- Node getWeakestImplicantInUnsatCore(Node lemma);
-
- int nextId() { return d_nextId++; }
-
- void setLogic(const LogicInfo& logic);
- const std::string getLogic() const { return d_logic.getLogicString(); }
- LogicInfo & getLogicInfo() { return d_logic; }
-
- void markPrinted(const Type& type);
- bool wasPrinted(const Type& type) const;
-
- void addRewriteFilter(const std::string &original, const std::string &substitute);
- void clearRewriteFilters();
- bool haveRewriteFilter(TNode lit);
-
- void addAssertionFilter(const Node& node, const std::string& rewritten);
-
- static void registerRewrite(unsigned ruleId, Node original, Node result);
- static void clearRewriteLog();
-
- std::vector<RewriteLogEntry> getRewriteLog();
- void dumpRewriteLog() const;
+ ProofManager(context::Context* context);
+ ~ProofManager();
- void printGlobalLetMap(std::set<Node>& atoms,
- ProofLetMap& letMap,
- std::ostream& out,
- std::ostringstream& paren);
-
- struct ProofManagerStatistics
- {
- ProofManagerStatistics();
- ~ProofManagerStatistics();
+ static ProofManager* currentPM();
- /**
- * Time spent producing proofs (i.e. generating the proof from the logging
- * information)
- */
- TimerStat d_proofProductionTime;
+ // initialization
+ void initSatProof(Minisat::Solver* solver);
+ void initCnfProof(CVC4::prop::CnfStream* cnfStream, context::Context* ctx);
- /**
- * Time spent printing proofs of theory lemmas
- */
- TimerStat d_theoryLemmaTime;
+ // getting various proofs
+ static CoreSatProof* getSatProof();
+ static CnfProof* getCnfProof();
- /**
- * Time spent tracing the proof of the boolean skeleton
- * (e.g. figuring out which assertions are needed, etc.)
- */
- TimerStat d_skeletonProofTraceTime;
+ /** Public unsat core methods **/
+ void addCoreAssertion(Node formula);
- /**
- * Time spent processing and printing declarations in the proof
- */
- TimerStat d_proofDeclarationsTime;
+ void addDependence(TNode n, TNode dep);
+ void addUnsatCore(Node formula);
- /**
- * Time spent printing the CNF proof
- */
- TimerStat d_cnfProofTime;
+ // trace dependences back to unsat core
+ void traceDeps(TNode n, CDNodeSet* coreAssertions);
+ void traceUnsatCore();
- /**
- * Time spent printing the final proof of UNSAT
- */
- TimerStat d_finalProofTime;
+ typedef CDNodeSet::const_iterator output_core_iterator;
- }; /* struct ProofManagerStatistics */
+ output_core_iterator begin_unsat_core() const
+ {
+ return d_outputCoreFormulas.begin();
+ }
+ output_core_iterator end_unsat_core() const
+ {
+ return d_outputCoreFormulas.end();
+ }
+ size_t size_unsat_core() const { return d_outputCoreFormulas.size(); }
+ std::vector<Node> extractUnsatCore();
- ProofManagerStatistics& getStats() { return d_stats; }
+ bool unsatCoreAvailable() const;
+ void getLemmasInUnsatCore(std::vector<Node>& lemmas);
- private:
- void constructSatProof();
- std::set<Node> satClauseToNodeSet(prop::SatClause* clause);
+ int nextId() { return d_nextId++; }
- ProofManagerStatistics d_stats;
+private:
+ void constructSatProof();
};/* class ProofManager */
-class LFSCProof : public Proof
-{
- public:
- LFSCProof(SmtEngine* smtEngine,
- CoreSatProof* sat,
- LFSCCnfProof* cnf,
- LFSCTheoryProofEngine* theory);
- ~LFSCProof() override {}
- void toStream(std::ostream& out) const override;
- void toStream(std::ostream& out, const ProofLetMap& map) const override;
-
- private:
- // FIXME: hack until we get preprocessing
- void printPreprocessedAssertions(const NodeSet& assertions,
- std::ostream& os,
- std::ostream& paren,
- ProofLetMap& globalLetMap) const;
-
- void checkUnrewrittenAssertion(const NodeSet& assertions) const;
-
- CoreSatProof* d_satProof;
- LFSCCnfProof* d_cnfProof;
- LFSCTheoryProofEngine* d_theoryProof;
- SmtEngine* d_smtEngine;
-}; /* class LFSCProof */
-
-std::ostream& operator<<(std::ostream& out, CVC4::ProofRule k);
}/* CVC4 namespace */
diff --git a/src/proof/proof_output_channel.cpp b/src/proof/proof_output_channel.cpp
deleted file mode 100644
index 1e6e759e3..000000000
--- a/src/proof/proof_output_channel.cpp
+++ /dev/null
@@ -1,100 +0,0 @@
-/********************* */
-/*! \file proof_output_channel.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Guy Katz, Tim King, Liana Hadarean
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** [[ Add lengthier description here ]]
-
- ** \todo document this file
-
-**/
-
-#include "proof/proof_output_channel.h"
-
-#include "base/check.h"
-#include "theory/term_registration_visitor.h"
-#include "theory/valuation.h"
-
-namespace CVC4 {
-
-ProofOutputChannel::ProofOutputChannel() : d_conflict(), d_proof(nullptr) {}
-const Proof& ProofOutputChannel::getConflictProof() const
-{
- Assert(hasConflict());
- return *d_proof;
-}
-
-void ProofOutputChannel::conflict(TNode n, std::unique_ptr<Proof> pf)
-{
- Trace("pf::tp") << "ProofOutputChannel: CONFLICT: " << n << std::endl;
- Assert(!hasConflict());
- Assert(!d_proof);
- d_conflict = n;
- d_proof = std::move(pf);
- Assert(hasConflict());
- Assert(d_proof);
-}
-
-bool ProofOutputChannel::propagate(TNode x) {
- Trace("pf::tp") << "ProofOutputChannel: got a propagation: " << x
- << std::endl;
- d_propagations.insert(x);
- return true;
-}
-
-theory::LemmaStatus ProofOutputChannel::lemma(TNode n, ProofRule rule, bool,
- bool, bool) {
- Trace("pf::tp") << "ProofOutputChannel: new lemma: " << n << std::endl;
- // TODO(#1231): We should transition to supporting multiple lemmas. The
- // following assertion cannot be enabled due to
- // "test/regress/regress0/arrays/swap_t1_np_nf_ai_00005_007.cvc.smt".
- // Assert(
- // d_lemma.isNull()) <<
- // "Multiple calls to ProofOutputChannel::lemma() are not supported.";
- d_lemma = n;
- return theory::LemmaStatus(TNode::null(), 0);
-}
-
-theory::LemmaStatus ProofOutputChannel::splitLemma(TNode, bool) {
- AlwaysAssert(false);
- return theory::LemmaStatus(TNode::null(), 0);
-}
-
-void ProofOutputChannel::requirePhase(TNode n, bool b) {
- Debug("pf::tp") << "ProofOutputChannel::requirePhase called" << std::endl;
- Trace("pf::tp") << "requirePhase " << n << " " << b << std::endl;
-}
-
-void ProofOutputChannel::setIncomplete() {
- Debug("pf::tp") << "ProofOutputChannel::setIncomplete called" << std::endl;
- AlwaysAssert(false);
-}
-
-
-MyPreRegisterVisitor::MyPreRegisterVisitor(theory::Theory* theory)
- : d_theory(theory)
- , d_visited() {
-}
-
-bool MyPreRegisterVisitor::alreadyVisited(TNode current, TNode parent) {
- return d_visited.find(current) != d_visited.end();
-}
-
-void MyPreRegisterVisitor::visit(TNode current, TNode parent) {
- d_theory->preRegisterTerm(current);
- d_visited.insert(current);
-}
-
-void MyPreRegisterVisitor::start(TNode node) {
-}
-
-void MyPreRegisterVisitor::done(TNode node) {
-}
-
-} /* namespace CVC4 */
diff --git a/src/proof/proof_output_channel.h b/src/proof/proof_output_channel.h
deleted file mode 100644
index 6a91bad7c..000000000
--- a/src/proof/proof_output_channel.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/********************* */
-/*! \file proof_output_channel.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Tim King, Guy Katz, Liana Hadarean
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__PROOF_OUTPUT_CHANNEL_H
-#define CVC4__PROOF_OUTPUT_CHANNEL_H
-
-#include <memory>
-#include <set>
-#include <unordered_set>
-
-#include "expr/node.h"
-#include "theory/output_channel.h"
-#include "theory/theory.h"
-#include "util/proof.h"
-
-namespace CVC4 {
-
-class ProofOutputChannel : public theory::OutputChannel {
- public:
- ProofOutputChannel();
- ~ProofOutputChannel() override {}
-
- /**
- * This may be called at most once per ProofOutputChannel.
- * Requires that `n` and `pf` are non-null.
- */
- void conflict(TNode n, std::unique_ptr<Proof> pf) override;
- bool propagate(TNode x) override;
- theory::LemmaStatus lemma(TNode n, ProofRule rule, bool, bool, bool) override;
- theory::LemmaStatus splitLemma(TNode, bool) override;
- void requirePhase(TNode n, bool b) override;
- void setIncomplete() override;
-
- /** Has conflict() has been called? */
- bool hasConflict() const { return !d_conflict.isNull(); }
-
- /**
- * Returns the proof passed into the conflict() call.
- * Requires hasConflict() to hold.
- */
- const Proof& getConflictProof() const;
- Node getLastLemma() const { return d_lemma; }
-
- private:
- Node d_conflict;
- std::unique_ptr<Proof> d_proof;
- Node d_lemma;
- std::set<Node> d_propagations;
-}; /* class ProofOutputChannel */
-
-class MyPreRegisterVisitor {
- theory::Theory* d_theory;
- std::unordered_set<TNode, TNodeHashFunction> d_visited;
-public:
- typedef void return_type;
- MyPreRegisterVisitor(theory::Theory* theory);
- bool alreadyVisited(TNode current, TNode parent);
- void visit(TNode current, TNode parent);
- void start(TNode node);
- void done(TNode node);
-}; /* class MyPreRegisterVisitor */
-
-} /* CVC4 namespace */
-
-#endif /* CVC4__PROOF_OUTPUT_CHANNEL_H */
diff --git a/src/proof/proof_utils.cpp b/src/proof/proof_utils.cpp
deleted file mode 100644
index cad56db6a..000000000
--- a/src/proof/proof_utils.cpp
+++ /dev/null
@@ -1,126 +0,0 @@
-/********************* */
-/*! \file proof_utils.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Liana Hadarean, Andrew Reynolds, Guy Katz
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** [[ Add lengthier description here ]]
-
- ** \todo document this file
-
-**/
-
-#include "proof/proof_utils.h"
-#include "theory/theory.h"
-
-namespace CVC4 {
-namespace utils {
-
-std::string toLFSCKind(Kind kind) {
- switch(kind) {
- // core kinds
- case kind::OR : return "or";
- case kind::AND: return "and";
- case kind::XOR: return "xor";
- case kind::EQUAL: return "=";
- case kind::IMPLIES: return "impl";
- case kind::NOT: return "not";
-
- // bit-vector kinds
- case kind::BITVECTOR_AND :
- return "bvand";
- case kind::BITVECTOR_OR :
- return "bvor";
- case kind::BITVECTOR_XOR :
- return "bvxor";
- case kind::BITVECTOR_NAND :
- return "bvnand";
- case kind::BITVECTOR_NOR :
- return "bvnor";
- case kind::BITVECTOR_XNOR :
- return "bvxnor";
- case kind::BITVECTOR_COMP :
- return "bvcomp";
- case kind::BITVECTOR_MULT :
- return "bvmul";
- case kind::BITVECTOR_PLUS :
- return "bvadd";
- case kind::BITVECTOR_SUB :
- return "bvsub";
- case kind::BITVECTOR_UDIV :
- case kind::BITVECTOR_UDIV_TOTAL :
- return "bvudiv";
- case kind::BITVECTOR_UREM :
- case kind::BITVECTOR_UREM_TOTAL :
- return "bvurem";
- case kind::BITVECTOR_SDIV :
- return "bvsdiv";
- case kind::BITVECTOR_SREM :
- return "bvsrem";
- case kind::BITVECTOR_SMOD :
- return "bvsmod";
- case kind::BITVECTOR_SHL :
- return "bvshl";
- case kind::BITVECTOR_LSHR :
- return "bvlshr";
- case kind::BITVECTOR_ASHR :
- return "bvashr";
- case kind::BITVECTOR_CONCAT :
- return "concat";
- case kind::BITVECTOR_NEG :
- return "bvneg";
- case kind::BITVECTOR_NOT :
- return "bvnot";
- case kind::BITVECTOR_ROTATE_LEFT :
- return "rotate_left";
- case kind::BITVECTOR_ROTATE_RIGHT :
- return "rotate_right";
- case kind::BITVECTOR_ULT :
- return "bvult";
- case kind::BITVECTOR_ULE :
- return "bvule";
- case kind::BITVECTOR_UGT :
- return "bvugt";
- case kind::BITVECTOR_UGE :
- return "bvuge";
- case kind::BITVECTOR_SLT :
- return "bvslt";
- case kind::BITVECTOR_SLE :
- return "bvsle";
- case kind::BITVECTOR_SGT :
- return "bvsgt";
- case kind::BITVECTOR_SGE :
- return "bvsge";
- case kind::BITVECTOR_EXTRACT :
- return "extract";
- case kind::BITVECTOR_REPEAT :
- return "repeat";
- case kind::BITVECTOR_ZERO_EXTEND :
- return "zero_extend";
- case kind::BITVECTOR_SIGN_EXTEND :
- return "sign_extend";
- default:
- Unreachable();
- }
-}
-
-std::string toLFSCKindTerm(Expr node) {
- Kind k = node.getKind();
- if( k==kind::EQUAL ){
- if( node[0].getType().isBoolean() ){
- return "iff";
- }else{
- return "=";
- }
- }else{
- return toLFSCKind( k );
- }
-}
-
-} /* namespace CVC4::utils */
-} /* namespace CVC4 */
diff --git a/src/proof/proof_utils.h b/src/proof/proof_utils.h
deleted file mode 100644
index e54edd8b7..000000000
--- a/src/proof/proof_utils.h
+++ /dev/null
@@ -1,229 +0,0 @@
-/********************* */
-/*! \file proof_utils.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Liana Hadarean, Guy Katz, Dejan Jovanovic
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** [[ Add lengthier description here ]]
-
- ** \todo document this file
-
-**/
-
-#include "cvc4_private.h"
-
-#pragma once
-
-#include <set>
-#include <sstream>
-#include <unordered_set>
-#include <vector>
-
-#include "expr/node_manager.h"
-
-namespace CVC4 {
-
-typedef std::unordered_set<Expr, ExprHashFunction> ExprSet;
-typedef std::unordered_set<Node, NodeHashFunction> NodeSet;
-
-typedef std::pair<Node, Node> NodePair;
-typedef std::set<NodePair> NodePairSet;
-
-
-class ProofLetCount {
-public:
- static unsigned counter;
- static void resetCounter() { counter = 0; }
- static unsigned newId() { return ++counter; }
-
- unsigned count;
- unsigned id;
- ProofLetCount()
- : count(0)
- , id(-1)
- {}
-
- void increment() { ++count; }
- ProofLetCount(unsigned i)
- : count(1)
- , id(i)
- {}
-
- ProofLetCount(const ProofLetCount& other)
- : count(other.count)
- , id (other.id)
- {}
-
- bool operator==(const ProofLetCount &other) const {
- return other.id == id && other.count == count;
- }
-
- ProofLetCount& operator=(const ProofLetCount &rhs) {
- if (&rhs == this) return *this;
- id = rhs.id;
- count = rhs.count;
- return *this;
- }
-};
-
-struct LetOrderElement {
- Expr expr;
- unsigned id;
- LetOrderElement(Expr e, unsigned i)
- : expr(e)
- , id(i)
- {}
-
- LetOrderElement()
- : expr()
- , id(-1)
- {}
-};
-
-typedef std::vector<LetOrderElement> Bindings;
-
-namespace utils {
-
-std::string toLFSCKind(Kind kind);
-std::string toLFSCKindTerm(Expr node);
-
-inline unsigned getExtractHigh(Expr node) {
- return node.getOperator().getConst<BitVectorExtract>().d_high;
-}
-
-inline unsigned getExtractLow(Expr node) {
- return node.getOperator().getConst<BitVectorExtract>().d_low;
-}
-
-inline unsigned getSize(Type type) {
- BitVectorType bv(type);
- return bv.getSize();
-}
-
-
-inline unsigned getSize(Expr node) {
- Assert(node.getType().isBitVector());
- return getSize(node.getType());
-}
-
-inline Expr mkTrue() {
- return NodeManager::currentNM()->toExprManager()->mkConst<bool>(true);
-}
-
-inline Expr mkFalse() {
- return NodeManager::currentNM()->toExprManager()->mkConst<bool>(false);
-}
-
-inline Expr mkExpr(Kind k , Expr expr) {
- return NodeManager::currentNM()->toExprManager()->mkExpr(k, expr);
-}
-inline Expr mkExpr(Kind k , Expr e1, Expr e2) {
- return NodeManager::currentNM()->toExprManager()->mkExpr(k, e1, e2);
-}
-inline Expr mkExpr(Kind k , std::vector<Expr>& children) {
- return NodeManager::currentNM()->toExprManager()->mkExpr(k, children);
-}
-
-
-inline Expr mkOnes(unsigned size) {
- BitVector val = BitVector::mkOnes(size);
- return NodeManager::currentNM()->toExprManager()->mkConst<BitVector>(val);
-}
-
-inline Expr mkConst(unsigned size, unsigned int value) {
- BitVector val(size, value);
- return NodeManager::currentNM()->toExprManager()->mkConst<BitVector>(val);
-}
-
-inline Expr mkConst(const BitVector& value) {
- return NodeManager::currentNM()->toExprManager()->mkConst<BitVector>(value);
-}
-
-inline Expr mkOr(const std::vector<Expr>& nodes) {
- std::set<Expr> all;
- all.insert(nodes.begin(), nodes.end());
- Assert(all.size() != 0);
-
- if (all.size() == 1) {
- // All the same, or just one
- return nodes[0];
- }
-
-
- NodeBuilder<> disjunction(kind::OR);
- std::set<Expr>::const_iterator it = all.begin();
- std::set<Expr>::const_iterator it_end = all.end();
- while (it != it_end) {
- disjunction << Node::fromExpr(*it);
- ++ it;
- }
-
- Node res = disjunction;
- return res.toExpr();
-}/* mkOr() */
-
-
-inline Expr mkAnd(const std::vector<Expr>& conjunctions) {
- std::set<Expr> all;
- all.insert(conjunctions.begin(), conjunctions.end());
-
- if (all.size() == 0) {
- return mkTrue();
- }
-
- if (all.size() == 1) {
- // All the same, or just one
- return conjunctions[0];
- }
-
-
- NodeBuilder<> conjunction(kind::AND);
- std::set<Expr>::const_iterator it = all.begin();
- std::set<Expr>::const_iterator it_end = all.end();
- while (it != it_end) {
- conjunction << Node::fromExpr(*it);
- ++ it;
- }
-
- Node res = conjunction;
- return res.toExpr();
-}/* mkAnd() */
-
-inline Expr mkSortedExpr(Kind kind, const std::vector<Expr>& children) {
- std::set<Expr> all;
- all.insert(children.begin(), children.end());
-
- if (all.size() == 0) {
- return mkTrue();
- }
-
- if (all.size() == 1) {
- // All the same, or just one
- return children[0];
- }
-
-
- NodeBuilder<> res(kind);
- std::set<Expr>::const_iterator it = all.begin();
- std::set<Expr>::const_iterator it_end = all.end();
- while (it != it_end) {
- res << Node::fromExpr(*it);
- ++ it;
- }
-
- return ((Node)res).toExpr();
-}/* mkSortedNode() */
-
-inline const bool getBit(Expr expr, unsigned i) {
- Assert(i < utils::getSize(expr) && expr.isConst());
- Integer bit = expr.getConst<BitVector>().extract(i, i).getValue();
- return (bit == 1u);
-}
-
-}
-}
diff --git a/src/proof/resolution_bitvector_proof.cpp b/src/proof/resolution_bitvector_proof.cpp
deleted file mode 100644
index d48789f71..000000000
--- a/src/proof/resolution_bitvector_proof.cpp
+++ /dev/null
@@ -1,523 +0,0 @@
-/********************* */
-/*! \file resolution_bitvector_proof.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Alex Ozdemir, Liana Hadarean, Guy Katz
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** [[ Add lengthier description here ]]
-
- ** \todo document this file
-
-**/
-
-#include "proof/resolution_bitvector_proof.h"
-#include "options/bv_options.h"
-#include "options/proof_options.h"
-#include "proof/array_proof.h"
-#include "proof/bitvector_proof.h"
-#include "proof/clause_id.h"
-#include "proof/lfsc_proof_printer.h"
-#include "proof/proof_output_channel.h"
-#include "proof/proof_utils.h"
-#include "proof/sat_proof_implementation.h"
-#include "prop/bvminisat/bvminisat.h"
-#include "prop/sat_solver_types.h"
-#include "theory/bv/bitblast/bitblaster.h"
-#include "theory/bv/theory_bv.h"
-#include "theory/bv/theory_bv_rewrite_rules.h"
-
-#include <iostream>
-#include <sstream>
-
-using namespace CVC4::theory;
-using namespace CVC4::theory::bv;
-
-namespace CVC4 {
-
-namespace proof {
-
-ResolutionBitVectorProof::ResolutionBitVectorProof(
- theory::bv::TheoryBV* bv, TheoryProofEngine* proofEngine)
- : BitVectorProof(bv, proofEngine),
- d_resolutionProof(),
- d_isAssumptionConflict(false)
-{
-}
-
-void ResolutionBitVectorProof::initSatProof(CVC4::BVMinisat::Solver* solver)
-{
- Assert(d_resolutionProof == NULL);
- d_resolutionProof.reset(new BVSatProof(solver, &d_fakeContext, "bb", true));
-}
-
-void ResolutionBitVectorProof::initCnfProof(prop::CnfStream* cnfStream,
- context::Context* cnf,
- prop::SatVariable trueVar,
- prop::SatVariable falseVar)
-{
- Assert(d_resolutionProof != NULL);
- Assert(d_cnfProof == nullptr);
- d_cnfProof.reset(new LFSCCnfProof(cnfStream, cnf, "bb"));
-
- d_cnfProof->registerTrueUnitClause(d_resolutionProof->getTrueUnit());
- d_cnfProof->registerFalseUnitClause(d_resolutionProof->getFalseUnit());
-}
-
-void ResolutionBitVectorProof::attachToSatSolver(prop::SatSolver& sat_solver)
-{
- sat_solver.setResolutionProofLog(this);
-}
-
-BVSatProof* ResolutionBitVectorProof::getSatProof()
-{
- Assert(d_resolutionProof != NULL);
- return d_resolutionProof.get();
-}
-
-void ResolutionBitVectorProof::startBVConflict(
- CVC4::BVMinisat::Solver::TCRef cr)
-{
- d_resolutionProof->startResChain(cr);
-}
-
-void ResolutionBitVectorProof::startBVConflict(
- CVC4::BVMinisat::Solver::TLit lit)
-{
- d_resolutionProof->startResChain(lit);
-}
-
-void ResolutionBitVectorProof::endBVConflict(
- const CVC4::BVMinisat::Solver::TLitVec& confl)
-{
- Debug("pf::bv") << "ResolutionBitVectorProof::endBVConflict called"
- << std::endl;
-
- std::vector<Expr> expr_confl;
- for (int i = 0; i < confl.size(); ++i)
- {
- prop::SatLiteral lit = prop::BVMinisatSatSolver::toSatLiteral(confl[i]);
- Expr atom = d_cnfProof->getAtom(lit.getSatVariable()).toExpr();
- Expr expr_lit = lit.isNegated() ? atom.notExpr() : atom;
- expr_confl.push_back(expr_lit);
- }
-
- Expr conflict = utils::mkSortedExpr(kind::OR, expr_confl);
- Debug("pf::bv") << "Make conflict for " << conflict << std::endl;
-
- if (d_bbConflictMap.find(conflict) != d_bbConflictMap.end())
- {
- Debug("pf::bv") << "Abort...already conflict for " << conflict << std::endl;
- // This can only happen when we have eager explanations in the bv solver
- // if we don't get to propagate p before ~p is already asserted
- d_resolutionProof->cancelResChain();
- return;
- }
-
- // we don't need to check for uniqueness in the sat solver then
- ClauseId clause_id = d_resolutionProof->registerAssumptionConflict(confl);
- d_bbConflictMap[conflict] = clause_id;
- d_resolutionProof->endResChain(clause_id);
- Debug("pf::bv") << "ResolutionBitVectorProof::endBVConflict id" << clause_id
- << " => " << conflict << "\n";
- d_isAssumptionConflict = false;
-}
-
-void ResolutionBitVectorProof::finalizeConflicts(std::vector<Expr>& conflicts)
-{
- if (options::bitblastMode() == options::BitblastMode::EAGER)
- {
- Debug("pf::bv") << "Construct full proof." << std::endl;
- d_resolutionProof->constructProof();
- return;
- }
-
- for (unsigned i = 0; i < conflicts.size(); ++i)
- {
- Expr confl = conflicts[i];
- Debug("pf::bv") << "Finalize conflict #" << i << ": " << confl << std::endl;
-
- // Special case: if the conflict has a (true) or a (not false) in it, it is
- // trivial...
- bool ignoreConflict = false;
- if ((confl.isConst() && confl.getConst<bool>())
- || (confl.getKind() == kind::NOT && confl[0].isConst()
- && !confl[0].getConst<bool>()))
- {
- ignoreConflict = true;
- }
- else if (confl.getKind() == kind::OR)
- {
- for (unsigned k = 0; k < confl.getNumChildren(); ++k)
- {
- if ((confl[k].isConst() && confl[k].getConst<bool>())
- || (confl[k].getKind() == kind::NOT && confl[k][0].isConst()
- && !confl[k][0].getConst<bool>()))
- {
- ignoreConflict = true;
- }
- }
- }
- if (ignoreConflict)
- {
- Debug("pf::bv") << "Ignoring conflict due to (true) or (not false)"
- << std::endl;
- continue;
- }
-
- if (d_bbConflictMap.find(confl) != d_bbConflictMap.end())
- {
- ClauseId id = d_bbConflictMap[confl];
- d_resolutionProof->collectClauses(id);
- }
- else
- {
- // There is no exact match for our conflict, but maybe it is a subset of
- // another conflict
- ExprToClauseId::const_iterator it;
- bool matchFound = false;
- for (it = d_bbConflictMap.begin(); it != d_bbConflictMap.end(); ++it)
- {
- Expr possibleMatch = it->first;
- if (possibleMatch.getKind() != kind::OR)
- {
- // This is a single-node conflict. If this node is in the conflict
- // we're trying to prove, we have a match.
- for (unsigned k = 0; k < confl.getNumChildren(); ++k)
- {
- if (confl[k] == possibleMatch)
- {
- matchFound = true;
- d_resolutionProof->collectClauses(it->second);
- break;
- }
- }
- }
- else
- {
- if (possibleMatch.getNumChildren() > confl.getNumChildren()) continue;
-
- unsigned k = 0;
- bool matching = true;
- for (unsigned j = 0; j < possibleMatch.getNumChildren(); ++j)
- {
- // j is the index in possibleMatch
- // k is the index in confl
- while (k < confl.getNumChildren() && confl[k] != possibleMatch[j])
- {
- ++k;
- }
- if (k == confl.getNumChildren())
- {
- // We couldn't find a match for possibleMatch[j], so not a match
- matching = false;
- break;
- }
- }
-
- if (matching)
- {
- Debug("pf::bv")
- << "Collecting info from a sub-conflict" << std::endl;
- d_resolutionProof->collectClauses(it->second);
- matchFound = true;
- break;
- }
- }
- }
-
- if (!matchFound)
- {
- Debug("pf::bv") << "Do not collect clauses for " << confl << std::endl
- << "Dumping existing conflicts:" << std::endl;
-
- i = 0;
- for (it = d_bbConflictMap.begin(); it != d_bbConflictMap.end(); ++it)
- {
- ++i;
- Debug("pf::bv") << "\tConflict #" << i << ": " << it->first
- << std::endl;
- }
-
- Unreachable();
- }
- }
- }
-}
-
-void LfscResolutionBitVectorProof::printTheoryLemmaProof(
- std::vector<Expr>& lemma,
- std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& map)
-{
- Debug("pf::bv")
- << "(pf::bv) LfscResolutionBitVectorProof::printTheoryLemmaProof called"
- << std::endl;
- Expr conflict = utils::mkSortedExpr(kind::OR, lemma);
- Debug("pf::bv") << "\tconflict = " << conflict << std::endl;
-
- if (d_bbConflictMap.find(conflict) != d_bbConflictMap.end())
- {
- std::ostringstream lemma_paren;
- for (unsigned i = 0; i < lemma.size(); ++i)
- {
- Expr lit = lemma[i];
-
- if (lit.getKind() == kind::NOT)
- {
- os << "(intro_assump_t _ _ _ ";
- }
- else
- {
- os << "(intro_assump_f _ _ _ ";
- }
- lemma_paren << ")";
- // print corresponding literal in main sat solver
- ProofManager* pm = ProofManager::currentPM();
- CnfProof* cnf = pm->getCnfProof();
- prop::SatLiteral main_lit = cnf->getLiteral(lit);
- os << pm->getLitName(main_lit);
- os << " ";
- // print corresponding literal in bv sat solver
- prop::SatVariable bb_var = d_cnfProof->getLiteral(lit).getSatVariable();
- os << pm->getAtomName(bb_var, "bb");
- os << "(\\ unit" << bb_var << "\n";
- lemma_paren << ")";
- }
- Expr lem = utils::mkOr(lemma);
- Assert(d_bbConflictMap.find(lem) != d_bbConflictMap.end());
- ClauseId lemma_id = d_bbConflictMap[lem];
- proof::LFSCProofPrinter::printAssumptionsResolution(
- d_resolutionProof.get(), lemma_id, os, lemma_paren);
- os << lemma_paren.str();
- }
- else
- {
- Debug("pf::bv") << "Found a non-recorded conflict. Looking for a matching "
- "sub-conflict..."
- << std::endl;
-
- bool matching;
-
- ExprToClauseId::const_iterator it;
- unsigned i = 0;
- for (it = d_bbConflictMap.begin(); it != d_bbConflictMap.end(); ++it)
- {
- // Our conflict is sorted, and the records are also sorted.
- ++i;
- Expr possibleMatch = it->first;
-
- if (possibleMatch.getKind() != kind::OR)
- {
- // This is a single-node conflict. If this node is in the conflict we're
- // trying to prove, we have a match.
- matching = false;
-
- for (unsigned k = 0; k < conflict.getNumChildren(); ++k)
- {
- if (conflict[k] == possibleMatch)
- {
- matching = true;
- break;
- }
- }
- }
- else
- {
- if (possibleMatch.getNumChildren() > conflict.getNumChildren())
- continue;
-
- unsigned k = 0;
-
- matching = true;
- for (unsigned j = 0; j < possibleMatch.getNumChildren(); ++j)
- {
- // j is the index in possibleMatch
- // k is the index in conflict
- while (k < conflict.getNumChildren()
- && conflict[k] != possibleMatch[j])
- {
- ++k;
- }
- if (k == conflict.getNumChildren())
- {
- // We couldn't find a match for possibleMatch[j], so not a match
- matching = false;
- break;
- }
- }
- }
-
- if (matching)
- {
- Debug("pf::bv") << "Found a match with conflict #" << i << ": "
- << std::endl
- << possibleMatch << std::endl;
- // The rest is just a copy of the usual handling, if a precise match is
- // found. We only use the literals that appear in the matching conflict,
- // though, and not in the original lemma - as these may not have even
- // been bit blasted!
- std::ostringstream lemma_paren;
-
- if (possibleMatch.getKind() == kind::OR)
- {
- for (const Expr& lit : possibleMatch)
- {
- if (lit.getKind() == kind::NOT)
- {
- os << "(intro_assump_t _ _ _ ";
- }
- else
- {
- os << "(intro_assump_f _ _ _ ";
- }
- lemma_paren << ")";
- // print corresponding literal in main sat solver
- ProofManager* pm = ProofManager::currentPM();
- CnfProof* cnf = pm->getCnfProof();
- prop::SatLiteral main_lit = cnf->getLiteral(lit);
- os << pm->getLitName(main_lit);
- os << " ";
- // print corresponding literal in bv sat solver
- prop::SatVariable bb_var =
- d_cnfProof->getLiteral(lit).getSatVariable();
- os << pm->getAtomName(bb_var, "bb");
- os << "(\\ unit" << bb_var << "\n";
- lemma_paren << ")";
- }
- }
- else
- {
- // The conflict only consists of one node, either positive or
- // negative.
- Expr lit = possibleMatch;
- if (lit.getKind() == kind::NOT)
- {
- os << "(intro_assump_t _ _ _ ";
- }
- else
- {
- os << "(intro_assump_f _ _ _ ";
- }
- lemma_paren << ")";
- // print corresponding literal in main sat solver
- ProofManager* pm = ProofManager::currentPM();
- CnfProof* cnf = pm->getCnfProof();
- prop::SatLiteral main_lit = cnf->getLiteral(lit);
- os << pm->getLitName(main_lit);
- os << " ";
- // print corresponding literal in bv sat solver
- prop::SatVariable bb_var =
- d_cnfProof->getLiteral(lit).getSatVariable();
- os << pm->getAtomName(bb_var, "bb");
- os << "(\\ unit" << bb_var << "\n";
- lemma_paren << ")";
- }
-
- ClauseId lemma_id = it->second;
- proof::LFSCProofPrinter::printAssumptionsResolution(
- d_resolutionProof.get(), lemma_id, os, lemma_paren);
- os << lemma_paren.str();
-
- return;
- }
- }
-
- // We failed to find a matching sub conflict. The last hope is that the
- // conflict has a FALSE assertion in it; this can happen in some corner
- // cases, where the FALSE is the result of a rewrite.
-
- for (const Expr& lit : lemma)
- {
- if (lit.getKind() == kind::NOT && lit[0] == utils::mkFalse())
- {
- Debug("pf::bv") << "Lemma has a (not false) literal" << std::endl;
- os << "(clausify_false ";
- os << ProofManager::getLitName(lit);
- os << ")";
- return;
- }
- }
-
- Debug("pf::bv") << "Failed to find a matching sub-conflict..." << std::endl
- << "Dumping existing conflicts:" << std::endl;
-
- i = 0;
- for (it = d_bbConflictMap.begin(); it != d_bbConflictMap.end(); ++it)
- {
- ++i;
- Debug("pf::bv") << "\tConflict #" << i << ": " << it->first << std::endl;
- }
-
- Unreachable();
- }
-}
-
-void LfscResolutionBitVectorProof::calculateAtomsInBitblastingProof()
-{
- // Collect the input clauses used
- IdToSatClause used_lemmas;
- IdToSatClause used_inputs;
- d_resolutionProof->collectClausesUsed(used_inputs, used_lemmas);
- d_cnfProof->collectAtomsForClauses(used_inputs, d_atomsInBitblastingProof);
- Assert(used_lemmas.empty());
-}
-
-void LfscResolutionBitVectorProof::printBBDeclarationAndCnf(std::ostream& os,
- std::ostream& paren,
- ProofLetMap& letMap)
-{
- // print mapping between theory atoms and internal SAT variables
- os << std::endl << ";; BB atom mapping\n" << std::endl;
-
- std::set<Node>::iterator atomIt;
- Debug("pf::bv") << std::endl
- << "BV Dumping atoms from inputs: " << std::endl
- << std::endl;
- for (atomIt = d_atomsInBitblastingProof.begin();
- atomIt != d_atomsInBitblastingProof.end();
- ++atomIt)
- {
- Debug("pf::bv") << "\tAtom: " << *atomIt << std::endl;
- }
- Debug("pf::bv") << std::endl;
-
- // first print bit-blasting
- printBitblasting(os, paren);
-
- // print CNF conversion proof for bit-blasted facts
- IdToSatClause used_lemmas;
- IdToSatClause used_inputs;
- d_resolutionProof->collectClausesUsed(used_inputs, used_lemmas);
-
- d_cnfProof->printAtomMapping(d_atomsInBitblastingProof, os, paren, letMap);
- os << std::endl << ";; Bit-blasting definitional clauses \n" << std::endl;
- for (IdToSatClause::iterator it = used_inputs.begin();
- it != used_inputs.end();
- ++it)
- {
- d_cnfProof->printCnfProofForClause(it->first, it->second, os, paren);
- }
-
- os << std::endl << " ;; Bit-blasting learned clauses \n" << std::endl;
- proof::LFSCProofPrinter::printResolutions(d_resolutionProof.get(), os, paren);
-}
-
-void LfscResolutionBitVectorProof::printEmptyClauseProof(std::ostream& os,
- std::ostream& paren)
-{
- Assert(options::bitblastMode() == options::BitblastMode::EAGER)
- << "the BV theory should only be proving bottom directly in the eager "
- "bitblasting mode";
- proof::LFSCProofPrinter::printResolutionEmptyClause(
- d_resolutionProof.get(), os, paren);
-}
-
-} // namespace proof
-
-} /* namespace CVC4 */
diff --git a/src/proof/resolution_bitvector_proof.h b/src/proof/resolution_bitvector_proof.h
deleted file mode 100644
index a1b0b0d59..000000000
--- a/src/proof/resolution_bitvector_proof.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/********************* */
-/*! \file resolution_bitvector_proof.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Alex Ozdemir, Mathias Preiner, Liana Hadarean
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Bitvector proof
- **
- ** Bitvector proof
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__PROOF__RESOLUTION_BITVECTOR_PROOF_H
-#define CVC4__PROOF__RESOLUTION_BITVECTOR_PROOF_H
-
-#include <iosfwd>
-
-#include "context/context.h"
-#include "expr/expr.h"
-#include "proof/bitvector_proof.h"
-#include "proof/sat_proof.h"
-#include "proof/theory_proof.h"
-#include "prop/bvminisat/core/Solver.h"
-#include "prop/cnf_stream.h"
-#include "prop/sat_solver_types.h"
-#include "theory/bv/bitblast/bitblaster.h"
-#include "theory/bv/theory_bv.h"
-
-namespace CVC4 {
-
-typedef TSatProof<CVC4::BVMinisat::Solver> BVSatProof;
-
-namespace proof {
-
-/**
- * Represents a bitvector proof which is backed by
- * (a) bitblasting and
- * (b) a resolution unsat proof.
- *
- * Contains tools for constructing BV conflicts
- */
-class ResolutionBitVectorProof : public BitVectorProof
-{
- public:
- ResolutionBitVectorProof(theory::bv::TheoryBV* bv,
- TheoryProofEngine* proofEngine);
-
- /**
- * Create an (internal) SAT proof object
- * Must be invoked before manipulating BV conflicts,
- * or initializing a BNF proof
- */
- void initSatProof(CVC4::BVMinisat::Solver* solver);
-
- BVSatProof* getSatProof();
-
- void finalizeConflicts(std::vector<Expr>& conflicts) override;
-
- void startBVConflict(CVC4::BVMinisat::Solver::TCRef cr);
- void startBVConflict(CVC4::BVMinisat::Solver::TLit lit);
- void endBVConflict(const BVMinisat::Solver::TLitVec& confl);
-
- void markAssumptionConflict() { d_isAssumptionConflict = true; }
- bool isAssumptionConflict() const { return d_isAssumptionConflict; }
-
- void initCnfProof(prop::CnfStream* cnfStream,
- context::Context* cnf,
- prop::SatVariable trueVar,
- prop::SatVariable falseVar) override;
-
- protected:
- void attachToSatSolver(prop::SatSolver& sat_solver) override;
-
- context::Context d_fakeContext;
-
- // The CNF formula that results from bit-blasting will need a proof.
- // This is that proof.
- std::unique_ptr<BVSatProof> d_resolutionProof;
-
- bool d_isAssumptionConflict;
-
-};
-
-class LfscResolutionBitVectorProof : public ResolutionBitVectorProof
-{
- public:
- LfscResolutionBitVectorProof(theory::bv::TheoryBV* bv,
- TheoryProofEngine* proofEngine)
- : ResolutionBitVectorProof(bv, proofEngine)
- {
- }
- void printTheoryLemmaProof(std::vector<Expr>& lemma,
- std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& map) override;
- void printBBDeclarationAndCnf(std::ostream& os,
- std::ostream& paren,
- ProofLetMap& letMap) override;
- void printEmptyClauseProof(std::ostream& os, std::ostream& paren) override;
- void calculateAtomsInBitblastingProof() override;
-};
-
-} // namespace proof
-
-} // namespace CVC4
-
-#endif /* CVC4__PROOF__RESOLUTIONBITVECTORPROOF_H */
diff --git a/src/proof/sat_proof.h b/src/proof/sat_proof.h
index 83e4d3930..27c98d62a 100644
--- a/src/proof/sat_proof.h
+++ b/src/proof/sat_proof.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Tim King, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,8 +19,6 @@
#ifndef CVC4__SAT__PROOF_H
#define CVC4__SAT__PROOF_H
-#include <stdint.h>
-
#include <iosfwd>
#include <set>
#include <sstream>
@@ -32,7 +30,6 @@
#include "expr/expr.h"
#include "proof/clause_id.h"
#include "proof/proof_manager.h"
-#include "util/proof.h"
#include "util/statistics_registry.h"
// Forward declarations.
diff --git a/src/proof/sat_proof_implementation.h b/src/proof/sat_proof_implementation.h
index 897a5c452..65dc38010 100644
--- a/src/proof/sat_proof_implementation.h
+++ b/src/proof/sat_proof_implementation.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Tim King, Guy Katz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,10 +20,7 @@
#define CVC4__SAT__PROOF_IMPLEMENTATION_H
#include "proof/clause_id.h"
-#include "proof/cnf_proof.h"
#include "proof/sat_proof.h"
-#include "prop/bvminisat/bvminisat.h"
-#include "prop/bvminisat/core/Solver.h"
#include "prop/minisat/core/Solver.h"
#include "prop/minisat/minisat.h"
#include "prop/sat_solver_types.h"
@@ -712,11 +709,6 @@ void TSatProof<Solver>::registerResolution(ClauseId id, ResChain<Solver>* res) {
Assert(checkResolution(id));
}
- PSTATS(uint64_t resolutionSteps =
- static_cast<uint64_t>(res.getSteps().size());
- d_statistics.d_resChainLengths << resolutionSteps;
- d_statistics.d_avgChainLength.addEntry(resolutionSteps);
- ++(d_statistics.d_numLearnedClauses);)
}
/// recording resolutions
@@ -912,14 +904,6 @@ void TSatProof<Solver>::markDeleted(typename Solver::TCRef clause) {
}
}
-// template<>
-// void toSatClause< ::BVMinisat::Solver> (const BVMinisat::Solver::TClause&
-// minisat_cl,
-// prop::SatClause& sat_cl) {
-
-// prop::BVMinisatSatSolver::toSatClause(minisat_cl, sat_cl);
-// }
-
template <class Solver>
void TSatProof<Solver>::constructProof(ClauseId conflict) {
d_satProofConstructed = true;
@@ -1002,9 +986,6 @@ void TSatProof<Solver>::collectClauses(ClauseId id) {
const ResolutionChain& res = getResolutionChain(id);
const typename ResolutionChain::ResSteps& steps = res.getSteps();
- PSTATS(d_statistics.d_usedResChainLengths
- << ((uint64_t)steps.size());
- d_statistics.d_usedClauseGlue << ((uint64_t)d_glueMap[id]););
ClauseId start = res.getStart();
collectClauses(start);
@@ -1018,8 +999,6 @@ void TSatProof<Solver>::collectClausesUsed(IdToSatClause& inputs,
IdToSatClause& lemmas) {
inputs = d_seenInputs;
lemmas = d_seenLemmas;
- PSTATS(d_statistics.d_numLearnedInProof.setData(d_seenLearnt.size());
- d_statistics.d_numLemmasInProof.setData(d_seenLemmas.size()););
}
template <class Solver>
diff --git a/src/proof/simplify_boolean_node.cpp b/src/proof/simplify_boolean_node.cpp
deleted file mode 100644
index 5f1943654..000000000
--- a/src/proof/simplify_boolean_node.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/********************* */
-/*! \file simplify_boolean_node.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Guy Katz, Liana Hadarean, Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Simplifying a boolean node, needed for constructing LFSC proofs.
- **
- **/
-
-#include "cvc4_private.h"
-
-#include "proof_manager.h"
-
-namespace CVC4 {
-
-inline static Node eqNode(TNode n1, TNode n2) {
- return NodeManager::currentNM()->mkNode(kind::EQUAL, n1, n2);
-}
-
-Node simplifyBooleanNode(const Node &n) {
- if (n.isNull())
- return n;
-
- // Only simplify boolean nodes
- if (!n.getType().isBoolean())
- return n;
-
- // Sometimes we get sent intermediate nodes that we shouldn't simplify.
- // If a node doesn't have a literal, it's clearly intermediate - ignore.
- if (!ProofManager::hasLitName(n))
- return n;
-
- // If we already simplified the node, ignore.
- if (ProofManager::currentPM()->haveRewriteFilter(n.negate()))
- return n;
-
-
- std::string litName = ProofManager::getLitName(n.negate());
- Node falseNode = NodeManager::currentNM()->mkConst(false);
- Node trueNode = NodeManager::currentNM()->mkConst(true);
- Node simplified = n;
-
- // (not (= false b)), (not (= true b)))
- if ((n.getKind() == kind::NOT) && (n[0].getKind() == kind::EQUAL) &&
- (n[0][0].getKind() == kind::BOOLEAN_TERM_VARIABLE || n[0][1].getKind() == kind::BOOLEAN_TERM_VARIABLE)) {
- Node lhs = n[0][0];
- Node rhs = n[0][1];
-
- if (lhs == falseNode) {
- Assert(rhs != falseNode);
- Assert(rhs.getKind() == kind::BOOLEAN_TERM_VARIABLE);
- // (not (= false b)) --> true = b
-
- simplified = eqNode(trueNode, rhs);
-
- std::string simplifiedLitName = ProofManager::getLitName(simplified.negate());
- std::stringstream newLitName;
- newLitName << "(pred_not_iff_f _ " << litName << ")";
- ProofManager::currentPM()->addRewriteFilter(simplifiedLitName, newLitName.str());
-
- } else if (rhs == falseNode) {
- Assert(lhs != falseNode);
- Assert(lhs.getKind() == kind::BOOLEAN_TERM_VARIABLE);
- // (not (= b false)) --> b = true
-
- simplified = eqNode(lhs, trueNode);
- std::string simplifiedLitName = ProofManager::getLitName(simplified.negate());
- std::stringstream newLitName;
- newLitName << "(pred_not_iff_f_2 _ " << litName << ")";
- ProofManager::currentPM()->addRewriteFilter(simplifiedLitName, newLitName.str());
-
- } else if (lhs == trueNode) {
- Assert(rhs != trueNode);
- Assert(rhs.getKind() == kind::BOOLEAN_TERM_VARIABLE);
- // (not (= true b)) --> b = false
-
- simplified = eqNode(falseNode, rhs);
- std::string simplifiedLitName = ProofManager::getLitName(simplified.negate());
- std::stringstream newLitName;
- newLitName << "(pred_not_iff_t _ " << litName << ")";
- ProofManager::currentPM()->addRewriteFilter(simplifiedLitName, newLitName.str());
-
- } else if (rhs == trueNode) {
- Assert(lhs != trueNode);
- Assert(lhs.getKind() == kind::BOOLEAN_TERM_VARIABLE);
- // (not (= b true)) --> b = false
-
- simplified = eqNode(lhs, falseNode);
- std::string simplifiedLitName = ProofManager::getLitName(simplified.negate());
- std::stringstream newLitName;
- newLitName << "(pred_not_iff_t_2 _ " << litName << ")";
- ProofManager::currentPM()->addRewriteFilter(simplifiedLitName, newLitName.str());
- }
-
- } else if ((n.getKind() == kind::EQUAL) &&
- (n[0].getKind() == kind::BOOLEAN_TERM_VARIABLE || n[1].getKind() == kind::BOOLEAN_TERM_VARIABLE)) {
- Node lhs = n[0];
- Node rhs = n[1];
-
- if (lhs == falseNode) {
- Assert(rhs != falseNode);
- Assert(rhs.getKind() == kind::BOOLEAN_TERM_VARIABLE);
- // (= false b)
-
- std::stringstream newLitName;
- newLitName << "(pred_iff_f _ " << litName << ")";
- ProofManager::currentPM()->addRewriteFilter(litName, newLitName.str());
-
- } else if (rhs == falseNode) {
- Assert(lhs != falseNode);
- Assert(lhs.getKind() == kind::BOOLEAN_TERM_VARIABLE);
- // (= b false))
-
- std::stringstream newLitName;
- newLitName << "(pred_iff_f_2 _ " << litName << ")";
- ProofManager::currentPM()->addRewriteFilter(litName, newLitName.str());
-
- } else if (lhs == trueNode) {
- Assert(rhs != trueNode);
- Assert(rhs.getKind() == kind::BOOLEAN_TERM_VARIABLE);
- // (= true b)
-
- std::stringstream newLitName;
- newLitName << "(pred_iff_t _ " << litName << ")";
- ProofManager::currentPM()->addRewriteFilter(litName, newLitName.str());
-
- } else if (rhs == trueNode) {
- Assert(lhs != trueNode);
- Assert(lhs.getKind() == kind::BOOLEAN_TERM_VARIABLE);
- // (= b true)
-
-
- std::stringstream newLitName;
- newLitName << "(pred_iff_t_2 _ " << litName << ")";
- ProofManager::currentPM()->addRewriteFilter(litName, newLitName.str());
- }
-
- } else if ((n.getKind() == kind::NOT) && (n[0].getKind() == kind::BOOLEAN_TERM_VARIABLE)) {
- // (not b) --> b = false
- simplified = eqNode(n[0], falseNode);
- std::string simplifiedLitName = ProofManager::getLitName(simplified.negate());
- std::stringstream newLitName;
- newLitName << "(pred_eq_f _ " << litName << ")";
- ProofManager::currentPM()->addRewriteFilter(simplifiedLitName, newLitName.str());
-
- } else if (n.getKind() == kind::BOOLEAN_TERM_VARIABLE) {
- // (b) --> b = true
- simplified = eqNode(n, trueNode);
- std::string simplifiedLitName = ProofManager::getLitName(simplified.negate());
- std::stringstream newLitName;
- newLitName << "(pred_eq_t _ " << litName << ")";
- ProofManager::currentPM()->addRewriteFilter(simplifiedLitName, newLitName.str());
-
- } else if ((n.getKind() == kind::NOT) && (n[0].getKind() == kind::SELECT)) {
- // not(a[x]) --> a[x] = false
- simplified = eqNode(n[0], falseNode);
- std::string simplifiedLitName = ProofManager::getLitName(simplified.negate());
- std::stringstream newLitName;
- newLitName << "(pred_eq_f _ " << litName << ")";
- ProofManager::currentPM()->addRewriteFilter(simplifiedLitName, newLitName.str());
-
- } else if (n.getKind() == kind::SELECT) {
- // a[x] --> a[x] = true
- simplified = eqNode(n, trueNode);
- std::string simplifiedLitName = ProofManager::getLitName(simplified.negate());
- std::stringstream newLitName;
- newLitName << "(pred_eq_t _ " << litName << ")";
- ProofManager::currentPM()->addRewriteFilter(simplifiedLitName, newLitName.str());
- }
-
- if (simplified != n)
- Debug("pf::simplify") << "simplifyBooleanNode: " << n << " --> " << simplified << std::endl;
-
- return simplified;
-}
-
-}/* CVC4 namespace */
diff --git a/src/proof/simplify_boolean_node.h b/src/proof/simplify_boolean_node.h
deleted file mode 100644
index bb4fe2e47..000000000
--- a/src/proof/simplify_boolean_node.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/********************* */
-/*! \file simplify_boolean_node.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Mathias Preiner, Guy Katz
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Simplifying a boolean node, needed for constructing LFSC proofs.
- **
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__SIMPLIFY_BOOLEAN_NODE_H
-#define CVC4__SIMPLIFY_BOOLEAN_NODE_H
-
-namespace CVC4 {
-
-Node simplifyBooleanNode(const Node &n);
-
-}/* CVC4 namespace */
-
-#endif /* CVC4__SIMPLIFY_BOOLEAN_NODE_H */
diff --git a/src/proof/skolemization_manager.cpp b/src/proof/skolemization_manager.cpp
deleted file mode 100644
index 1bb14598d..000000000
--- a/src/proof/skolemization_manager.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/********************* */
-/*! \file skolemization_manager.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Paul Meng, Tim King, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** [[ Add lengthier description here ]]
-
- ** \todo document this file
-
- **/
-
-#include "proof/skolemization_manager.h"
-
-namespace CVC4 {
-
-void SkolemizationManager::registerSkolem(Node disequality, Node skolem) {
- Debug("pf::pm") << "SkolemizationManager: registerSkolem: disequality = " << disequality << ", skolem = " << skolem << std::endl;
-
- if (isSkolem(skolem)) {
- Assert(d_skolemToDisequality[skolem] == disequality);
- return;
- }
-
- d_disequalityToSkolem[disequality] = skolem;
- d_skolemToDisequality[skolem] = disequality;
-}
-
-bool SkolemizationManager::hasSkolem(Node disequality) {
- return (d_disequalityToSkolem.find(disequality) != d_disequalityToSkolem.end());
-}
-
-Node SkolemizationManager::getSkolem(Node disequality) {
- Debug("pf::pm") << "SkolemizationManager: getSkolem( ";
- Assert(d_disequalityToSkolem.find(disequality)
- != d_disequalityToSkolem.end());
- Debug("pf::pm") << disequality << " ) = " << d_disequalityToSkolem[disequality] << std::endl;
- return d_disequalityToSkolem[disequality];
-}
-
-Node SkolemizationManager::getDisequality(Node skolem) {
- Assert(d_skolemToDisequality.find(skolem) != d_skolemToDisequality.end());
- return d_skolemToDisequality[skolem];
-}
-
-bool SkolemizationManager::isSkolem(Node skolem) {
- return (d_skolemToDisequality.find(skolem) != d_skolemToDisequality.end());
-}
-
-void SkolemizationManager::clear() {
- Debug("pf::pm") << "SkolemizationManager: clear" << std::endl;
- d_disequalityToSkolem.clear();
- d_skolemToDisequality.clear();
-}
-
-std::unordered_map<Node, Node, NodeHashFunction>::const_iterator SkolemizationManager::begin() {
- return d_disequalityToSkolem.begin();
-}
-
-std::unordered_map<Node, Node, NodeHashFunction>::const_iterator SkolemizationManager::end() {
- return d_disequalityToSkolem.end();
-}
-
-} /* CVC4 namespace */
diff --git a/src/proof/skolemization_manager.h b/src/proof/skolemization_manager.h
deleted file mode 100644
index a2c61db4d..000000000
--- a/src/proof/skolemization_manager.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/********************* */
-/*! \file skolemization_manager.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Guy Katz, Tim King, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** [[ Add lengthier description here ]]
-
- ** \todo document this file
-
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__SKOLEMIZATION_MANAGER_H
-#define CVC4__SKOLEMIZATION_MANAGER_H
-
-#include <iostream>
-#include <unordered_map>
-
-#include "proof/proof.h"
-#include "util/proof.h"
-#include "expr/node.h"
-#include "theory/logic_info.h"
-#include "theory/substitutions.h"
-
-namespace CVC4 {
-
-class SkolemizationManager {
-public:
- void registerSkolem(Node disequality, Node skolem);
- bool hasSkolem(Node disequality);
- Node getSkolem(Node disequality);
- Node getDisequality(Node skolem);
- bool isSkolem(Node skolem);
- void clear();
-
- std::unordered_map<Node, Node, NodeHashFunction>::const_iterator begin();
- std::unordered_map<Node, Node, NodeHashFunction>::const_iterator end();
-
-private:
- std::unordered_map<Node, Node, NodeHashFunction> d_disequalityToSkolem;
- std::unordered_map<Node, Node, NodeHashFunction> d_skolemToDisequality;
-};
-
-}/* CVC4 namespace */
-
-
-
-#endif /* CVC4__SKOLEMIZATION_MANAGER_H */
diff --git a/src/proof/theory_proof.cpp b/src/proof/theory_proof.cpp
deleted file mode 100644
index 3103557c8..000000000
--- a/src/proof/theory_proof.cpp
+++ /dev/null
@@ -1,1750 +0,0 @@
-/********************* */
-/*! \file theory_proof.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Guy Katz, Liana Hadarean, Yoni Zohar
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-#include "proof/theory_proof.h"
-
-#include "base/check.h"
-#include "context/context.h"
-#include "expr/node_visitor.h"
-#include "options/bv_options.h"
-#include "options/proof_options.h"
-#include "proof/arith_proof.h"
-#include "proof/array_proof.h"
-#include "proof/clausal_bitvector_proof.h"
-#include "proof/clause_id.h"
-#include "proof/cnf_proof.h"
-#include "proof/proof_manager.h"
-#include "proof/proof_output_channel.h"
-#include "proof/proof_utils.h"
-#include "proof/resolution_bitvector_proof.h"
-#include "proof/sat_proof.h"
-#include "proof/simplify_boolean_node.h"
-#include "proof/uf_proof.h"
-#include "prop/sat_solver_types.h"
-#include "smt/smt_engine.h"
-#include "smt/smt_engine_scope.h"
-#include "theory/arrays/theory_arrays.h"
-#include "theory/bv/theory_bv.h"
-#include "theory/output_channel.h"
-#include "theory/term_registration_visitor.h"
-#include "theory/uf/theory_uf.h"
-#include "theory/valuation.h"
-#include "util/hash.h"
-#include "util/proof.h"
-
-namespace CVC4 {
-
-using proof::LfscResolutionBitVectorProof;
-using proof::ResolutionBitVectorProof;
-
-unsigned CVC4::ProofLetCount::counter = 0;
-static unsigned LET_COUNT = 1;
-
-TheoryProofEngine::TheoryProofEngine()
- : d_registrationCache()
- , d_theoryProofTable()
-{
- d_theoryProofTable[theory::THEORY_BOOL] = new LFSCBooleanProof(this);
-}
-
-TheoryProofEngine::~TheoryProofEngine() {
- TheoryProofTable::iterator it = d_theoryProofTable.begin();
- TheoryProofTable::iterator end = d_theoryProofTable.end();
- for (; it != end; ++it) {
- delete it->second;
- }
-}
-
-void TheoryProofEngine::registerTheory(theory::Theory* th) {
- if (th) {
- theory::TheoryId id = th->getId();
- if(d_theoryProofTable.find(id) == d_theoryProofTable.end()) {
-
- Trace("pf::tp") << "TheoryProofEngine::registerTheory: " << id << std::endl;
-
- if (id == theory::THEORY_UF) {
- d_theoryProofTable[id] = new LFSCUFProof((theory::uf::TheoryUF*)th, this);
- return;
- }
-
- if (id == theory::THEORY_BV) {
- auto thBv = static_cast<theory::bv::TheoryBV*>(th);
- if (options::bitblastMode() == options::BitblastMode::EAGER
- && options::bvSatSolver() == options::SatSolverMode::CRYPTOMINISAT)
- {
- proof::BitVectorProof* bvp = nullptr;
- switch (options::bvProofFormat())
- {
- case options::BvProofFormat::DRAT:
- {
- bvp = new proof::LfscDratBitVectorProof(thBv, this);
- break;
- }
- case options::BvProofFormat::LRAT:
- {
- bvp = new proof::LfscLratBitVectorProof(thBv, this);
- break;
- }
- case options::BvProofFormat::ER:
- {
- bvp = new proof::LfscErBitVectorProof(thBv, this);
- break;
- }
- default:
- {
- Unreachable() << "Invalid BvProofFormat";
- }
- };
- d_theoryProofTable[id] = bvp;
- }
- else
- {
- proof::BitVectorProof* bvp =
- new proof::LfscResolutionBitVectorProof(thBv, this);
- d_theoryProofTable[id] = bvp;
- }
- return;
- }
-
- if (id == theory::THEORY_ARRAYS) {
- d_theoryProofTable[id] = new LFSCArrayProof((theory::arrays::TheoryArrays*)th, this);
- return;
- }
-
- if (id == theory::THEORY_ARITH) {
- d_theoryProofTable[id] = new LFSCArithProof((theory::arith::TheoryArith*)th, this);
- return;
- }
-
- // TODO other theories
- }
- }
-}
-
-void TheoryProofEngine::finishRegisterTheory(theory::Theory* th) {
- if (th) {
- theory::TheoryId id = th->getId();
- if (id == theory::THEORY_BV) {
- theory::bv::TheoryBV* bv_th = static_cast<theory::bv::TheoryBV*>(th);
- Assert(d_theoryProofTable.find(id) != d_theoryProofTable.end());
- proof::BitVectorProof* bvp =
- static_cast<proof::BitVectorProof*>(d_theoryProofTable[id]);
- bv_th->setProofLog(bvp);
- return;
- }
- }
-}
-
-TheoryProof* TheoryProofEngine::getTheoryProof(theory::TheoryId id) {
- // The UF theory handles queries for the Builtin theory.
- if (id == theory::THEORY_BUILTIN) {
- Debug("pf::tp") << "TheoryProofEngine::getTheoryProof: BUILTIN --> UF" << std::endl;
- id = theory::THEORY_UF;
- }
-
- if (d_theoryProofTable.find(id) == d_theoryProofTable.end()) {
- InternalError()
- << "Error! Proofs not yet supported for the following theory: " << id
- << std::endl;
- }
-
- return d_theoryProofTable[id];
-}
-
-void TheoryProofEngine::markTermForFutureRegistration(Expr term, theory::TheoryId id) {
- d_exprToTheoryIds[term].insert(id);
-}
-
-void TheoryProofEngine::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap) {
- Assert(c1.isConst());
- Assert(c2.isConst());
-
- Assert(theory::Theory::theoryOf(c1) == theory::Theory::theoryOf(c2));
- getTheoryProof(theory::Theory::theoryOf(c1))->printConstantDisequalityProof(os, c1, c2, globalLetMap);
-}
-
-void TheoryProofEngine::printTheoryTerm(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType)
-{
- this->printTheoryTermAsType(term, os, map, expectedType);
-}
-
-TypeNode TheoryProofEngine::equalityType(const Expr& left, const Expr& right)
-{
- // Ask the two theories what they think..
- TypeNode leftType = getTheoryProof(theory::Theory::theoryOf(left))->equalityType(left, right);
- TypeNode rightType = getTheoryProof(theory::Theory::theoryOf(right))->equalityType(left, right);
-
- // Error if the disagree.
- Assert(leftType.isNull() || rightType.isNull() || leftType == rightType)
- << "TheoryProofEngine::equalityType(" << left << ", " << right << "):" << std::endl
- << "theories disagree about the type of an equality:" << std::endl
- << "\tleft: " << leftType << std::endl
- << "\tright:" << rightType;
-
- return leftType.isNull() ? rightType : leftType;
-}
-
-void TheoryProofEngine::registerTerm(Expr term) {
- Debug("pf::tp::register") << "TheoryProofEngine::registerTerm: registering term: " << term << std::endl;
-
- if (d_registrationCache.count(term)) {
- return;
- }
-
- Debug("pf::tp::register") << "TheoryProofEngine::registerTerm: registering NEW term: " << term << std::endl;
-
- theory::TheoryId theory_id = theory::Theory::theoryOf(term);
-
- Debug("pf::tp::register") << "Term's theory( " << term << " ) = " << theory_id << std::endl;
-
- // don't need to register boolean terms
- if (theory_id == theory::THEORY_BUILTIN ||
- term.getKind() == kind::ITE) {
- for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- registerTerm(term[i]);
- }
- d_registrationCache.insert(term);
- return;
- }
-
- if (!supportedTheory(theory_id)) return;
-
- // Register the term with its owner theory
- getTheoryProof(theory_id)->registerTerm(term);
-
- // A special case: the array theory needs to know of every skolem, even if
- // it belongs to another theory (e.g., a BV skolem)
- if (ProofManager::getSkolemizationManager()->isSkolem(term) && theory_id != theory::THEORY_ARRAYS) {
- Debug("pf::tp::register") << "TheoryProofEngine::registerTerm: registering a non-array skolem: " << term << std::endl;
- getTheoryProof(theory::THEORY_ARRAYS)->registerTerm(term);
- }
-
- d_registrationCache.insert(term);
-}
-
-theory::TheoryId TheoryProofEngine::getTheoryForLemma(const prop::SatClause* clause) {
- ProofManager* pm = ProofManager::currentPM();
-
- std::set<Node> nodes;
- for(unsigned i = 0; i < clause->size(); ++i) {
- prop::SatLiteral lit = (*clause)[i];
- Node node = pm->getCnfProof()->getAtom(lit.getSatVariable());
- Expr atom = node.toExpr();
- if (atom.isConst()) {
- Assert(atom == utils::mkTrue());
- continue;
- }
-
- nodes.insert(lit.isNegated() ? node.notNode() : node);
- }
-
- // Ensure that the lemma is in the database.
- Assert(pm->getCnfProof()->haveProofRecipe(nodes));
- return pm->getCnfProof()->getProofRecipe(nodes).getTheory();
-}
-
-void LFSCTheoryProofEngine::bind(Expr term, ProofLetMap& map, Bindings& let_order) {
- ProofLetMap::iterator it = map.find(term);
- if (it != map.end()) {
- ProofLetCount& count = it->second;
- count.increment();
- return;
- }
- for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- bind(term[i], map, let_order);
- }
- unsigned new_id = ProofLetCount::newId();
- map[term] = ProofLetCount(new_id);
- let_order.push_back(LetOrderElement(term, new_id));
-}
-
-void LFSCTheoryProofEngine::printLetTerm(Expr term, std::ostream& os) {
- ProofLetMap map;
- Bindings let_order;
- bind(term, map, let_order);
- std::ostringstream paren;
- for (unsigned i = 0; i < let_order.size(); ++i) {
- Expr current_expr = let_order[i].expr;
- unsigned let_id = let_order[i].id;
- ProofLetMap::const_iterator it = map.find(current_expr);
- Assert(it != map.end());
- unsigned let_count = it->second.count;
- Assert(let_count);
- // skip terms that only appear once
- if (let_count <= LET_COUNT) {
- continue;
- }
-
- os << "(@ let" <<let_id << " ";
- printTheoryTerm(current_expr, os, map);
- paren <<")";
- }
- unsigned last_let_id = let_order.back().id;
- Expr last = let_order.back().expr;
- unsigned last_count = map.find(last)->second.count;
- if (last_count <= LET_COUNT) {
- printTheoryTerm(last, os, map);
- }
- else {
- os << " let" << last_let_id;
- }
- os << paren.str();
-}
-
-void LFSCTheoryProofEngine::printTheoryTermAsType(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType)
-{
- theory::TheoryId theory_id = theory::Theory::theoryOf(term);
-
- // boolean terms and ITEs are special because they
- // are common to all theories
- if (theory_id == theory::THEORY_BUILTIN ||
- term.getKind() == kind::ITE ||
- term.getKind() == kind::EQUAL) {
- printCoreTerm(term, os, map, expectedType);
- return;
- }
- // dispatch to proper theory
- getTheoryProof(theory_id)->printOwnedTerm(term, os, map, expectedType);
-}
-
-void LFSCTheoryProofEngine::printSort(Type type, std::ostream& os) {
- if (type.isSort()) {
- getTheoryProof(theory::THEORY_UF)->printOwnedSort(type, os);
- return;
- }
- if (type.isBitVector()) {
- getTheoryProof(theory::THEORY_BV)->printOwnedSort(type, os);
- return;
- }
-
- if (type.isArray()) {
- getTheoryProof(theory::THEORY_ARRAYS)->printOwnedSort(type, os);
- return;
- }
-
- if (type.isInteger() || type.isReal()) {
- getTheoryProof(theory::THEORY_ARITH)->printOwnedSort(type, os);
- return;
- }
-
- if (type.isBoolean()) {
- getTheoryProof(theory::THEORY_BOOL)->printOwnedSort(type, os);
- return;
- }
-
- Unreachable();
-}
-
-void LFSCTheoryProofEngine::performExtraRegistrations() {
- ExprToTheoryIds::const_iterator it;
- for (it = d_exprToTheoryIds.begin(); it != d_exprToTheoryIds.end(); ++it) {
- if (d_registrationCache.count(it->first)) { // Only register if the term appeared
- TheoryIdSet::const_iterator theoryIt;
- for (theoryIt = it->second.begin(); theoryIt != it->second.end(); ++theoryIt) {
- Debug("pf::tp") << "\tExtra registration of term " << it->first
- << " with theory: " << *theoryIt << std::endl;
- Assert(supportedTheory(*theoryIt));
- getTheoryProof(*theoryIt)->registerTerm(it->first);
- }
- }
- }
-}
-
-void LFSCTheoryProofEngine::registerTermsFromAssertions() {
- ProofManager::assertions_iterator it = ProofManager::currentPM()->begin_assertions();
- ProofManager::assertions_iterator end = ProofManager::currentPM()->end_assertions();
-
- for(; it != end; ++it) {
- registerTerm(*it);
- }
-
- performExtraRegistrations();
-}
-
-void LFSCTheoryProofEngine::printAssertions(std::ostream& os, std::ostream& paren) {
- Debug("pf::tp") << "LFSCTheoryProofEngine::printAssertions called" << std::endl << std::endl;
-
- ProofManager::assertions_iterator it = ProofManager::currentPM()->begin_assertions();
- ProofManager::assertions_iterator end = ProofManager::currentPM()->end_assertions();
-
- for (; it != end; ++it) {
- Debug("pf::tp") << "printAssertions: assertion is: " << *it << std::endl;
- os << "(% " << ProofManager::currentPM()->getInputFormulaName(*it) << " (th_holds ";
-
- // Assertions appear before the global let map, so we use a dummpMap to avoid letification here.
- ProofLetMap dummyMap;
-
- bool convertFromBool = (it->getType().isBoolean() && printsAsBool(*it));
- if (convertFromBool) os << "(p_app ";
- printBoundTerm(*it, os, dummyMap);
- if (convertFromBool) os << ")";
-
- os << ")\n";
- paren << ")";
- }
-
- Debug("pf::tp") << "LFSCTheoryProofEngine::printAssertions done" << std::endl << std::endl;
-}
-
-void LFSCTheoryProofEngine::printLemmaRewrites(NodePairSet& rewrites,
- std::ostream& os,
- std::ostream& paren) {
- Debug("pf::tp") << "LFSCTheoryProofEngine::printLemmaRewrites called" << std::endl << std::endl;
-
- NodePairSet::const_iterator it;
-
- for (it = rewrites.begin(); it != rewrites.end(); ++it) {
- Debug("pf::tp") << "printLemmaRewrites: " << it->first << " --> " << it->second << std::endl;
-
- Node n1 = it->first;
- Node n2 = it->second;
- Assert(n1.toExpr() == utils::mkFalse()
- || theory::Theory::theoryOf(n1) == theory::Theory::theoryOf(n2));
-
- std::ostringstream rewriteRule;
- rewriteRule << ".lrr" << d_assertionToRewrite.size();
-
- os << "(th_let_pf _ ";
- getTheoryProof(theory::Theory::theoryOf(n1))->printRewriteProof(os, n1, n2);
- os << "(\\ " << rewriteRule.str() << "\n";
-
- d_assertionToRewrite[it->first] = rewriteRule.str();
- Debug("pf::tp") << "d_assertionToRewrite[" << it->first << "] = " << rewriteRule.str() << std::endl;
- paren << "))";
- }
-
- Debug("pf::tp") << "LFSCTheoryProofEngine::printLemmaRewrites done" << std::endl << std::endl;
-}
-
-void LFSCTheoryProofEngine::printSortDeclarations(std::ostream& os, std::ostream& paren) {
- Debug("pf::tp") << "LFSCTheoryProofEngine::printSortDeclarations called" << std::endl << std::endl;
-
- TheoryProofTable::const_iterator it = d_theoryProofTable.begin();
- TheoryProofTable::const_iterator end = d_theoryProofTable.end();
- for (; it != end; ++it) {
- it->second->printSortDeclarations(os, paren);
- }
-
- Debug("pf::tp") << "LFSCTheoryProofEngine::printSortDeclarations done" << std::endl << std::endl;
-}
-
-void LFSCTheoryProofEngine::printTermDeclarations(std::ostream& os, std::ostream& paren) {
- Debug("pf::tp") << "LFSCTheoryProofEngine::printTermDeclarations called" << std::endl << std::endl;
-
- TheoryProofTable::const_iterator it = d_theoryProofTable.begin();
- TheoryProofTable::const_iterator end = d_theoryProofTable.end();
- for (; it != end; ++it) {
- it->second->printTermDeclarations(os, paren);
- }
-
- Debug("pf::tp") << "LFSCTheoryProofEngine::printTermDeclarations done" << std::endl << std::endl;
-}
-
-void LFSCTheoryProofEngine::printDeferredDeclarations(std::ostream& os, std::ostream& paren) {
- Debug("pf::tp") << "LFSCTheoryProofEngine::printDeferredDeclarations called" << std::endl;
-
- TheoryProofTable::const_iterator it = d_theoryProofTable.begin();
- TheoryProofTable::const_iterator end = d_theoryProofTable.end();
- for (; it != end; ++it) {
- it->second->printDeferredDeclarations(os, paren);
- }
-}
-
-void LFSCTheoryProofEngine::printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) {
- Debug("pf::tp") << "LFSCTheoryProofEngine::printAliasingDeclarations called" << std::endl;
-
- TheoryProofTable::const_iterator it = d_theoryProofTable.begin();
- TheoryProofTable::const_iterator end = d_theoryProofTable.end();
- for (; it != end; ++it) {
- it->second->printAliasingDeclarations(os, paren, globalLetMap);
- }
-}
-
-void LFSCTheoryProofEngine::dumpTheoryLemmas(const IdToSatClause& lemmas) {
- Debug("pf::dumpLemmas") << "Dumping ALL theory lemmas" << std::endl << std::endl;
-
- ProofManager* pm = ProofManager::currentPM();
- for (IdToSatClause::const_iterator it = lemmas.begin(); it != lemmas.end(); ++it) {
- ClauseId id = it->first;
- Debug("pf::dumpLemmas") << "**** \tLemma ID = " << id << std::endl;
- const prop::SatClause* clause = it->second;
- std::set<Node> nodes;
- for(unsigned i = 0; i < clause->size(); ++i) {
- prop::SatLiteral lit = (*clause)[i];
- Node node = pm->getCnfProof()->getAtom(lit.getSatVariable());
- if (node.isConst()) {
- Assert(node.toExpr() == utils::mkTrue());
- continue;
- }
- nodes.insert(lit.isNegated() ? node.notNode() : node);
- }
-
- LemmaProofRecipe recipe = pm->getCnfProof()->getProofRecipe(nodes);
- recipe.dump("pf::dumpLemmas");
- }
-
- Debug("pf::dumpLemmas") << "Theory lemma printing DONE" << std::endl << std::endl;
-}
-
-// TODO: this function should be moved into the BV prover.
-void LFSCTheoryProofEngine::finalizeBvConflicts(const IdToSatClause& lemmas, std::ostream& os) {
- // BitVector theory is special case: must know all conflicts needed
- // ahead of time for resolution proof lemmas
- std::vector<Expr> bv_lemmas;
-
- for (IdToSatClause::const_iterator it = lemmas.begin(); it != lemmas.end(); ++it) {
- const prop::SatClause* clause = it->second;
-
- std::vector<Expr> conflict;
- std::set<Node> conflictNodes;
- for(unsigned i = 0; i < clause->size(); ++i) {
- prop::SatLiteral lit = (*clause)[i];
- Node node = ProofManager::currentPM()->getCnfProof()->getAtom(lit.getSatVariable());
- Expr atom = node.toExpr();
-
- // The literals (true) and (not false) are omitted from conflicts
- if (atom.isConst()) {
- Assert(atom == utils::mkTrue()
- || (atom == utils::mkFalse() && lit.isNegated()));
- continue;
- }
-
- Expr expr_lit = lit.isNegated() ? atom.notExpr() : atom;
- conflict.push_back(expr_lit);
- conflictNodes.insert(lit.isNegated() ? node.notNode() : node);
- }
-
- LemmaProofRecipe recipe = ProofManager::currentPM()->getCnfProof()->getProofRecipe(conflictNodes);
-
- unsigned numberOfSteps = recipe.getNumSteps();
-
- prop::SatClause currentClause = *clause;
- std::vector<Expr> currentClauseExpr = conflict;
-
- for (unsigned i = 0; i < numberOfSteps; ++i) {
- const LemmaProofRecipe::ProofStep* currentStep = recipe.getStep(i);
-
- if (currentStep->getTheory() != theory::THEORY_BV) {
- continue;
- }
-
- // If any rewrites took place, we need to update the conflict clause accordingly
- std::set<Node> missingAssertions = recipe.getMissingAssertionsForStep(i);
- std::map<Node, Node> explanationToMissingAssertion;
- std::set<Node>::iterator assertionIt;
- for (assertionIt = missingAssertions.begin();
- assertionIt != missingAssertions.end();
- ++assertionIt) {
- Node negated = (*assertionIt).negate();
- explanationToMissingAssertion[recipe.getExplanation(negated)] = negated;
- }
-
- currentClause = *clause;
- currentClauseExpr = conflict;
-
- for (unsigned j = 0; j < i; ++j) {
- // Literals already used in previous steps need to be negated
- Node previousLiteralNode = recipe.getStep(j)->getLiteral();
-
- // If this literal is the result of a rewrite, we need to translate it
- if (explanationToMissingAssertion.find(previousLiteralNode) !=
- explanationToMissingAssertion.end()) {
- previousLiteralNode = explanationToMissingAssertion[previousLiteralNode];
- }
-
- Node previousLiteralNodeNegated = previousLiteralNode.negate();
- prop::SatLiteral previousLiteralNegated =
- ProofManager::currentPM()->getCnfProof()->getLiteral(previousLiteralNodeNegated);
-
- currentClause.push_back(previousLiteralNegated);
- currentClauseExpr.push_back(previousLiteralNodeNegated.toExpr());
- }
-
- // If we're in the final step, the last literal is Null and should not be added.
- // Otherwise, the current literal does NOT need to be negated
- Node currentLiteralNode = currentStep->getLiteral();
-
- if (currentLiteralNode != Node()) {
- prop::SatLiteral currentLiteral =
- ProofManager::currentPM()->getCnfProof()->getLiteral(currentLiteralNode);
-
- currentClause.push_back(currentLiteral);
- currentClauseExpr.push_back(currentLiteralNode.toExpr());
- }
-
- bv_lemmas.push_back(utils::mkSortedExpr(kind::OR, currentClauseExpr));
- }
- }
-
- proof::BitVectorProof* bv = ProofManager::getBitVectorProof();
- bv->finalizeConflicts(bv_lemmas);
-}
-
-void LFSCTheoryProofEngine::printTheoryLemmas(const IdToSatClause& lemmas,
- std::ostream& os,
- std::ostream& paren,
- ProofLetMap& map) {
- os << " ;; Theory Lemmas \n";
- Debug("pf::tp") << "LFSCTheoryProofEngine::printTheoryLemmas: starting" << std::endl;
-
- if (Debug.isOn("pf::dumpLemmas")) {
- dumpTheoryLemmas(lemmas);
- }
-
- // finalizeBvConflicts(lemmas, os, paren, map);
- ProofManager::getBitVectorProof()->printBBDeclarationAndCnf(os, paren, map);
-
- if (options::bitblastMode() == options::BitblastMode::EAGER)
- {
- Assert(lemmas.size() == 1);
- // nothing more to do (no combination with eager so far)
- return;
- }
-
- ProofManager* pm = ProofManager::currentPM();
- Debug("pf::tp") << "LFSCTheoryProofEngine::printTheoryLemmas: printing lemmas..." << std::endl;
-
- for (IdToSatClause::const_iterator it = lemmas.begin(); it != lemmas.end(); ++it) {
- ClauseId id = it->first;
- const prop::SatClause* clause = it->second;
-
- Debug("pf::tp") << "LFSCTheoryProofEngine::printTheoryLemmas: printing lemma. ID = "
- << id << std::endl;
-
- std::vector<Expr> clause_expr;
- std::set<Node> clause_expr_nodes;
- for(unsigned i = 0; i < clause->size(); ++i) {
- prop::SatLiteral lit = (*clause)[i];
- Node node = pm->getCnfProof()->getAtom(lit.getSatVariable());
- Expr atom = node.toExpr();
- if (atom.isConst()) {
- Assert(atom == utils::mkTrue());
- continue;
- }
- Expr expr_lit = lit.isNegated() ? atom.notExpr(): atom;
- clause_expr.push_back(expr_lit);
- clause_expr_nodes.insert(lit.isNegated() ? node.notNode() : node);
- }
-
- LemmaProofRecipe recipe = pm->getCnfProof()->getProofRecipe(clause_expr_nodes);
-
- if (recipe.simpleLemma()) {
- // In a simple lemma, there will be no propositional resolution in the end
-
- Debug("pf::tp") << "Simple lemma" << std::endl;
- // Printing the clause as it appears in resolution proof
- os << "(satlem _ _ ";
- std::ostringstream clause_paren;
- pm->getCnfProof()->printClause(*clause, os, clause_paren);
-
- // Find and handle missing assertions, due to rewrites
- std::set<Node> missingAssertions = recipe.getMissingAssertionsForStep(0);
- if (!missingAssertions.empty()) {
- Debug("pf::tp") << "Have missing assertions for this simple lemma!" << std::endl;
- }
-
- std::set<Node>::const_iterator missingAssertion;
- for (missingAssertion = missingAssertions.begin();
- missingAssertion != missingAssertions.end();
- ++missingAssertion) {
-
- Debug("pf::tp") << "Working on missing assertion: " << *missingAssertion << std::endl;
- Assert(recipe.wasRewritten(missingAssertion->negate()));
- Node explanation = recipe.getExplanation(missingAssertion->negate()).negate();
- Debug("pf::tp") << "Found explanation: " << explanation << std::endl;
-
- // We have a missing assertion.
- // rewriteIt->first is the assertion after the rewrite (the explanation),
- // rewriteIt->second is the original assertion that needs to be fed into the theory.
-
- bool found = false;
- unsigned k;
- for (k = 0; k < clause_expr.size(); ++k) {
- if (clause_expr[k] == explanation.toExpr()) {
- found = true;
- break;
- }
- }
-
- AlwaysAssert(found);
- Debug("pf::tp") << "Replacing theory assertion "
- << clause_expr[k]
- << " with "
- << *missingAssertion
- << std::endl;
-
- clause_expr[k] = missingAssertion->toExpr();
-
- std::ostringstream rewritten;
-
- if (missingAssertion->getKind() == kind::NOT && (*missingAssertion)[0].toExpr() == utils::mkFalse()) {
- rewritten << "(or_elim_2 _ _ ";
- rewritten << "(not_not_intro _ ";
- rewritten << pm->getLitName(explanation);
- rewritten << ") (iff_elim_2 _ _ ";
- rewritten << d_assertionToRewrite[missingAssertion->negate()];
- rewritten << "))";
- }
- else {
- rewritten << "(or_elim_1 _ _ ";
- rewritten << "(not_not_intro _ ";
- rewritten << pm->getLitName(explanation);
- rewritten << ") (iff_elim_1 _ _ ";
- rewritten << d_assertionToRewrite[missingAssertion->negate()];
- rewritten << "))";
- }
-
- Debug("pf::tp") << "Setting a rewrite filter for this proof: " << std::endl
- << pm->getLitName(*missingAssertion) << " --> " << rewritten.str()
- << ", explanation = " << explanation
- << std::endl << std::endl;
-
- pm->addRewriteFilter(pm->getLitName(*missingAssertion), rewritten.str());
- }
-
- // Query the appropriate theory for a proof of this clause
- theory::TheoryId theory_id = getTheoryForLemma(clause);
- Debug("pf::tp") << "Get theory lemma from " << theory_id << "..." << std::endl;
- getTheoryProof(theory_id)->printTheoryLemmaProof(clause_expr, os, paren, map);
-
- // Turn rewrite filter OFF
- pm->clearRewriteFilters();
-
- Debug("pf::tp") << "Get theory lemma from " << theory_id << "... DONE!" << std::endl;
- os << clause_paren.str();
- os << "( \\ " << pm->getLemmaClauseName(id) <<"\n";
- paren << "))";
- } else { // This is a composite lemma
-
- unsigned numberOfSteps = recipe.getNumSteps();
- prop::SatClause currentClause = *clause;
- std::vector<Expr> currentClauseExpr = clause_expr;
-
- for (unsigned i = 0; i < numberOfSteps; ++i) {
- const LemmaProofRecipe::ProofStep* currentStep = recipe.getStep(i);
-
- currentClause = *clause;
- currentClauseExpr = clause_expr;
-
- for (unsigned j = 0; j < i; ++j) {
- // Literals already used in previous steps need to be negated
- Node previousLiteralNode = recipe.getStep(j)->getLiteral();
- Node previousLiteralNodeNegated = previousLiteralNode.negate();
- prop::SatLiteral previousLiteralNegated =
- ProofManager::currentPM()->getCnfProof()->getLiteral(previousLiteralNodeNegated);
- currentClause.push_back(previousLiteralNegated);
- currentClauseExpr.push_back(previousLiteralNodeNegated.toExpr());
- }
-
- // If the current literal is NULL, can ignore (final step)
- // Otherwise, the current literal does NOT need to be negated
- Node currentLiteralNode = currentStep->getLiteral();
- if (currentLiteralNode != Node()) {
- prop::SatLiteral currentLiteral =
- ProofManager::currentPM()->getCnfProof()->getLiteral(currentLiteralNode);
-
- currentClause.push_back(currentLiteral);
- currentClauseExpr.push_back(currentLiteralNode.toExpr());
- }
-
- os << "(satlem _ _ ";
- std::ostringstream clause_paren;
-
- pm->getCnfProof()->printClause(currentClause, os, clause_paren);
-
- // query appropriate theory for proof of clause
- theory::TheoryId theory_id = currentStep->getTheory();
- Debug("pf::tp") << "Get theory lemma from " << theory_id << "..." << std::endl;
-
- std::set<Node> missingAssertions = recipe.getMissingAssertionsForStep(i);
- if (!missingAssertions.empty()) {
- Debug("pf::tp") << "Have missing assertions for this step!" << std::endl;
- }
-
- // Turn rewrite filter ON
- std::set<Node>::const_iterator missingAssertion;
- for (missingAssertion = missingAssertions.begin();
- missingAssertion != missingAssertions.end();
- ++missingAssertion) {
-
- Debug("pf::tp") << "Working on missing assertion: " << *missingAssertion << std::endl;
-
- Assert(recipe.wasRewritten(missingAssertion->negate()));
- Node explanation = recipe.getExplanation(missingAssertion->negate()).negate();
-
- Debug("pf::tp") << "Found explanation: " << explanation << std::endl;
-
- // We have a missing assertion.
- // rewriteIt->first is the assertion after the rewrite (the explanation),
- // rewriteIt->second is the original assertion that needs to be fed into the theory.
-
- bool found = false;
- unsigned k;
- for (k = 0; k < currentClauseExpr.size(); ++k) {
- if (currentClauseExpr[k] == explanation.toExpr()) {
- found = true;
- break;
- }
- }
-
- AlwaysAssert(found);
-
- Debug("pf::tp") << "Replacing theory assertion "
- << currentClauseExpr[k]
- << " with "
- << *missingAssertion
- << std::endl;
-
- currentClauseExpr[k] = missingAssertion->toExpr();
-
- std::ostringstream rewritten;
-
- if (missingAssertion->getKind() == kind::NOT && (*missingAssertion)[0].toExpr() == utils::mkFalse()) {
- rewritten << "(or_elim_2 _ _ ";
- rewritten << "(not_not_intro _ ";
- rewritten << pm->getLitName(explanation);
- rewritten << ") (iff_elim_2 _ _ ";
- rewritten << d_assertionToRewrite[missingAssertion->negate()];
- rewritten << "))";
- }
- else {
- rewritten << "(or_elim_1 _ _ ";
- rewritten << "(not_not_intro _ ";
- rewritten << pm->getLitName(explanation);
- rewritten << ") (iff_elim_1 _ _ ";
- rewritten << d_assertionToRewrite[missingAssertion->negate()];
- rewritten << "))";
- }
-
- Debug("pf::tp") << "Setting a rewrite filter for this proof: " << std::endl
- << pm->getLitName(*missingAssertion) << " --> " << rewritten.str()
- << "explanation = " << explanation
- << std::endl << std::endl;
-
- pm->addRewriteFilter(pm->getLitName(*missingAssertion), rewritten.str());
- }
-
- getTheoryProof(theory_id)->printTheoryLemmaProof(currentClauseExpr, os, paren, map);
-
- // Turn rewrite filter OFF
- pm->clearRewriteFilters();
-
- Debug("pf::tp") << "Get theory lemma from " << theory_id << "... DONE!" << std::endl;
- os << clause_paren.str();
- os << "( \\ " << pm->getLemmaClauseName(id) << "s" << i <<"\n";
- paren << "))";
- }
-
- Assert(numberOfSteps >= 2);
-
- os << "(satlem_simplify _ _ _ ";
- for (unsigned i = 0; i < numberOfSteps - 1; ++i) {
- // Resolve step i with step i + 1
- if (recipe.getStep(i)->getLiteral().getKind() == kind::NOT) {
- os << "(Q _ _ ";
- } else {
- os << "(R _ _ ";
- }
-
- os << pm->getLemmaClauseName(id) << "s" << i;
- os << " ";
- }
-
- os << pm->getLemmaClauseName(id) << "s" << numberOfSteps - 1 << " ";
-
- prop::SatLiteral v;
- for (int i = numberOfSteps - 2; i >= 0; --i) {
- v = ProofManager::currentPM()->getCnfProof()->getLiteral(recipe.getStep(i)->getLiteral());
- os << ProofManager::getVarName(v.getSatVariable(), "") << ") ";
- }
-
- os << "( \\ " << pm->getLemmaClauseName(id) << "\n";
- paren << "))";
- }
- }
-}
-
-void LFSCTheoryProofEngine::printBoundTermAsType(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType)
-{
- Debug("pf::tp") << "LFSCTheoryProofEngine::printBoundTerm( " << term << " ) " << std::endl;
-
- // Since let-abbreviated terms are abbreviated with their default type, only
- // use the let map if there is no expectedType or the expectedType matches
- // the default.
- if (expectedType.isNull()
- || TypeNode::fromType(term.getType()) == expectedType)
- {
- ProofLetMap::const_iterator it = map.find(term);
- if (it != map.end())
- {
- unsigned id = it->second.id;
- unsigned count = it->second.count;
-
- if (count > LET_COUNT)
- {
- os << "let" << id;
- Debug("pf::tp::letmap") << "Using let map for " << term << std::endl;
- return;
- }
- }
- }
- Debug("pf::tp::letmap") << "Skipping let map for " << term << std::endl;
-
- printTheoryTerm(term, os, map, expectedType);
-}
-
-void LFSCTheoryProofEngine::printBoundFormula(Expr term,
- std::ostream& os,
- const ProofLetMap& map)
-{
- Assert(term.getType().isBoolean() or term.getType().isPredicate());
- bool wrapWithBoolToPred = term.getType().isBoolean() and printsAsBool(term);
- if (wrapWithBoolToPred)
- {
- os << "(p_app ";
- }
- printBoundTerm(term, os, map);
- if (wrapWithBoolToPred)
- {
- os << ")";
- }
-}
-
-void LFSCTheoryProofEngine::printCoreTerm(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType)
-{
- if (term.isVariable()) {
- os << ProofManager::sanitize(term);
- return;
- }
-
- Kind k = term.getKind();
-
- switch(k) {
- case kind::ITE: {
- TypeNode armType = expectedType.isNull()
- ? TypeNode::fromType(term.getType())
- : expectedType;
- bool useFormulaType = term.getType().isBoolean();
- Assert(term[1].getType().isSubtypeOf(term.getType()));
- Assert(term[2].getType().isSubtypeOf(term.getType()));
- os << (useFormulaType ? "(ifte " : "(ite _ ");
-
- printBoundFormula(term[0], os, map);
- os << " ";
- if (useFormulaType)
- {
- printBoundFormula(term[1], os, map);
- }
- else
- {
- printBoundTerm(term[1], os, map, armType);
- }
- os << " ";
- if (useFormulaType)
- {
- printBoundFormula(term[2], os, map);
- }
- else
- {
- printBoundTerm(term[2], os, map, armType);
- }
- os << ")";
- return;
- }
-
- case kind::EQUAL: {
- bool booleanCase = term[0].getType().isBoolean();
- TypeNode armType = equalityType(term[0], term[1]);
-
- os << "(";
- if (booleanCase) {
- os << "iff ";
- } else {
- os << "= ";
- printSort(term[0].getType(), os);
- os << " ";
- }
-
- if (booleanCase && printsAsBool(term[0])) os << "(p_app ";
- printBoundTerm(term[0], os, map, armType);
- if (booleanCase && printsAsBool(term[0])) os << ")";
-
- os << " ";
-
- if (booleanCase && printsAsBool(term[1])) os << "(p_app ";
- printBoundTerm(term[1], os, map, armType);
- if (booleanCase && printsAsBool(term[1])) os << ") ";
- os << ")";
-
- return;
- }
-
- case kind::DISTINCT:
- {
- // Distinct nodes can have any number of chidlren.
- Assert(term.getNumChildren() >= 2);
- TypeNode armType = equalityType(term[0], term[1]);
-
- if (term.getNumChildren() == 2) {
- os << "(not (= ";
- printSort(term[0].getType(), os);
- os << " ";
- printBoundTerm(term[0], os, map, armType);
- os << " ";
- printBoundTerm(term[1], os, map, armType);
- os << "))";
- } else {
- unsigned numOfPairs = term.getNumChildren() * (term.getNumChildren() - 1) / 2;
- for (unsigned i = 1; i < numOfPairs; ++i) {
- os << "(and ";
- }
-
- for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- for (unsigned j = i + 1; j < term.getNumChildren(); ++j) {
- armType = equalityType(term[i], term[j]);
- if ((i != 0) || (j != 1)) {
- os << "(not (= ";
- printSort(term[0].getType(), os);
- os << " ";
- printBoundTerm(term[i], os, map, armType);
- os << " ";
- printBoundTerm(term[j], os, map, armType);
- os << ")))";
- } else {
- os << "(not (= ";
- printSort(term[0].getType(), os);
- os << " ";
- printBoundTerm(term[0], os, map, armType);
- os << " ";
- printBoundTerm(term[1], os, map, armType);
- os << "))";
- }
- }
- }
- }
- return;
- }
-
- default: Unhandled() << k;
- }
-}
-
-void TheoryProof::printTheoryLemmaProof(std::vector<Expr>& lemma,
- std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& map) {
- // Default method for replaying proofs: assert (negated) literals back to a fresh copy of the theory
- Assert(d_theory != NULL);
-
- context::UserContext fakeContext;
- ProofOutputChannel oc;
- theory::Valuation v(NULL);
- //make new copy of theory
- theory::Theory* th;
- Trace("pf::tp") << ";; Print theory lemma proof, theory id = " << d_theory->getId() << std::endl;
-
- if (d_theory->getId()==theory::THEORY_UF) {
- th = new theory::uf::TheoryUF(&fakeContext,
- &fakeContext,
- oc,
- v,
- ProofManager::currentPM()->getLogicInfo(),
- nullptr,
- "replay::");
- } else if (d_theory->getId()==theory::THEORY_ARRAYS) {
- th = new theory::arrays::TheoryArrays(
- &fakeContext,
- &fakeContext,
- oc,
- v,
- ProofManager::currentPM()->getLogicInfo(),
- nullptr,
- "replay::");
- } else if (d_theory->getId() == theory::THEORY_ARITH) {
- Trace("theory-proof-debug") << "Arith proofs currently not supported. Use 'trust'" << std::endl;
- os << " (clausify_false trust)";
- return;
- } else {
- InternalError() << "can't generate theory-proof for "
- << ProofManager::currentPM()->getLogic();
- }
-
- Debug("pf::tp") << "TheoryProof::printTheoryLemmaProof - calling th->ProduceProofs()" << std::endl;
- th->produceProofs();
- Debug("pf::tp") << "TheoryProof::printTheoryLemmaProof - th->ProduceProofs() DONE" << std::endl;
-
- MyPreRegisterVisitor preRegVisitor(th);
- for (unsigned i=0; i<lemma.size(); i++) {
- Node strippedLit = (lemma[i].getKind() == kind::NOT) ? lemma[i][0] : lemma[i];
- if (strippedLit.getKind() == kind::EQUAL ||
- d_theory->getId() == theory::Theory::theoryOf(strippedLit)) {
- Node lit = Node::fromExpr( lemma[i] ).negate();
- Trace("pf::tp") << "; preregistering and asserting " << lit << std::endl;
- NodeVisitor<MyPreRegisterVisitor>::run(preRegVisitor, lit);
- th->assertFact(lit, false);
- }
- }
-
- Debug("pf::tp") << "TheoryProof::printTheoryLemmaProof - calling th->check()" << std::endl;
- th->check(theory::Theory::EFFORT_FULL);
- Debug("pf::tp") << "TheoryProof::printTheoryLemmaProof - th->check() DONE" << std::endl;
-
- if(!oc.hasConflict()) {
- Trace("pf::tp") << "; conflict is null" << std::endl;
- Node lastLemma = oc.getLastLemma();
- Assert(!lastLemma.isNull());
- Trace("pf::tp") << "; ++ but got lemma: " << lastLemma << std::endl;
-
- if (lastLemma.getKind() == kind::OR) {
- Debug("pf::tp") << "OR lemma. Negating each child separately" << std::endl;
- for (unsigned i = 0; i < lastLemma.getNumChildren(); ++i) {
- if (lastLemma[i].getKind() == kind::NOT) {
- Trace("pf::tp") << "; asserting fact: " << lastLemma[i][0] << std::endl;
- th->assertFact(lastLemma[i][0], false);
- }
- else {
- Trace("pf::tp") << "; asserting fact: " << lastLemma[i].notNode() << std::endl;
- th->assertFact(lastLemma[i].notNode(), false);
- }
- }
- } else {
- Unreachable();
-
- Assert(oc.getLastLemma().getKind() == kind::NOT);
- Debug("pf::tp") << "NOT lemma" << std::endl;
- Trace("pf::tp") << "; asserting fact: " << oc.getLastLemma()[0]
- << std::endl;
- th->assertFact(oc.getLastLemma()[0], false);
- }
-
- // Trace("pf::tp") << "; ++ but got lemma: " << oc.d_lemma << std::endl;
- // Trace("pf::tp") << "; asserting " << oc.d_lemma[1].negate() << std::endl;
- // th->assertFact(oc.d_lemma[1].negate(), false);
-
- //
- th->check(theory::Theory::EFFORT_FULL);
- } else {
- Debug("pf::tp") << "Calling oc.d_proof->toStream(os)" << std::endl;
- oc.getConflictProof().toStream(os, map);
- Debug("pf::tp") << "Calling oc.d_proof->toStream(os) -- DONE!" << std::endl;
- }
-
- Debug("pf::tp") << "About to delete the theory solver used for proving the lemma... " << std::endl;
- delete th;
- Debug("pf::tp") << "About to delete the theory solver used for proving the lemma: DONE! " << std::endl;
-}
-
-bool TheoryProofEngine::supportedTheory(theory::TheoryId id) {
- return (id == theory::THEORY_ARRAYS ||
- id == theory::THEORY_ARITH ||
- id == theory::THEORY_BV ||
- id == theory::THEORY_UF ||
- id == theory::THEORY_BOOL);
-}
-
-bool TheoryProofEngine::printsAsBool(const Node &n) {
- if (!n.getType().isBoolean()) {
- return false;
- }
-
- theory::TheoryId theory_id = theory::Theory::theoryOf(n);
- return getTheoryProof(theory_id)->printsAsBool(n);
-}
-
-BooleanProof::BooleanProof(TheoryProofEngine* proofEngine)
- : TheoryProof(NULL, proofEngine)
-{}
-
-void BooleanProof::registerTerm(Expr term) {
- Assert(term.getType().isBoolean());
-
- if (term.isVariable() && d_declarations.find(term) == d_declarations.end()) {
- d_declarations.insert(term);
- return;
- }
- for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- d_proofEngine->registerTerm(term[i]);
- }
-}
-
-theory::TheoryId BooleanProof::getTheoryId() { return theory::THEORY_BOOL; }
-void LFSCBooleanProof::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap) {
- Node falseNode = NodeManager::currentNM()->mkConst(false);
- Node trueNode = NodeManager::currentNM()->mkConst(true);
-
- Assert(c1 == falseNode.toExpr() || c1 == trueNode.toExpr());
- Assert(c2 == falseNode.toExpr() || c2 == trueNode.toExpr());
- Assert(c1 != c2);
-
- if (c1 == trueNode.toExpr())
- os << "t_t_neq_f";
- else
- os << "(negsymm _ _ _ t_t_neq_f)";
-}
-
-void LFSCBooleanProof::printOwnedTermAsType(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType)
-{
- Assert(term.getType().isBoolean());
- if (term.isVariable()) {
- os << ProofManager::sanitize(term);
- return;
- }
-
- Kind k = term.getKind();
- switch(k) {
- case kind::OR:
- case kind::AND:
- if (options::lfscLetification() && term.getNumChildren() > 2) {
- // If letification is on, the entire term is probably a let expression.
- // However, we need to transform it from (and a b c) into (and a (and b c)) form first.
- Node currentExpression = term[term.getNumChildren() - 1];
- for (int i = term.getNumChildren() - 2; i >= 0; --i) {
- NodeBuilder<> builder(k);
- builder << term[i];
- builder << currentExpression.toExpr();
- currentExpression = builder;
- }
-
- // The let map should already have the current expression.
- ProofLetMap::const_iterator it = map.find(currentExpression.toExpr());
- if (it != map.end()) {
- unsigned id = it->second.id;
- unsigned count = it->second.count;
-
- if (count > LET_COUNT) {
- os << "let" << id;
- break;
- }
- }
- }
-
- // If letification is off or there were 2 children, same treatment as the other cases.
- CVC4_FALLTHROUGH;
- case kind::XOR:
- case kind::IMPLIES:
- case kind::NOT:
- // print the Boolean operators
- os << "(" << utils::toLFSCKind(k);
- if(term.getNumChildren() > 2) {
- // LFSC doesn't allow declarations with variable numbers of
- // arguments, so we have to flatten these N-ary versions.
- std::ostringstream paren;
- os << " ";
- for (unsigned i = 0; i < term.getNumChildren(); ++i) {
-
- if (printsAsBool(term[i])) os << "(p_app ";
- d_proofEngine->printBoundTerm(term[i], os, map);
- if (printsAsBool(term[i])) os << ")";
-
- os << " ";
- if(i < term.getNumChildren() - 2) {
- os << "(" << utils::toLFSCKind(k) << " ";
- paren << ")";
- }
- }
- os << paren.str() << ")";
- } else {
- // this is for binary and unary operators
- for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- os << " ";
- if (printsAsBool(term[i])) os << "(p_app ";
- d_proofEngine->printBoundTerm(term[i], os, map);
- if (printsAsBool(term[i])) os << ")";
- }
- os << ")";
- }
- return;
-
- case kind::CONST_BOOLEAN:
- os << (term.getConst<bool>() ? "true" : "false");
- return;
-
- default: Unhandled() << k;
- }
-}
-
-void LFSCBooleanProof::printOwnedSort(Type type, std::ostream& os) {
- Assert(type.isBoolean());
- os << "Bool";
-}
-
-void LFSCBooleanProof::printSortDeclarations(std::ostream& os, std::ostream& paren) {
- // Nothing to do here at this point.
-}
-
-void LFSCBooleanProof::printTermDeclarations(std::ostream& os, std::ostream& paren) {
- for (ExprSet::const_iterator it = d_declarations.begin(); it != d_declarations.end(); ++it) {
- Expr term = *it;
-
- os << "(% " << ProofManager::sanitize(term) << " (term ";
- printSort(term.getType(), os);
- os <<")\n";
- paren <<")";
- }
-}
-
-void LFSCBooleanProof::printDeferredDeclarations(std::ostream& os, std::ostream& paren) {
- // Nothing to do here at this point.
-}
-
-void LFSCBooleanProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) {
- // Nothing to do here at this point.
-}
-
-void LFSCBooleanProof::printTheoryLemmaProof(std::vector<Expr>& lemma,
- std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& map) {
- Unreachable() << "No boolean lemmas yet!";
-}
-
-bool LFSCBooleanProof::printsAsBool(const Node &n)
-{
- Kind k = n.getKind();
- switch (k) {
- case kind::BOOLEAN_TERM_VARIABLE:
- case kind::VARIABLE:
- return true;
-
- default:
- return false;
- }
-}
-
-void TheoryProof::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap) {
- // By default, we just print a trust statement. Specific theories can implement
- // better proofs.
-
- os << "(trust_f (not (= _ ";
- d_proofEngine->printBoundTerm(c1, os, globalLetMap);
- os << " ";
- d_proofEngine->printBoundTerm(c2, os, globalLetMap);
- os << ")))";
-}
-
-void TheoryProof::printRewriteProof(std::ostream& os, const Node &n1, const Node &n2) {
- // This is the default for a rewrite proof: just a trust statement.
- ProofLetMap emptyMap;
- os << "(trust_f (iff ";
- d_proofEngine->printBoundTerm(n1.toExpr(), os, emptyMap);
- os << " ";
- d_proofEngine->printBoundTerm(n2.toExpr(), os, emptyMap);
- os << "))";
-}
-
-void TheoryProof::printOwnedTerm(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType)
-{
- this->printOwnedTermAsType(term, os, map, expectedType);
-}
-
-TypeNode TheoryProof::equalityType(const Expr& left, const Expr& right)
-{
- Assert(left.getType() == right.getType())
- << "TheoryProof::equalityType(" << left << ", " << right << "):" << std::endl
- << "types disagree:" << std::endl
- << "\tleft: " << left.getType() << std::endl
- << "\tright:" << right.getType();
- return TypeNode::fromType(left.getType());
-}
-
-bool TheoryProof::match(TNode n1, TNode n2)
-{
- theory::TheoryId theoryId = this->getTheoryId();
- ProofManager* pm = ProofManager::currentPM();
- bool ufProof = (theoryId == theory::THEORY_UF);
- Debug(ufProof ? "pf::uf" : "mgd") << "match " << n1 << " " << n2 << std::endl;
- if (pm->hasOp(n1))
- {
- n1 = pm->lookupOp(n1);
- }
- if (pm->hasOp(n2))
- {
- n2 = pm->lookupOp(n2);
- }
- Debug(ufProof ? "pf::uf" : "mgd") << "+ match " << n1 << " " << n2
- << std::endl;
- if (!ufProof)
- {
- Debug("pf::array") << "+ match: step 1" << std::endl;
- }
- if (n1 == n2)
- {
- return true;
- }
-
- if (n1.getType().isFunction() && n2.hasOperator())
- {
- if (pm->hasOp(n2.getOperator()))
- {
- return n1 == pm->lookupOp(n2.getOperator());
- }
- else
- {
- return n1 == n2.getOperator();
- }
- }
-
- if (n2.getType().isFunction() && n1.hasOperator())
- {
- if (pm->hasOp(n1.getOperator()))
- {
- return n2 == pm->lookupOp(n1.getOperator());
- }
- else
- {
- return n2 == n1.getOperator();
- }
- }
-
- if (n1.hasOperator() && n2.hasOperator()
- && n1.getOperator() != n2.getOperator())
- {
- if (ufProof
- || !((n1.getKind() == kind::SELECT
- && n2.getKind() == kind::PARTIAL_SELECT_0)
- || (n1.getKind() == kind::SELECT
- && n2.getKind() == kind::PARTIAL_SELECT_1)
- || (n1.getKind() == kind::PARTIAL_SELECT_1
- && n2.getKind() == kind::SELECT)
- || (n1.getKind() == kind::PARTIAL_SELECT_1
- && n2.getKind() == kind::PARTIAL_SELECT_0)
- || (n1.getKind() == kind::PARTIAL_SELECT_0
- && n2.getKind() == kind::SELECT)
- || (n1.getKind() == kind::PARTIAL_SELECT_0
- && n2.getKind() == kind::PARTIAL_SELECT_1)))
- {
- return false;
- }
- }
-
- for (size_t i = 0; i < n1.getNumChildren() && i < n2.getNumChildren(); ++i)
- {
- if (n1[i] != n2[i])
- {
- return false;
- }
- }
-
- return true;
-}
-
-int TheoryProof::assertAndPrint(
- const theory::eq::EqProof& pf,
- const ProofLetMap& map,
- std::shared_ptr<theory::eq::EqProof> subTrans,
- theory::eq::EqProof::PrettyPrinter* pPrettyPrinter)
-{
- theory::TheoryId theoryId = getTheoryId();
- int neg = -1;
- Assert(theoryId == theory::THEORY_UF || theoryId == theory::THEORY_ARRAYS);
- bool ufProof = (theoryId == theory::THEORY_UF);
- std::string theoryName = theory::getStatsPrefix(theoryId);
- pf.debug_print(("pf::" + theoryName).c_str(), 0, pPrettyPrinter);
- Debug("pf::" + theoryName) << std::endl;
-
- Assert(pf.d_id == theory::eq::MERGED_THROUGH_TRANS);
- Assert(!pf.d_node.isNull());
- Assert(pf.d_children.size() >= 2);
-
- subTrans->d_id = theory::eq::MERGED_THROUGH_TRANS;
- subTrans->d_node = pf.d_node;
-
- size_t i = 0;
- while (i < pf.d_children.size())
- {
- // special treatment for uf and not for array
- if (ufProof
- || pf.d_children[i]->d_id != theory::eq::MERGED_THROUGH_CONGRUENCE)
- {
- pf.d_children[i]->d_node = simplifyBooleanNode(pf.d_children[i]->d_node);
- }
-
- // Look for the negative clause, with which we will form a contradiction.
- if (!pf.d_children[i]->d_node.isNull()
- && pf.d_children[i]->d_node.getKind() == kind::NOT)
- {
- Assert(neg < 0);
- (neg) = i;
- ++i;
- }
-
- // Handle congruence closures over equalities.
- else if (pf.d_children[i]->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE
- && pf.d_children[i]->d_node.isNull())
- {
- Debug("pf::" + theoryName) << "Handling congruence over equalities"
- << std::endl;
-
- // Gather the sequence of consecutive congruence closures.
- std::vector<std::shared_ptr<const theory::eq::EqProof>>
- congruenceClosures;
- unsigned count;
- Debug("pf::" + theoryName) << "Collecting congruence sequence"
- << std::endl;
- for (count = 0; i + count < pf.d_children.size()
- && pf.d_children[i + count]->d_id
- == theory::eq::MERGED_THROUGH_CONGRUENCE
- && pf.d_children[i + count]->d_node.isNull();
- ++count)
- {
- Debug("pf::" + theoryName) << "Found a congruence: " << std::endl;
- pf.d_children[i + count]->debug_print(
- ("pf::" + theoryName).c_str(), 0, pPrettyPrinter);
- congruenceClosures.push_back(pf.d_children[i + count]);
- }
-
- Debug("pf::" + theoryName)
- << "Total number of congruences found: " << congruenceClosures.size()
- << std::endl;
-
- // Determine if the "target" of the congruence sequence appears right
- // before or right after the sequence.
- bool targetAppearsBefore = true;
- bool targetAppearsAfter = true;
-
- if ((i == 0) || (i == 1 && neg == 0))
- {
- Debug("pf::" + theoryName) << "Target does not appear before"
- << std::endl;
- targetAppearsBefore = false;
- }
-
- if ((i + count >= pf.d_children.size())
- || (!pf.d_children[i + count]->d_node.isNull()
- && pf.d_children[i + count]->d_node.getKind() == kind::NOT))
- {
- Debug("pf::" + theoryName) << "Target does not appear after"
- << std::endl;
- targetAppearsAfter = false;
- }
-
- // Flow changes between uf and array
- if (ufProof)
- {
- // Assert that we have precisely at least one possible clause.
- Assert(targetAppearsBefore || targetAppearsAfter);
-
- // If both are valid, assume the one after the sequence is correct
- if (targetAppearsAfter && targetAppearsBefore)
- {
- targetAppearsBefore = false;
- }
- }
- else
- { // not a uf proof
- // Assert that we have precisely one target clause.
- Assert(targetAppearsBefore != targetAppearsAfter);
- }
-
- // Begin breaking up the congruences and ordering the equalities
- // correctly.
- std::vector<std::shared_ptr<theory::eq::EqProof>> orderedEqualities;
-
- // Insert target clause first.
- if (targetAppearsBefore)
- {
- orderedEqualities.push_back(pf.d_children[i - 1]);
- // The target has already been added to subTrans; remove it.
- subTrans->d_children.pop_back();
- }
- else
- {
- orderedEqualities.push_back(pf.d_children[i + count]);
- }
-
- // Start with the congruence closure closest to the target clause, and
- // work our way back/forward.
- if (targetAppearsBefore)
- {
- for (unsigned j = 0; j < count; ++j)
- {
- if (pf.d_children[i + j]->d_children[0]->d_id
- != theory::eq::MERGED_THROUGH_REFLEXIVITY)
- orderedEqualities.insert(orderedEqualities.begin(),
- pf.d_children[i + j]->d_children[0]);
- if (pf.d_children[i + j]->d_children[1]->d_id
- != theory::eq::MERGED_THROUGH_REFLEXIVITY)
- orderedEqualities.insert(orderedEqualities.end(),
- pf.d_children[i + j]->d_children[1]);
- }
- }
- else
- {
- for (unsigned j = 0; j < count; ++j)
- {
- if (pf.d_children[i + count - 1 - j]->d_children[0]->d_id
- != theory::eq::MERGED_THROUGH_REFLEXIVITY)
- orderedEqualities.insert(
- orderedEqualities.begin(),
- pf.d_children[i + count - 1 - j]->d_children[0]);
- if (pf.d_children[i + count - 1 - j]->d_children[1]->d_id
- != theory::eq::MERGED_THROUGH_REFLEXIVITY)
- orderedEqualities.insert(
- orderedEqualities.end(),
- pf.d_children[i + count - 1 - j]->d_children[1]);
- }
- }
-
- // Copy the result into the main transitivity proof.
- subTrans->d_children.insert(subTrans->d_children.end(),
- orderedEqualities.begin(),
- orderedEqualities.end());
-
- // Increase i to skip over the children that have been processed.
- i += count;
- if (targetAppearsAfter)
- {
- ++i;
- }
- }
-
- // Else, just copy the child proof as is
- else
- {
- subTrans->d_children.push_back(pf.d_children[i]);
- ++i;
- }
- }
-
- bool disequalityFound = (neg >= 0);
- if (!disequalityFound)
- {
- Debug("pf::" + theoryName)
- << "A disequality was NOT found. UNSAT due to merged constants"
- << std::endl;
- Debug("pf::" + theoryName) << "Proof for: " << pf.d_node << std::endl;
- Assert(pf.d_node.getKind() == kind::EQUAL);
- Assert(pf.d_node.getNumChildren() == 2);
- Assert(pf.d_node[0].isConst() && pf.d_node[1].isConst());
- }
- return neg;
-}
-
-std::pair<Node, Node> TheoryProof::identicalEqualitiesPrinterHelper(
- bool evenLengthSequence,
- bool sequenceOver,
- const theory::eq::EqProof& pf,
- const ProofLetMap& map,
- const std::string subproofStr,
- std::stringstream* outStream,
- Node n,
- Node nodeAfterEqualitySequence)
-{
- theory::TheoryId theoryId = getTheoryId();
- Assert(theoryId == theory::THEORY_UF || theoryId == theory::THEORY_ARRAYS);
- bool ufProof = (theoryId == theory::THEORY_UF);
- std::string theoryName = theory::getStatsPrefix(theoryId);
- if (evenLengthSequence)
- {
- // If the length is even, we need to apply transitivity for the "correct"
- // hand of the equality.
-
- Debug("pf::" + theoryName) << "Equality sequence of even length"
- << std::endl;
- Debug("pf::" + theoryName) << "n1 is: " << n << std::endl;
- Debug("pf::" + theoryName) << "pf-d_node is: " << pf.d_node << std::endl;
- Debug("pf::" + theoryName) << "Next node is: " << nodeAfterEqualitySequence
- << std::endl;
-
- (*outStream) << "(trans _ _ _ _ ";
-
- // If the sequence is at the very end of the transitivity proof, use
- // pf.d_node to guide us.
- if (!sequenceOver)
- {
- if (match(n[0], pf.d_node[0]))
- {
- n = n[0].eqNode(n[0]);
- (*outStream) << subproofStr << " (symm _ _ _ " << subproofStr << ")";
- }
- else if (match(n[1], pf.d_node[1]))
- {
- n = n[1].eqNode(n[1]);
- (*outStream) << " (symm _ _ _ " << subproofStr << ")" << subproofStr;
- }
- else
- {
- Debug("pf::" + theoryName) << "Error: identical equalities over, but "
- "hands don't match what we're proving."
- << std::endl;
- Assert(false);
- }
- }
- else
- {
- // We have a "next node". Use it to guide us.
- if (!ufProof && nodeAfterEqualitySequence.getKind() == kind::NOT)
- {
- nodeAfterEqualitySequence = nodeAfterEqualitySequence[0];
- }
-
- Assert(nodeAfterEqualitySequence.getKind() == kind::EQUAL);
-
- if ((n[0] == nodeAfterEqualitySequence[0])
- || (n[0] == nodeAfterEqualitySequence[1]))
- {
- // Eliminate n[1]
- (*outStream) << subproofStr << " (symm _ _ _ " << subproofStr << ")";
- n = n[0].eqNode(n[0]);
- }
- else if ((n[1] == nodeAfterEqualitySequence[0])
- || (n[1] == nodeAfterEqualitySequence[1]))
- {
- // Eliminate n[0]
- (*outStream) << " (symm _ _ _ " << subproofStr << ")" << subproofStr;
- n = n[1].eqNode(n[1]);
- }
- else
- {
- Debug("pf::" + theoryName) << "Error: even length sequence, but I "
- "don't know which hand to keep!"
- << std::endl;
- Assert(false);
- }
- }
-
- (*outStream) << ")";
- }
- else
- {
- Debug("pf::" + theoryName) << "Equality sequence length is odd!"
- << std::endl;
- (*outStream).str(subproofStr);
- }
-
- Debug("pf::" + theoryName) << "Have proven: " << n << std::endl;
- return std::make_pair<Node&, Node&>(n, nodeAfterEqualitySequence);
-}
-
-} /* namespace CVC4 */
diff --git a/src/proof/theory_proof.h b/src/proof/theory_proof.h
deleted file mode 100644
index dd5fe0326..000000000
--- a/src/proof/theory_proof.h
+++ /dev/null
@@ -1,510 +0,0 @@
-/********************* */
-/*! \file theory_proof.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Liana Hadarean, Guy Katz, Alex Ozdemir
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** [[ Add lengthier description here ]]
-
- ** \todo document this file
-
-**/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__THEORY_PROOF_H
-#define CVC4__THEORY_PROOF_H
-
-#include <iosfwd>
-#include <unordered_map>
-#include <unordered_set>
-
-#include "expr/expr.h"
-#include "expr/type_node.h"
-#include "proof/clause_id.h"
-#include "proof/proof_utils.h"
-#include "prop/sat_solver_types.h"
-#include "theory/uf/equality_engine.h"
-#include "util/proof.h"
-namespace CVC4 {
-
-namespace theory {
-class Theory;
-} /* namespace CVC4::theory */
-
-typedef std::unordered_map < ClauseId, prop::SatClause* > IdToSatClause;
-
-class TheoryProof;
-
-typedef std::unordered_set<Expr, ExprHashFunction > ExprSet;
-typedef std::map<theory::TheoryId, TheoryProof* > TheoryProofTable;
-
-typedef std::set<theory::TheoryId> TheoryIdSet;
-typedef std::map<Expr, TheoryIdSet> ExprToTheoryIds;
-
-class TheoryProofEngine {
-protected:
- ExprSet d_registrationCache;
- TheoryProofTable d_theoryProofTable;
- ExprToTheoryIds d_exprToTheoryIds;
-
- /**
- * Returns whether the theory is currently supported in proof
- * production mode.
- */
- bool supportedTheory(theory::TheoryId id);
-public:
-
- TheoryProofEngine();
- virtual ~TheoryProofEngine();
-
- /**
- * Print the theory term (could be an atom) by delegating to the proper theory.
- *
- * @param term
- * @param os
- */
- virtual void printLetTerm(Expr term, std::ostream& os) = 0;
-
- /**
- * Print a term in some (core or non-core) theory
- *
- * @param term expression representing term
- * @param os output stream
- * @param expectedType The type that this is expected to have in a parent
- * node. Null if there are no such requirements. This is useful for requesting
- * type conversions from the theory. e.g. in (5.5 == 4) the right-hand-side
- * should be converted to a real.
- *
- * The first version of this function has a default value for expectedType
- * (null) The second version is virtual.
- *
- * They are split to avoid mixing virtual function and default argument
- * values, which behave weirdly when combined.
- */
- void printBoundTerm(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType = TypeNode())
- {
- this->printBoundTermAsType(term, os, map, expectedType);
- }
- virtual void printBoundTermAsType(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType) = 0;
-
- /**
- * Print the proof representation of the given sort.
- *
- * @param os
- */
- virtual void printSort(Type type, std::ostream& os) = 0;
-
- /**
- * Go over the assertions and register all terms with the theories.
- *
- * @param os
- * @param paren closing parenthesis
- */
- virtual void registerTermsFromAssertions() = 0;
-
- /**
- * Print the theory assertions (arbitrary formulas over
- * theory atoms)
- *
- * @param os
- * @param paren closing parenthesis
- */
- virtual void printAssertions(std::ostream& os, std::ostream& paren) = 0;
- /**
- * Print variable declarations that need to appear within the proof,
- * e.g. skolemized variables.
- *
- * @param os
- * @param paren closing parenthesis
- */
- virtual void printDeferredDeclarations(std::ostream& os, std::ostream& paren) = 0;
-
- /**
- * Print aliasing declarations.
- *
- * @param os
- * @param paren closing parenthesis
- */
- virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) = 0;
-
- /**
- * Print proofs of all the theory lemmas (must prove
- * actual clause used in resolution proof).
- *
- * @param os
- * @param paren
- */
- virtual void printTheoryLemmas(const IdToSatClause& lemmas, std::ostream& os,
- std::ostream& paren, ProofLetMap& map) = 0;
-
- /**
- * Register theory atom (ensures all terms and atoms are declared).
- *
- * @param atom
- */
- void registerTerm(Expr atom);
-
- /**
- * Ensures that a theory proof class for the given theory is created.
- * This method can be invoked regardless of whether the "proof" option
- * has been set.
- *
- * @param theory
- */
- void registerTheory(theory::Theory* theory);
- /**
- * Additional configuration of the theory proof class for the given theory.
- * This method should only be invoked when the "proof" option has been set.
- *
- * @param theory
- */
- void finishRegisterTheory(theory::Theory* theory);
-
- theory::TheoryId getTheoryForLemma(const prop::SatClause* clause);
- TheoryProof* getTheoryProof(theory::TheoryId id);
-
- void markTermForFutureRegistration(Expr term, theory::TheoryId id);
-
- void printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap);
-
- /**
- * Print a term in some non-core theory
- *
- * @param term expression representing term
- * @param os output stream
- * @param expectedType The type that this is expected to have in a parent
- * node. Null if there are no such requirements. This is useful for requesting
- * type conversions from the theory. e.g. in (5.5 == 4) the right-hand-side
- * should be converted to a real.
- *
- * The first version of this function has a default value for expectedType
- * (null) The second version is virtual.
- *
- * They are split to avoid mixing virtual function and default argument
- * values, which behave weirdly when combined.
- */
- void printTheoryTerm(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType = TypeNode());
- virtual void printTheoryTermAsType(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType) = 0;
- /**
- * Calls `TheoryProof::equalityType` on the appropriate theory.
- */
- TypeNode equalityType(const Expr& left, const Expr& right);
-
- bool printsAsBool(const Node &n);
-};
-
-class LFSCTheoryProofEngine : public TheoryProofEngine {
- void bind(Expr term, ProofLetMap& map, Bindings& let_order);
-public:
- LFSCTheoryProofEngine()
- : TheoryProofEngine() {}
-
- void printTheoryTermAsType(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType) override;
-
- void registerTermsFromAssertions() override;
- void printSortDeclarations(std::ostream& os, std::ostream& paren);
- void printTermDeclarations(std::ostream& os, std::ostream& paren);
- void printCoreTerm(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType = TypeNode());
- void printLetTerm(Expr term, std::ostream& os) override;
- void printBoundTermAsType(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType) override;
- void printAssertions(std::ostream& os, std::ostream& paren) override;
- void printLemmaRewrites(NodePairSet& rewrites,
- std::ostream& os,
- std::ostream& paren);
- void printDeferredDeclarations(std::ostream& os,
- std::ostream& paren) override;
- void printAliasingDeclarations(std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& globalLetMap) override;
- void printTheoryLemmas(const IdToSatClause& lemmas,
- std::ostream& os,
- std::ostream& paren,
- ProofLetMap& map) override;
- void printSort(Type type, std::ostream& os) override;
-
- void performExtraRegistrations();
-
- void finalizeBvConflicts(const IdToSatClause& lemmas, std::ostream& os);
-
-private:
- static void dumpTheoryLemmas(const IdToSatClause& lemmas);
-
- // Prints this boolean term as a formula.
- // If necessary, it prints a wrapper converting a `Bool`-sorted term to a
- // formula.
- void printBoundFormula(Expr term, std::ostream& os, const ProofLetMap& map);
-
- // TODO: this function should be moved into the BV prover.
-
- std::map<Node, std::string> d_assertionToRewrite;
-};
-
-class TheoryProof {
-protected:
- // Pointer to the theory for this proof
- theory::Theory* d_theory;
- TheoryProofEngine* d_proofEngine;
- virtual theory::TheoryId getTheoryId() = 0;
-
- public:
- TheoryProof(theory::Theory* th, TheoryProofEngine* proofEngine)
- : d_theory(th)
- , d_proofEngine(proofEngine)
- {}
- virtual ~TheoryProof() {};
- /**
- * Print a term belonging some theory, not necessarily this one.
- *
- * @param term expresion representing term
- * @param os output stream
- */
- void printTerm(Expr term, std::ostream& os, const ProofLetMap& map) {
- d_proofEngine->printBoundTerm(term, os, map);
- }
- /**
- * Print a term belonging to THIS theory.
- *
- * @param term expression representing term
- * @param os output stream
- * @param expectedType The type that this is expected to have in a parent
- * node. Null if there are no such requirements. This is useful for requesting
- * type conversions from the theory. e.g. in (5.5 == 4) the right-hand-side
- * should be converted to a real.
- *
- * The first version of this function has a default value for expectedType
- * (null) The second version is virtual.
- *
- * They are split to avoid mixing virtual function and default argument
- * values, which behave weirdly when combined.
- */
- void printOwnedTerm(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType = TypeNode());
-
- virtual void printOwnedTermAsType(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType) = 0;
-
- /**
- * Return the type (at the SMT level, the sort) of an equality or disequality
- * between `left` and `right`.
- *
- * The default implementation asserts that the two have the same type, and
- * returns it.
- *
- * A theory may want to do something else.
- *
- * For example, the theory of arithmetic allows equalities between Reals and
- * Integers. In this case the integer is upcast to a real, and the equality
- * is over reals.
- */
- virtual TypeNode equalityType(const Expr& left, const Expr& right);
-
- /**
- * Print the proof representation of the given type that belongs to some theory.
- *
- * @param type
- * @param os
- */
- void printSort(Type type, std::ostream& os) {
- d_proofEngine->printSort(type, os);
- }
-
- // congrence matching term helper
- bool match(TNode n1, TNode n2);
-
- /**
- * Helper function for ProofUF::toStreamRecLFSC and
- * ProofArray::toStreamRecLFSC
- * Inputs:
- * - pf: equality engine proof
- * - map: A map for the let-expressions in the proof
- * - subTrans: main transitivity proof part
- * - pPrettyPrinter: optional pretty printer for sub-proofs
- * returns:
- * - the index of the contradicting node in pf.
- * */
- int assertAndPrint(
- const theory::eq::EqProof& pf,
- const ProofLetMap& map,
- std::shared_ptr<theory::eq::EqProof> subTrans,
- theory::eq::EqProof::PrettyPrinter* pPrettyPrinter = nullptr);
-
- /**
- * Helper function for ProofUF::toStreamRecLFSC and
- * ProofArray::toStreamRecLFSC
- * Inputs:
- * - evenLengthSequence: true iff the length of the sequence
- * of the identical equalities is even.
- * - sequenceOver: have we reached the last equality of this sequence?
- * - pf: equality engine proof
- * - map: A map for the let-expressions in the proof
- * - subproofStr: current stringstream content
- * - outStream: output stream to which the proof is printed
- * - n: transitivity sub-proof
- * - nodeAfterEqualitySequence: The node after the identical sequence.
- * Returns:
- * A pair of nodes, that are the updated nodes n and nodeAfterEqualitySequence
- *
- */
- std::pair<Node, Node> identicalEqualitiesPrinterHelper(
- bool evenLengthSequence,
- bool sequenceOver,
- const theory::eq::EqProof& pf,
- const ProofLetMap& map,
- const std::string subproofStr,
- std::stringstream* outStream,
- Node n,
- Node nodeAfterEqualitySequence);
-
- /**
- * Print the proof representation of the given type that belongs to THIS theory.
- *
- * @param type
- * @param os
- */
- virtual void printOwnedSort(Type type, std::ostream& os) = 0;
- /**
- * Print a proof for the theory lemmas. Must prove
- * clause representing lemmas to be used in resolution proof.
- *
- * @param os output stream
- */
- virtual void printTheoryLemmaProof(std::vector<Expr>& lemma,
- std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& map);
- /**
- * Print the sorts declarations for this theory.
- *
- * @param os
- * @param paren
- */
- virtual void printSortDeclarations(std::ostream& os, std::ostream& paren) = 0;
- /**
- * Print the term declarations for this theory.
- *
- * @param os
- * @param paren
- */
- virtual void printTermDeclarations(std::ostream& os, std::ostream& paren) = 0;
- /**
- * Print any deferred variable/sorts declarations for this theory
- * (those that need to appear inside the actual proof).
- *
- * @param os
- * @param paren
- */
- virtual void printDeferredDeclarations(std::ostream& os, std::ostream& paren) = 0;
- /**
- * Print any aliasing declarations.
- *
- * @param os
- * @param paren
- */
- virtual void printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) = 0;
- /**
- * Register a term of this theory that appears in the proof.
- *
- * @param term
- */
- virtual void registerTerm(Expr term) = 0;
- /**
- * Print a proof for the disequality of two constants that belong to this theory.
- *
- * @param term
- */
- virtual void printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap);
- /**
- * Print a proof for the equivalence of n1 and n2.
- *
- * @param term
- */
- virtual void printRewriteProof(std::ostream& os, const Node &n1, const Node &n2);
-
- /**
- * Return whether this node, when serialized as an LFSC proof, has sort `Bool`.
- *
- * This is virtual because it ultimately, theories control the serialization
- * of their proofs, so a theory will need to override this appropriately.
- *
- * This should only be called on nodes of type `Bool`.
- */
- virtual bool printsAsBool(const Node &n) {
- // Most nodes print as formulas, so this is the default.
- return false;
- }
-};
-
-class BooleanProof : public TheoryProof {
-protected:
- ExprSet d_declarations; // all the boolean variables
- theory::TheoryId getTheoryId() override;
-
- public:
- BooleanProof(TheoryProofEngine* proofEngine);
-
- void registerTerm(Expr term) override;
-};
-
-class LFSCBooleanProof : public BooleanProof {
-public:
- LFSCBooleanProof(TheoryProofEngine* proofEngine)
- : BooleanProof(proofEngine)
- {}
- void printOwnedTermAsType(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode ty) override;
- void printOwnedSort(Type type, std::ostream& os) override;
- void printTheoryLemmaProof(std::vector<Expr>& lemma,
- std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& map) override;
- void printSortDeclarations(std::ostream& os, std::ostream& paren) override;
- void printTermDeclarations(std::ostream& os, std::ostream& paren) override;
- void printDeferredDeclarations(std::ostream& os,
- std::ostream& paren) override;
- void printAliasingDeclarations(std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& globalLetMap) override;
-
- bool printsAsBool(const Node& n) override;
- void printConstantDisequalityProof(std::ostream& os,
- Expr c1,
- Expr c2,
- const ProofLetMap& globalLetMap) override;
-};
-
-} /* CVC4 namespace */
-
-#endif /* CVC4__THEORY_PROOF_H */
diff --git a/src/proof/uf_proof.cpp b/src/proof/uf_proof.cpp
deleted file mode 100644
index 74990ff44..000000000
--- a/src/proof/uf_proof.cpp
+++ /dev/null
@@ -1,759 +0,0 @@
-/********************* */
-/*! \file uf_proof.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Liana Hadarean, Guy Katz, Yoni Zohar
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** [[ Add lengthier description here ]]
-
- ** \todo document this file
-
-**/
-#include "proof/uf_proof.h"
-
-#include <stack>
-
-#include "proof/proof_manager.h"
-#include "proof/simplify_boolean_node.h"
-#include "theory/uf/theory_uf.h"
-
-namespace CVC4 {
-
-void ProofUF::toStream(std::ostream& out) const
-{
- ProofLetMap map;
- toStream(out, map);
-}
-
-void ProofUF::toStream(std::ostream& out, const ProofLetMap& map) const
-{
- Trace("theory-proof-debug") << "; Print UF proof..." << std::endl;
- //AJR : carry this further?
- toStreamLFSC(out, ProofManager::getUfProof(), *d_proof, map);
-}
-
-void ProofUF::toStreamLFSC(std::ostream& out,
- TheoryProof* tp,
- const theory::eq::EqProof& pf,
- const ProofLetMap& map)
-{
- Debug("pf::uf") << "ProofUF::toStreamLFSC starting" << std::endl;
- Debug("lfsc-uf") << "Printing uf proof in LFSC : " << std::endl;
- pf.debug_print("lfsc-uf");
- Debug("lfsc-uf") << std::endl;
- toStreamRecLFSC( out, tp, pf, 0, map );
-}
-
-Node ProofUF::toStreamRecLFSC(std::ostream& out,
- TheoryProof* tp,
- const theory::eq::EqProof& pf,
- unsigned tb,
- const ProofLetMap& map)
-{
- Debug("pf::uf") << std::endl
- << std::endl
- << "toStreamRecLFSC called. tb = " << tb
- << " . proof:" << std::endl;
- if (tb == 0)
- {
- // Special case: false was an input, so the proof is just "false".
- if (pf.d_id == theory::eq::MERGED_THROUGH_EQUALITY &&
- pf.d_node == NodeManager::currentNM()->mkConst(false)) {
- out << "(clausify_false ";
- out << ProofManager::getLitName(NodeManager::currentNM()->mkConst(false).notNode());
- out << ")" << std::endl;
- return Node();
- }
-
- std::shared_ptr<theory::eq::EqProof> subTrans =
- std::make_shared<theory::eq::EqProof>();
-
- int neg = tp->assertAndPrint(pf, map, subTrans);
-
- Node n1;
- std::stringstream ss, ss2;
- Debug("pf::uf") << "\nsubtrans has " << subTrans->d_children.size() << " children\n";
- bool disequalityFound = (neg >= 0);
-
- if(!disequalityFound || subTrans->d_children.size() >= 2) {
- n1 = toStreamRecLFSC(ss, tp, *subTrans, 1, map);
- } else {
- n1 = toStreamRecLFSC(ss, tp, *(subTrans->d_children[0]), 1, map);
- Debug("pf::uf") << "\nsubTrans unique child "
- << subTrans->d_children[0]->d_id
- << " was proven\ngot: " << n1 << std::endl;
- }
-
- Debug("pf::uf") << "\nhave proven: " << n1 << std::endl;
-
- out << "(clausify_false (contra _ ";
- if (disequalityFound) {
- Node n2 = pf.d_children[neg]->d_node;
- Assert(n2.getKind() == kind::NOT);
-
- Debug("pf::uf") << "n2 is " << n2[0] << std::endl;
-
- if (n2[0].getNumChildren() > 0)
- {
- Debug("pf::uf") << "\nn2[0]: " << n2[0][0] << std::endl;
- }
- if (n1.getNumChildren() > 1) { Debug("pf::uf") << "n1[1]: " << n1[1] << std::endl; }
-
- if(n2[0].getKind() == kind::APPLY_UF) {
- out << "(trans _ _ _ _ ";
-
- if (n1[0] == n2[0]) {
- out << "(symm _ _ _ ";
- out << ss.str();
- out << ") ";
- } else {
- Assert(n1[1] == n2[0]);
- out << ss.str();
- }
- out << "(pred_eq_f _ " << ProofManager::getLitName(n2[0]) << ")) t_t_neq_f))" << std::endl;
- } else if (n2[0].getKind() == kind::BOOLEAN_TERM_VARIABLE) {
- out << ss.str() << " " << ProofManager::getLitName(n2[0]) << "))";
- } else {
- Assert((n1[0] == n2[0][0] && n1[1] == n2[0][1])
- || (n1[1] == n2[0][0] && n1[0] == n2[0][1]));
- if(n1[1] == n2[0][0]) {
- out << "(symm _ _ _ " << ss.str() << ")";
- } else {
- out << ss.str();
- }
- out << " " << ProofManager::getLitName(n2[0]) << "))" << std::endl;
- }
- } else {
- Node n2 = pf.d_node;
- Assert(n2.getKind() == kind::EQUAL);
- Assert((n1[0] == n2[0] && n1[1] == n2[1])
- || (n1[1] == n2[0] && n1[0] == n2[1]));
-
- out << ss.str();
- out << " ";
- ProofManager::getTheoryProofEngine()->printConstantDisequalityProof(
- out, n1[0].toExpr(), n1[1].toExpr(), map);
- out << "))" << std::endl;
- }
-
- return Node();
- }
- // TODO (#2965): improve this code, which is highly complicated.
- switch(pf.d_id) {
- case theory::eq::MERGED_THROUGH_CONGRUENCE: {
- Debug("pf::uf") << "\nok, looking at congruence:\n";
- pf.debug_print("pf::uf");
- std::stack<const theory::eq::EqProof*> stk;
- for (const theory::eq::EqProof* pf2 = &pf;
- pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE;
- pf2 = pf2->d_children[0].get()) {
- Assert(!pf2->d_node.isNull());
- Assert(pf2->d_node.getKind() == kind::PARTIAL_APPLY_UF
- || pf2->d_node.getKind() == kind::BUILTIN
- || pf2->d_node.getKind() == kind::APPLY_UF
- || pf2->d_node.getKind() == kind::SELECT
- || pf2->d_node.getKind() == kind::STORE);
- Assert(pf2->d_children.size() == 2);
- out << "(cong _ _ _ _ _ _ ";
- stk.push(pf2);
- }
- Assert(stk.top()->d_children[0]->d_id
- != theory::eq::MERGED_THROUGH_CONGRUENCE);
- NodeBuilder<> b1(kind::PARTIAL_APPLY_UF), b2(kind::PARTIAL_APPLY_UF);
- const theory::eq::EqProof* pf2 = stk.top();
- stk.pop();
- Assert(pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE);
- Node n1 = toStreamRecLFSC(out, tp, *(pf2->d_children[0]), tb + 1, map);
- out << " ";
- std::stringstream ss;
- Node n2 = toStreamRecLFSC(ss, tp, *(pf2->d_children[1]), tb + 1, map);
- Debug("pf::uf") << "\nok, in FIRST cong[" << stk.size() << "]" << "\n";
- pf2->debug_print("pf::uf");
- Debug("pf::uf") << "looking at " << pf2->d_node << "\n";
- Debug("pf::uf") << " " << n1 << "\n";
- Debug("pf::uf") << " " << n2 << "\n";
- int side = 0;
- if (tp->match(pf2->d_node, n1[0]))
- {
- //if(tb == 1) {
- Debug("pf::uf") << "SIDE IS 0\n";
- //}
- side = 0;
- } else {
- //if(tb == 1) {
- Debug("pf::uf") << "SIDE IS 1\n";
- //}
- if (!tp->match(pf2->d_node, n1[1]))
- {
- Debug("pf::uf") << "IN BAD CASE, our first subproof is\n";
- pf2->d_children[0]->debug_print("pf::uf");
- }
- Assert(tp->match(pf2->d_node, n1[1]));
- side = 1;
- }
- if (n1[side].getKind() == kind::APPLY_UF
- || n1[side].getKind() == kind::PARTIAL_APPLY_UF
- || n1[side].getKind() == kind::SELECT
- || n1[side].getKind() == kind::STORE)
- {
- if (n1[side].getKind() == kind::APPLY_UF
- || n1[side].getKind() == kind::PARTIAL_APPLY_UF)
- {
- b1 << n1[side].getOperator();
- } else {
- b1 << ProofManager::currentPM()->mkOp(n1[side].getOperator());
- }
- b1.append(n1[side].begin(), n1[side].end());
- } else {
- b1 << n1[side];
- }
- if(n1[1-side].getKind() == kind::PARTIAL_APPLY_UF || n1[1-side].getKind() == kind::APPLY_UF || n1[side].getKind() == kind::SELECT || n1[side].getKind() == kind::STORE) {
- if (n1[1 - side].getKind() == kind::PARTIAL_APPLY_UF
- || n1[1 - side].getKind() == kind::APPLY_UF)
- {
- b2 << n1[1-side].getOperator();
- } else {
- b2 << ProofManager::currentPM()->mkOp(n1[1-side].getOperator());
- }
- b2.append(n1[1-side].begin(), n1[1-side].end());
- } else {
- b2 << n1[1-side];
- }
- Debug("pf::uf") << "pf2->d_node " << pf2->d_node << std::endl;
- Debug("pf::uf") << "b1.getNumChildren() " << b1.getNumChildren() << std::endl;
- Debug("pf::uf") << "n1 " << n1 << std::endl;
- Debug("pf::uf") << "n2 " << n2 << std::endl;
- Debug("pf::uf") << "side " << side << std::endl;
- if(pf2->d_node[b1.getNumChildren() - (pf2->d_node.getMetaKind() == kind::metakind::PARAMETERIZED ? 0 : 1)] == n2[side]) {
- b1 << n2[side];
- b2 << n2[1-side];
- out << ss.str();
- } else {
- Assert(pf2->d_node[b1.getNumChildren()
- - (pf2->d_node.getMetaKind()
- == kind::metakind::PARAMETERIZED
- ? 0
- : 1)]
- == n2[1 - side]);
- b1 << n2[1-side];
- b2 << n2[side];
- out << "(symm _ _ _ " << ss.str() << ")";
- }
- out << ")";
- while(!stk.empty()) {
- if(tb == 1) {
- Debug("pf::uf") << "\nMORE TO DO\n";
- }
- pf2 = stk.top();
- stk.pop();
- Assert(pf2->d_id == theory::eq::MERGED_THROUGH_CONGRUENCE);
- out << " ";
- ss.str("");
- n2 = toStreamRecLFSC(ss, tp, *(pf2->d_children[1]), tb + 1, map);
- Debug("pf::uf") << "\nok, in cong[" << stk.size() << "]" << "\n";
- Debug("pf::uf") << "looking at " << pf2->d_node << "\n";
- Debug("pf::uf") << " " << n1 << "\n";
- Debug("pf::uf") << " " << n2 << "\n";
- Debug("pf::uf") << " " << b1 << "\n";
- Debug("pf::uf") << " " << b2 << "\n";
- if(pf2->d_node[b1.getNumChildren()] == n2[side]) {
- b1 << n2[side];
- b2 << n2[1-side];
- out << ss.str();
- } else {
- Assert(pf2->d_node[b1.getNumChildren()] == n2[1 - side]);
- b1 << n2[1-side];
- b2 << n2[side];
- out << "(symm _ _ _ " << ss.str() << ")";
- }
- out << ")";
- }
- n1 = b1;
- n2 = b2;
- Debug("pf::uf") << "at end assert, got " << pf2->d_node << " and " << n1 << std::endl;
- if(pf2->d_node.getKind() == kind::PARTIAL_APPLY_UF) {
- Assert(n1 == pf2->d_node);
- }
- if(n1.getOperator().getType().getNumChildren() == n1.getNumChildren() + 1) {
- if(ProofManager::currentPM()->hasOp(n1.getOperator())) {
- b1.clear(ProofManager::currentPM()->lookupOp(n2.getOperator()).getConst<Kind>());
- } else {
- b1.clear(kind::APPLY_UF);
- b1 << n1.getOperator();
- }
- b1.append(n1.begin(), n1.end());
- n1 = b1;
- Debug("pf::uf") << "at[2] end assert, got " << pf2->d_node << " and " << n1 << std::endl;
- if(pf2->d_node.getKind() == kind::APPLY_UF) {
- Assert(n1 == pf2->d_node);
- }
- }
- if(n2.getOperator().getType().getNumChildren() == n2.getNumChildren() + 1) {
- if(ProofManager::currentPM()->hasOp(n2.getOperator())) {
- b2.clear(ProofManager::currentPM()->lookupOp(n2.getOperator()).getConst<Kind>());
- } else {
- b2.clear(kind::APPLY_UF);
- b2 << n2.getOperator();
- }
- b2.append(n2.begin(), n2.end());
- n2 = b2;
- }
- Node n = (side == 0 ? n1.eqNode(n2) : n2.eqNode(n1));
- if(tb == 1) {
- Debug("pf::uf") << "\ncong proved: " << n << "\n";
- }
- return n;
- }
-
- case theory::eq::MERGED_THROUGH_REFLEXIVITY:
- {
- Assert(!pf.d_node.isNull());
- Assert(pf.d_children.empty());
- out << "(refl _ ";
- tp->printTerm(NodeManager::currentNM()->toExpr(pf.d_node), out, map);
- out << ")";
- return pf.d_node.eqNode(pf.d_node);
- }
- case theory::eq::MERGED_THROUGH_EQUALITY:
- Assert(!pf.d_node.isNull());
- Assert(pf.d_children.empty());
- out << ProofManager::getLitName(pf.d_node.negate());
- return pf.d_node;
-
- case theory::eq::MERGED_THROUGH_TRANS: {
- Assert(!pf.d_node.isNull());
- Assert(pf.d_children.size() >= 2);
- std::stringstream ss;
- Debug("pf::uf") << "\ndoing trans proof[[\n";
- pf.debug_print("pf::uf");
- Debug("pf::uf") << "\n";
-
- pf.d_children[0]->d_node = simplifyBooleanNode(pf.d_children[0]->d_node);
-
- Node n1 = toStreamRecLFSC(ss, tp, *(pf.d_children[0]), tb + 1, map);
- Debug("pf::uf") << "\ndoing trans proof, got n1 " << n1 << "\n";
- if(tb == 1) {
- Debug("pf::uf") << "\ntrans proof[0], got n1 " << n1 << "\n";
- }
-
- bool identicalEqualities = false;
- bool evenLengthSequence;
- std::stringstream dontCare;
- Node nodeAfterEqualitySequence =
- toStreamRecLFSC(dontCare, tp, *(pf.d_children[0]), tb + 1, map);
-
- std::map<size_t, Node> childToStream;
- std::pair<Node, Node> nodePair;
- for(size_t i = 1; i < pf.d_children.size(); ++i) {
- std::stringstream ss1(ss.str()), ss2;
- ss.str("");
-
- pf.d_children[i]->d_node = simplifyBooleanNode(pf.d_children[i]->d_node);
-
- // It is possible that we've already converted the i'th child to stream.
- // If so,
- // use previously stored result. Otherwise, convert and store.
- Node n2;
- if (childToStream.find(i) != childToStream.end())
- n2 = childToStream[i];
- else
- {
- n2 = toStreamRecLFSC(ss2, tp, *(pf.d_children[i]), tb + 1, map);
- childToStream[i] = n2;
- }
-
- // The following branch is dedicated to handling sequences of identical
- // equalities,
- // i.e. trans[ a=b, a=b, a=b ].
- //
- // There are two cases:
- // 1. The number of equalities is odd. Then, the sequence can be
- // collapsed to just one equality,
- // i.e. a=b.
- // 2. The number of equalities is even. Now, we have two options: a=a
- // or b=b. To determine this,
- // we look at the node after the equality sequence. If it needs a,
- // we go for a=a; and if it needs
- // b, we go for b=b. If there is no following node, we look at the
- // goal of the transitivity proof,
- // and use it to determine which option we need.
- if (n2.getKind() == kind::EQUAL)
- {
- if (((n1[0] == n2[0]) && (n1[1] == n2[1]))
- || ((n1[0] == n2[1]) && (n1[1] == n2[0])))
- {
- // We are in a sequence of identical equalities
-
- Debug("pf::uf") << "Detected identical equalities: " << std::endl
- << "\t" << n1 << std::endl;
-
- if (!identicalEqualities)
- {
- // The sequence of identical equalities has started just now
- identicalEqualities = true;
-
- Debug("pf::uf")
- << "The sequence is just beginning. Determining length..."
- << std::endl;
-
- // Determine whether the length of this sequence is odd or even.
- evenLengthSequence = true;
- bool sequenceOver = false;
- size_t j = i + 1;
-
- while (j < pf.d_children.size() && !sequenceOver)
- {
- std::stringstream ignore;
- nodeAfterEqualitySequence =
- toStreamRecLFSC(ignore, tp, *(pf.d_children[j]), tb + 1, map);
-
- if (((nodeAfterEqualitySequence[0] == n1[0])
- && (nodeAfterEqualitySequence[1] == n1[1]))
- || ((nodeAfterEqualitySequence[0] == n1[1])
- && (nodeAfterEqualitySequence[1] == n1[0])))
- {
- evenLengthSequence = !evenLengthSequence;
- }
- else
- {
- sequenceOver = true;
- }
-
- ++j;
- }
-
- nodePair =
- tp->identicalEqualitiesPrinterHelper(evenLengthSequence,
- sequenceOver,
- pf,
- map,
- ss1.str(),
- &ss,
- n1,
- nodeAfterEqualitySequence);
- n1 = nodePair.first;
- nodeAfterEqualitySequence = nodePair.second;
- } else {
- ss.str(ss1.str());
- }
-
- // Ignore the redundancy.
- continue;
- }
- }
-
- if (identicalEqualities) {
- // We were in a sequence of identical equalities, but it has now ended. Resume normal operation.
- identicalEqualities = false;
- }
-
- Debug("pf::uf") << "\ndoing trans proof, got n2 " << n2 << "\n";
- if(tb == 1) {
- Debug("pf::uf") << "\ntrans proof[" << i << "], got n2 " << n2 << "\n";
- Debug("pf::uf") << (n2.getKind() == kind::EQUAL) << "\n";
-
- if ((n1.getNumChildren() >= 2) && (n2.getNumChildren() >= 2)) {
- Debug("pf::uf") << n1[0].getId() << " " << n1[1].getId() << " / " << n2[0].getId() << " " << n2[1].getId() << "\n";
- Debug("pf::uf") << n1[0].getId() << " " << n1[0] << "\n";
- Debug("pf::uf") << n1[1].getId() << " " << n1[1] << "\n";
- Debug("pf::uf") << n2[0].getId() << " " << n2[0] << "\n";
- Debug("pf::uf") << n2[1].getId() << " " << n2[1] << "\n";
- Debug("pf::uf") << (n1[0] == n2[0]) << "\n";
- Debug("pf::uf") << (n1[1] == n2[1]) << "\n";
- Debug("pf::uf") << (n1[0] == n2[1]) << "\n";
- Debug("pf::uf") << (n1[1] == n2[0]) << "\n";
- }
- }
-
- ss << "(trans _ _ _ _ ";
-
- if(n2.getKind() == kind::EQUAL && n1.getKind() == kind::EQUAL)
- // Both elements of the transitivity rule are equalities/iffs
- {
- if(n1[0] == n2[0]) {
- if(tb == 1) { Debug("pf::uf") << "case 1\n"; }
- n1 = n1[1].eqNode(n2[1]);
- ss << "(symm _ _ _ " << ss1.str() << ") " << ss2.str();
- } else if(n1[1] == n2[1]) {
- if(tb == 1) { Debug("pf::uf") << "case 2\n"; }
- n1 = n1[0].eqNode(n2[0]);
- ss << ss1.str() << " (symm _ _ _ " << ss2.str() << ")";
- } else if(n1[0] == n2[1]) {
- if(tb == 1) { Debug("pf::uf") << "case 3\n"; }
- n1 = n2[0].eqNode(n1[1]);
- ss << ss2.str() << " " << ss1.str();
- if(tb == 1) { Debug("pf::uf") << "++ proved " << n1 << "\n"; }
- } else if(n1[1] == n2[0]) {
- if(tb == 1) { Debug("pf::uf") << "case 4\n"; }
- n1 = n1[0].eqNode(n2[1]);
- ss << ss1.str() << " " << ss2.str();
- } else {
- Warning() << "\n\ntrans proof failure at step " << i << "\n\n";
- Warning() << "0 proves " << n1 << "\n";
- Warning() << "1 proves " << n2 << "\n\n";
- pf.debug_print("pf::uf",0);
- //toStreamRec(Warning.getStream(), pf, 0);
- Warning() << "\n\n";
- Unreachable();
- }
- Debug("pf::uf") << "++ trans proof[" << i << "], now have " << n1 << std::endl;
- } else if(n1.getKind() == kind::EQUAL) {
- // n1 is an equality/iff, but n2 is a predicate
- if(n1[0] == n2) {
- n1 = n1[1].eqNode(NodeManager::currentNM()->mkConst(true));
- ss << "(symm _ _ _ " << ss1.str() << ") (pred_eq_t _ " << ss2.str() << ")";
- } else if(n1[1] == n2) {
- n1 = n1[0].eqNode(NodeManager::currentNM()->mkConst(true));
- ss << ss1.str() << " (pred_eq_t _ " << ss2.str() << ")";
- } else {
- Unreachable();
- }
- } else if(n2.getKind() == kind::EQUAL) {
- // n2 is an equality/iff, but n1 is a predicate
- if(n2[0] == n1) {
- n1 = n2[1].eqNode(NodeManager::currentNM()->mkConst(true));
- ss << "(symm _ _ _ " << ss2.str() << ") (pred_eq_t _ " << ss1.str() << ")";
- } else if(n2[1] == n1) {
- n1 = n2[0].eqNode(NodeManager::currentNM()->mkConst(true));
- ss << ss2.str() << " (pred_eq_t _ " << ss1.str() << ")";
- } else {
- Unreachable();
- }
- } else {
- // Both n1 and n2 are predicates.
- // We want to prove b1 = b2, and we know that ((b1), (b2)) or ((not b1), (not b2))
- if (n1.getKind() == kind::NOT) {
- Assert(n2.getKind() == kind::NOT);
- Assert(pf.d_node[0] == n1[0] || pf.d_node[0] == n2[0]);
- Assert(pf.d_node[1] == n1[0] || pf.d_node[1] == n2[0]);
- Assert(n1[0].getKind() == kind::BOOLEAN_TERM_VARIABLE);
- Assert(n2[0].getKind() == kind::BOOLEAN_TERM_VARIABLE);
-
- if (pf.d_node[0] == n1[0]) {
- ss << "(false_preds_equal _ _ " << ss1.str() << " " << ss2.str() << ") ";
- ss << "(pred_refl_neg _ " << ss2.str() << ")";
- } else {
- ss << "(false_preds_equal _ _ " << ss2.str() << " " << ss1.str() << ") ";
- ss << "(pred_refl_neg _ " << ss1.str() << ")";
- }
- n1 = pf.d_node;
-
- } else if (n1.getKind() == kind::BOOLEAN_TERM_VARIABLE) {
- Assert(n2.getKind() == kind::BOOLEAN_TERM_VARIABLE);
- Assert(pf.d_node[0] == n1 || pf.d_node[0] == n2);
- Assert(pf.d_node[1] == n1 || pf.d_node[2] == n2);
-
- if (pf.d_node[0] == n1) {
- ss << "(true_preds_equal _ _ " << ss1.str() << " " << ss2.str() << ") ";
- ss << "(pred_refl_pos _ " << ss2.str() << ")";
- } else {
- ss << "(true_preds_equal _ _ " << ss2.str() << " " << ss1.str() << ") ";
- ss << "(pred_refl_pos _ " << ss1.str() << ")";
- }
- n1 = pf.d_node;
-
- } else {
-
- Unreachable();
- }
- }
-
- ss << ")";
- }
- out << ss.str();
- Debug("pf::uf") << "\n++ trans proof done, have proven " << n1 << std::endl;
- return n1;
- }
-
- default:
- Assert(!pf.d_node.isNull());
- Assert(pf.d_children.empty());
- Debug("pf::uf") << "theory proof: " << pf.d_node << " by rule " << int(pf.d_id) << std::endl;
- AlwaysAssert(false);
- return pf.d_node;
- }
-}
-
-UFProof::UFProof(theory::uf::TheoryUF* uf, TheoryProofEngine* pe)
- : TheoryProof(uf, pe)
-{}
-
-theory::TheoryId UFProof::getTheoryId() { return theory::THEORY_UF; }
-void UFProof::registerTerm(Expr term) {
- // already registered
- if (d_declarations.find(term) != d_declarations.end())
- return;
-
- Type type = term.getType();
- if (type.isSort()) {
- // declare uninterpreted sorts
- d_sorts.insert(type);
- }
-
- if (term.getKind() == kind::APPLY_UF) {
- Expr function = term.getOperator();
- d_declarations.insert(function);
- }
-
- if (term.isVariable()) {
- d_declarations.insert(term);
-
-
- if (term.getKind() == kind::BOOLEAN_TERM_VARIABLE) {
- // Ensure cnf literals
- Node asNode(term);
- ProofManager::currentPM()->ensureLiteral(
- asNode.eqNode(NodeManager::currentNM()->mkConst(true)));
- ProofManager::currentPM()->ensureLiteral(
- asNode.eqNode(NodeManager::currentNM()->mkConst(false)));
- }
- }
-
- // recursively declare all other terms
- for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- // could belong to other theories
- d_proofEngine->registerTerm(term[i]);
- }
-}
-
-void LFSCUFProof::printOwnedTermAsType(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType)
-{
- Node node = Node::fromExpr(term);
- Debug("pf::uf") << std::endl << "(pf::uf) LFSCUfProof::printOwnedTerm: term = " << node << std::endl;
-
- Assert(theory::Theory::theoryOf(node) == theory::THEORY_UF);
-
- if (node.getKind() == kind::VARIABLE ||
- node.getKind() == kind::SKOLEM ||
- node.getKind() == kind::BOOLEAN_TERM_VARIABLE) {
- os << node;
- return;
- }
-
- Assert(node.getKind() == kind::APPLY_UF);
-
- if(node.getType().isBoolean()) {
- os << "(p_app ";
- }
- Node func = node.getOperator();
- for (unsigned i = 0; i < term.getNumChildren(); ++i) {
- os << "(apply _ _ ";
- }
- os << func << " ";
- Assert(func.getType().isFunction());
- std::vector<TypeNode> argsTypes = node.getOperator().getType().getArgTypes();
- for (unsigned i = 0; i < node.getNumChildren(); ++i) {
-
- bool convertToBool = (node[i].getType().isBoolean() && !d_proofEngine->printsAsBool(node[i]));
- if (convertToBool) os << "(f_to_b ";
- d_proofEngine->printBoundTerm(term[i], os, map, argsTypes[i]);
- if (convertToBool) os << ")";
- os << ")";
- }
- if(term.getType().isBoolean()) {
- os << ")";
- }
-}
-
-void LFSCUFProof::printOwnedSort(Type type, std::ostream& os) {
- Debug("pf::uf") << std::endl << "(pf::uf) LFSCArrayProof::printOwnedSort: type is: " << type << std::endl;
-
- Assert(type.isSort());
- os << type;
-}
-
-void LFSCUFProof::printTheoryLemmaProof(std::vector<Expr>& lemma, std::ostream& os, std::ostream& paren, const ProofLetMap& map) {
- os << " ;; UF Theory Lemma \n;;";
- for (unsigned i = 0; i < lemma.size(); ++i) {
- os << lemma[i] <<" ";
- }
- os <<"\n";
- //os << " (clausify_false trust)";
- UFProof::printTheoryLemmaProof(lemma, os, paren, map);
-}
-
-void LFSCUFProof::printSortDeclarations(std::ostream& os, std::ostream& paren) {
- for (TypeSet::const_iterator it = d_sorts.begin(); it != d_sorts.end(); ++it) {
- if (!ProofManager::currentPM()->wasPrinted(*it)) {
- os << "(% " << *it << " sort\n";
- paren << ")";
- ProofManager::currentPM()->markPrinted(*it);
- }
- }
-}
-
-void LFSCUFProof::printTermDeclarations(std::ostream& os, std::ostream& paren) {
- // declaring the terms
- Debug("pf::uf") << "LFSCUFProof::printTermDeclarations called" << std::endl;
-
- for (ExprSet::const_iterator it = d_declarations.begin(); it != d_declarations.end(); ++it) {
- Expr term = *it;
-
- os << "(% " << ProofManager::sanitize(term) << " ";
- os << "(term ";
-
- Type type = term.getType();
- if (type.isFunction()) {
- std::ostringstream fparen;
- FunctionType ftype = (FunctionType)type;
- std::vector<Type> args = ftype.getArgTypes();
- args.push_back(ftype.getRangeType());
- os << "(arrow";
- for (unsigned i = 0; i < args.size(); i++) {
- Type arg_type = args[i];
- os << " ";
- d_proofEngine->printSort(arg_type, os);
- if (i < args.size() - 2) {
- os << " (arrow";
- fparen << ")";
- }
- }
- os << fparen.str() << "))\n";
- } else {
- Assert(term.isVariable());
- os << type << ")\n";
- }
- paren << ")";
- }
-
- Debug("pf::uf") << "LFSCUFProof::printTermDeclarations done" << std::endl;
-}
-
-void LFSCUFProof::printDeferredDeclarations(std::ostream& os, std::ostream& paren) {
- // Nothing to do here at this point.
-}
-
-void LFSCUFProof::printAliasingDeclarations(std::ostream& os, std::ostream& paren, const ProofLetMap &globalLetMap) {
- // Nothing to do here at this point.
-}
-
-bool LFSCUFProof::printsAsBool(const Node &n) {
- if (n.getKind() == kind::BOOLEAN_TERM_VARIABLE)
- return true;
-
- return false;
-}
-
-void LFSCUFProof::printConstantDisequalityProof(std::ostream& os, Expr c1, Expr c2, const ProofLetMap &globalLetMap) {
- Node falseNode = NodeManager::currentNM()->mkConst(false);
- Node trueNode = NodeManager::currentNM()->mkConst(true);
-
- Assert(c1 == falseNode.toExpr() || c1 == trueNode.toExpr());
- Assert(c2 == falseNode.toExpr() || c2 == trueNode.toExpr());
- Assert(c1 != c2);
-
- if (c1 == trueNode.toExpr())
- os << "t_t_neq_f";
- else
- os << "(symm _ _ _ t_t_neq_f)";
-}
-
-} /* namespace CVC4 */
diff --git a/src/proof/uf_proof.h b/src/proof/uf_proof.h
deleted file mode 100644
index 647359a87..000000000
--- a/src/proof/uf_proof.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/********************* */
-/*! \file uf_proof.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Mathias Preiner, Liana Hadarean, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief UF proof
- **
- ** UF proof
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__UF__PROOF_H
-#define CVC4__UF__PROOF_H
-
-#include <memory>
-#include <unordered_set>
-
-#include "expr/expr.h"
-#include "proof/theory_proof.h"
-#include "theory/uf/equality_engine.h"
-#include "util/proof.h"
-
-namespace CVC4 {
-
-// proof object outputted by TheoryUF
-class ProofUF : public Proof
-{
- public:
- ProofUF(std::shared_ptr<theory::eq::EqProof> pf) : d_proof(pf) {}
- void toStream(std::ostream& out) const override;
- void toStream(std::ostream& out, const ProofLetMap& map) const override;
-
- private:
- static void toStreamLFSC(std::ostream& out, TheoryProof* tp,
- const theory::eq::EqProof& pf,
- const ProofLetMap& map);
- static Node toStreamRecLFSC(std::ostream& out, TheoryProof* tp,
- const theory::eq::EqProof& pf, unsigned tb,
- const ProofLetMap& map);
-
- // it is simply an equality engine proof
- std::shared_ptr<theory::eq::EqProof> d_proof;
-};
-
-namespace theory {
-namespace uf {
-class TheoryUF;
-}
-}
-
-typedef std::unordered_set<Type, TypeHashFunction > TypeSet;
-
-
-class UFProof : public TheoryProof {
-protected:
- TypeSet d_sorts; // all the uninterpreted sorts in this theory
- ExprSet d_declarations; // all the variable/function declarations
- theory::TheoryId getTheoryId() override;
-
- public:
- UFProof(theory::uf::TheoryUF* uf, TheoryProofEngine* proofEngine);
-
- void registerTerm(Expr term) override;
-};
-
-class LFSCUFProof : public UFProof {
-public:
- LFSCUFProof(theory::uf::TheoryUF* uf, TheoryProofEngine* proofEngine)
- : UFProof(uf, proofEngine)
- {}
- void printOwnedTermAsType(Expr term,
- std::ostream& os,
- const ProofLetMap& map,
- TypeNode expectedType) override;
- void printOwnedSort(Type type, std::ostream& os) override;
- void printTheoryLemmaProof(std::vector<Expr>& lemma,
- std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& map) override;
- void printSortDeclarations(std::ostream& os, std::ostream& paren) override;
- void printTermDeclarations(std::ostream& os, std::ostream& paren) override;
- void printDeferredDeclarations(std::ostream& os,
- std::ostream& paren) override;
- void printAliasingDeclarations(std::ostream& os,
- std::ostream& paren,
- const ProofLetMap& globalLetMap) override;
-
- bool printsAsBool(const Node& n) override;
-
- void printConstantDisequalityProof(std::ostream& os,
- Expr c1,
- Expr c2,
- const ProofLetMap& globalLetMap) override;
-};
-
-
-}/* CVC4 namespace */
-
-#endif /* CVC4__UF__PROOF_H */
diff --git a/src/proof/unsat_core.cpp b/src/proof/unsat_core.cpp
index e54d976c9..dd470b299 100644
--- a/src/proof/unsat_core.cpp
+++ b/src/proof/unsat_core.cpp
@@ -5,13 +5,11 @@
** Morgan Deters, Clark Barrett, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
** \brief Representation of unsat cores
- **
- ** Representation of unsat cores.
**/
#include "proof/unsat_core.h"
@@ -20,15 +18,28 @@
#include "expr/expr_iomanip.h"
#include "options/base_options.h"
#include "printer/printer.h"
-#include "smt/command.h"
#include "smt/smt_engine_scope.h"
namespace CVC4 {
-void UnsatCore::initMessage() const {
+UnsatCore::UnsatCore(const std::vector<Node>& core)
+ : d_useNames(false), d_core(core), d_names()
+{
Debug("core") << "UnsatCore size " << d_core.size() << std::endl;
}
+UnsatCore::UnsatCore(std::vector<std::string>& names)
+ : d_useNames(true), d_core(), d_names(names)
+{
+ Debug("core") << "UnsatCore (names) size " << d_names.size() << std::endl;
+}
+
+const std::vector<Node>& UnsatCore::getCore() const { return d_core; }
+const std::vector<std::string>& UnsatCore::getCoreNames() const
+{
+ return d_names;
+}
+
UnsatCore::const_iterator UnsatCore::begin() const {
return d_core.begin();
}
@@ -38,8 +49,6 @@ UnsatCore::const_iterator UnsatCore::end() const {
}
void UnsatCore::toStream(std::ostream& out) const {
- Assert(d_smt != NULL);
- smt::SmtScope smts(d_smt);
expr::ExprDag::Scope scope(out, false);
Printer::getPrinter(options::outputLanguage())->toStream(out, *this);
}
diff --git a/src/proof/unsat_core.h b/src/proof/unsat_core.h
index c0dd36ea5..fb3401876 100644
--- a/src/proof/unsat_core.h
+++ b/src/proof/unsat_core.h
@@ -5,17 +5,14 @@
** Morgan Deters, Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
+ ** \brief Representation of unsat cores.
**/
-#include "cvc4_public.h"
+#include "cvc4_private.h"
#ifndef CVC4__UNSAT_CORE_H
#define CVC4__UNSAT_CORE_H
@@ -23,52 +20,54 @@
#include <iosfwd>
#include <vector>
-#include "expr/expr.h"
+#include "expr/node.h"
namespace CVC4 {
-class SmtEngine;
-class UnsatCore;
-
-std::ostream& operator<<(std::ostream& out, const UnsatCore& core) CVC4_PUBLIC;
-
-class CVC4_PUBLIC UnsatCore {
- friend std::ostream& operator<<(std::ostream&, const UnsatCore&);
-
- /** The SmtEngine we're associated with */
- SmtEngine* d_smt;
-
- std::vector<Expr> d_core;
-
- void initMessage() const;
-
-public:
- UnsatCore() : d_smt(NULL) {}
-
- UnsatCore(SmtEngine* smt, std::vector<Expr> core) : d_smt(smt), d_core(core) {
- initMessage();
- }
-
+/**
+ * An unsat core, which can optionally be initialized as a list of names
+ * or as a list of formulas.
+ */
+class UnsatCore
+{
+ public:
+ UnsatCore() {}
+ /** Initialize using assertions */
+ UnsatCore(const std::vector<Node>& core);
+ /** Initialize using assertion names */
+ UnsatCore(std::vector<std::string>& names);
~UnsatCore() {}
- /** get the smt engine that this unsat core is hooked up to */
- SmtEngine* getSmtEngine() const { return d_smt; }
+ /** Whether we are using names for this unsat core */
+ bool useNames() const { return d_useNames; }
+ /** Get the assertions in the unsat core */
+ const std::vector<Node>& getCore() const;
+ /** Get their names */
+ const std::vector<std::string>& getCoreNames() const;
- size_t size() const { return d_core.size(); }
-
- typedef std::vector<Expr>::const_iterator iterator;
- typedef std::vector<Expr>::const_iterator const_iterator;
+ typedef std::vector<Node>::const_iterator iterator;
+ typedef std::vector<Node>::const_iterator const_iterator;
const_iterator begin() const;
const_iterator end() const;
-
- /** prints this UnsatCore object to the stream out.
- * We use the expression names stored in the SmtEngine d_smt
- */
+
+ /**
+ * prints this UnsatCore object to the stream out.
+ */
void toStream(std::ostream& out) const;
+ private:
+ /** Whether we are using names for this unsat core */
+ bool d_useNames;
+ /** The unsat core */
+ std::vector<Node> d_core;
+ /** The names of assertions in the above core */
+ std::vector<std::string> d_names;
};/* class UnsatCore */
+/** Print the unsat core to stream out */
+std::ostream& operator<<(std::ostream& out, const UnsatCore& core);
+
}/* CVC4 namespace */
#endif /* CVC4__UNSAT_CORE_H */
diff --git a/src/prop/bv_sat_solver_notify.h b/src/prop/bv_sat_solver_notify.h
index 6569c0394..e1b964adf 100644
--- a/src/prop/bv_sat_solver_notify.h
+++ b/src/prop/bv_sat_solver_notify.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Alex Ozdemir, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/prop/bvminisat/bvminisat.cpp b/src/prop/bvminisat/bvminisat.cpp
index c1aac33be..fd2215c89 100644
--- a/src/prop/bvminisat/bvminisat.cpp
+++ b/src/prop/bvminisat/bvminisat.cpp
@@ -5,7 +5,7 @@
** Liana Hadarean, Dejan Jovanovic, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,7 +18,6 @@
#include "prop/bvminisat/simp/SimpSolver.h"
#include "proof/clause_id.h"
-#include "proof/sat_proof.h"
#include "util/statistics_registry.h"
namespace CVC4 {
@@ -66,7 +65,6 @@ ClauseId BVMinisatSatSolver::addClause(SatClause& clause,
// }
ClauseId clause_id = ClauseIdError;
d_minisat->addClause(minisat_clause, clause_id);
- THEORY_PROOF(Assert(clause_id != ClauseIdError););
return clause_id;
}
@@ -76,14 +74,14 @@ SatValue BVMinisatSatSolver::propagate() {
void BVMinisatSatSolver::addMarkerLiteral(SatLiteral lit) {
d_minisat->addMarkerLiteral(BVMinisat::var(toMinisatLit(lit)));
- markUnremovable(lit);
+ markUnremovable(lit);
}
void BVMinisatSatSolver::explain(SatLiteral lit, std::vector<SatLiteral>& explanation) {
std::vector<BVMinisat::Lit> minisat_explanation;
d_minisat->explain(toMinisatLit(lit), minisat_explanation);
for (unsigned i = 0; i < minisat_explanation.size(); ++i) {
- explanation.push_back(toSatLiteral(minisat_explanation[i]));
+ explanation.push_back(toSatLiteral(minisat_explanation[i]));
}
}
@@ -104,12 +102,6 @@ void BVMinisatSatSolver::popAssumption() {
d_minisat->popAssumption();
}
-void BVMinisatSatSolver::setResolutionProofLog(
- proof::ResolutionBitVectorProof* bvp)
-{
- d_minisat->setProofLog( bvp );
-}
-
SatVariable BVMinisatSatSolver::newVar(bool isTheoryAtom, bool preRegister, bool canErase){
return d_minisat->newVar(true, true, !canErase);
}
@@ -148,9 +140,7 @@ SatValue BVMinisatSatSolver::solve(long unsigned int& resource){
return result;
}
-bool BVMinisatSatSolver::ok() const {
- return d_minisat->okay();
-}
+bool BVMinisatSatSolver::ok() const { return d_minisat->okay(); }
void BVMinisatSatSolver::getUnsatCore(SatClause& unsatCore) {
// TODO add assertion to check the call was after an unsat call
@@ -160,11 +150,11 @@ void BVMinisatSatSolver::getUnsatCore(SatClause& unsatCore) {
}
SatValue BVMinisatSatSolver::value(SatLiteral l){
- return toSatLiteralValue(d_minisat->value(toMinisatLit(l)));
+ return toSatLiteralValue(d_minisat->value(toMinisatLit(l)));
}
SatValue BVMinisatSatSolver::modelValue(SatLiteral l){
- return toSatLiteralValue(d_minisat->modelValue(toMinisatLit(l)));
+ return toSatLiteralValue(d_minisat->modelValue(toMinisatLit(l)));
}
void BVMinisatSatSolver::unregisterVar(SatLiteral lit) {
@@ -309,17 +299,3 @@ void BVMinisatSatSolver::Statistics::init(BVMinisat::SimpSolver* minisat){
} /* namespace CVC4::prop */
} /* namespace CVC4 */
-
-namespace CVC4 {
-template<>
-prop::SatLiteral toSatLiteral< BVMinisat::Solver>(BVMinisat::Solver::TLit lit) {
- return prop::BVMinisatSatSolver::toSatLiteral(lit);
-}
-
-template<>
-void toSatClause< BVMinisat::Solver> (const BVMinisat::Solver::TClause& minisat_cl,
- prop::SatClause& sat_cl) {
- prop::BVMinisatSatSolver::toSatClause(minisat_cl, sat_cl);
-}
-
-}
diff --git a/src/prop/bvminisat/bvminisat.h b/src/prop/bvminisat/bvminisat.h
index 01a0a518e..e5ac41143 100644
--- a/src/prop/bvminisat/bvminisat.h
+++ b/src/prop/bvminisat/bvminisat.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Liana Hadarean, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,8 +21,6 @@
#include <memory>
#include "context/cdo.h"
-#include "proof/clause_id.h"
-#include "proof/resolution_bitvector_proof.h"
#include "prop/bv_sat_solver_notify.h"
#include "prop/bvminisat/simp/SimpSolver.h"
#include "prop/sat_solver.h"
@@ -57,8 +55,8 @@ class BVMinisatSatSolver : public BVSatSolverInterface,
}
};
- std::unique_ptr<BVMinisat::SimpSolver> d_minisat;
- std::unique_ptr<MinisatNotify> d_minisatNotify;
+ std::unique_ptr<BVMinisat::SimpSolver> d_minisat;
+ std::unique_ptr<MinisatNotify> d_minisatNotify;
unsigned d_assertionsCount;
context::CDO<unsigned> d_assertionsRealCount;
@@ -79,6 +77,7 @@ public:
ClauseId addXorClause(SatClause& clause, bool rhs, bool removable) override
{
Unreachable() << "Minisat does not support native XOR reasoning";
+ return ClauseIdError;
}
SatValue propagate() override;
@@ -123,8 +122,6 @@ public:
void popAssumption() override;
- void setResolutionProofLog(proof::ResolutionBitVectorProof* bvp) override;
-
private:
/* Disable the default constructor. */
BVMinisatSatSolver() = delete;
diff --git a/src/prop/bvminisat/core/Solver.cc b/src/prop/bvminisat/core/Solver.cc
index 84ab62fd8..704ea0e20 100644
--- a/src/prop/bvminisat/core/Solver.cc
+++ b/src/prop/bvminisat/core/Solver.cc
@@ -29,11 +29,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
#include "base/output.h"
#include "options/bv_options.h"
#include "options/smt_options.h"
-#include "proof/clause_id.h"
-#include "proof/proof_manager.h"
-#include "proof/resolution_bitvector_proof.h"
-#include "proof/sat_proof.h"
-#include "proof/sat_proof_implementation.h"
#include "prop/bvminisat/mtl/Sort.h"
#include "theory/interrupted.h"
#include "util/utility.h"
@@ -170,8 +165,7 @@ Solver::Solver(CVC4::context::Context* context)
,
conflict_budget(-1),
propagation_budget(-1),
- asynch_interrupt(false),
- d_bvp(NULL)
+ asynch_interrupt(false)
{
// Create the constant variables
varTrue = newVar(true, false);
@@ -220,7 +214,7 @@ bool Solver::addClause_(vec<Lit>& ps, ClauseId& id)
if (decisionLevel() > 0) {
cancelUntil(0);
}
-
+
if (!ok) {
id = ClauseIdUndef;
return false;
@@ -231,7 +225,7 @@ bool Solver::addClause_(vec<Lit>& ps, ClauseId& id)
sort(ps);
Lit p; int i, j;
int falseLiteralsCount = 0;
-
+
for (i = j = 0, p = lit_Undef; i < ps.size(); i++) {
// tautologies are ignored
if (value(ps[i]) == l_True || ps[i] == ~p) {
@@ -245,82 +239,30 @@ bool Solver::addClause_(vec<Lit>& ps, ClauseId& id)
}
if (value(ps[i]) == l_False) {
- if (!THEORY_PROOF_ON())
- continue;
- ++falseLiteralsCount;
+ continue;
}
ps[j++] = p = ps[i];
}
-
+
ps.shrink(i - j);
clause_added = true;
- Assert(falseLiteralsCount == 0 || THEORY_PROOF_ON());
-
if(falseLiteralsCount == 0) {
if (ps.size() == 0) {
- Assert(!THEORY_PROOF_ON());
return ok = false;
}
else if (ps.size() == 1){
- if(d_bvp){ id = d_bvp->getSatProof()->registerUnitClause(ps[0], INPUT);}
uncheckedEnqueue(ps[0]);
CRef confl_ref = propagate();
ok = (confl_ref == CRef_Undef);
- if(d_bvp){ if (!ok) d_bvp->getSatProof()->finalizeProof(confl_ref); }
return ok;
} else {
CRef cr = ca.alloc(ps, false);
clauses.push(cr);
attachClause(cr);
- if(d_bvp){ id = d_bvp->getSatProof()->registerClause(cr, INPUT);}
- }
- return ok;
- }
-
- if (falseLiteralsCount != 0 && THEORY_PROOF_ON()) {
- // we are in a conflicting state
- if (ps.size() == falseLiteralsCount && falseLiteralsCount == 1) {
- if(d_bvp){ id = d_bvp->getSatProof()->storeUnitConflict(ps[0], INPUT); }
- if(d_bvp){ d_bvp->getSatProof()->finalizeProof(CVC4::BVMinisat::CRef_Lazy); }
- return ok = false;
- }
-
- assign_lt lt(*this);
- sort(ps, lt);
-
- CRef cr = ca.alloc(ps, false);
- clauses.push(cr);
- attachClause(cr);
-
- if(d_bvp){id = d_bvp->getSatProof()->registerClause(cr, INPUT);}
-
- if(ps.size() == falseLiteralsCount) {
- if(d_bvp){ d_bvp->getSatProof()->finalizeProof(cr); }
- return ok = false;
- }
-
- // Check if it propagates
- if (ps.size() == falseLiteralsCount + 1) {
- Clause& cl = ca[cr];
-
- Assert(value(cl[0]) == l_Undef);
- uncheckedEnqueue(cl[0], cr);
- Assert(cl.size() > 1);
- CRef confl = propagate();
- ok = (confl == CRef_Undef);
- if(!ok) {
- if(d_bvp){
- if(ca[confl].size() == 1) {
- id = d_bvp->getSatProof()->storeUnitConflict(ca[confl][0], LEARNT);
- d_bvp->getSatProof()->finalizeProof(CVC4::BVMinisat::CRef_Lazy);
- } else {
- d_bvp->getSatProof()->finalizeProof(confl);
- }
- }
- }
}
+ return ok;
}
return ok;
}
@@ -338,9 +280,6 @@ void Solver::attachClause(CRef cr) {
void Solver::detachClause(CRef cr, bool strict) {
const Clause& clause = ca[cr];
- if (d_bvp)
- {
- d_bvp->getSatProof()->markDeleted(cr); }
assert(clause.size() > 1);
@@ -425,23 +364,24 @@ Lit Solver::pickBranchLit()
return next == var_Undef ? lit_Undef : mkLit(next, rnd_pol ? drand(random_seed) < 0.5 : polarity[next]);
}
-
/*_________________________________________________________________________________________________
|
-| analyze : (confl : Clause*) (out_learnt : vec<Lit>&) (out_btlevel : int&) -> [void]
-|
+| analyze : (confl : Clause*) (out_learnt : vec<Lit>&) (out_btlevel : int&) ->
+[void]
+|
| Description:
| Analyze conflict and produce a reason clause.
-|
+|
| Pre-conditions:
| * 'out_learnt' is assumed to be cleared.
| * Current decision level must be greater than root level.
-|
+|
| Post-conditions:
| * 'out_learnt[0]' is the asserting literal at level 'out_btlevel'.
-| * If out_learnt.size() > 1 then 'out_learnt[1]' has the greatest decision level of the
-| rest of literals. There may be others from the same level though.
-|
+| * If out_learnt.size() > 1 then 'out_learnt[1]' has the greatest decision
+level of the | rest of literals. There may be others from the same level
+though.
+|
|________________________________________________________________________________________________@*/
void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip)
{
@@ -454,8 +394,6 @@ void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip
int index = trail.size() - 1;
bool done = false;
-
- if(d_bvp){ d_bvp->getSatProof()->startResChain(confl); }
do{
assert(confl != CRef_Undef); // (otherwise should be UIP)
@@ -477,13 +415,6 @@ void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip
out_learnt.push(q);
}
- if (level(var(q)) == 0)
- {
- if (d_bvp)
- {
- d_bvp->getSatProof()->resolveOutUnit(q);
- }
- }
}
// Select next clause to look at:
@@ -493,10 +424,6 @@ void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip
seen[var(p)] = 0;
pathC--;
- if ( pathC > 0 && confl != CRef_Undef ) {
- if(d_bvp){ d_bvp->getSatProof()->addResolutionStep(p, confl, sign(p));}
- }
-
switch (uip) {
case UIP_FIRST:
done = pathC == 0;
@@ -536,13 +463,6 @@ void Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel, UIP uip
// Literal is not redundant
out_learnt[j++] = out_learnt[i1];
}
- else
- {
- if (d_bvp)
- {
- d_bvp->getSatProof()->storeLitRedundant(out_learnt[i1]);
- }
- }
}
}
}else if (ccmin_mode == 1){
@@ -640,10 +560,10 @@ bool Solver::litRedundant(Lit p, uint32_t abstract_levels)
return true;
}
-/**
+/**
* Specialized analyzeFinal procedure where we test the consistency
* of the assumptions before backtracking bellow the assumption level.
- *
+ *
* @param p the original uip (may be unit)
* @param confl_clause the conflict clause
* @param out_conflict the conflict in terms of assumptions we are building
@@ -653,14 +573,14 @@ void Solver::analyzeFinal2(Lit p, CRef confl_clause, vec<Lit>& out_conflict) {
assert (decisionLevel() == assumptions.size());
assert (level(var(p)) == assumptions.size());
- out_conflict.clear();
-
+ out_conflict.clear();
+
Clause& cl = ca[confl_clause];
for (int i = 0; i < cl.size(); ++i) {
seen[var(cl[i])] = 1;
}
- int end = options::proof() ? 0 : trail_lim[0];
+ int end = trail_lim[0];
for (int i = trail.size() - 1; i >= end; i--) {
Var x = var(trail[i]);
if (seen[x]) {
@@ -670,44 +590,31 @@ void Solver::analyzeFinal2(Lit p, CRef confl_clause, vec<Lit>& out_conflict) {
if (marker[x] == 2) {
assert (level(x) > 0);
out_conflict.push(~trail[i]);
- } else {
- if(d_bvp){d_bvp->getSatProof()->resolveOutUnit(~(trail[i])); }
}
- } else {
- if(d_bvp){d_bvp->getSatProof()->resolveOutUnit(~p);}
}
} else {
Clause& clause = ca[reason(x)];
- if(d_bvp){d_bvp->getSatProof()->addResolutionStep(trail[i],reason(x), sign(trail[i]));}
for (int j = 1; j < clause.size(); j++)
{
if (level(var(clause[j])) > 0) seen[var(clause[j])] = 1;
- if(d_bvp){
- if (level(var(clause[j])) == 0)
- {
- d_bvp->getSatProof()->resolveOutUnit(clause[j]);
- seen[var(clause[j])] =
- 0; // we don't need to resolve it out again
- }
- }
}
}
seen[x] = 0;
}
- assert (seen[x] == 0);
+ assert(seen[x] == 0);
}
- assert (out_conflict.size());
+ assert(out_conflict.size());
}
/*_________________________________________________________________________________________________
|
| analyzeFinal : (p : Lit) -> [void]
-|
+|
| Description:
-| Specialized analysis procedure to express the final conflict in terms of assumptions.
-| Calculates the (possibly empty) set of assumptions that led to the assignment of 'p', and
-| stores the result in 'out_conflict'.
+| Specialized analysis procedure to express the final conflict in terms of
+assumptions. | Calculates the (possibly empty) set of assumptions that led to
+the assignment of 'p', and | stores the result in 'out_conflict'.
|________________________________________________________________________________________________@*/
void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict)
{
@@ -716,22 +623,14 @@ void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict)
out_conflict.push(p);
}
- if(d_bvp){
- if (level(var(p)) == 0 && d_bvp->isAssumptionConflict()) {
- Assert(marker[var(p)] == 2);
- if (reason(var(p)) == CRef_Undef) {
- d_bvp->startBVConflict(p);
- }
- }
- }
-
- if (decisionLevel() == 0 && !options::proof()) {
+ if (decisionLevel() == 0)
+ {
return;
}
seen[var(p)] = 1;
- int end = options::proof() ? 0 : trail_lim[0];
-
+ int end = trail_lim[0];
+
for (int i = trail.size()-1; i >= end; i--){
Var x = var(trail[i]);
if (seen[x]) {
@@ -744,26 +643,12 @@ void Solver::analyzeFinal(Lit p, vec<Lit>& out_conflict)
}
} else {
Clause& clause = ca[reason(x)];
- if(d_bvp){
- if (d_bvp->isAssumptionConflict() &&
- trail[i] == p) {
- d_bvp->startBVConflict(reason(x));
- } else {
- d_bvp->getSatProof()->addResolutionStep(trail[i], reason(x), sign(trail[i]));
- }
- }
for (int j = 1; j < clause.size(); j++)
{
if (level(var(clause[j])) > 0)
{
seen[var(clause[j])] = 1;
}
- if(d_bvp){
- if (level(var(clause[j])) == 0)
- {
- d_bvp->getSatProof()->resolveOutUnit(clause[j]);
- }
- }
}
}
seen[x] = 0;
@@ -805,10 +690,9 @@ lbool Solver::propagateAssumptions() {
lbool Solver::assertAssumption(Lit p, bool propagate) {
// TODO need to somehow mark the assumption as unit in the current context?
// it's not always unit though, but this would be useful for debugging
-
+
// assert(marker[var(p)] == 1);
-
if (decisionLevel() > assumptions.size()) {
cancelUntil(assumptions.size());
}
@@ -829,9 +713,9 @@ lbool Solver::assertAssumption(Lit p, bool propagate) {
// run the propagation
if (propagate) {
only_bcp = true;
- ccmin_mode = 0;
+ ccmin_mode = 0;
lbool result = search(-1);
- return result;
+ return result;
} else {
return l_True;
}
@@ -841,18 +725,16 @@ void Solver::addMarkerLiteral(Var var) {
// make sure it wasn't already marked
Assert(marker[var] == 0);
marker[var] = 1;
- if(d_bvp){d_bvp->getSatProof()->registerAssumption(var);}
}
-
/*_________________________________________________________________________________________________
|
| propagate : [void] -> [Clause*]
-|
+|
| Description:
-| Propagates all enqueued facts. If a conflict arises, the conflicting clause is returned,
-| otherwise CRef_Undef.
-|
+| Propagates all enqueued facts. If a conflict arises, the conflicting clause
+is returned, | otherwise CRef_Undef.
+|
| Post-conditions:
| * the propagation queue is empty, even if there was a conflict.
|________________________________________________________________________________________________@*/
@@ -920,20 +802,24 @@ CRef Solver::propagate()
return confl;
}
-
/*_________________________________________________________________________________________________
|
| reduceDB : () -> [void]
-|
+|
| Description:
-| Remove half of the learnt clauses, minus the clauses locked by the current assignment. Locked
-| clauses are clauses that are reason to some assignment. Binary clauses are never removed.
+| Remove half of the learnt clauses, minus the clauses locked by the current
+assignment. Locked | clauses are clauses that are reason to some assignment.
+Binary clauses are never removed.
|________________________________________________________________________________________________@*/
-struct reduceDB_lt {
- ClauseAllocator& ca;
- reduceDB_lt(ClauseAllocator& ca_) : ca(ca_) {}
- bool operator () (CRef x, CRef y) {
- return ca[x].size() > 2 && (ca[y].size() == 2 || ca[x].activity() < ca[y].activity()); }
+struct reduceDB_lt
+{
+ ClauseAllocator& ca;
+ reduceDB_lt(ClauseAllocator& ca_) : ca(ca_) {}
+ bool operator()(CRef x, CRef y)
+ {
+ return ca[x].size() > 2
+ && (ca[y].size() == 2 || ca[x].activity() < ca[y].activity());
+ }
};
void Solver::reduceDB()
{
@@ -963,14 +849,6 @@ void Solver::removeSatisfied(vec<CRef>& cs)
Clause& clause = ca[cs[i]];
if (satisfied(clause))
{
- if (locked(clause))
- {
- // store a resolution of the literal clause propagated
- if (d_bvp)
- {
- d_bvp->getSatProof()->storeUnitResolution(clause[0]);
- }
- }
removeClause(cs[i]);
}
else
@@ -989,14 +867,14 @@ void Solver::rebuildOrderHeap()
order_heap.build(vs);
}
-
/*_________________________________________________________________________________________________
|
| simplify : [void] -> [bool]
-|
+|
| Description:
-| Simplify the clause database according to the current top-level assigment. Currently, the only
-| thing done here is the removal of satisfied clauses, but more things can be put here.
+| Simplify the clause database according to the current top-level assigment.
+Currently, the only | thing done here is the removal of satisfied clauses,
+but more things can be put here.
|________________________________________________________________________________________________@*/
bool Solver::simplify()
{
@@ -1008,6 +886,8 @@ bool Solver::simplify()
if (nAssigns() == simpDB_assigns || (simpDB_props > 0))
return true;
+ d_notify->spendResource(ResourceManager::Resource::BvSatSimplifyStep);
+
// Remove satisfied clauses:
removeSatisfied(learnts);
if (remove_satisfied) // Can be turned off.
@@ -1021,19 +901,19 @@ bool Solver::simplify()
return true;
}
-
/*_________________________________________________________________________________________________
|
| search : (nof_conflicts : int) (params : const SearchParams&) -> [lbool]
-|
+|
| Description:
-| Search for a model the specified number of conflicts.
+| Search for a model the specified number of conflicts.
| NOTE! Use negative value for 'nof_conflicts' indicate infinity.
-|
+|
| Output:
-| 'l_True' if a partial assigment that is consistent with respect to the clauseset is found. If
-| all variables are decision variables, this means that the clause set is satisfiable. 'l_False'
-| if the clause set is unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached.
+| 'l_True' if a partial assigment that is consistent with respect to the
+clauseset is found. If | all variables are decision variables, this means
+that the clause set is satisfiable. 'l_False' | if the clause set is
+unsatisfiable. 'l_Undef' if the bound on number of conflicts is reached.
|________________________________________________________________________________________________@*/
lbool Solver::search(int nof_conflicts, UIP uip)
{
@@ -1044,6 +924,7 @@ lbool Solver::search(int nof_conflicts, UIP uip)
starts++;
for (;;){
+ d_notify->safePoint(ResourceManager::Resource::BvSatPropagateStep);
CRef confl = propagate();
if (confl != CRef_Undef){
// CONFLICT
@@ -1051,7 +932,6 @@ lbool Solver::search(int nof_conflicts, UIP uip)
if (decisionLevel() == 0) {
// can this happen for bv?
- if(d_bvp){ d_bvp->getSatProof()->finalizeProof(confl);}
return l_False;
}
@@ -1067,59 +947,34 @@ lbool Solver::search(int nof_conflicts, UIP uip)
learnts.push(cr);
attachClause(cr);
claBumpActivity(ca[cr]);
- if(d_bvp){
- ClauseId id = d_bvp->getSatProof()->registerClause(cr, LEARNT);
- PSTATS(
- std::unordered_set<int> cl_levels;
- for (int i = 0; i < learnt_clause.size(); ++i) {
- cl_levels.insert(level(var(learnt_clause[i])));
- }
- if( d_bvp ){ d_bvp->getSatProof()->storeClauseGlue(id, cl_levels.size()); }
- )
- d_bvp->getSatProof()->endResChain(id);
- }
}
-
+
if (learnt_clause.size() == 1) {
// learning a unit clause
- if(d_bvp){ d_bvp->getSatProof()->endResChain(learnt_clause[0]);}
}
-
+
// if the uip was an assumption we are unsat
if (level(var(p)) <= assumptions.size()) {
for (int i = 0; i < learnt_clause.size(); ++i) {
- assert (level(var(learnt_clause[i])) <= decisionLevel());
+ assert(level(var(learnt_clause[i])) <= decisionLevel());
seen[var(learnt_clause[i])] = 1;
}
- // Starting new resolution chain for bit-vector proof
- if( d_bvp ){
- if (cr == CRef_Undef) {
- d_bvp->startBVConflict(learnt_clause[0]);
- }
- else {
- d_bvp->startBVConflict(cr);
- }
- }
analyzeFinal(p, conflict);
- if(d_bvp){ d_bvp->endBVConflict(conflict); }
Debug("bvminisat::search") << OUTPUT_TAG << " conflict on assumptions " << std::endl;
return l_False;
}
if (!CVC4::options::bvEagerExplanations()) {
- // check if uip leads to a conflict
+ // check if uip leads to a conflict
if (backtrack_level < assumptions.size()) {
cancelUntil(assumptions.size());
uncheckedEnqueue(p, cr);
-
+
CRef new_confl = propagate();
if (new_confl != CRef_Undef) {
// we have a conflict we now need to explain it
- // TODO: proof for analyzeFinal2
- if(d_bvp){ d_bvp->startBVConflict(new_confl); }
analyzeFinal2(p, new_confl, conflict);
- if(d_bvp){ d_bvp->endBVConflict(conflict); }
return l_False;
}
}
@@ -1127,8 +982,7 @@ lbool Solver::search(int nof_conflicts, UIP uip)
cancelUntil(backtrack_level);
uncheckedEnqueue(p, cr);
-
-
+
varDecayActivity();
claDecayActivity();
@@ -1138,10 +992,17 @@ lbool Solver::search(int nof_conflicts, UIP uip)
max_learnts *= learntsize_inc;
if (verbosity >= 1)
- printf("| %9d | %7d %8d %8d | %8d %8d %6.0f | %6.3f %% |\n",
- (int)conflicts,
- (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]), nClauses(), (int)clauses_literals,
- (int)max_learnts, nLearnts(), (double)learnts_literals/nLearnts(), progressEstimate()*100);
+ printf("| %9d | %7d %8d %8d | %8d %8d %6.0f | %6.3f %% |\n",
+ (int)conflicts,
+ (int)dec_vars
+ - (trail_lim.size() == 0 ? trail.size()
+ : trail_lim[0]),
+ nClauses(),
+ (int)clauses_literals,
+ (int)max_learnts,
+ nLearnts(),
+ (double)learnts_literals / nLearnts(),
+ progressEstimate() * 100);
}
}else{
@@ -1152,9 +1013,9 @@ lbool Solver::search(int nof_conflicts, UIP uip)
withinBudget(ResourceManager::Resource::BvSatConflictsStep);
}
catch (const CVC4::theory::Interrupted& e) {
- // do some clean-up and rethrow
- cancelUntil(assumptions.size());
- throw e;
+ // do some clean-up and rethrow
+ cancelUntil(assumptions.size());
+ throw e;
}
if ((decisionLevel() > assumptions.size() && nof_conflicts >= 0
@@ -1192,10 +1053,8 @@ lbool Solver::search(int nof_conflicts, UIP uip)
newDecisionLevel();
}else if (value(p) == l_False){
marker[var(p)] = 2;
-
- if(d_bvp){ d_bvp->markAssumptionConflict(); }
+
analyzeFinal(~p, conflict);
- if(d_bvp){ d_bvp->endBVConflict(conflict); }
Debug("bvminisat::search") << OUTPUT_TAG << " assumption false, we're unsat" << std::endl;
return l_False;
}else{
@@ -1283,7 +1142,7 @@ lbool Solver::solve_()
conflict.clear();
ccmin_mode = 0;
-
+
if (!ok) return l_False;
solves++;
@@ -1324,31 +1183,20 @@ lbool Solver::solve_()
//=================================================================================================
// Bitvector propagations
-//
+//
void Solver::explain(Lit p, std::vector<Lit>& explanation) {
Debug("bvminisat::explain") << OUTPUT_TAG << "starting explain of " << p << std::endl;
// top level fact, no explanation necessary
if (level(var(p)) == 0) {
- if(d_bvp){
- // the only way a marker variable is
- if (reason(var(p)) == CRef_Undef) {
- d_bvp->startBVConflict(p);
- vec<Lit> confl;
- confl.push(p);
- d_bvp->endBVConflict(confl);
- return;
- }
- }
- if (!THEORY_PROOF_ON())
- return;
+ return;
}
-
+
seen[var(p)] = 1;
// if we are called at decisionLevel = 0 trail_lim is empty
- int bottom = options::proof() ? 0 : trail_lim[0];
+ int bottom = trail_lim[0];
for (int i = trail.size()-1; i >= bottom; i--){
Var x = var(trail[i]);
if (seen[x]) {
@@ -1358,21 +1206,12 @@ void Solver::explain(Lit p, std::vector<Lit>& explanation) {
explanation.push_back(trail[i]);
} else {
Assert(level(x) == 0);
- if(d_bvp){ d_bvp->getSatProof()->resolveOutUnit(~(trail[i])); }
}
-
} else {
Clause& clause = ca[reason(x)];
- if(d_bvp){
- if (p == trail[i]) {
- d_bvp->startBVConflict(reason(var(p)));
- } else {
- d_bvp->getSatProof()->addResolutionStep(trail[i], reason(x), sign(trail[i]));
- }
- }
for (int j = 1; j < clause.size(); j++)
{
- if (level(var(clause[j])) > 0 || options::proof())
+ if (level(var(clause[j])) > 0)
{
seen[var(clause[j])] = 1;
}
@@ -1382,28 +1221,11 @@ void Solver::explain(Lit p, std::vector<Lit>& explanation) {
}
}
seen[var(p)] = 0;
-
- if(d_bvp){
- vec<Lit> conflict_clause;
- conflict_clause.push(p);
- for(unsigned i = 0; i < explanation.size(); ++i) {
- conflict_clause.push(~explanation[i]);
- }
- d_bvp->endBVConflict(conflict_clause);
- }
-}
-
-void Solver::setProofLog(proof::ResolutionBitVectorProof* bvp)
-{
- d_bvp = bvp;
- d_bvp->initSatProof(this);
- d_bvp->getSatProof()->registerTrueLit(mkLit(varTrue, false));
- d_bvp->getSatProof()->registerFalseLit(mkLit(varFalse, true));
}
//=================================================================================================
// Writing CNF to DIMACS:
-//
+//
// FIXME: this needs to be rewritten completely.
static Var mapVar(Var x, vec<Var>& map, Var& max)
@@ -1454,7 +1276,7 @@ void Solver::toDimacs(FILE* f, const vec<Lit>& assumps)
for (int i = 0; i < clauses.size(); i++)
if (!satisfied(ca[clauses[i]]))
cnt++;
-
+
for (int i = 0; i < clauses.size(); i++)
if (!satisfied(ca[clauses[i]])){
Clause& clause = ca[clauses[i]];
@@ -1494,8 +1316,7 @@ void Solver::relocAll(ClauseAllocator& to)
Lit p = mkLit(v, s);
// printf(" >>> RELOCING: %s%d\n", sign(p)?"-":"", var(p)+1);
vec<Watcher>& ws = watches[p];
- for (int j = 0; j < ws.size(); j++)
- ca.reloc(ws[j].cref, to, d_bvp ? d_bvp->getSatProof() : NULL);
+ for (int j = 0; j < ws.size(); j++) ca.reloc(ws[j].cref, to);
}
// All reasons:
@@ -1504,20 +1325,16 @@ void Solver::relocAll(ClauseAllocator& to)
Var v = var(trail[i]);
if (reason(v) != CRef_Undef && (ca[reason(v)].reloced() || locked(ca[reason(v)])))
- ca.reloc(vardata[v].reason, to, d_bvp ? d_bvp->getSatProof() : NULL);
+ ca.reloc(vardata[v].reason, to);
}
// All learnt:
//
- for (int i = 0; i < learnts.size(); i++)
- ca.reloc(learnts[i], to, d_bvp ? d_bvp->getSatProof() : NULL);
+ for (int i = 0; i < learnts.size(); i++) ca.reloc(learnts[i], to);
// All original:
//
- for (int i = 0; i < clauses.size(); i++)
- ca.reloc(clauses[i], to, d_bvp ? d_bvp->getSatProof() : NULL);
-
- if(d_bvp){ d_bvp->getSatProof()->finishUpdateCRef(); }
+ for (int i = 0; i < clauses.size(); i++) ca.reloc(clauses[i], to);
}
@@ -1525,33 +1342,28 @@ void Solver::garbageCollect()
{
// Initialize the next region to a size corresponding to the estimated utilization degree. This
// is not precise but should avoid some unnecessary reallocations for the new region:
- ClauseAllocator to(ca.size() - ca.wasted());
- Debug("bvminisat") << " BVMinisat::Garbage collection \n";
+ ClauseAllocator to(ca.size() - ca.wasted());
+ Debug("bvminisat") << " BVMinisat::Garbage collection \n";
relocAll(to);
if (verbosity >= 2)
- printf("| Garbage collection: %12d bytes => %12d bytes |\n",
- ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size);
+ printf(
+ "| Garbage collection: %12d bytes => %12d bytes |\n",
+ ca.size() * ClauseAllocator::Unit_Size,
+ to.size() * ClauseAllocator::Unit_Size);
to.moveTo(ca);
}
-void ClauseAllocator::reloc(CRef& cr,
- ClauseAllocator& to,
- CVC4::TSatProof<Solver>* proof)
+void ClauseAllocator::reloc(CRef& cr, ClauseAllocator& to)
{
- CRef old = cr; // save the old reference
-
Clause& c = operator[](cr);
if (c.reloced()) { cr = c.relocation(); return; }
-
+
cr = to.alloc(c, c.learnt());
c.relocate(cr);
- if (proof)
- {
- proof->updateCRef(old, cr);
- }
-
- // Copy extra data-fields:
- // (This could be cleaned-up. Generalize Clause-constructor to be applicable here instead?)
+
+ // Copy extra data-fields:
+ // (This could be cleaned-up. Generalize Clause-constructor to be applicable
+ // here instead?)
to[cr].mark(c.mark());
if (to[cr].learnt()) to[cr].activity() = c.activity();
else if (to[cr].has_extra()) to[cr].calcAbstraction();
diff --git a/src/prop/bvminisat/core/Solver.h b/src/prop/bvminisat/core/Solver.h
index 7fad72d6d..f2721c88d 100644
--- a/src/prop/bvminisat/core/Solver.h
+++ b/src/prop/bvminisat/core/Solver.h
@@ -25,7 +25,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
#include "context/context.h"
#include "proof/clause_id.h"
-#include "proof/sat_proof.h"
#include "prop/bvminisat/core/SolverTypes.h"
#include "prop/bvminisat/mtl/Alg.h"
#include "prop/bvminisat/mtl/Heap.h"
@@ -39,11 +38,6 @@ namespace BVMinisat {
class Solver;
}
-// TODO (aozdemir) replace this forward declaration with an include
-namespace proof {
-class ResolutionBitVectorProof;
-}
-
namespace BVMinisat {
/** Interface for minisat callbacks */
@@ -71,11 +65,10 @@ public:
//=================================================================================================
// Solver -- the main class:
class Solver {
- friend class CVC4::TSatProof< CVC4::BVMinisat::Solver>;
public:
typedef Var TVar;
typedef Lit TLit;
- typedef Clause TClause;
+ typedef Clause TClause;
typedef CRef TCRef;
typedef vec<Lit> TLitVec;
@@ -109,12 +102,17 @@ public:
Var trueVar() const { return varTrue; }
Var falseVar() const { return varFalse; }
-
- bool addClause (const vec<Lit>& ps, ClauseId& id); // Add a clause to the solver.
+ bool addClause(const vec<Lit>& ps,
+ ClauseId& id); // Add a clause to the solver.
bool addEmptyClause(); // Add the empty clause, making the solver contradictory.
- bool addClause (Lit p, ClauseId& id); // Add a unit clause to the solver.
- bool addClause (Lit p, Lit q, ClauseId& id); // Add a binary clause to the solver.
- bool addClause (Lit p, Lit q, Lit r, ClauseId& id); // Add a ternary clause to the solver.
+ bool addClause(Lit p, ClauseId& id); // Add a unit clause to the solver.
+ bool addClause(Lit p,
+ Lit q,
+ ClauseId& id); // Add a binary clause to the solver.
+ bool addClause(Lit p,
+ Lit q,
+ Lit r,
+ ClauseId& id); // Add a ternary clause to the solver.
bool addClause_( vec<Lit>& ps, ClauseId& id); // Add a clause to the solver without making superflous internal copy. Will
// change the passed vector 'ps'.
@@ -141,9 +139,9 @@ public:
void toDimacs (const char* file, Lit p);
void toDimacs (const char* file, Lit p, Lit q);
void toDimacs (const char* file, Lit p, Lit q, Lit r);
-
+
// Variable mode:
- //
+ //
void setPolarity (Var v, bool b); // Declare which polarity the decision heuristic should use for a variable. Requires mode 'polarity_user'.
void setDecisionVar (Var v, bool b); // Declare if a variable should be eligible for selection in the decision heuristic.
@@ -211,13 +209,12 @@ public:
void addMarkerLiteral(Var var);
- bool need_to_propagate; // true if we added new clauses, set to true in propagation
+ bool need_to_propagate; // true if we added new clauses, set to true in
+ // propagation
bool only_bcp; // solving mode in which only boolean constraint propagation is done
void setOnlyBCP (bool val) { only_bcp = val;}
void explain(Lit l, std::vector<Lit>& explanation);
- void setProofLog(CVC4::proof::ResolutionBitVectorProof* bvp);
-
protected:
// has a clause been added
@@ -293,9 +290,6 @@ public:
int64_t conflict_budget; // -1 means no budget.
int64_t propagation_budget; // -1 means no budget.
bool asynch_interrupt;
-
- //proof log
- CVC4::proof::ResolutionBitVectorProof* d_bvp;
// Main internal methods:
//
@@ -458,13 +452,15 @@ inline int Solver::nLearnts () const { return learnts.size(); }
inline int Solver::nVars () const { return vardata.size(); }
inline int Solver::nFreeVars () const { return (int)dec_vars - (trail_lim.size() == 0 ? trail.size() : trail_lim[0]); }
inline void Solver::setPolarity (Var v, bool b) { polarity[v] = b; }
-inline void Solver::setDecisionVar(Var v, bool b)
-{
- if ( b && !decision[v]) dec_vars++;
- else if (!b && decision[v]) dec_vars--;
+inline void Solver::setDecisionVar(Var v, bool b)
+{
+ if (b && !decision[v])
+ dec_vars++;
+ else if (!b && decision[v])
+ dec_vars--;
- decision[v] = b;
- insertVarOrder(v);
+ decision[v] = b;
+ insertVarOrder(v);
}
inline void Solver::setConfBudget(int64_t x){ conflict_budget = conflicts + x; }
inline void Solver::setPropBudget(int64_t x){ propagation_budget = propagations + x; }
diff --git a/src/prop/bvminisat/core/SolverTypes.h b/src/prop/bvminisat/core/SolverTypes.h
index 302db104f..cf9ce7e15 100644
--- a/src/prop/bvminisat/core/SolverTypes.h
+++ b/src/prop/bvminisat/core/SolverTypes.h
@@ -86,15 +86,14 @@ struct LitHashFunction {
const Lit lit_Undef = { -2 }; // }- Useful special constants.
const Lit lit_Error = { -1 }; // }
-
//=================================================================================================
// Lifted booleans:
//
-// NOTE: this implementation is optimized for the case when comparisons between values are mostly
-// between one variable and one constant. Some care had to be taken to make sure that gcc
-// does enough constant propagation to produce sensible code, and this appears to be somewhat
-// fragile unfortunately.
-
+// NOTE: this implementation is optimized for the case when comparisons between
+// values are mostly
+// between one variable and one constant. Some care had to be taken to
+// make sure that gcc does enough constant propagation to produce sensible
+// code, and this appears to be somewhat fragile unfortunately.
#ifndef l_True
#define l_True (lbool((uint8_t)0)) // gcc does not do constant propagation if these are real constants.
@@ -121,10 +120,12 @@ public:
bool operator != (lbool b) const { return !(*this == b); }
lbool operator ^ (bool b) const { return lbool((uint8_t)(value^(uint8_t)b)); }
- lbool operator && (lbool b) const {
- uint8_t sel = (this->value << 1) | (b.value << 3);
- uint8_t v = (0xF7F755F4 >> sel) & 3;
- return lbool(v); }
+ lbool operator&&(lbool b) const
+ {
+ uint8_t sel = (this->value << 1) | (b.value << 3);
+ uint8_t v = (0xF7F755F4 >> sel) & 3;
+ return lbool(v);
+ }
lbool operator || (lbool b) const {
uint8_t sel = (this->value << 1) | (b.value << 3);
@@ -163,14 +164,14 @@ class Clause {
header.reloced = 0;
header.size = ps.size();
- for (int i = 0; i < ps.size(); i++)
- data[i].lit = ps[i];
+ for (int i = 0; i < ps.size(); i++) data[i].lit = ps[i];
if (header.has_extra){
if (header.learnt)
- data[header.size].act = 0;
- else
- calcAbstraction(); }
+ data[header.size].act = 0;
+ else
+ calcAbstraction();
+ }
}
public:
@@ -256,9 +257,7 @@ class ClauseAllocator : public RegionAllocator<uint32_t>
RegionAllocator<uint32_t>::free(clauseWord32Size(c.size(), c.has_extra()));
}
- void reloc(CRef& cr,
- ClauseAllocator& to,
- CVC4::TSatProof<Solver>* proof = NULL);
+ void reloc(CRef& cr, ClauseAllocator& to);
};
@@ -275,7 +274,7 @@ class OccLists
public:
OccLists(const Deleted& d) : deleted(d) {}
-
+
void init (const Idx& idx){ occs.growTo(toInt(idx)+1); dirty.growTo(toInt(idx)+1, 0); }
// Vec& operator[](const Idx& idx){ return occs[toInt(idx)]; }
Vec& operator[](const Idx& idx){ return occs[toInt(idx)]; }
@@ -334,13 +333,12 @@ class CMap
typedef Map<CRef, T, CRefHash> HashTable;
HashTable map;
-
+
public:
// Size-operations:
void clear () { map.clear(); }
int size () const { return map.elems(); }
-
// Insert/Remove/Test mapping:
void insert (CRef cr, const T& t){ map.insert(cr, t); }
void growTo (CRef cr, const T& t){ map.insert(cr, t); } // NOTE: for compatibility
@@ -363,15 +361,14 @@ class CMap
printf(" --- size = %d, bucket_count = %d\n", size(), map.bucket_count()); }
};
-
/*_________________________________________________________________________________________________
|
| subsumes : (other : const Clause&) -> Lit
-|
+|
| Description:
-| Checks if clause subsumes 'other', and at the same time, if it can be used to simplify 'other'
-| by subsumption resolution.
-|
+| Checks if clause subsumes 'other', and at the same time, if it can be
+used to simplify 'other' | by subsumption resolution.
+|
| Result:
| lit_Error - No subsumption or simplification
| lit_Undef - Clause subsumes 'other'
diff --git a/src/prop/bvminisat/simp/SimpSolver.cc b/src/prop/bvminisat/simp/SimpSolver.cc
index 0c2898b03..9429e4ced 100644
--- a/src/prop/bvminisat/simp/SimpSolver.cc
+++ b/src/prop/bvminisat/simp/SimpSolver.cc
@@ -23,7 +23,6 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
#include "options/bv_options.h"
#include "options/smt_options.h"
#include "proof/clause_id.h"
-#include "proof/proof.h"
#include "prop/bvminisat/mtl/Sort.h"
#include "prop/bvminisat/utils/System.h"
@@ -64,7 +63,7 @@ SimpSolver::SimpSolver(CVC4::context::Context* context)
asymm_lits(0),
eliminated_vars(0),
elimorder(1),
- use_simplification(!PROOF_ON()),
+ use_simplification(true),
occurs(ClauseDeleted(ca)),
elim_heap(ElimLt(n_occ)),
bwdsub_assigns(0),
@@ -94,7 +93,7 @@ SimpSolver::SimpSolver(CVC4::context::Context* context)
SimpSolver::~SimpSolver()
{
- // CVC4::StatisticsRegistry::unregisterStat(&total_eliminate_time);
+ // CVC4::StatisticsRegistry::unregisterStat(&total_eliminate_time);
}
@@ -111,7 +110,7 @@ Var SimpSolver::newVar(bool sign, bool dvar, bool freeze) {
touched .push(0);
elim_heap .insert(v);
if (freeze) {
- setFrozen(v, true);
+ setFrozen(v, true);
}
}
return v;
@@ -122,7 +121,7 @@ Var SimpSolver::newVar(bool sign, bool dvar, bool freeze) {
lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp)
{
only_bcp = false;
-
+
vec<Var> extra_frozen;
lbool result = l_True;
@@ -210,13 +209,14 @@ void SimpSolver::removeClause(CRef cr)
const Clause& clause = ca[cr];
if (use_simplification)
+ {
for (int i = 0; i < clause.size(); i++)
{
n_occ[toInt(clause[i])]--;
updateElimHeap(var(clause[i]));
occurs.smudge(var(clause[i]));
}
-
+ }
Solver::removeClause(cr);
}
@@ -538,7 +538,7 @@ bool SimpSolver::eliminateVar(Var v)
for (int i = 0; i < cls.size(); i++)
(find(ca[cls[i]], mkLit(v)) ? pos : neg).push(cls[i]);
- // Check wether the increase in number of clauses stays within the allowed ('grow'). Moreover, no
+ // Check whether the increase in number of clauses stays within the allowed ('grow'). Moreover, no
// clause must exceed the limit on the maximal clause size (if it is set):
//
int cnt = 0;
@@ -546,9 +546,10 @@ bool SimpSolver::eliminateVar(Var v)
for (int i = 0; i < pos.size(); i++)
for (int j = 0; j < neg.size(); j++)
- if (merge(ca[pos[i]], ca[neg[j]], v, clause_size) &&
- (++cnt > cls.size() + grow || (clause_lim != -1 && clause_size > clause_lim)))
- return true;
+ if (merge(ca[pos[i]], ca[neg[j]], v, clause_size)
+ && (++cnt > cls.size() + grow
+ || (clause_lim != -1 && clause_size > clause_lim)))
+ return true;
// Delete and store old clauses:
eliminated[v] = true;
@@ -565,8 +566,7 @@ bool SimpSolver::eliminateVar(Var v)
mkElimClause(elimclauses, ~mkLit(v));
}
- for (int i = 0; i < cls.size(); i++)
- removeClause(cls[i]);
+ for (int i = 0; i < cls.size(); i++) removeClause(cls[i]);
// Produce clauses in cross product:
vec<Lit>& resolvent = add_tmp;
@@ -580,7 +580,7 @@ bool SimpSolver::eliminateVar(Var v)
// Free occurs list for this variable:
occurs[v].clear(true);
-
+
// Free watchers lists for this variable, if possible:
if (watches[ mkLit(v)].size() == 0) watches[ mkLit(v)].clear(true);
if (watches[~mkLit(v)].size() == 0) watches[~mkLit(v)].clear(true);
@@ -600,7 +600,7 @@ bool SimpSolver::substitute(Var v, Lit x)
eliminated[v] = true;
setDecisionVar(v, false);
const vec<CRef>& cls = occurs.lookup(v);
-
+
vec<Lit>& subst_clause = add_tmp;
for (int i = 0; i < cls.size(); i++){
Clause& clause = ca[cls[i]];
@@ -643,7 +643,7 @@ bool SimpSolver::eliminate(bool turn_off_elim)
{
// CVC4::TimerStat::CodeTimer codeTimer(total_eliminate_time);
-
+
if (!simplify())
return false;
else if (!use_simplification)
@@ -655,9 +655,12 @@ bool SimpSolver::eliminate(bool turn_off_elim)
gatherTouchedClauses();
// printf(" ## (time = %6.2f s) BWD-SUB: queue = %d, trail = %d\n", cpuTime(), subsumption_queue.size(), trail.size() - bwdsub_assigns);
- if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()) &&
- !backwardSubsumptionCheck(true)){
- ok = false; goto cleanup; }
+ if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size())
+ && !backwardSubsumptionCheck(true))
+ {
+ ok = false;
+ goto cleanup;
+ }
// Empty elim_heap and return immediately on user-interrupt:
if (asynch_interrupt){
@@ -670,7 +673,7 @@ bool SimpSolver::eliminate(bool turn_off_elim)
// printf(" ## (time = %6.2f s) ELIM: vars = %d\n", cpuTime(), elim_heap.size());
for (int cnt = 0; !elim_heap.empty(); cnt++){
Var elim = elim_heap.removeMin();
-
+
if (asynch_interrupt) break;
if (isEliminated(elim) || value(elim) != l_Undef) continue;
@@ -720,8 +723,10 @@ bool SimpSolver::eliminate(bool turn_off_elim)
}
if (verbosity >= 1 && elimclauses.size() > 0)
- printf("| Eliminated clauses: %10.2f Mb |\n",
- double(elimclauses.size() * sizeof(uint32_t)) / (1024*1024));
+ printf(
+ "| Eliminated clauses: %10.2f Mb "
+ " |\n",
+ double(elimclauses.size() * sizeof(uint32_t)) / (1024 * 1024));
return ok;
@@ -772,15 +777,17 @@ void SimpSolver::garbageCollect()
{
// Initialize the next region to a size corresponding to the estimated utilization degree. This
// is not precise but should avoid some unnecessary reallocations for the new region:
- ClauseAllocator to(ca.size() - ca.wasted());
+ ClauseAllocator to(ca.size() - ca.wasted());
cleanUpClauses();
to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields.
relocAll(to);
Solver::relocAll(to);
if (verbosity >= 2)
- printf("| Garbage collection: %12d bytes => %12d bytes |\n",
- ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size);
+ printf(
+ "| Garbage collection: %12d bytes => %12d bytes |\n",
+ ca.size() * ClauseAllocator::Unit_Size,
+ to.size() * ClauseAllocator::Unit_Size);
to.moveTo(ca);
}
diff --git a/src/prop/bvminisat/simp/SimpSolver.h b/src/prop/bvminisat/simp/SimpSolver.h
index 9d3a51c02..9907b8d72 100644
--- a/src/prop/bvminisat/simp/SimpSolver.h
+++ b/src/prop/bvminisat/simp/SimpSolver.h
@@ -54,7 +54,7 @@ class SimpSolver : public Solver {
Lit r,
ClauseId& id); // Add a ternary clause to the solver.
bool addClause_(vec<Lit>& ps, ClauseId& id);
- bool substitute(Var v, Lit x); // Replace all occurences of v with x (may
+ bool substitute(Var v, Lit x); // Replace all occurrences of v with x (may
// cause a contradiction).
// Variable mode:
diff --git a/src/prop/cadical.cpp b/src/prop/cadical.cpp
index ca447cea8..6410552ba 100644
--- a/src/prop/cadical.cpp
+++ b/src/prop/cadical.cpp
@@ -5,7 +5,7 @@
** Mathias Preiner, Andres Noetzli, Liana Hadarean
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,7 +19,6 @@
#ifdef CVC4_USE_CADICAL
#include "base/check.h"
-#include "proof/sat_proof.h"
namespace CVC4 {
namespace prop {
diff --git a/src/prop/cadical.h b/src/prop/cadical.h
index 2545d0db0..bb7b7aa9f 100644
--- a/src/prop/cadical.h
+++ b/src/prop/cadical.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Aina Niemetz, Liana Hadarean
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/prop/cnf_stream.cpp b/src/prop/cnf_stream.cpp
index a6a4b6859..7dcd3f910 100644
--- a/src/prop/cnf_stream.cpp
+++ b/src/prop/cnf_stream.cpp
@@ -5,7 +5,7 @@
** Dejan Jovanovic, Liana Hadarean, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -31,95 +31,95 @@
#include "prop/minisat/minisat.h"
#include "prop/prop_engine.h"
#include "prop/theory_proxy.h"
-#include "smt/command.h"
+#include "smt/dump.h"
+#include "smt/smt_engine.h"
+#include "printer/printer.h"
#include "smt/smt_engine_scope.h"
#include "theory/theory.h"
#include "theory/theory_engine.h"
-using namespace std;
-using namespace CVC4::kind;
-
namespace CVC4 {
namespace prop {
-CnfStream::CnfStream(SatSolver* satSolver, Registrar* registrar,
- context::Context* context, bool fullLitToNodeMap,
+CnfStream::CnfStream(SatSolver* satSolver,
+ Registrar* registrar,
+ context::Context* context,
+ OutputManager* outMgr,
+ ResourceManager* rm,
+ bool fullLitToNodeMap,
std::string name)
: d_satSolver(satSolver),
+ d_outMgr(outMgr),
d_booleanVariables(context),
d_nodeToLiteralMap(context),
d_literalToNodeMap(context),
d_fullLitToNodeMap(fullLitToNodeMap),
- d_convertAndAssertCounter(0),
d_registrar(registrar),
d_name(name),
- d_cnfProof(NULL),
- d_removable(false) {
-}
-
-TseitinCnfStream::TseitinCnfStream(SatSolver* satSolver,
- Registrar* registrar,
- context::Context* context,
- ResourceManager* rm,
- bool fullLitToNodeMap,
- std::string name)
- : CnfStream(satSolver, registrar, context, fullLitToNodeMap, name),
+ d_cnfProof(nullptr),
+ d_removable(false),
d_resourceManager(rm)
-{}
+{
+}
-void CnfStream::assertClause(TNode node, SatClause& c) {
- Debug("cnf") << "Inserting into stream " << c << " node = " << node << endl;
- if(Dump.isOn("clauses")) {
- if(c.size() == 1) {
- Dump("clauses") << AssertCommand(Expr(getNode(c[0]).toExpr()));
- } else {
+bool CnfStream::assertClause(TNode node, SatClause& c)
+{
+ Trace("cnf") << "Inserting into stream " << c << " node = " << node << "\n";
+ if (Dump.isOn("clauses") && d_outMgr != nullptr)
+ {
+ const Printer& printer = d_outMgr->getPrinter();
+ std::ostream& out = d_outMgr->getDumpOut();
+ if (c.size() == 1)
+ {
+ printer.toStreamCmdAssert(out, getNode(c[0]));
+ }
+ else
+ {
Assert(c.size() > 1);
NodeBuilder<> b(kind::OR);
- for(unsigned i = 0; i < c.size(); ++i) {
+ for (unsigned i = 0; i < c.size(); ++i)
+ {
b << getNode(c[i]);
}
Node n = b;
- Dump("clauses") << AssertCommand(Expr(n.toExpr()));
+ printer.toStreamCmdAssert(out, n);
}
}
- if (PROOF_ON() && d_cnfProof)
- {
- d_cnfProof->pushCurrentDefinition(node);
- }
-
- ClauseId clause_id = d_satSolver->addClause(c, d_removable);
- if (clause_id == ClauseIdUndef) return; // nothing to store (no clause was added)
+ ClauseId clauseId = d_satSolver->addClause(c, d_removable);
- if (PROOF_ON() && d_cnfProof)
+ if (d_cnfProof && clauseId != ClauseIdUndef)
{
- if (clause_id != ClauseIdError)
- {
- d_cnfProof->registerConvertedClause(clause_id);
- }
- d_cnfProof->popCurrentDefinition();
- };
+ d_cnfProof->registerConvertedClause(clauseId);
+ }
+ return clauseId != ClauseIdUndef;
}
-void CnfStream::assertClause(TNode node, SatLiteral a) {
+bool CnfStream::assertClause(TNode node, SatLiteral a)
+{
SatClause clause(1);
clause[0] = a;
- assertClause(node, clause);
+ return assertClause(node, clause);
}
-void CnfStream::assertClause(TNode node, SatLiteral a, SatLiteral b) {
+bool CnfStream::assertClause(TNode node, SatLiteral a, SatLiteral b)
+{
SatClause clause(2);
clause[0] = a;
clause[1] = b;
- assertClause(node, clause);
+ return assertClause(node, clause);
}
-void CnfStream::assertClause(TNode node, SatLiteral a, SatLiteral b, SatLiteral c) {
+bool CnfStream::assertClause(TNode node,
+ SatLiteral a,
+ SatLiteral b,
+ SatLiteral c)
+{
SatClause clause(3);
clause[0] = a;
clause[1] = b;
clause[2] = c;
- assertClause(node, clause);
+ return assertClause(node, clause);
}
bool CnfStream::hasLiteral(TNode n) const {
@@ -127,11 +127,12 @@ bool CnfStream::hasLiteral(TNode n) const {
return find != d_nodeToLiteralMap.end();
}
-void TseitinCnfStream::ensureLiteral(TNode n, bool noPreregistration) {
+void CnfStream::ensureLiteral(TNode n, bool noPreregistration)
+{
// These are not removable and have no proof ID
d_removable = false;
- Debug("cnf") << "ensureLiteral(" << n << ")" << endl;
+ Trace("cnf") << "ensureLiteral(" << n << ")\n";
if(hasLiteral(n)) {
SatLiteral lit = getLiteral(n);
if(!d_literalToNodeMap.contains(lit)){
@@ -171,11 +172,17 @@ void TseitinCnfStream::ensureLiteral(TNode n, bool noPreregistration) {
// non-empty and that we are not associating a bogus assertion with the
// clause. This should be ok because we use the mapping back to assertions
// for clauses from input assertions only.
- PROOF(if (d_cnfProof) { d_cnfProof->pushCurrentAssertion(Node::null()); });
+ if (d_cnfProof)
+ {
+ d_cnfProof->pushCurrentAssertion(Node::null());
+ }
lit = toCNF(n, false);
- PROOF(if (d_cnfProof) { d_cnfProof->popCurrentAssertion(); });
+ if (d_cnfProof)
+ {
+ d_cnfProof->popCurrentAssertion();
+ }
// Store backward-mappings
// These may already exist
@@ -191,20 +198,25 @@ void TseitinCnfStream::ensureLiteral(TNode n, bool noPreregistration) {
}
SatLiteral CnfStream::newLiteral(TNode node, bool isTheoryAtom, bool preRegister, bool canEliminate) {
- Debug("cnf") << d_name << "::newLiteral(" << node << ", " << isTheoryAtom << ")" << endl;
+ Trace("cnf") << d_name << "::newLiteral(" << node << ", " << isTheoryAtom
+ << ")\n"
+ << push;
Assert(node.getKind() != kind::NOT);
// Get the literal for this node
SatLiteral lit;
if (!hasLiteral(node)) {
+ Trace("cnf") << d_name << "::newLiteral: node already registered\n";
// If no literal, we'll make one
if (node.getKind() == kind::CONST_BOOLEAN) {
+ Trace("cnf") << d_name << "::newLiteral: boolean const\n";
if (node.getConst<bool>()) {
lit = SatLiteral(d_satSolver->trueVar());
} else {
lit = SatLiteral(d_satSolver->falseVar());
}
} else {
+ Trace("cnf") << d_name << "::newLiteral: new var\n";
lit = SatLiteral(d_satSolver->newVar(isTheoryAtom, preRegister, canEliminate));
}
d_nodeToLiteralMap.insert(node, lit);
@@ -227,19 +239,28 @@ SatLiteral CnfStream::newLiteral(TNode node, bool isTheoryAtom, bool preRegister
d_registrar->preRegister(node);
d_removable = backupRemovable;
}
-
// Here, you can have it
- Debug("cnf") << "newLiteral(" << node << ") => " << lit << endl;
-
+ Trace("cnf") << "newLiteral(" << node << ") => " << lit << "\n" << pop;
return lit;
}
TNode CnfStream::getNode(const SatLiteral& literal) {
- Debug("cnf") << "getNode(" << literal << ")" << endl;
- Debug("cnf") << "getNode(" << literal << ") => " << d_literalToNodeMap[literal] << endl;
+ Trace("cnf") << "getNode(" << literal << ")\n";
+ Trace("cnf") << "getNode(" << literal << ") => "
+ << d_literalToNodeMap[literal] << "\n";
return d_literalToNodeMap[literal];
}
+const CnfStream::NodeToLiteralMap& CnfStream::getTranslationCache() const
+{
+ return d_nodeToLiteralMap;
+}
+
+const CnfStream::LiteralToNodeMap& CnfStream::getNodeCache() const
+{
+ return d_literalToNodeMap;
+}
+
void CnfStream::getBooleanVariables(std::vector<TNode>& outputVariables) const {
context::CDList<TNode>::const_iterator it, it_end;
for (it = d_booleanVariables.begin(); it != d_booleanVariables.end(); ++ it) {
@@ -253,7 +274,7 @@ void CnfStream::setProof(CnfProof* proof) {
}
SatLiteral CnfStream::convertAtom(TNode node, bool noPreregistration) {
- Debug("cnf") << "convertAtom(" << node << ")" << endl;
+ Trace("cnf") << "convertAtom(" << node << ")\n";
Assert(!hasLiteral(node)) << "atom already mapped!";
@@ -262,9 +283,12 @@ SatLiteral CnfStream::convertAtom(TNode node, bool noPreregistration) {
bool preRegister = false;
// Is this a variable add it to the list
- if (node.isVar() && node.getKind()!=BOOLEAN_TERM_VARIABLE) {
+ if (node.isVar() && node.getKind() != kind::BOOLEAN_TERM_VARIABLE)
+ {
d_booleanVariables.push_back(node);
- } else {
+ }
+ else
+ {
theoryLiteral = true;
canEliminate = false;
preRegister = !noPreregistration;
@@ -283,15 +307,18 @@ SatLiteral CnfStream::getLiteral(TNode node) {
<< "Literal not in the CNF Cache: " << node << "\n";
SatLiteral literal = d_nodeToLiteralMap[node];
- Debug("cnf") << "CnfStream::getLiteral(" << node << ") => " << literal << std::endl;
+ Trace("cnf") << "CnfStream::getLiteral(" << node << ") => " << literal
+ << "\n";
return literal;
}
-SatLiteral TseitinCnfStream::handleXor(TNode xorNode) {
+SatLiteral CnfStream::handleXor(TNode xorNode)
+{
Assert(!hasLiteral(xorNode)) << "Atom already mapped!";
- Assert(xorNode.getKind() == XOR) << "Expecting an XOR expression!";
+ Assert(xorNode.getKind() == kind::XOR) << "Expecting an XOR expression!";
Assert(xorNode.getNumChildren() == 2) << "Expecting exactly 2 children!";
Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
+ Trace("cnf") << "CnfStream::handleXor(" << xorNode << ")\n";
SatLiteral a = toCNF(xorNode[0]);
SatLiteral b = toCNF(xorNode[1]);
@@ -306,11 +333,13 @@ SatLiteral TseitinCnfStream::handleXor(TNode xorNode) {
return xorLit;
}
-SatLiteral TseitinCnfStream::handleOr(TNode orNode) {
+SatLiteral CnfStream::handleOr(TNode orNode)
+{
Assert(!hasLiteral(orNode)) << "Atom already mapped!";
- Assert(orNode.getKind() == OR) << "Expecting an OR expression!";
+ Assert(orNode.getKind() == kind::OR) << "Expecting an OR expression!";
Assert(orNode.getNumChildren() > 1) << "Expecting more then 1 child!";
Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
+ Trace("cnf") << "CnfStream::handleOr(" << orNode << ")\n";
// Number of children
unsigned n_children = orNode.getNumChildren();
@@ -343,11 +372,13 @@ SatLiteral TseitinCnfStream::handleOr(TNode orNode) {
return orLit;
}
-SatLiteral TseitinCnfStream::handleAnd(TNode andNode) {
+SatLiteral CnfStream::handleAnd(TNode andNode)
+{
Assert(!hasLiteral(andNode)) << "Atom already mapped!";
- Assert(andNode.getKind() == AND) << "Expecting an AND expression!";
+ Assert(andNode.getKind() == kind::AND) << "Expecting an AND expression!";
Assert(andNode.getNumChildren() > 1) << "Expecting more than 1 child!";
Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
+ Trace("cnf") << "handleAnd(" << andNode << ")\n";
// Number of children
unsigned n_children = andNode.getNumChildren();
@@ -380,12 +411,14 @@ SatLiteral TseitinCnfStream::handleAnd(TNode andNode) {
return andLit;
}
-SatLiteral TseitinCnfStream::handleImplies(TNode impliesNode) {
+SatLiteral CnfStream::handleImplies(TNode impliesNode)
+{
Assert(!hasLiteral(impliesNode)) << "Atom already mapped!";
- Assert(impliesNode.getKind() == IMPLIES)
+ Assert(impliesNode.getKind() == kind::IMPLIES)
<< "Expecting an IMPLIES expression!";
Assert(impliesNode.getNumChildren() == 2) << "Expecting exactly 2 children!";
Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
+ Trace("cnf") << "handleImplies(" << impliesNode << ")\n";
// Convert the children to cnf
SatLiteral a = toCNF(impliesNode[0]);
@@ -406,13 +439,13 @@ SatLiteral TseitinCnfStream::handleImplies(TNode impliesNode) {
return impliesLit;
}
-
-SatLiteral TseitinCnfStream::handleIff(TNode iffNode) {
+SatLiteral CnfStream::handleIff(TNode iffNode)
+{
Assert(!hasLiteral(iffNode)) << "Atom already mapped!";
- Assert(iffNode.getKind() == EQUAL) << "Expecting an EQUAL expression!";
+ Assert(iffNode.getKind() == kind::EQUAL) << "Expecting an EQUAL expression!";
Assert(iffNode.getNumChildren() == 2) << "Expecting exactly 2 children!";
-
- Debug("cnf") << "handleIff(" << iffNode << ")" << endl;
+ Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
+ Trace("cnf") << "handleIff(" << iffNode << ")\n";
// Convert the children to CNF
SatLiteral a = toCNF(iffNode[0]);
@@ -438,23 +471,14 @@ SatLiteral TseitinCnfStream::handleIff(TNode iffNode) {
return iffLit;
}
-
-SatLiteral TseitinCnfStream::handleNot(TNode notNode) {
- Assert(!hasLiteral(notNode)) << "Atom already mapped!";
- Assert(notNode.getKind() == NOT) << "Expecting a NOT expression!";
- Assert(notNode.getNumChildren() == 1) << "Expecting exactly 1 child!";
-
- SatLiteral notLit = ~toCNF(notNode[0]);
-
- return notLit;
-}
-
-SatLiteral TseitinCnfStream::handleIte(TNode iteNode) {
- Assert(iteNode.getKind() == ITE);
+SatLiteral CnfStream::handleIte(TNode iteNode)
+{
+ Assert(!hasLiteral(iteNode)) << "Atom already mapped!";
+ Assert(iteNode.getKind() == kind::ITE);
Assert(iteNode.getNumChildren() == 3);
Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
-
- Debug("cnf") << "handleIte(" << iteNode[0] << " " << iteNode[1] << " " << iteNode[2] << ")" << endl;
+ Trace("cnf") << "handleIte(" << iteNode[0] << " " << iteNode[1] << " "
+ << iteNode[2] << ")\n";
SatLiteral condLit = toCNF(iteNode[0]);
SatLiteral thenLit = toCNF(iteNode[1]);
@@ -485,69 +509,52 @@ SatLiteral TseitinCnfStream::handleIte(TNode iteNode) {
return iteLit;
}
-
-SatLiteral TseitinCnfStream::toCNF(TNode node, bool negated) {
- Debug("cnf") << "toCNF(" << node << ", negated = " << (negated ? "true" : "false") << ")" << endl;
-
+SatLiteral CnfStream::toCNF(TNode node, bool negated)
+{
+ Trace("cnf") << "toCNF(" << node
+ << ", negated = " << (negated ? "true" : "false") << ")\n";
SatLiteral nodeLit;
Node negatedNode = node.notNode();
// If the non-negated node has already been translated, get the translation
if(hasLiteral(node)) {
- Debug("cnf") << "toCNF(): already translated" << endl;
+ Trace("cnf") << "toCNF(): already translated\n";
nodeLit = getLiteral(node);
- } else {
- // Handle each Boolean operator case
- switch(node.getKind()) {
- case NOT:
- nodeLit = handleNot(node);
- break;
- case XOR:
- nodeLit = handleXor(node);
- break;
- case ITE:
- nodeLit = handleIte(node);
- break;
- case IMPLIES:
- nodeLit = handleImplies(node);
- break;
- case OR:
- nodeLit = handleOr(node);
- break;
- case AND:
- nodeLit = handleAnd(node);
- break;
- case EQUAL:
- if(node[0].getType().isBoolean()) {
- nodeLit = handleIff(node);
- } else {
- nodeLit = convertAtom(node);
- }
+ // Return the (maybe negated) literal
+ return !negated ? nodeLit : ~nodeLit;
+ }
+ // Handle each Boolean operator case
+ switch (node.getKind())
+ {
+ case kind::NOT: nodeLit = ~toCNF(node[0]); break;
+ case kind::XOR: nodeLit = handleXor(node); break;
+ case kind::ITE: nodeLit = handleIte(node); break;
+ case kind::IMPLIES: nodeLit = handleImplies(node); break;
+ case kind::OR: nodeLit = handleOr(node); break;
+ case kind::AND: nodeLit = handleAnd(node); break;
+ case kind::EQUAL:
+ nodeLit =
+ node[0].getType().isBoolean() ? handleIff(node) : convertAtom(node);
break;
default:
- {
- //TODO make sure this does not contain any boolean substructure
- nodeLit = convertAtom(node);
- //Unreachable();
- //Node atomic = handleNonAtomicNode(node);
- //return isCached(atomic) ? lookupInCache(atomic) : convertAtom(atomic);
- }
- break;
+ {
+ nodeLit = convertAtom(node);
}
+ break;
}
-
- // Return the appropriate (negated) literal
- if (!negated) return nodeLit;
- else return ~nodeLit;
+ // Return the (maybe negated) literal
+ return !negated ? nodeLit : ~nodeLit;
}
-void TseitinCnfStream::convertAndAssertAnd(TNode node, bool negated) {
- Assert(node.getKind() == AND);
+void CnfStream::convertAndAssertAnd(TNode node, bool negated)
+{
+ Assert(node.getKind() == kind::AND);
+ Trace("cnf") << "CnfStream::convertAndAssertAnd(" << node
+ << ", negated = " << (negated ? "true" : "false") << ")\n";
if (!negated) {
// If the node is a conjunction, we handle each conjunct separately
for(TNode::const_iterator conjunct = node.begin(), node_end = node.end();
conjunct != node_end; ++conjunct ) {
- PROOF(if (d_cnfProof) d_cnfProof->setCnfDependence(*conjunct, node););
convertAndAssert(*conjunct, false);
}
} else {
@@ -564,8 +571,11 @@ void TseitinCnfStream::convertAndAssertAnd(TNode node, bool negated) {
}
}
-void TseitinCnfStream::convertAndAssertOr(TNode node, bool negated) {
- Assert(node.getKind() == OR);
+void CnfStream::convertAndAssertOr(TNode node, bool negated)
+{
+ Assert(node.getKind() == kind::OR);
+ Trace("cnf") << "CnfStream::convertAndAssertOr(" << node
+ << ", negated = " << (negated ? "true" : "false") << ")\n";
if (!negated) {
// If the node is a disjunction, we construct a clause and assert it
int nChildren = node.getNumChildren();
@@ -581,13 +591,16 @@ void TseitinCnfStream::convertAndAssertOr(TNode node, bool negated) {
// If the node is a conjunction, we handle each conjunct separately
for(TNode::const_iterator conjunct = node.begin(), node_end = node.end();
conjunct != node_end; ++conjunct ) {
- PROOF(if (d_cnfProof) d_cnfProof->setCnfDependence((*conjunct).negate(), node.negate()););
convertAndAssert(*conjunct, true);
}
}
}
-void TseitinCnfStream::convertAndAssertXor(TNode node, bool negated) {
+void CnfStream::convertAndAssertXor(TNode node, bool negated)
+{
+ Assert(node.getKind() == kind::XOR);
+ Trace("cnf") << "CnfStream::convertAndAssertXor(" << node
+ << ", negated = " << (negated ? "true" : "false") << ")\n";
if (!negated) {
// p XOR q
SatLiteral p = toCNF(node[0], false);
@@ -617,7 +630,11 @@ void TseitinCnfStream::convertAndAssertXor(TNode node, bool negated) {
}
}
-void TseitinCnfStream::convertAndAssertIff(TNode node, bool negated) {
+void CnfStream::convertAndAssertIff(TNode node, bool negated)
+{
+ Assert(node.getKind() == kind::EQUAL);
+ Trace("cnf") << "CnfStream::convertAndAssertIff(" << node
+ << ", negated = " << (negated ? "true" : "false") << ")\n";
if (!negated) {
// p <=> q
SatLiteral p = toCNF(node[0], false);
@@ -647,7 +664,11 @@ void TseitinCnfStream::convertAndAssertIff(TNode node, bool negated) {
}
}
-void TseitinCnfStream::convertAndAssertImplies(TNode node, bool negated) {
+void CnfStream::convertAndAssertImplies(TNode node, bool negated)
+{
+ Assert(node.getKind() == kind::IMPLIES);
+ Trace("cnf") << "CnfStream::convertAndAssertImplies(" << node
+ << ", negated = " << (negated ? "true" : "false") << ")\n";
if (!negated) {
// p => q
SatLiteral p = toCNF(node[0], false);
@@ -658,21 +679,26 @@ void TseitinCnfStream::convertAndAssertImplies(TNode node, bool negated) {
clause[1] = q;
assertClause(node, clause);
} else {// Construct the
- PROOF(if (d_cnfProof) d_cnfProof->setCnfDependence(node[0], node.negate()););
- PROOF(if (d_cnfProof) d_cnfProof->setCnfDependence(node[1].negate(), node.negate()););
// !(p => q) is the same as (p && ~q)
convertAndAssert(node[0], false);
convertAndAssert(node[1], true);
}
}
-void TseitinCnfStream::convertAndAssertIte(TNode node, bool negated) {
+void CnfStream::convertAndAssertIte(TNode node, bool negated)
+{
+ Assert(node.getKind() == kind::ITE);
+ Trace("cnf") << "CnfStream::convertAndAssertIte(" << node
+ << ", negated = " << (negated ? "true" : "false") << ")\n";
// ITE(p, q, r)
SatLiteral p = toCNF(node[0], false);
SatLiteral q = toCNF(node[1], negated);
SatLiteral r = toCNF(node[2], negated);
// Construct the clauses:
// (p => q) and (!p => r)
+ //
+ // Note that below q and r can be used directly because whether they are
+ // negated has been push to the literal definitions above
Node nnode = node;
if( negated ){
nnode = node.negate();
@@ -690,80 +716,58 @@ void TseitinCnfStream::convertAndAssertIte(TNode node, bool negated) {
// At the top level we must ensure that all clauses that are asserted are
// not unit, except for the direct assertions. This allows us to remove the
// clauses later when they are not needed anymore (lemmas for example).
-void TseitinCnfStream::convertAndAssert(TNode node,
- bool removable,
- bool negated,
- ProofRule proof_id,
- TNode from) {
- Debug("cnf") << "convertAndAssert(" << node
- << ", removable = " << (removable ? "true" : "false")
- << ", negated = " << (negated ? "true" : "false") << ")" << endl;
+void CnfStream::convertAndAssert(TNode node,
+ bool removable,
+ bool negated,
+ bool input)
+{
+ Trace("cnf") << "convertAndAssert(" << node
+ << ", negated = " << (negated ? "true" : "false")
+ << ", removable = " << (removable ? "true" : "false") << ")\n";
d_removable = removable;
- PROOF
- (if (d_cnfProof) {
- Node assertion = negated ? node.notNode() : (Node)node;
- Node from_assertion = negated? from.notNode() : (Node) from;
-
- if (proof_id != RULE_INVALID) {
- d_cnfProof->pushCurrentAssertion(from.isNull() ? assertion : from_assertion);
- d_cnfProof->registerAssertion(from.isNull() ? assertion : from_assertion, proof_id);
- }
- else {
- d_cnfProof->pushCurrentAssertion(assertion);
- d_cnfProof->registerAssertion(assertion, proof_id);
- }
- });
+ if (d_cnfProof)
+ {
+ d_cnfProof->pushCurrentAssertion(negated ? node.notNode() : (Node)node,
+ input);
+ }
convertAndAssert(node, negated);
- PROOF
- (if (d_cnfProof) {
- d_cnfProof->popCurrentAssertion();
- });
+ if (d_cnfProof)
+ {
+ d_cnfProof->popCurrentAssertion();
+ }
}
-void TseitinCnfStream::convertAndAssert(TNode node, bool negated) {
- Debug("cnf") << "convertAndAssert(" << node
- << ", negated = " << (negated ? "true" : "false") << ")" << endl;
+void CnfStream::convertAndAssert(TNode node, bool negated)
+{
+ Trace("cnf") << "convertAndAssert(" << node
+ << ", negated = " << (negated ? "true" : "false") << ")\n";
- if (d_convertAndAssertCounter % ResourceManager::getFrequencyCount() == 0) {
- d_resourceManager->spendResource(ResourceManager::Resource::CnfStep);
- d_convertAndAssertCounter = 0;
- }
- ++d_convertAndAssertCounter;
+ d_resourceManager->spendResource(ResourceManager::Resource::CnfStep);
switch(node.getKind()) {
- case AND:
- convertAndAssertAnd(node, negated);
- break;
- case OR:
- convertAndAssertOr(node, negated);
- break;
- case XOR:
- convertAndAssertXor(node, negated);
- break;
- case IMPLIES:
- convertAndAssertImplies(node, negated);
- break;
- case ITE:
- convertAndAssertIte(node, negated);
- break;
- case NOT:
- convertAndAssert(node[0], !negated);
- break;
- case EQUAL:
- if( node[0].getType().isBoolean() ){
- convertAndAssertIff(node, negated);
- break;
- }
- CVC4_FALLTHROUGH;
- default:
- {
- Node nnode = node;
- if( negated ){
- nnode = node.negate();
- }
- // Atoms
- assertClause(nnode, toCNF(node, negated));
+ case kind::AND: convertAndAssertAnd(node, negated); break;
+ case kind::OR: convertAndAssertOr(node, negated); break;
+ case kind::XOR: convertAndAssertXor(node, negated); break;
+ case kind::IMPLIES: convertAndAssertImplies(node, negated); break;
+ case kind::ITE: convertAndAssertIte(node, negated); break;
+ case kind::NOT: convertAndAssert(node[0], !negated); break;
+ case kind::EQUAL:
+ if (node[0].getType().isBoolean())
+ {
+ convertAndAssertIff(node, negated);
+ break;
+ }
+ CVC4_FALLTHROUGH;
+ default:
+ {
+ Node nnode = node;
+ if (negated)
+ {
+ nnode = node.negate();
+ }
+ // Atoms
+ assertClause(nnode, toCNF(node, negated));
}
break;
}
diff --git a/src/prop/cnf_stream.h b/src/prop/cnf_stream.h
index 40243e5b9..74ead0d22 100644
--- a/src/prop/cnf_stream.h
+++ b/src/prop/cnf_stream.h
@@ -5,7 +5,7 @@
** Dejan Jovanovic, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -29,20 +29,31 @@
#include "context/cdlist.h"
#include "expr/node.h"
#include "proof/proof_manager.h"
+#include "prop/proof_cnf_stream.h"
#include "prop/registrar.h"
#include "prop/theory_proxy.h"
namespace CVC4 {
+class OutputManager;
+
namespace prop {
-class PropEngine;
+class ProofCnfStream;
/**
- * Comments for the behavior of the whole class... [??? -Chris]
- * @author Tim King <taking@cs.nyu.edu>
+ * Implements the following recursive algorithm
+ * http://people.inf.ethz.ch/daniekro/classes/251-0247-00/f2007/readings/Tseitin70.pdf
+ * in a single pass.
+ *
+ * The general idea is to introduce a new literal that will be equivalent to
+ * each subexpression in the constructed equi-satisfiable formula, then
+ * substitute the new literal for the formula, and so on, recursively.
*/
class CnfStream {
+ friend PropEngine;
+ friend ProofCnfStream;
+
public:
/** Cache of what nodes have been registered to a literal. */
typedef context::CDInsertHashMap<SatLiteral, TNode, SatLiteralHashFunction>
@@ -52,10 +63,129 @@ class CnfStream {
typedef context::CDInsertHashMap<Node, SatLiteral, NodeHashFunction>
NodeToLiteralMap;
+ /**
+ * Constructs a CnfStream that performs equisatisfiable CNF transformations
+ * and sends the generated clauses and to the given SAT solver. This does not
+ * take ownership of satSolver, registrar, or context.
+ *
+ * @param satSolver the sat solver to use.
+ * @param registrar the entity that takes care of preregistration of Nodes.
+ * @param context the context that the CNF should respect.
+ * @param outMgr Reference to the output manager of the smt engine. Assertions
+ * will not be dumped if outMgr == nullptr.
+ * @param rm the resource manager of the CNF stream
+ * @param fullLitToNodeMap maintain a full SAT-literal-to-Node mapping.
+ * @param name string identifier to distinguish between different instances
+ * even for non-theory literals.
+ */
+ CnfStream(SatSolver* satSolver,
+ Registrar* registrar,
+ context::Context* context,
+ OutputManager* outMgr,
+ ResourceManager* rm,
+ bool fullLitToNodeMap = false,
+ std::string name = "");
+ /**
+ * Convert a given formula to CNF and assert it to the SAT solver.
+ *
+ * @param node node to convert and assert
+ * @param removable whether the sat solver can choose to remove the clauses
+ * @param negated whether we are asserting the node negated
+ * @param input whether it is an input assertion (rather than a lemma). This
+ * information is only relevant for unsat core tracking.
+ */
+ void convertAndAssert(TNode node,
+ bool removable,
+ bool negated,
+ bool input = false);
+ /**
+ * Get the node that is represented by the given SatLiteral.
+ * @param literal the literal from the sat solver
+ * @return the actual node
+ */
+ TNode getNode(const SatLiteral& literal);
+
+ /**
+ * Returns true iff the node has an assigned literal (it might not be
+ * translated).
+ * @param node the node
+ */
+ bool hasLiteral(TNode node) const;
+
+ /**
+ * Ensure that the given node will have a designated SAT literal that is
+ * definitionally equal to it. The result of this function is that the Node
+ * can be queried via getSatValue(). Essentially, this is like a "convert-but-
+ * don't-assert" version of convertAndAssert().
+ */
+ void ensureLiteral(TNode n, bool noPreregistration = false);
+
+ /**
+ * Returns the literal that represents the given node in the SAT CNF
+ * representation.
+ * @param node [Presumably there are some constraints on the kind of
+ * node? E.g., it needs to be a boolean? -Chris]
+ */
+ SatLiteral getLiteral(TNode node);
+
+ /**
+ * Returns the Boolean variables from the input problem.
+ */
+ void getBooleanVariables(std::vector<TNode>& outputVariables) const;
+
+ /** Retrieves map from nodes to literals. */
+ const CnfStream::NodeToLiteralMap& getTranslationCache() const;
+
+ /** Retrieves map from literals to nodes. */
+ const CnfStream::LiteralToNodeMap& getNodeCache() const;
+
+ void setProof(CnfProof* proof);
+
protected:
+ /**
+ * Same as above, except that uses the saved d_removable flag. It calls the
+ * dedicated converter for the possible formula kinds.
+ */
+ void convertAndAssert(TNode node, bool negated);
+ /** Specific converters for each formula kind. */
+ void convertAndAssertAnd(TNode node, bool negated);
+ void convertAndAssertOr(TNode node, bool negated);
+ void convertAndAssertXor(TNode node, bool negated);
+ void convertAndAssertIff(TNode node, bool negated);
+ void convertAndAssertImplies(TNode node, bool negated);
+ void convertAndAssertIte(TNode node, bool negated);
+
+ /**
+ * Transforms the node into CNF recursively and yields a literal
+ * definitionally equal to it.
+ *
+ * This method also populates caches, kept in d_cnfStream, between formulas
+ * and literals to avoid redundant work and to retrieve formulas from literals
+ * and vice-versa.
+ *
+ * @param node the formula to transform
+ * @param negated whether the literal is negated
+ * @return the literal representing the root of the formula
+ */
+ SatLiteral toCNF(TNode node, bool negated = false);
+
+ /** Specific clausifiers, based on the formula kinds, that clausify a formula,
+ * by calling toCNF into each of the formula's children under the respective
+ * kind, and introduce a literal definitionally equal to it. */
+ SatLiteral handleNot(TNode node);
+ SatLiteral handleXor(TNode node);
+ SatLiteral handleImplies(TNode node);
+ SatLiteral handleIff(TNode node);
+ SatLiteral handleIte(TNode node);
+ SatLiteral handleAnd(TNode node);
+ SatLiteral handleOr(TNode node);
+
/** The SAT solver we will be using */
SatSolver* d_satSolver;
+ /** Reference to the output manager of the smt engine */
+ OutputManager* d_outMgr;
+
/** Boolean variables that we translated */
context::CDList<TNode> d_booleanVariables;
@@ -72,12 +202,6 @@ class CnfStream {
*/
const bool d_fullLitToNodeMap;
- /**
- * Counter for resource limiting that is used to spend a resource
- * every ResourceManager::resourceCounter calls to convertAndAssert.
- */
- unsigned long d_convertAndAssertCounter;
-
/** The "registrar" for pre-registration of terms */
Registrar* d_registrar;
@@ -87,14 +211,6 @@ class CnfStream {
/** Pointer to the proof corresponding to this CnfStream */
CnfProof* d_cnfProof;
- /** Remove nots from the node */
- TNode stripNot(TNode node) {
- while (node.getKind() == kind::NOT) {
- node = node[0];
- }
- return node;
- }
-
/**
* Are we asserting a removable clause (true) or a permanent clause (false).
* This is set at the beginning of convertAndAssert so that it doesn't
@@ -107,23 +223,26 @@ class CnfStream {
* Asserts the given clause to the sat solver.
* @param node the node giving rise to this clause
* @param clause the clause to assert
+ * @return whether the clause was asserted in the SAT solver.
*/
- void assertClause(TNode node, SatClause& clause);
+ bool assertClause(TNode node, SatClause& clause);
/**
* Asserts the unit clause to the sat solver.
* @param node the node giving rise to this clause
* @param a the unit literal of the clause
+ * @return whether the clause was asserted in the SAT solver.
*/
- void assertClause(TNode node, SatLiteral a);
+ bool assertClause(TNode node, SatLiteral a);
/**
* Asserts the binary clause to the sat solver.
* @param node the node giving rise to this clause
* @param a the first literal in the clause
* @param b the second literal in the clause
+ * @return whether the clause was asserted in the SAT solver.
*/
- void assertClause(TNode node, SatLiteral a, SatLiteral b);
+ bool assertClause(TNode node, SatLiteral a, SatLiteral b);
/**
* Asserts the ternary clause to the sat solver.
@@ -131,8 +250,9 @@ class CnfStream {
* @param a the first literal in the clause
* @param b the second literal in the clause
* @param c the thirs literal in the clause
+ * @return whether the clause was asserted in the SAT solver.
*/
- void assertClause(TNode node, SatLiteral a, SatLiteral b, SatLiteral c);
+ bool assertClause(TNode node, SatLiteral a, SatLiteral b, SatLiteral c);
/**
* Acquires a new variable from the SAT solver to represent the node
@@ -158,170 +278,11 @@ class CnfStream {
*/
SatLiteral convertAtom(TNode node, bool noPreprocessing = false);
- public:
- /**
- * Constructs a CnfStream that sends constructs an equi-satisfiable
- * set of clauses and sends them to the given sat solver. This does not take
- * ownership of satSolver, registrar, or context.
- * @param satSolver the sat solver to use.
- * @param registrar the entity that takes care of preregistration of Nodes.
- * @param context the context that the CNF should respect.
- * @param fullLitToNodeMap maintain a full SAT-literal-to-Node mapping.
- * @param name string identifier to distinguish between different instances
- * even for non-theory literals.
- */
- CnfStream(SatSolver* satSolver, Registrar* registrar,
- context::Context* context, bool fullLitToNodeMap = false,
- std::string name = "");
-
- /**
- * Destructs a CnfStream. This implementation does nothing, but we
- * need a virtual destructor for safety in case subclasses have a
- * destructor.
- */
- virtual ~CnfStream() {}
-
- /**
- * Converts and asserts a formula.
- * @param node node to convert and assert
- * @param removable whether the sat solver can choose to remove the clauses
- * @param negated whether we are asserting the node negated
- */
- virtual void convertAndAssert(TNode node, bool removable, bool negated,
- ProofRule proof_id,
- TNode from = TNode::null()) = 0;
-
- /**
- * Get the node that is represented by the given SatLiteral.
- * @param literal the literal from the sat solver
- * @return the actual node
- */
- TNode getNode(const SatLiteral& literal);
-
- /**
- * Returns true iff the node has an assigned literal (it might not be
- * translated).
- * @param node the node
- */
- bool hasLiteral(TNode node) const;
-
- /**
- * Ensure that the given node will have a designated SAT literal that is
- * definitionally equal to it. The result of this function is that the Node
- * can be queried via getSatValue(). Essentially, this is like a "convert-but-
- * don't-assert" version of convertAndAssert().
- */
- virtual void ensureLiteral(TNode n, bool noPreregistration = false) = 0;
-
- /**
- * Returns the literal that represents the given node in the SAT CNF
- * representation.
- * @param node [Presumably there are some constraints on the kind of
- * node? E.g., it needs to be a boolean? -Chris]
- */
- SatLiteral getLiteral(TNode node);
-
- /**
- * Returns the Boolean variables from the input problem.
- */
- void getBooleanVariables(std::vector<TNode>& outputVariables) const;
-
- const NodeToLiteralMap& getTranslationCache() const {
- return d_nodeToLiteralMap;
- }
-
- const LiteralToNodeMap& getNodeCache() const { return d_literalToNodeMap; }
-
- void setProof(CnfProof* proof);
-}; /* class CnfStream */
-
-/**
- * TseitinCnfStream is based on the following recursive algorithm
- * http://people.inf.ethz.ch/daniekro/classes/251-0247-00/f2007/readings/Tseitin70.pdf
- * The general idea is to introduce a new literal that
- * will be equivalent to each subexpression in the constructed equi-satisfiable
- * formula, then substitute the new literal for the formula, and so on,
- * recursively.
- *
- * This implementation does this in a single recursive pass. [??? -Chris]
- */
-class TseitinCnfStream : public CnfStream {
- public:
- /**
- * Constructs the stream to use the given sat solver. This does not take
- * ownership of satSolver, registrar, or context.
- * @param satSolver the sat solver to use
- * @param registrar the entity that takes care of pre-registration of Nodes
- * @param context the context that the CNF should respect.
- * @param rm the resource manager of the CNF stream
- * @param fullLitToNodeMap maintain a full SAT-literal-to-Node mapping,
- * even for non-theory literals
- */
- TseitinCnfStream(SatSolver* satSolver,
- Registrar* registrar,
- context::Context* context,
- ResourceManager* rm,
- bool fullLitToNodeMap = false,
- std::string name = "");
-
- /**
- * Convert a given formula to CNF and assert it to the SAT solver.
- * @param node the formula to assert
- * @param removable is this something that can be erased
- * @param negated true if negated
- */
- void convertAndAssert(TNode node,
- bool removable,
- bool negated,
- ProofRule rule,
- TNode from = TNode::null()) override;
-
- private:
- /**
- * Same as above, except that removable is remembered.
- */
- void convertAndAssert(TNode node, bool negated);
-
- // Each of these formulas handles takes care of a Node of each Kind.
- //
- // Each handleX(Node &n) is responsible for:
- // - constructing a new literal, l (if necessary)
- // - calling registerNode(n,l)
- // - adding clauses assure that l is equivalent to the Node
- // - calling toCNF on its children (if necessary)
- // - returning l
- //
- // handleX( n ) can assume that n is not in d_translationCache
- SatLiteral handleNot(TNode node);
- SatLiteral handleXor(TNode node);
- SatLiteral handleImplies(TNode node);
- SatLiteral handleIff(TNode node);
- SatLiteral handleIte(TNode node);
- SatLiteral handleAnd(TNode node);
- SatLiteral handleOr(TNode node);
-
- void convertAndAssertAnd(TNode node, bool negated);
- void convertAndAssertOr(TNode node, bool negated);
- void convertAndAssertXor(TNode node, bool negated);
- void convertAndAssertIff(TNode node, bool negated);
- void convertAndAssertImplies(TNode node, bool negated);
- void convertAndAssertIte(TNode node, bool negated);
-
- /**
- * Transforms the node into CNF recursively.
- * @param node the formula to transform
- * @param negated whether the literal is negated
- * @return the literal representing the root of the formula
- */
- SatLiteral toCNF(TNode node, bool negated = false);
-
- void ensureLiteral(TNode n, bool noPreregistration = false) override;
-
/** Pointer to resource manager for associated SmtEngine */
ResourceManager* d_resourceManager;
-}; /* class TseitinCnfStream */
+}; /* class CnfStream */
-} /* CVC4::prop namespace */
-} /* CVC4 namespace */
+} // namespace prop
+} // namespace CVC4
#endif /* CVC4__PROP__CNF_STREAM_H */
diff --git a/src/prop/cryptominisat.cpp b/src/prop/cryptominisat.cpp
index cf23758f1..1072003d2 100644
--- a/src/prop/cryptominisat.cpp
+++ b/src/prop/cryptominisat.cpp
@@ -5,7 +5,7 @@
** Liana Hadarean, Mathias Preiner, Alex Ozdemir
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,8 +19,6 @@
#include "prop/cryptominisat.h"
#include "base/check.h"
-#include "proof/clause_id.h"
-#include "proof/sat_proof.h"
#include <cryptominisat5/cryptominisat.h>
@@ -64,7 +62,6 @@ void toInternalClause(SatClause& clause,
CryptoMinisatSolver::CryptoMinisatSolver(StatisticsRegistry* registry,
const std::string& name)
: d_solver(new CMSat::SATSolver()),
- d_bvp(nullptr),
d_numVariables(0),
d_okay(true),
d_statistics(registry, name)
@@ -87,8 +84,9 @@ void CryptoMinisatSolver::init()
CryptoMinisatSolver::~CryptoMinisatSolver() {}
ClauseId CryptoMinisatSolver::addXorClause(SatClause& clause,
- bool rhs,
- bool removable) {
+ bool rhs,
+ bool removable)
+{
Debug("sat::cryptominisat") << "Add xor clause " << clause <<" = " << rhs << "\n";
if (!d_okay) {
@@ -97,7 +95,7 @@ ClauseId CryptoMinisatSolver::addXorClause(SatClause& clause,
}
++(d_statistics.d_xorClausesAdded);
-
+
// ensure all sat literals have positive polarity by pushing
// the negation on the result
std::vector<CMSatVar> xor_clause;
@@ -119,36 +117,19 @@ ClauseId CryptoMinisatSolver::addClause(SatClause& clause, bool removable){
}
++(d_statistics.d_clausesAdded);
-
+
std::vector<CMSat::Lit> internal_clause;
toInternalClause(clause, internal_clause);
bool nowOkay = d_solver->add_clause(internal_clause);
ClauseId freshId;
- if (THEORY_PROOF_ON())
- {
- freshId = ClauseId(ProofManager::currentPM()->nextId());
- // If this clause results in a conflict, then `nowOkay` may be false, but
- // we still need to register this clause as used. Thus, we look at
- // `d_okay` instead
- if (d_bvp && d_okay)
- {
- d_bvp->registerUsedClause(freshId, clause);
- }
- }
- else
- {
- freshId = ClauseIdError;
- }
+ freshId = ClauseIdError;
d_okay &= nowOkay;
return freshId;
}
-bool CryptoMinisatSolver::ok() const {
- return d_okay;
-}
-
+bool CryptoMinisatSolver::ok() const { return d_okay; }
SatVariable CryptoMinisatSolver::newVar(bool isTheoryAtom, bool preRegister, bool canErase){
d_solver->new_var();
@@ -208,19 +189,11 @@ SatValue CryptoMinisatSolver::value(SatLiteral l){
return toSatLiteralValue(value);
}
-SatValue CryptoMinisatSolver::modelValue(SatLiteral l){
- return value(l);
-}
+SatValue CryptoMinisatSolver::modelValue(SatLiteral l) { return value(l); }
unsigned CryptoMinisatSolver::getAssertionLevel() const {
Unreachable() << "No interface to get assertion level in Cryptominisat";
- return -1;
-}
-
-void CryptoMinisatSolver::setClausalProofLog(proof::ClausalBitVectorProof* bvp)
-{
- d_bvp = bvp;
- d_solver->set_drat(&bvp->getDratOstream(), false);
+ return -1;
}
// Satistics for CryptoMinisatSolver
diff --git a/src/prop/cryptominisat.h b/src/prop/cryptominisat.h
index d60855654..8861daf61 100644
--- a/src/prop/cryptominisat.h
+++ b/src/prop/cryptominisat.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Liana Hadarean, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,7 +21,6 @@
#ifdef CVC4_USE_CRYPTOMINISAT
-#include "proof/clausal_bitvector_proof.h"
#include "prop/sat_solver.h"
// Cryptominisat has name clashes with the other Minisat implementations since
@@ -68,7 +67,6 @@ class CryptoMinisatSolver : public SatSolver
SatValue modelValue(SatLiteral l) override;
unsigned getAssertionLevel() const override;
- void setClausalProofLog(proof::ClausalBitVectorProof* bvp) override;
private:
class Statistics
@@ -97,7 +95,6 @@ class CryptoMinisatSolver : public SatSolver
void init();
std::unique_ptr<CMSat::SATSolver> d_solver;
- proof::ClausalBitVectorProof* d_bvp;
unsigned d_numVariables;
bool d_okay;
SatVariable d_true;
diff --git a/src/prop/kissat.cpp b/src/prop/kissat.cpp
index 0440fcd4e..f7fc1afcd 100644
--- a/src/prop/kissat.cpp
+++ b/src/prop/kissat.cpp
@@ -5,7 +5,7 @@
** Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,7 +19,6 @@
#ifdef CVC4_USE_KISSAT
#include "base/check.h"
-#include "proof/sat_proof.h"
namespace CVC4 {
namespace prop {
diff --git a/src/prop/kissat.h b/src/prop/kissat.h
index 35b33daeb..7f672a98a 100644
--- a/src/prop/kissat.h
+++ b/src/prop/kissat.h
@@ -5,7 +5,7 @@
** Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/prop/minisat/core/Solver.cc b/src/prop/minisat/core/Solver.cc
index f56f6a447..e769ba6cc 100644
--- a/src/prop/minisat/core/Solver.cc
+++ b/src/prop/minisat/core/Solver.cc
@@ -30,6 +30,7 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
#include "options/prop_options.h"
#include "options/smt_options.h"
#include "proof/clause_id.h"
+#include "proof/cnf_proof.h"
#include "proof/proof_manager.h"
#include "proof/sat_proof.h"
#include "proof/sat_proof_implementation.h"
@@ -217,7 +218,10 @@ Solver::Solver(CVC4::prop::TheoryProxy* proxy,
propagation_budget(-1),
asynch_interrupt(false)
{
- PROOF(ProofManager::currentPM()->initSatProof(this);)
+ if (options::unsatCores())
+ {
+ ProofManager::currentPM()->initSatProof(this);
+ }
// Create the constant variables
varTrue = newVar(true, false, false);
@@ -227,11 +231,11 @@ Solver::Solver(CVC4::prop::TheoryProxy* proxy,
uncheckedEnqueue(mkLit(varTrue, false));
uncheckedEnqueue(mkLit(varFalse, true));
// FIXME: these should be axioms I believe
- PROOF
- (
- ProofManager::getSatProof()->registerTrueLit(mkLit(varTrue, false));
- ProofManager::getSatProof()->registerFalseLit(mkLit(varFalse, true));
- );
+ if (options::unsatCores())
+ {
+ ProofManager::getSatProof()->registerTrueLit(mkLit(varTrue, false));
+ ProofManager::getSatProof()->registerFalseLit(mkLit(varFalse, true));
+ }
}
@@ -390,15 +394,20 @@ CRef Solver::reason(Var x) {
// FIXME: at some point will need more information about where this explanation
// came from (ie. the theory/sharing)
Debug("pf::sat") << "Minisat::Solver registering a THEORY_LEMMA (1)" << std::endl;
- PROOF(ClauseId id = ProofManager::getSatProof()->registerClause(
- real_reason, THEORY_LEMMA);
- ProofManager::getCnfProof()->registerConvertedClause(id, true);
- // explainPropagation() pushes the explanation on the assertion stack
- // in CnfProof, so we need to pop it here. This is important because
- // reason() may be called indirectly while adding a clause, which can
- // lead to a wrong assertion being associated with the clause being
- // added (see issue #2137).
- ProofManager::getCnfProof()->popCurrentAssertion(););
+ if (options::unsatCores())
+ {
+ ClauseId id = ProofManager::getSatProof()->registerClause(real_reason,
+ THEORY_LEMMA);
+ // map id to assertion, which may be required if looking for
+ // lemmas in unsat core
+ ProofManager::getCnfProof()->registerConvertedClause(id);
+ // explainPropagation() pushes the explanation on the assertion stack
+ // in CnfProof, so we need to pop it here. This is important because
+ // reason() may be called indirectly while adding a clause, which can
+ // lead to a wrong assertion being associated with the clause being
+ // added (see issue #2137).
+ ProofManager::getCnfProof()->popCurrentAssertion();
+ }
vardata[x] = VarData(real_reason, level(x), user_level(x), intro_level(x), trail_index(x));
clauses_removable.push(real_reason);
attachClause(real_reason);
@@ -441,9 +450,13 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id)
}
// If a literal is false at 0 level (both sat and user level) we also ignore it
if (value(ps[i]) == l_False) {
- if (!PROOF_ON() && level(var(ps[i])) == 0 && user_level(var(ps[i])) == 0) {
+ if (!options::unsatCores() && level(var(ps[i])) == 0
+ && user_level(var(ps[i])) == 0)
+ {
continue;
- } else {
+ }
+ else
+ {
// If we decide to keep it, we count it into the false literals
falseLiteralsCount ++;
}
@@ -467,34 +480,46 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id)
lemmas.push();
ps.copyTo(lemmas.last());
lemmas_removable.push(removable);
- PROOF(
- // Store the expression being converted to CNF until
- // the clause is actually created
- Node assertion = ProofManager::getCnfProof()->getCurrentAssertion();
- Node def = ProofManager::getCnfProof()->getCurrentDefinition();
- lemmas_cnf_assertion.push_back(std::make_pair(assertion, def));
- id = ClauseIdUndef;
- );
- // does it have to always be a lemma?
- // PROOF(id = ProofManager::getSatProof()->registerUnitClause(ps[0], THEORY_LEMMA););
- // PROOF(id = ProofManager::getSatProof()->registerTheoryLemma(ps););
- // Debug("cores") << "lemma push " << proof_id << " " << (proof_id & 0xffffffff) << std::endl;
- // lemmas_proof_id.push(proof_id);
+ if (options::unsatCores())
+ {
+ // Store the expression being converted to CNF until
+ // the clause is actually created
+ lemmas_cnf_assertion.push_back(
+ ProofManager::getCnfProof()->getCurrentAssertion());
+ id = ClauseIdUndef;
+ }
} else {
assert(decisionLevel() == 0);
// If all false, we're in conflict
if (ps.size() == falseLiteralsCount) {
- if(PROOF_ON()) {
+ if (options::unsatCores())
+ {
// Take care of false units here; otherwise, we need to
// construct the clause below to give to the proof manager
// as the final conflict.
if(falseLiteralsCount == 1) {
- PROOF( id = ProofManager::getSatProof()->storeUnitConflict(ps[0], INPUT); )
- PROOF( ProofManager::getSatProof()->finalizeProof(CVC4::Minisat::CRef_Lazy); )
+ if (options::unsatCores())
+ {
+ ClauseKind ck =
+ ProofManager::getCnfProof()->getCurrentAssertionKind()
+ ? INPUT
+ : THEORY_LEMMA;
+ id = ProofManager::getSatProof()->storeUnitConflict(ps[0], ck);
+ // map id to assertion, which may be required if looking for
+ // lemmas in unsat core
+ if (ck == THEORY_LEMMA)
+ {
+ ProofManager::getCnfProof()->registerConvertedClause(id);
+ }
+ ProofManager::getSatProof()->finalizeProof(
+ CVC4::Minisat::CRef_Lazy);
+ }
return ok = false;
}
- } else {
+ }
+ else
+ {
return ok = false;
}
}
@@ -509,14 +534,23 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id)
cr = ca.alloc(clauseLevel, ps, false);
clauses_persistent.push(cr);
- attachClause(cr);
-
- if(PROOF_ON()) {
- PROOF(
- id = ProofManager::getSatProof()->registerClause(cr, INPUT);
- )
- if(ps.size() == falseLiteralsCount) {
- PROOF( ProofManager::getSatProof()->finalizeProof(cr); )
+ attachClause(cr);
+
+ if (options::unsatCores())
+ {
+ ClauseKind ck = ProofManager::getCnfProof()->getCurrentAssertionKind()
+ ? INPUT
+ : THEORY_LEMMA;
+ id = ProofManager::getSatProof()->registerClause(cr, ck);
+ // map id to assertion, which may be required if looking for
+ // lemmas in unsat core
+ if (ck == THEORY_LEMMA)
+ {
+ ProofManager::getCnfProof()->registerConvertedClause(id);
+ }
+ if (ps.size() == falseLiteralsCount)
+ {
+ ProofManager::getSatProof()->finalizeProof(cr);
return ok = false;
}
}
@@ -527,15 +561,25 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id)
if(assigns[var(ps[0])] == l_Undef) {
assert(assigns[var(ps[0])] != l_False);
uncheckedEnqueue(ps[0], cr);
- Debug("cores") << "i'm registering a unit clause, input" << std::endl;
- PROOF(
- if(ps.size() == 1) {
- id = ProofManager::getSatProof()->registerUnitClause(ps[0], INPUT);
- }
- );
+ Debug("cores") << "i'm registering a unit clause, maybe input"
+ << std::endl;
+ if (options::unsatCores() && ps.size() == 1)
+ {
+ ClauseKind ck =
+ ProofManager::getCnfProof()->getCurrentAssertionKind()
+ ? INPUT
+ : THEORY_LEMMA;
+ id = ProofManager::getSatProof()->registerUnitClause(ps[0], ck);
+ // map id to assertion, which may be required if looking for
+ // lemmas in unsat core
+ if (ck == THEORY_LEMMA)
+ {
+ ProofManager::getCnfProof()->registerConvertedClause(id);
+ }
+ }
CRef confl = propagate(CHECK_WITHOUT_THEORY);
if(! (ok = (confl == CRef_Undef)) ) {
- if (PROOF_ON())
+ if (options::unsatCores())
{
if (ca[confl].size() == 1)
{
@@ -552,7 +596,10 @@ bool Solver::addClause_(vec<Lit>& ps, bool removable, ClauseId& id)
}
return ok;
} else {
- PROOF(id = ClauseIdUndef;);
+ if (options::unsatCores())
+ {
+ id = ClauseIdUndef;
+ }
return ok;
}
}
@@ -575,7 +622,10 @@ void Solver::attachClause(CRef cr) {
void Solver::detachClause(CRef cr, bool strict) {
const Clause& c = ca[cr];
- PROOF( ProofManager::getSatProof()->markDeleted(cr); );
+ if (options::unsatCores())
+ {
+ ProofManager::getSatProof()->markDeleted(cr);
+ }
Debug("minisat") << "Solver::detachClause(" << c << ")" << std::endl;
assert(c.size() > 1);
@@ -619,9 +669,6 @@ void Solver::cancelUntil(int level) {
// Pop the SMT context
for (int l = trail_lim.size() - level; l > 0; --l) {
d_context->pop();
- if(Dump.isOn("state")) {
- d_proxy->dumpStatePop();
- }
}
for (int c = trail.size()-1; c >= trail_lim[level]; c--){
Var x = var(trail[c]);
@@ -826,7 +873,10 @@ int Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel)
int max_resolution_level = 0; // Maximal level of the resolved clauses
- PROOF( ProofManager::getSatProof()->startResChain(confl); )
+ if (options::unsatCores())
+ {
+ ProofManager::getSatProof()->startResChain(confl);
+ }
do{
assert(confl != CRef_Undef); // (otherwise should be UIP)
@@ -867,9 +917,9 @@ int Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel)
}
// FIXME: can we do it lazily if we actually need the proof?
- if (level(var(q)) == 0)
+ if (options::unsatCores() && level(var(q)) == 0)
{
- PROOF(ProofManager::getSatProof()->resolveOutUnit(q);)
+ ProofManager::getSatProof()->resolveOutUnit(q);
}
}
}
@@ -881,8 +931,9 @@ int Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel)
seen[var(p)] = 0;
pathC--;
- if ( pathC > 0 && confl != CRef_Undef ) {
- PROOF( ProofManager::getSatProof()->addResolutionStep(p, confl, sign(p)); )
+ if (options::unsatCores() && pathC > 0 && confl != CRef_Undef)
+ {
+ ProofManager::getSatProof()->addResolutionStep(p, confl, sign(p));
}
}while (pathC > 0);
@@ -905,7 +956,10 @@ int Solver::analyze(CRef confl, vec<Lit>& out_learnt, int& out_btlevel)
// Literal is not redundant
out_learnt[j++] = out_learnt[i];
} else {
- PROOF( ProofManager::getSatProof()->storeLitRedundant(out_learnt[i]); )
+ if (options::unsatCores())
+ {
+ ProofManager::getSatProof()->storeLitRedundant(out_learnt[i]);
+ }
// Literal is redundant, to be safe, mark the level as current assertion level
// TODO: maybe optimize
max_resolution_level = std::max(max_resolution_level, user_level(var(out_learnt[i])));
@@ -1169,7 +1223,10 @@ void Solver::propagateTheory() {
addClause(explanation, true, id);
// explainPropagation() pushes the explanation on the assertion
// stack in CnfProof, so we need to pop it here.
- PROOF(ProofManager::getCnfProof()->popCurrentAssertion();)
+ if (options::unsatCores())
+ {
+ ProofManager::getCnfProof()->popCurrentAssertion();
+ }
}
}
}
@@ -1310,9 +1367,10 @@ void Solver::removeSatisfied(vec<CRef>& cs)
for (i = j = 0; i < cs.size(); i++){
Clause& c = ca[cs[i]];
if (satisfied(c)) {
- if (locked(c)) {
+ if (options::unsatCores() && locked(c))
+ {
// store a resolution of the literal c propagated
- PROOF( ProofManager::getSatProof()->storeUnitResolution(c[0]); )
+ ProofManager::getSatProof()->storeUnitResolution(c[0]);
}
removeClause(cs[i]);
}
@@ -1412,8 +1470,11 @@ lbool Solver::search(int nof_conflicts)
conflicts++; conflictC++;
if (decisionLevel() == 0) {
- PROOF( ProofManager::getSatProof()->finalizeProof(confl); )
- return l_False;
+ if (options::unsatCores())
+ {
+ ProofManager::getSatProof()->finalizeProof(confl);
+ }
+ return l_False;
}
// Analyze the conflict
@@ -1425,8 +1486,10 @@ lbool Solver::search(int nof_conflicts)
if (learnt_clause.size() == 1) {
uncheckedEnqueue(learnt_clause[0]);
- PROOF( ProofManager::getSatProof()->endResChain(learnt_clause[0]); )
-
+ if (options::unsatCores())
+ {
+ ProofManager::getSatProof()->endResChain(learnt_clause[0]);
+ }
} else {
CRef cr =
ca.alloc(assertionLevelOnly() ? assertionLevel : max_level,
@@ -1436,15 +1499,12 @@ lbool Solver::search(int nof_conflicts)
attachClause(cr);
claBumpActivity(ca[cr]);
uncheckedEnqueue(learnt_clause[0], cr);
- PROOF(ClauseId id =
- ProofManager::getSatProof()->registerClause(cr, LEARNT);
- PSTATS(std::unordered_set<int> cl_levels;
- for (int i = 0; i < learnt_clause.size(); ++i) {
- cl_levels.insert(level(var(learnt_clause[i])));
- } ProofManager::getSatProof()
- ->storeClauseGlue(id, cl_levels.size());)
- ProofManager::getSatProof()
- ->endResChain(id););
+ if (options::unsatCores())
+ {
+ ClauseId id =
+ ProofManager::getSatProof()->registerClause(cr, LEARNT);
+ ProofManager::getSatProof()->endResChain(id);
+ }
}
varDecayActivity();
@@ -1469,25 +1529,33 @@ lbool Solver::search(int nof_conflicts)
}
} else {
-
- // If this was a final check, we are satisfiable
- if (check_type == CHECK_FINAL) {
- bool decisionEngineDone = d_proxy->isDecisionEngineDone();
- // Unless a lemma has added more stuff to the queues
- if (!decisionEngineDone &&
- (!order_heap.empty() || qhead < trail.size()) ) {
- check_type = CHECK_WITH_THEORY;
- continue;
- } else if (recheck) {
- // There some additional stuff added, so we go for another full-check
- continue;
- } else {
- // Yes, we're truly satisfiable
- return l_True;
- }
- } else if (check_type == CHECK_FINAL_FAKE) {
+ // If this was a final check, we are satisfiable
+ if (check_type == CHECK_FINAL)
+ {
+ bool decisionEngineDone = d_proxy->isDecisionEngineDone();
+ // Unless a lemma has added more stuff to the queues
+ if (!decisionEngineDone
+ && (!order_heap.empty() || qhead < trail.size()))
+ {
check_type = CHECK_WITH_THEORY;
+ continue;
+ }
+ else if (recheck)
+ {
+ // There some additional stuff added, so we go for another
+ // full-check
+ continue;
}
+ else
+ {
+ // Yes, we're truly satisfiable
+ return l_True;
+ }
+ }
+ else if (check_type == CHECK_FINAL_FAKE)
+ {
+ check_type = CHECK_WITH_THEORY;
+ }
if ((nof_conflicts >= 0 && conflictC >= nof_conflicts)
|| !withinBudget(ResourceManager::Resource::SatConflictStep))
@@ -1744,7 +1812,10 @@ void Solver::relocAll(ClauseAllocator& to)
// printf(" >>> RELOCING: %s%d\n", sign(p)?"-":"", var(p)+1);
vec<Watcher>& ws = watches[p];
for (int j = 0; j < ws.size(); j++)
- ca.reloc(ws[j].cref, to, NULLPROOF(ProofManager::getSatProof()));
+ ca.reloc(ws[j].cref,
+ to,
+ CVC4::options::unsatCores() ? ProofManager::getSatProof()
+ : nullptr);
}
// All reasons:
@@ -1753,22 +1824,31 @@ void Solver::relocAll(ClauseAllocator& to)
Var v = var(trail[i]);
if (hasReasonClause(v) && (ca[reason(v)].reloced() || locked(ca[reason(v)])))
- ca.reloc(
- vardata[v].d_reason, to, NULLPROOF(ProofManager::getSatProof()));
+ ca.reloc(vardata[v].d_reason,
+ to,
+ CVC4::options::unsatCores() ? ProofManager::getSatProof()
+ : nullptr);
}
// All learnt:
//
for (int i = 0; i < clauses_removable.size(); i++)
ca.reloc(
- clauses_removable[i], to, NULLPROOF(ProofManager::getSatProof()));
+ clauses_removable[i],
+ to,
+ CVC4::options::unsatCores() ? ProofManager::getSatProof() : nullptr);
// All original:
//
for (int i = 0; i < clauses_persistent.size(); i++)
ca.reloc(
- clauses_persistent[i], to, NULLPROOF(ProofManager::getSatProof()));
+ clauses_persistent[i],
+ to,
+ CVC4::options::unsatCores() ? ProofManager::getSatProof() : nullptr);
- PROOF(ProofManager::getSatProof()->finishUpdateCRef();)
+ if (options::unsatCores())
+ {
+ ProofManager::getSatProof()->finishUpdateCRef();
+ }
}
@@ -1874,7 +1954,7 @@ CRef Solver::updateLemmas() {
// If it's an empty lemma, we have a conflict at zero level
if (lemma.size() == 0) {
- Assert(!PROOF_ON());
+ Assert(!options::unsatCores());
conflict = CRef_Lazy;
backtrackLevel = 0;
Debug("minisat::lemmas") << "Solver::updateLemmas(): found empty clause" << std::endl;
@@ -1904,7 +1984,8 @@ CRef Solver::updateLemmas() {
// Last index in the trail
int backtrack_index = trail.size();
- PROOF(Assert(lemmas.size() == (int)lemmas_cnf_assertion.size()););
+ Assert(!options::unsatCores()
+ || lemmas.size() == (int)lemmas_cnf_assertion.size());
// Attach all the clauses and enqueue all the propagations
for (int j = 0; j < lemmas.size(); ++j)
@@ -1928,15 +2009,16 @@ CRef Solver::updateLemmas() {
}
lemma_ref = ca.alloc(clauseLevel, lemma, removable);
- PROOF(TNode cnf_assertion = lemmas_cnf_assertion[j].first;
- TNode cnf_def = lemmas_cnf_assertion[j].second;
-
- Debug("pf::sat")
- << "Minisat::Solver registering a THEORY_LEMMA (2)" << std::endl;
- ClauseId id = ProofManager::getSatProof()->registerClause(
- lemma_ref, THEORY_LEMMA);
- ProofManager::getCnfProof()->setClauseAssertion(id, cnf_assertion);
- ProofManager::getCnfProof()->setClauseDefinition(id, cnf_def););
+ if (options::unsatCores())
+ {
+ TNode cnf_assertion = lemmas_cnf_assertion[j];
+
+ Debug("pf::sat") << "Minisat::Solver registering a THEORY_LEMMA (2)"
+ << std::endl;
+ ClauseId id = ProofManager::getSatProof()->registerClause(lemma_ref,
+ THEORY_LEMMA);
+ ProofManager::getCnfProof()->setClauseAssertion(id, cnf_assertion);
+ }
if (removable) {
clauses_removable.push(lemma_ref);
} else {
@@ -1948,17 +2030,15 @@ CRef Solver::updateLemmas() {
// If the lemma is propagating enqueue its literal (or set the conflict)
if (conflict == CRef_Undef && value(lemma[0]) != l_True) {
if (lemma.size() == 1 || (value(lemma[1]) == l_False && trail_index(var(lemma[1])) < backtrack_index)) {
- if (PROOF_ON() && lemma.size() == 1)
+ if (options::unsatCores() && lemma.size() == 1)
{
- Node cnf_assertion = lemmas_cnf_assertion[j].first;
- Node cnf_def = lemmas_cnf_assertion[j].second;
+ Node cnf_assertion = lemmas_cnf_assertion[j];
Debug("pf::sat") << "Minisat::Solver registering a THEORY_LEMMA (3) "
<< cnf_assertion << value(lemma[0]) << std::endl;
ClauseId id = ProofManager::getSatProof()->registerUnitClause(
lemma[0], THEORY_LEMMA);
ProofManager::getCnfProof()->setClauseAssertion(id, cnf_assertion);
- ProofManager::getCnfProof()->setClauseDefinition(id, cnf_def);
}
if (value(lemma[0]) == l_False) {
@@ -1969,7 +2049,10 @@ 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], LEARNT); );
+ if (options::unsatCores())
+ {
+ ProofManager::getSatProof()->storeUnitConflict(lemma[0], LEARNT);
+ }
}
} else {
Debug("minisat::lemmas") << "lemma size is " << lemma.size() << std::endl;
@@ -1979,7 +2062,8 @@ CRef Solver::updateLemmas() {
}
}
- PROOF(Assert(lemmas.size() == (int)lemmas_cnf_assertion.size()););
+ Assert(!options::unsatCores()
+ || lemmas.size() == (int)lemmas_cnf_assertion.size());
// Clear the lemmas
lemmas.clear();
lemmas_cnf_assertion.clear();
diff --git a/src/prop/minisat/core/Solver.h b/src/prop/minisat/core/Solver.h
index 508947456..f3bcfb67e 100644
--- a/src/prop/minisat/core/Solver.h
+++ b/src/prop/minisat/core/Solver.h
@@ -33,6 +33,7 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
#include "prop/minisat/mtl/Heap.h"
#include "prop/minisat/mtl/Vec.h"
#include "prop/minisat/utils/Options.h"
+#include "prop/sat_proof_manager.h"
#include "theory/theory.h"
@@ -55,6 +56,7 @@ class Solver {
/** The only two CVC4 entry points to the private solver data */
friend class CVC4::prop::TheoryProxy;
+ friend class CVC4::prop::SatProofManager;
friend class CVC4::TSatProof<Minisat::Solver>;
public:
@@ -63,7 +65,7 @@ public:
typedef Var TVar;
typedef Lit TLit;
- typedef Clause TClause;
+ typedef Clause TClause;
typedef CRef TCRef;
typedef vec<Lit> TLitVec;
@@ -98,7 +100,7 @@ public:
vec<bool> lemmas_removable;
/** Nodes being converted to CNF */
- std::vector<std::pair<CVC4::Node, CVC4::Node> > lemmas_cnf_assertion;
+ std::vector<CVC4::Node> lemmas_cnf_assertion;
/** Do a another check if FULL_EFFORT was the last one */
bool recheck;
@@ -203,7 +205,7 @@ public:
lbool solve (Lit p, Lit q, Lit r); // Search for a model that respects three assumptions.
bool okay () const; // FALSE means solver is in a conflicting state
- void toDimacs ();
+ void toDimacs();
void toDimacs (FILE* f, const vec<Lit>& assumps); // Write CNF to file in DIMACS-format.
void toDimacs (const char *file, const vec<Lit>& assumps);
void toDimacs (FILE* f, Clause& c, vec<Var>& map, Var& max);
@@ -572,10 +574,6 @@ inline void Solver::newDecisionLevel()
trail_lim.push(trail.size());
flipped.push(false);
d_context->push();
- if (Dump.isOn("state"))
- {
- Dump("state") << CVC4::PushCommand();
- }
}
inline int Solver::decisionLevel () const { return trail_lim.size(); }
diff --git a/src/prop/minisat/core/SolverTypes.h b/src/prop/minisat/core/SolverTypes.h
index bbd6e17a2..b30d97aee 100644
--- a/src/prop/minisat/core/SolverTypes.h
+++ b/src/prop/minisat/core/SolverTypes.h
@@ -73,9 +73,14 @@ inline bool sign (Lit p) { return p.x & 1; }
inline int var (Lit p) { return p.x >> 1; }
// Mapping Literals to and from compact integers suitable for array indexing:
-inline int toInt (Var v) { return v; }
-inline int toInt (Lit p) { return p.x; }
-inline Lit toLit (int i) { Lit p; p.x = i; return p; }
+inline int toInt(Var v) { return v; }
+inline int toInt(Lit p) { return p.x; }
+inline Lit toLit(int i)
+{
+ Lit p;
+ p.x = i;
+ return p;
+}
//const Lit lit_Undef = mkLit(var_Undef, false); // }- Useful special constants.
//const Lit lit_Error = mkLit(var_Undef, true ); // }
@@ -83,20 +88,19 @@ inline Lit toLit (int i) { Lit p; p.x = i; return p; }
const Lit lit_Undef = { -2 }; // }- Useful special constants.
const Lit lit_Error = { -1 }; // }
-
//=================================================================================================
// Lifted booleans:
//
-// NOTE: this implementation is optimized for the case when comparisons between values are mostly
-// between one variable and one constant. Some care had to be taken to make sure that gcc
-// does enough constant propagation to produce sensible code, and this appears to be somewhat
-// fragile unfortunately.
+// NOTE: this implementation is optimized for the case when comparisons between
+// values are mostly
+// between one variable and one constant. Some care had to be taken to
+// make sure that gcc does enough constant propagation to produce sensible
+// code, and this appears to be somewhat fragile unfortunately.
/*
- This is to avoid multiple definitions of l_True, l_False and l_Undef if using multiple copies of
- Minisat.
- IMPORTANT: if we you change the value of the constants so that it is not the same in all copies
- of Minisat this breaks!
+ This is to avoid multiple definitions of l_True, l_False and l_Undef if using
+ multiple copies of Minisat. IMPORTANT: if we you change the value of the
+ constants so that it is not the same in all copies of Minisat this breaks!
*/
#ifndef l_True
@@ -124,10 +128,12 @@ public:
bool operator != (lbool b) const { return !(*this == b); }
lbool operator ^ (bool b) const { return lbool((uint8_t)(value^(uint8_t)b)); }
- lbool operator && (lbool b) const {
- uint8_t sel = (this->value << 1) | (b.value << 3);
- uint8_t v = (0xF7F755F4 >> sel) & 3;
- return lbool(v); }
+ lbool operator&&(lbool b) const
+ {
+ uint8_t sel = (this->value << 1) | (b.value << 3);
+ uint8_t v = (0xF7F755F4 >> sel) & 3;
+ return lbool(v);
+ }
lbool operator || (lbool b) const {
uint8_t sel = (this->value << 1) | (b.value << 3);
@@ -163,7 +169,7 @@ inline std::ostream& operator <<(std::ostream& out, Minisat::vec<Minisat::Lit>&
}
inline std::ostream& operator <<(std::ostream& out, Minisat::lbool val) {
- std::string val_str;
+ std::string val_str;
if( val == l_False ) {
val_str = "0";
} else if (val == l_True ) {
@@ -208,14 +214,14 @@ class Clause {
header.size = ps.size();
header.level = level;
- for (int i = 0; i < ps.size(); i++)
- data[i].lit = ps[i];
+ for (int i = 0; i < ps.size(); i++) data[i].lit = ps[i];
if (header.has_extra){
if (header.removable)
- data[header.size].act = 0;
- else
- calcAbstraction(); }
+ data[header.size].act = 0;
+ else
+ calcAbstraction();
+ }
}
public:
@@ -321,7 +327,7 @@ class OccLists
public:
OccLists(const Deleted& d) : deleted(d) {}
-
+
void init (const Idx& idx){ occs.growTo(toInt(idx)+1); dirty.growTo(toInt(idx)+1, 0); }
void resizeTo (const Idx& idx);
// Vec& operator[](const Idx& idx){ return occs[toInt(idx)]; }
@@ -394,13 +400,12 @@ class CMap
typedef Map<CRef, T, CRefHash> HashTable;
HashTable map;
-
+
public:
// Size-operations:
void clear () { map.clear(); }
int size () const { return map.elems(); }
-
// Insert/Remove/Test mapping:
void insert (CRef cr, const T& t){ map.insert(cr, t); }
void growTo (CRef cr, const T& t){ map.insert(cr, t); } // NOTE: for compatibility
@@ -423,15 +428,14 @@ class CMap
printf(" --- size = %d, bucket_count = %d\n", size(), map.bucket_count()); }
};
-
/*_________________________________________________________________________________________________
|
| subsumes : (other : const Clause&) -> Lit
-|
+|
| Description:
-| Checks if clause subsumes 'other', and at the same time, if it can be used to simplify 'other'
-| by subsumption resolution.
-|
+| Checks if clause subsumes 'other', and at the same time, if it can be
+used to simplify 'other' | by subsumption resolution.
+|
| Result:
| lit_Error - No subsumption or simplification
| lit_Undef - Clause subsumes 'other'
diff --git a/src/prop/minisat/minisat.cpp b/src/prop/minisat/minisat.cpp
index 86c9142d0..90368ac15 100644
--- a/src/prop/minisat/minisat.cpp
+++ b/src/prop/minisat/minisat.cpp
@@ -5,7 +5,7 @@
** Liana Hadarean, Dejan Jovanovic, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -154,7 +154,7 @@ ClauseId MinisatSatSolver::addClause(SatClause& clause, bool removable) {
return ClauseIdUndef;
}
d_minisat->addClause(minisat_clause, removable, clause_id);
- PROOF(Assert(clause_id != ClauseIdError););
+ Assert(!CVC4::options::unsatCores() || clause_id != ClauseIdError);
return clause_id;
}
@@ -182,7 +182,9 @@ SatValue MinisatSatSolver::solve(unsigned long& resource) {
SatValue MinisatSatSolver::solve() {
setupOptions();
d_minisat->budgetOff();
- return toSatLiteralValue(d_minisat->solve());
+ SatValue result = toSatLiteralValue(d_minisat->solve());
+ d_minisat->clearInterrupt();
+ return result;
}
bool MinisatSatSolver::ok() const {
diff --git a/src/prop/minisat/minisat.h b/src/prop/minisat/minisat.h
index 947a27b3b..e2b5699f7 100644
--- a/src/prop/minisat/minisat.h
+++ b/src/prop/minisat/minisat.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Liana Hadarean, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/prop/minisat/simp/SimpSolver.cc b/src/prop/minisat/simp/SimpSolver.cc
index a101a0c2d..0ec8981ca 100644
--- a/src/prop/minisat/simp/SimpSolver.cc
+++ b/src/prop/minisat/simp/SimpSolver.cc
@@ -21,8 +21,8 @@ OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWA
#include "prop/minisat/simp/SimpSolver.h"
#include "options/prop_options.h"
+#include "options/smt_options.h"
#include "proof/clause_id.h"
-#include "proof/proof.h"
#include "prop/minisat/mtl/Sort.h"
#include "prop/minisat/utils/System.h"
@@ -47,25 +47,30 @@ static DoubleOption opt_simp_garbage_frac(_cat, "simp-gc-frac", "The fraction of
//=================================================================================================
// Constructor/Destructor:
-
-SimpSolver::SimpSolver(CVC4::prop::TheoryProxy* proxy, CVC4::context::Context* context, bool enableIncremental) :
- Solver(proxy, context, enableIncremental)
- , grow (opt_grow)
- , clause_lim (opt_clause_lim)
- , subsumption_lim (opt_subsumption_lim)
- , simp_garbage_frac (opt_simp_garbage_frac)
- , use_asymm (opt_use_asymm)
- , use_rcheck (opt_use_rcheck)
- , use_elim (options::minisatUseElim() && !enableIncremental)
- , merges (0)
- , asymm_lits (0)
- , eliminated_vars (0)
- , elimorder (1)
- , use_simplification (!enableIncremental && !PROOF_ON()) // TODO: turn off simplifications if proofs are on initially
- , occurs (ClauseDeleted(ca))
- , elim_heap (ElimLt(n_occ))
- , bwdsub_assigns (0)
- , n_touched (0)
+SimpSolver::SimpSolver(CVC4::prop::TheoryProxy* proxy,
+ CVC4::context::Context* context,
+ bool enableIncremental)
+ : Solver(proxy, context, enableIncremental),
+ grow(opt_grow),
+ clause_lim(opt_clause_lim),
+ subsumption_lim(opt_subsumption_lim),
+ simp_garbage_frac(opt_simp_garbage_frac),
+ use_asymm(opt_use_asymm),
+ use_rcheck(opt_use_rcheck),
+ use_elim(options::minisatUseElim() && !enableIncremental),
+ merges(0),
+ asymm_lits(0),
+ eliminated_vars(0),
+ elimorder(1),
+ use_simplification(
+ !enableIncremental
+ && !options::unsatCores()) // TODO: turn off simplifications if
+ // proofs are on initially
+ ,
+ occurs(ClauseDeleted(ca)),
+ elim_heap(ElimLt(n_occ)),
+ bwdsub_assigns(0),
+ n_touched(0)
{
if(options::minisatUseElim() &&
options::minisatUseElim.wasSetByUser() &&
@@ -117,8 +122,8 @@ Var SimpSolver::newVar(bool sign, bool dvar, bool isTheoryAtom, bool preRegister
lbool SimpSolver::solve_(bool do_simp, bool turn_off_simp)
{
if (options::minisatDumpDimacs()) {
- toDimacs();
- return l_Undef;
+ toDimacs();
+ return l_Undef;
}
assert(decisionLevel() == 0);
@@ -525,7 +530,7 @@ bool SimpSolver::eliminateVar(Var v)
for (int i = 0; i < cls.size(); i++)
(find(ca[cls[i]], mkLit(v)) ? pos : neg).push(cls[i]);
- // Check wether the increase in number of clauses stays within the allowed ('grow'). Moreover, no
+ // Check whether the increase in number of clauses stays within the allowed ('grow'). Moreover, no
// clause must exceed the limit on the maximal clause size (if it is set):
//
int cnt = 0;
@@ -533,9 +538,10 @@ bool SimpSolver::eliminateVar(Var v)
for (int i = 0; i < pos.size(); i++)
for (int j = 0; j < neg.size(); j++)
- if (merge(ca[pos[i]], ca[neg[j]], v, clause_size) &&
- (++cnt > cls.size() + grow || (clause_lim != -1 && clause_size > clause_lim)))
- return true;
+ if (merge(ca[pos[i]], ca[neg[j]], v, clause_size)
+ && (++cnt > cls.size() + grow
+ || (clause_lim != -1 && clause_size > clause_lim)))
+ return true;
// Delete and store old clauses:
eliminated[v] = true;
@@ -552,10 +558,9 @@ bool SimpSolver::eliminateVar(Var v)
mkElimClause(elimclauses, ~mkLit(v));
}
- for (int i = 0; i < cls.size(); i++)
- removeClause(cls[i]);
+ for (int i = 0; i < cls.size(); i++) removeClause(cls[i]);
- ClauseId id = ClauseIdUndef;
+ ClauseId id = ClauseIdUndef;
// Produce clauses in cross product:
vec<Lit>& resolvent = add_tmp;
for (int i = 0; i < pos.size(); i++)
@@ -569,7 +574,7 @@ bool SimpSolver::eliminateVar(Var v)
// Free occurs list for this variable:
occurs[v].clear(true);
-
+
// Free watchers lists for this variable, if possible:
if (watches[ mkLit(v)].size() == 0) watches[ mkLit(v)].clear(true);
if (watches[~mkLit(v)].size() == 0) watches[~mkLit(v)].clear(true);
@@ -589,7 +594,7 @@ bool SimpSolver::substitute(Var v, Lit x)
eliminated[v] = true;
setDecisionVar(v, false);
const vec<CRef>& cls = occurs.lookup(v);
-
+
vec<Lit>& subst_clause = add_tmp;
for (int i = 0; i < cls.size(); i++){
Clause& c = ca[cls[i]];
@@ -641,9 +646,12 @@ bool SimpSolver::eliminate(bool turn_off_elim)
gatherTouchedClauses();
// printf(" ## (time = %6.2f s) BWD-SUB: queue = %d, trail = %d\n", cpuTime(), subsumption_queue.size(), trail.size() - bwdsub_assigns);
- if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size()) &&
- !backwardSubsumptionCheck(true)){
- ok = false; goto cleanup; }
+ if ((subsumption_queue.size() > 0 || bwdsub_assigns < trail.size())
+ && !backwardSubsumptionCheck(true))
+ {
+ ok = false;
+ goto cleanup;
+ }
// Empty elim_heap and return immediately on user-interrupt:
if (asynch_interrupt){
@@ -656,7 +664,7 @@ bool SimpSolver::eliminate(bool turn_off_elim)
// printf(" ## (time = %6.2f s) ELIM: vars = %d\n", cpuTime(), elim_heap.size());
for (int cnt = 0; !elim_heap.empty(); cnt++){
Var elim = elim_heap.removeMin();
-
+
if (asynch_interrupt) break;
if (isEliminated(elim) || value(elim) != l_Undef) continue;
@@ -706,8 +714,10 @@ bool SimpSolver::eliminate(bool turn_off_elim)
}
if (verbosity >= 1 && elimclauses.size() > 0)
- printf("| Eliminated clauses: %10.2f Mb |\n",
- double(elimclauses.size() * sizeof(uint32_t)) / (1024*1024));
+ printf(
+ "| Eliminated clauses: %10.2f Mb "
+ " |\n",
+ double(elimclauses.size() * sizeof(uint32_t)) / (1024 * 1024));
return ok;
}
@@ -744,11 +754,11 @@ void SimpSolver::relocAll(ClauseAllocator& to)
//
for (int i = 0; i < subsumption_queue.size(); i++)
ca.reloc(subsumption_queue[i], to);
- // TODO reloc now takes the proof form the core solver
+ // TODO reloc now takes the proof form the core solver
// Temporary clause:
//
ca.reloc(bwdsub_tmpunit, to);
- // TODO reloc now takes the proof form the core solver
+ // TODO reloc now takes the proof form the core solver
}
@@ -756,15 +766,17 @@ void SimpSolver::garbageCollect()
{
// Initialize the next region to a size corresponding to the estimated utilization degree. This
// is not precise but should avoid some unnecessary reallocations for the new region:
- ClauseAllocator to(ca.size() - ca.wasted());
+ ClauseAllocator to(ca.size() - ca.wasted());
cleanUpClauses();
to.extra_clause_field = ca.extra_clause_field; // NOTE: this is important to keep (or lose) the extra fields.
relocAll(to);
Solver::relocAll(to);
if (verbosity >= 2)
- printf("| Garbage collection: %12d bytes => %12d bytes |\n",
- ca.size()*ClauseAllocator::Unit_Size, to.size()*ClauseAllocator::Unit_Size);
+ printf(
+ "| Garbage collection: %12d bytes => %12d bytes |\n",
+ ca.size() * ClauseAllocator::Unit_Size,
+ to.size() * ClauseAllocator::Unit_Size);
to.moveTo(ca);
- // TODO: proof.finalizeUpdateId();
+ // TODO: proof.finalizeUpdateId();
}
diff --git a/src/prop/minisat/simp/SimpSolver.h b/src/prop/minisat/simp/SimpSolver.h
index 335075f09..c13ee5583 100644
--- a/src/prop/minisat/simp/SimpSolver.h
+++ b/src/prop/minisat/simp/SimpSolver.h
@@ -55,7 +55,7 @@ class SimpSolver : public Solver {
bool addClause (Lit p, Lit q, bool removable, ClauseId& id); // Add a binary clause to the solver.
bool addClause (Lit p, Lit q, Lit r, bool removable, ClauseId& id); // Add a ternary clause to the solver.
bool addClause_(vec<Lit>& ps, bool removable, ClauseId& id);
- bool substitute(Var v, Lit x); // Replace all occurences of v with x (may cause a contradiction).
+ bool substitute(Var v, Lit x); // Replace all occurrences of v with x (may cause a contradiction).
// Variable mode:
//
diff --git a/src/prop/proof_cnf_stream.cpp b/src/prop/proof_cnf_stream.cpp
new file mode 100644
index 000000000..790e5aeb2
--- /dev/null
+++ b/src/prop/proof_cnf_stream.cpp
@@ -0,0 +1,981 @@
+/********************* */
+/*! \file proof_cnf_stream.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Haniel Barbosa
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of the proof-producing CNF stream
+ **/
+
+#include "prop/proof_cnf_stream.h"
+
+#include "options/smt_options.h"
+#include "prop/minisat/minisat.h"
+#include "theory/builtin/proof_checker.h"
+
+namespace CVC4 {
+namespace prop {
+
+ProofCnfStream::ProofCnfStream(context::UserContext* u,
+ CnfStream& cnfStream,
+ SatProofManager* satPM,
+ ProofNodeManager* pnm)
+ : d_cnfStream(cnfStream),
+ d_satPM(satPM),
+ d_proof(pnm, nullptr, u, "ProofCnfStream::LazyCDProof"),
+ d_blocked(u)
+{
+}
+
+void ProofCnfStream::addBlocked(std::shared_ptr<ProofNode> pfn)
+{
+ d_blocked.insert(pfn);
+}
+
+bool ProofCnfStream::isBlocked(std::shared_ptr<ProofNode> pfn)
+{
+ return d_blocked.contains(pfn);
+}
+
+std::shared_ptr<ProofNode> ProofCnfStream::getProofFor(Node f)
+{
+ return d_proof.getProofFor(f);
+}
+
+bool ProofCnfStream::hasProofFor(Node f)
+{
+ return d_proof.hasStep(f) || d_proof.hasGenerator(f);
+}
+
+std::string ProofCnfStream::identify() const { return "ProofCnfStream"; }
+
+void ProofCnfStream::normalizeAndRegister(TNode clauseNode)
+{
+ Node normClauseNode = d_psb.factorReorderElimDoubleNeg(clauseNode);
+ if (Trace.isOn("cnf") && normClauseNode != clauseNode)
+ {
+ Trace("cnf") << push
+ << "ProofCnfStream::normalizeAndRegister: steps to normalized "
+ << normClauseNode << "\n"
+ << pop;
+ }
+ d_satPM->registerSatAssumptions({normClauseNode});
+}
+
+void ProofCnfStream::convertAndAssert(TNode node,
+ bool negated,
+ bool removable,
+ ProofGenerator* pg)
+{
+ Trace("cnf") << "ProofCnfStream::convertAndAssert(" << node
+ << ", negated = " << (negated ? "true" : "false")
+ << ", removable = " << (removable ? "true" : "false") << ")\n";
+ d_removable = removable;
+ if (pg)
+ {
+ Trace("cnf") << "ProofCnfStream::convertAndAssert: pg: " << pg->identify()
+ << "\n";
+ Node toJustify = negated ? node.notNode() : static_cast<Node>(node);
+ d_proof.addLazyStep(toJustify,
+ pg,
+ PfRule::ASSUME,
+ true,
+ "ProofCnfStream::convertAndAssert:cnf");
+ }
+ convertAndAssert(node, negated);
+ // process saved steps in buffer
+ const std::vector<std::pair<Node, ProofStep>>& steps = d_psb.getSteps();
+ for (const std::pair<Node, ProofStep>& step : steps)
+ {
+ d_proof.addStep(step.first, step.second);
+ }
+ d_psb.clear();
+}
+
+void ProofCnfStream::convertAndAssert(TNode node, bool negated)
+{
+ Trace("cnf") << "ProofCnfStream::convertAndAssert(" << node
+ << ", negated = " << (negated ? "true" : "false") << ")\n";
+ switch (node.getKind())
+ {
+ case kind::AND: convertAndAssertAnd(node, negated); break;
+ case kind::OR: convertAndAssertOr(node, negated); break;
+ case kind::XOR: convertAndAssertXor(node, negated); break;
+ case kind::IMPLIES: convertAndAssertImplies(node, negated); break;
+ case kind::ITE: convertAndAssertIte(node, negated); break;
+ case kind::NOT:
+ {
+ // track double negation elimination
+ if (negated)
+ {
+ d_proof.addStep(node[0], PfRule::NOT_NOT_ELIM, {node.notNode()}, {});
+ Trace("cnf")
+ << "ProofCnfStream::convertAndAssert: NOT_NOT_ELIM added norm "
+ << node[0] << "\n";
+ }
+ convertAndAssert(node[0], !negated);
+ break;
+ }
+ case kind::EQUAL:
+ if (node[0].getType().isBoolean())
+ {
+ convertAndAssertIff(node, negated);
+ break;
+ }
+ CVC4_FALLTHROUGH;
+ default:
+ {
+ // negate
+ Node nnode = negated ? node.negate() : static_cast<Node>(node);
+ // Atoms
+ SatLiteral lit = toCNF(node, negated);
+ bool added = d_cnfStream.assertClause(nnode, lit);
+ if (negated && added && nnode != node.notNode())
+ {
+ // track double negation elimination
+ // (not (not n))
+ // -------------- NOT_NOT_ELIM
+ // n
+ d_proof.addStep(nnode, PfRule::NOT_NOT_ELIM, {node.notNode()}, {});
+ Trace("cnf")
+ << "ProofCnfStream::convertAndAssert: NOT_NOT_ELIM added norm "
+ << nnode << "\n";
+ }
+ if (added)
+ {
+ // note that we do not need to do the normalization here since this is
+ // not a clause and double negation is tracked in a dedicated manner
+ // above
+ d_satPM->registerSatAssumptions({nnode});
+ }
+ }
+ }
+}
+
+void ProofCnfStream::convertAndAssertAnd(TNode node, bool negated)
+{
+ Trace("cnf") << "ProofCnfStream::convertAndAssertAnd(" << node
+ << ", negated = " << (negated ? "true" : "false") << ")\n";
+ Assert(node.getKind() == kind::AND);
+ if (!negated)
+ {
+ // If the node is a conjunction, we handle each conjunct separately
+ NodeManager* nm = NodeManager::currentNM();
+ for (unsigned i = 0, size = node.getNumChildren(); i < size; ++i)
+ {
+ // Create a proof step for each n_i
+ Node iNode = nm->mkConst<Rational>(i);
+ d_proof.addStep(node[i], PfRule::AND_ELIM, {node}, {iNode});
+ Trace("cnf") << "ProofCnfStream::convertAndAssertAnd: AND_ELIM " << i
+ << " added norm " << node[i] << "\n";
+ convertAndAssert(node[i], false);
+ }
+ }
+ else
+ {
+ // If the node is a disjunction, we construct a clause and assert it
+ unsigned i, size = node.getNumChildren();
+ SatClause clause(size);
+ for (i = 0; i < size; ++i)
+ {
+ clause[i] = toCNF(node[i], true);
+ }
+ bool added = d_cnfStream.assertClause(node.negate(), clause);
+ // register proof step
+ if (added)
+ {
+ std::vector<Node> disjuncts;
+ for (i = 0; i < size; ++i)
+ {
+ disjuncts.push_back(node[i].notNode());
+ }
+ Node clauseNode = NodeManager::currentNM()->mkNode(kind::OR, disjuncts);
+ d_proof.addStep(clauseNode, PfRule::NOT_AND, {node.notNode()}, {});
+ Trace("cnf") << "ProofCnfStream::convertAndAssertAnd: NOT_AND added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ }
+}
+
+void ProofCnfStream::convertAndAssertOr(TNode node, bool negated)
+{
+ Trace("cnf") << "ProofCnfStream::convertAndAssertOr(" << node
+ << ", negated = " << (negated ? "true" : "false") << ")\n";
+ Assert(node.getKind() == kind::OR);
+ if (!negated)
+ {
+ // If the node is a disjunction, we construct a clause and assert it
+ unsigned size = node.getNumChildren();
+ SatClause clause(size);
+ for (unsigned i = 0; i < size; ++i)
+ {
+ clause[i] = toCNF(node[i], false);
+ }
+ normalizeAndRegister(node);
+ d_cnfStream.assertClause(node, clause);
+ }
+ else
+ {
+ // If the node is a negated disjunction, we handle it as a conjunction of
+ // the negated arguments
+ NodeManager* nm = NodeManager::currentNM();
+ for (unsigned i = 0, size = node.getNumChildren(); i < size; ++i)
+ {
+ // Create a proof step for each (not n_i)
+ Node iNode = nm->mkConst<Rational>(i);
+ d_proof.addStep(
+ node[i].notNode(), PfRule::NOT_OR_ELIM, {node.notNode()}, {iNode});
+ Trace("cnf") << "ProofCnfStream::convertAndAssertOr: NOT_OR_ELIM " << i
+ << " added norm " << node[i].notNode() << "\n";
+ convertAndAssert(node[i], true);
+ }
+ }
+}
+
+void ProofCnfStream::convertAndAssertXor(TNode node, bool negated)
+{
+ Trace("cnf") << "ProofCnfStream::convertAndAssertXor(" << node
+ << ", negated = " << (negated ? "true" : "false") << ")\n";
+ if (!negated)
+ {
+ // p XOR q
+ SatLiteral p = toCNF(node[0], false);
+ SatLiteral q = toCNF(node[1], false);
+ bool added;
+ NodeManager* nm = NodeManager::currentNM();
+ // Construct the clause (~p v ~q)
+ SatClause clause1(2);
+ clause1[0] = ~p;
+ clause1[1] = ~q;
+ added = d_cnfStream.assertClause(node, clause1);
+ if (added)
+ {
+ Node clauseNode =
+ nm->mkNode(kind::OR, node[0].notNode(), node[1].notNode());
+ d_proof.addStep(clauseNode, PfRule::XOR_ELIM2, {node}, {});
+ Trace("cnf") << "ProofCnfStream::convertAndAssertXor: XOR_ELIM2 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ // Construct the clause (p v q)
+ SatClause clause2(2);
+ clause2[0] = p;
+ clause2[1] = q;
+ added = d_cnfStream.assertClause(node, clause2);
+ if (added)
+ {
+ Node clauseNode = nm->mkNode(kind::OR, node[0], node[1]);
+ d_proof.addStep(clauseNode, PfRule::XOR_ELIM1, {node}, {});
+ Trace("cnf") << "ProofCnfStream::convertAndAssertXor: XOR_ELIM1 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ }
+ else
+ {
+ // ~(p XOR q) is the same as p <=> q
+ SatLiteral p = toCNF(node[0], false);
+ SatLiteral q = toCNF(node[1], false);
+ bool added;
+ NodeManager* nm = NodeManager::currentNM();
+ // Construct the clause ~p v q
+ SatClause clause1(2);
+ clause1[0] = ~p;
+ clause1[1] = q;
+ added = d_cnfStream.assertClause(node.negate(), clause1);
+ if (added)
+ {
+ Node clauseNode = nm->mkNode(kind::OR, node[0].notNode(), node[1]);
+ d_proof.addStep(clauseNode, PfRule::NOT_XOR_ELIM2, {node.notNode()}, {});
+ Trace("cnf")
+ << "ProofCnfStream::convertAndAssertXor: NOT_XOR_ELIM2 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ // Construct the clause ~q v p
+ SatClause clause2(2);
+ clause2[0] = p;
+ clause2[1] = ~q;
+ added = d_cnfStream.assertClause(node.negate(), clause2);
+ if (added)
+ {
+ Node clauseNode = nm->mkNode(kind::OR, node[0], node[1].notNode());
+ d_proof.addStep(clauseNode, PfRule::NOT_XOR_ELIM1, {node.notNode()}, {});
+ Trace("cnf")
+ << "ProofCnfStream::convertAndAssertXor: NOT_XOR_ELIM1 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ }
+}
+
+void ProofCnfStream::convertAndAssertIff(TNode node, bool negated)
+{
+ Trace("cnf") << "ProofCnfStream::convertAndAssertIff(" << node
+ << ", negated = " << (negated ? "true" : "false") << ")\n";
+ if (!negated)
+ {
+ // p <=> q
+ Trace("cnf") << push;
+ SatLiteral p = toCNF(node[0], false);
+ SatLiteral q = toCNF(node[1], false);
+ Trace("cnf") << pop;
+ bool added;
+ NodeManager* nm = NodeManager::currentNM();
+ // Construct the clauses ~p v q
+ SatClause clause1(2);
+ clause1[0] = ~p;
+ clause1[1] = q;
+ added = d_cnfStream.assertClause(node, clause1);
+ if (added)
+ {
+ Node clauseNode = nm->mkNode(kind::OR, node[0].notNode(), node[1]);
+ d_proof.addStep(clauseNode, PfRule::EQUIV_ELIM1, {node}, {});
+ Trace("cnf") << "ProofCnfStream::convertAndAssertIff: EQUIV_ELIM1 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ // Construct the clauses ~q v p
+ SatClause clause2(2);
+ clause2[0] = p;
+ clause2[1] = ~q;
+ added = d_cnfStream.assertClause(node, clause2);
+ if (added)
+ {
+ Node clauseNode = nm->mkNode(kind::OR, node[0], node[1].notNode());
+ d_proof.addStep(clauseNode, PfRule::EQUIV_ELIM2, {node}, {});
+ Trace("cnf") << "ProofCnfStream::convertAndAssertIff: EQUIV_ELIM2 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ }
+ else
+ {
+ // ~(p <=> q) is the same as p XOR q
+ Trace("cnf") << push;
+ SatLiteral p = toCNF(node[0], false);
+ SatLiteral q = toCNF(node[1], false);
+ Trace("cnf") << pop;
+ bool added;
+ NodeManager* nm = NodeManager::currentNM();
+ // Construct the clauses ~p v ~q
+ SatClause clause1(2);
+ clause1[0] = ~p;
+ clause1[1] = ~q;
+ added = d_cnfStream.assertClause(node.negate(), clause1);
+ if (added)
+ {
+ Node clauseNode =
+ nm->mkNode(kind::OR, node[0].notNode(), node[1].notNode());
+ d_proof.addStep(
+ clauseNode, PfRule::NOT_EQUIV_ELIM2, {node.notNode()}, {});
+ Trace("cnf")
+ << "ProofCnfStream::convertAndAssertIff: NOT_EQUIV_ELIM2 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ // Construct the clauses q v p
+ SatClause clause2(2);
+ clause2[0] = p;
+ clause2[1] = q;
+ added = d_cnfStream.assertClause(node.negate(), clause2);
+ if (added)
+ {
+ Node clauseNode = nm->mkNode(kind::OR, node[0], node[1]);
+ d_proof.addStep(
+ clauseNode, PfRule::NOT_EQUIV_ELIM1, {node.notNode()}, {});
+ Trace("cnf")
+ << "ProofCnfStream::convertAndAssertIff: NOT_EQUIV_ELIM1 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ }
+}
+
+void ProofCnfStream::convertAndAssertImplies(TNode node, bool negated)
+{
+ Trace("cnf") << "ProofCnfStream::convertAndAssertImplies(" << node
+ << ", negated = " << (negated ? "true" : "false") << ")\n";
+ if (!negated)
+ {
+ // ~p v q
+ SatLiteral p = toCNF(node[0], false);
+ SatLiteral q = toCNF(node[1], false);
+ // Construct the clause ~p || q
+ SatClause clause(2);
+ clause[0] = ~p;
+ clause[1] = q;
+ bool added = d_cnfStream.assertClause(node, clause);
+ if (added)
+ {
+ Node clauseNode = NodeManager::currentNM()->mkNode(
+ kind::OR, node[0].notNode(), node[1]);
+ d_proof.addStep(clauseNode, PfRule::IMPLIES_ELIM, {node}, {});
+ Trace("cnf")
+ << "ProofCnfStream::convertAndAssertImplies: IMPLIES_ELIM added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ }
+ else
+ {
+ // ~(p => q) is the same as p ^ ~q
+ // process p
+ convertAndAssert(node[0], false);
+ d_proof.addStep(node[0], PfRule::NOT_IMPLIES_ELIM1, {node.notNode()}, {});
+ Trace("cnf")
+ << "ProofCnfStream::convertAndAssertImplies: NOT_IMPLIES_ELIM1 added "
+ << node[0] << "\n";
+ // process ~q
+ convertAndAssert(node[1], true);
+ d_proof.addStep(
+ node[1].notNode(), PfRule::NOT_IMPLIES_ELIM2, {node.notNode()}, {});
+ Trace("cnf")
+ << "ProofCnfStream::convertAndAssertImplies: NOT_IMPLIES_ELIM2 added "
+ << node[1].notNode() << "\n";
+ }
+}
+
+void ProofCnfStream::convertAndAssertIte(TNode node, bool negated)
+{
+ Trace("cnf") << "ProofCnfStream::convertAndAssertIte(" << node
+ << ", negated = " << (negated ? "true" : "false") << ")\n";
+ // ITE(p, q, r)
+ SatLiteral p = toCNF(node[0], false);
+ SatLiteral q = toCNF(node[1], negated);
+ SatLiteral r = toCNF(node[2], negated);
+ bool added;
+ NodeManager* nm = NodeManager::currentNM();
+ // Construct the clauses:
+ // (~p v q) and (p v r)
+ //
+ // Note that below q and r can be used directly because whether they are
+ // negated has been push to the literal definitions above
+ Node nnode = negated ? node.negate() : static_cast<Node>(node);
+ // (~p v q)
+ SatClause clause1(2);
+ clause1[0] = ~p;
+ clause1[1] = q;
+ added = d_cnfStream.assertClause(nnode, clause1);
+ if (added)
+ {
+ // redo the negation here to avoid silent double negation elimination
+ if (!negated)
+ {
+ Node clauseNode = nm->mkNode(kind::OR, node[0].notNode(), node[1]);
+ d_proof.addStep(clauseNode, PfRule::ITE_ELIM1, {node}, {});
+ Trace("cnf") << "ProofCnfStream::convertAndAssertIte: ITE_ELIM1 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ else
+ {
+ Node clauseNode =
+ nm->mkNode(kind::OR, node[0].notNode(), node[1].notNode());
+ d_proof.addStep(clauseNode, PfRule::NOT_ITE_ELIM1, {node.notNode()}, {});
+ Trace("cnf")
+ << "ProofCnfStream::convertAndAssertIte: NOT_ITE_ELIM1 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ }
+ // (p v r)
+ SatClause clause2(2);
+ clause2[0] = p;
+ clause2[1] = r;
+ added = d_cnfStream.assertClause(nnode, clause2);
+ if (added)
+ {
+ // redo the negation here to avoid silent double negation elimination
+ if (!negated)
+ {
+ Node clauseNode = nm->mkNode(kind::OR, node[0], node[2]);
+ d_proof.addStep(clauseNode, PfRule::ITE_ELIM2, {node}, {});
+ Trace("cnf") << "ProofCnfStream::convertAndAssertIte: ITE_ELIM2 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ else
+ {
+ Node clauseNode = nm->mkNode(kind::OR, node[0], node[2].notNode());
+ d_proof.addStep(clauseNode, PfRule::NOT_ITE_ELIM2, {node.notNode()}, {});
+ Trace("cnf")
+ << "ProofCnfStream::convertAndAssertIte: NOT_ITE_ELIM2 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ }
+}
+
+void ProofCnfStream::convertPropagation(theory::TrustNode trn)
+{
+ Node proven = trn.getProven();
+ Trace("cnf") << "ProofCnfStream::convertPropagation: proven explanation"
+ << proven << "\n";
+ Assert(trn.getGenerator());
+ Assert(trn.getGenerator()->getProofFor(proven)->isClosed());
+ Trace("cnf-steps") << proven << " by explainPropagation "
+ << trn.identifyGenerator() << std::endl;
+ d_proof.addLazyStep(proven,
+ trn.getGenerator(),
+ PfRule::ASSUME,
+ true,
+ "ProofCnfStream::convertPropagation");
+ // since the propagation is added directly to the SAT solver via theoryProxy,
+ // do the transformation of the lemma E1 ^ ... ^ En => P into CNF here
+ NodeManager* nm = NodeManager::currentNM();
+ Node clauseImpliesElim = nm->mkNode(kind::OR, proven[0].notNode(), proven[1]);
+ Trace("cnf") << "ProofCnfStream::convertPropagation: adding "
+ << PfRule::IMPLIES_ELIM << " rule to conclude "
+ << clauseImpliesElim << "\n";
+ d_proof.addStep(clauseImpliesElim, PfRule::IMPLIES_ELIM, {proven}, {});
+ Node clauseExp;
+ // need to eliminate AND
+ if (proven[0].getKind() == kind::AND)
+ {
+ std::vector<Node> disjunctsAndNeg{proven[0]};
+ std::vector<Node> disjunctsRes;
+ for (unsigned i = 0, size = proven[0].getNumChildren(); i < size; ++i)
+ {
+ disjunctsAndNeg.push_back(proven[0][i].notNode());
+ disjunctsRes.push_back(proven[0][i].notNode());
+ }
+ disjunctsRes.push_back(proven[1]);
+ Node clauseAndNeg = nm->mkNode(kind::OR, disjunctsAndNeg);
+ // add proof steps to convert into clause
+ d_proof.addStep(clauseAndNeg, PfRule::CNF_AND_NEG, {}, {proven[0]});
+ clauseExp = nm->mkNode(kind::OR, disjunctsRes);
+ d_proof.addStep(clauseExp,
+ PfRule::RESOLUTION,
+ {clauseAndNeg, clauseImpliesElim},
+ {nm->mkConst(true), proven[0]});
+ }
+ else
+ {
+ clauseExp = clauseImpliesElim;
+ }
+ normalizeAndRegister(clauseExp);
+ // consume steps
+ const std::vector<std::pair<Node, ProofStep>>& steps = d_psb.getSteps();
+ for (const std::pair<Node, ProofStep>& step : steps)
+ {
+ d_proof.addStep(step.first, step.second);
+ }
+ d_psb.clear();
+}
+
+SatLiteral ProofCnfStream::toCNF(TNode node, bool negated)
+{
+ Trace("cnf") << "toCNF(" << node
+ << ", negated = " << (negated ? "true" : "false") << ")\n";
+ SatLiteral lit;
+ // If the node has already has a literal, return it (maybe negated)
+ if (d_cnfStream.hasLiteral(node))
+ {
+ Trace("cnf") << "toCNF(): already translated\n";
+ lit = d_cnfStream.getLiteral(node);
+ // Return the (maybe negated) literal
+ return !negated ? lit : ~lit;
+ }
+
+ // Handle each Boolean operator case
+ switch (node.getKind())
+ {
+ case kind::AND: lit = handleAnd(node); break;
+ case kind::OR: lit = handleOr(node); break;
+ case kind::XOR: lit = handleXor(node); break;
+ case kind::IMPLIES: lit = handleImplies(node); break;
+ case kind::ITE: lit = handleIte(node); break;
+ case kind::NOT: lit = ~toCNF(node[0]); break;
+ case kind::EQUAL:
+ lit = node[0].getType().isBoolean() ? handleIff(node)
+ : d_cnfStream.convertAtom(node);
+ break;
+ default: { lit = d_cnfStream.convertAtom(node);
+ }
+ break;
+ }
+ // Return the (maybe negated) literal
+ return !negated ? lit : ~lit;
+}
+
+SatLiteral ProofCnfStream::handleAnd(TNode node)
+{
+ Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!";
+ Assert(node.getKind() == kind::AND) << "Expecting an AND expression!";
+ Assert(node.getNumChildren() > 1) << "Expecting more than 1 child!";
+ Assert(!d_removable) << "Removable clauses cannot contain Boolean structure";
+ Trace("cnf") << "ProofCnfStream::handleAnd(" << node << ")\n";
+ // Number of children
+ unsigned size = node.getNumChildren();
+ // Transform all the children first (remembering the negation)
+ SatClause clause(size + 1);
+ for (unsigned i = 0; i < size; ++i)
+ {
+ Trace("cnf") << push;
+ clause[i] = ~toCNF(node[i]);
+ Trace("cnf") << pop;
+ }
+ // Create literal for the node
+ SatLiteral lit = d_cnfStream.newLiteral(node);
+ bool added;
+ NodeManager* nm = NodeManager::currentNM();
+ // lit -> (a_1 & a_2 & a_3 & ... & a_n)
+ // ~lit | (a_1 & a_2 & a_3 & ... & a_n)
+ // (~lit | a_1) & (~lit | a_2) & ... & (~lit | a_n)
+ for (unsigned i = 0; i < size; ++i)
+ {
+ Trace("cnf") << push;
+ added = d_cnfStream.assertClause(node.negate(), ~lit, ~clause[i]);
+ Trace("cnf") << pop;
+ if (added)
+ {
+ Node clauseNode = nm->mkNode(kind::OR, node.notNode(), node[i]);
+ Node iNode = nm->mkConst<Rational>(i);
+ d_proof.addStep(clauseNode, PfRule::CNF_AND_POS, {}, {node, iNode});
+ Trace("cnf") << "ProofCnfStream::handleAnd: CNF_AND_POS " << i
+ << " added " << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ }
+ // lit <- (a_1 & a_2 & a_3 & ... a_n)
+ // lit | ~(a_1 & a_2 & a_3 & ... & a_n)
+ // lit | ~a_1 | ~a_2 | ~a_3 | ... | ~a_n
+ clause[size] = lit;
+ // This needs to go last, as the clause might get modified by the SAT solver
+ Trace("cnf") << push;
+ added = d_cnfStream.assertClause(node, clause);
+ Trace("cnf") << pop;
+ if (added)
+ {
+ std::vector<Node> disjuncts{node};
+ for (unsigned i = 0; i < size; ++i)
+ {
+ disjuncts.push_back(node[i].notNode());
+ }
+ Node clauseNode = nm->mkNode(kind::OR, disjuncts);
+ d_proof.addStep(clauseNode, PfRule::CNF_AND_NEG, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleAnd: CNF_AND_NEG added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ return lit;
+}
+
+SatLiteral ProofCnfStream::handleOr(TNode node)
+{
+ Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!";
+ Assert(node.getKind() == kind::OR) << "Expecting an OR expression!";
+ Assert(node.getNumChildren() > 1) << "Expecting more then 1 child!";
+ Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
+ Trace("cnf") << "ProofCnfStream::handleOr(" << node << ")\n";
+ // Number of children
+ unsigned size = node.getNumChildren();
+ // Transform all the children first
+ SatClause clause(size + 1);
+ for (unsigned i = 0; i < size; ++i)
+ {
+ clause[i] = toCNF(node[i]);
+ }
+ // Create literal for the node
+ SatLiteral lit = d_cnfStream.newLiteral(node);
+ bool added;
+ NodeManager* nm = NodeManager::currentNM();
+ // lit <- (a_1 | a_2 | a_3 | ... | a_n)
+ // lit | ~(a_1 | a_2 | a_3 | ... | a_n)
+ // (lit | ~a_1) & (lit | ~a_2) & (lit & ~a_3) & ... & (lit & ~a_n)
+ for (unsigned i = 0; i < size; ++i)
+ {
+ added = d_cnfStream.assertClause(node, lit, ~clause[i]);
+ if (added)
+ {
+ Node clauseNode = nm->mkNode(kind::OR, node, node[i].notNode());
+ Node iNode = nm->mkConst<Rational>(i);
+ d_proof.addStep(clauseNode, PfRule::CNF_OR_NEG, {}, {node, iNode});
+ Trace("cnf") << "ProofCnfStream::handleOr: CNF_OR_NEG " << i << " added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ }
+ // lit -> (a_1 | a_2 | a_3 | ... | a_n)
+ // ~lit | a_1 | a_2 | a_3 | ... | a_n
+ clause[size] = ~lit;
+ // This needs to go last, as the clause might get modified by the SAT solver
+ added = d_cnfStream.assertClause(node.negate(), clause);
+ if (added)
+ {
+ std::vector<Node> disjuncts{node.notNode()};
+ for (unsigned i = 0; i < size; ++i)
+ {
+ disjuncts.push_back(node[i]);
+ }
+ Node clauseNode = nm->mkNode(kind::OR, disjuncts);
+ d_proof.addStep(clauseNode, PfRule::CNF_OR_POS, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleOr: CNF_OR_POS added " << clauseNode
+ << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ return lit;
+}
+
+SatLiteral ProofCnfStream::handleXor(TNode node)
+{
+ Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!";
+ Assert(node.getKind() == kind::XOR) << "Expecting an XOR expression!";
+ Assert(node.getNumChildren() == 2) << "Expecting exactly 2 children!";
+ Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
+ Trace("cnf") << "ProofCnfStream::handleXor(" << node << ")\n";
+ SatLiteral a = toCNF(node[0]);
+ SatLiteral b = toCNF(node[1]);
+ SatLiteral lit = d_cnfStream.newLiteral(node);
+ bool added;
+ added = d_cnfStream.assertClause(node.negate(), a, b, ~lit);
+ if (added)
+ {
+ Node clauseNode = NodeManager::currentNM()->mkNode(
+ kind::OR, node.notNode(), node[0], node[1]);
+ d_proof.addStep(clauseNode, PfRule::CNF_XOR_POS1, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleXor: CNF_XOR_POS1 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ added = d_cnfStream.assertClause(node.negate(), ~a, ~b, ~lit);
+ if (added)
+ {
+ Node clauseNode = NodeManager::currentNM()->mkNode(
+ kind::OR, node.notNode(), node[0].notNode(), node[1].notNode());
+ d_proof.addStep(clauseNode, PfRule::CNF_XOR_POS2, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleXor: CNF_XOR_POS2 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ added = d_cnfStream.assertClause(node, a, ~b, lit);
+ if (added)
+ {
+ Node clauseNode = NodeManager::currentNM()->mkNode(
+ kind::OR, node, node[0], node[1].notNode());
+ d_proof.addStep(clauseNode, PfRule::CNF_XOR_NEG2, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleXor: CNF_XOR_NEG2 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ added = d_cnfStream.assertClause(node, ~a, b, lit);
+ if (added)
+ {
+ Node clauseNode = NodeManager::currentNM()->mkNode(
+ kind::OR, node, node[0].notNode(), node[1]);
+ d_proof.addStep(clauseNode, PfRule::CNF_XOR_NEG1, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleXor: CNF_XOR_NEG1 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ return lit;
+}
+
+SatLiteral ProofCnfStream::handleIff(TNode node)
+{
+ Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!";
+ Assert(node.getKind() == kind::EQUAL) << "Expecting an EQUAL expression!";
+ Assert(node.getNumChildren() == 2) << "Expecting exactly 2 children!";
+ Trace("cnf") << "handleIff(" << node << ")\n";
+ // Convert the children to CNF
+ SatLiteral a = toCNF(node[0]);
+ SatLiteral b = toCNF(node[1]);
+ // Create literal for the node
+ SatLiteral lit = d_cnfStream.newLiteral(node);
+ bool added;
+ NodeManager* nm = NodeManager::currentNM();
+ // lit -> ((a-> b) & (b->a))
+ // ~lit | ((~a | b) & (~b | a))
+ // (~a | b | ~lit) & (~b | a | ~lit)
+ added = d_cnfStream.assertClause(node.negate(), ~a, b, ~lit);
+ if (added)
+ {
+ Node clauseNode =
+ nm->mkNode(kind::OR, node.notNode(), node[0].notNode(), node[1]);
+ d_proof.addStep(clauseNode, PfRule::CNF_EQUIV_POS1, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleIff: CNF_EQUIV_POS1 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ added = d_cnfStream.assertClause(node.negate(), a, ~b, ~lit);
+ if (added)
+ {
+ Node clauseNode =
+ nm->mkNode(kind::OR, node.notNode(), node[0], node[1].notNode());
+ d_proof.addStep(clauseNode, PfRule::CNF_EQUIV_POS2, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleIff: CNF_EQUIV_POS2 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ // (a<->b) -> lit
+ // ~((a & b) | (~a & ~b)) | lit
+ // (~(a & b)) & (~(~a & ~b)) | lit
+ // ((~a | ~b) & (a | b)) | lit
+ // (~a | ~b | lit) & (a | b | lit)
+ added = d_cnfStream.assertClause(node, ~a, ~b, lit);
+ if (added)
+ {
+ Node clauseNode =
+ nm->mkNode(kind::OR, node, node[0].notNode(), node[1].notNode());
+ d_proof.addStep(clauseNode, PfRule::CNF_EQUIV_NEG2, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleIff: CNF_EQUIV_NEG2 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ added = d_cnfStream.assertClause(node, a, b, lit);
+ if (added)
+ {
+ Node clauseNode = nm->mkNode(kind::OR, node, node[0], node[1]);
+ d_proof.addStep(clauseNode, PfRule::CNF_EQUIV_NEG1, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleIff: CNF_EQUIV_NEG1 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ return lit;
+}
+
+SatLiteral ProofCnfStream::handleImplies(TNode node)
+{
+ Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!";
+ Assert(node.getKind() == kind::IMPLIES) << "Expecting an IMPLIES expression!";
+ Assert(node.getNumChildren() == 2) << "Expecting exactly 2 children!";
+ Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
+ Trace("cnf") << "ProofCnfStream::handleImplies(" << node << ")\n";
+ // Convert the children to cnf
+ SatLiteral a = toCNF(node[0]);
+ SatLiteral b = toCNF(node[1]);
+ SatLiteral lit = d_cnfStream.newLiteral(node);
+ bool added;
+ NodeManager* nm = NodeManager::currentNM();
+ // lit -> (a->b)
+ // ~lit | ~ a | b
+ added = d_cnfStream.assertClause(node.negate(), ~lit, ~a, b);
+ if (added)
+ {
+ Node clauseNode =
+ nm->mkNode(kind::OR, node.notNode(), node[0].notNode(), node[1]);
+ d_proof.addStep(clauseNode, PfRule::CNF_IMPLIES_POS, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleImplies: CNF_IMPLIES_POS added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ // (a->b) -> lit
+ // ~(~a | b) | lit
+ // (a | l) & (~b | l)
+ added = d_cnfStream.assertClause(node, a, lit);
+ if (added)
+ {
+ Node clauseNode = nm->mkNode(kind::OR, node, node[0]);
+ d_proof.addStep(clauseNode, PfRule::CNF_IMPLIES_NEG1, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleImplies: CNF_IMPLIES_NEG1 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ added = d_cnfStream.assertClause(node, ~b, lit);
+ if (added)
+ {
+ Node clauseNode = nm->mkNode(kind::OR, node, node[1].notNode());
+ d_proof.addStep(clauseNode, PfRule::CNF_IMPLIES_NEG2, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleImplies: CNF_IMPLIES_NEG2 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ return lit;
+}
+
+SatLiteral ProofCnfStream::handleIte(TNode node)
+{
+ Assert(!d_cnfStream.hasLiteral(node)) << "Atom already mapped!";
+ Assert(node.getKind() == kind::ITE);
+ Assert(node.getNumChildren() == 3);
+ Assert(!d_removable) << "Removable clauses can not contain Boolean structure";
+ Trace("cnf") << "handleIte(" << node[0] << " " << node[1] << " " << node[2]
+ << ")\n";
+ SatLiteral condLit = toCNF(node[0]);
+ SatLiteral thenLit = toCNF(node[1]);
+ SatLiteral elseLit = toCNF(node[2]);
+ // create literal to the node
+ SatLiteral lit = d_cnfStream.newLiteral(node);
+ bool added;
+ NodeManager* nm = NodeManager::currentNM();
+ // If ITE is true then one of the branches is true and the condition
+ // implies which one
+ // lit -> (ite b t e)
+ // lit -> (t | e) & (b -> t) & (!b -> e)
+ // lit -> (t | e) & (!b | t) & (b | e)
+ // (!lit | t | e) & (!lit | !b | t) & (!lit | b | e)
+ added = d_cnfStream.assertClause(node.negate(), ~lit, thenLit, elseLit);
+ if (added)
+ {
+ Node clauseNode = nm->mkNode(kind::OR, node.notNode(), node[1], node[2]);
+ d_proof.addStep(clauseNode, PfRule::CNF_ITE_POS3, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_POS3 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ added = d_cnfStream.assertClause(node.negate(), ~lit, ~condLit, thenLit);
+ if (added)
+ {
+ Node clauseNode =
+ nm->mkNode(kind::OR, node.notNode(), node[0].notNode(), node[1]);
+ d_proof.addStep(clauseNode, PfRule::CNF_ITE_POS1, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_POS1 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ added = d_cnfStream.assertClause(node.negate(), ~lit, condLit, elseLit);
+ if (added)
+ {
+ Node clauseNode = nm->mkNode(kind::OR, node.notNode(), node[0], node[2]);
+ d_proof.addStep(clauseNode, PfRule::CNF_ITE_POS2, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_POS2 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ // If ITE is false then one of the branches is false and the condition
+ // implies which one
+ // !lit -> !(ite b t e)
+ // !lit -> (!t | !e) & (b -> !t) & (!b -> !e)
+ // !lit -> (!t | !e) & (!b | !t) & (b | !e)
+ // (lit | !t | !e) & (lit | !b | !t) & (lit | b | !e)
+ added = d_cnfStream.assertClause(node, lit, ~thenLit, ~elseLit);
+ if (added)
+ {
+ Node clauseNode =
+ nm->mkNode(kind::OR, node, node[1].notNode(), node[2].notNode());
+ d_proof.addStep(clauseNode, PfRule::CNF_ITE_NEG3, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_NEG3 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ added = d_cnfStream.assertClause(node, lit, ~condLit, ~thenLit);
+ if (added)
+ {
+ Node clauseNode =
+ nm->mkNode(kind::OR, node, node[0].notNode(), node[1].notNode());
+ d_proof.addStep(clauseNode, PfRule::CNF_ITE_NEG1, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_NEG1 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ added = d_cnfStream.assertClause(node, lit, condLit, ~elseLit);
+ if (added)
+ {
+ Node clauseNode = nm->mkNode(kind::OR, node, node[0], node[2].notNode());
+ d_proof.addStep(clauseNode, PfRule::CNF_ITE_NEG2, {}, {node});
+ Trace("cnf") << "ProofCnfStream::handleIte: CNF_ITE_NEG2 added "
+ << clauseNode << "\n";
+ normalizeAndRegister(clauseNode);
+ }
+ return lit;
+}
+
+} // namespace prop
+} // namespace CVC4
diff --git a/src/prop/proof_cnf_stream.h b/src/prop/proof_cnf_stream.h
new file mode 100644
index 000000000..80be07231
--- /dev/null
+++ b/src/prop/proof_cnf_stream.h
@@ -0,0 +1,174 @@
+/********************* */
+/*! \file proof_cnf_stream.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Haniel Barbosa
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The proof-producing CNF stream
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__PROP__PROOF_CNF_STREAM_H
+#define CVC4__PROP__PROOF_CNF_STREAM_H
+
+#include "context/cdhashmap.h"
+#include "expr/lazy_proof.h"
+#include "expr/node.h"
+#include "expr/proof_node.h"
+#include "expr/proof_node_manager.h"
+#include "prop/cnf_stream.h"
+#include "prop/sat_proof_manager.h"
+#include "theory/eager_proof_generator.h"
+#include "theory/theory_proof_step_buffer.h"
+
+namespace CVC4 {
+namespace prop {
+
+class SatProofManager;
+
+/**
+ * A proof generator for CNF transformation. It is a layer on top of CNF stream,
+ * tracking the justifications for clauses added into the underlying SAT solver
+ * in a user-context dependent manner in a lazy context-dependent (LazyCDProof)
+ * object. The proof is lazy because formulas asserted to this class may also
+ * take proof generators (which is the case, for example, for theory lemmas), so
+ * that getting the proof of a clausified formula will also extend to its
+ * registered proof generator.
+ */
+class ProofCnfStream : public ProofGenerator
+{
+ public:
+ ProofCnfStream(context::UserContext* u,
+ CnfStream& cnfStream,
+ SatProofManager* satPM,
+ ProofNodeManager* pnm);
+
+ /** Invokes getProofFor of the underlying LazyCDProof */
+ std::shared_ptr<ProofNode> getProofFor(Node f) override;
+ /** Whether there is a concrete step or a generator associated with f in the
+ * underlying LazyCDProof. */
+ bool hasProofFor(Node f) override;
+ /** identify */
+ std::string identify() const override;
+ /**
+ * Converts a formula into CNF into CNF and asserts the generated clauses into
+ * the underlying SAT solver of d_cnfStream. Every transformation the formula
+ * goes through is saved as a concrete step in d_proof.
+ *
+ * The given formula has arbitrary Boolean structure via kinds AND, OR, EQUAL,
+ * XOR, IMPLIES. ITE and NOT. The conversion is done polynomially via Tseitin
+ * transformation, with the children of non-conjunctive kinds being abstracted
+ * as new literals, which are clausified with the respective "handle" methods
+ * below.
+
+ * @param node formula to convert and assert
+ * @param negated whether we are asserting the node negated
+ * @param removable whether the SAT solver can choose to remove the clauses
+ * @param pg a proof generator for node
+ */
+ void convertAndAssert(TNode node,
+ bool negated,
+ bool removable,
+ ProofGenerator* pg);
+
+ /**
+ * Clausifies the given propagation lemma *without* registering the
+ * resoluting clause in the SAT solver, as this is handled internally by the
+ * SAT solver. The clausification steps and the generator within the trust
+ * node are saved in d_proof. */
+ void convertPropagation(theory::TrustNode ttn);
+
+ /**
+ * Blocks a proof, so that it is not further updated by a post processor of
+ * this class's proof. */
+ void addBlocked(std::shared_ptr<ProofNode> pfn);
+
+ /**
+ * Whether a given proof is blocked for further updates. An example of a
+ * blocked proof node is one integrated into this class via an external proof
+ * generator. */
+ bool isBlocked(std::shared_ptr<ProofNode> pfn);
+
+ private:
+ /**
+ * Same as above, except that uses the saved d_removable flag. It calls the
+ * dedicated converter for the possible formula kinds.
+ */
+ void convertAndAssert(TNode node, bool negated);
+ /** Specific converters for each formula kind. */
+ void convertAndAssertAnd(TNode node, bool negated);
+ void convertAndAssertOr(TNode node, bool negated);
+ void convertAndAssertXor(TNode node, bool negated);
+ void convertAndAssertIff(TNode node, bool negated);
+ void convertAndAssertImplies(TNode node, bool negated);
+ void convertAndAssertIte(TNode node, bool negated);
+ /**
+ * Transforms the node into CNF recursively and yields a literal
+ * definitionally equal to it.
+ *
+ * This method also populates caches, kept in d_cnfStream, between formulas
+ * and literals to avoid redundant work and to retrieve formulas from literals
+ * and vice-versa.
+ *
+ * @param node the formula to transform
+ * @param negated whether the literal is negated
+ * @return the literal representing the root of the formula
+ */
+ SatLiteral toCNF(TNode node, bool negated = false);
+ /**
+ * Specific clausifiers, based on the formula kinds, that clausify a formula,
+ * by calling toCNF into each of the formula's children under the respective
+ * kind, and introduce a literal definitionally equal to it. */
+ SatLiteral handleNot(TNode node);
+ SatLiteral handleXor(TNode node);
+ SatLiteral handleImplies(TNode node);
+ SatLiteral handleIff(TNode node);
+ SatLiteral handleIte(TNode node);
+ SatLiteral handleAnd(TNode node);
+ SatLiteral handleOr(TNode node);
+
+ /** Normalizes a clause node and registers it in the SAT proof manager.
+ *
+ * Normalization (factoring, reordering, double negation elimination) is done
+ * via the TheoryProofStepBuffer of this class, which will register the
+ * respective steps, if any. This normalization is necessary so that the
+ * resulting clauses of the clausification process are synchronized with the
+ * clauses used in the underlying SAT solver, which automatically performs the
+ * above normalizations on all added clauses.
+ */
+ void normalizeAndRegister(TNode clauseNode);
+ /**
+ * Are we asserting a removable clause (true) or a permanent clause (false).
+ * This is set at the beginning of convertAndAssert so that it doesn't need to
+ * be passed on over the stack. Only pure clauses can be asserted as
+ * removable.
+ */
+ bool d_removable;
+ /** Reference to the underlying cnf stream. */
+ CnfStream& d_cnfStream;
+ /** The proof manager of underlying SAT solver associated with this stream. */
+ SatProofManager* d_satPM;
+ /** The proof node manager. */
+ ProofNodeManager* d_pnm;
+ /** The user-context-dependent proof object. */
+ LazyCDProof d_proof;
+ /** An accumulator of steps that may be applied to normalize the clauses
+ * generated during clausification. */
+ theory::TheoryProofStepBuffer d_psb;
+ /** Blocked proofs.
+ *
+ * These are proof nodes added to this class by external generators. */
+ context::CDHashSet<std::shared_ptr<ProofNode>, ProofNodeHashFunction>
+ d_blocked;
+};
+
+} // namespace prop
+} // namespace CVC4
+
+#endif
diff --git a/src/prop/proof_post_processor.cpp b/src/prop/proof_post_processor.cpp
new file mode 100644
index 000000000..441805758
--- /dev/null
+++ b/src/prop/proof_post_processor.cpp
@@ -0,0 +1,108 @@
+/********************* */
+/*! \file proof_post_processor.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Haniel Barbosa
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of the module for processing proof nodes in the prop
+ ** engine
+ **/
+
+#include "prop/proof_post_processor.h"
+
+#include "theory/builtin/proof_checker.h"
+
+namespace CVC4 {
+namespace prop {
+
+ProofPostprocessCallback::ProofPostprocessCallback(
+ ProofNodeManager* pnm, ProofCnfStream* proofCnfStream)
+ : d_pnm(pnm), d_proofCnfStream(proofCnfStream)
+{
+}
+
+void ProofPostprocessCallback::initializeUpdate() { d_assumpToProof.clear(); }
+
+bool ProofPostprocessCallback::shouldUpdate(std::shared_ptr<ProofNode> pn,
+ bool& continueUpdate)
+{
+ bool result = pn->getRule() == PfRule::ASSUME
+ && d_proofCnfStream->hasProofFor(pn->getResult());
+ // check if should continue traversing
+ if (d_proofCnfStream->isBlocked(pn))
+ {
+ continueUpdate = false;
+ result = false;
+ }
+ return result;
+}
+
+bool ProofPostprocessCallback::update(Node res,
+ PfRule id,
+ const std::vector<Node>& children,
+ const std::vector<Node>& args,
+ CDProof* cdp,
+ bool& continueUpdate)
+{
+ Trace("prop-proof-pp-debug")
+ << "- Post process " << id << " " << children << " / " << args << "\n";
+ Assert(id == PfRule::ASSUME);
+ // we cache based on the assumption node, not the proof node, since there
+ // may be multiple occurrences of the same node.
+ Node f = args[0];
+ std::shared_ptr<ProofNode> pfn;
+ std::map<Node, std::shared_ptr<ProofNode>>::iterator it =
+ d_assumpToProof.find(f);
+ if (it != d_assumpToProof.end())
+ {
+ Trace("prop-proof-pp-debug") << "...already computed" << std::endl;
+ pfn = it->second;
+ }
+ else
+ {
+ Assert(d_proofCnfStream != nullptr);
+ // get proof from proof cnf stream
+ pfn = d_proofCnfStream->getProofFor(f);
+ Assert(pfn != nullptr && pfn->getResult() == f);
+ if (Trace.isOn("prop-proof-pp"))
+ {
+ Trace("prop-proof-pp") << "=== Connect CNF proof for: " << f << "\n";
+ Trace("prop-proof-pp") << *pfn.get() << "\n";
+ }
+ d_assumpToProof[f] = pfn;
+ }
+ // connect the proof
+ cdp->addProof(pfn);
+ // do not recursively process the result
+ continueUpdate = false;
+ // moreover block the fact f so that its proof node is not traversed if we run
+ // this post processor again (which can happen in incremental benchmarks)
+ d_proofCnfStream->addBlocked(pfn);
+ return true;
+}
+
+ProofPostproccess::ProofPostproccess(ProofNodeManager* pnm,
+ ProofCnfStream* proofCnfStream)
+ : d_cb(pnm, proofCnfStream), d_pnm(pnm)
+{
+}
+
+ProofPostproccess::~ProofPostproccess() {}
+
+void ProofPostproccess::process(std::shared_ptr<ProofNode> pf)
+{
+ // Initialize the callback, which computes necessary static information about
+ // how to process, including how to process assumptions in pf.
+ d_cb.initializeUpdate();
+ // now, process
+ ProofNodeUpdater updater(d_pnm, d_cb);
+ updater.process(pf);
+}
+
+} // namespace prop
+} // namespace CVC4
diff --git a/src/prop/proof_post_processor.h b/src/prop/proof_post_processor.h
new file mode 100644
index 000000000..ced3e5b92
--- /dev/null
+++ b/src/prop/proof_post_processor.h
@@ -0,0 +1,112 @@
+/********************* */
+/*! \file proof_post_processor.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Haniel Barbosa
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The module for processing proof nodes in the prop engine
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__PROP__PROOF_POST_PROCESSOR_H
+#define CVC4__PROP__PROOF_POST_PROCESSOR_H
+
+#include <map>
+#include <unordered_set>
+
+#include "expr/proof_node_updater.h"
+#include "prop/proof_cnf_stream.h"
+
+namespace CVC4 {
+
+namespace prop {
+
+/**
+ * A callback class used by PropEngine for post-processing proof nodes by
+ * connecting proofs of resolution, whose leaves are clausified preprocessed
+ * assertions and lemmas, with the CNF transformation of these formulas, while
+ * expanding the generators of lemmas.
+ */
+class ProofPostprocessCallback : public ProofNodeUpdaterCallback
+{
+ public:
+ ProofPostprocessCallback(ProofNodeManager* pnm,
+ ProofCnfStream* proofCnfStream);
+ ~ProofPostprocessCallback() {}
+ /**
+ * Initialize, called once for each new ProofNode to process. This initializes
+ * static information to be used by successive calls to update. For this
+ * callback it resets d_assumpToProof.
+ */
+ void initializeUpdate();
+ /** Should proof pn be updated?
+ *
+ * For this callback a proof node is updatable if it's an assumption for which
+ * the proof cnf straem has a proof. However if the proof node is blocked
+ * (which is the case for proof nodes introduced into the proof cnf stream's
+ * proof via expansion of its generators) then traversal is the proof node is
+ * cancelled, i.e., continueUpdate is set to false.
+ */
+ bool shouldUpdate(std::shared_ptr<ProofNode> pn,
+ bool& continueUpdate) override;
+ /** Update the proof rule application.
+ *
+ * Replaces assumptions by their proof in proof cnf stream. Note that in doing
+ * this the proof node is blocked, so that future post-processing does not
+ * traverse it.
+ *
+ * This method uses the cache in d_assumpToProof to avoid recomputing proofs
+ * for the same assumption (in the same scope).
+ */
+ bool update(Node res,
+ PfRule id,
+ const std::vector<Node>& children,
+ const std::vector<Node>& args,
+ CDProof* cdp,
+ bool& continueUpdate) override;
+
+ private:
+ /** The proof node manager */
+ ProofNodeManager* d_pnm;
+ /** The cnf stream proof generator */
+ ProofCnfStream* d_proofCnfStream;
+ //---------------------------------reset at the begining of each update
+ /** Mapping assumptions to their proof from cnf transformation */
+ std::map<Node, std::shared_ptr<ProofNode> > d_assumpToProof;
+ //---------------------------------end reset at the begining of each update
+};
+
+/**
+ * The proof postprocessor module. This postprocesses the refutation proof
+ * produced by the SAT solver. Its main task is to connect the refutation's
+ * assumptions to the CNF transformation proof in ProofCnfStream.
+ */
+class ProofPostproccess
+{
+ public:
+ ProofPostproccess(ProofNodeManager* pnm, ProofCnfStream* proofCnfStream);
+ ~ProofPostproccess();
+ /** post-process
+ *
+ * The post-processing is done via a proof node updater run on pf with this
+ * class's callback d_cb.
+ */
+ void process(std::shared_ptr<ProofNode> pf);
+
+ private:
+ /** The post process callback */
+ ProofPostprocessCallback d_cb;
+ /** The proof node manager */
+ ProofNodeManager* d_pnm;
+};
+
+} // namespace prop
+} // namespace CVC4
+
+#endif
diff --git a/src/prop/prop_engine.cpp b/src/prop/prop_engine.cpp
index 2bf425f2b..4596972e9 100644
--- a/src/prop/prop_engine.cpp
+++ b/src/prop/prop_engine.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Dejan Jovanovic, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -34,7 +34,6 @@
#include "prop/sat_solver.h"
#include "prop/sat_solver_factory.h"
#include "prop/theory_proxy.h"
-#include "smt/command.h"
#include "smt/smt_statistics_registry.h"
#include "theory/theory_engine.h"
#include "theory/theory_registrar.h"
@@ -70,7 +69,8 @@ public:
PropEngine::PropEngine(TheoryEngine* te,
Context* satContext,
UserContext* userContext,
- ResourceManager* rm)
+ ResourceManager* rm,
+ OutputManager& outMgr)
: d_inCheckSat(false),
d_theoryEngine(te),
d_context(satContext),
@@ -79,7 +79,8 @@ PropEngine::PropEngine(TheoryEngine* te,
d_registrar(NULL),
d_cnfStream(NULL),
d_interrupted(false),
- d_resourceManager(rm)
+ d_resourceManager(rm),
+ d_outMgr(outMgr)
{
Debug("prop") << "Constructing the PropEngine" << endl;
@@ -90,8 +91,8 @@ PropEngine::PropEngine(TheoryEngine* te,
d_satSolver = SatSolverFactory::createDPLLMinisat(smtStatisticsRegistry());
d_registrar = new theory::TheoryRegistrar(d_theoryEngine);
- d_cnfStream = new CVC4::prop::TseitinCnfStream(
- d_satSolver, d_registrar, userContext, rm, true);
+ d_cnfStream = new CVC4::prop::CnfStream(
+ d_satSolver, d_registrar, userContext, &d_outMgr, rm, true);
d_theoryProxy = new TheoryProxy(
this, d_theoryEngine, d_decisionEngine.get(), d_context, d_cnfStream);
@@ -99,14 +100,17 @@ PropEngine::PropEngine(TheoryEngine* te,
d_decisionEngine->setSatSolver(d_satSolver);
d_decisionEngine->setCnfStream(d_cnfStream);
- PROOF (
- ProofManager::currentPM()->initCnfProof(d_cnfStream, userContext);
- );
+ if (options::unsatCores())
+ {
+ ProofManager::currentPM()->initCnfProof(d_cnfStream, userContext);
+ }
+}
+void PropEngine::finishInit()
+{
NodeManager* nm = NodeManager::currentNM();
- d_cnfStream->convertAndAssert(nm->mkConst(true), false, false, RULE_GIVEN);
- d_cnfStream->convertAndAssert(
- nm->mkConst(false).notNode(), false, false, RULE_GIVEN);
+ d_cnfStream->convertAndAssert(nm->mkConst(true), false, false);
+ d_cnfStream->convertAndAssert(nm->mkConst(false).notNode(), false, false);
}
PropEngine::~PropEngine() {
@@ -123,18 +127,15 @@ void PropEngine::assertFormula(TNode node) {
Assert(!d_inCheckSat) << "Sat solver in solve()!";
Debug("prop") << "assertFormula(" << node << ")" << endl;
// Assert as non-removable
- d_cnfStream->convertAndAssert(node, false, false, RULE_GIVEN);
+ d_cnfStream->convertAndAssert(node, false, false, true);
}
-void PropEngine::assertLemma(TNode node, bool negated,
- bool removable,
- ProofRule rule,
- TNode from) {
- //Assert(d_inCheckSat, "Sat solver should be in solve()!");
+void PropEngine::assertLemma(TNode node, bool negated, bool removable)
+{
Debug("prop::lemmas") << "assertLemma(" << node << ")" << endl;
// Assert as (possibly) removable
- d_cnfStream->convertAndAssert(node, removable, negated, rule, from);
+ d_cnfStream->convertAndAssert(node, removable, negated);
}
void PropEngine::addAssertionsToDecisionEngine(
@@ -242,7 +243,7 @@ bool PropEngine::isSatLiteral(TNode node) const {
bool PropEngine::hasValue(TNode node, bool& value) const {
Assert(node.getType().isBoolean());
- Assert(d_cnfStream->hasLiteral(node));
+ Assert(d_cnfStream->hasLiteral(node)) << node;
SatLiteral lit = d_cnfStream->getLiteral(node);
diff --git a/src/prop/prop_engine.h b/src/prop/prop_engine.h
index 7f1d5ef65..1fb79231d 100644
--- a/src/prop/prop_engine.h
+++ b/src/prop/prop_engine.h
@@ -5,7 +5,7 @@
** Morgan Deters, Dejan Jovanovic, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -36,6 +36,7 @@ namespace CVC4 {
class ResourceManager;
class DecisionEngine;
+class OutputManager;
class TheoryEngine;
namespace theory {
@@ -62,7 +63,8 @@ class PropEngine
PropEngine(TheoryEngine*,
context::Context* satContext,
context::UserContext* userContext,
- ResourceManager* rm);
+ ResourceManager* rm,
+ OutputManager& outMgr);
/**
* Destructor.
@@ -70,6 +72,13 @@ class PropEngine
CVC4_PUBLIC ~PropEngine();
/**
+ * Finish initialize. Call this after construction just before we are
+ * ready to use this class. Should be called after TheoryEngine::finishInit.
+ * This method converts and asserts true and false into the CNF stream.
+ */
+ void finishInit();
+
+ /**
* This is called by SmtEngine, at shutdown time, just before
* destruction. It is important because there are destruction
* ordering issues between some parts of the system (notably between
@@ -96,11 +105,7 @@ class PropEngine
* @param removable whether this lemma can be quietly removed based
* on an activity heuristic (or not)
*/
- void assertLemma(TNode node,
- bool negated,
- bool removable,
- ProofRule rule,
- TNode from = TNode::null());
+ void assertLemma(TNode node, bool negated, bool removable);
/**
* Pass a list of assertions from an AssertionPipeline to the decision engine.
@@ -252,6 +257,8 @@ class PropEngine
/** Pointer to resource manager for associated SmtEngine */
ResourceManager* d_resourceManager;
+ /** Reference to the output manager of the smt engine */
+ OutputManager& d_outMgr;
};
} // namespace prop
diff --git a/src/prop/prop_proof_manager.cpp b/src/prop/prop_proof_manager.cpp
new file mode 100644
index 000000000..aa58ffa2c
--- /dev/null
+++ b/src/prop/prop_proof_manager.cpp
@@ -0,0 +1,109 @@
+/********************* */
+/*! \file prop_proof_manager
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Haniel Barbosa
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of the proof manager for the PropPfManager
+ **/
+
+#include "prop/prop_proof_manager.h"
+
+#include "expr/proof_node_algorithm.h"
+
+namespace CVC4 {
+namespace prop {
+
+PropPfManager::PropPfManager(context::UserContext* userContext,
+ ProofNodeManager* pnm,
+ SatProofManager* satPM,
+ ProofCnfStream* cnfProof)
+ : d_pnm(pnm),
+ d_pfpp(new ProofPostproccess(pnm, cnfProof)),
+ d_satPM(satPM),
+ d_assertions(userContext)
+{
+ // add trivial assumption. This is so that we can check the that the prop
+ // engine's proof is closed, as the SAT solver's refutation proof may use True
+ // as an assumption even when True is not given as an assumption. An example
+ // is when a propagated literal has an empty explanation (i.e., it is a valid
+ // literal), which leads to adding True as its explanation, since for creating
+ // a learned clause we need at least two literals.
+ d_assertions.push_back(NodeManager::currentNM()->mkConst(true));
+}
+
+void PropPfManager::registerAssertion(Node assertion)
+{
+ d_assertions.push_back(assertion);
+}
+
+void PropPfManager::checkProof(context::CDList<Node>* assertions)
+{
+ Trace("sat-proof") << "PropPfManager::checkProof: Checking if resolution "
+ "proof of false is closed\n";
+ std::shared_ptr<ProofNode> conflictProof = d_satPM->getProof();
+ Assert(conflictProof);
+ // connect it with CNF proof
+ d_pfpp->process(conflictProof);
+ // add given assertions d_assertions
+ for (const Node& assertion : *assertions)
+ {
+ d_assertions.push_back(assertion);
+ }
+ std::vector<Node> avec{d_assertions.begin(), d_assertions.end()};
+ pfnEnsureClosedWrt(
+ conflictProof.get(), avec, "sat-proof", "PropPfManager::checkProof");
+}
+
+std::shared_ptr<ProofNode> PropPfManager::getProof()
+{
+ // retrieve the SAT solver's refutation proof
+ Trace("sat-proof")
+ << "PropPfManager::getProof: Getting resolution proof of false\n";
+ std::shared_ptr<ProofNode> conflictProof = d_satPM->getProof();
+ Assert(conflictProof);
+ if (Trace.isOn("sat-proof"))
+ {
+ std::vector<Node> fassumps;
+ expr::getFreeAssumptions(conflictProof.get(), fassumps);
+ Trace("sat-proof")
+ << "PropPfManager::getProof: initial free assumptions are:\n";
+ for (const Node& a : fassumps)
+ {
+ Trace("sat-proof") << "- " << a << "\n";
+ }
+ Trace("sat-proof-debug")
+ << "PropPfManager::getProof: proof is " << *conflictProof.get() << "\n";
+ Trace("sat-proof")
+ << "PropPfManager::getProof: Connecting with CNF proof\n";
+ }
+ // connect it with CNF proof
+ d_pfpp->process(conflictProof);
+ if (Trace.isOn("sat-proof"))
+ {
+ std::vector<Node> fassumps;
+ expr::getFreeAssumptions(conflictProof.get(), fassumps);
+ Trace("sat-proof")
+ << "PropPfManager::getProof: new free assumptions are:\n";
+ for (const Node& a : fassumps)
+ {
+ Trace("sat-proof") << "- " << a << "\n";
+ }
+ Trace("sat-proof") << "PropPfManager::getProof: assertions are:\n";
+ for (const Node& a : d_assertions)
+ {
+ Trace("sat-proof") << "- " << a << "\n";
+ }
+ Trace("sat-proof-debug")
+ << "PropPfManager::getProof: proof is " << *conflictProof.get() << "\n";
+ }
+ return conflictProof;
+}
+
+} // namespace prop
+} // namespace CVC4
diff --git a/src/prop/prop_proof_manager.h b/src/prop/prop_proof_manager.h
new file mode 100644
index 000000000..f3deee5bc
--- /dev/null
+++ b/src/prop/prop_proof_manager.h
@@ -0,0 +1,95 @@
+/********************* */
+/*! \file prop_proof_manager.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Haniel Barbosa
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The proof manager of PropEngine
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__PROP_PROOF_MANAGER_H
+#define CVC4__PROP_PROOF_MANAGER_H
+
+#include "context/cdlist.h"
+#include "expr/proof.h"
+#include "expr/proof_node_manager.h"
+#include "prop/proof_post_processor.h"
+#include "prop/sat_proof_manager.h"
+
+namespace CVC4 {
+
+namespace prop {
+
+/**
+ * This class is responsible for managing the proof output of PropEngine, both
+ * building and checking it.
+ *
+ * The expected proof to be built is a refutation proof with preprocessed
+ * assertions as free assumptions.
+ */
+class PropPfManager
+{
+ public:
+ PropPfManager(context::UserContext* userContext,
+ ProofNodeManager* pnm,
+ SatProofManager* satPM,
+ ProofCnfStream* cnfProof);
+
+ /** Saves assertion for later checking whether refutation proof is closed.
+ *
+ * The assertions registered via this interface are preprocessed assertions
+ * from SMT engine as they are asserted to the prop engine.
+ */
+ void registerAssertion(Node assertion);
+ /**
+ * Generates the prop engine proof: a proof of false resulting from the
+ * connection of the refutation proof in d_satPM with the justification for
+ * its assumptions, which are retrieved from the CNF conversion proof, if any.
+ *
+ * The connection is done by running the proof post processor d_pfpp over the
+ * proof of false provided by d_satPM. See ProofPostProcessor for more
+ * details.
+ */
+ std::shared_ptr<ProofNode> getProof();
+
+ /**
+ * Checks that the prop engine proof is closed w.r.t. the given assertions and
+ * previously registered assertions in d_assertions.
+ *
+ * A common use of other assertions on top of the ones already registered on
+ * d_assertions is checking closedness w.r.t. preprocessed *and* input
+ * assertions. This is necessary if a prop engine's proof is modified
+ * externally (which can happen, for example, when connecting the prop
+ * engine's proof with the preprocessing proof) and these changes survive for
+ * a next check-sat call.
+ */
+ void checkProof(context::CDList<Node>* assertions);
+
+ private:
+ /** A node manager */
+ ProofNodeManager* d_pnm;
+ /** The proof post-processor */
+ std::unique_ptr<prop::ProofPostproccess> d_pfpp;
+ /**
+ * The SAT solver's proof manager, which will provide a refutation
+ * proofresolution proof when requested */
+ SatProofManager* d_satPM;
+ /** Assertions corresponding to the leaves of the prop engine's proof.
+ *
+ * These are kept in a context-dependent manner since the prop engine's proof
+ * is also kept in a context-dependent manner.
+ */
+ context::CDList<Node> d_assertions;
+}; /* class PropPfManager */
+
+} // namespace prop
+} // namespace CVC4
+
+#endif /* CVC4__PROP__PROOF_MANAGER_H */
diff --git a/src/prop/registrar.h b/src/prop/registrar.h
index 51f08074e..9cbfef4bc 100644
--- a/src/prop/registrar.h
+++ b/src/prop/registrar.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Liana Hadarean, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/prop/sat_proof_manager.cpp b/src/prop/sat_proof_manager.cpp
new file mode 100644
index 000000000..36913fda8
--- /dev/null
+++ b/src/prop/sat_proof_manager.cpp
@@ -0,0 +1,722 @@
+/********************* */
+/*! \file sat_proof_manager.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Haniel Barbosa
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of the proof manager for Minisat
+ **/
+
+#include "prop/sat_proof_manager.h"
+
+#include "expr/proof_node_algorithm.h"
+#include "options/smt_options.h"
+#include "prop/cnf_stream.h"
+#include "prop/minisat/minisat.h"
+#include "theory/theory_proof_step_buffer.h"
+
+namespace CVC4 {
+namespace prop {
+
+SatProofManager::SatProofManager(Minisat::Solver* solver,
+ CnfStream* cnfStream,
+ context::UserContext* userContext,
+ ProofNodeManager* pnm)
+ : d_solver(solver),
+ d_cnfStream(cnfStream),
+ d_pnm(pnm),
+ d_resChains(pnm, true, userContext),
+ d_resChainPg(userContext, pnm),
+ d_assumptions(userContext),
+ d_conflictLit(undefSatVariable)
+{
+ d_false = NodeManager::currentNM()->mkConst(false);
+}
+
+void SatProofManager::printClause(const Minisat::Clause& clause)
+{
+ for (unsigned i = 0, size = clause.size(); i < size; ++i)
+ {
+ SatLiteral satLit = MinisatSatSolver::toSatLiteral(clause[i]);
+ Trace("sat-proof") << satLit << " ";
+ }
+}
+
+Node SatProofManager::getClauseNode(SatLiteral satLit)
+{
+ Assert(d_cnfStream->getNodeCache().find(satLit)
+ != d_cnfStream->getNodeCache().end())
+ << "SatProofManager::getClauseNode: literal " << satLit
+ << " undefined.\n";
+ return d_cnfStream->getNodeCache()[satLit];
+}
+
+Node SatProofManager::getClauseNode(const Minisat::Clause& clause)
+{
+ std::vector<Node> clauseNodes;
+ for (unsigned i = 0, size = clause.size(); i < size; ++i)
+ {
+ SatLiteral satLit = MinisatSatSolver::toSatLiteral(clause[i]);
+ Assert(d_cnfStream->getNodeCache().find(satLit)
+ != d_cnfStream->getNodeCache().end())
+ << "SatProofManager::getClauseNode: literal " << satLit
+ << " undefined\n";
+ clauseNodes.push_back(d_cnfStream->getNodeCache()[satLit]);
+ }
+ // order children by node id
+ std::sort(clauseNodes.begin(), clauseNodes.end());
+ return NodeManager::currentNM()->mkNode(kind::OR, clauseNodes);
+}
+
+void SatProofManager::startResChain(const Minisat::Clause& start)
+{
+ if (Trace.isOn("sat-proof"))
+ {
+ Trace("sat-proof") << "SatProofManager::startResChain: ";
+ printClause(start);
+ Trace("sat-proof") << "\n";
+ }
+ d_resLinks.push_back(
+ std::pair<Node, Node>(getClauseNode(start), Node::null()));
+}
+
+void SatProofManager::addResolutionStep(Minisat::Lit lit, bool redundant)
+{
+ SatLiteral satLit = MinisatSatSolver::toSatLiteral(lit);
+ if (!redundant)
+ {
+ Trace("sat-proof") << "SatProofManager::addResolutionStep: [" << satLit
+ << "] " << ~satLit << "\n";
+ d_resLinks.push_back(
+ std::pair<Node, Node>(d_cnfStream->getNodeCache()[~satLit],
+ d_cnfStream->getNodeCache()[satLit]));
+ }
+ else
+ {
+ Trace("sat-proof") << "SatProofManager::addResolutionStep: redundant lit "
+ << satLit << " stored\n";
+ d_redundantLits.push_back(satLit);
+ }
+}
+
+void SatProofManager::addResolutionStep(const Minisat::Clause& clause,
+ Minisat::Lit lit)
+{
+ // the given clause is supposed to be the second in a resolution, with the
+ // given literal as the pivot occurring positive in the first and negatively
+ // in the second clause. Thus, we store its negation
+ SatLiteral satLit = MinisatSatSolver::toSatLiteral(~lit);
+ Node clauseNode = getClauseNode(clause);
+ d_resLinks.push_back(
+ std::pair<Node, Node>(clauseNode, d_cnfStream->getNodeCache()[satLit]));
+ if (Trace.isOn("sat-proof"))
+ {
+ Trace("sat-proof") << "SatProofManager::addResolutionStep: [" << satLit
+ << "] ";
+ printClause(clause);
+ Trace("sat-proof") << "\nSatProofManager::addResolutionStep:\t"
+ << clauseNode << "\n";
+ }
+}
+
+void SatProofManager::endResChain(Minisat::Lit lit)
+{
+ SatLiteral satLit = MinisatSatSolver::toSatLiteral(lit);
+ Trace("sat-proof") << "SatProofManager::endResChain: chain_res for "
+ << satLit;
+ endResChain(getClauseNode(satLit), {satLit});
+}
+
+void SatProofManager::endResChain(const Minisat::Clause& clause)
+{
+ if (Trace.isOn("sat-proof"))
+ {
+ Trace("sat-proof") << "SatProofManager::endResChain: chain_res for ";
+ printClause(clause);
+ }
+ std::set<SatLiteral> clauseLits;
+ for (unsigned i = 0, size = clause.size(); i < size; ++i)
+ {
+ clauseLits.insert(MinisatSatSolver::toSatLiteral(clause[i]));
+ }
+ endResChain(getClauseNode(clause), clauseLits);
+}
+
+void SatProofManager::endResChain(Node conclusion,
+ const std::set<SatLiteral>& conclusionLits)
+{
+ Trace("sat-proof") << ", " << conclusion << "\n";
+ // first process redundant literals
+ std::set<SatLiteral> visited;
+ unsigned pos = d_resLinks.size();
+ for (SatLiteral satLit : d_redundantLits)
+ {
+ processRedundantLit(satLit, conclusionLits, visited, pos);
+ }
+ d_redundantLits.clear();
+ // build resolution chain
+ std::vector<Node> children, args;
+ for (unsigned i = 0, size = d_resLinks.size(); i < size; ++i)
+ {
+ children.push_back(d_resLinks[i].first);
+ Trace("sat-proof") << "SatProofManager::endResChain: ";
+ if (i > 0)
+ {
+ Trace("sat-proof")
+ << "[" << d_cnfStream->getTranslationCache()[d_resLinks[i].second]
+ << "] ";
+ }
+ // special case for clause (or l1 ... ln) being a single literal
+ // corresponding itself to a clause, which is indicated by the pivot being
+ // of the form (not (or l1 ... ln))
+ if (d_resLinks[i].first.getKind() == kind::OR
+ && !(d_resLinks[i].second.getKind() == kind::NOT
+ && d_resLinks[i].second[0].getKind() == kind::OR
+ && d_resLinks[i].second[0] == d_resLinks[i].first))
+ {
+ for (unsigned j = 0, sizeJ = d_resLinks[i].first.getNumChildren();
+ j < sizeJ;
+ ++j)
+ {
+ Trace("sat-proof")
+ << d_cnfStream->getTranslationCache()[d_resLinks[i].first[j]];
+ if (j < sizeJ - 1)
+ {
+ Trace("sat-proof") << ", ";
+ }
+ }
+ }
+ else
+ {
+ Assert(d_cnfStream->getTranslationCache().find(d_resLinks[i].first)
+ != d_cnfStream->getTranslationCache().end())
+ << "clause node " << d_resLinks[i].first
+ << " treated as unit has no literal. Pivot is "
+ << d_resLinks[i].second << "\n";
+ Trace("sat-proof")
+ << d_cnfStream->getTranslationCache()[d_resLinks[i].first];
+ }
+ Trace("sat-proof") << " : ";
+ if (i > 0)
+ {
+ args.push_back(d_resLinks[i].second);
+ Trace("sat-proof") << "[" << d_resLinks[i].second << "] ";
+ }
+ Trace("sat-proof") << d_resLinks[i].first << "\n";
+ }
+ // clearing
+ d_resLinks.clear();
+ // whether no-op
+ if (children.size() == 1)
+ {
+ Trace("sat-proof") << "SatProofManager::endResChain: no-op. The conclusion "
+ << conclusion << " is set-equal to premise "
+ << children[0] << "\n";
+ return;
+ }
+ if (Trace.isOn("sat-proof") && d_resChains.hasGenerator(conclusion))
+ {
+ Trace("sat-proof") << "SatProofManager::endResChain: replacing proof of "
+ << conclusion << "\n";
+ }
+ // since the conclusion can be both reordered and without duplicates and the
+ // SAT solver does not record this information, we must recompute it here so
+ // the proper CHAIN_RESOLUTION step can be created
+ // compute chain resolution conclusion
+ Node chainConclusion = d_pnm->getChecker()->checkDebug(
+ PfRule::CHAIN_RESOLUTION, children, args, Node::null(), "");
+ Trace("sat-proof")
+ << "SatProofManager::endResChain: creating step for computed conclusion "
+ << chainConclusion << "\n";
+ // buffer steps
+ theory::TheoryProofStepBuffer psb;
+ psb.addStep(PfRule::CHAIN_RESOLUTION, children, args, chainConclusion);
+ if (chainConclusion != conclusion)
+ {
+ // if this happens that chainConclusion needs to be factored and/or
+ // reordered, which in either case can be done only if it's not a unit
+ // clause.
+ CVC4_UNUSED Node reducedChainConclusion =
+ psb.factorReorderElimDoubleNeg(chainConclusion);
+ Assert(reducedChainConclusion == conclusion)
+ << "original conclusion " << conclusion
+ << "\nis different from computed conclusion " << chainConclusion
+ << "\nafter factorReorderElimDoubleNeg " << reducedChainConclusion;
+ }
+ // buffer the steps in the resolution chain proof generator
+ const std::vector<std::pair<Node, ProofStep>>& steps = psb.getSteps();
+ for (const std::pair<Node, ProofStep>& step : steps)
+ {
+ Trace("sat-proof") << "SatProofManager::endResChain: adding for "
+ << step.first << " step " << step.second << "\n";
+ d_resChainPg.addStep(step.first, step.second);
+ // the premises of this resolution may not have been justified yet, so we do
+ // not pass assumptions to check closedness
+ d_resChains.addLazyStep(step.first, &d_resChainPg);
+ }
+}
+
+void SatProofManager::processRedundantLit(
+ SatLiteral lit,
+ const std::set<SatLiteral>& conclusionLits,
+ std::set<SatLiteral>& visited,
+ unsigned pos)
+{
+ Trace("sat-proof") << push
+ << "SatProofManager::processRedundantLit: Lit: " << lit
+ << "\n";
+ if (visited.count(lit))
+ {
+ Trace("sat-proof") << "already visited\n" << pop;
+ return;
+ }
+ Minisat::Solver::TCRef reasonRef =
+ d_solver->reason(Minisat::var(MinisatSatSolver::toMinisatLit(lit)));
+ if (reasonRef == Minisat::Solver::TCRef_Undef)
+ {
+ Trace("sat-proof") << "unit, add link to lit " << lit << " at pos: " << pos
+ << "\n"
+ << pop;
+ visited.insert(lit);
+ d_resLinks.insert(d_resLinks.begin() + pos,
+ std::pair<Node, Node>(d_cnfStream->getNodeCache()[~lit],
+ d_cnfStream->getNodeCache()[lit]));
+ return;
+ }
+ Assert(reasonRef >= 0 && reasonRef < d_solver->ca.size())
+ << "reasonRef " << reasonRef << " and d_satSolver->ca.size() "
+ << d_solver->ca.size() << "\n";
+ const Minisat::Clause& reason = d_solver->ca[reasonRef];
+ if (Trace.isOn("sat-proof"))
+ {
+ Trace("sat-proof") << "reason: ";
+ printClause(reason);
+ Trace("sat-proof") << "\n";
+ }
+ // check if redundant literals in the reason. The first literal is the one we
+ // will be eliminating, so we check the others
+ for (unsigned i = 1, size = reason.size(); i < size; ++i)
+ {
+ SatLiteral satLit = MinisatSatSolver::toSatLiteral(reason[i]);
+ // if literal does not occur in the conclusion we process it as well
+ if (!conclusionLits.count(satLit))
+ {
+ processRedundantLit(satLit, conclusionLits, visited, pos);
+ }
+ }
+ Assert(!visited.count(lit));
+ visited.insert(lit);
+ Trace("sat-proof") << "clause, add link to lit " << lit << " at pos: " << pos
+ << "\n"
+ << pop;
+ // add the step before steps for children. Note that the step is with the
+ // reason, not only with ~lit, since the learned clause is built under the
+ // assumption that the redundant literal is removed via the resolution with
+ // the explanation of its negation
+ Node clauseNode = getClauseNode(reason);
+ d_resLinks.insert(
+ d_resLinks.begin() + pos,
+ std::pair<Node, Node>(clauseNode, d_cnfStream->getNodeCache()[lit]));
+}
+
+void SatProofManager::explainLit(
+ SatLiteral lit, std::unordered_set<TNode, TNodeHashFunction>& premises)
+{
+ Node litNode = getClauseNode(lit);
+ Trace("sat-proof") << push << "SatProofManager::explainLit: Lit: " << lit
+ << " [" << litNode << "]\n";
+ Minisat::Solver::TCRef reasonRef =
+ d_solver->reason(Minisat::var(MinisatSatSolver::toMinisatLit(lit)));
+ if (reasonRef == Minisat::Solver::TCRef_Undef)
+ {
+ Trace("sat-proof") << "SatProofManager::explainLit: no SAT reason\n" << pop;
+ return;
+ }
+ Assert(reasonRef >= 0 && reasonRef < d_solver->ca.size())
+ << "reasonRef " << reasonRef << " and d_satSolver->ca.size() "
+ << d_solver->ca.size() << "\n";
+ const Minisat::Clause& reason = d_solver->ca[reasonRef];
+ unsigned size = reason.size();
+ if (Trace.isOn("sat-proof"))
+ {
+ Trace("sat-proof") << "SatProofManager::explainLit: with clause: ";
+ printClause(reason);
+ Trace("sat-proof") << "\n";
+ }
+ // pedantically check that the negation of the literal to explain *does not*
+ // occur in the reason, otherwise we will loop forever
+ for (unsigned i = 0; i < size; ++i)
+ {
+ AlwaysAssert(~MinisatSatSolver::toSatLiteral(reason[i]) != lit)
+ << "cyclic justification\n";
+ }
+ // add the reason clause first
+ std::vector<Node> children{getClauseNode(reason)}, args;
+ // save in the premises
+ premises.insert(children.back());
+ Trace("sat-proof") << push;
+ for (unsigned i = 0; i < size; ++i)
+ {
+ SatLiteral curr_lit = MinisatSatSolver::toSatLiteral(reason[i]);
+ // ignore the lit we are trying to explain...
+ if (curr_lit == lit)
+ {
+ continue;
+ }
+ std::unordered_set<TNode, TNodeHashFunction> childPremises;
+ explainLit(~curr_lit, childPremises);
+ // save to resolution chain premises / arguments
+ Assert(d_cnfStream->getNodeCache().find(curr_lit)
+ != d_cnfStream->getNodeCache().end());
+ children.push_back(d_cnfStream->getNodeCache()[~curr_lit]);
+ args.push_back(d_cnfStream->getNodeCache()[curr_lit]);
+ // add child premises and the child itself
+ premises.insert(childPremises.begin(), childPremises.end());
+ premises.insert(d_cnfStream->getNodeCache()[~curr_lit]);
+ }
+ if (Trace.isOn("sat-proof"))
+ {
+ Trace("sat-proof") << pop << "SatProofManager::explainLit: chain_res for "
+ << lit << ", " << litNode << " with clauses:\n";
+ for (unsigned i = 0, csize = children.size(); i < csize; ++i)
+ {
+ Trace("sat-proof") << "SatProofManager::explainLit: " << children[i];
+ if (i > 0)
+ {
+ Trace("sat-proof") << " [" << args[i - 1] << "]";
+ }
+ Trace("sat-proof") << "\n";
+ }
+ }
+ // if justification of children contains the expected conclusion, avoid the
+ // cyclic proof by aborting.
+ if (premises.count(litNode))
+ {
+ Trace("sat-proof") << "SatProofManager::explainLit: CYCLIC PROOF of " << lit
+ << " [" << litNode << "], ABORT\n"
+ << pop;
+ return;
+ }
+ Trace("sat-proof") << pop;
+ // create step
+ ProofStep ps(PfRule::CHAIN_RESOLUTION, children, args);
+ d_resChainPg.addStep(litNode, ps);
+ // the premises in the limit of the justification may correspond to other
+ // links in the chain which have, themselves, literals yet to be justified. So
+ // we are not ready yet to check closedness w.r.t. CNF transformation of the
+ // preprocessed assertions
+ d_resChains.addLazyStep(litNode, &d_resChainPg);
+}
+
+void SatProofManager::finalizeProof(Node inConflictNode,
+ const std::vector<SatLiteral>& inConflict)
+{
+ Trace("sat-proof")
+ << "SatProofManager::finalizeProof: conflicting clause node: "
+ << inConflictNode << "\n";
+ // nothing to do
+ if (inConflictNode == d_false)
+ {
+ return;
+ }
+ if (Trace.isOn("sat-proof-debug2"))
+ {
+ Trace("sat-proof-debug2")
+ << push << "SatProofManager::finalizeProof: saved proofs in chain:\n";
+ std::map<Node, std::shared_ptr<ProofNode>> links = d_resChains.getLinks();
+ std::unordered_set<Node, NodeHashFunction> skip;
+ for (const std::pair<const Node, std::shared_ptr<ProofNode>>& link : links)
+ {
+ if (skip.count(link.first))
+ {
+ continue;
+ }
+ auto it = d_cnfStream->getTranslationCache().find(link.first);
+ if (it != d_cnfStream->getTranslationCache().end())
+ {
+ Trace("sat-proof-debug2")
+ << "SatProofManager::finalizeProof: " << it->second;
+ }
+ // a refl step added due to double elim negation, ignore
+ else if (link.second->getRule() == PfRule::REFL)
+ {
+ continue;
+ }
+ // a clause
+ else
+ {
+ Trace("sat-proof-debug2") << "SatProofManager::finalizeProof:";
+ Assert(link.first.getKind() == kind::OR) << link.first;
+ for (const Node& n : link.first)
+ {
+ it = d_cnfStream->getTranslationCache().find(n);
+ Assert(it != d_cnfStream->getTranslationCache().end());
+ Trace("sat-proof-debug2") << it->second << " ";
+ }
+ }
+ Trace("sat-proof-debug2") << "\n";
+ Trace("sat-proof-debug2")
+ << "SatProofManager::finalizeProof: " << link.first << "\n";
+ // get resolution
+ Node cur = link.first;
+ std::shared_ptr<ProofNode> pfn = link.second;
+ while (pfn->getRule() != PfRule::CHAIN_RESOLUTION)
+ {
+ Assert(pfn->getChildren().size() == 1
+ && pfn->getChildren()[0]->getRule() == PfRule::ASSUME)
+ << *link.second.get() << "\n"
+ << *pfn.get();
+ cur = pfn->getChildren()[0]->getResult();
+ // retrieve justification of assumption in the links
+ Assert(links.find(cur) != links.end());
+ pfn = links[cur];
+ // ignore it in the rest of the outside loop
+ skip.insert(cur);
+ }
+ std::vector<Node> fassumps;
+ expr::getFreeAssumptions(pfn.get(), fassumps);
+ Trace("sat-proof-debug2") << push;
+ for (const Node& fa : fassumps)
+ {
+ Trace("sat-proof-debug2") << "SatProofManager::finalizeProof: - ";
+ it = d_cnfStream->getTranslationCache().find(fa);
+ if (it != d_cnfStream->getTranslationCache().end())
+ {
+ Trace("sat-proof-debug2") << it->second << "\n";
+ continue;
+ }
+ // then it's a clause
+ Assert(fa.getKind() == kind::OR);
+ for (const Node& n : fa)
+ {
+ it = d_cnfStream->getTranslationCache().find(n);
+ Assert(it != d_cnfStream->getTranslationCache().end());
+ Trace("sat-proof-debug2") << it->second << " ";
+ }
+ Trace("sat-proof-debug2") << "\n";
+ }
+ Trace("sat-proof-debug2") << pop;
+ Trace("sat-proof-debug2")
+ << "SatProofManager::finalizeProof: " << *pfn.get() << "\n=======\n";
+ ;
+ }
+ Trace("sat-proof-debug2") << pop;
+ }
+ // We will resolve away of the literals l_1...l_n in inConflict. At this point
+ // each ~l_i must be either explainable, the result of a previously saved
+ // resolution chain, or an input. In account of it possibly being the first,
+ // we call explainLit on each ~l_i while accumulating the children and
+ // arguments for the resolution step to conclude false.
+ std::vector<Node> children{inConflictNode}, args;
+ std::unordered_set<TNode, TNodeHashFunction> premises;
+ for (unsigned i = 0, size = inConflict.size(); i < size; ++i)
+ {
+ Assert(d_cnfStream->getNodeCache().find(inConflict[i])
+ != d_cnfStream->getNodeCache().end());
+ std::unordered_set<TNode, TNodeHashFunction> childPremises;
+ explainLit(~inConflict[i], childPremises);
+ Node negatedLitNode = d_cnfStream->getNodeCache()[~inConflict[i]];
+ // save to resolution chain premises / arguments
+ children.push_back(negatedLitNode);
+ args.push_back(d_cnfStream->getNodeCache()[inConflict[i]]);
+ // add child premises and the child itself
+ premises.insert(childPremises.begin(), childPremises.end());
+ premises.insert(negatedLitNode);
+ Trace("sat-proof") << "===========\n";
+ }
+ if (Trace.isOn("sat-proof"))
+ {
+ Trace("sat-proof") << "SatProofManager::finalizeProof: chain_res for false "
+ "with clauses:\n";
+ for (unsigned i = 0, size = children.size(); i < size; ++i)
+ {
+ Trace("sat-proof") << "SatProofManager::finalizeProof: " << children[i];
+ if (i > 0)
+ {
+ Trace("sat-proof") << " [" << args[i - 1] << "]";
+ }
+ Trace("sat-proof") << "\n";
+ }
+ }
+ // create step
+ ProofStep ps(PfRule::CHAIN_RESOLUTION, children, args);
+ d_resChainPg.addStep(d_false, ps);
+ // not yet ready to check closedness because maybe only now we will justify
+ // literals used in resolutions
+ d_resChains.addLazyStep(d_false, &d_resChainPg);
+ // Fix point justification of literals in leaves of the proof of false
+ bool expanded;
+ do
+ {
+ expanded = false;
+ Trace("sat-proof") << "expand assumptions to prove false\n";
+ std::shared_ptr<ProofNode> pfn = d_resChains.getProofFor(d_false);
+ Assert(pfn);
+ Trace("sat-proof-debug") << "sat proof of flase: " << *pfn.get() << "\n";
+ std::vector<Node> fassumps;
+ expr::getFreeAssumptions(pfn.get(), fassumps);
+ if (Trace.isOn("sat-proof"))
+ {
+ for (const Node& fa : fassumps)
+ {
+ Trace("sat-proof") << "- ";
+ auto it = d_cnfStream->getTranslationCache().find(fa);
+ if (it != d_cnfStream->getTranslationCache().end())
+ {
+ Trace("sat-proof") << it->second << "\n";
+ Trace("sat-proof") << "- " << fa << "\n";
+ continue;
+ }
+ // then it's a clause
+ Assert(fa.getKind() == kind::OR);
+ for (const Node& n : fa)
+ {
+ it = d_cnfStream->getTranslationCache().find(n);
+ Assert(it != d_cnfStream->getTranslationCache().end());
+ Trace("sat-proof") << it->second << " ";
+ }
+ Trace("sat-proof") << "\n";
+ Trace("sat-proof") << "- " << fa << "\n";
+ }
+ }
+
+ // for each assumption, see if it has a reason
+ for (const Node& fa : fassumps)
+ {
+ // ignore already processed assumptions
+ if (premises.count(fa))
+ {
+ Trace("sat-proof") << "already processed assumption " << fa << "\n";
+ continue;
+ }
+ // ignore input assumptions. This is necessary to avoid rare collisions
+ // between input clauses and literals that are equivalent at the node
+ // level. In trying to justify the literal below if, it was previously
+ // propagated (say, in a previous check-sat call that survived the
+ // user-context changes) but no longer holds, then we may introduce a
+ // bogus proof for it, rather than keeping it as an input.
+ if (d_assumptions.contains(fa))
+ {
+ Trace("sat-proof") << "input assumption " << fa << "\n";
+ continue;
+ }
+ // ignore non-literals
+ auto it = d_cnfStream->getTranslationCache().find(fa);
+ if (it == d_cnfStream->getTranslationCache().end())
+ {
+ Trace("sat-proof") << "no lit assumption " << fa << "\n";
+ premises.insert(fa);
+ continue;
+ }
+ Trace("sat-proof") << "lit assumption (" << it->second << "), " << fa
+ << "\n";
+ // mark another iteration for the loop, as some resolution link may be
+ // connected because of the new justifications
+ expanded = true;
+ std::unordered_set<TNode, TNodeHashFunction> childPremises;
+ explainLit(it->second, childPremises);
+ // add the premises used in the justification. We know they will have
+ // been as expanded as possible
+ premises.insert(childPremises.begin(), childPremises.end());
+ // add free assumption itself
+ premises.insert(fa);
+ }
+ } while (expanded);
+ // now we should be able to close it
+ if (options::proofNewEagerChecking())
+ {
+ std::vector<Node> assumptionsVec;
+ for (const Node& a : d_assumptions)
+ {
+ assumptionsVec.push_back(a);
+ }
+ d_resChains.addLazyStep(d_false, &d_resChainPg, assumptionsVec);
+ }
+}
+
+void SatProofManager::storeUnitConflict(Minisat::Lit inConflict)
+{
+ Assert(d_conflictLit == undefSatVariable);
+ d_conflictLit = MinisatSatSolver::toSatLiteral(inConflict);
+}
+
+void SatProofManager::finalizeProof()
+{
+ Assert(d_conflictLit != undefSatVariable);
+ Trace("sat-proof")
+ << "SatProofManager::finalizeProof: conflicting (lazy) satLit: "
+ << d_conflictLit << "\n";
+ finalizeProof(getClauseNode(d_conflictLit), {d_conflictLit});
+}
+
+void SatProofManager::finalizeProof(Minisat::Lit inConflict, bool adding)
+{
+ SatLiteral satLit = MinisatSatSolver::toSatLiteral(inConflict);
+ Trace("sat-proof") << "SatProofManager::finalizeProof: conflicting satLit: "
+ << satLit << "\n";
+ Node clauseNode = getClauseNode(satLit);
+ if (adding)
+ {
+ registerSatAssumptions({clauseNode});
+ }
+ finalizeProof(clauseNode, {satLit});
+}
+
+void SatProofManager::finalizeProof(const Minisat::Clause& inConflict,
+ bool adding)
+{
+ if (Trace.isOn("sat-proof"))
+ {
+ Trace("sat-proof")
+ << "SatProofManager::finalizeProof: conflicting clause: ";
+ printClause(inConflict);
+ Trace("sat-proof") << "\n";
+ }
+ std::vector<SatLiteral> clause;
+ for (unsigned i = 0, size = inConflict.size(); i < size; ++i)
+ {
+ clause.push_back(MinisatSatSolver::toSatLiteral(inConflict[i]));
+ }
+ Node clauseNode = getClauseNode(inConflict);
+ if (adding)
+ {
+ registerSatAssumptions({clauseNode});
+ }
+ finalizeProof(clauseNode, clause);
+}
+
+std::shared_ptr<ProofNode> SatProofManager::getProof()
+{
+ std::shared_ptr<ProofNode> pfn = d_resChains.getProofFor(d_false);
+ if (!pfn)
+ {
+ pfn = d_pnm->mkAssume(d_false);
+ }
+ return pfn;
+}
+
+void SatProofManager::registerSatLitAssumption(Minisat::Lit lit)
+{
+ Trace("sat-proof") << "SatProofManager::registerSatLitAssumption: - "
+ << getClauseNode(MinisatSatSolver::toSatLiteral(lit))
+ << "\n";
+ d_assumptions.insert(getClauseNode(MinisatSatSolver::toSatLiteral(lit)));
+}
+
+void SatProofManager::registerSatAssumptions(const std::vector<Node>& assumps)
+{
+ for (const Node& a : assumps)
+ {
+ Trace("sat-proof") << "SatProofManager::registerSatAssumptions: - " << a
+ << "\n";
+ d_assumptions.insert(a);
+ }
+}
+
+} // namespace prop
+} // namespace CVC4
diff --git a/src/prop/sat_proof_manager.h b/src/prop/sat_proof_manager.h
new file mode 100644
index 000000000..da67f0c1e
--- /dev/null
+++ b/src/prop/sat_proof_manager.h
@@ -0,0 +1,587 @@
+/********************* */
+/*! \file sat_proof_manager.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Haniel Barbosa
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The proof manager for Minisat
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__SAT_PROOF_MANAGER_H
+#define CVC4__SAT_PROOF_MANAGER_H
+
+#include "context/cdhashset.h"
+#include "expr/buffered_proof_generator.h"
+#include "expr/expr.h"
+#include "expr/lazy_proof_chain.h"
+#include "expr/node.h"
+#include "expr/proof.h"
+#include "expr/proof_node_manager.h"
+#include "prop/minisat/core/SolverTypes.h"
+#include "prop/cnf_stream.h"
+#include "prop/sat_solver_types.h"
+
+namespace Minisat {
+class Solver;
+}
+
+namespace CVC4 {
+namespace prop {
+
+/**
+ * This class is responsible for managing the proof production of the SAT
+ * solver. It tracks resolutions produced during solving and stores them,
+ * independently, with the connection of the resolutions only made when the
+ * empty clause is produced and the refutation is complete. The expected
+ * assumptions of the refutation are the clausified preprocessed assertions and
+ * lemmas.
+ *
+ * These resolutions are stored in a LazyCDProofChain, a user-context-dependent
+ * proof that takes lazy steps and can connect them when generating a proof for
+ * a given fact. Its use in this proof manager is so that, assuming the
+ * following lazy steps are saved in the LazyCDProofChain:
+ *
+ * --- S0: (l4, PG0)
+ * --- S1: ((or l3 l4), PG1)
+ * --- S2: ((or l1 ~l3), PG2)
+ * --- S3: (false, PG3)
+ * --- S4: (~l2, PG4)
+ * --- S5: (~l3, PG5)
+ * --- S6: (~l5, PG6)
+ *
+ * when requesting the proof of false, assuming that the proof generators have
+ * the following expansions:
+ *
+ * --- PG0 -> (CHAIN_RES ((or l4 l1) ~l1))
+ * --- PG1 -> (CHAIN_RES ((or l3 l5 l6 l7) ~l5 (or ~l6 l7) (or l4 ~l7)))
+ * --- PG2 -> (CHAIN_RES ((or l1 ~l3 l5) ~l5))
+ * --- PG3 -> (CHAIN_RES ((or l1 l2) ~l1 ~l2))
+ * --- PG4 -> (CHAIN_RES ((or l3 ~l2) ~l3))
+ * --- PG5 -> (CHAIN_RES ((or l1 ~l3) ~l1))
+ * --- PG6 -> (CHAIN_RES ((or l1 ~l5) ~l1))
+ *
+ * will connect the independent resolutions and yield the following refutation
+ *
+ * (or l1 ~l5) ~l1
+ * ---------------- CHAIN_RES
+ * (or l1 ~l3 l5) ~l5
+ * ---------------------- CHAIN_RES
+ * (or l1 ~l3) ~l1
+ * ----------------------------- CHAIN_RES
+ * (or l3 ~l2) ~l3
+ * -------------------- CHAIN_RES
+ * (or l1 l2) ~l1 ~l2
+ * --------------------------- CHAIN_RES
+ * false
+ *
+ * where note that the steps S0 and S1, for l4 and (or l3 l4), respectively,
+ * were ignored, since they were not part of the chain starting with
+ * false. Moreover there is no requirement that the steps are registered
+ * chronologically in the LazyCDProofChain. The chain started on step S3 and
+ * proceeded to steps S4, S5, S2, and finally S6.
+ *
+ * To track the reasoning of the SAT solver and produce the steps above this
+ * class does three main things:
+ * (1) Register the resolutions for learned clauses as they are learned.
+ * (2) Register the resolutions for propagated literals when necessary.
+ * (3) Register the *full* resolution proof for the empty clause.
+ *
+ * Case (1) covers the learned clauses during backjumping. The only information
+ * saved is that, from clauses C1 to Cn, a given learned clause C is derived via
+ * chain resolution (and possibly factoring, reordering and double negation
+ * elimination in its literals), i.e., we do not recursively prove C1 to Cn at
+ * this moment.
+ *
+ * Not explaining C1 to Cn eagerly is beneficial because:
+ * - we might be wasting resources in fully explanaining it now, since C may not
+ * be necessary for the derivation of the empty clause, and
+ * - in explaining clauses lazily we might have shorter explanations, which has
+ * been observed empirically to be often the case.
+ *
+ * The latter case is a result of the SAT solver possibly changing the
+ * explanation of each of C, C1 to Cn, or the components of their
+ * explanations. This is because the set of propagated literals that may be used
+ * in these explanations can change in different SAT contexts, with the same
+ * clause being derived several times, each from a different set of clauses.
+ *
+ * Therefore we only fully explain a clause when absolutely necessary, i.e.,
+ * when we are done (see case (3)) or when we'd not be able to do it afterwards
+ * (see case (2)). In the example above, step S2 is generated from case (1),
+ * with the shallow proof
+ *
+ * (or l1 ~l3 l5) ~l5
+ * ------------------------- CHAIN_RES
+ * (or l1 ~l3)
+ *
+ * explaining the learned clause (or l1 ~l3). Its full proof would only be
+ * produced if it were part of the final refutation, as it indeed is. Note that
+ * in the example above the refutation proof contains the resolution proof of
+ * ~l5.
+ *
+ * Case (2) covers:
+ * (2.1) propagated literals explained by clauses being deleted
+ * (2.2) propagated literals whose negation occurs in a learned clause, which
+ * are then deleted for being redundant.
+ *
+ * Case (2.1) only happens for the so-called "locked clauses", which are clauses
+ * C = l1 v ... v ln that propagate their first literal, l1. When a locked
+ * clause C is deleted we save a chain resolution proof of l1 because we'd not
+ * be able to retrieve C afterwards, since it is deleted. The proof is a chain
+ * resolution step between C and ~l2, ..., ~ln, concluding l1. In the example
+ * above, step S0 is generated from case (2.1), with the locked clause (or l4
+ * l1) being deleted and requiring the registration in the LazyCDPRoofChain of a
+ * lazy step for
+ *
+ * (or l4 l1) ~l1
+ * ------------------------- CHAIN_RES
+ * l4
+ *
+ * Case (2.2) requires that, when a redundant literal (i.e., a literal whose
+ * negation is propagated) is deleted from a learned clause, we add the
+ * explanation of its negation to the chain resolution proof of the learned
+ * clause. This justifies the deletion of the redundant literal. However, the
+ * explanation for the propagated literal (the SAT solver maintains a map from
+ * propagated literals to the clauses that propagate them in the current
+ * context, i.e., their explanations, clauses in which all literals but the
+ * propagated one have their negation propagated) may also contain literals that
+ * were in the learned clause and were deleted for being redundant. Therefore
+ * eliminating a redundant literal requires recursively explaining the
+ * propagated literals in its explanation as long as they are, themselves,
+ * redundant literals in the learned clause.
+ *
+ * In the above example step S1, concluding (or l3 l4), is generated from the
+ * resolutions
+ *
+ * (or l3 l5 l6 l7) ~l5
+ * -------------------------- CHAIN_RES
+ * (or l3 l6 l7) (or ~l6 l7) (or l4 ~l7)
+ * ---------------------------------------------------------------- CHAIN_RES
+ * (or l3 l4)
+ *
+ * as l6 and l7 are redundant, which leads to (or l3 l6 l7) being resolved with
+ * l6's explanation, (or ~l6 l7). The literals in the explanation of l7 are
+ * recursively explained if they are also redundant, which is the case for l7,
+ * so its explanation is also added as premise for the resolution. Since l4 is
+ * not redundant, it is not recursively explained.
+ *
+ * Note that the actual proof generated does not have the intermediary step
+ * before removing redundant literals. It's all done in one fell swoop:
+ *
+ * (or l3 l5 l6 l7) ~l5 (or ~l6 l7) (or l4 ~l7)
+ * --------------------------------------------------- CHAIN_RES
+ * (or l3 l4)
+ *
+ * Finally, case (3) happens when the SAT solver derives the empty clause and
+ * it's not possible to backjump. The empty clause is learned from a conflict
+ * clause: a clause whose every literal has its negation propagated in the
+ * current context. Thus the proof of the empty clause is generated, at first,
+ * in the same way as case (1): a resolution chain betweeen the conflict clause
+ * and its negated literals. However, since we are now done, we recursively
+ * explain the propagated literals, starting from the negated literals from the
+ * conflict clause and progressing to all propagated literals ocurring in a
+ * given explanation.
+ *
+ * In the above example this happens as: step S3
+ *
+ * (or l1 l2) ~l1 ~l2
+ * --------------------------- CHAIN_RES
+ * false
+ *
+ * is added for a conflict clause (or l1 l2). Then we attempt to explain ~l1 and
+ * ~l2. The former has no explanation (i.e., it's an input), while the latter
+ * has explanation (or l3 ~l2). This leads to step S4
+ *
+ * (or l3 ~l2) ~l3
+ * -------------------- CHAIN_RES
+ * ~l2
+ *
+ * being added to the LazyCDProofChain. In explaining ~l3 the step S5
+ *
+ * (or l1 ~l3) ~l1
+ * --------------------- CHAIN_RES
+ * ~l3
+ *
+ * is added. Since ~l1 has no explanation, the process halts. Note that at this
+ * point the step S6 has not been added to the LazyCDProofChain. This is because
+ * to explain ~l5 we need to look at the literal premises in the proofs of
+ * learned clauses.
+ *
+ * The last thing done then in case (3), after the resolution on the conflict
+ * clause and an initial recursive explanation of propagated literals, is to
+ * connect the refutation proof and then recursively its propagated literal
+ * leaves, repeating until a fix point.
+ *
+ * In the above example the first connection yields
+ *
+ * (or l1 ~l3 l5) ~l5
+ * ---------------------- CHAIN_RES
+ * (or l1 ~l3) ~l1
+ * ----------------------------- CHAIN_RES
+ * (or l3 ~l2) ~l3
+ * -------------------- CHAIN_RES
+ * (or l1 l2) ~l1 ~l2
+ * --------------------------- CHAIN_RES
+ * false
+ *
+ * whose literal leaves are ~l1 and ~l5. The former has no explanation, but the
+ * latter is explained by (or l1 ~l5), thus leading to step S6
+ *
+ * (or l1 ~l5) ~l1
+ * --------------------- CHAIN_RES
+ * ~l5
+ *
+ * then the final connection
+ *
+ * (or l1 ~l5) ~l1
+ * ---------------- CHAIN_RES
+ * (or l1 ~l3 l5) ~l5
+ * ---------------------- CHAIN_RES
+ * (or l1 ~l3) ~l1
+ * ----------------------------- CHAIN_RES
+ * (or l3 ~l2) ~l3
+ * -------------------- CHAIN_RES
+ * (or l1 l2) ~l1 ~l2
+ * --------------------------- CHAIN_RES
+ * false
+ *
+ * which has no more explainable literals as leaves.
+ *
+ * The interfaces below provide ways for the SAT solver to register its
+ * assumptions (clausified assertions and lemmas) for the SAT proof
+ * (registerSatAssumption), register resolution steps (startResChain /
+ * addResolutionStep / endResChain), build the final refutation proof
+ * (finalizeProof) and retrieve the refutation proof (getProof). So in a given
+ * run of the SAT solver these interfaces are expected to be used in the
+ * following order:
+ *
+ * (registerSatAssumptions | (startResChain (addResolutionStep)+ endResChain)*)*
+ * finalizeProof
+ * getProof
+ *
+ */
+class SatProofManager
+{
+ public:
+ SatProofManager(Minisat::Solver* solver,
+ CnfStream* cnfStream,
+ context::UserContext* userContext,
+ ProofNodeManager* pnm);
+
+ /** Marks the start of a resolution chain.
+ *
+ * This call is followed by *at least one* call to addResolution step and one
+ * call to endResChain.
+ *
+ * The given clause, at the node level, is registered in d_resLinks with a
+ * null pivot, since this is the first link in the chain.
+ *
+ * @param start a SAT solver clause (list of literals) that will be the first
+ * clause in a resolution chain.
+ */
+ void startResChain(const Minisat::Clause& start);
+ /** Adds a resolution step with a clause
+ *
+ * There must have been a call to startResChain before any call to
+ * addResolution step. After following calls to addResolution step there is
+ * one call to endResChain.
+ *
+ * The resolution step is added to d_resLinks with the clause, at the node
+ * level, and the literal, at the node level, as the pivot.
+ *
+ * @param clause the clause being resolved against
+ * @param lit the pivot of the resolution step
+ */
+ void addResolutionStep(const Minisat::Clause& clause, Minisat::Lit lit);
+ /** Adds a resolution step with a unit clause
+ *
+ * The resolution step is added to d_resLinks such that lit, at the node
+ * level, is the pivot and and the unit clause is ~lit, at the node level.
+ *
+ * If the literal is marked as redundant, then a step is *not* is added to
+ * d_resLinks. It is rather saved to d_redundandLits, whose components we will
+ * be handled in a special manner when the resolution chain is finished. This
+ * is because the steps corresponding to the removal of redundant literals
+ * have to be done in a specific order. See proccessRedundantLits below.
+ *
+ * @param lit the literal being resolved against
+ * @param redundant whether lit is redundant
+ */
+ void addResolutionStep(Minisat::Lit lit, bool redundant = false);
+ /** Ends resolution chain concluding a unit clause
+ *
+ * This call must have been preceded by one call to startResChain and at least
+ * one call to addResolutionStep.
+ *
+ * This and the version below both call the node version of this method,
+ * described further below, which actually does the necessary processing.
+ */
+ void endResChain(Minisat::Lit lit);
+ /** Ends resolution chain concluding a clause */
+ void endResChain(const Minisat::Clause& clause);
+ /** Build refutation proof starting from conflict clause
+ *
+ * This method (or its variations) is only called when the SAT solver has
+ * reached an unsatisfiable state.
+ *
+ * This and the versions below call the node version of this method, described
+ * further below, which actually does the necessary processing.
+ *
+ * @param adding whether the conflict is coming from a freshly added clause
+ */
+ void finalizeProof(const Minisat::Clause& inConflict, bool adding = false);
+ /** Build refutation proof starting from conflict unit clause
+ *
+ * @param adding whether the conflict is coming from a freshly added clause
+ */
+ void finalizeProof(Minisat::Lit inConflict, bool adding = false);
+ /** As above, but uses the unit conflict clause saved in d_conflictLit. */
+ void finalizeProof();
+ /** Set the unit conflict clause d_conflictLit. */
+ void storeUnitConflict(Minisat::Lit inConflict);
+
+ /** Retrive the refutation proof
+ *
+ * If there is no chain for false in d_resChains, meaning that this call was
+ * made before finalizeProof, an assumption proof node is produced.
+ */
+ std::shared_ptr<ProofNode> getProof();
+
+ /** Register a unit clause input, converted to its node representation. */
+ void registerSatLitAssumption(Minisat::Lit lit);
+ /** Register a set clause inputs. */
+ void registerSatAssumptions(const std::vector<Node>& assumps);
+
+ private:
+ /** Ends resolution chain concluding clause
+ *
+ * This method builds the proof of conclusion from the resolution chain
+ * currently saved in d_resLinks.
+ *
+ * First each saved redundant literals in d_redundantLits is processed via
+ * processRedundantLit. The literals in the resolution chain's conclusion are
+ * used to verifynig which literals in the computed explanations are
+ * redundant, i.e., don't occur in conclusionLits. The nessary resolution
+ * steps will be added to d_resLinks.
+ *
+ * The proof to be built will be a CHAIN_RESOLUTION step, whose children and
+ * arguments will be retrieved from traversing d_resLinks. Consider the
+ * following d_resLinks (where each [~]li is its node equivalent):
+ *
+ * - <(or l3 l5 l6 l7), null>
+ * - <~l5, l5>
+ * - <(or ~l6 l7), l6>
+ * - <(or l4 ~l7), l7>
+ *
+ * The resulting children and arguments for the CHAIN_RESOLUTION proof step would be:
+ * - [(or l3 l5 l6 l7), ~l5, (or ~l6 l7), (or l4 ~l7)]
+ * - [l5, l6, l7]
+ * and the proof step
+ *
+ * (or l3 l5 l6 l7) ~l5 (or ~l6 l7) (or l4 ~l7)
+ * --------------------------------------------------- CHAIN_RES_{l5,l6,l7}
+ * (or l3 l4)
+ *
+ * The conclusion of the CHAIN_RES proof step is *not* the given conclusion of
+ * this method. This is because conclusion is the node equivalent of the
+ * clause in the SAT solver, which is kept modulo duplicates, reordering, and
+ * double negation elimination. Therefore we generate the above step in the
+ * correct way for the semantics of CHAIN_RES, based on its children and
+ * arguments, via the d_pnm's proof checker. The resulting node n is fed into
+ * the clause normalization in TheoryProofStepBuffer, which reduces n to
+ * conclusion.
+ *
+ * All the proof steps generated to conclude conclusion from the premises in
+ * d_resLinks are saved into d_resChainPg, which is saved as the proof
+ * generator for lazy step added to d_resChains for the conclusion.
+ *
+ * @param conclusion the node-level conclusion of the resolution chain
+ * @param conclusionLits the set of literals in the conclusion
+ */
+ void endResChain(Node conclusion, const std::set<SatLiteral>& conclusionLits);
+
+ /** Explain redundant literal and generate corresponding resolution steps
+ *
+ * If the redundant literal has a reason, we add a resolution step with that
+ * clause, otherwise with the negation of the redundant literal as the unit
+ * clause. The redundant literal is the resolvent in both cases. The steps
+ * are always added as the *first* link after last resolution step added
+ * *before* processing redundant literals began, i.e., at d_resLinks.begin() +
+ * pos. This is to guarantee that the links are in the correct order for the
+ * chain resolution, see below.
+ *
+ * If the reason contains literals that do not occur in conclusionLits, they
+ * are redundant and recursively processed by this method. This recursive
+ * processing happens *before* the resolution step for lit is added. Since
+ * steps are always added in position pos, pushing steps after that 1
+ * position, this guarantees that a step with a clause will occur before the
+ * steps that eliminate its redundant literals.
+ *
+ * Consider d_resLinks with 3 links before the first processRedundantLit call,
+ * i.e., pos = 3, and d_redundantLits = {l1}, with reason(l1) = (or l1 ~l2),
+ * with ~l2 redundant. Assume ~l2 has no explanation. By processing ~l2 first,
+ * the link <~l2, l2> will be added at position 3. Then by coming back to the
+ * processing of l1 the link <(or l1 ~l2), l1> will also be added position 3,
+ * with <~l2, l2> pushed to position 4. If this these links had the reverse
+ * order the literal ~l2 would, erroneously, occur in the chain resolution
+ * conclusion, as it is introduced by (or l1 ~l2).
+ *
+ * After a resolution step for a redundant literal is added, it is marked as
+ * visited, thus avoiding adding redundunt resolution steps to the chain if
+ * that literal occurs again in another redundant literal's reason.
+ *
+ * @param lit the redundant literal
+ * @param conclusionLits the literals in the clause from which redundant
+ * literals have been removed
+ * @param visited cache of literals already processed
+ * @param pos position, in d_resLinks, of last resolution step added *before*
+ * processing redundant literals
+ */
+ void processRedundantLit(SatLiteral lit,
+ const std::set<SatLiteral>& conclusionLits,
+ std::set<SatLiteral>& visited,
+ unsigned pos);
+ /** Explain literal if it is propagated in the SAT solver
+ *
+ * If a literal is propagated, i.e., it has a reason in the SAT solver, that
+ * clause is retrieved. This method is then called recursively on the negation
+ * of each of reason's literals (that is not lit). Afterwards a
+ * CHAIN_RESOLUTION proof step is created to conclude lit from the reason and
+ * its literals, other than lit, negations.
+ *
+ * This method also tracks all the literals and clauses, at the node level,
+ * that have been used as premises of resolutions steps in the recursive
+ * explanations. A resolution step is only created if the conclusion does not
+ * occur in these premises, as this would configure a cyclic proof.
+ *
+ * These cyclic proofs, at the node level, are naturally generated by the SAT
+ * solver because they are so that a literal is derived from a clause (so they
+ * are different) but both correspond to the *same node*. For example,
+ * consider the following derivation at the SAT solver level
+ *
+ * [l1, l2, l3] ~l2 ~l3
+ * -------------------------- CHAIN_RES
+ * [l0, ~l1] l1
+ * ---------------------- CHAIN_RES
+ * l0
+ *
+ * which has no issues. However, its node equivalent is
+ *
+ * (or a b c) (not b) (not c)
+ * ------------------------------- CHAIN_RES
+ * (or (or a b c) (not a)) a
+ * --------------------------------- CHAIN_RES
+ * (or a b c)
+ *
+ * which is cyclic. The issue is that l0 = (or a b c). Only at the SAT level
+ * are l0 and [l1, l2, l3] different.
+ *
+ * If a cyclic proof is identified, the respective node is kept as an
+ * assumption.
+ *
+ * @param lit the literal to explained
+ * @param premises set of literals and clauses, at the node level, that
+ * have been used as premises of resolution steps while explaining
+ * propagations
+ */
+ void explainLit(prop::SatLiteral lit,
+ std::unordered_set<TNode, TNodeHashFunction>& premises);
+
+ /** Build refutation proof starting from conflict clause
+ *
+ * Given a conflict clause, this method handles case (3) described in the
+ * preamble. Each of the literals in the conflict clause is either
+ * explainable, the result of a previously saved resolution chain, or an
+ * input.
+ *
+ * First, explainLit is called recursively on the negated literals from
+ * the conflict clause.
+ *
+ * Second, a CHAIN_RESOLUTION proof step is added between
+ * the conflict clause and its negated literals, concluding false.
+ *
+ * Third, until a fix point, the refutation proof is connected, by calling
+ * d_resChain.getProofFor(d_false), its free assumptions are determined and,
+ * in case any as a literal that might be explained, we call explainLit.
+ *
+ * The latter is called to a fix point because adding an explanation to a
+ * propagated literal may connect it with a previously saved resolution chain,
+ * which may have free assumptions that are literals that can be explained and
+ * so on.
+ *
+ * @param inConflictNode node corresponding to conflict clause
+ * @param inConflict literals in the conflict clause
+ */
+ void finalizeProof(Node inConflictNode,
+ const std::vector<SatLiteral>& inConflict);
+
+ /** The SAT solver to which we are managing proofs */
+ Minisat::Solver* d_solver;
+ /** Pointer to the underlying cnf stream. */
+ CnfStream* d_cnfStream;
+ /** The proof node manager */
+ ProofNodeManager* d_pnm;
+ /** Resolution steps (links) accumulator for chain resolution.
+ *
+ * Each pair has a clause and the pivot for the resolution step it is involved
+ * on. The pivot occurs positively in the clause yielded by the resolution up
+ * to the previous link and negatively in this link. The first link has a null
+ * pivot. Links are kept at the node level.
+ *
+ * This accumulator is reset after each chain resolution. */
+ std::vector<std::pair<Node, Node>> d_resLinks;
+
+ /** Redundant literals removed from the resolution chain's conclusion.
+ *
+ * This accumulator is reset after each chain resolution. */
+ std::vector<SatLiteral> d_redundantLits;
+
+ /**
+ * Associates clauses to their local proofs. These proofs are local and
+ * possibly updated during solving. When the final conclusion is reached, a
+ * final proof is built based on the proofs saved here.
+ *
+ * This chain is initialized so that its getProofFor method, which connects
+ * the chain, accounts for cyclic proofs. This is so that we avoid the issue
+ * described in explainLit.
+ */
+ LazyCDProofChain d_resChains;
+
+ /** The proof generator for resolution chains */
+ BufferedProofGenerator d_resChainPg;
+
+ /** The false node */
+ Node d_false;
+
+ /** All clauses added to the SAT solver, kept in a context-dependent manner.
+ */
+ context::CDHashSet<Node, NodeHashFunction> d_assumptions;
+
+ /**
+ * A placeholder that may be used to store the literal with the final
+ * conflict.
+ */
+ SatLiteral d_conflictLit;
+ /** Gets node equivalent to literal */
+ Node getClauseNode(SatLiteral satLit);
+ /** Gets node equivalent to clause.
+ *
+ * To avoid generating different nodes for the same clause, modulo ordering,
+ * an invariant assumed throughout this class, the OR node generated by this
+ * method always has its children ordered.
+ */
+ Node getClauseNode(const Minisat::Clause& clause);
+ /** Prints clause, as a sequence of literals, in the "sat-proof" trace. */
+ void printClause(const Minisat::Clause& clause);
+}; /* class SatProofManager */
+
+} // namespace prop
+} // namespace CVC4
+
+#endif /* CVC4__SAT_PROOF_MANAGER_H */
diff --git a/src/prop/sat_solver.h b/src/prop/sat_solver.h
index d4b08ab71..a842647bd 100644
--- a/src/prop/sat_solver.h
+++ b/src/prop/sat_solver.h
@@ -5,7 +5,7 @@
** Dejan Jovanovic, Liana Hadarean, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,8 +19,6 @@
#ifndef CVC4__PROP__SAT_SOLVER_H
#define CVC4__PROP__SAT_SOLVER_H
-#include <stdint.h>
-
#include <string>
#include "context/cdlist.h"
@@ -33,11 +31,6 @@
namespace CVC4 {
-namespace proof {
-class ClausalBitVectorProof;
-class ResolutionBitVectorProof;
-} // namespace proof
-
namespace prop {
class TheoryProxy;
@@ -58,7 +51,7 @@ public:
/** Add a clause corresponding to rhs = l1 xor .. xor ln */
virtual ClauseId addXorClause(SatClause& clause, bool rhs, bool removable) = 0;
-
+
/**
* Create a new boolean variable in the solver.
* @param isTheoryAtom is this a theory atom that needs to be asserted to theory
@@ -84,6 +77,7 @@ public:
virtual SatValue solve(const std::vector<SatLiteral>& assumptions)
{
Unimplemented() << "Solving under assumptions not implemented";
+ return SAT_VALUE_UNKNOWN;
};
/** Interrupt the solver */
@@ -101,10 +95,6 @@ public:
/** Check if the solver is in an inconsistent state */
virtual bool ok() const = 0;
- virtual void setResolutionProofLog(proof::ResolutionBitVectorProof* bvp) {}
-
- virtual void setClausalProofLog(proof::ClausalBitVectorProof* drat_proof) {}
-
};/* class SatSolver */
diff --git a/src/prop/sat_solver_factory.cpp b/src/prop/sat_solver_factory.cpp
index afd2a4c30..cfdbc8b04 100644
--- a/src/prop/sat_solver_factory.cpp
+++ b/src/prop/sat_solver_factory.cpp
@@ -5,7 +5,7 @@
** Mathias Preiner, Aina Niemetz, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/prop/sat_solver_factory.h b/src/prop/sat_solver_factory.h
index c9ed207f9..75069e63b 100644
--- a/src/prop/sat_solver_factory.h
+++ b/src/prop/sat_solver_factory.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Liana Hadarean, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/prop/sat_solver_types.cpp b/src/prop/sat_solver_types.cpp
index 881086bf2..193330e06 100644
--- a/src/prop/sat_solver_types.cpp
+++ b/src/prop/sat_solver_types.cpp
@@ -5,7 +5,7 @@
** Alex Ozdemir
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/prop/sat_solver_types.h b/src/prop/sat_solver_types.h
index 83e9366fe..717b1ffaa 100644
--- a/src/prop/sat_solver_types.h
+++ b/src/prop/sat_solver_types.h
@@ -5,7 +5,7 @@
** Dejan Jovanovic, Alex Ozdemir, Liana Hadarean
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/prop/theory_proxy.cpp b/src/prop/theory_proxy.cpp
index 41da4546e..65da2fc7c 100644
--- a/src/prop/theory_proxy.cpp
+++ b/src/prop/theory_proxy.cpp
@@ -2,10 +2,10 @@
/*! \file theory_proxy.cpp
** \verbatim
** Top contributors (to current version):
- ** Tim King, Kshitij Bansal, Guy Katz
+ ** Tim King, Kshitij Bansal, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -22,7 +22,6 @@
#include "prop/cnf_stream.h"
#include "prop/prop_engine.h"
#include "proof/cnf_proof.h"
-#include "smt/command.h"
#include "smt/smt_statistics_registry.h"
#include "theory/rewriter.h"
#include "theory/theory_engine.h"
@@ -76,22 +75,13 @@ void TheoryProxy::explainPropagation(SatLiteral l, SatClause& explanation) {
TNode lNode = d_cnfStream->getNode(l);
Debug("prop-explain") << "explainPropagation(" << lNode << ")" << std::endl;
- LemmaProofRecipe* proofRecipe = NULL;
- PROOF(proofRecipe = new LemmaProofRecipe;);
+ theory::TrustNode texp = d_theoryEngine->getExplanation(lNode);
+ Node theoryExplanation = texp.getNode();
- Node theoryExplanation = d_theoryEngine->getExplanationAndRecipe(lNode, proofRecipe);
-
- PROOF({
- ProofManager::getCnfProof()->pushCurrentAssertion(theoryExplanation);
- ProofManager::getCnfProof()->setProofRecipe(proofRecipe);
-
- Debug("pf::sat") << "TheoryProxy::explainPropagation: setting lemma recipe to: "
- << std::endl;
- proofRecipe->dump("pf::sat");
-
- delete proofRecipe;
- proofRecipe = NULL;
- });
+ if (options::unsatCores())
+ {
+ ProofManager::getCnfProof()->pushCurrentAssertion(theoryExplanation);
+ }
Debug("prop-explain") << "explainPropagation() => " << theoryExplanation << std::endl;
if (theoryExplanation.getKind() == kind::AND) {
@@ -159,11 +149,7 @@ SatValue TheoryProxy::getDecisionPolarity(SatVariable var) {
return d_decisionEngine->getPolarity(var);
}
-void TheoryProxy::dumpStatePop() {
- if(Dump.isOn("state")) {
- Dump("state") << PopCommand();
- }
-}
+CnfStream* TheoryProxy::getCnfStream() { return d_cnfStream; }
}/* CVC4::prop namespace */
}/* CVC4 namespace */
diff --git a/src/prop/theory_proxy.h b/src/prop/theory_proxy.h
index 7fd735bf2..e16728d0d 100644
--- a/src/prop/theory_proxy.h
+++ b/src/prop/theory_proxy.h
@@ -5,7 +5,7 @@
** Dejan Jovanovic, Tim King, Kshitij Bansal
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -88,8 +88,7 @@ class TheoryProxy
SatValue getDecisionPolarity(SatVariable var);
- /** Shorthand for Dump("state") << PopCommand() */
- void dumpStatePop();
+ CnfStream* getCnfStream();
private:
/** The prop engine we are using. */
@@ -112,8 +111,7 @@ class TheoryProxy
* all imported and exported lemmas.
*/
std::unordered_set<Node, NodeHashFunction> d_shared;
-
-}; /* class SatSolver */
+}; /* class TheoryProxy */
}/* CVC4::prop namespace */
diff --git a/src/smt/abduction_solver.cpp b/src/smt/abduction_solver.cpp
index 01e2a4f0f..3f03c00e2 100644
--- a/src/smt/abduction_solver.cpp
+++ b/src/smt/abduction_solver.cpp
@@ -2,10 +2,10 @@
/*! \file abduction_solver.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds
+ ** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -39,12 +39,7 @@ bool AbductionSolver::getAbduct(const Node& goal,
throw ModalException(msg);
}
Trace("sygus-abduct") << "SmtEngine::getAbduct: goal " << goal << std::endl;
- std::vector<Expr> easserts = d_parent->getExpandedAssertions();
- std::vector<Node> axioms;
- for (unsigned i = 0, size = easserts.size(); i < size; i++)
- {
- axioms.push_back(Node::fromExpr(easserts[i]));
- }
+ std::vector<Node> axioms = d_parent->getExpandedAssertions();
std::vector<Node> asserts(axioms.begin(), axioms.end());
// must expand definitions
Node conjn = d_parent->expandDefinitions(goal);
@@ -89,16 +84,15 @@ bool AbductionSolver::getAbductInternal(Node& abd)
if (r.asSatisfiabilityResult().isSat() == Result::UNSAT)
{
// get the synthesis solution
- std::map<Expr, Expr> sols;
+ std::map<Node, Node> sols;
d_subsolver->getSynthSolutions(sols);
Assert(sols.size() == 1);
- Expr essf = d_sssf.toExpr();
- std::map<Expr, Expr>::iterator its = sols.find(essf);
+ std::map<Node, Node>::iterator its = sols.find(d_sssf);
if (its != sols.end())
{
Trace("sygus-abduct")
<< "SmtEngine::getAbduct: solution is " << its->second << std::endl;
- abd = Node::fromExpr(its->second);
+ abd = its->second;
if (abd.getKind() == kind::LAMBDA)
{
abd = abd[1];
@@ -140,8 +134,8 @@ void AbductionSolver::checkAbduct(Node a)
Trace("check-abduct") << "SmtEngine::checkAbduct: get expanded assertions"
<< std::endl;
- std::vector<Expr> asserts = d_parent->getExpandedAssertions();
- asserts.push_back(a.toExpr());
+ std::vector<Node> asserts = d_parent->getExpandedAssertions();
+ asserts.push_back(a);
// two checks: first, consistent with assertions, second, implies negated goal
// is unsatisfiable.
@@ -154,7 +148,7 @@ void AbductionSolver::checkAbduct(Node a)
initializeSubsolver(abdChecker);
Trace("check-abduct") << "SmtEngine::checkAbduct: phase " << j
<< ": asserting formulas" << std::endl;
- for (const Expr& e : asserts)
+ for (const Node& e : asserts)
{
abdChecker->assertFormula(e);
}
@@ -178,7 +172,7 @@ void AbductionSolver::checkAbduct(Node a)
<< "SmtEngine::checkAbduct: goal is " << d_abdConj << std::endl;
// add the goal to the set of assertions
Assert(!d_abdConj.isNull());
- asserts.push_back(d_abdConj.toExpr());
+ asserts.push_back(d_abdConj);
}
else
{
diff --git a/src/smt/abduction_solver.h b/src/smt/abduction_solver.h
index 2041b961d..974de224e 100644
--- a/src/smt/abduction_solver.h
+++ b/src/smt/abduction_solver.h
@@ -2,10 +2,10 @@
/*! \file abduction_solver.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds
+ ** Andrew Reynolds, Aina Niemetz, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/smt/abstract_values.cpp b/src/smt/abstract_values.cpp
new file mode 100644
index 000000000..7d3ff64a6
--- /dev/null
+++ b/src/smt/abstract_values.cpp
@@ -0,0 +1,55 @@
+/********************* */
+/*! \file abstract_values.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Morgan Deters
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utility for constructing and maintaining abstract values.
+ **/
+
+#include "smt/abstract_values.h"
+
+#include "options/smt_options.h"
+
+namespace CVC4 {
+namespace smt {
+
+AbstractValues::AbstractValues(NodeManager* nm)
+ : d_nm(nm),
+ d_fakeContext(),
+ d_abstractValueMap(&d_fakeContext),
+ d_abstractValues()
+{
+}
+AbstractValues::~AbstractValues() {}
+
+Node AbstractValues::substituteAbstractValues(TNode n)
+{
+ // We need to do this even if options::abstractValues() is off,
+ // since the setting might have changed after we already gave out
+ // some abstract values.
+ return d_abstractValueMap.apply(n);
+}
+
+Node AbstractValues::mkAbstractValue(TNode n)
+{
+ Assert(options::abstractValues());
+ Node& val = d_abstractValues[n];
+ if (val.isNull())
+ {
+ val = d_nm->mkAbstractValue(n.getType());
+ d_abstractValueMap.addSubstitution(val, n);
+ }
+ // We are supposed to ascribe types to all abstract values that go out.
+ Node ascription = d_nm->mkConst(AscriptionType(n.getType()));
+ Node retval = d_nm->mkNode(kind::APPLY_TYPE_ASCRIPTION, ascription, val);
+ return retval;
+}
+
+} // namespace smt
+} // namespace CVC4
diff --git a/src/smt/abstract_values.h b/src/smt/abstract_values.h
new file mode 100644
index 000000000..aba7c8e89
--- /dev/null
+++ b/src/smt/abstract_values.h
@@ -0,0 +1,80 @@
+/********************* */
+/*! \file abstract_values.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Morgan Deters, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utility for constructing and maintaining abstract values.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__SMT__ABSTRACT_VALUES_H
+#define CVC4__SMT__ABSTRACT_VALUES_H
+
+#include <unordered_map>
+
+#include "context/context.h"
+#include "expr/node.h"
+#include "theory/substitutions.h"
+
+namespace CVC4 {
+namespace smt {
+
+/**
+ * This utility is responsible for constructing and maintaining abstract
+ * values, which are used in some responses to e.g. get-value / get-model
+ * commands. See SMT-LIB standard 2.6 page 65 for details.
+ */
+class AbstractValues
+{
+ typedef std::unordered_map<Node, Node, NodeHashFunction> NodeToNodeHashMap;
+ public:
+ AbstractValues(NodeManager* nm);
+ ~AbstractValues();
+ /**
+ * Substitute away all AbstractValues in a node, which replaces all
+ * abstract values with their original definition. For example, if `@a` was
+ * introduced for term t, then applying this method on f(`@a`) returns f(t).
+ */
+ Node substituteAbstractValues(TNode n);
+
+ /**
+ * Make a new (or return an existing) abstract value for a node.
+ * Can only use this if options::abstractValues() is on.
+ */
+ Node mkAbstractValue(TNode n);
+
+ private:
+ /** Pointer to the used node manager */
+ NodeManager* d_nm;
+ /**
+ * A context that never pushes/pops, for use by CD structures (like
+ * SubstitutionMaps) that should be "global".
+ */
+ context::Context d_fakeContext;
+
+ /**
+ * A map of AbsractValues to their actual constants. Only used if
+ * options::abstractValues() is on.
+ */
+ theory::SubstitutionMap d_abstractValueMap;
+
+ /**
+ * A mapping of all abstract values (actual value |-> abstract) that
+ * we've handed out. This is necessary to ensure that we give the
+ * same AbstractValues for the same real constants. Only used if
+ * options::abstractValues() is on.
+ */
+ NodeToNodeHashMap d_abstractValues;
+};
+
+} // namespace smt
+} // namespace CVC4
+
+#endif
diff --git a/src/smt/assertions.cpp b/src/smt/assertions.cpp
new file mode 100644
index 000000000..ab2c9ae5d
--- /dev/null
+++ b/src/smt/assertions.cpp
@@ -0,0 +1,243 @@
+/********************* */
+/*! \file assertions.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Andres Noetzli, Haniel Barbosa
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The module for storing assertions for an SMT engine.
+ **/
+
+#include "smt/assertions.h"
+
+#include "expr/node_algorithm.h"
+#include "options/base_options.h"
+#include "options/language.h"
+#include "options/smt_options.h"
+#include "proof/proof_manager.h"
+#include "smt/smt_engine.h"
+
+using namespace CVC4::theory;
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace smt {
+
+Assertions::Assertions(context::UserContext* u, AbstractValues& absv)
+ : d_userContext(u),
+ d_absValues(absv),
+ d_assertionList(nullptr),
+ d_globalNegation(false),
+ d_assertions()
+{
+}
+
+Assertions::~Assertions()
+{
+ if (d_assertionList != nullptr)
+ {
+ d_assertionList->deleteSelf();
+ }
+}
+
+void Assertions::finishInit()
+{
+ // [MGD 10/20/2011] keep around in incremental mode, due to a
+ // cleanup ordering issue and Nodes/TNodes. If SAT is popped
+ // first, some user-context-dependent TNodes might still exist
+ // with rc == 0.
+ if (options::produceAssertions() || options::incrementalSolving())
+ {
+ // In the case of incremental solving, we appear to need these to
+ // ensure the relevant Nodes remain live.
+ d_assertionList = new (true) AssertionList(d_userContext);
+ d_globalDefineFunRecLemmas.reset(new std::vector<Node>());
+ }
+}
+
+void Assertions::clearCurrent()
+{
+ d_assertions.clear();
+ d_assertions.getIteSkolemMap().clear();
+}
+
+void Assertions::initializeCheckSat(const std::vector<Node>& assumptions,
+ bool inUnsatCore,
+ bool isEntailmentCheck)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ // reset global negation
+ d_globalNegation = false;
+ // clear the assumptions
+ d_assumptions.clear();
+ if (isEntailmentCheck)
+ {
+ size_t size = assumptions.size();
+ if (size > 1)
+ {
+ /* Assume: not (BIGAND assumptions) */
+ d_assumptions.push_back(nm->mkNode(AND, assumptions).notNode());
+ }
+ else if (size == 1)
+ {
+ /* Assume: not expr */
+ d_assumptions.push_back(assumptions[0].notNode());
+ }
+ }
+ else
+ {
+ /* Assume: BIGAND assumptions */
+ d_assumptions = assumptions;
+ }
+
+ Result r(Result::SAT_UNKNOWN, Result::UNKNOWN_REASON);
+ for (const Node& e : d_assumptions)
+ {
+ // Substitute out any abstract values in ex.
+ Node n = d_absValues.substituteAbstractValues(e);
+ // Ensure expr is type-checked at this point.
+ ensureBoolean(n);
+ addFormula(n, inUnsatCore, true, true, false);
+ }
+ if (d_globalDefineFunRecLemmas != nullptr)
+ {
+ // Global definitions are asserted at check-sat-time because we have to
+ // make sure that they are always present (they are essentially level
+ // zero assertions)
+ for (const Node& lemma : *d_globalDefineFunRecLemmas)
+ {
+ addFormula(lemma, false, true, false, false);
+ }
+ }
+}
+
+void Assertions::assertFormula(const Node& n, bool inUnsatCore)
+{
+ ensureBoolean(n);
+ bool maybeHasFv = language::isInputLangSygus(options::inputLanguage());
+ addFormula(n, inUnsatCore, true, false, maybeHasFv);
+}
+
+std::vector<Node>& Assertions::getAssumptions() { return d_assumptions; }
+bool Assertions::isGlobalNegated() const { return d_globalNegation; }
+void Assertions::flipGlobalNegated() { d_globalNegation = !d_globalNegation; }
+
+preprocessing::AssertionPipeline& Assertions::getAssertionPipeline()
+{
+ return d_assertions;
+}
+
+context::CDList<Node>* Assertions::getAssertionList()
+{
+ return d_assertionList;
+}
+
+void Assertions::addFormula(
+ TNode n, bool inUnsatCore, bool inInput, bool isAssumption, bool maybeHasFv)
+{
+ // add to assertion list if it exists
+ if (d_assertionList != nullptr)
+ {
+ d_assertionList->push_back(n);
+ }
+ if (n.isConst() && n.getConst<bool>())
+ {
+ // true, nothing to do
+ return;
+ }
+
+ Trace("smt") << "SmtEnginePrivate::addFormula(" << n
+ << "), inUnsatCore = " << inUnsatCore
+ << ", inInput = " << inInput
+ << ", isAssumption = " << isAssumption << std::endl;
+
+ // Ensure that it does not contain free variables
+ if (maybeHasFv)
+ {
+ if (expr::hasFreeVar(n))
+ {
+ std::stringstream se;
+ se << "Cannot process assertion with free variable.";
+ if (language::isInputLangSygus(options::inputLanguage()))
+ {
+ // Common misuse of SyGuS is to use top-level assert instead of
+ // constraint when defining the synthesis conjecture.
+ se << " Perhaps you meant `constraint` instead of `assert`?";
+ }
+ throw ModalException(se.str().c_str());
+ }
+ }
+
+ // Give it to proof manager
+ if (options::unsatCores())
+ {
+ if (inInput)
+ { // n is an input assertion
+ if (inUnsatCore || options::unsatCores() || options::dumpUnsatCores()
+ || options::checkUnsatCores())
+ {
+ ProofManager::currentPM()->addCoreAssertion(n.toExpr());
+ }
+ }
+ else
+ {
+ // n is the result of an unknown preprocessing step, add it to dependency
+ // map to null
+ ProofManager::currentPM()->addDependence(n, Node::null());
+ }
+ }
+
+ // Add the normalized formula to the queue
+ d_assertions.push_back(n, isAssumption, true);
+}
+
+void Assertions::addDefineFunRecDefinition(Node n, bool global)
+{
+ n = d_absValues.substituteAbstractValues(n);
+ if (d_assertionList != nullptr)
+ {
+ d_assertionList->push_back(n);
+ }
+ if (global && d_globalDefineFunRecLemmas != nullptr)
+ {
+ // Global definitions are asserted at check-sat-time because we have to
+ // make sure that they are always present
+ Assert(!language::isInputLangSygus(options::inputLanguage()));
+ d_globalDefineFunRecLemmas->emplace_back(n);
+ }
+ else
+ {
+ bool maybeHasFv = language::isInputLangSygus(options::inputLanguage());
+ addFormula(n, false, true, false, maybeHasFv);
+ }
+}
+
+void Assertions::ensureBoolean(const Node& n)
+{
+ TypeNode type = n.getType(options::typeChecking());
+ if (!type.isBoolean())
+ {
+ std::stringstream ss;
+ ss << "Expected Boolean type\n"
+ << "The assertion : " << n << "\n"
+ << "Its type : " << type;
+ throw TypeCheckingException(n.toExpr(), ss.str());
+ }
+}
+
+void Assertions::setProofGenerator(smt::PreprocessProofGenerator* pppg)
+{
+ d_assertions.setProofGenerator(pppg);
+}
+
+bool Assertions::isProofEnabled() const
+{
+ return d_assertions.isProofEnabled();
+}
+
+} // namespace smt
+} // namespace CVC4
diff --git a/src/smt/assertions.h b/src/smt/assertions.h
new file mode 100644
index 000000000..5ce2556a7
--- /dev/null
+++ b/src/smt/assertions.h
@@ -0,0 +1,177 @@
+/********************* */
+/*! \file assertions.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Morgan Deters, Andres Noetzli
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The module for storing assertions for an SMT engine.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__SMT__ASSERTIONS_H
+#define CVC4__SMT__ASSERTIONS_H
+
+#include <vector>
+
+#include "context/cdlist.h"
+#include "context/context.h"
+#include "expr/node.h"
+#include "preprocessing/assertion_pipeline.h"
+#include "smt/abstract_values.h"
+
+namespace CVC4 {
+namespace smt {
+
+/**
+ * Contains all information pertaining to the assertions of an SMT engine.
+ *
+ * This class is responsible for setting up the assertions pipeline for
+ * check-sat calls. It is *not* responsible for the preprocessing itself, and
+ * instead is intended to be the input to a preprocessor utility.
+ */
+class Assertions
+{
+ /** The type of our internal assertion list */
+ typedef context::CDList<Node> AssertionList;
+
+ public:
+ Assertions(context::UserContext* u, AbstractValues& absv);
+ ~Assertions();
+ /**
+ * Finish initialization, called once after options are finalized. Sets up
+ * the required bookkeeping based on the options.
+ */
+ void finishInit();
+ /**
+ * Clears out the non-context-dependent data in this class. Necessary to
+ * clear out our assertion vectors in case someone does a push-assert-pop
+ * without a check-sat.
+ */
+ void clearCurrent();
+ /*
+ * Initialize a call to check satisfiability. This adds assumptions to
+ * the list of assumptions maintained by this class, and finalizes the
+ * set of formulas (in the assertions pipeline) that will be used for the
+ * upcoming check-sat call.
+ *
+ * @param assumptions The assumptions of the upcoming check-sat call.
+ * @param inUnsatCore Whether assumptions are in the unsat core.
+ * @param isEntailmentCheck Whether we are checking entailment of assumptions
+ * in the upcoming check-sat call.
+ */
+ void initializeCheckSat(const std::vector<Node>& assumptions,
+ bool inUnsatCore,
+ bool isEntailmentCheck);
+ /**
+ * Add a formula to the current context: preprocess, do per-theory
+ * setup, use processAssertionList(), asserting to T-solver for
+ * literals and conjunction of literals. Returns false if
+ * immediately determined to be inconsistent. This version
+ * takes a Boolean flag to determine whether to include this asserted
+ * formula in an unsat core (if one is later requested).
+ *
+ * @throw TypeCheckingException, LogicException, UnsafeInterruptException
+ */
+ void assertFormula(const Node& n, bool inUnsatCore = true);
+ /**
+ * Assert that n corresponds to an assertion from a define-fun-rec command.
+ * This assertion is added to the set of assertions maintained by this class.
+ * If this has a global definition, this assertion is persistent for any
+ * subsequent check-sat calls.
+ */
+ void addDefineFunRecDefinition(Node n, bool global);
+ /**
+ * Get the assertions pipeline, which contains the set of assertions we are
+ * currently processing.
+ */
+ preprocessing::AssertionPipeline& getAssertionPipeline();
+ /**
+ * Get assertions list corresponding to the original list of assertions,
+ * before preprocessing.
+ */
+ context::CDList<Node>* getAssertionList();
+ /**
+ * Get the list of assumptions, which are those registered to this class
+ * on initializeCheckSat.
+ */
+ std::vector<Node>& getAssumptions();
+ /**
+ * Is the set of assertions globally negated? When this flag is true, the
+ * overall result of check-sat should be inverted.
+ */
+ bool isGlobalNegated() const;
+ /** Flip the global negation flag. */
+ void flipGlobalNegated();
+
+ //------------------------------------ for proofs
+ /** Set proof generator */
+ void setProofGenerator(smt::PreprocessProofGenerator* pppg);
+ /** Is proof enabled? */
+ bool isProofEnabled() const;
+ //------------------------------------ end for proofs
+ private:
+ /**
+ * Fully type-check the argument, and also type-check that it's
+ * actually Boolean.
+ * throw@ TypeCheckingException
+ */
+ void ensureBoolean(const Node& n);
+ /**
+ * Adds a formula to the current context. Action here depends on
+ * the SimplificationMode (in the current Options scope); the
+ * formula might be pushed out to the propositional layer
+ * immediately, or it might be simplified and kept, or it might not
+ * even be simplified.
+ * The arguments isInput and isAssumption are used for bookkeeping for unsat
+ * cores.
+ * The argument maybeHasFv should be set to true if the assertion may have
+ * free variables. By construction, assertions from the smt2 parser are
+ * guaranteed not to have free variables. However, other cases such as
+ * assertions from the SyGuS parser may have free variables (say if the
+ * input contains an assert or define-fun-rec command).
+ *
+ * @param isAssumption If true, the formula is considered to be an assumption
+ * (this is used to distinguish assertions and assumptions)
+ */
+ void addFormula(TNode n,
+ bool inUnsatCore,
+ bool inInput,
+ bool isAssumption,
+ bool maybeHasFv);
+ /** pointer to the user context */
+ context::UserContext* d_userContext;
+ /** Reference to the abstract values utility */
+ AbstractValues& d_absValues;
+ /**
+ * The assertion list (before any conversion) for supporting
+ * getAssertions(). Only maintained if in incremental mode.
+ */
+ AssertionList* d_assertionList;
+ /**
+ * List of lemmas generated for global recursive function definitions. We
+ * assert this list of definitions in each check-sat call.
+ */
+ std::unique_ptr<std::vector<Node>> d_globalDefineFunRecLemmas;
+ /**
+ * The list of assumptions from the previous call to checkSatisfiability.
+ * Note that if the last call to checkSatisfiability was an entailment check,
+ * i.e., a call to checkEntailed(a1, ..., an), then d_assumptions contains
+ * one single assumption ~(a1 AND ... AND an).
+ */
+ std::vector<Node> d_assumptions;
+ /** Whether we did a global negation of the formula. */
+ bool d_globalNegation;
+ /** Assertions in the preprocessing pipeline */
+ preprocessing::AssertionPipeline d_assertions;
+};
+
+} // namespace smt
+} // namespace CVC4
+
+#endif
diff --git a/src/smt/check_models.cpp b/src/smt/check_models.cpp
new file mode 100644
index 000000000..612084de2
--- /dev/null
+++ b/src/smt/check_models.cpp
@@ -0,0 +1,272 @@
+/********************* */
+/*! \file check_models.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utility for constructing and maintaining abstract values.
+ **/
+
+#include "smt/check_models.h"
+
+#include "options/smt_options.h"
+#include "smt/node_command.h"
+#include "smt/preprocessor.h"
+#include "theory/rewriter.h"
+#include "theory/substitutions.h"
+#include "theory/theory_engine.h"
+
+using namespace CVC4::theory;
+
+namespace CVC4 {
+namespace smt {
+
+CheckModels::CheckModels(SmtSolver& s) : d_smt(s) {}
+CheckModels::~CheckModels() {}
+
+void CheckModels::checkModel(Model* m,
+ context::CDList<Node>* al,
+ bool hardFailure)
+{
+ // Throughout, we use Notice() to give diagnostic output.
+ //
+ // If this function is running, the user gave --check-model (or equivalent),
+ // and if Notice() is on, the user gave --verbose (or equivalent).
+
+ // check-model is not guaranteed to succeed if approximate values were used.
+ // Thus, we intentionally abort here.
+ if (m->hasApproximations())
+ {
+ throw RecoverableModalException(
+ "Cannot run check-model on a model with approximate values.");
+ }
+
+ // Check individual theory assertions
+ if (options::debugCheckModels())
+ {
+ TheoryEngine* te = d_smt.getTheoryEngine();
+ Assert(te != nullptr);
+ te->checkTheoryAssertionsWithModel(hardFailure);
+ }
+
+ // Output the model
+ Notice() << *m;
+
+ NodeManager* nm = NodeManager::currentNM();
+ Preprocessor* pp = d_smt.getPreprocessor();
+
+ // We have a "fake context" for the substitution map (we don't need it
+ // to be context-dependent)
+ context::Context fakeContext;
+ SubstitutionMap substitutions(&fakeContext,
+ /* substituteUnderQuantifiers = */ false);
+
+ Trace("check-model") << "checkModel: Collect substitution..." << std::endl;
+ for (size_t k = 0, ncmd = m->getNumCommands(); k < ncmd; ++k)
+ {
+ const DeclareFunctionNodeCommand* c =
+ dynamic_cast<const DeclareFunctionNodeCommand*>(m->getCommand(k));
+ Notice() << "SmtEngine::checkModel(): model command " << k << " : "
+ << m->getCommand(k)->toString() << std::endl;
+ if (c == nullptr)
+ {
+ // we don't care about DECLARE-DATATYPES, DECLARE-SORT, ...
+ Notice() << "SmtEngine::checkModel(): skipping..." << std::endl;
+ continue;
+ }
+ // We have a DECLARE-FUN:
+ //
+ // We'll first do some checks, then add to our substitution map
+ // the mapping: function symbol |-> value
+
+ Node func = c->getFunction();
+ Node val = m->getValue(func);
+
+ Notice() << "SmtEngine::checkModel(): adding substitution: " << func
+ << " |-> " << val << std::endl;
+
+ // (1) if the value is a lambda, ensure the lambda doesn't contain the
+ // function symbol (since then the definition is recursive)
+ if (val.getKind() == kind::LAMBDA)
+ {
+ // first apply the model substitutions we have so far
+ Node n = substitutions.apply(val[1]);
+ // now check if n contains func by doing a substitution
+ // [func->func2] and checking equality of the Nodes.
+ // (this just a way to check if func is in n.)
+ SubstitutionMap subs(&fakeContext);
+ Node func2 =
+ nm->mkSkolem("", func.getType(), "", NodeManager::SKOLEM_NO_NOTIFY);
+ subs.addSubstitution(func, func2);
+ if (subs.apply(n) != n)
+ {
+ Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE DEFINED "
+ "IN TERMS OF ITSELF ***"
+ << std::endl;
+ std::stringstream ss;
+ ss << "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH "
+ "MODEL:"
+ << std::endl
+ << "considering model value for " << func << std::endl
+ << "body of lambda is: " << val << std::endl;
+ if (n != val[1])
+ {
+ ss << "body substitutes to: " << n << std::endl;
+ }
+ ss << "so " << func << " is defined in terms of itself." << std::endl
+ << "Run with `--check-models -v' for additional diagnostics.";
+ InternalError() << ss.str();
+ }
+ }
+
+ // (2) check that the value is actually a value
+ else if (!val.isConst())
+ {
+ // This is only a warning since it could have been assigned an
+ // unevaluable term (e.g. an application of a transcendental function).
+ // This parallels the behavior (warnings for non-constant expressions)
+ // when checking whether assertions are satisfied below.
+ Warning() << "Warning : SmtEngine::checkModel(): "
+ << "model value for " << func << std::endl
+ << " is " << val << std::endl
+ << "and that is not a constant (.isConst() == false)."
+ << std::endl
+ << "Run with `--check-models -v' for additional diagnostics."
+ << std::endl;
+ }
+
+ // (3) check that it's the correct (sub)type
+ // This was intended to be a more general check, but for now we can't do
+ // that because e.g. "1" is an INT, which isn't a subrange type [1..10]
+ // (etc.).
+ else if (func.getType().isInteger() && !val.getType().isInteger())
+ {
+ Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE NOT "
+ "CORRECT TYPE ***"
+ << std::endl;
+ InternalError()
+ << "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH "
+ "MODEL:"
+ << std::endl
+ << "model value for " << func << std::endl
+ << " is " << val << std::endl
+ << "value type is " << val.getType() << std::endl
+ << "should be of type " << func.getType() << std::endl
+ << "Run with `--check-models -v' for additional diagnostics.";
+ }
+
+ // (4) checks complete, add the substitution
+ Trace("check-model") << "Substitution: " << func << " :=> " << val
+ << std::endl;
+ substitutions.addSubstitution(func, val);
+ }
+
+ Trace("check-model") << "checkModel: Check assertions..." << std::endl;
+ std::unordered_map<Node, Node, NodeHashFunction> cache;
+ // Now go through all our user assertions checking if they're satisfied.
+ for (const Node& assertion : *al)
+ {
+ Notice() << "SmtEngine::checkModel(): checking assertion " << assertion
+ << std::endl;
+ Node n = assertion;
+ Notice() << "SmtEngine::checkModel(): -- rewritten form is " << Rewriter::rewrite(n) << std::endl;
+ Node nr = Rewriter::rewrite(substitutions.apply(n));
+ if (nr.isConst() && nr.getConst<bool>())
+ {
+ continue;
+ }
+ // Apply any define-funs from the problem.
+ n = pp->expandDefinitions(n, cache);
+ Notice() << "SmtEngine::checkModel(): -- expands to " << n << std::endl;
+
+ // Apply our model value substitutions.
+ n = substitutions.apply(n);
+ Notice() << "SmtEngine::checkModel(): -- substitutes to " << n << std::endl;
+
+ // We look up the value before simplifying. If n contains quantifiers,
+ // this may increases the chance of finding its value before the node is
+ // altered by simplification below.
+ n = m->getValue(n);
+ Notice() << "SmtEngine::checkModel(): -- get value : " << n << std::endl;
+
+ // Simplify the result and replace the already-known ITEs (this is important
+ // for ground ITEs under quantifiers).
+ n = pp->simplify(n, true);
+ Notice()
+ << "SmtEngine::checkModel(): -- simplifies with ite replacement to "
+ << n << std::endl;
+
+ // Apply our model value substitutions (again), as things may have been
+ // simplified.
+ n = substitutions.apply(n);
+ Notice() << "SmtEngine::checkModel(): -- re-substitutes to " << n
+ << std::endl;
+
+ // As a last-ditch effort, ask model to simplify it.
+ // Presently, this is only an issue for quantifiers, which can have a value
+ // but don't show up in our substitution map above.
+ n = m->getValue(n);
+ Notice() << "SmtEngine::checkModel(): -- model-substitutes to " << n
+ << std::endl;
+
+ if (n.isConst() && n.getConst<bool>())
+ {
+ // assertion is true, everything is fine
+ continue;
+ }
+
+ // Otherwise, we did not succeed in showing the current assertion to be
+ // true. This may either indicate that our model is wrong, or that we cannot
+ // check it. The latter may be the case for several reasons.
+ // For example, quantified formulas are not checkable, although we assign
+ // them to true/false based on the satisfying assignment. However,
+ // quantified formulas can be modified during preprocess, so they may not
+ // correspond to those in the satisfying assignment. Hence we throw
+ // warnings for assertions that do not simplify to either true or false.
+ // Other theories such as non-linear arithmetic (in particular,
+ // transcendental functions) also have the property of not being able to
+ // be checked precisely here.
+ // Note that warnings like these can be avoided for quantified formulas
+ // by making preprocessing passes explicitly record how they
+ // rewrite quantified formulas (see cvc4-wishues#43).
+ if (!n.isConst())
+ {
+ // Not constant, print a less severe warning message here.
+ Warning() << "Warning : SmtEngine::checkModel(): cannot check simplified "
+ "assertion : "
+ << n << std::endl;
+ continue;
+ }
+ // Assertions that simplify to false result in an InternalError or
+ // Warning being thrown below (when hardFailure is false).
+ Notice() << "SmtEngine::checkModel(): *** PROBLEM: EXPECTED `TRUE' ***"
+ << std::endl;
+ std::stringstream ss;
+ ss << "SmtEngine::checkModel(): "
+ << "ERRORS SATISFYING ASSERTIONS WITH MODEL:" << std::endl
+ << "assertion: " << assertion << std::endl
+ << "simplifies to: " << n << std::endl
+ << "expected `true'." << std::endl
+ << "Run with `--check-models -v' for additional diagnostics.";
+ if (hardFailure)
+ {
+ // internal error if hardFailure is true
+ InternalError() << ss.str();
+ }
+ else
+ {
+ Warning() << ss.str() << std::endl;
+ }
+ }
+ Trace("check-model") << "checkModel: Finish" << std::endl;
+ Notice() << "SmtEngine::checkModel(): all assertions checked out OK !"
+ << std::endl;
+}
+
+} // namespace smt
+} // namespace CVC4
diff --git a/src/smt/check_models.h b/src/smt/check_models.h
new file mode 100644
index 000000000..14af41b27
--- /dev/null
+++ b/src/smt/check_models.h
@@ -0,0 +1,52 @@
+/********************* */
+/*! \file check_models.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utility for checking models
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__SMT__CHECK_MODELS_H
+#define CVC4__SMT__CHECK_MODELS_H
+
+#include "context/cdlist.h"
+#include "expr/node.h"
+#include "smt/model.h"
+#include "smt/smt_solver.h"
+
+namespace CVC4 {
+namespace smt {
+
+/**
+ * This utility is responsible for checking the current model.
+ */
+class CheckModels
+{
+ public:
+ CheckModels(SmtSolver& s);
+ ~CheckModels();
+ /**
+ * Check model m against the current set of input assertions al.
+ *
+ * This throws an exception if we fail to verify that m is a proper model
+ * given assertion list al based on the model checking policy.
+ */
+ void checkModel(Model* m, context::CDList<Node>* al, bool hardFailure);
+
+ private:
+ /** Reference to the SMT solver */
+ SmtSolver& d_smt;
+};
+
+} // namespace smt
+} // namespace CVC4
+
+#endif
diff --git a/src/smt/command.cpp b/src/smt/command.cpp
index 2e36190b4..717d423fe 100644
--- a/src/smt/command.cpp
+++ b/src/smt/command.cpp
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -28,10 +28,12 @@
#include "base/output.h"
#include "expr/expr_iomanip.h"
#include "expr/node.h"
+#include "expr/symbol_manager.h"
#include "expr/type.h"
#include "options/options.h"
#include "options/smt_options.h"
#include "printer/printer.h"
+#include "proof/unsat_core.h"
#include "smt/dump.h"
#include "smt/model.h"
#include "smt/smt_engine.h"
@@ -52,7 +54,6 @@ std::ostream& operator<<(std::ostream& out, const Command& c)
{
c.toStream(out,
Node::setdepth::getDepth(out),
- Node::printtypes::getPrintTypes(out),
Node::dag::getDag(out),
Node::setlanguage::getLanguage(out));
return out;
@@ -90,7 +91,6 @@ ostream& operator<<(ostream& out, const CommandStatus* s)
return out;
}
-
/* output stream insertion operator for benchmark statuses */
std::ostream& operator<<(std::ostream& out, BenchmarkStatus status)
{
@@ -137,8 +137,8 @@ std::ostream& operator<<(std::ostream& out, CommandPrintSuccess cps)
Command::Command() : d_commandStatus(nullptr), d_muted(false) {}
-Command::Command(api::Solver* solver)
- : d_solver(solver), d_commandStatus(nullptr), d_muted(false)
+Command::Command(const api::Solver* solver)
+ : d_commandStatus(nullptr), d_muted(false)
{
}
@@ -176,15 +176,14 @@ bool Command::interrupted() const
&& dynamic_cast<const CommandInterrupted*>(d_commandStatus) != NULL;
}
-void Command::invoke(SmtEngine* smtEngine, std::ostream& out)
+void Command::invoke(api::Solver* solver, SymbolManager* sm, std::ostream& out)
{
- invoke(smtEngine);
+ invoke(solver, sm);
if (!(isMuted() && ok()))
{
- printResult(out,
- smtEngine->getOption("command-verbosity:" + getCommandName())
- .getIntegerValue()
- .toUnsignedInt());
+ printResult(
+ out,
+ std::stoul(solver->getOption("command-verbosity:" + getCommandName())));
}
}
@@ -195,15 +194,6 @@ std::string Command::toString() const
return ss.str();
}
-void Command::toStream(std::ostream& out,
- int toDepth,
- bool types,
- size_t dag,
- OutputLanguage language) const
-{
- Printer::getPrinter(language)->toStream(out, this, toDepth, types, dag);
-}
-
void CommandStatus::toStream(std::ostream& out, OutputLanguage language) const
{
Printer::getPrinter(language)->toStream(out, this);
@@ -226,69 +216,74 @@ void Command::printResult(std::ostream& out, uint32_t verbosity) const
EmptyCommand::EmptyCommand(std::string name) : d_name(name) {}
std::string EmptyCommand::getName() const { return d_name; }
-void EmptyCommand::invoke(SmtEngine* smtEngine)
+void EmptyCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
/* empty commands have no implementation */
d_commandStatus = CommandSuccess::instance();
}
-Command* EmptyCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- return new EmptyCommand(d_name);
-}
-
Command* EmptyCommand::clone() const { return new EmptyCommand(d_name); }
std::string EmptyCommand::getCommandName() const { return "empty"; }
+void EmptyCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdEmpty(out, d_name);
+}
+
/* -------------------------------------------------------------------------- */
/* class EchoCommand */
/* -------------------------------------------------------------------------- */
EchoCommand::EchoCommand(std::string output) : d_output(output) {}
std::string EchoCommand::getOutput() const { return d_output; }
-void EchoCommand::invoke(SmtEngine* smtEngine)
+void EchoCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
/* we don't have an output stream here, nothing to do */
d_commandStatus = CommandSuccess::instance();
}
-void EchoCommand::invoke(SmtEngine* smtEngine, std::ostream& out)
+void EchoCommand::invoke(api::Solver* solver,
+ SymbolManager* sm,
+ std::ostream& out)
{
out << d_output << std::endl;
Trace("dtview::command") << "* ~COMMAND: echo |" << d_output << "|~"
<< std::endl;
d_commandStatus = CommandSuccess::instance();
- printResult(out,
- smtEngine->getOption("command-verbosity:" + getCommandName())
- .getIntegerValue()
- .toUnsignedInt());
-}
-
-Command* EchoCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- return new EchoCommand(d_output);
+ printResult(
+ out,
+ std::stoul(solver->getOption("command-verbosity:" + getCommandName())));
}
Command* EchoCommand::clone() const { return new EchoCommand(d_output); }
std::string EchoCommand::getCommandName() const { return "echo"; }
+void EchoCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdEcho(out, d_output);
+}
+
/* -------------------------------------------------------------------------- */
/* class AssertCommand */
/* -------------------------------------------------------------------------- */
-AssertCommand::AssertCommand(const Expr& e, bool inUnsatCore)
- : d_expr(e), d_inUnsatCore(inUnsatCore)
+AssertCommand::AssertCommand(const api::Term& t, bool inUnsatCore)
+ : d_term(t), d_inUnsatCore(inUnsatCore)
{
}
-Expr AssertCommand::getExpr() const { return d_expr; }
-void AssertCommand::invoke(SmtEngine* smtEngine)
+api::Term AssertCommand::getTerm() const { return d_term; }
+void AssertCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- smtEngine->assertFormula(d_expr, d_inUnsatCore);
+ solver->getSmtEngine()->assertFormula(d_term.getNode(), d_inUnsatCore);
d_commandStatus = CommandSuccess::instance();
}
catch (UnsafeInterruptException& e)
@@ -301,29 +296,30 @@ void AssertCommand::invoke(SmtEngine* smtEngine)
}
}
-Command* AssertCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- return new AssertCommand(d_expr.exportTo(exprManager, variableMap),
- d_inUnsatCore);
-}
-
Command* AssertCommand::clone() const
{
- return new AssertCommand(d_expr, d_inUnsatCore);
+ return new AssertCommand(d_term, d_inUnsatCore);
}
std::string AssertCommand::getCommandName() const { return "assert"; }
+void AssertCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdAssert(out, d_term.getNode());
+}
+
/* -------------------------------------------------------------------------- */
/* class PushCommand */
/* -------------------------------------------------------------------------- */
-void PushCommand::invoke(SmtEngine* smtEngine)
+void PushCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- smtEngine->push();
+ solver->push();
d_commandStatus = CommandSuccess::instance();
}
catch (UnsafeInterruptException& e)
@@ -336,24 +332,26 @@ void PushCommand::invoke(SmtEngine* smtEngine)
}
}
-Command* PushCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- return new PushCommand();
-}
-
Command* PushCommand::clone() const { return new PushCommand(); }
std::string PushCommand::getCommandName() const { return "push"; }
+void PushCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdPush(out);
+}
+
/* -------------------------------------------------------------------------- */
/* class PopCommand */
/* -------------------------------------------------------------------------- */
-void PopCommand::invoke(SmtEngine* smtEngine)
+void PopCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- smtEngine->pop();
+ solver->pop();
d_commandStatus = CommandSuccess::instance();
}
catch (UnsafeInterruptException& e)
@@ -366,31 +364,35 @@ void PopCommand::invoke(SmtEngine* smtEngine)
}
}
-Command* PopCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- return new PopCommand();
-}
-
Command* PopCommand::clone() const { return new PopCommand(); }
std::string PopCommand::getCommandName() const { return "pop"; }
+void PopCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdPop(out);
+}
+
/* -------------------------------------------------------------------------- */
/* class CheckSatCommand */
/* -------------------------------------------------------------------------- */
-CheckSatCommand::CheckSatCommand() : d_expr() {}
+CheckSatCommand::CheckSatCommand() : d_term() {}
-CheckSatCommand::CheckSatCommand(const Expr& expr) : d_expr(expr) {}
+CheckSatCommand::CheckSatCommand(const api::Term& term) : d_term(term) {}
-Expr CheckSatCommand::getExpr() const { return d_expr; }
-void CheckSatCommand::invoke(SmtEngine* smtEngine)
+api::Term CheckSatCommand::getTerm() const { return d_term; }
+void CheckSatCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
Trace("dtview::command") << "* ~COMMAND: " << getCommandName() << "~"
<< std::endl;
try
{
- d_result = smtEngine->checkSat(d_expr);
+ d_result =
+ d_term.isNull() ? solver->checkSat() : solver->checkSatAssuming(d_term);
+
d_commandStatus = CommandSuccess::instance();
}
catch (exception& e)
@@ -399,7 +401,7 @@ void CheckSatCommand::invoke(SmtEngine* smtEngine)
}
}
-Result CheckSatCommand::getResult() const { return d_result; }
+api::Result CheckSatCommand::getResult() const { return d_result; }
void CheckSatCommand::printResult(std::ostream& out, uint32_t verbosity) const
{
if (!ok())
@@ -413,47 +415,50 @@ void CheckSatCommand::printResult(std::ostream& out, uint32_t verbosity) const
}
}
-Command* CheckSatCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- CheckSatCommand* c =
- new CheckSatCommand(d_expr.exportTo(exprManager, variableMap));
- c->d_result = d_result;
- return c;
-}
-
Command* CheckSatCommand::clone() const
{
- CheckSatCommand* c = new CheckSatCommand(d_expr);
+ CheckSatCommand* c = new CheckSatCommand(d_term);
c->d_result = d_result;
return c;
}
std::string CheckSatCommand::getCommandName() const { return "check-sat"; }
+void CheckSatCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdCheckSat(out, d_term.getNode());
+}
+
/* -------------------------------------------------------------------------- */
/* class CheckSatAssumingCommand */
/* -------------------------------------------------------------------------- */
-CheckSatAssumingCommand::CheckSatAssumingCommand(Expr term) : d_terms({term}) {}
+CheckSatAssumingCommand::CheckSatAssumingCommand(api::Term term)
+ : d_terms({term})
+{
+}
-CheckSatAssumingCommand::CheckSatAssumingCommand(const std::vector<Expr>& terms)
+CheckSatAssumingCommand::CheckSatAssumingCommand(
+ const std::vector<api::Term>& terms)
: d_terms(terms)
{
}
-const std::vector<Expr>& CheckSatAssumingCommand::getTerms() const
+const std::vector<api::Term>& CheckSatAssumingCommand::getTerms() const
{
return d_terms;
}
-void CheckSatAssumingCommand::invoke(SmtEngine* smtEngine)
+void CheckSatAssumingCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
Trace("dtview::command") << "* ~COMMAND: (check-sat-assuming ( " << d_terms
<< " )~" << std::endl;
try
{
- d_result = smtEngine->checkSat(d_terms);
+ d_result = solver->checkSatAssuming(d_terms);
d_commandStatus = CommandSuccess::instance();
}
catch (exception& e)
@@ -462,7 +467,7 @@ void CheckSatAssumingCommand::invoke(SmtEngine* smtEngine)
}
}
-Result CheckSatAssumingCommand::getResult() const
+api::Result CheckSatAssumingCommand::getResult() const
{
Trace("dtview::command") << "* ~RESULT: " << d_result << "~" << std::endl;
return d_result;
@@ -481,19 +486,6 @@ void CheckSatAssumingCommand::printResult(std::ostream& out,
}
}
-Command* CheckSatAssumingCommand::exportTo(
- ExprManager* exprManager, ExprManagerMapCollection& variableMap)
-{
- vector<Expr> exportedTerms;
- for (const Expr& e : d_terms)
- {
- exportedTerms.push_back(e.exportTo(exprManager, variableMap));
- }
- CheckSatAssumingCommand* c = new CheckSatAssumingCommand(exportedTerms);
- c->d_result = d_result;
- return c;
-}
-
Command* CheckSatAssumingCommand::clone() const
{
CheckSatAssumingCommand* c = new CheckSatAssumingCommand(d_terms);
@@ -506,21 +498,30 @@ std::string CheckSatAssumingCommand::getCommandName() const
return "check-sat-assuming";
}
+void CheckSatAssumingCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdCheckSatAssuming(
+ out, api::termVectorToNodes(d_terms));
+}
+
/* -------------------------------------------------------------------------- */
/* class QueryCommand */
/* -------------------------------------------------------------------------- */
-QueryCommand::QueryCommand(const Expr& e, bool inUnsatCore)
- : d_expr(e), d_inUnsatCore(inUnsatCore)
+QueryCommand::QueryCommand(const api::Term& t, bool inUnsatCore)
+ : d_term(t), d_inUnsatCore(inUnsatCore)
{
}
-Expr QueryCommand::getExpr() const { return d_expr; }
-void QueryCommand::invoke(SmtEngine* smtEngine)
+api::Term QueryCommand::getTerm() const { return d_term; }
+void QueryCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- d_result = smtEngine->checkEntailed(d_expr);
+ d_result = solver->checkEntailed(d_term);
d_commandStatus = CommandSuccess::instance();
}
catch (exception& e)
@@ -529,7 +530,7 @@ void QueryCommand::invoke(SmtEngine* smtEngine)
}
}
-Result QueryCommand::getResult() const { return d_result; }
+api::Result QueryCommand::getResult() const { return d_result; }
void QueryCommand::printResult(std::ostream& out, uint32_t verbosity) const
{
if (!ok())
@@ -542,62 +543,45 @@ void QueryCommand::printResult(std::ostream& out, uint32_t verbosity) const
}
}
-Command* QueryCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- QueryCommand* c = new QueryCommand(d_expr.exportTo(exprManager, variableMap),
- d_inUnsatCore);
- c->d_result = d_result;
- return c;
-}
-
Command* QueryCommand::clone() const
{
- QueryCommand* c = new QueryCommand(d_expr, d_inUnsatCore);
+ QueryCommand* c = new QueryCommand(d_term, d_inUnsatCore);
c->d_result = d_result;
return c;
}
std::string QueryCommand::getCommandName() const { return "query"; }
+void QueryCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdQuery(out, d_term.getNode());
+}
+
/* -------------------------------------------------------------------------- */
/* class DeclareSygusVarCommand */
/* -------------------------------------------------------------------------- */
DeclareSygusVarCommand::DeclareSygusVarCommand(const std::string& id,
- Expr var,
- Type t)
- : DeclarationDefinitionCommand(id), d_var(var), d_type(t)
+ api::Term var,
+ api::Sort sort)
+ : DeclarationDefinitionCommand(id), d_var(var), d_sort(sort)
{
}
-Expr DeclareSygusVarCommand::getVar() const { return d_var; }
-Type DeclareSygusVarCommand::getType() const { return d_type; }
-
-void DeclareSygusVarCommand::invoke(SmtEngine* smtEngine)
-{
- try
- {
- smtEngine->declareSygusVar(d_symbol, d_var, d_type);
- d_commandStatus = CommandSuccess::instance();
- }
- catch (exception& e)
- {
- d_commandStatus = new CommandFailure(e.what());
- }
-}
+api::Term DeclareSygusVarCommand::getVar() const { return d_var; }
+api::Sort DeclareSygusVarCommand::getSort() const { return d_sort; }
-Command* DeclareSygusVarCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
+void DeclareSygusVarCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
- return new DeclareSygusVarCommand(d_symbol,
- d_var.exportTo(exprManager, variableMap),
- d_type.exportTo(exprManager, variableMap));
+ d_commandStatus = CommandSuccess::instance();
}
Command* DeclareSygusVarCommand::clone() const
{
- return new DeclareSygusVarCommand(d_symbol, d_var, d_type);
+ return new DeclareSygusVarCommand(d_symbol, d_var, d_sort);
}
std::string DeclareSygusVarCommand::getCommandName() const
@@ -605,107 +589,55 @@ std::string DeclareSygusVarCommand::getCommandName() const
return "declare-var";
}
-/* -------------------------------------------------------------------------- */
-/* class DeclareSygusFunctionCommand */
-/* -------------------------------------------------------------------------- */
-
-DeclareSygusFunctionCommand::DeclareSygusFunctionCommand(const std::string& id,
- Expr func,
- Type t)
- : DeclarationDefinitionCommand(id), d_func(func), d_type(t)
+void DeclareSygusVarCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
{
-}
-
-Expr DeclareSygusFunctionCommand::getFunction() const { return d_func; }
-Type DeclareSygusFunctionCommand::getType() const { return d_type; }
-
-void DeclareSygusFunctionCommand::invoke(SmtEngine* smtEngine)
-{
- try
- {
- smtEngine->declareSygusFunctionVar(d_symbol, d_func, d_type);
- d_commandStatus = CommandSuccess::instance();
- }
- catch (exception& e)
- {
- d_commandStatus = new CommandFailure(e.what());
- }
-}
-
-Command* DeclareSygusFunctionCommand::exportTo(
- ExprManager* exprManager, ExprManagerMapCollection& variableMap)
-{
- return new DeclareSygusFunctionCommand(
- d_symbol,
- d_func.exportTo(exprManager, variableMap),
- d_type.exportTo(exprManager, variableMap));
-}
-
-Command* DeclareSygusFunctionCommand::clone() const
-{
- return new DeclareSygusFunctionCommand(d_symbol, d_func, d_type);
-}
-
-std::string DeclareSygusFunctionCommand::getCommandName() const
-{
- return "declare-fun";
+ Printer::getPrinter(language)->toStreamCmdDeclareVar(
+ out, d_var.getNode(), d_sort.getTypeNode());
}
/* -------------------------------------------------------------------------- */
-/* class SynthFunCommand */
+/* class SynthFunCommand */
/* -------------------------------------------------------------------------- */
SynthFunCommand::SynthFunCommand(const std::string& id,
- Expr func,
- Type sygusType,
+ api::Term fun,
+ const std::vector<api::Term>& vars,
+ api::Sort sort,
bool isInv,
- const std::vector<Expr>& vars)
+ api::Grammar* g)
: DeclarationDefinitionCommand(id),
- d_func(func),
- d_sygusType(sygusType),
+ d_fun(fun),
+ d_vars(vars),
+ d_sort(sort),
d_isInv(isInv),
- d_vars(vars)
+ d_grammar(g)
{
}
-SynthFunCommand::SynthFunCommand(const std::string& id,
- Expr func,
- Type sygusType,
- bool isInv)
- : SynthFunCommand(id, func, sygusType, isInv, {})
+api::Term SynthFunCommand::getFunction() const { return d_fun; }
+
+const std::vector<api::Term>& SynthFunCommand::getVars() const
{
+ return d_vars;
}
-Expr SynthFunCommand::getFunction() const { return d_func; }
-const std::vector<Expr>& SynthFunCommand::getVars() const { return d_vars; }
-Type SynthFunCommand::getSygusType() const { return d_sygusType; }
+api::Sort SynthFunCommand::getSort() const { return d_sort; }
bool SynthFunCommand::isInv() const { return d_isInv; }
-void SynthFunCommand::invoke(SmtEngine* smtEngine)
-{
- try
- {
- smtEngine->declareSynthFun(d_symbol, d_func, d_sygusType, d_isInv, d_vars);
- d_commandStatus = CommandSuccess::instance();
- }
- catch (exception& e)
- {
- d_commandStatus = new CommandFailure(e.what());
- }
-}
+const api::Grammar* SynthFunCommand::getGrammar() const { return d_grammar; }
-Command* SynthFunCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
+void SynthFunCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
- return new SynthFunCommand(d_symbol,
- d_func.exportTo(exprManager, variableMap),
- d_sygusType.exportTo(exprManager, variableMap),
- d_isInv);
+ d_commandStatus = CommandSuccess::instance();
}
Command* SynthFunCommand::clone() const
{
- return new SynthFunCommand(d_symbol, d_func, d_sygusType, d_isInv, d_vars);
+ return new SynthFunCommand(
+ d_symbol, d_fun, d_vars, d_sort, d_isInv, d_grammar);
}
std::string SynthFunCommand::getCommandName() const
@@ -713,17 +645,34 @@ std::string SynthFunCommand::getCommandName() const
return d_isInv ? "synth-inv" : "synth-fun";
}
+void SynthFunCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ std::vector<Node> nodeVars = termVectorToNodes(d_vars);
+ Printer::getPrinter(language)->toStreamCmdSynthFun(
+ out,
+ d_symbol,
+ nodeVars,
+ d_sort.getTypeNode(),
+ d_isInv,
+ d_grammar->resolve().getTypeNode());
+}
+
/* -------------------------------------------------------------------------- */
/* class SygusConstraintCommand */
/* -------------------------------------------------------------------------- */
-SygusConstraintCommand::SygusConstraintCommand(const Expr& e) : d_expr(e) {}
+SygusConstraintCommand::SygusConstraintCommand(const api::Term& t) : d_term(t)
+{
+}
-void SygusConstraintCommand::invoke(SmtEngine* smtEngine)
+void SygusConstraintCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- smtEngine->assertSygusConstraint(d_expr);
+ solver->addSygusConstraint(d_term);
d_commandStatus = CommandSuccess::instance();
}
catch (exception& e)
@@ -732,17 +681,11 @@ void SygusConstraintCommand::invoke(SmtEngine* smtEngine)
}
}
-Expr SygusConstraintCommand::getExpr() const { return d_expr; }
-
-Command* SygusConstraintCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- return new SygusConstraintCommand(d_expr.exportTo(exprManager, variableMap));
-}
+api::Term SygusConstraintCommand::getTerm() const { return d_term; }
Command* SygusConstraintCommand::clone() const
{
- return new SygusConstraintCommand(d_expr);
+ return new SygusConstraintCommand(d_term);
}
std::string SygusConstraintCommand::getCommandName() const
@@ -750,29 +693,37 @@ std::string SygusConstraintCommand::getCommandName() const
return "constraint";
}
+void SygusConstraintCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdConstraint(out, d_term.getNode());
+}
+
/* -------------------------------------------------------------------------- */
/* class SygusInvConstraintCommand */
/* -------------------------------------------------------------------------- */
SygusInvConstraintCommand::SygusInvConstraintCommand(
- const std::vector<Expr>& predicates)
+ const std::vector<api::Term>& predicates)
: d_predicates(predicates)
{
}
-SygusInvConstraintCommand::SygusInvConstraintCommand(const Expr& inv,
- const Expr& pre,
- const Expr& trans,
- const Expr& post)
- : SygusInvConstraintCommand(std::vector<Expr>{inv, pre, trans, post})
+SygusInvConstraintCommand::SygusInvConstraintCommand(const api::Term& inv,
+ const api::Term& pre,
+ const api::Term& trans,
+ const api::Term& post)
+ : SygusInvConstraintCommand(std::vector<api::Term>{inv, pre, trans, post})
{
}
-void SygusInvConstraintCommand::invoke(SmtEngine* smtEngine)
+void SygusInvConstraintCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- smtEngine->assertSygusInvConstraint(
+ solver->addSygusInvConstraint(
d_predicates[0], d_predicates[1], d_predicates[2], d_predicates[3]);
d_commandStatus = CommandSuccess::instance();
}
@@ -782,17 +733,11 @@ void SygusInvConstraintCommand::invoke(SmtEngine* smtEngine)
}
}
-const std::vector<Expr>& SygusInvConstraintCommand::getPredicates() const
+const std::vector<api::Term>& SygusInvConstraintCommand::getPredicates() const
{
return d_predicates;
}
-Command* SygusInvConstraintCommand::exportTo(
- ExprManager* exprManager, ExprManagerMapCollection& variableMap)
-{
- return new SygusInvConstraintCommand(d_predicates);
-}
-
Command* SygusInvConstraintCommand::clone() const
{
return new SygusInvConstraintCommand(d_predicates);
@@ -803,20 +748,32 @@ std::string SygusInvConstraintCommand::getCommandName() const
return "inv-constraint";
}
+void SygusInvConstraintCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdInvConstraint(
+ out,
+ d_predicates[0].getNode(),
+ d_predicates[1].getNode(),
+ d_predicates[2].getNode(),
+ d_predicates[3].getNode());
+}
+
/* -------------------------------------------------------------------------- */
/* class CheckSynthCommand */
/* -------------------------------------------------------------------------- */
-void CheckSynthCommand::invoke(SmtEngine* smtEngine)
+void CheckSynthCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- d_result = smtEngine->checkSynth();
+ d_result = solver->checkSynth();
d_commandStatus = CommandSuccess::instance();
- smt::SmtScope scope(smtEngine);
d_solution.clear();
// check whether we should print the status
- if (d_result.asSatisfiabilityResult() != Result::UNSAT
+ if (!d_result.isUnsat()
|| options::sygusOut() == options::SygusSolutionOutMode::STATUS_AND_DEF
|| options::sygusOut() == options::SygusSolutionOutMode::STATUS)
{
@@ -830,7 +787,7 @@ void CheckSynthCommand::invoke(SmtEngine* smtEngine)
}
}
// check whether we should print the solution
- if (d_result.asSatisfiabilityResult() == Result::UNSAT
+ if (d_result.isUnsat()
&& options::sygusOut() != options::SygusSolutionOutMode::STATUS)
{
// printing a synthesis solution is a non-constant
@@ -838,7 +795,7 @@ void CheckSynthCommand::invoke(SmtEngine* smtEngine)
// (Figure 5 of Reynolds et al. CAV 2015).
// Hence, we must call here print solution here,
// instead of during printResult.
- smtEngine->printSynthSolution(d_solution);
+ solver->printSynthSolution(d_solution);
}
}
catch (exception& e)
@@ -847,7 +804,7 @@ void CheckSynthCommand::invoke(SmtEngine* smtEngine)
}
}
-Result CheckSynthCommand::getResult() const { return d_result; }
+api::Result CheckSynthCommand::getResult() const { return d_result; }
void CheckSynthCommand::printResult(std::ostream& out, uint32_t verbosity) const
{
if (!ok())
@@ -860,25 +817,27 @@ void CheckSynthCommand::printResult(std::ostream& out, uint32_t verbosity) const
}
}
-Command* CheckSynthCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- return new CheckSynthCommand();
-}
-
Command* CheckSynthCommand::clone() const { return new CheckSynthCommand(); }
std::string CheckSynthCommand::getCommandName() const { return "check-synth"; }
+void CheckSynthCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdCheckSynth(out);
+}
+
/* -------------------------------------------------------------------------- */
/* class ResetCommand */
/* -------------------------------------------------------------------------- */
-void ResetCommand::invoke(SmtEngine* smtEngine)
+void ResetCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- smtEngine->reset();
+ solver->getSmtEngine()->reset();
d_commandStatus = CommandSuccess::instance();
}
catch (exception& e)
@@ -887,24 +846,26 @@ void ResetCommand::invoke(SmtEngine* smtEngine)
}
}
-Command* ResetCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- return new ResetCommand();
-}
-
Command* ResetCommand::clone() const { return new ResetCommand(); }
std::string ResetCommand::getCommandName() const { return "reset"; }
+void ResetCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdReset(out);
+}
+
/* -------------------------------------------------------------------------- */
/* class ResetAssertionsCommand */
/* -------------------------------------------------------------------------- */
-void ResetAssertionsCommand::invoke(SmtEngine* smtEngine)
+void ResetAssertionsCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- smtEngine->resetAssertions();
+ solver->resetAssertions();
d_commandStatus = CommandSuccess::instance();
}
catch (exception& e)
@@ -913,12 +874,6 @@ void ResetAssertionsCommand::invoke(SmtEngine* smtEngine)
}
}
-Command* ResetAssertionsCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- return new ResetAssertionsCommand();
-}
-
Command* ResetAssertionsCommand::clone() const
{
return new ResetAssertionsCommand();
@@ -929,46 +884,58 @@ std::string ResetAssertionsCommand::getCommandName() const
return "reset-assertions";
}
+void ResetAssertionsCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdResetAssertions(out);
+}
+
/* -------------------------------------------------------------------------- */
/* class QuitCommand */
/* -------------------------------------------------------------------------- */
-void QuitCommand::invoke(SmtEngine* smtEngine)
+void QuitCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
Dump("benchmark") << *this;
d_commandStatus = CommandSuccess::instance();
}
-Command* QuitCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- return new QuitCommand();
-}
-
Command* QuitCommand::clone() const { return new QuitCommand(); }
std::string QuitCommand::getCommandName() const { return "exit"; }
+void QuitCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdQuit(out);
+}
+
/* -------------------------------------------------------------------------- */
/* class CommentCommand */
/* -------------------------------------------------------------------------- */
CommentCommand::CommentCommand(std::string comment) : d_comment(comment) {}
std::string CommentCommand::getComment() const { return d_comment; }
-void CommentCommand::invoke(SmtEngine* smtEngine)
+void CommentCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
Dump("benchmark") << *this;
d_commandStatus = CommandSuccess::instance();
}
-Command* CommentCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- return new CommentCommand(d_comment);
-}
-
Command* CommentCommand::clone() const { return new CommentCommand(d_comment); }
std::string CommentCommand::getCommandName() const { return "comment"; }
+void CommentCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdComment(out, d_comment);
+}
+
/* -------------------------------------------------------------------------- */
/* class CommandSequence */
/* -------------------------------------------------------------------------- */
@@ -988,11 +955,11 @@ void CommandSequence::addCommand(Command* cmd)
}
void CommandSequence::clear() { d_commandSequence.clear(); }
-void CommandSequence::invoke(SmtEngine* smtEngine)
+void CommandSequence::invoke(api::Solver* solver, SymbolManager* sm)
{
for (; d_index < d_commandSequence.size(); ++d_index)
{
- d_commandSequence[d_index]->invoke(smtEngine);
+ d_commandSequence[d_index]->invoke(solver, sm);
if (!d_commandSequence[d_index]->ok())
{
// abort execution
@@ -1006,11 +973,13 @@ void CommandSequence::invoke(SmtEngine* smtEngine)
d_commandStatus = CommandSuccess::instance();
}
-void CommandSequence::invoke(SmtEngine* smtEngine, std::ostream& out)
+void CommandSequence::invoke(api::Solver* solver,
+ SymbolManager* sm,
+ std::ostream& out)
{
for (; d_index < d_commandSequence.size(); ++d_index)
{
- d_commandSequence[d_index]->invoke(smtEngine, out);
+ d_commandSequence[d_index]->invoke(solver, sm, out);
if (!d_commandSequence[d_index]->ok())
{
// abort execution
@@ -1024,21 +993,6 @@ void CommandSequence::invoke(SmtEngine* smtEngine, std::ostream& out)
d_commandStatus = CommandSuccess::instance();
}
-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 converted: " << seq << endl;
- }
- seq->d_index = d_index;
- return seq;
-}
-
Command* CommandSequence::clone() const
{
CommandSequence* seq = new CommandSequence();
@@ -1072,6 +1026,28 @@ CommandSequence::iterator CommandSequence::end()
std::string CommandSequence::getCommandName() const { return "sequence"; }
+void CommandSequence::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdCommandSequence(out,
+ d_commandSequence);
+}
+
+/* -------------------------------------------------------------------------- */
+/* class DeclarationSequence */
+/* -------------------------------------------------------------------------- */
+
+void DeclarationSequence::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdDeclarationSequence(
+ out, d_commandSequence);
+}
+
/* -------------------------------------------------------------------------- */
/* class DeclarationDefinitionCommand */
/* -------------------------------------------------------------------------- */
@@ -1089,18 +1065,18 @@ std::string DeclarationDefinitionCommand::getSymbol() const { return d_symbol; }
/* -------------------------------------------------------------------------- */
DeclareFunctionCommand::DeclareFunctionCommand(const std::string& id,
- Expr func,
- Type t)
+ api::Term func,
+ api::Sort sort)
: DeclarationDefinitionCommand(id),
d_func(func),
- d_type(t),
+ d_sort(sort),
d_printInModel(true),
d_printInModelSetByUser(false)
{
}
-Expr DeclareFunctionCommand::getFunction() const { return d_func; }
-Type DeclareFunctionCommand::getType() const { return d_type; }
+api::Term DeclareFunctionCommand::getFunction() const { return d_func; }
+api::Sort DeclareFunctionCommand::getSort() const { return d_sort; }
bool DeclareFunctionCommand::getPrintInModel() const { return d_printInModel; }
bool DeclareFunctionCommand::getPrintInModelSetByUser() const
{
@@ -1113,27 +1089,15 @@ void DeclareFunctionCommand::setPrintInModel(bool p)
d_printInModelSetByUser = true;
}
-void DeclareFunctionCommand::invoke(SmtEngine* smtEngine)
+void DeclareFunctionCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
d_commandStatus = CommandSuccess::instance();
}
-Command* DeclareFunctionCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- DeclareFunctionCommand* dfc =
- new DeclareFunctionCommand(d_symbol,
- d_func.exportTo(exprManager, variableMap),
- d_type.exportTo(exprManager, variableMap));
- dfc->d_printInModel = d_printInModel;
- dfc->d_printInModelSetByUser = d_printInModelSetByUser;
- return dfc;
-}
-
Command* DeclareFunctionCommand::clone() const
{
DeclareFunctionCommand* dfc =
- new DeclareFunctionCommand(d_symbol, d_func, d_type);
+ new DeclareFunctionCommand(d_symbol, d_func, d_sort);
dfc->d_printInModel = d_printInModel;
dfc->d_printInModelSetByUser = d_printInModelSetByUser;
return dfc;
@@ -1144,94 +1108,105 @@ std::string DeclareFunctionCommand::getCommandName() const
return "declare-fun";
}
+void DeclareFunctionCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdDeclareFunction(
+ out, d_func.toString(), d_sort.getTypeNode());
+}
+
/* -------------------------------------------------------------------------- */
-/* class DeclareTypeCommand */
+/* class DeclareSortCommand */
/* -------------------------------------------------------------------------- */
-DeclareTypeCommand::DeclareTypeCommand(const std::string& id,
+DeclareSortCommand::DeclareSortCommand(const std::string& id,
size_t arity,
- Type t)
- : DeclarationDefinitionCommand(id), d_arity(arity), d_type(t)
+ api::Sort sort)
+ : DeclarationDefinitionCommand(id), d_arity(arity), d_sort(sort)
{
}
-size_t DeclareTypeCommand::getArity() const { return d_arity; }
-Type DeclareTypeCommand::getType() const { return d_type; }
-void DeclareTypeCommand::invoke(SmtEngine* smtEngine)
+size_t DeclareSortCommand::getArity() const { return d_arity; }
+api::Sort DeclareSortCommand::getSort() const { return d_sort; }
+void DeclareSortCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
d_commandStatus = CommandSuccess::instance();
}
-Command* DeclareTypeCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
+Command* DeclareSortCommand::clone() const
{
- return new DeclareTypeCommand(
- d_symbol, d_arity, d_type.exportTo(exprManager, variableMap));
+ return new DeclareSortCommand(d_symbol, d_arity, d_sort);
}
-Command* DeclareTypeCommand::clone() const
+std::string DeclareSortCommand::getCommandName() const
{
- return new DeclareTypeCommand(d_symbol, d_arity, d_type);
+ return "declare-sort";
}
-std::string DeclareTypeCommand::getCommandName() const
+void DeclareSortCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
{
- return "declare-sort";
+ Printer::getPrinter(language)->toStreamCmdDeclareType(
+ out, d_sort.toString(), d_arity, d_sort.getTypeNode());
}
/* -------------------------------------------------------------------------- */
-/* class DefineTypeCommand */
+/* class DefineSortCommand */
/* -------------------------------------------------------------------------- */
-DefineTypeCommand::DefineTypeCommand(const std::string& id, Type t)
- : DeclarationDefinitionCommand(id), d_params(), d_type(t)
+DefineSortCommand::DefineSortCommand(const std::string& id, api::Sort sort)
+ : DeclarationDefinitionCommand(id), d_params(), d_sort(sort)
{
}
-DefineTypeCommand::DefineTypeCommand(const std::string& id,
- const std::vector<Type>& params,
- Type t)
- : DeclarationDefinitionCommand(id), d_params(params), d_type(t)
+DefineSortCommand::DefineSortCommand(const std::string& id,
+ const std::vector<api::Sort>& params,
+ api::Sort sort)
+ : DeclarationDefinitionCommand(id), d_params(params), d_sort(sort)
{
}
-const std::vector<Type>& DefineTypeCommand::getParameters() const
+const std::vector<api::Sort>& DefineSortCommand::getParameters() const
{
return d_params;
}
-Type DefineTypeCommand::getType() const { return d_type; }
-void DefineTypeCommand::invoke(SmtEngine* smtEngine)
+api::Sort DefineSortCommand::getSort() const { return d_sort; }
+void DefineSortCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
d_commandStatus = CommandSuccess::instance();
}
-Command* DefineTypeCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
+Command* DefineSortCommand::clone() const
{
- vector<Type> params;
- transform(d_params.begin(),
- d_params.end(),
- back_inserter(params),
- ExportTransformer(exprManager, variableMap));
- Type type = d_type.exportTo(exprManager, variableMap);
- return new DefineTypeCommand(d_symbol, params, type);
+ return new DefineSortCommand(d_symbol, d_params, d_sort);
}
-Command* DefineTypeCommand::clone() const
+std::string DefineSortCommand::getCommandName() const { return "define-sort"; }
+
+void DefineSortCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
{
- return new DefineTypeCommand(d_symbol, d_params, d_type);
+ Printer::getPrinter(language)->toStreamCmdDefineType(
+ out,
+ d_symbol,
+ api::sortVectorToTypeNodes(d_params),
+ d_sort.getTypeNode());
}
-std::string DefineTypeCommand::getCommandName() const { return "define-sort"; }
-
/* -------------------------------------------------------------------------- */
/* class DefineFunctionCommand */
/* -------------------------------------------------------------------------- */
DefineFunctionCommand::DefineFunctionCommand(const std::string& id,
- Expr func,
- Expr formula,
+ api::Term func,
+ api::Term formula,
bool global)
: DeclarationDefinitionCommand(id),
d_func(func),
@@ -1241,34 +1216,34 @@ DefineFunctionCommand::DefineFunctionCommand(const std::string& id,
{
}
-DefineFunctionCommand::DefineFunctionCommand(const std::string& id,
- Expr func,
- const std::vector<Expr>& formals,
- Expr formula,
- bool global)
+DefineFunctionCommand::DefineFunctionCommand(
+ const std::string& id,
+ api::Term func,
+ const std::vector<api::Term>& formals,
+ api::Term formula,
+ bool global)
: DeclarationDefinitionCommand(id),
d_func(func),
d_formals(formals),
d_formula(formula),
d_global(global)
-
{
}
-Expr DefineFunctionCommand::getFunction() const { return d_func; }
-const std::vector<Expr>& DefineFunctionCommand::getFormals() const
+api::Term DefineFunctionCommand::getFunction() const { return d_func; }
+const std::vector<api::Term>& DefineFunctionCommand::getFormals() const
{
return d_formals;
}
-Expr DefineFunctionCommand::getFormula() const { return d_formula; }
-void DefineFunctionCommand::invoke(SmtEngine* smtEngine)
+api::Term DefineFunctionCommand::getFormula() const { return d_formula; }
+void DefineFunctionCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
if (!d_func.isNull())
{
- smtEngine->defineFunction(d_func, d_formals, d_formula, d_global);
+ solver->defineFun(d_func, d_formals, d_formula, d_global);
}
d_commandStatus = CommandSuccess::instance();
}
@@ -1278,20 +1253,6 @@ void DefineFunctionCommand::invoke(SmtEngine* smtEngine)
}
}
-Command* DefineFunctionCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& 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));
- Expr formula = d_formula.exportTo(exprManager, variableMap);
- return new DefineFunctionCommand(d_symbol, func, formals, formula, d_global);
-}
-
Command* DefineFunctionCommand::clone() const
{
return new DefineFunctionCommand(
@@ -1303,48 +1264,17 @@ std::string DefineFunctionCommand::getCommandName() const
return "define-fun";
}
-/* -------------------------------------------------------------------------- */
-/* class DefineNamedFunctionCommand */
-/* -------------------------------------------------------------------------- */
-
-DefineNamedFunctionCommand::DefineNamedFunctionCommand(
- const std::string& id,
- Expr func,
- const std::vector<Expr>& formals,
- Expr formula,
- bool global)
- : DefineFunctionCommand(id, func, formals, formula, global)
-{
-}
-
-void DefineNamedFunctionCommand::invoke(SmtEngine* smtEngine)
+void DefineFunctionCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
{
- this->DefineFunctionCommand::invoke(smtEngine);
- if (!d_func.isNull() && d_func.getType().isBoolean())
- {
- smtEngine->addToAssignment(d_func);
- }
- d_commandStatus = CommandSuccess::instance();
-}
-
-Command* DefineNamedFunctionCommand::exportTo(
- ExprManager* exprManager, ExprManagerMapCollection& variableMap)
-{
- Expr func = d_func.exportTo(exprManager, variableMap);
- vector<Expr> formals;
- transform(d_formals.begin(),
- d_formals.end(),
- back_inserter(formals),
- ExportTransformer(exprManager, variableMap));
- Expr formula = d_formula.exportTo(exprManager, variableMap);
- return new DefineNamedFunctionCommand(
- d_symbol, func, formals, formula, d_global);
-}
-
-Command* DefineNamedFunctionCommand::clone() const
-{
- return new DefineNamedFunctionCommand(
- d_symbol, d_func, d_formals, d_formula, d_global);
+ Printer::getPrinter(language)->toStreamCmdDefineFunction(
+ out,
+ d_func.toString(),
+ api::termVectorToNodes(d_formals),
+ d_func.getNode().getType().getRangeType(),
+ d_formula.getNode());
}
/* -------------------------------------------------------------------------- */
@@ -1352,12 +1282,12 @@ Command* DefineNamedFunctionCommand::clone() const
/* -------------------------------------------------------------------------- */
DefineFunctionRecCommand::DefineFunctionRecCommand(
- api::Solver* solver,
+
api::Term func,
const std::vector<api::Term>& formals,
api::Term formula,
bool global)
- : Command(solver), d_global(global)
+ : d_global(global)
{
d_funcs.push_back(func);
d_formals.push_back(formals);
@@ -1365,16 +1295,12 @@ DefineFunctionRecCommand::DefineFunctionRecCommand(
}
DefineFunctionRecCommand::DefineFunctionRecCommand(
- api::Solver* solver,
+
const std::vector<api::Term>& funcs,
const std::vector<std::vector<api::Term>>& formals,
const std::vector<api::Term>& formulas,
bool global)
- : Command(solver),
- d_funcs(funcs),
- d_formals(formals),
- d_formulas(formulas),
- d_global(global)
+ : d_funcs(funcs), d_formals(formals), d_formulas(formulas), d_global(global)
{
}
@@ -1394,11 +1320,11 @@ const std::vector<api::Term>& DefineFunctionRecCommand::getFormulas() const
return d_formulas;
}
-void DefineFunctionRecCommand::invoke(SmtEngine* smtEngine)
+void DefineFunctionRecCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- d_solver->defineFunsRec(d_funcs, d_formals, d_formulas, d_global);
+ solver->defineFunsRec(d_funcs, d_formals, d_formulas, d_global);
d_commandStatus = CommandSuccess::instance();
}
catch (exception& e)
@@ -1407,16 +1333,9 @@ void DefineFunctionRecCommand::invoke(SmtEngine* smtEngine)
}
}
-Command* DefineFunctionRecCommand::exportTo(
- ExprManager* exprManager, ExprManagerMapCollection& variableMap)
-{
- Unimplemented();
-}
-
Command* DefineFunctionRecCommand::clone() const
{
- return new DefineFunctionRecCommand(
- d_solver, d_funcs, d_formals, d_formulas, d_global);
+ return new DefineFunctionRecCommand(d_funcs, d_formals, d_formulas, d_global);
}
std::string DefineFunctionRecCommand::getCommandName() const
@@ -1424,48 +1343,104 @@ std::string DefineFunctionRecCommand::getCommandName() const
return "define-fun-rec";
}
+void DefineFunctionRecCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ std::vector<std::vector<Node>> formals;
+ formals.reserve(d_formals.size());
+ for (const std::vector<api::Term>& formal : d_formals)
+ {
+ formals.push_back(api::termVectorToNodes(formal));
+ }
+
+ Printer::getPrinter(language)->toStreamCmdDefineFunctionRec(
+ out,
+ api::termVectorToNodes(d_funcs),
+ formals,
+ api::termVectorToNodes(d_formulas));
+}
/* -------------------------------------------------------------------------- */
-/* class SetUserAttribute */
+/* class DeclareHeapCommand */
+/* -------------------------------------------------------------------------- */
+DeclareHeapCommand::DeclareHeapCommand(api::Sort locSort, api::Sort dataSort)
+ : d_locSort(locSort), d_dataSort(dataSort)
+{
+}
+
+api::Sort DeclareHeapCommand::getLocationSort() const { return d_locSort; }
+api::Sort DeclareHeapCommand::getDataSort() const { return d_dataSort; }
+
+void DeclareHeapCommand::invoke(api::Solver* solver, SymbolManager* sm)
+{
+ solver->declareSeparationHeap(d_locSort, d_dataSort);
+}
+
+Command* DeclareHeapCommand::clone() const
+{
+ return new DeclareHeapCommand(d_locSort, d_dataSort);
+}
+
+std::string DeclareHeapCommand::getCommandName() const
+{
+ return "declare-heap";
+}
+
+void DeclareHeapCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdDeclareHeap(
+ out, d_locSort.getTypeNode(), d_dataSort.getTypeNode());
+}
+
+/* -------------------------------------------------------------------------- */
+/* class SetUserAttributeCommand */
/* -------------------------------------------------------------------------- */
SetUserAttributeCommand::SetUserAttributeCommand(
const std::string& attr,
- Expr expr,
- const std::vector<Expr>& expr_values,
- const std::string& str_value)
- : d_attr(attr),
- d_expr(expr),
- d_expr_values(expr_values),
- d_str_value(str_value)
+ api::Term term,
+ const std::vector<api::Term>& termValues,
+ const std::string& strValue)
+ : d_attr(attr), d_term(term), d_termValues(termValues), d_strValue(strValue)
{
}
SetUserAttributeCommand::SetUserAttributeCommand(const std::string& attr,
- Expr expr)
- : SetUserAttributeCommand(attr, expr, {}, "")
+ api::Term term)
+ : SetUserAttributeCommand(attr, term, {}, "")
{
}
SetUserAttributeCommand::SetUserAttributeCommand(
- const std::string& attr, Expr expr, const std::vector<Expr>& values)
- : SetUserAttributeCommand(attr, expr, values, "")
+ const std::string& attr,
+ api::Term term,
+ const std::vector<api::Term>& values)
+ : SetUserAttributeCommand(attr, term, values, "")
{
}
SetUserAttributeCommand::SetUserAttributeCommand(const std::string& attr,
- Expr expr,
+ api::Term term,
const std::string& value)
- : SetUserAttributeCommand(attr, expr, {}, value)
+ : SetUserAttributeCommand(attr, term, {}, value)
{
}
-void SetUserAttributeCommand::invoke(SmtEngine* smtEngine)
+void SetUserAttributeCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- if (!d_expr.isNull())
+ if (!d_term.isNull())
{
- smtEngine->setUserAttribute(d_attr, d_expr, d_expr_values, d_str_value);
+ solver->getSmtEngine()->setUserAttribute(
+ d_attr,
+ d_term.getExpr(),
+ api::termVectorToExprs(d_termValues),
+ d_strValue);
}
d_commandStatus = CommandSuccess::instance();
}
@@ -1475,17 +1450,9 @@ void SetUserAttributeCommand::invoke(SmtEngine* smtEngine)
}
}
-Command* SetUserAttributeCommand::exportTo(
- ExprManager* exprManager, ExprManagerMapCollection& variableMap)
-{
- Expr expr = d_expr.exportTo(exprManager, variableMap);
- return new SetUserAttributeCommand(d_attr, expr, d_expr_values, d_str_value);
-}
-
Command* SetUserAttributeCommand::clone() const
{
- return new SetUserAttributeCommand(
- d_attr, d_expr, d_expr_values, d_str_value);
+ return new SetUserAttributeCommand(d_attr, d_term, d_termValues, d_strValue);
}
std::string SetUserAttributeCommand::getCommandName() const
@@ -1493,17 +1460,26 @@ std::string SetUserAttributeCommand::getCommandName() const
return "set-user-attribute";
}
+void SetUserAttributeCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdSetUserAttribute(
+ out, d_attr, d_term.getNode());
+}
+
/* -------------------------------------------------------------------------- */
/* class SimplifyCommand */
/* -------------------------------------------------------------------------- */
-SimplifyCommand::SimplifyCommand(Expr term) : d_term(term) {}
-Expr SimplifyCommand::getTerm() const { return d_term; }
-void SimplifyCommand::invoke(SmtEngine* smtEngine)
+SimplifyCommand::SimplifyCommand(api::Term term) : d_term(term) {}
+api::Term SimplifyCommand::getTerm() const { return d_term; }
+void SimplifyCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- d_result = smtEngine->simplify(d_term);
+ d_result = solver->simplify(d_term);
d_commandStatus = CommandSuccess::instance();
}
catch (UnsafeInterruptException& e)
@@ -1516,7 +1492,7 @@ void SimplifyCommand::invoke(SmtEngine* smtEngine)
}
}
-Expr SimplifyCommand::getResult() const { return d_result; }
+api::Term SimplifyCommand::getResult() const { return d_result; }
void SimplifyCommand::printResult(std::ostream& out, uint32_t verbosity) const
{
if (!ok())
@@ -1529,15 +1505,6 @@ void SimplifyCommand::printResult(std::ostream& out, uint32_t verbosity) const
}
}
-Command* SimplifyCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- SimplifyCommand* c =
- new SimplifyCommand(d_term.exportTo(exprManager, variableMap));
- c->d_result = d_result.exportTo(exprManager, variableMap);
- return c;
-}
-
Command* SimplifyCommand::clone() const
{
SimplifyCommand* c = new SimplifyCommand(d_term);
@@ -1547,102 +1514,50 @@ Command* SimplifyCommand::clone() const
std::string SimplifyCommand::getCommandName() const { return "simplify"; }
-/* -------------------------------------------------------------------------- */
-/* class ExpandDefinitionsCommand */
-/* -------------------------------------------------------------------------- */
-
-ExpandDefinitionsCommand::ExpandDefinitionsCommand(Expr term) : d_term(term) {}
-Expr ExpandDefinitionsCommand::getTerm() const { return d_term; }
-void ExpandDefinitionsCommand::invoke(SmtEngine* smtEngine)
-{
- Node t = Node::fromExpr(d_term);
- d_result = smtEngine->expandDefinitions(t).toExpr();
- d_commandStatus = CommandSuccess::instance();
-}
-
-Expr ExpandDefinitionsCommand::getResult() const { return d_result; }
-void ExpandDefinitionsCommand::printResult(std::ostream& out,
- uint32_t verbosity) const
-{
- if (!ok())
- {
- this->Command::printResult(out, verbosity);
- }
- else
- {
- out << d_result << endl;
- }
-}
-
-Command* ExpandDefinitionsCommand::exportTo(
- ExprManager* exprManager, ExprManagerMapCollection& variableMap)
+void SimplifyCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
{
- ExpandDefinitionsCommand* c =
- new ExpandDefinitionsCommand(d_term.exportTo(exprManager, variableMap));
- c->d_result = d_result.exportTo(exprManager, variableMap);
- return c;
-}
-
-Command* ExpandDefinitionsCommand::clone() const
-{
- ExpandDefinitionsCommand* c = new ExpandDefinitionsCommand(d_term);
- c->d_result = d_result;
- return c;
-}
-
-std::string ExpandDefinitionsCommand::getCommandName() const
-{
- return "expand-definitions";
+ Printer::getPrinter(language)->toStreamCmdSimplify(out, d_term.getNode());
}
/* -------------------------------------------------------------------------- */
/* class GetValueCommand */
/* -------------------------------------------------------------------------- */
-GetValueCommand::GetValueCommand(Expr term) : d_terms()
+GetValueCommand::GetValueCommand(api::Term term) : d_terms()
{
d_terms.push_back(term);
}
-GetValueCommand::GetValueCommand(const std::vector<Expr>& terms)
+GetValueCommand::GetValueCommand(const std::vector<api::Term>& terms)
: d_terms(terms)
{
PrettyCheckArgument(
terms.size() >= 1, terms, "cannot get-value of an empty set of terms");
}
-const std::vector<Expr>& GetValueCommand::getTerms() const { return d_terms; }
-void GetValueCommand::invoke(SmtEngine* smtEngine)
+const std::vector<api::Term>& GetValueCommand::getTerms() const
+{
+ return d_terms;
+}
+void GetValueCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- ExprManager* em = smtEngine->getExprManager();
- NodeManager* nm = NodeManager::fromExprManager(em);
- smt::SmtScope scope(smtEngine);
- vector<Expr> result = smtEngine->getValues(d_terms);
+ std::vector<api::Term> result = solver->getValue(d_terms);
Assert(result.size() == d_terms.size());
for (int i = 0, size = d_terms.size(); i < size; i++)
{
- Expr e = d_terms[i];
- Node eNode = Node::fromExpr(e);
- Assert(nm == NodeManager::fromExprManager(e.getExprManager()));
- Node request = options::expandDefinitions()
- ? smtEngine->expandDefinitions(eNode)
- : eNode;
- Node value = Node::fromExpr(result[i]);
- if (value.getType().isInteger() && request.getType() == nm->realType())
- {
- // Need to wrap in division-by-one so that output printers know this
- // is an integer-looking constant that really should be output as
- // a rational. Necessary for SMT-LIB standards compliance.
- value = nm->mkNode(kind::DIVISION, value, nm->mkConst(Rational(1)));
- }
- result[i] = nm->mkNode(kind::SEXPR, request, value).toExpr();
+ api::Term request = d_terms[i];
+ api::Term value = result[i];
+ result[i] = solver->mkTerm(api::SEXPR, request, value);
}
- d_result = em->mkExpr(kind::SEXPR, result);
+ d_result = solver->mkTerm(api::SEXPR, result);
d_commandStatus = CommandSuccess::instance();
}
- catch (RecoverableModalException& e)
+ catch (api::CVC4ApiRecoverableException& e)
{
d_commandStatus = new CommandRecoverableFailure(e.what());
}
@@ -1656,7 +1571,7 @@ void GetValueCommand::invoke(SmtEngine* smtEngine)
}
}
-Expr GetValueCommand::getResult() const { return d_result; }
+api::Term GetValueCommand::getResult() const { return d_result; }
void GetValueCommand::printResult(std::ostream& out, uint32_t verbosity) const
{
if (!ok())
@@ -1670,21 +1585,6 @@ void GetValueCommand::printResult(std::ostream& out, uint32_t verbosity) const
}
}
-Command* GetValueCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- vector<Expr> exportedTerms;
- for (std::vector<Expr>::const_iterator i = d_terms.begin();
- i != d_terms.end();
- ++i)
- {
- exportedTerms.push_back((*i).exportTo(exprManager, variableMap));
- }
- GetValueCommand* c = new GetValueCommand(exportedTerms);
- c->d_result = d_result.exportTo(exprManager, variableMap);
- return c;
-}
-
Command* GetValueCommand::clone() const
{
GetValueCommand* c = new GetValueCommand(d_terms);
@@ -1694,28 +1594,48 @@ Command* GetValueCommand::clone() const
std::string GetValueCommand::getCommandName() const { return "get-value"; }
+void GetValueCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdGetValue(
+ out, api::termVectorToNodes(d_terms));
+}
+
/* -------------------------------------------------------------------------- */
/* class GetAssignmentCommand */
/* -------------------------------------------------------------------------- */
GetAssignmentCommand::GetAssignmentCommand() {}
-void GetAssignmentCommand::invoke(SmtEngine* smtEngine)
+void GetAssignmentCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- std::vector<std::pair<Expr, Expr>> assignments = smtEngine->getAssignment();
- vector<SExpr> sexprs;
- for (const auto& p : assignments)
+ std::map<api::Term, std::string> enames = sm->getExpressionNames();
+ std::vector<api::Term> terms;
+ std::vector<std::string> names;
+ for (const std::pair<const api::Term, std::string>& e : enames)
{
- vector<SExpr> v;
- v.emplace_back(SExpr::Keyword(p.first.toString()));
- v.emplace_back(SExpr::Keyword(p.second.toString()));
- sexprs.emplace_back(v);
+ terms.push_back(e.first);
+ names.push_back(e.second);
+ }
+ // Must use vector version of getValue to ensure error is thrown regardless
+ // of whether terms is empty.
+ std::vector<api::Term> values = solver->getValue(terms);
+ Assert(values.size() == names.size());
+ std::vector<SExpr> sexprs;
+ for (size_t i = 0, nterms = terms.size(); i < nterms; i++)
+ {
+ std::vector<SExpr> ss;
+ ss.emplace_back(SExpr::Keyword(names[i]));
+ ss.emplace_back(SExpr::Keyword(values[i].toString()));
+ sexprs.emplace_back(ss);
}
d_result = SExpr(sexprs);
d_commandStatus = CommandSuccess::instance();
}
- catch (RecoverableModalException& e)
+ catch (api::CVC4ApiRecoverableException& e)
{
d_commandStatus = new CommandRecoverableFailure(e.what());
}
@@ -1743,14 +1663,6 @@ void GetAssignmentCommand::printResult(std::ostream& out,
}
}
-Command* GetAssignmentCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- GetAssignmentCommand* c = new GetAssignmentCommand();
- c->d_result = d_result;
- return c;
-}
-
Command* GetAssignmentCommand::clone() const
{
GetAssignmentCommand* c = new GetAssignmentCommand();
@@ -1763,17 +1675,24 @@ std::string GetAssignmentCommand::getCommandName() const
return "get-assignment";
}
+void GetAssignmentCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdGetAssignment(out);
+}
+
/* -------------------------------------------------------------------------- */
/* class GetModelCommand */
/* -------------------------------------------------------------------------- */
-GetModelCommand::GetModelCommand() : d_result(nullptr), d_smtEngine(nullptr) {}
-void GetModelCommand::invoke(SmtEngine* smtEngine)
+GetModelCommand::GetModelCommand() : d_result(nullptr) {}
+void GetModelCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- d_result = smtEngine->getModel();
- d_smtEngine = smtEngine;
+ d_result = solver->getSmtEngine()->getModel();
d_commandStatus = CommandSuccess::instance();
}
catch (RecoverableModalException& e)
@@ -1808,38 +1727,36 @@ void GetModelCommand::printResult(std::ostream& out, uint32_t verbosity) const
}
}
-Command* GetModelCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- GetModelCommand* c = new GetModelCommand();
- c->d_result = d_result;
- c->d_smtEngine = d_smtEngine;
- return c;
-}
-
Command* GetModelCommand::clone() const
{
GetModelCommand* c = new GetModelCommand();
c->d_result = d_result;
- c->d_smtEngine = d_smtEngine;
return c;
}
std::string GetModelCommand::getCommandName() const { return "get-model"; }
+void GetModelCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdGetModel(out);
+}
+
/* -------------------------------------------------------------------------- */
/* class BlockModelCommand */
/* -------------------------------------------------------------------------- */
BlockModelCommand::BlockModelCommand() {}
-void BlockModelCommand::invoke(SmtEngine* smtEngine)
+void BlockModelCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- smtEngine->blockModel();
+ solver->blockModel();
d_commandStatus = CommandSuccess::instance();
}
- catch (RecoverableModalException& e)
+ catch (api::CVC4ApiRecoverableException& e)
{
d_commandStatus = new CommandRecoverableFailure(e.what());
}
@@ -1853,13 +1770,6 @@ void BlockModelCommand::invoke(SmtEngine* smtEngine)
}
}
-Command* BlockModelCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- BlockModelCommand* c = new BlockModelCommand();
- return c;
-}
-
Command* BlockModelCommand::clone() const
{
BlockModelCommand* c = new BlockModelCommand();
@@ -1868,11 +1778,20 @@ Command* BlockModelCommand::clone() const
std::string BlockModelCommand::getCommandName() const { return "block-model"; }
+void BlockModelCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdBlockModel(out);
+}
+
/* -------------------------------------------------------------------------- */
/* class BlockModelValuesCommand */
/* -------------------------------------------------------------------------- */
-BlockModelValuesCommand::BlockModelValuesCommand(const std::vector<Expr>& terms)
+BlockModelValuesCommand::BlockModelValuesCommand(
+ const std::vector<api::Term>& terms)
: d_terms(terms)
{
PrettyCheckArgument(terms.size() >= 1,
@@ -1880,15 +1799,15 @@ BlockModelValuesCommand::BlockModelValuesCommand(const std::vector<Expr>& terms)
"cannot block-model-values of an empty set of terms");
}
-const std::vector<Expr>& BlockModelValuesCommand::getTerms() const
+const std::vector<api::Term>& BlockModelValuesCommand::getTerms() const
{
return d_terms;
}
-void BlockModelValuesCommand::invoke(SmtEngine* smtEngine)
+void BlockModelValuesCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- smtEngine->blockModelValues(d_terms);
+ solver->blockModelValues(d_terms);
d_commandStatus = CommandSuccess::instance();
}
catch (RecoverableModalException& e)
@@ -1905,20 +1824,6 @@ void BlockModelValuesCommand::invoke(SmtEngine* smtEngine)
}
}
-Command* BlockModelValuesCommand::exportTo(
- ExprManager* exprManager, ExprManagerMapCollection& variableMap)
-{
- vector<Expr> exportedTerms;
- for (std::vector<Expr>::const_iterator i = d_terms.begin();
- i != d_terms.end();
- ++i)
- {
- exportedTerms.push_back((*i).exportTo(exprManager, variableMap));
- }
- BlockModelValuesCommand* c = new BlockModelValuesCommand(exportedTerms);
- return c;
-}
-
Command* BlockModelValuesCommand::clone() const
{
BlockModelValuesCommand* c = new BlockModelValuesCommand(d_terms);
@@ -1930,76 +1835,51 @@ std::string BlockModelValuesCommand::getCommandName() const
return "block-model-values";
}
+void BlockModelValuesCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdBlockModelValues(
+ out, api::termVectorToNodes(d_terms));
+}
+
/* -------------------------------------------------------------------------- */
/* class GetProofCommand */
/* -------------------------------------------------------------------------- */
-GetProofCommand::GetProofCommand() : d_smtEngine(nullptr), d_result(nullptr) {}
-void GetProofCommand::invoke(SmtEngine* smtEngine)
+GetProofCommand::GetProofCommand() {}
+void GetProofCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
- try
- {
- d_smtEngine = smtEngine;
- d_result = &smtEngine->getProof();
- d_commandStatus = CommandSuccess::instance();
- }
- catch (RecoverableModalException& e)
- {
- d_commandStatus = new CommandRecoverableFailure(e.what());
- }
- catch (UnsafeInterruptException& e)
- {
- d_commandStatus = new CommandInterrupted();
- }
- catch (exception& e)
- {
- d_commandStatus = new CommandFailure(e.what());
- }
-}
-
-const Proof& GetProofCommand::getResult() const { return *d_result; }
-void GetProofCommand::printResult(std::ostream& out, uint32_t verbosity) const
-{
- if (!ok())
- {
- this->Command::printResult(out, verbosity);
- }
- else
- {
- smt::SmtScope scope(d_smtEngine);
- d_result->toStream(out);
- }
-}
-
-Command* GetProofCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- GetProofCommand* c = new GetProofCommand();
- c->d_result = d_result;
- c->d_smtEngine = d_smtEngine;
- return c;
+ Unimplemented() << "Unimplemented get-proof\n";
}
Command* GetProofCommand::clone() const
{
GetProofCommand* c = new GetProofCommand();
- c->d_result = d_result;
- c->d_smtEngine = d_smtEngine;
return c;
}
std::string GetProofCommand::getCommandName() const { return "get-proof"; }
+void GetProofCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdGetProof(out);
+}
+
/* -------------------------------------------------------------------------- */
/* class GetInstantiationsCommand */
/* -------------------------------------------------------------------------- */
-GetInstantiationsCommand::GetInstantiationsCommand() : d_smtEngine(nullptr) {}
-void GetInstantiationsCommand::invoke(SmtEngine* smtEngine)
+GetInstantiationsCommand::GetInstantiationsCommand() : d_solver(nullptr) {}
+void GetInstantiationsCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- d_smtEngine = smtEngine;
+ d_solver = solver;
d_commandStatus = CommandSuccess::instance();
}
catch (exception& e)
@@ -2017,24 +1897,15 @@ void GetInstantiationsCommand::printResult(std::ostream& out,
}
else
{
- d_smtEngine->printInstantiations(out);
+ d_solver->printInstantiations(out);
}
}
-Command* GetInstantiationsCommand::exportTo(
- ExprManager* exprManager, ExprManagerMapCollection& variableMap)
-{
- GetInstantiationsCommand* c = new GetInstantiationsCommand();
- // c->d_result = d_result;
- c->d_smtEngine = d_smtEngine;
- return c;
-}
-
Command* GetInstantiationsCommand::clone() const
{
GetInstantiationsCommand* c = new GetInstantiationsCommand();
// c->d_result = d_result;
- c->d_smtEngine = d_smtEngine;
+ c->d_solver = d_solver;
return c;
}
@@ -2043,16 +1914,24 @@ std::string GetInstantiationsCommand::getCommandName() const
return "get-instantiations";
}
+void GetInstantiationsCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdGetInstantiations(out);
+}
+
/* -------------------------------------------------------------------------- */
/* class GetSynthSolutionCommand */
/* -------------------------------------------------------------------------- */
-GetSynthSolutionCommand::GetSynthSolutionCommand() : d_smtEngine(nullptr) {}
-void GetSynthSolutionCommand::invoke(SmtEngine* smtEngine)
+GetSynthSolutionCommand::GetSynthSolutionCommand() : d_solver(nullptr) {}
+void GetSynthSolutionCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- d_smtEngine = smtEngine;
+ d_solver = solver;
d_commandStatus = CommandSuccess::instance();
}
catch (exception& e)
@@ -2070,64 +1949,66 @@ void GetSynthSolutionCommand::printResult(std::ostream& out,
}
else
{
- d_smtEngine->printSynthSolution(out);
+ d_solver->printSynthSolution(out);
}
}
-Command* GetSynthSolutionCommand::exportTo(
- ExprManager* exprManager, ExprManagerMapCollection& variableMap)
+Command* GetSynthSolutionCommand::clone() const
{
GetSynthSolutionCommand* c = new GetSynthSolutionCommand();
- c->d_smtEngine = d_smtEngine;
+ c->d_solver = d_solver;
return c;
}
-Command* GetSynthSolutionCommand::clone() const
+std::string GetSynthSolutionCommand::getCommandName() const
{
- GetSynthSolutionCommand* c = new GetSynthSolutionCommand();
- c->d_smtEngine = d_smtEngine;
- return c;
+ return "get-synth-solution";
}
-std::string GetSynthSolutionCommand::getCommandName() const
+void GetSynthSolutionCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
{
- return "get-instantiations";
+ Printer::getPrinter(language)->toStreamCmdGetSynthSolution(out);
}
-GetInterpolCommand::GetInterpolCommand(api::Solver* solver,
- const std::string& name,
- api::Term conj)
- : Command(solver), d_name(name), d_conj(conj), d_resultStatus(false)
+/* -------------------------------------------------------------------------- */
+/* class GetInterpolCommand */
+/* -------------------------------------------------------------------------- */
+
+GetInterpolCommand::GetInterpolCommand(const std::string& name, api::Term conj)
+ : d_name(name), d_conj(conj), d_resultStatus(false)
{
}
-GetInterpolCommand::GetInterpolCommand(api::Solver* solver,
- const std::string& name,
+GetInterpolCommand::GetInterpolCommand(const std::string& name,
api::Term conj,
- const Type& gtype)
- : Command(solver),
- d_name(name),
- d_conj(conj),
- d_sygus_grammar_type(gtype),
- d_resultStatus(false)
+ api::Grammar* g)
+ : d_name(name), d_conj(conj), d_sygus_grammar(g), d_resultStatus(false)
{
}
api::Term GetInterpolCommand::getConjecture() const { return d_conj; }
-Type GetInterpolCommand::getGrammarType() const { return d_sygus_grammar_type; }
+
+const api::Grammar* GetInterpolCommand::getGrammar() const
+{
+ return d_sygus_grammar;
+}
+
api::Term GetInterpolCommand::getResult() const { return d_result; }
-void GetInterpolCommand::invoke(SmtEngine* smtEngine)
+void GetInterpolCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- if (d_sygus_grammar_type.isNull())
+ if (d_sygus_grammar == nullptr)
{
- d_resultStatus = d_solver->getInterpolant(d_conj, d_result);
+ d_resultStatus = solver->getInterpolant(d_conj, d_result);
}
else
{
d_resultStatus =
- d_solver->getInterpolant(d_conj, d_sygus_grammar_type, d_result);
+ solver->getInterpolant(d_conj, *d_sygus_grammar, d_result);
}
d_commandStatus = CommandSuccess::instance();
}
@@ -2159,15 +2040,10 @@ void GetInterpolCommand::printResult(std::ostream& out,
}
}
-Command* GetInterpolCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- Unimplemented();
-}
-
Command* GetInterpolCommand::clone() const
{
- GetInterpolCommand* c = new GetInterpolCommand(d_solver, d_name, d_conj);
+ GetInterpolCommand* c =
+ new GetInterpolCommand(d_name, d_conj, d_sygus_grammar);
c->d_result = d_result;
c->d_resultStatus = d_resultStatus;
return c;
@@ -2178,42 +2054,52 @@ std::string GetInterpolCommand::getCommandName() const
return "get-interpol";
}
-GetAbductCommand::GetAbductCommand() {}
-GetAbductCommand::GetAbductCommand(const std::string& name, Expr conj)
+void GetInterpolCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdGetInterpol(
+ out, d_name, d_conj.getNode(), d_sygus_grammar->resolve().getTypeNode());
+}
+
+/* -------------------------------------------------------------------------- */
+/* class GetAbductCommand */
+/* -------------------------------------------------------------------------- */
+
+GetAbductCommand::GetAbductCommand(const std::string& name, api::Term conj)
: d_name(name), d_conj(conj), d_resultStatus(false)
{
}
GetAbductCommand::GetAbductCommand(const std::string& name,
- Expr conj,
- const Type& gtype)
- : d_name(name),
- d_conj(conj),
- d_sygus_grammar_type(gtype),
- d_resultStatus(false)
+ api::Term conj,
+ api::Grammar* g)
+ : d_name(name), d_conj(conj), d_sygus_grammar(g), d_resultStatus(false)
{
}
-Expr GetAbductCommand::getConjecture() const { return d_conj; }
-Type GetAbductCommand::getGrammarType() const { return d_sygus_grammar_type; }
+api::Term GetAbductCommand::getConjecture() const { return d_conj; }
+
+const api::Grammar* GetAbductCommand::getGrammar() const
+{
+ return d_sygus_grammar;
+}
+
std::string GetAbductCommand::getAbductName() const { return d_name; }
-Expr GetAbductCommand::getResult() const { return d_result; }
+api::Term GetAbductCommand::getResult() const { return d_result; }
-void GetAbductCommand::invoke(SmtEngine* smtEngine)
+void GetAbductCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- Node conjNode = Node::fromExpr(d_conj);
- Node resn;
- if (d_sygus_grammar_type.isNull())
+ if (d_sygus_grammar == nullptr)
{
- d_resultStatus = smtEngine->getAbduct(conjNode, resn);
+ d_resultStatus = solver->getAbduct(d_conj, d_result);
}
else
{
- TypeNode gtype = TypeNode::fromType(d_sygus_grammar_type);
- d_resultStatus = smtEngine->getAbduct(conjNode, gtype, resn);
+ d_resultStatus = solver->getAbduct(d_conj, *d_sygus_grammar, d_result);
}
- d_result = resn.toExpr();
d_commandStatus = CommandSuccess::instance();
}
catch (exception& e)
@@ -2243,22 +2129,9 @@ void GetAbductCommand::printResult(std::ostream& out, uint32_t verbosity) const
}
}
-Command* GetAbductCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- GetAbductCommand* c =
- new GetAbductCommand(d_name, d_conj.exportTo(exprManager, variableMap));
- c->d_sygus_grammar_type =
- d_sygus_grammar_type.exportTo(exprManager, variableMap);
- c->d_result = d_result.exportTo(exprManager, variableMap);
- c->d_resultStatus = d_resultStatus;
- return c;
-}
-
Command* GetAbductCommand::clone() const
{
- GetAbductCommand* c = new GetAbductCommand(d_name, d_conj);
- c->d_sygus_grammar_type = d_sygus_grammar_type;
+ GetAbductCommand* c = new GetAbductCommand(d_name, d_conj, d_sygus_grammar);
c->d_result = d_result;
c->d_resultStatus = d_resultStatus;
return c;
@@ -2266,27 +2139,44 @@ Command* GetAbductCommand::clone() const
std::string GetAbductCommand::getCommandName() const { return "get-abduct"; }
+void GetAbductCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdGetAbduct(
+ out, d_name, d_conj.getNode(), d_sygus_grammar->resolve().getTypeNode());
+}
+
/* -------------------------------------------------------------------------- */
/* class GetQuantifierEliminationCommand */
/* -------------------------------------------------------------------------- */
GetQuantifierEliminationCommand::GetQuantifierEliminationCommand()
- : d_expr(), d_doFull(true)
+ : d_term(), d_doFull(true)
{
}
GetQuantifierEliminationCommand::GetQuantifierEliminationCommand(
- const Expr& expr, bool doFull)
- : d_expr(expr), d_doFull(doFull)
+ const api::Term& term, bool doFull)
+ : d_term(term), d_doFull(doFull)
{
}
-Expr GetQuantifierEliminationCommand::getExpr() const { return d_expr; }
+api::Term GetQuantifierEliminationCommand::getTerm() const { return d_term; }
bool GetQuantifierEliminationCommand::getDoFull() const { return d_doFull; }
-void GetQuantifierEliminationCommand::invoke(SmtEngine* smtEngine)
+void GetQuantifierEliminationCommand::invoke(api::Solver* solver,
+ SymbolManager* sm)
{
try
{
- d_result = smtEngine->doQuantifierElimination(d_expr, d_doFull);
+ if (d_doFull)
+ {
+ d_result = solver->getQuantifierElimination(d_term);
+ }
+ else
+ {
+ d_result = solver->getQuantifierEliminationDisjunct(d_term);
+ }
d_commandStatus = CommandSuccess::instance();
}
catch (exception& e)
@@ -2295,7 +2185,10 @@ void GetQuantifierEliminationCommand::invoke(SmtEngine* smtEngine)
}
}
-Expr GetQuantifierEliminationCommand::getResult() const { return d_result; }
+api::Term GetQuantifierEliminationCommand::getResult() const
+{
+ return d_result;
+}
void GetQuantifierEliminationCommand::printResult(std::ostream& out,
uint32_t verbosity) const
{
@@ -2309,19 +2202,10 @@ void GetQuantifierEliminationCommand::printResult(std::ostream& out,
}
}
-Command* GetQuantifierEliminationCommand::exportTo(
- ExprManager* exprManager, ExprManagerMapCollection& variableMap)
-{
- GetQuantifierEliminationCommand* c = new GetQuantifierEliminationCommand(
- d_expr.exportTo(exprManager, variableMap), d_doFull);
- c->d_result = d_result;
- return c;
-}
-
Command* GetQuantifierEliminationCommand::clone() const
{
GetQuantifierEliminationCommand* c =
- new GetQuantifierEliminationCommand(d_expr, d_doFull);
+ new GetQuantifierEliminationCommand(d_term, d_doFull);
c->d_result = d_result;
return c;
}
@@ -2331,20 +2215,29 @@ std::string GetQuantifierEliminationCommand::getCommandName() const
return d_doFull ? "get-qe" : "get-qe-disjunct";
}
+void GetQuantifierEliminationCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdGetQuantifierElimination(
+ out, d_term.getNode());
+}
+
/* -------------------------------------------------------------------------- */
/* class GetUnsatAssumptionsCommand */
/* -------------------------------------------------------------------------- */
GetUnsatAssumptionsCommand::GetUnsatAssumptionsCommand() {}
-void GetUnsatAssumptionsCommand::invoke(SmtEngine* smtEngine)
+void GetUnsatAssumptionsCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- d_result = smtEngine->getUnsatAssumptions();
+ d_result = solver->getUnsatAssumptions();
d_commandStatus = CommandSuccess::instance();
}
- catch (RecoverableModalException& e)
+ catch (api::CVC4ApiRecoverableException& e)
{
d_commandStatus = new CommandRecoverableFailure(e.what());
}
@@ -2354,7 +2247,7 @@ void GetUnsatAssumptionsCommand::invoke(SmtEngine* smtEngine)
}
}
-std::vector<Expr> GetUnsatAssumptionsCommand::getResult() const
+std::vector<api::Term> GetUnsatAssumptionsCommand::getResult() const
{
return d_result;
}
@@ -2372,14 +2265,6 @@ void GetUnsatAssumptionsCommand::printResult(std::ostream& out,
}
}
-Command* GetUnsatAssumptionsCommand::exportTo(
- ExprManager* exprManager, ExprManagerMapCollection& variableMap)
-{
- GetUnsatAssumptionsCommand* c = new GetUnsatAssumptionsCommand;
- c->d_result = d_result;
- return c;
-}
-
Command* GetUnsatAssumptionsCommand::clone() const
{
GetUnsatAssumptionsCommand* c = new GetUnsatAssumptionsCommand;
@@ -2392,19 +2277,29 @@ std::string GetUnsatAssumptionsCommand::getCommandName() const
return "get-unsat-assumptions";
}
+void GetUnsatAssumptionsCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdGetUnsatAssumptions(out);
+}
+
/* -------------------------------------------------------------------------- */
/* class GetUnsatCoreCommand */
/* -------------------------------------------------------------------------- */
-GetUnsatCoreCommand::GetUnsatCoreCommand() {}
-void GetUnsatCoreCommand::invoke(SmtEngine* smtEngine)
+GetUnsatCoreCommand::GetUnsatCoreCommand() : d_sm(nullptr) {}
+void GetUnsatCoreCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- d_result = smtEngine->getUnsatCore();
+ d_sm = sm;
+ d_result = solver->getUnsatCore();
+
d_commandStatus = CommandSuccess::instance();
}
- catch (RecoverableModalException& e)
+ catch (api::CVC4ApiRecoverableException& e)
{
d_commandStatus = new CommandRecoverableFailure(e.what());
}
@@ -2423,27 +2318,33 @@ void GetUnsatCoreCommand::printResult(std::ostream& out,
}
else
{
- d_result.toStream(out);
+ if (options::dumpUnsatCoresFull())
+ {
+ // use the assertions
+ UnsatCore ucr(api::termVectorToNodes(d_result));
+ ucr.toStream(out);
+ }
+ else
+ {
+ // otherwise, use the names
+ std::vector<std::string> names;
+ d_sm->getExpressionNames(d_result, names, true);
+ UnsatCore ucr(names);
+ ucr.toStream(out);
+ }
}
}
-const UnsatCore& GetUnsatCoreCommand::getUnsatCore() const
+const std::vector<api::Term>& GetUnsatCoreCommand::getUnsatCore() const
{
// of course, this will be empty if the command hasn't been invoked yet
return d_result;
}
-Command* GetUnsatCoreCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- GetUnsatCoreCommand* c = new GetUnsatCoreCommand;
- c->d_result = d_result;
- return c;
-}
-
Command* GetUnsatCoreCommand::clone() const
{
GetUnsatCoreCommand* c = new GetUnsatCoreCommand;
+ c->d_sm = d_sm;
c->d_result = d_result;
return c;
}
@@ -2453,19 +2354,27 @@ std::string GetUnsatCoreCommand::getCommandName() const
return "get-unsat-core";
}
+void GetUnsatCoreCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdGetUnsatCore(out);
+}
+
/* -------------------------------------------------------------------------- */
/* class GetAssertionsCommand */
/* -------------------------------------------------------------------------- */
GetAssertionsCommand::GetAssertionsCommand() {}
-void GetAssertionsCommand::invoke(SmtEngine* smtEngine)
+void GetAssertionsCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
stringstream ss;
- const vector<Expr> v = smtEngine->getAssertions();
+ const vector<api::Term> v = solver->getAssertions();
ss << "(\n";
- copy(v.begin(), v.end(), ostream_iterator<Expr>(ss, "\n"));
+ copy(v.begin(), v.end(), ostream_iterator<api::Term>(ss, "\n"));
ss << ")\n";
d_result = ss.str();
d_commandStatus = CommandSuccess::instance();
@@ -2490,14 +2399,6 @@ void GetAssertionsCommand::printResult(std::ostream& out,
}
}
-Command* GetAssertionsCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- GetAssertionsCommand* c = new GetAssertionsCommand();
- c->d_result = d_result;
- return c;
-}
-
Command* GetAssertionsCommand::clone() const
{
GetAssertionsCommand* c = new GetAssertionsCommand();
@@ -2510,6 +2411,14 @@ std::string GetAssertionsCommand::getCommandName() const
return "get-assertions";
}
+void GetAssertionsCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdGetAssertions(out);
+}
+
/* -------------------------------------------------------------------------- */
/* class SetBenchmarkStatusCommand */
/* -------------------------------------------------------------------------- */
@@ -2524,14 +2433,13 @@ BenchmarkStatus SetBenchmarkStatusCommand::getStatus() const
return d_status;
}
-void SetBenchmarkStatusCommand::invoke(SmtEngine* smtEngine)
+void SetBenchmarkStatusCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
stringstream ss;
ss << d_status;
- SExpr status = SExpr(ss.str());
- smtEngine->setInfo("status", status);
+ solver->setInfo("status", ss.str());
d_commandStatus = CommandSuccess::instance();
}
catch (exception& e)
@@ -2540,12 +2448,6 @@ void SetBenchmarkStatusCommand::invoke(SmtEngine* smtEngine)
}
}
-Command* SetBenchmarkStatusCommand::exportTo(
- ExprManager* exprManager, ExprManagerMapCollection& variableMap)
-{
- return new SetBenchmarkStatusCommand(d_status);
-}
-
Command* SetBenchmarkStatusCommand::clone() const
{
return new SetBenchmarkStatusCommand(d_status);
@@ -2556,6 +2458,22 @@ std::string SetBenchmarkStatusCommand::getCommandName() const
return "set-info";
}
+void SetBenchmarkStatusCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Result::Sat status = Result::SAT_UNKNOWN;
+ switch (d_status)
+ {
+ case BenchmarkStatus::SMT_SATISFIABLE: status = Result::SAT; break;
+ case BenchmarkStatus::SMT_UNSATISFIABLE: status = Result::UNSAT; break;
+ case BenchmarkStatus::SMT_UNKNOWN: status = Result::SAT_UNKNOWN; break;
+ }
+
+ Printer::getPrinter(language)->toStreamCmdSetBenchmarkStatus(out, status);
+}
+
/* -------------------------------------------------------------------------- */
/* class SetBenchmarkLogicCommand */
/* -------------------------------------------------------------------------- */
@@ -2566,11 +2484,11 @@ SetBenchmarkLogicCommand::SetBenchmarkLogicCommand(std::string logic)
}
std::string SetBenchmarkLogicCommand::getLogic() const { return d_logic; }
-void SetBenchmarkLogicCommand::invoke(SmtEngine* smtEngine)
+void SetBenchmarkLogicCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- smtEngine->setLogic(d_logic);
+ solver->setLogic(d_logic);
d_commandStatus = CommandSuccess::instance();
}
catch (exception& e)
@@ -2579,12 +2497,6 @@ void SetBenchmarkLogicCommand::invoke(SmtEngine* smtEngine)
}
}
-Command* SetBenchmarkLogicCommand::exportTo(
- ExprManager* exprManager, ExprManagerMapCollection& variableMap)
-{
- return new SetBenchmarkLogicCommand(d_logic);
-}
-
Command* SetBenchmarkLogicCommand::clone() const
{
return new SetBenchmarkLogicCommand(d_logic);
@@ -2595,6 +2507,14 @@ std::string SetBenchmarkLogicCommand::getCommandName() const
return "set-logic";
}
+void SetBenchmarkLogicCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdSetBenchmarkLogic(out, d_logic);
+}
+
/* -------------------------------------------------------------------------- */
/* class SetInfoCommand */
/* -------------------------------------------------------------------------- */
@@ -2606,11 +2526,11 @@ SetInfoCommand::SetInfoCommand(std::string flag, const SExpr& sexpr)
std::string SetInfoCommand::getFlag() const { return d_flag; }
SExpr SetInfoCommand::getSExpr() const { return d_sexpr; }
-void SetInfoCommand::invoke(SmtEngine* smtEngine)
+void SetInfoCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- smtEngine->setInfo(d_flag, d_sexpr);
+ solver->getSmtEngine()->setInfo(d_flag, d_sexpr);
d_commandStatus = CommandSuccess::instance();
}
catch (UnrecognizedOptionException&)
@@ -2624,12 +2544,6 @@ void SetInfoCommand::invoke(SmtEngine* smtEngine)
}
}
-Command* SetInfoCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- return new SetInfoCommand(d_flag, d_sexpr);
-}
-
Command* SetInfoCommand::clone() const
{
return new SetInfoCommand(d_flag, d_sexpr);
@@ -2637,19 +2551,27 @@ Command* SetInfoCommand::clone() const
std::string SetInfoCommand::getCommandName() const { return "set-info"; }
+void SetInfoCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdSetInfo(out, d_flag, d_sexpr);
+}
+
/* -------------------------------------------------------------------------- */
/* class GetInfoCommand */
/* -------------------------------------------------------------------------- */
GetInfoCommand::GetInfoCommand(std::string flag) : d_flag(flag) {}
std::string GetInfoCommand::getFlag() const { return d_flag; }
-void GetInfoCommand::invoke(SmtEngine* smtEngine)
+void GetInfoCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
vector<SExpr> v;
v.push_back(SExpr(SExpr::Keyword(string(":") + d_flag)));
- v.push_back(smtEngine->getInfo(d_flag));
+ v.emplace_back(solver->getSmtEngine()->getInfo(d_flag));
stringstream ss;
if (d_flag == "all-options" || d_flag == "all-statistics")
{
@@ -2686,14 +2608,6 @@ void GetInfoCommand::printResult(std::ostream& out, uint32_t verbosity) const
}
}
-Command* GetInfoCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- GetInfoCommand* c = new GetInfoCommand(d_flag);
- c->d_result = d_result;
- return c;
-}
-
Command* GetInfoCommand::clone() const
{
GetInfoCommand* c = new GetInfoCommand(d_flag);
@@ -2703,6 +2617,14 @@ Command* GetInfoCommand::clone() const
std::string GetInfoCommand::getCommandName() const { return "get-info"; }
+void GetInfoCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdGetInfo(out, d_flag);
+}
+
/* -------------------------------------------------------------------------- */
/* class SetOptionCommand */
/* -------------------------------------------------------------------------- */
@@ -2714,11 +2636,11 @@ SetOptionCommand::SetOptionCommand(std::string flag, const SExpr& sexpr)
std::string SetOptionCommand::getFlag() const { return d_flag; }
SExpr SetOptionCommand::getSExpr() const { return d_sexpr; }
-void SetOptionCommand::invoke(SmtEngine* smtEngine)
+void SetOptionCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- smtEngine->setOption(d_flag, d_sexpr);
+ solver->getSmtEngine()->setOption(d_flag, d_sexpr);
d_commandStatus = CommandSuccess::instance();
}
catch (UnrecognizedOptionException&)
@@ -2731,12 +2653,6 @@ void SetOptionCommand::invoke(SmtEngine* smtEngine)
}
}
-Command* SetOptionCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- return new SetOptionCommand(d_flag, d_sexpr);
-}
-
Command* SetOptionCommand::clone() const
{
return new SetOptionCommand(d_flag, d_sexpr);
@@ -2744,18 +2660,25 @@ Command* SetOptionCommand::clone() const
std::string SetOptionCommand::getCommandName() const { return "set-option"; }
+void SetOptionCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdSetOption(out, d_flag, d_sexpr);
+}
+
/* -------------------------------------------------------------------------- */
/* class GetOptionCommand */
/* -------------------------------------------------------------------------- */
GetOptionCommand::GetOptionCommand(std::string flag) : d_flag(flag) {}
std::string GetOptionCommand::getFlag() const { return d_flag; }
-void GetOptionCommand::invoke(SmtEngine* smtEngine)
+void GetOptionCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
try
{
- SExpr res = smtEngine->getOption(d_flag);
- d_result = res.toString();
+ d_result = solver->getOption(d_flag);
d_commandStatus = CommandSuccess::instance();
}
catch (UnrecognizedOptionException&)
@@ -2781,14 +2704,6 @@ void GetOptionCommand::printResult(std::ostream& out, uint32_t verbosity) const
}
}
-Command* GetOptionCommand::exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
-{
- GetOptionCommand* c = new GetOptionCommand(d_flag);
- c->d_result = d_result;
- return c;
-}
-
Command* GetOptionCommand::clone() const
{
GetOptionCommand* c = new GetOptionCommand(d_flag);
@@ -2798,73 +2713,41 @@ Command* GetOptionCommand::clone() const
std::string GetOptionCommand::getCommandName() const { return "get-option"; }
-/* -------------------------------------------------------------------------- */
-/* class SetExpressionNameCommand */
-/* -------------------------------------------------------------------------- */
-
-SetExpressionNameCommand::SetExpressionNameCommand(Expr expr, std::string name)
- : d_expr(expr), d_name(name)
-{
-}
-
-void SetExpressionNameCommand::invoke(SmtEngine* smtEngine)
-{
- smtEngine->setExpressionName(d_expr, d_name);
- d_commandStatus = CommandSuccess::instance();
-}
-
-Command* SetExpressionNameCommand::exportTo(
- ExprManager* exprManager, ExprManagerMapCollection& variableMap)
+void GetOptionCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
{
- SetExpressionNameCommand* c = new SetExpressionNameCommand(
- d_expr.exportTo(exprManager, variableMap), d_name);
- return c;
-}
-
-Command* SetExpressionNameCommand::clone() const
-{
- SetExpressionNameCommand* c = new SetExpressionNameCommand(d_expr, d_name);
- return c;
-}
-
-std::string SetExpressionNameCommand::getCommandName() const
-{
- return "set-expr-name";
+ Printer::getPrinter(language)->toStreamCmdGetOption(out, d_flag);
}
/* -------------------------------------------------------------------------- */
/* class DatatypeDeclarationCommand */
/* -------------------------------------------------------------------------- */
-DatatypeDeclarationCommand::DatatypeDeclarationCommand(const Type& datatype)
+DatatypeDeclarationCommand::DatatypeDeclarationCommand(
+ const api::Sort& datatype)
: d_datatypes()
{
d_datatypes.push_back(datatype);
}
DatatypeDeclarationCommand::DatatypeDeclarationCommand(
- const std::vector<Type>& datatypes)
+ const std::vector<api::Sort>& datatypes)
: d_datatypes(datatypes)
{
}
-const std::vector<Type>& DatatypeDeclarationCommand::getDatatypes() const
+const std::vector<api::Sort>& DatatypeDeclarationCommand::getDatatypes() const
{
return d_datatypes;
}
-void DatatypeDeclarationCommand::invoke(SmtEngine* smtEngine)
+void DatatypeDeclarationCommand::invoke(api::Solver* solver, SymbolManager* sm)
{
d_commandStatus = CommandSuccess::instance();
}
-Command* DatatypeDeclarationCommand::exportTo(
- ExprManager* exprManager, ExprManagerMapCollection& variableMap)
-{
- throw ExportUnsupportedException(
- "export of DatatypeDeclarationCommand unsupported");
-}
-
Command* DatatypeDeclarationCommand::clone() const
{
return new DatatypeDeclarationCommand(d_datatypes);
@@ -2875,4 +2758,13 @@ std::string DatatypeDeclarationCommand::getCommandName() const
return "declare-datatypes";
}
+void DatatypeDeclarationCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdDatatypeDeclaration(
+ out, api::sortVectorToTypeNodes(d_datatypes));
+}
+
} // namespace CVC4
diff --git a/src/smt/command.h b/src/smt/command.h
index 552847fee..96a6938d6 100644
--- a/src/smt/command.h
+++ b/src/smt/command.h
@@ -2,10 +2,10 @@
/*! \file command.h
** \verbatim
** Top contributors (to current version):
- ** Tim King, Morgan Deters, Haniel Barbosa
+ ** Tim King, Morgan Deters, Abdalrhman Mohamed
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -29,12 +29,8 @@
#include <vector>
#include "api/cvc4cpp.h"
-#include "expr/datatype.h"
#include "expr/expr.h"
#include "expr/type.h"
-#include "expr/variable_type_map.h"
-#include "proof/unsat_core.h"
-#include "util/proof.h"
#include "util/result.h"
#include "util/sexpr.h"
@@ -45,10 +41,15 @@ class Solver;
class Term;
} // namespace api
+class SymbolManager;
+class UnsatCore;
class SmtEngine;
class Command;
class CommandStatus;
+
+namespace smt {
class Model;
+}
std::ostream& operator<<(std::ostream&, const Command&) CVC4_PUBLIC;
std::ostream& operator<<(std::ostream&, const Command*) CVC4_PUBLIC;
@@ -121,6 +122,7 @@ class CVC4_PUBLIC CommandStatus
protected:
// shouldn't construct a CommandStatus (use a derived class)
CommandStatus() {}
+
public:
virtual ~CommandStatus() {}
void toStream(std::ostream& out,
@@ -196,19 +198,28 @@ class CVC4_PUBLIC Command
typedef CommandPrintSuccess printsuccess;
Command();
- Command(api::Solver* solver);
+ Command(const api::Solver* solver);
Command(const Command& cmd);
virtual ~Command();
- virtual void invoke(SmtEngine* smtEngine) = 0;
- virtual void invoke(SmtEngine* smtEngine, std::ostream& out);
+ /**
+ * Invoke the command on the solver and symbol manager sm.
+ */
+ virtual void invoke(api::Solver* solver, SymbolManager* sm) = 0;
+ /**
+ * Same as above, and prints the result to output stream out.
+ */
+ virtual void invoke(api::Solver* solver,
+ SymbolManager* sm,
+ std::ostream& out);
+
+ virtual void toStream(
+ std::ostream& out,
+ int toDepth = -1,
- void toStream(std::ostream& out,
- int toDepth = -1,
- bool types = false,
- size_t dag = 1,
- OutputLanguage language = language::output::LANG_AUTO) const;
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const = 0;
std::string toString() const;
@@ -244,37 +255,10 @@ class CVC4_PUBLIC Command
virtual void printResult(std::ostream& out, uint32_t verbosity = 2) const;
/**
- * Maps this Command into one for a different ExprManager, using
- * variableMap for the translation and extending it with any new
- * mappings.
- */
- virtual Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) = 0;
-
- /**
* Clone this Command (make a shallow copy).
*/
virtual Command* clone() const = 0;
- protected:
- class ExportTransformer
- {
- ExprManager* d_exprManager;
- ExprManagerMapCollection& d_variableMap;
-
- public:
- ExportTransformer(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap)
- : d_exprManager(exprManager), d_variableMap(variableMap)
- {
- }
- Expr operator()(Expr e) { return e.exportTo(d_exprManager, d_variableMap); }
- Type operator()(Type t) { return t.exportTo(d_exprManager, d_variableMap); }
- }; /* class Command::ExportTransformer */
-
- /** The solver instance that this command is associated with. */
- api::Solver* d_solver;
-
/**
* This field contains a command status if the command has been
* invoked, or NULL if it has not. This field is either a
@@ -290,7 +274,7 @@ class CVC4_PUBLIC Command
* successful execution.
*/
bool d_muted;
-}; /* class Command */
+}; /* class Command */
/**
* EmptyCommands are the residue of a command after the parser handles
@@ -301,11 +285,14 @@ class CVC4_PUBLIC EmptyCommand : public Command
public:
EmptyCommand(std::string name = "");
std::string getName() const;
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
protected:
std::string d_name;
@@ -318,12 +305,18 @@ class CVC4_PUBLIC EchoCommand : public Command
std::string getOutput() const;
- void invoke(SmtEngine* smtEngine) override;
- void invoke(SmtEngine* smtEngine, std::ostream& out) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
+ void invoke(api::Solver* solver,
+ SymbolManager* sm,
+ std::ostream& out) override;
+
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
protected:
std::string d_output;
@@ -332,39 +325,49 @@ class CVC4_PUBLIC EchoCommand : public Command
class CVC4_PUBLIC AssertCommand : public Command
{
protected:
- Expr d_expr;
+ api::Term d_term;
bool d_inUnsatCore;
public:
- AssertCommand(const Expr& e, bool inUnsatCore = true);
+ AssertCommand(const api::Term& t, bool inUnsatCore = true);
+
+ api::Term getTerm() const;
- Expr getExpr() const;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class AssertCommand */
class CVC4_PUBLIC PushCommand : public Command
{
public:
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class PushCommand */
class CVC4_PUBLIC PopCommand : public Command
{
public:
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class PopCommand */
class CVC4_PUBLIC DeclarationDefinitionCommand : public Command
@@ -375,104 +378,116 @@ class CVC4_PUBLIC DeclarationDefinitionCommand : public Command
public:
DeclarationDefinitionCommand(const std::string& id);
- void invoke(SmtEngine* smtEngine) override = 0;
+ void invoke(api::Solver* solver, SymbolManager* sm) override = 0;
std::string getSymbol() const;
}; /* class DeclarationDefinitionCommand */
class CVC4_PUBLIC DeclareFunctionCommand : public DeclarationDefinitionCommand
{
protected:
- Expr d_func;
- Type d_type;
+ api::Term d_func;
+ api::Sort d_sort;
bool d_printInModel;
bool d_printInModelSetByUser;
public:
- DeclareFunctionCommand(const std::string& id, Expr func, Type type);
- Expr getFunction() const;
- Type getType() const;
+ DeclareFunctionCommand(const std::string& id, api::Term func, api::Sort sort);
+ api::Term getFunction() const;
+ api::Sort getSort() const;
bool getPrintInModel() const;
bool getPrintInModelSetByUser() const;
void setPrintInModel(bool p);
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class DeclareFunctionCommand */
-class CVC4_PUBLIC DeclareTypeCommand : public DeclarationDefinitionCommand
+class CVC4_PUBLIC DeclareSortCommand : public DeclarationDefinitionCommand
{
protected:
size_t d_arity;
- Type d_type;
+ api::Sort d_sort;
public:
- DeclareTypeCommand(const std::string& id, size_t arity, Type t);
+ DeclareSortCommand(const std::string& id, size_t arity, api::Sort sort);
size_t getArity() const;
- Type getType() const;
+ api::Sort getSort() const;
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
-}; /* class DeclareTypeCommand */
-
-class CVC4_PUBLIC DefineTypeCommand : public DeclarationDefinitionCommand
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
+}; /* class DeclareSortCommand */
+
+class CVC4_PUBLIC DefineSortCommand : public DeclarationDefinitionCommand
{
protected:
- std::vector<Type> d_params;
- Type d_type;
+ std::vector<api::Sort> d_params;
+ api::Sort d_sort;
public:
- DefineTypeCommand(const std::string& id, Type t);
- DefineTypeCommand(const std::string& id,
- const std::vector<Type>& params,
- Type t);
+ DefineSortCommand(const std::string& id, api::Sort sort);
+ DefineSortCommand(const std::string& id,
+ const std::vector<api::Sort>& params,
+ api::Sort sort);
- const std::vector<Type>& getParameters() const;
- Type getType() const;
+ const std::vector<api::Sort>& getParameters() const;
+ api::Sort getSort() const;
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
-}; /* class DefineTypeCommand */
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
+}; /* class DefineSortCommand */
class CVC4_PUBLIC DefineFunctionCommand : public DeclarationDefinitionCommand
{
public:
DefineFunctionCommand(const std::string& id,
- Expr func,
- Expr formula,
+ api::Term func,
+ api::Term formula,
bool global);
DefineFunctionCommand(const std::string& id,
- Expr func,
- const std::vector<Expr>& formals,
- Expr formula,
+ api::Term func,
+ const std::vector<api::Term>& formals,
+ api::Term formula,
bool global);
- Expr getFunction() const;
- const std::vector<Expr>& getFormals() const;
- Expr getFormula() const;
+ api::Term getFunction() const;
+ const std::vector<api::Term>& getFormals() const;
+ api::Term getFormula() const;
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
protected:
/** The function we are defining */
- Expr d_func;
+ api::Term d_func;
/** The formal arguments for the function we are defining */
- std::vector<Expr> d_formals;
+ std::vector<api::Term> d_formals;
/** The formula corresponding to the body of the function we are defining */
- Expr d_formula;
+ api::Term d_formula;
/**
* Stores whether this definition is global (i.e. should persist when
* popping the user context.
@@ -481,25 +496,6 @@ class CVC4_PUBLIC DefineFunctionCommand : public DeclarationDefinitionCommand
}; /* class DefineFunctionCommand */
/**
- * This differs from DefineFunctionCommand only in that it instructs
- * the SmtEngine to "remember" this function for later retrieval with
- * getAssignment(). Used for :named attributes in SMT-LIBv2.
- */
-class CVC4_PUBLIC DefineNamedFunctionCommand : public DefineFunctionCommand
-{
- public:
- DefineNamedFunctionCommand(const std::string& id,
- Expr func,
- const std::vector<Expr>& formals,
- Expr formula,
- bool global);
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
- Command* clone() const override;
-}; /* class DefineNamedFunctionCommand */
-
-/**
* The command when parsing define-fun-rec or define-funs-rec.
* This command will assert a set of quantified formulas that specify
* the (mutually recursive) function definitions provided to it.
@@ -507,13 +503,11 @@ class CVC4_PUBLIC DefineNamedFunctionCommand : public DefineFunctionCommand
class CVC4_PUBLIC DefineFunctionRecCommand : public Command
{
public:
- DefineFunctionRecCommand(api::Solver* solver,
- api::Term func,
+ DefineFunctionRecCommand(api::Term func,
const std::vector<api::Term>& formals,
api::Term formula,
bool global);
- DefineFunctionRecCommand(api::Solver* solver,
- const std::vector<api::Term>& funcs,
+ DefineFunctionRecCommand(const std::vector<api::Term>& funcs,
const std::vector<std::vector<api::Term> >& formals,
const std::vector<api::Term>& formula,
bool global);
@@ -522,11 +516,14 @@ class CVC4_PUBLIC DefineFunctionRecCommand : public Command
const std::vector<std::vector<api::Term> >& getFormals() const;
const std::vector<api::Term>& getFormulas() const;
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
protected:
/** functions we are defining */
@@ -543,36 +540,67 @@ class CVC4_PUBLIC DefineFunctionRecCommand : public Command
}; /* class DefineFunctionRecCommand */
/**
+ * In separation logic inputs, which is an extension of smt2 inputs, this
+ * corresponds to the command:
+ * (declare-heap (T U))
+ * where T is the location sort and U is the data sort.
+ */
+class CVC4_PUBLIC DeclareHeapCommand : public Command
+{
+ public:
+ DeclareHeapCommand(api::Sort locSort, api::Sort dataSort);
+ api::Sort getLocationSort() const;
+ api::Sort getDataSort() const;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
+ Command* clone() const override;
+ std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
+
+ protected:
+ /** The location sort */
+ api::Sort d_locSort;
+ /** The data sort */
+ api::Sort d_dataSort;
+};
+
+/**
* The command when an attribute is set by a user. In SMT-LIBv2 this is done
* via the syntax (! expr :attr)
*/
class CVC4_PUBLIC SetUserAttributeCommand : public Command
{
public:
- SetUserAttributeCommand(const std::string& attr, Expr expr);
+ SetUserAttributeCommand(const std::string& attr, api::Term term);
SetUserAttributeCommand(const std::string& attr,
- Expr expr,
- const std::vector<Expr>& values);
+ api::Term term,
+ const std::vector<api::Term>& values);
SetUserAttributeCommand(const std::string& attr,
- Expr expr,
+ api::Term term,
const std::string& value);
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
private:
SetUserAttributeCommand(const std::string& attr,
- Expr expr,
- const std::vector<Expr>& expr_values,
- const std::string& str_value);
+ api::Term term,
+ const std::vector<api::Term>& termValues,
+ const std::string& strValue);
const std::string d_attr;
- const Expr d_expr;
- const std::vector<Expr> d_expr_values;
- const std::string d_str_value;
+ const api::Term d_term;
+ const std::vector<api::Term> d_termValues;
+ const std::string d_strValue;
}; /* class SetUserAttributeCommand */
/**
@@ -583,20 +611,23 @@ class CVC4_PUBLIC CheckSatCommand : public Command
{
public:
CheckSatCommand();
- CheckSatCommand(const Expr& expr);
+ CheckSatCommand(const api::Term& term);
- Expr getExpr() const;
- Result getResult() const;
- void invoke(SmtEngine* smtEngine) override;
+ api::Term getTerm() const;
+ api::Result getResult() const;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
private:
- Expr d_expr;
- Result d_result;
+ api::Term d_term;
+ api::Result d_result;
}; /* class CheckSatCommand */
/**
@@ -607,41 +638,47 @@ class CVC4_PUBLIC CheckSatCommand : public Command
class CVC4_PUBLIC CheckSatAssumingCommand : public Command
{
public:
- CheckSatAssumingCommand(Expr term);
- CheckSatAssumingCommand(const std::vector<Expr>& terms);
+ CheckSatAssumingCommand(api::Term term);
+ CheckSatAssumingCommand(const std::vector<api::Term>& terms);
- const std::vector<Expr>& getTerms() const;
- Result getResult() const;
- void invoke(SmtEngine* smtEngine) override;
+ const std::vector<api::Term>& getTerms() const;
+ api::Result getResult() const;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
private:
- std::vector<Expr> d_terms;
- Result d_result;
+ std::vector<api::Term> d_terms;
+ api::Result d_result;
}; /* class CheckSatAssumingCommand */
class CVC4_PUBLIC QueryCommand : public Command
{
protected:
- Expr d_expr;
- Result d_result;
+ api::Term d_term;
+ api::Result d_result;
bool d_inUnsatCore;
public:
- QueryCommand(const Expr& e, bool inUnsatCore = true);
+ QueryCommand(const api::Term& t, bool inUnsatCore = true);
- Expr getExpr() const;
- Result getResult() const;
- void invoke(SmtEngine* smtEngine) override;
+ api::Term getTerm() const;
+ api::Result getResult() const;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class QueryCommand */
/* ------------------- sygus commands ------------------ */
@@ -650,61 +687,33 @@ class CVC4_PUBLIC QueryCommand : public Command
class CVC4_PUBLIC DeclareSygusVarCommand : public DeclarationDefinitionCommand
{
public:
- DeclareSygusVarCommand(const std::string& id, Expr var, Type type);
+ DeclareSygusVarCommand(const std::string& id, api::Term var, api::Sort sort);
/** returns the declared variable */
- Expr getVar() const;
- /** returns the declared variable's type */
- Type getType() const;
+ api::Term getVar() const;
+ /** returns the declared variable's sort */
+ api::Sort getSort() const;
/** invokes this command
*
* The declared sygus variable is communicated to the SMT engine in case a
* synthesis conjecture is built later on.
*/
- void invoke(SmtEngine* smtEngine) override;
- /** exports command to given expression manager */
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
/** creates a copy of this command */
Command* clone() const override;
/** returns this command's name */
std::string getCommandName() const override;
+ /** prints this command */
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
protected:
/** the declared variable */
- Expr d_var;
- /** the declared variable's type */
- Type d_type;
-};
-
-/** Declares a sygus universal function variable */
-class CVC4_PUBLIC DeclareSygusFunctionCommand
- : public DeclarationDefinitionCommand
-{
- public:
- DeclareSygusFunctionCommand(const std::string& id, Expr func, Type type);
- /** returns the declared function variable */
- Expr getFunction() const;
- /** returns the declared function variable's type */
- Type getType() const;
- /** invokes this command
- *
- * The declared sygus function variable is communicated to the SMT engine in
- * case a synthesis conjecture is built later on.
- */
- void invoke(SmtEngine* smtEngine) override;
- /** exports command to given expression manager */
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
- /** creates a copy of this command */
- Command* clone() const override;
- /** returns this command's name */
- std::string getCommandName() const override;
-
- protected:
- /** the declared function variable */
- Expr d_func;
- /** the declared function variable's type */
- Type d_type;
+ api::Term d_var;
+ /** the declared variable's sort */
+ api::Sort d_sort;
};
/** Declares a sygus function-to-synthesize
@@ -716,73 +725,79 @@ class CVC4_PUBLIC SynthFunCommand : public DeclarationDefinitionCommand
{
public:
SynthFunCommand(const std::string& id,
- Expr func,
- Type sygusType,
+ api::Term fun,
+ const std::vector<api::Term>& vars,
+ api::Sort sort,
bool isInv,
- const std::vector<Expr>& vars);
- SynthFunCommand(const std::string& id, Expr func, Type sygusType, bool isInv);
+ api::Grammar* g);
/** returns the function-to-synthesize */
- Expr getFunction() const;
+ api::Term getFunction() const;
/** returns the input variables of the function-to-synthesize */
- const std::vector<Expr>& getVars() const;
- /** returns the sygus type of the function-to-synthesize */
- Type getSygusType() const;
+ const std::vector<api::Term>& getVars() const;
+ /** returns the sygus sort of the function-to-synthesize */
+ api::Sort getSort() const;
/** returns whether the function-to-synthesize should be an invariant */
bool isInv() const;
+ /** Get the sygus grammar given for the synth fun command */
+ const api::Grammar* getGrammar() const;
/** invokes this command
*
* The declared function-to-synthesize is communicated to the SMT engine in
* case a synthesis conjecture is built later on.
*/
- void invoke(SmtEngine* smtEngine) override;
- /** exports command to given expression manager */
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
/** creates a copy of this command */
Command* clone() const override;
/** returns this command's name */
std::string getCommandName() const override;
+ /** prints this command */
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
protected:
/** the function-to-synthesize */
- Expr d_func;
- /** sygus type of the function-to-synthesize
- *
- * If this type is a "sygus datatype" then it encodes a grammar for the
- * possible varlues of the function-to-sytnhesize
- */
- Type d_sygusType;
+ api::Term d_fun;
+ /** the input variables of the function-to-synthesize */
+ std::vector<api::Term> d_vars;
+ /** sort of the function-to-synthesize */
+ api::Sort d_sort;
/** whether the function-to-synthesize should be an invariant */
bool d_isInv;
- /** the input variables of the function-to-synthesize */
- std::vector<Expr> d_vars;
+ /** optional grammar for the possible values of the function-to-sytnhesize */
+ api::Grammar* d_grammar;
};
/** Declares a sygus constraint */
class CVC4_PUBLIC SygusConstraintCommand : public Command
{
public:
- SygusConstraintCommand(const Expr& e);
+ SygusConstraintCommand(const api::Term& t);
/** returns the declared constraint */
- Expr getExpr() const;
+ api::Term getTerm() const;
/** invokes this command
*
* The declared constraint is communicated to the SMT engine in case a
* synthesis conjecture is built later on.
*/
- void invoke(SmtEngine* smtEngine) override;
- /** exports command to given expression manager */
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
/** creates a copy of this command */
Command* clone() const override;
/** returns this command's name */
std::string getCommandName() const override;
+ /** prints this command */
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
protected:
/** the declared constraint */
- Expr d_expr;
+ api::Term d_term;
};
/** Declares a sygus invariant constraint
@@ -798,33 +813,36 @@ class CVC4_PUBLIC SygusConstraintCommand : public Command
class CVC4_PUBLIC SygusInvConstraintCommand : public Command
{
public:
- SygusInvConstraintCommand(const std::vector<Expr>& predicates);
- SygusInvConstraintCommand(const Expr& inv,
- const Expr& pre,
- const Expr& trans,
- const Expr& post);
+ SygusInvConstraintCommand(const std::vector<api::Term>& predicates);
+ SygusInvConstraintCommand(const api::Term& inv,
+ const api::Term& pre,
+ const api::Term& trans,
+ const api::Term& post);
/** returns the place holder predicates */
- const std::vector<Expr>& getPredicates() const;
+ const std::vector<api::Term>& getPredicates() const;
/** invokes this command
*
* The place holders are communicated to the SMT engine and the actual
* invariant constraint is built, in case an actual synthesis conjecture is
* built later on.
*/
- void invoke(SmtEngine* smtEngine) override;
- /** exports command to given expression manager */
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
/** creates a copy of this command */
Command* clone() const override;
/** returns this command's name */
std::string getCommandName() const override;
+ /** prints this command */
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
protected:
/** the place holder predicates with which to build the actual constraint
* (i.e. the invariant, precondition, transition relation and postcondition)
*/
- std::vector<Expr> d_predicates;
+ std::vector<api::Term> d_predicates;
};
/** Declares a synthesis conjecture */
@@ -833,7 +851,7 @@ class CVC4_PUBLIC CheckSynthCommand : public Command
public:
CheckSynthCommand(){};
/** returns the result of the check-synth call */
- Result getResult() const;
+ api::Result getResult() const;
/** prints the result of the check-synth-call */
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
/** invokes this command
@@ -844,18 +862,21 @@ class CVC4_PUBLIC CheckSynthCommand : public Command
* and then perform a satisfiability check, whose result is stored in
* d_result.
*/
- void invoke(SmtEngine* smtEngine) override;
- /** exports command to given expression manager */
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
/** creates a copy of this command */
Command* clone() const override;
/** returns this command's name */
std::string getCommandName() const override;
+ /** prints this command */
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
protected:
/** result of the check-synth call */
- Result d_result;
+ api::Result d_result;
/** string stream that stores the output of the solution */
std::stringstream d_solution;
};
@@ -866,59 +887,46 @@ class CVC4_PUBLIC CheckSynthCommand : public Command
class CVC4_PUBLIC SimplifyCommand : public Command
{
protected:
- Expr d_term;
- Expr d_result;
+ api::Term d_term;
+ api::Term d_result;
public:
- SimplifyCommand(Expr term);
+ SimplifyCommand(api::Term term);
- Expr getTerm() const;
- Expr getResult() const;
- void invoke(SmtEngine* smtEngine) override;
+ api::Term getTerm() const;
+ api::Term getResult() const;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class SimplifyCommand */
-class CVC4_PUBLIC ExpandDefinitionsCommand : public Command
-{
- protected:
- Expr d_term;
- Expr d_result;
-
- public:
- ExpandDefinitionsCommand(Expr term);
-
- Expr getTerm() const;
- Expr getResult() const;
- void invoke(SmtEngine* smtEngine) override;
- void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
- Command* clone() const override;
- std::string getCommandName() const override;
-}; /* class ExpandDefinitionsCommand */
-
class CVC4_PUBLIC GetValueCommand : public Command
{
protected:
- std::vector<Expr> d_terms;
- Expr d_result;
+ std::vector<api::Term> d_terms;
+ api::Term d_result;
public:
- GetValueCommand(Expr term);
- GetValueCommand(const std::vector<Expr>& terms);
+ GetValueCommand(api::Term term);
+ GetValueCommand(const std::vector<api::Term>& terms);
- const std::vector<Expr>& getTerms() const;
- Expr getResult() const;
- void invoke(SmtEngine* smtEngine) override;
+ const std::vector<api::Term>& getTerms() const;
+ api::Term getResult() const;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class GetValueCommand */
class CVC4_PUBLIC GetAssignmentCommand : public Command
@@ -930,12 +938,15 @@ class CVC4_PUBLIC GetAssignmentCommand : public Command
GetAssignmentCommand();
SExpr getResult() const;
- void invoke(SmtEngine* smtEngine) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class GetAssignmentCommand */
class CVC4_PUBLIC GetModelCommand : public Command
@@ -945,16 +956,18 @@ class CVC4_PUBLIC GetModelCommand : public Command
// Model is private to the library -- for now
// Model* getResult() const ;
- void invoke(SmtEngine* smtEngine) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
protected:
- Model* d_result;
- SmtEngine* d_smtEngine;
+ smt::Model* d_result;
}; /* class GetModelCommand */
/** The command to block models. */
@@ -963,29 +976,35 @@ class CVC4_PUBLIC BlockModelCommand : public Command
public:
BlockModelCommand();
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class BlockModelCommand */
/** The command to block model values. */
class CVC4_PUBLIC BlockModelValuesCommand : public Command
{
public:
- BlockModelValuesCommand(const std::vector<Expr>& terms);
+ BlockModelValuesCommand(const std::vector<api::Term>& terms);
- const std::vector<Expr>& getTerms() const;
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ const std::vector<api::Term>& getTerms() const;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
protected:
/** The terms we are blocking */
- std::vector<Expr> d_terms;
+ std::vector<api::Term> d_terms;
}; /* class BlockModelValuesCommand */
class CVC4_PUBLIC GetProofCommand : public Command
@@ -993,18 +1012,14 @@ class CVC4_PUBLIC GetProofCommand : public Command
public:
GetProofCommand();
- const Proof& getResult() const;
- void invoke(SmtEngine* smtEngine) override;
- void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
-
- protected:
- SmtEngine* d_smtEngine;
- // d_result is owned by d_smtEngine.
- const Proof* d_result;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class GetProofCommand */
class CVC4_PUBLIC GetInstantiationsCommand : public Command
@@ -1012,15 +1027,18 @@ class CVC4_PUBLIC GetInstantiationsCommand : public Command
public:
GetInstantiationsCommand();
- void invoke(SmtEngine* smtEngine) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
protected:
- SmtEngine* d_smtEngine;
+ api::Solver* d_solver;
}; /* class GetInstantiationsCommand */
class CVC4_PUBLIC GetSynthSolutionCommand : public Command
@@ -1028,18 +1046,21 @@ class CVC4_PUBLIC GetSynthSolutionCommand : public Command
public:
GetSynthSolutionCommand();
- void invoke(SmtEngine* smtEngine) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
protected:
- SmtEngine* d_smtEngine;
+ api::Solver* d_solver;
}; /* class GetSynthSolutionCommand */
-/** The command (get-interpol s B)
+/** The command (get-interpol s B (G)?)
*
* This command asks for an interpolant from the current set of assertions and
* conjecture (goal) B.
@@ -1051,40 +1072,35 @@ class CVC4_PUBLIC GetSynthSolutionCommand : public Command
class CVC4_PUBLIC GetInterpolCommand : public Command
{
public:
- GetInterpolCommand(api::Solver* solver,
- const std::string& name,
- api::Term conj);
- /** The argument gtype is the grammar of the interpolation query */
- GetInterpolCommand(api::Solver* solver,
- const std::string& name,
- api::Term conj,
- const Type& gtype);
+ GetInterpolCommand(const std::string& name, api::Term conj);
+ /** The argument g is the grammar of the interpolation query */
+ GetInterpolCommand(const std::string& name, api::Term conj, api::Grammar* g);
/** Get the conjecture of the interpolation query */
api::Term getConjecture() const;
- /** Get the grammar sygus datatype type given for the interpolation query */
- Type getGrammarType() const;
+ /** Get the sygus grammar given for the interpolation query */
+ const api::Grammar* getGrammar() const;
/** Get the result of the query, which is the solution to the interpolation
* query. */
api::Term getResult() const;
- void invoke(SmtEngine* smtEngine) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
protected:
/** The name of the interpolation predicate */
std::string d_name;
/** The conjecture of the interpolation query */
api::Term d_conj;
- /**
- * The (optional) grammar of the interpolation query, expressed as a sygus
- * datatype type.
- */
- Type d_sygus_grammar_type;
+ /** The (optional) grammar of the interpolation query */
+ api::Grammar* d_sygus_grammar;
/** the return status of the command */
bool d_resultStatus;
/** the return expression of the command */
@@ -1100,104 +1116,115 @@ class CVC4_PUBLIC GetInterpolCommand : public Command
* find a predicate P, then the output response of this command is:
* (define-fun s () Bool P)
*
- * A grammar type G can be optionally provided to indicate the syntactic
- * restrictions on the possible solutions returned.
+ * A grammar G can be optionally provided to indicate the syntactic restrictions
+ * on the possible solutions returned.
*/
class CVC4_PUBLIC GetAbductCommand : public Command
{
public:
- GetAbductCommand();
- GetAbductCommand(const std::string& name, Expr conj);
- GetAbductCommand(const std::string& name, Expr conj, const Type& gtype);
+ GetAbductCommand(const std::string& name, api::Term conj);
+ GetAbductCommand(const std::string& name, api::Term conj, api::Grammar* g);
/** Get the conjecture of the abduction query */
- Expr getConjecture() const;
- /** Get the grammar type given for the abduction query */
- Type getGrammarType() const;
+ api::Term getConjecture() const;
+ /** Get the grammar given for the abduction query */
+ const api::Grammar* getGrammar() const;
/** Get the name of the abduction predicate for the abduction query */
std::string getAbductName() const;
/** Get the result of the query, which is the solution to the abduction query.
*/
- Expr getResult() const;
+ api::Term getResult() const;
- void invoke(SmtEngine* smtEngine) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
protected:
/** The name of the abduction predicate */
std::string d_name;
/** The conjecture of the abduction query */
- Expr d_conj;
- /**
- * The (optional) grammar of the abduction query, expressed as a sygus
- * datatype type.
- */
- Type d_sygus_grammar_type;
+ api::Term d_conj;
+ /** The (optional) grammar of the abduction query */
+ api::Grammar* d_sygus_grammar;
/** the return status of the command */
bool d_resultStatus;
/** the return expression of the command */
- Expr d_result;
+ api::Term d_result;
}; /* class GetAbductCommand */
class CVC4_PUBLIC GetQuantifierEliminationCommand : public Command
{
protected:
- Expr d_expr;
+ api::Term d_term;
bool d_doFull;
- Expr d_result;
+ api::Term d_result;
public:
GetQuantifierEliminationCommand();
- GetQuantifierEliminationCommand(const Expr& expr, bool doFull);
+ GetQuantifierEliminationCommand(const api::Term& term, bool doFull);
- Expr getExpr() const;
+ api::Term getTerm() const;
bool getDoFull() const;
- void invoke(SmtEngine* smtEngine) override;
- Expr getResult() const;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
+ api::Term getResult() const;
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class GetQuantifierEliminationCommand */
class CVC4_PUBLIC GetUnsatAssumptionsCommand : public Command
{
public:
GetUnsatAssumptionsCommand();
- void invoke(SmtEngine* smtEngine) override;
- std::vector<Expr> getResult() const;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
+ std::vector<api::Term> getResult() const;
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
+
protected:
- std::vector<Expr> d_result;
+ std::vector<api::Term> d_result;
}; /* class GetUnsatAssumptionsCommand */
class CVC4_PUBLIC GetUnsatCoreCommand : public Command
{
public:
GetUnsatCoreCommand();
- const UnsatCore& getUnsatCore() const;
+ const std::vector<api::Term>& getUnsatCore() const;
- void invoke(SmtEngine* smtEngine) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
protected:
- // the result of the unsat core call
- UnsatCore d_result;
+ /** The symbol manager we were invoked with */
+ SymbolManager* d_sm;
+ /** the result of the unsat core call */
+ std::vector<api::Term> d_result;
}; /* class GetUnsatCoreCommand */
class CVC4_PUBLIC GetAssertionsCommand : public Command
@@ -1208,13 +1235,16 @@ class CVC4_PUBLIC GetAssertionsCommand : public Command
public:
GetAssertionsCommand();
- void invoke(SmtEngine* smtEngine) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
std::string getResult() const;
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class GetAssertionsCommand */
class CVC4_PUBLIC SetBenchmarkStatusCommand : public Command
@@ -1227,11 +1257,14 @@ class CVC4_PUBLIC SetBenchmarkStatusCommand : public Command
BenchmarkStatus getStatus() const;
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class SetBenchmarkStatusCommand */
class CVC4_PUBLIC SetBenchmarkLogicCommand : public Command
@@ -1243,11 +1276,14 @@ class CVC4_PUBLIC SetBenchmarkLogicCommand : public Command
SetBenchmarkLogicCommand(std::string logic);
std::string getLogic() const;
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class SetBenchmarkLogicCommand */
class CVC4_PUBLIC SetInfoCommand : public Command
@@ -1262,11 +1298,14 @@ class CVC4_PUBLIC SetInfoCommand : public Command
std::string getFlag() const;
SExpr getSExpr() const;
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class SetInfoCommand */
class CVC4_PUBLIC GetInfoCommand : public Command
@@ -1281,12 +1320,15 @@ class CVC4_PUBLIC GetInfoCommand : public Command
std::string getFlag() const;
std::string getResult() const;
- void invoke(SmtEngine* smtEngine) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class GetInfoCommand */
class CVC4_PUBLIC SetOptionCommand : public Command
@@ -1301,11 +1343,14 @@ class CVC4_PUBLIC SetOptionCommand : public Command
std::string getFlag() const;
SExpr getSExpr() const;
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class SetOptionCommand */
class CVC4_PUBLIC GetOptionCommand : public Command
@@ -1320,85 +1365,77 @@ class CVC4_PUBLIC GetOptionCommand : public Command
std::string getFlag() const;
std::string getResult() const;
- void invoke(SmtEngine* smtEngine) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
void printResult(std::ostream& out, uint32_t verbosity = 2) const override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class GetOptionCommand */
-// Set expression name command
-// Note this is not an official smt2 command
-// Conceptually:
-// (assert (! expr :named name))
-// is converted to
-// (assert expr)
-// (set-expr-name expr name)
-class CVC4_PUBLIC SetExpressionNameCommand : public Command
-{
- protected:
- Expr d_expr;
- std::string d_name;
-
- public:
- SetExpressionNameCommand(Expr expr, std::string name);
-
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
- Command* clone() const override;
- std::string getCommandName() const override;
-}; /* class SetExpressionNameCommand */
-
class CVC4_PUBLIC DatatypeDeclarationCommand : public Command
{
private:
- std::vector<Type> d_datatypes;
+ std::vector<api::Sort> d_datatypes;
public:
- DatatypeDeclarationCommand(const Type& datatype);
+ DatatypeDeclarationCommand(const api::Sort& datatype);
- DatatypeDeclarationCommand(const std::vector<Type>& datatypes);
- const std::vector<Type>& getDatatypes() const;
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ DatatypeDeclarationCommand(const std::vector<api::Sort>& datatypes);
+ const std::vector<api::Sort>& getDatatypes() const;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class DatatypeDeclarationCommand */
class CVC4_PUBLIC ResetCommand : public Command
{
public:
ResetCommand() {}
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class ResetCommand */
class CVC4_PUBLIC ResetAssertionsCommand : public Command
{
public:
ResetAssertionsCommand() {}
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class ResetAssertionsCommand */
class CVC4_PUBLIC QuitCommand : public Command
{
public:
QuitCommand() {}
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class QuitCommand */
class CVC4_PUBLIC CommentCommand : public Command
@@ -1410,16 +1447,19 @@ class CVC4_PUBLIC CommentCommand : public Command
std::string getComment() const;
- void invoke(SmtEngine* smtEngine) override;
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class CommentCommand */
class CVC4_PUBLIC CommandSequence : public Command
{
- private:
+ protected:
/** All the commands to be executed (in sequence) */
std::vector<Command*> d_commandSequence;
/** Next command to be executed */
@@ -1432,8 +1472,10 @@ class CVC4_PUBLIC CommandSequence : public Command
void addCommand(Command* cmd);
void clear();
- void invoke(SmtEngine* smtEngine) override;
- void invoke(SmtEngine* smtEngine, std::ostream& out) override;
+ void invoke(api::Solver* solver, SymbolManager* sm) override;
+ void invoke(api::Solver* solver,
+ SymbolManager* sm,
+ std::ostream& out) override;
typedef std::vector<Command*>::iterator iterator;
typedef std::vector<Command*>::const_iterator const_iterator;
@@ -1444,16 +1486,24 @@ class CVC4_PUBLIC CommandSequence : public Command
iterator begin();
iterator end();
- Command* exportTo(ExprManager* exprManager,
- ExprManagerMapCollection& variableMap) override;
Command* clone() const override;
std::string getCommandName() const override;
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
}; /* class CommandSequence */
class CVC4_PUBLIC DeclarationSequence : public CommandSequence
{
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
};
-} /* CVC4 namespace */
+} // namespace CVC4
#endif /* CVC4__COMMAND_H */
diff --git a/src/smt/command_list.cpp b/src/smt/command_list.cpp
deleted file mode 100644
index a88efbbec..000000000
--- a/src/smt/command_list.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-/********************* */
-/*! \file command_list.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Morgan Deters
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief A context-sensitive list of Commands, and their cleanup
- **
- ** A context-sensitive list of Commands, and their cleanup.
- **/
-
-// we include both of these to make sure they agree on the typedef
-#include "smt/command.h"
-#include "smt/command_list.h"
-#include "smt/smt_engine.h"
-
-namespace CVC4 {
-namespace smt {
-
-void CommandCleanup::operator()(Command** c) {
- delete *c;
-}
-
-}/* CVC4::smt namespace */
-}/* CVC4 namespace */
diff --git a/src/smt/command_list.h b/src/smt/command_list.h
deleted file mode 100644
index cdc8e4c22..000000000
--- a/src/smt/command_list.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/********************* */
-/*! \file command_list.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Morgan Deters, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief A context-sensitive list of Commands, and their cleanup
- **
- ** A context-sensitive list of Commands, and their cleanup.
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__SMT__COMMAND_LIST_H
-#define CVC4__SMT__COMMAND_LIST_H
-
-#include "context/cdlist.h"
-
-namespace CVC4 {
-
-class Command;
-
-namespace smt {
-
-struct CommandCleanup {
- void operator()(Command** c);
-};/* struct CommandCleanup */
-
-typedef context::CDList<Command*, CommandCleanup> CommandList;
-
-}/* CVC4::smt namespace */
-}/* CVC4 namespace */
-
-#endif /* CVC4__SMT__COMMAND_LIST_H */
diff --git a/src/smt/defined_function.h b/src/smt/defined_function.h
index afac2df58..c2e594fe7 100644
--- a/src/smt/defined_function.h
+++ b/src/smt/defined_function.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -34,7 +34,7 @@ class DefinedFunction
{
public:
DefinedFunction() {}
- DefinedFunction(Node func, std::vector<Node>& formals, Node formula)
+ DefinedFunction(Node func, const std::vector<Node>& formals, Node formula)
: d_func(func), d_formals(formals), d_formula(formula)
{
}
diff --git a/src/smt/dump.cpp b/src/smt/dump.cpp
index d8d486e12..ceb0eb11f 100644
--- a/src/smt/dump.cpp
+++ b/src/smt/dump.cpp
@@ -5,7 +5,7 @@
** Andres Noetzli, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,9 +19,41 @@
#include "base/output.h"
#include "lib/strtok_r.h"
#include "preprocessing/preprocessing_pass_registry.h"
+#include "smt/command.h"
+#include "smt/node_command.h"
namespace CVC4 {
+#if defined(CVC4_DUMPING) && !defined(CVC4_MUZZLE)
+
+CVC4dumpstream& CVC4dumpstream::operator<<(const Command& c)
+{
+ if (d_os != nullptr)
+ {
+ (*d_os) << c;
+ }
+ return *this;
+}
+
+CVC4dumpstream& CVC4dumpstream::operator<<(const NodeCommand& nc)
+{
+ if (d_os != nullptr)
+ {
+ (*d_os) << nc;
+ }
+ return *this;
+}
+
+#else
+
+CVC4dumpstream& CVC4dumpstream::operator<<(const Command& c) { return *this; }
+CVC4dumpstream& CVC4dumpstream::operator<<(const NodeCommand& nc)
+{
+ return *this;
+}
+
+#endif /* CVC4_DUMPING && !CVC4_MUZZLE */
+
DumpC DumpChannel CVC4_PUBLIC;
std::ostream& DumpC::setStream(std::ostream* os) {
@@ -100,42 +132,6 @@ void DumpC::setDumpFromString(const std::string& optarg) {
|| !strcmp(optargPtr, "bv-rewrites")
|| !strcmp(optargPtr, "theory::fullcheck"))
{
- // These are "non-state-dumping" modes. If state (SAT decisions,
- // propagations, etc.) is dumped, it will interfere with the validity
- // of these generated queries.
- if (Dump.isOn("state"))
- {
- throw OptionException(std::string("dump option `") + optargPtr +
- "' conflicts with a previous, "
- "state-dumping dump option. You cannot "
- "mix stateful and non-stateful dumping modes; "
- "see --dump help.");
- }
- else
- {
- Dump.on("no-permit-state");
- }
- }
- else if (!strcmp(optargPtr, "state")
- || !strcmp(optargPtr, "missed-t-conflicts")
- || !strcmp(optargPtr, "t-propagations")
- || !strcmp(optargPtr, "missed-t-propagations"))
- {
- // These are "state-dumping" modes. If state (SAT decisions,
- // propagations, etc.) is not dumped, it will interfere with the
- // validity of these generated queries.
- if (Dump.isOn("no-permit-state"))
- {
- throw OptionException(std::string("dump option `") + optargPtr +
- "' conflicts with a previous, "
- "non-state-dumping dump option. You cannot "
- "mix stateful and non-stateful dumping modes; "
- "see --dump help.");
- }
- else
- {
- Dump.on("state");
- }
}
else if (!strcmp(optargPtr, "help"))
{
@@ -152,14 +148,6 @@ void DumpC::setDumpFromString(const std::string& optarg) {
puts(ss.str().c_str());
exit(1);
}
- else if (!strcmp(optargPtr, "bv-abstraction"))
- {
- Dump.on("bv-abstraction");
- }
- else if (!strcmp(optargPtr, "bv-algebraic"))
- {
- Dump.on("bv-algebraic");
- }
else
{
throw OptionException(std::string("unknown option for --dump: `")
@@ -222,49 +210,25 @@ clauses\n\
+ Do all the preprocessing outlined above, and dump the CNF-converted\n\
output\n\
\n\
-state\n\
-+ Dump all contextual assertions (e.g., SAT decisions, propagations..).\n\
- Implied by all \"stateful\" modes below and conflicts with all\n\
- non-stateful modes below.\n\
-\n\
-t-conflicts [non-stateful]\n\
+t-conflicts\n\
+ Output correctness queries for all theory conflicts\n\
\n\
-missed-t-conflicts [stateful]\n\
-+ Output completeness queries for theory conflicts\n\
-\n\
-t-propagations [stateful]\n\
-+ Output correctness queries for all theory propagations\n\
-\n\
-missed-t-propagations [stateful]\n\
-+ Output completeness queries for theory propagations (LARGE and EXPENSIVE)\n\
-\n\
-t-lemmas [non-stateful]\n\
+t-lemmas\n\
+ Output correctness queries for all theory lemmas\n\
\n\
-t-explanations [non-stateful]\n\
+t-explanations\n\
+ Output correctness queries for all theory explanations\n\
\n\
-bv-rewrites [non-stateful]\n\
+bv-rewrites\n\
+ Output correctness queries for all bitvector rewrites\n\
\n\
-bv-abstraction [non-stateful]\n\
-+ Output correctness queries for all bv abstraction \n\
-\n\
-bv-algebraic [non-stateful]\n\
-+ Output correctness queries for bv algebraic solver. \n\
-\n\
-theory::fullcheck [non-stateful]\n\
+theory::fullcheck\n\
+ Output completeness queries for all full-check effort-level theory checks\n\
\n\
Dump modes can be combined with multiple uses of --dump. Generally you want\n\
raw-benchmark or, alternatively, one from the assertions category (either\n\
-assertions or clauses), and perhaps one or more stateful or non-stateful modes\n\
+assertions or clauses), and perhaps one or more other modes\n\
for checking correctness and completeness of decision procedure implementations.\n\
-Stateful modes dump the contextual assertions made by the core solver (all\n\
-decisions and propagations as assertions); this affects the validity of the\n\
-resulting correctness and completeness queries, so of course stateful and\n\
-non-stateful modes cannot be mixed in the same run.\n\
\n\
The --output-language option controls the language used for dumping, and\n\
this allows you to connect CVC4 to another solver implementation via a UNIX\n\
diff --git a/src/smt/dump.h b/src/smt/dump.h
index 050935422..6d355e317 100644
--- a/src/smt/dump.h
+++ b/src/smt/dump.h
@@ -2,10 +2,10 @@
/*! \file dump.h
** \verbatim
** Top contributors (to current version):
- ** Morgan Deters, Andres Noetzli, Tim King
+ ** Morgan Deters, Andres Noetzli, Abdalrhman Mohamed
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,10 +20,12 @@
#define CVC4__DUMP_H
#include "base/output.h"
-#include "smt/command.h"
namespace CVC4 {
+class Command;
+class NodeCommand;
+
#if defined(CVC4_DUMPING) && !defined(CVC4_MUZZLE)
class CVC4_PUBLIC CVC4dumpstream
@@ -32,13 +34,14 @@ class CVC4_PUBLIC CVC4dumpstream
CVC4dumpstream() : d_os(nullptr) {}
CVC4dumpstream(std::ostream& os) : d_os(&os) {}
- CVC4dumpstream& operator<<(const Command& c) {
- if (d_os != nullptr)
- {
- (*d_os) << c << std::endl;
- }
- return *this;
- }
+ CVC4dumpstream& operator<<(const Command& c);
+
+ /** A convenience function for dumping internal commands.
+ *
+ * Since Commands are now part of the public API, internal code should use
+ * NodeCommands and this function (instead of the one above) to dump them.
+ */
+ CVC4dumpstream& operator<<(const NodeCommand& nc);
private:
std::ostream* d_os;
@@ -55,7 +58,8 @@ class CVC4_PUBLIC CVC4dumpstream
public:
CVC4dumpstream() {}
CVC4dumpstream(std::ostream& os) {}
- CVC4dumpstream& operator<<(const Command& c) { return *this; }
+ CVC4dumpstream& operator<<(const Command& c);
+ CVC4dumpstream& operator<<(const NodeCommand& nc);
}; /* class CVC4dumpstream */
#endif /* CVC4_DUMPING && !CVC4_MUZZLE */
diff --git a/src/smt/dump_manager.cpp b/src/smt/dump_manager.cpp
new file mode 100644
index 000000000..9b7fba5a2
--- /dev/null
+++ b/src/smt/dump_manager.cpp
@@ -0,0 +1,145 @@
+/********************* */
+/*! \file dump_manager.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Morgan Deters, Abdalrhman Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of the dump manager.
+ **/
+
+#include "smt/dump_manager.h"
+
+#include "expr/expr_manager.h"
+#include "options/smt_options.h"
+#include "smt/dump.h"
+#include "smt/node_command.h"
+
+namespace CVC4 {
+namespace smt {
+
+DumpManager::DumpManager(context::UserContext* u)
+ : d_fullyInited(false),
+ d_modelGlobalCommands(),
+ d_modelCommands(u),
+ d_dumpCommands()
+{
+}
+
+DumpManager::~DumpManager()
+{
+ d_dumpCommands.clear();
+ d_modelCommandsAlloc.clear();
+ d_modelGlobalCommands.clear();
+}
+
+void DumpManager::finishInit()
+{
+ Trace("smt-debug") << "Dump declaration commands..." << std::endl;
+ // dump out any pending declaration commands
+ for (size_t i = 0, ncoms = d_dumpCommands.size(); i < ncoms; ++i)
+ {
+ Dump("declarations") << *d_dumpCommands[i];
+ }
+ d_dumpCommands.clear();
+
+ d_fullyInited = true;
+}
+
+void DumpManager::resetAssertions() { d_modelGlobalCommands.clear(); }
+
+void DumpManager::addToModelCommandAndDump(const NodeCommand& c,
+ uint32_t flags,
+ bool userVisible,
+ const char* dumpTag)
+{
+ Trace("smt") << "SMT addToModelCommandAndDump(" << c << ")" << std::endl;
+ // If we aren't yet fully inited, the user might still turn on
+ // produce-models. So let's keep any commands around just in
+ // case. This is useful in two cases: (1) SMT-LIBv1 auto-declares
+ // sort "U" in QF_UF before setLogic() is run and we still want to
+ // support finding card(U) with --finite-model-find, and (2) to
+ // decouple SmtEngine and ExprManager if the user does a few
+ // ExprManager::mkSort() before SmtEngine::setOption("produce-models")
+ // and expects to find their cardinalities in the model.
+ if ((!d_fullyInited || options::produceModels())
+ && (flags & ExprManager::VAR_FLAG_DEFINED) == 0)
+ {
+ if (flags & ExprManager::VAR_FLAG_GLOBAL)
+ {
+ d_modelGlobalCommands.push_back(std::unique_ptr<NodeCommand>(c.clone()));
+ }
+ else
+ {
+ NodeCommand* cc = c.clone();
+ d_modelCommands.push_back(cc);
+ // also remember for memory management purposes
+ d_modelCommandsAlloc.push_back(std::unique_ptr<NodeCommand>(cc));
+ }
+ }
+ if (Dump.isOn(dumpTag))
+ {
+ if (d_fullyInited)
+ {
+ Dump(dumpTag) << c;
+ }
+ else
+ {
+ d_dumpCommands.push_back(std::unique_ptr<NodeCommand>(c.clone()));
+ }
+ }
+}
+
+void DumpManager::setPrintFuncInModel(Node f, bool p)
+{
+ Trace("setp-model") << "Set printInModel " << f << " to " << p << std::endl;
+ for (std::unique_ptr<NodeCommand>& c : d_modelGlobalCommands)
+ {
+ DeclareFunctionNodeCommand* dfc =
+ dynamic_cast<DeclareFunctionNodeCommand*>(c.get());
+ if (dfc != NULL)
+ {
+ Node df = dfc->getFunction();
+ if (df == f)
+ {
+ dfc->setPrintInModel(p);
+ }
+ }
+ }
+ for (NodeCommand* c : d_modelCommands)
+ {
+ DeclareFunctionNodeCommand* dfc =
+ dynamic_cast<DeclareFunctionNodeCommand*>(c);
+ if (dfc != NULL)
+ {
+ Node df = dfc->getFunction();
+ if (df == f)
+ {
+ dfc->setPrintInModel(p);
+ }
+ }
+ }
+}
+
+size_t DumpManager::getNumModelCommands() const
+{
+ return d_modelCommands.size() + d_modelGlobalCommands.size();
+}
+
+const NodeCommand* DumpManager::getModelCommand(size_t i) const
+{
+ Assert(i < getNumModelCommands());
+ // index the global commands first, then the locals
+ if (i < d_modelGlobalCommands.size())
+ {
+ return d_modelGlobalCommands[i].get();
+ }
+ return d_modelCommands[i - d_modelGlobalCommands.size()];
+}
+
+} // namespace smt
+} // namespace CVC4
diff --git a/src/smt/dump_manager.h b/src/smt/dump_manager.h
new file mode 100644
index 000000000..0ba8e0b8b
--- /dev/null
+++ b/src/smt/dump_manager.h
@@ -0,0 +1,108 @@
+/********************* */
+/*! \file dump_manager.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Morgan Deters, Abdalrhman Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The dump manager of the SmtEngine.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__SMT__DUMP_MANAGER_H
+#define CVC4__SMT__DUMP_MANAGER_H
+
+#include <memory>
+#include <vector>
+
+#include "context/cdlist.h"
+#include "expr/node.h"
+
+namespace CVC4 {
+
+class NodeCommand;
+
+namespace smt {
+
+/**
+ * This utility is responsible for:
+ * (1) storing information required for SMT-LIB queries such as get-model,
+ * which requires knowing what symbols are declared and should be printed in
+ * the model.
+ * (2) implementing some dumping traces e.g. --dump=declarations.
+ */
+class DumpManager
+{
+ typedef context::CDList<NodeCommand*> CommandList;
+
+ public:
+ DumpManager(context::UserContext* u);
+ ~DumpManager();
+ /**
+ * Finish init, called during SmtEngine::finishInit, which is triggered
+ * when initialization of options is finished.
+ */
+ void finishInit();
+ /**
+ * Reset assertions, called on SmtEngine::resetAssertions.
+ */
+ void resetAssertions();
+ /**
+ * Add to Model command. This is used for recording a command
+ * that should be reported during a get-model call.
+ */
+ void addToModelCommandAndDump(const NodeCommand& c,
+ uint32_t flags = 0,
+ bool userVisible = true,
+ const char* dumpTag = "declarations");
+
+ /**
+ * Set that function f should print in the model if and only if p is true.
+ */
+ void setPrintFuncInModel(Node f, bool p);
+ /** get number of commands to report in a model */
+ size_t getNumModelCommands() const;
+ /** get model command at index i */
+ const NodeCommand* getModelCommand(size_t i) const;
+
+ private:
+ /** Fully inited */
+ bool d_fullyInited;
+
+ /**
+ * A list of commands that should be in the Model globally (i.e.,
+ * regardless of push/pop). Only maintained if produce-models option
+ * is on.
+ */
+ std::vector<std::unique_ptr<NodeCommand>> d_modelGlobalCommands;
+
+ /**
+ * A list of commands that should be in the Model locally (i.e.,
+ * it is context-dependent on push/pop). Only maintained if
+ * produce-models option is on.
+ */
+ CommandList d_modelCommands;
+ /**
+ * A list of model commands allocated to d_modelCommands at any time. This
+ * is maintained for memory management purposes.
+ */
+ std::vector<std::unique_ptr<NodeCommand>> d_modelCommandsAlloc;
+
+ /**
+ * A vector of declaration commands waiting to be dumped out.
+ * Once the SmtEngine is fully initialized, we'll dump them.
+ * This ensures the declarations come after the set-logic and
+ * any necessary set-option commands are dumped.
+ */
+ std::vector<std::unique_ptr<NodeCommand>> d_dumpCommands;
+};
+
+} // namespace smt
+} // namespace CVC4
+
+#endif
diff --git a/src/smt/interpolation_solver.cpp b/src/smt/interpolation_solver.cpp
new file mode 100644
index 000000000..c47d99951
--- /dev/null
+++ b/src/smt/interpolation_solver.cpp
@@ -0,0 +1,137 @@
+/********************* */
+/*! \file interpolation_solver.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Ying Sheng
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The solver for interpolation queries
+ **/
+
+#include "smt/interpolation_solver.h"
+
+#include "options/smt_options.h"
+#include "smt/smt_engine.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
+#include "theory/quantifiers/sygus/sygus_grammar_cons.h"
+#include "theory/quantifiers/sygus/sygus_interpol.h"
+#include "theory/smt_engine_subsolver.h"
+
+using namespace CVC4::theory;
+
+namespace CVC4 {
+namespace smt {
+
+InterpolationSolver::InterpolationSolver(SmtEngine* parent) : d_parent(parent)
+{
+}
+
+InterpolationSolver::~InterpolationSolver() {}
+
+bool InterpolationSolver::getInterpol(const Node& conj,
+ const TypeNode& grammarType,
+ Node& interpol)
+{
+ if (options::produceInterpols() == options::ProduceInterpols::NONE)
+ {
+ const char* msg =
+ "Cannot get interpolation when produce-interpol options is off.";
+ throw ModalException(msg);
+ }
+ Trace("sygus-interpol") << "SmtEngine::getInterpol: conjecture " << conj
+ << std::endl;
+ std::vector<Node> axioms = d_parent->getExpandedAssertions();
+ // must expand definitions
+ Node conjn = d_parent->expandDefinitions(conj);
+ std::string name("A");
+
+ quantifiers::SygusInterpol interpolSolver;
+ if (interpolSolver.solveInterpolation(
+ name, axioms, conjn, grammarType, interpol))
+ {
+ if (options::checkInterpols())
+ {
+ checkInterpol(interpol.toExpr(), axioms, conj);
+ }
+ return true;
+ }
+ return false;
+}
+
+bool InterpolationSolver::getInterpol(const Node& conj, Node& interpol)
+{
+ TypeNode grammarType;
+ return getInterpol(conj, grammarType, interpol);
+}
+
+void InterpolationSolver::checkInterpol(Node interpol,
+ const std::vector<Node>& easserts,
+ const Node& conj)
+{
+ Assert(interpol.getType().isBoolean());
+ Trace("check-interpol") << "SmtEngine::checkInterpol: get expanded assertions"
+ << std::endl;
+
+ // two checks: first, axioms imply interpol, second, interpol implies conj.
+ for (unsigned j = 0; j < 2; j++)
+ {
+ if (j == 1)
+ {
+ Trace("check-interpol") << "SmtEngine::checkInterpol: conjecture is "
+ << conj.toExpr() << std::endl;
+ }
+ Trace("check-interpol") << "SmtEngine::checkInterpol: phase " << j
+ << ": make new SMT engine" << std::endl;
+ // Start new SMT engine to check solution
+ std::unique_ptr<SmtEngine> itpChecker;
+ initializeSubsolver(itpChecker);
+ Trace("check-interpol") << "SmtEngine::checkInterpol: phase " << j
+ << ": asserting formulas" << std::endl;
+ if (j == 0)
+ {
+ for (const Node& e : easserts)
+ {
+ itpChecker->assertFormula(e);
+ }
+ Node negitp = interpol.notNode();
+ itpChecker->assertFormula(negitp);
+ }
+ else
+ {
+ itpChecker->assertFormula(interpol);
+ Assert(!conj.isNull());
+ itpChecker->assertFormula(conj.notNode());
+ }
+ Trace("check-interpol") << "SmtEngine::checkInterpol: phase " << j
+ << ": check the assertions" << std::endl;
+ Result r = itpChecker->checkSat();
+ Trace("check-interpol") << "SmtEngine::checkInterpol: phase " << j
+ << ": result is " << r << std::endl;
+ std::stringstream serr;
+ if (r.asSatisfiabilityResult().isSat() != Result::UNSAT)
+ {
+ if (j == 0)
+ {
+ serr << "SmtEngine::checkInterpol(): negated produced solution cannot "
+ "be shown "
+ "satisfiable with assertions, result was "
+ << r;
+ }
+ else
+ {
+ serr
+ << "SmtEngine::checkInterpol(): negated conjecture cannot be shown "
+ "satisfiable with produced solution, result was "
+ << r;
+ }
+ InternalError() << serr.str();
+ }
+ }
+}
+
+} // namespace smt
+} // namespace CVC4
diff --git a/src/smt/interpolation_solver.h b/src/smt/interpolation_solver.h
new file mode 100644
index 000000000..096cf8983
--- /dev/null
+++ b/src/smt/interpolation_solver.h
@@ -0,0 +1,86 @@
+/********************* */
+/*! \file interpolation_solver.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Ying Sheng
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The solver for interpolation queries
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__SMT__INTERPOLATION_SOLVER_H
+#define CVC4__SMT__INTERPOLATION_SOLVER_H
+
+#include "expr/node.h"
+#include "expr/type_node.h"
+
+namespace CVC4 {
+
+class SmtEngine;
+
+namespace smt {
+
+/**
+ * A solver for interpolation queries.
+ *
+ * This class is responsible for responding to get-interpol commands. It spawns
+ * a subsolver SmtEngine for a sygus conjecture that captures the interpolation
+ * query, and implements supporting utility methods such as checkInterpol.
+ */
+class InterpolationSolver
+{
+ public:
+ InterpolationSolver(SmtEngine* parent);
+ ~InterpolationSolver();
+
+ /**
+ * This method asks this SMT engine to find an interpolant with respect to
+ * the current assertion stack (call it A) and the conjecture (call it B). If
+ * this method returns true, then interpolant is set to a formula I such that
+ * A ^ ~I and I ^ ~B are both unsatisfiable.
+ *
+ * @param conj The conjecture of the interpolation problem.
+ * @param grammarType A sygus datatype type that encodes the syntax
+ * restrictions on the shape of possible solutions.
+ * @param interpol This argument is updated to contain the solution to the
+ * interpolation problem.
+ *
+ * This method invokes a separate copy of the SMT engine for solving the
+ * corresponding sygus problem for generating such a solution.
+ */
+ bool getInterpol(const Node& conj,
+ const TypeNode& grammarType,
+ Node& interpol);
+
+ /**
+ * Same as above, but without user-provided grammar restrictions. A default
+ * grammar is chosen internally using the sygus grammar constructor utility.
+ */
+ bool getInterpol(const Node& conj, Node& interpol);
+
+ /**
+ * Check that a solution to an interpolation problem is indeed a solution.
+ *
+ * The check is made by determining that the assertions imply the solution of
+ * the interpolation problem (interpol), and the solution implies the goal
+ * (conj). If these criteria are not met, an internal error is thrown.
+ */
+ void checkInterpol(Node interpol,
+ const std::vector<Node>& easserts,
+ const Node& conj);
+
+ private:
+ /** The parent SMT engine */
+ SmtEngine* d_parent;
+};
+
+} // namespace smt
+} // namespace CVC4
+
+#endif /* CVC4__SMT__INTERPOLATION_SOLVER_H */
diff --git a/src/smt/listeners.cpp b/src/smt/listeners.cpp
new file mode 100644
index 000000000..7d34f3373
--- /dev/null
+++ b/src/smt/listeners.cpp
@@ -0,0 +1,112 @@
+/********************* */
+/*! \file listeners.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Abdalrhman Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implements listener classes for SMT engine.
+ **/
+
+#include "smt/listeners.h"
+
+#include "expr/attribute.h"
+#include "expr/expr.h"
+#include "expr/node_manager_attributes.h"
+#include "options/smt_options.h"
+#include "printer/printer.h"
+#include "smt/dump.h"
+#include "smt/dump_manager.h"
+#include "smt/node_command.h"
+#include "smt/smt_engine.h"
+#include "smt/smt_engine_scope.h"
+
+namespace CVC4 {
+namespace smt {
+
+ResourceOutListener::ResourceOutListener(SmtEngine& smt) : d_smt(smt) {}
+
+void ResourceOutListener::notify()
+{
+ SmtScope scope(&d_smt);
+ Assert(smt::smtEngineInScope());
+ d_smt.interrupt();
+}
+
+SmtNodeManagerListener::SmtNodeManagerListener(DumpManager& dm,
+ OutputManager& outMgr)
+ : d_dm(dm), d_outMgr(outMgr)
+{
+}
+
+void SmtNodeManagerListener::nmNotifyNewSort(TypeNode tn, uint32_t flags)
+{
+ DeclareTypeNodeCommand c(tn.getAttribute(expr::VarNameAttr()), 0, tn);
+ if ((flags & ExprManager::SORT_FLAG_PLACEHOLDER) == 0)
+ {
+ d_dm.addToModelCommandAndDump(c, flags);
+ }
+}
+
+void SmtNodeManagerListener::nmNotifyNewSortConstructor(TypeNode tn,
+ uint32_t flags)
+{
+ DeclareTypeNodeCommand c(tn.getAttribute(expr::VarNameAttr()),
+ tn.getAttribute(expr::SortArityAttr()),
+ tn);
+ if ((flags & ExprManager::SORT_FLAG_PLACEHOLDER) == 0)
+ {
+ d_dm.addToModelCommandAndDump(c);
+ }
+}
+
+void SmtNodeManagerListener::nmNotifyNewDatatypes(
+ const std::vector<TypeNode>& dtts, uint32_t flags)
+{
+ if ((flags & NodeManager::DATATYPE_FLAG_PLACEHOLDER) == 0)
+ {
+ if (Configuration::isAssertionBuild())
+ {
+ for (CVC4_UNUSED const TypeNode& dt : dtts)
+ {
+ Assert(dt.isDatatype());
+ }
+ }
+ DeclareDatatypeNodeCommand c(dtts);
+ d_dm.addToModelCommandAndDump(c);
+ }
+}
+
+void SmtNodeManagerListener::nmNotifyNewVar(TNode n, uint32_t flags)
+{
+ DeclareFunctionNodeCommand c(
+ n.getAttribute(expr::VarNameAttr()), n, n.getType());
+ if ((flags & ExprManager::VAR_FLAG_DEFINED) == 0)
+ {
+ d_dm.addToModelCommandAndDump(c, flags);
+ }
+}
+
+void SmtNodeManagerListener::nmNotifyNewSkolem(TNode n,
+ const std::string& comment,
+ uint32_t flags)
+{
+ std::string id = n.getAttribute(expr::VarNameAttr());
+ DeclareFunctionNodeCommand c(id, n, n.getType());
+ if (Dump.isOn("skolems") && comment != "")
+ {
+ d_outMgr.getPrinter().toStreamCmdComment(d_outMgr.getDumpOut(),
+ id + " is " + comment);
+ }
+ if ((flags & ExprManager::VAR_FLAG_DEFINED) == 0)
+ {
+ d_dm.addToModelCommandAndDump(c, flags, false, "skolems");
+ }
+}
+
+} // namespace smt
+} // namespace CVC4
diff --git a/src/smt/listeners.h b/src/smt/listeners.h
new file mode 100644
index 000000000..150ee7ba8
--- /dev/null
+++ b/src/smt/listeners.h
@@ -0,0 +1,80 @@
+/********************* */
+/*! \file listeners.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Mathias Preiner
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Listener classes for SMT engine.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__SMT__LISTENERS_H
+#define CVC4__SMT__LISTENERS_H
+
+#include <vector>
+
+#include "base/listener.h"
+#include "expr/node.h"
+
+namespace CVC4 {
+
+class OutputManager;
+class SmtEngine;
+
+namespace smt {
+
+/** A listener for resource outs */
+class ResourceOutListener : public Listener
+{
+ public:
+ ResourceOutListener(SmtEngine& smt);
+ /** notify method, interupts SmtEngine */
+ void notify() override;
+
+ private:
+ /** Reference to the SmtEngine */
+ SmtEngine& d_smt;
+};
+
+class DumpManager;
+
+/**
+ * A listener for node manager calls, which impacts certain dumping traces.
+ */
+class SmtNodeManagerListener : public NodeManagerListener
+{
+ public:
+ SmtNodeManagerListener(DumpManager& dm, OutputManager& outMgr);
+ /** Notify when new sort is created */
+ void nmNotifyNewSort(TypeNode tn, uint32_t flags) override;
+ /** Notify when new sort constructor is created */
+ void nmNotifyNewSortConstructor(TypeNode tn, uint32_t flags) override;
+ /** Notify when list of datatypes is created */
+ void nmNotifyNewDatatypes(const std::vector<TypeNode>& dtts,
+ uint32_t flags) override;
+ /** Notify when new variable is created */
+ void nmNotifyNewVar(TNode n, uint32_t flags) override;
+ /** Notify when new skolem is created */
+ void nmNotifyNewSkolem(TNode n,
+ const std::string& comment,
+ uint32_t flags) override;
+ /** Notify when a term is deleted */
+ void nmNotifyDeleteNode(TNode n) override {}
+
+ private:
+ /** Reference to the dump manager of smt engine */
+ DumpManager& d_dm;
+ /** Reference to the output manager of the smt engine */
+ OutputManager& d_outMgr;
+};
+
+} // namespace smt
+} // namespace CVC4
+
+#endif
diff --git a/src/smt/logic_exception.h b/src/smt/logic_exception.h
index 109d49c06..1c361b909 100644
--- a/src/smt/logic_exception.h
+++ b/src/smt/logic_exception.h
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/smt/logic_request.cpp b/src/smt/logic_request.cpp
index 486ac829d..aad32fa70 100644
--- a/src/smt/logic_request.cpp
+++ b/src/smt/logic_request.cpp
@@ -5,7 +5,7 @@
** Mathias Preiner, Martin Brain, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/smt/logic_request.h b/src/smt/logic_request.h
index b1822d0a1..3210de7b1 100644
--- a/src/smt/logic_request.h
+++ b/src/smt/logic_request.h
@@ -5,7 +5,7 @@
** Martin Brain, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/smt/managed_ostreams.cpp b/src/smt/managed_ostreams.cpp
index 12f98aa95..c49de7372 100644
--- a/src/smt/managed_ostreams.cpp
+++ b/src/smt/managed_ostreams.cpp
@@ -5,7 +5,7 @@
** Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/smt/managed_ostreams.h b/src/smt/managed_ostreams.h
index 577ef3226..d4cf33554 100644
--- a/src/smt/managed_ostreams.h
+++ b/src/smt/managed_ostreams.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -74,20 +74,6 @@ class ManagedOstream {
std::ostream* d_managed;
}; /* class ManagedOstream */
-class SetToDefaultSourceListener : public Listener {
- public:
- SetToDefaultSourceListener(ManagedOstream* managedOstream)
- : d_managedOstream(managedOstream){}
-
- void notify() override
- {
- d_managedOstream->set(d_managedOstream->defaultSource());
- }
-
- private:
- ManagedOstream* d_managedOstream;
-};
-
/**
* This controls the memory associated with --dump-to.
* This is is assumed to recieve a set whenever diagnosticChannelName
diff --git a/src/smt/model.cpp b/src/smt/model.cpp
index 6f6a09f38..fc9ea8fbb 100644
--- a/src/smt/model.cpp
+++ b/src/smt/model.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,19 +14,23 @@
#include "smt/model.h"
-#include <vector>
-
#include "expr/expr_iomanip.h"
#include "options/base_options.h"
#include "printer/printer.h"
-#include "smt/command.h"
-#include "smt/command_list.h"
+#include "smt/dump_manager.h"
+#include "smt/node_command.h"
#include "smt/smt_engine.h"
#include "smt/smt_engine_scope.h"
-
-using namespace std;
+#include "theory/theory_model.h"
namespace CVC4 {
+namespace smt {
+
+Model::Model(SmtEngine& smt, theory::TheoryModel* tm)
+ : d_smt(smt), d_isKnownSat(false), d_tmodel(tm)
+{
+ Assert(d_tmodel != nullptr);
+}
std::ostream& operator<<(std::ostream& out, const Model& m) {
smt::SmtScope smts(&m.d_smt);
@@ -35,20 +39,27 @@ std::ostream& operator<<(std::ostream& out, const Model& m) {
return out;
}
-Model::Model() : d_smt(*smt::currentSmtEngine()), d_isKnownSat(false) {}
+size_t Model::getNumCommands() const
+{
+ return d_smt.getDumpManager()->getNumModelCommands();
+}
-size_t Model::getNumCommands() const {
- return d_smt.d_modelCommands->size() + d_smt.d_modelGlobalCommands.size();
+const NodeCommand* Model::getCommand(size_t i) const
+{
+ return d_smt.getDumpManager()->getModelCommand(i);
}
-const Command* Model::getCommand(size_t i) const {
- Assert(i < getNumCommands());
- // index the global commands first, then the locals
- if(i < d_smt.d_modelGlobalCommands.size()) {
- return d_smt.d_modelGlobalCommands[i];
- } else {
- return (*d_smt.d_modelCommands)[i - d_smt.d_modelGlobalCommands.size()];
- }
+theory::TheoryModel* Model::getTheoryModel() { return d_tmodel; }
+
+const theory::TheoryModel* Model::getTheoryModel() const { return d_tmodel; }
+
+bool Model::isModelCoreSymbol(TNode sym) const
+{
+ return d_tmodel->isModelCoreSymbol(sym);
}
+Node Model::getValue(TNode n) const { return d_tmodel->getValue(n); }
+
+bool Model::hasApproximations() const { return d_tmodel->hasApproximations(); }
+} // namespace smt
}/* CVC4 namespace */
diff --git a/src/smt/model.h b/src/smt/model.h
index 1f7c5daae..dc36b5d29 100644
--- a/src/smt/model.h
+++ b/src/smt/model.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,34 +21,38 @@
#include <vector>
#include "expr/expr.h"
+#include "theory/theory_model.h"
#include "util/cardinality.h"
namespace CVC4 {
-class Command;
class SmtEngine;
+class NodeCommand;
+
+namespace smt {
+
class Model;
std::ostream& operator<<(std::ostream&, const Model&);
+/**
+ * This is the SMT-level model object, that is responsible for maintaining
+ * the necessary information for how to print the model, as well as
+ * holding a pointer to the underlying implementation of the theory model.
+ */
class Model {
friend std::ostream& operator<<(std::ostream&, const Model&);
- friend class SmtEngine;
-
- protected:
- /** The SmtEngine we're associated with */
- SmtEngine& d_smt;
-
- /** construct the base class; users cannot do this, only CVC4 internals */
- Model();
+ friend class ::CVC4::SmtEngine;
public:
+ /** construct */
+ Model(SmtEngine& smt, theory::TheoryModel* tm);
/** virtual destructor */
- virtual ~Model() { }
+ ~Model() {}
/** get number of commands to report */
size_t getNumCommands() const;
/** get command */
- const Command* getCommand(size_t i) const;
+ const NodeCommand* 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 */
@@ -62,54 +66,21 @@ class Model {
* only a candidate solution.
*/
bool isKnownSat() const { return d_isKnownSat; }
- //--------------------------- model cores
- /** set using model core
- *
- * This sets that this model is minimized to be a "model core" for some
- * formula (typically the input formula).
- *
- * For example, given formula ( a>5 OR b>5 ) AND f( c ) = 0,
- * a model for this formula is: a -> 6, b -> 0, c -> 0, f -> lambda x. 0.
- * A "model core" is a subset of this model that suffices to show the
- * above formula is true, for example { a -> 6, f -> lambda x. 0 } is a
- * model core for this formula.
- */
- virtual void setUsingModelCore() = 0;
- /** record model core symbol
- *
- * This marks that sym is a "model core symbol". In other words, its value is
- * critical to the satisfiability of the formula this model is for.
- */
- virtual void recordModelCoreSymbol(Expr sym) = 0;
- /** Check whether this expr is in the model core */
- virtual bool isModelCoreSymbol(Expr expr) const = 0;
- //--------------------------- end model cores
- /** get value for expression */
- virtual Expr getValue(Expr expr) const = 0;
- /** get cardinality for sort */
- virtual Cardinality getCardinality(Type t) const = 0;
- /** print comments */
- virtual void getComments(std::ostream& out) const {}
- /** get heap model (for separation logic) */
- virtual bool getHeapModel( Expr& h, Expr& ne ) const { return false; }
- /** are there any approximations in this model? */
- virtual bool hasApproximations() const { return false; }
- /** get the list of approximations
- *
- * This is a list of pairs of the form (t,p), where t is a term and p
- * is a predicate over t that indicates a property that t satisfies.
- */
- virtual std::vector<std::pair<Expr, Expr> > getApproximations() const = 0;
- /** get the domain elements for uninterpreted sort t
- *
- * This method gets the interpretation of an uninterpreted sort t.
- * All models interpret uninterpreted sorts t as finite sets
- * of domain elements v_1, ..., v_n. This method returns this list for t in
- * this model.
- */
- virtual std::vector<Expr> getDomainElements(Type t) const = 0;
-
+ /** Get the underlying theory model */
+ theory::TheoryModel* getTheoryModel();
+ /** Get the underlying theory model (const version) */
+ const theory::TheoryModel* getTheoryModel() const;
+ //----------------------- helper methods in the underlying theory model
+ /** Is the node n a model core symbol? */
+ bool isModelCoreSymbol(TNode sym) const;
+ /** Get value */
+ Node getValue(TNode n) const;
+ /** Does this model have approximations? */
+ bool hasApproximations() const;
+ //----------------------- end helper methods
protected:
+ /** The SmtEngine we're associated with */
+ SmtEngine& d_smt;
/** the input name (file name, etc.) this model is associated to */
std::string d_inputName;
/**
@@ -117,15 +88,14 @@ class Model {
* from the solver.
*/
bool d_isKnownSat;
-};/* class Model */
-
-class ModelBuilder {
-public:
- ModelBuilder() { }
- virtual ~ModelBuilder() { }
- virtual bool buildModel(Model* m) = 0;
-};/* class ModelBuilder */
+ /**
+ * Pointer to the underlying theory model, which maintains all data regarding
+ * the values of sorts and terms.
+ */
+ theory::TheoryModel* d_tmodel;
+};
+} // namespace smt
}/* CVC4 namespace */
#endif /* CVC4__MODEL_H */
diff --git a/src/smt/model_blocker.cpp b/src/smt/model_blocker.cpp
index 7a34cd928..cabd7bd20 100644
--- a/src/smt/model_blocker.cpp
+++ b/src/smt/model_blocker.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -23,24 +23,15 @@ using namespace CVC4::kind;
namespace CVC4 {
-Expr ModelBlocker::getModelBlocker(const std::vector<Expr>& assertions,
+Node ModelBlocker::getModelBlocker(const std::vector<Node>& assertions,
theory::TheoryModel* m,
options::BlockModelsMode mode,
- const std::vector<Expr>& exprToBlock)
+ const std::vector<Node>& exprToBlock)
{
NodeManager* nm = NodeManager::currentNM();
// convert to nodes
- std::vector<Node> tlAsserts;
- for (const Expr& a : assertions)
- {
- Node an = Node::fromExpr(a);
- tlAsserts.push_back(an);
- }
- std::vector<Node> nodesToBlock;
- for (const Expr& eb : exprToBlock)
- {
- nodesToBlock.push_back(Node::fromExpr(eb));
- }
+ std::vector<Node> tlAsserts = assertions;
+ std::vector<Node> nodesToBlock = exprToBlock;
Trace("model-blocker") << "Compute model blocker, assertions:" << std::endl;
Node blocker;
if (mode == options::BlockModelsMode::LITERALS)
@@ -75,7 +66,7 @@ Expr ModelBlocker::getModelBlocker(const std::vector<Expr>& assertions,
Node blockTriv = nm->mkConst(false);
Trace("model-blocker")
<< "...model blocker is (trivially) " << blockTriv << std::endl;
- return blockTriv.toExpr();
+ return blockTriv;
}
Node formula = asserts.size() > 1 ? nm->mkNode(AND, asserts) : asserts[0];
@@ -117,7 +108,7 @@ Expr ModelBlocker::getModelBlocker(const std::vector<Expr>& assertions,
// rewrite, this ensures that e.g. the propositional value of
// quantified formulas can be queried
n = theory::Rewriter::rewrite(n);
- Node vn = Node::fromExpr(m->getValue(n.toExpr()));
+ Node vn = m->getValue(n);
Assert(vn.isConst());
if (vn.getConst<bool>() == cpol)
{
@@ -139,7 +130,7 @@ Expr ModelBlocker::getModelBlocker(const std::vector<Expr>& assertions,
}
else if (catom.getKind() == ITE)
{
- Node vcond = Node::fromExpr(m->getValue(cur[0].toExpr()));
+ Node vcond = m->getValue(cur[0]);
Assert(vcond.isConst());
Node cond = cur[0];
Node branch;
@@ -161,7 +152,7 @@ Expr ModelBlocker::getModelBlocker(const std::vector<Expr>& assertions,
std::vector<Node> children;
for (const Node& cn : catom)
{
- Node vn = Node::fromExpr(m->getValue(cn.toExpr()));
+ Node vn = m->getValue(cn);
Assert(vn.isConst());
children.push_back(vn.getConst<bool>() ? cn : cn.negate());
}
@@ -282,7 +273,7 @@ Expr ModelBlocker::getModelBlocker(const std::vector<Expr>& assertions,
}
}
Trace("model-blocker") << "...model blocker is " << blocker << std::endl;
- return blocker.toExpr();
+ return blocker;
}
} /* namespace CVC4 */
diff --git a/src/smt/model_blocker.h b/src/smt/model_blocker.h
index ef4c6e700..92d200d40 100644
--- a/src/smt/model_blocker.h
+++ b/src/smt/model_blocker.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -59,11 +59,11 @@ class ModelBlocker
* our input. In other words, we do not return ~(x < 0) V ~(w < 0) since the
* left disjunct is always false.
*/
- static Expr getModelBlocker(
- const std::vector<Expr>& assertions,
+ static Node getModelBlocker(
+ const std::vector<Node>& assertions,
theory::TheoryModel* m,
options::BlockModelsMode mode,
- const std::vector<Expr>& exprToBlock = std::vector<Expr>());
+ const std::vector<Node>& exprToBlock = std::vector<Node>());
}; /* class TheoryModelCoreBuilder */
} // namespace CVC4
diff --git a/src/smt/model_core_builder.cpp b/src/smt/model_core_builder.cpp
index 6fc48c7e5..cb8494e85 100644
--- a/src/smt/model_core_builder.cpp
+++ b/src/smt/model_core_builder.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,28 +20,23 @@ using namespace CVC4::kind;
namespace CVC4 {
-bool ModelCoreBuilder::setModelCore(const std::vector<Expr>& assertions,
- Model* m,
+bool ModelCoreBuilder::setModelCore(const std::vector<Node>& assertions,
+ theory::TheoryModel* m,
options::ModelCoresMode mode)
{
if (Trace.isOn("model-core"))
{
Trace("model-core") << "Compute model core, assertions:" << std::endl;
- for (const Expr& a : assertions)
+ for (const Node& a : assertions)
{
Trace("model-core") << " " << a << std::endl;
}
}
// convert to nodes
- std::vector<Node> asserts;
- for (unsigned i = 0, size = assertions.size(); i < size; i++)
- {
- asserts.push_back(Node::fromExpr(assertions[i]));
- }
NodeManager* nm = NodeManager::currentNM();
- Node formula = asserts.size() > 1? nm->mkNode(AND, asserts) : asserts[0];
+ Node formula = nm->mkAnd(assertions);
std::vector<Node> vars;
std::vector<Node> subs;
Trace("model-core") << "Assignments: " << std::endl;
@@ -58,7 +53,7 @@ bool ModelCoreBuilder::setModelCore(const std::vector<Expr>& assertions,
visited.insert(cur);
if (cur.isVar())
{
- Node vcur = Node::fromExpr(m->getValue(cur.toExpr()));
+ Node vcur = m->getValue(cur);
Trace("model-core") << " " << cur << " -> " << vcur << std::endl;
vars.push_back(cur);
subs.push_back(vcur);
@@ -100,7 +95,7 @@ bool ModelCoreBuilder::setModelCore(const std::vector<Expr>& assertions,
for (const Node& cv : coreVars)
{
- m->recordModelCoreSymbol(cv.toExpr());
+ m->recordModelCoreSymbol(cv);
}
return true;
}
diff --git a/src/smt/model_core_builder.h b/src/smt/model_core_builder.h
index 2897ce728..7a28c47f2 100644
--- a/src/smt/model_core_builder.h
+++ b/src/smt/model_core_builder.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,7 +21,7 @@
#include "expr/expr.h"
#include "options/smt_options.h"
-#include "smt/model.h"
+#include "theory/theory_model.h"
namespace CVC4 {
@@ -54,8 +54,8 @@ class ModelCoreBuilder
* If m is not a model for assertions, this method returns false and m is
* left unchanged.
*/
- static bool setModelCore(const std::vector<Expr>& assertions,
- Model* m,
+ static bool setModelCore(const std::vector<Node>& assertions,
+ theory::TheoryModel* m,
options::ModelCoresMode mode);
}; /* class TheoryModelCoreBuilder */
diff --git a/src/smt/node_command.cpp b/src/smt/node_command.cpp
new file mode 100644
index 000000000..eb2493c87
--- /dev/null
+++ b/src/smt/node_command.cpp
@@ -0,0 +1,178 @@
+/********************* */
+/*! \file node_command.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Abdalrhman Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of NodeCommand functions.
+ **
+ ** Implementation of NodeCommand functions.
+ **/
+
+#include "smt/node_command.h"
+
+#include "printer/printer.h"
+
+namespace CVC4 {
+
+/* -------------------------------------------------------------------------- */
+/* class NodeCommand */
+/* -------------------------------------------------------------------------- */
+
+NodeCommand::~NodeCommand() {}
+
+std::string NodeCommand::toString() const
+{
+ std::stringstream ss;
+ toStream(ss);
+ return ss.str();
+}
+
+std::ostream& operator<<(std::ostream& out, const NodeCommand& nc)
+{
+ nc.toStream(out,
+ Node::setdepth::getDepth(out),
+ Node::dag::getDag(out),
+ Node::setlanguage::getLanguage(out));
+ return out;
+}
+
+/* -------------------------------------------------------------------------- */
+/* class DeclareFunctionNodeCommand */
+/* -------------------------------------------------------------------------- */
+
+DeclareFunctionNodeCommand::DeclareFunctionNodeCommand(const std::string& id,
+ Node expr,
+ TypeNode type)
+ : d_id(id),
+ d_fun(expr),
+ d_type(type),
+ d_printInModel(true),
+ d_printInModelSetByUser(false)
+{
+}
+
+void DeclareFunctionNodeCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdDeclareFunction(out, d_id, d_type);
+}
+
+NodeCommand* DeclareFunctionNodeCommand::clone() const
+{
+ return new DeclareFunctionNodeCommand(d_id, d_fun, d_type);
+}
+
+const Node& DeclareFunctionNodeCommand::getFunction() const { return d_fun; }
+
+bool DeclareFunctionNodeCommand::getPrintInModel() const
+{
+ return d_printInModel;
+}
+
+bool DeclareFunctionNodeCommand::getPrintInModelSetByUser() const
+{
+ return d_printInModelSetByUser;
+}
+
+void DeclareFunctionNodeCommand::setPrintInModel(bool p)
+{
+ d_printInModel = p;
+ d_printInModelSetByUser = true;
+}
+
+/* -------------------------------------------------------------------------- */
+/* class DeclareTypeNodeCommand */
+/* -------------------------------------------------------------------------- */
+
+DeclareTypeNodeCommand::DeclareTypeNodeCommand(const std::string& id,
+ size_t arity,
+ TypeNode type)
+ : d_id(id), d_arity(arity), d_type(type)
+{
+}
+
+void DeclareTypeNodeCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdDeclareType(
+ out, d_id, d_arity, d_type);
+}
+
+NodeCommand* DeclareTypeNodeCommand::clone() const
+{
+ return new DeclareTypeNodeCommand(d_id, d_arity, d_type);
+}
+
+const std::string DeclareTypeNodeCommand::getSymbol() const { return d_id; }
+
+const TypeNode& DeclareTypeNodeCommand::getType() const { return d_type; }
+
+/* -------------------------------------------------------------------------- */
+/* class DeclareDatatypeNodeCommand */
+/* -------------------------------------------------------------------------- */
+
+DeclareDatatypeNodeCommand::DeclareDatatypeNodeCommand(
+ const std::vector<TypeNode>& datatypes)
+ : d_datatypes(datatypes)
+{
+}
+
+void DeclareDatatypeNodeCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ Printer::getPrinter(language)->toStreamCmdDatatypeDeclaration(out,
+ d_datatypes);
+}
+
+NodeCommand* DeclareDatatypeNodeCommand::clone() const
+{
+ return new DeclareDatatypeNodeCommand(d_datatypes);
+}
+
+/* -------------------------------------------------------------------------- */
+/* class DefineFunctionNodeCommand */
+/* -------------------------------------------------------------------------- */
+
+DefineFunctionNodeCommand::DefineFunctionNodeCommand(
+ const std::string& id,
+ Node fun,
+ const std::vector<Node>& formals,
+ Node formula)
+ : d_id(id), d_fun(fun), d_formals(formals), d_formula(formula)
+{
+}
+
+void DefineFunctionNodeCommand::toStream(std::ostream& out,
+ int toDepth,
+ size_t dag,
+ OutputLanguage language) const
+{
+ TypeNode tn = d_fun.getType();
+ bool hasRange =
+ (tn.isFunction() || tn.isConstructor() || tn.isSelector());
+ Printer::getPrinter(language)->toStreamCmdDefineFunction(
+ out,
+ d_fun.toString(),
+ d_formals,
+ (hasRange ? d_fun.getType().getRangeType() : tn),
+ d_formula);
+}
+
+NodeCommand* DefineFunctionNodeCommand::clone() const
+{
+ return new DefineFunctionNodeCommand(d_id, d_fun, d_formals, d_formula);
+}
+
+} // namespace CVC4
diff --git a/src/smt/node_command.h b/src/smt/node_command.h
new file mode 100644
index 000000000..8cf9a5e10
--- /dev/null
+++ b/src/smt/node_command.h
@@ -0,0 +1,152 @@
+/********************* */
+/*! \file node_command.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Abdalrhman Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Datastructures used for printing commands internally.
+ **
+ ** Datastructures used for printing commands internally.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__SMT__NODE_COMMAND_H
+#define CVC4__SMT__NODE_COMMAND_H
+
+#include <string>
+
+#include "expr/node.h"
+#include "expr/type_node.h"
+#include "options/language.h"
+
+namespace CVC4 {
+
+/**
+ * A node version of Command. DO NOT use this version unless there is a need
+ * to buffer commands for later use (e.g., printing models).
+ */
+class NodeCommand
+{
+ public:
+ /** Destructor */
+ virtual ~NodeCommand();
+
+ /** Print this NodeCommand to output stream */
+ virtual void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const = 0;
+
+ /** Get a string representation of this NodeCommand */
+ std::string toString() const;
+
+ /** Clone this NodeCommand (make a shallow copy). */
+ virtual NodeCommand* clone() const = 0;
+};
+
+std::ostream& operator<<(std::ostream& out, const NodeCommand& nc);
+
+/**
+ * Declare n-ary function symbol.
+ * SMT-LIB: ( declare-fun <id> ( <type.getArgTypes()> ) <type.getRangeType()> )
+ */
+class DeclareFunctionNodeCommand : public NodeCommand
+{
+ public:
+ DeclareFunctionNodeCommand(const std::string& id, Node fun, TypeNode type);
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
+ NodeCommand* clone() const override;
+ const Node& getFunction() const;
+ bool getPrintInModel() const;
+ bool getPrintInModelSetByUser() const;
+ void setPrintInModel(bool p);
+
+ private:
+ std::string d_id;
+ Node d_fun;
+ TypeNode d_type;
+ bool d_printInModel;
+ bool d_printInModelSetByUser;
+};
+
+/**
+ * Create datatype sort.
+ * SMT-LIB: ( declare-datatypes ( <datatype decls>{n+1} ) ( <datatypes>{n+1} ) )
+ */
+class DeclareDatatypeNodeCommand : public NodeCommand
+{
+ public:
+ DeclareDatatypeNodeCommand(const std::vector<TypeNode>& datatypes);
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
+ NodeCommand* clone() const override;
+
+ private:
+ std::vector<TypeNode> d_datatypes;
+};
+
+/**
+ * Declare uninterpreted sort.
+ * SMT-LIB: ( declare-sort <id> <arity> )
+ */
+class DeclareTypeNodeCommand : public NodeCommand
+{
+ public:
+ DeclareTypeNodeCommand(const std::string& id, size_t arity, TypeNode type);
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
+ NodeCommand* clone() const override;
+ const std::string getSymbol() const;
+ const TypeNode& getType() const;
+
+ private:
+ std::string d_id;
+ size_t d_arity;
+ TypeNode d_type;
+};
+
+/**
+ * Define n-ary function.
+ * SMT-LIB: ( define-fun <id> ( <formals> ) <fun.getType()> <formula> )
+ */
+class DefineFunctionNodeCommand : public NodeCommand
+{
+ public:
+ DefineFunctionNodeCommand(const std::string& id,
+ Node fun,
+ const std::vector<Node>& formals,
+ Node formula);
+ void toStream(
+ std::ostream& out,
+ int toDepth = -1,
+ size_t dag = 1,
+ OutputLanguage language = language::output::LANG_AUTO) const override;
+ NodeCommand* clone() const override;
+
+ private:
+ std::string d_id;
+ Node d_fun;
+ std::vector<Node> d_formals;
+ Node d_formula;
+};
+
+} // namespace CVC4
+
+#endif /* CVC4__SMT__NODE_COMMAND_H */
diff --git a/src/smt/options_manager.cpp b/src/smt/options_manager.cpp
new file mode 100644
index 000000000..81e13c446
--- /dev/null
+++ b/src/smt/options_manager.cpp
@@ -0,0 +1,146 @@
+/********************* */
+/*! \file options_manager.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Module for managing options of an SmtEngine.
+ **/
+
+#include "smt/options_manager.h"
+
+#include "base/output.h"
+#include "expr/expr_iomanip.h"
+#include "options/base_options.h"
+#include "options/expr_options.h"
+#include "options/smt_options.h"
+#include "smt/command.h"
+#include "smt/dump.h"
+#include "smt/set_defaults.h"
+#include "util/resource_manager.h"
+
+namespace CVC4 {
+namespace smt {
+
+OptionsManager::OptionsManager(Options* opts, ResourceManager* rm)
+ : d_options(opts), d_resourceManager(rm)
+{
+ // set options that must take effect immediately
+ if (opts->wasSetByUser(options::defaultExprDepth))
+ {
+ notifySetOption(options::defaultExprDepth.getName());
+ }
+ if (opts->wasSetByUser(options::defaultDagThresh))
+ {
+ notifySetOption(options::defaultDagThresh.getName());
+ }
+ if (opts->wasSetByUser(options::dumpModeString))
+ {
+ notifySetOption(options::dumpModeString.getName());
+ }
+ if (opts->wasSetByUser(options::printSuccess))
+ {
+ notifySetOption(options::printSuccess.getName());
+ }
+ if (opts->wasSetByUser(options::diagnosticChannelName))
+ {
+ notifySetOption(options::diagnosticChannelName.getName());
+ }
+ if (opts->wasSetByUser(options::regularChannelName))
+ {
+ notifySetOption(options::regularChannelName.getName());
+ }
+ if (opts->wasSetByUser(options::dumpToFileName))
+ {
+ notifySetOption(options::dumpToFileName.getName());
+ }
+ // set this as a listener to be notified of options changes from now on
+ opts->setListener(this);
+}
+
+OptionsManager::~OptionsManager() {}
+
+void OptionsManager::notifySetOption(const std::string& key)
+{
+ Trace("smt") << "SmtEnginePrivate::notifySetOption(" << key << ")"
+ << std::endl;
+ if (key == options::defaultExprDepth.getName())
+ {
+ int depth = (*d_options)[options::defaultExprDepth];
+ Debug.getStream() << expr::ExprSetDepth(depth);
+ Trace.getStream() << expr::ExprSetDepth(depth);
+ Notice.getStream() << expr::ExprSetDepth(depth);
+ Chat.getStream() << expr::ExprSetDepth(depth);
+ Message.getStream() << expr::ExprSetDepth(depth);
+ Warning.getStream() << expr::ExprSetDepth(depth);
+ // intentionally exclude Dump stream from this list
+ }
+ else if (key == options::defaultDagThresh.getName())
+ {
+ int dag = (*d_options)[options::defaultDagThresh];
+ Debug.getStream() << expr::ExprDag(dag);
+ Trace.getStream() << expr::ExprDag(dag);
+ Notice.getStream() << expr::ExprDag(dag);
+ Chat.getStream() << expr::ExprDag(dag);
+ Message.getStream() << expr::ExprDag(dag);
+ Warning.getStream() << expr::ExprDag(dag);
+ Dump.getStream() << expr::ExprDag(dag);
+ }
+ else if (key == options::dumpModeString.getName())
+ {
+ const std::string& value = (*d_options)[options::dumpModeString];
+ Dump.setDumpFromString(value);
+ }
+ else if (key == options::printSuccess.getName())
+ {
+ bool value = (*d_options)[options::printSuccess];
+ Debug.getStream() << Command::printsuccess(value);
+ Trace.getStream() << Command::printsuccess(value);
+ Notice.getStream() << Command::printsuccess(value);
+ Chat.getStream() << Command::printsuccess(value);
+ Message.getStream() << Command::printsuccess(value);
+ Warning.getStream() << Command::printsuccess(value);
+ *options::out() << Command::printsuccess(value);
+ }
+ else if (key == options::regularChannelName.getName())
+ {
+ d_managedRegularChannel.set(options::regularChannelName());
+ }
+ else if (key == options::diagnosticChannelName.getName())
+ {
+ d_managedDiagnosticChannel.set(options::diagnosticChannelName());
+ }
+ else if (key == options::dumpToFileName.getName())
+ {
+ d_managedDumpChannel.set(options::dumpToFileName());
+ }
+ // otherwise, no action is necessary
+}
+
+void OptionsManager::finishInit(LogicInfo& logic, bool isInternalSubsolver)
+{
+ // set up the timeouts and resource limits
+ if ((*d_options)[options::perCallResourceLimit] != 0)
+ {
+ d_resourceManager->setResourceLimit(options::perCallResourceLimit(), false);
+ }
+ if ((*d_options)[options::cumulativeResourceLimit] != 0)
+ {
+ d_resourceManager->setResourceLimit(options::cumulativeResourceLimit(),
+ true);
+ }
+ if ((*d_options)[options::perCallMillisecondLimit] != 0)
+ {
+ d_resourceManager->setTimeLimit(options::perCallMillisecondLimit());
+ }
+ // ensure that our heuristics are properly set up
+ setDefaults(logic, isInternalSubsolver);
+}
+
+} // namespace smt
+} // namespace CVC4
diff --git a/src/smt/options_manager.h b/src/smt/options_manager.h
new file mode 100644
index 000000000..983b98b34
--- /dev/null
+++ b/src/smt/options_manager.h
@@ -0,0 +1,80 @@
+/********************* */
+/*! \file options_manager.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Module for managing options of an SmtEngine.
+ **/
+
+#ifndef CVC4__SMT__OPTIONS_MANAGER_H
+#define CVC4__SMT__OPTIONS_MANAGER_H
+
+#include "options/options.h"
+#include "options/options_listener.h"
+#include "smt/managed_ostreams.h"
+
+namespace CVC4 {
+
+class SmtEngine;
+class LogicInfo;
+class ResourceManager;
+
+namespace smt {
+
+/**
+ * This class is intended to be used by SmtEngine, and is responsible for:
+ * (1) Implementing core options including timeouts and output preferences,
+ * (2) Setting default values for options based on a logic.
+ *
+ * Notice that the constructor of this class retroactively sets all
+ * necessary options that have already been set in the options object it is
+ * given. This is to ensure that the command line arguments, which modified
+ * on an options object in the driver, immediately take effect upon creation of
+ * this class.
+ */
+class OptionsManager : public OptionsListener
+{
+ public:
+ OptionsManager(Options* opts, ResourceManager* rm = nullptr);
+ ~OptionsManager();
+ /**
+ * Called when a set option call is made on the options object associated
+ * with this class. This handles all options that should be taken into account
+ * immediately instead of e.g. at SmtEngine::finishInit time. This primarily
+ * includes options related to parsing and output.
+ *
+ * This function call is made after the option has been updated. This means
+ * that the value of the option can be queried in the options object that
+ * this class is listening to.
+ */
+ void notifySetOption(const std::string& key) override;
+ /**
+ * Finish init, which is called at the beginning of SmtEngine::finishInit,
+ * just before solving begins. This initializes the options pertaining to
+ * time limits, and sets the default options.
+ */
+ void finishInit(LogicInfo& logic, bool isInternalSubsolver);
+
+ private:
+ /** Reference to the options object */
+ Options* d_options;
+ /** Pointer to the resource manager */
+ ResourceManager* d_resourceManager;
+ /** Manager for the memory of regular-output-channel. */
+ ManagedRegularOutputChannel d_managedRegularChannel;
+ /** Manager for the memory of diagnostic-output-channel. */
+ ManagedDiagnosticOutputChannel d_managedDiagnosticChannel;
+ /** Manager for the memory of --dump-to. */
+ ManagedDumpOStream d_managedDumpChannel;
+};
+
+} // namespace smt
+} // namespace CVC4
+
+#endif /* CVC4__SMT__OPTIONS_MANAGER_H */
diff --git a/src/smt/output_manager.cpp b/src/smt/output_manager.cpp
new file mode 100644
index 000000000..a801b7527
--- /dev/null
+++ b/src/smt/output_manager.cpp
@@ -0,0 +1,35 @@
+/********************* */
+/*! \file output_manager.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Abdalrhman Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of OutputManager functions.
+ **
+ ** Implementation of OutputManager functions.
+ **/
+
+#include "smt/output_manager.h"
+
+#include "smt/smt_engine.h"
+
+namespace CVC4 {
+
+OutputManager::OutputManager(SmtEngine* smt) : d_smt(smt) {}
+
+const Printer& OutputManager::getPrinter() const
+{
+ return *d_smt->getPrinter();
+}
+
+std::ostream& OutputManager::getDumpOut() const
+{
+ return *d_smt->getOptions().getOut();
+}
+
+} // namespace CVC4
diff --git a/src/smt/output_manager.h b/src/smt/output_manager.h
new file mode 100644
index 000000000..5ffd6b964
--- /dev/null
+++ b/src/smt/output_manager.h
@@ -0,0 +1,57 @@
+/********************* */
+/*! \file output_manager.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Abdalrhman Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The output manager for the SmtEngine.
+ **
+ ** The output manager provides helper functions for printing commands
+ ** internally.
+ **/
+
+#ifndef CVC4__SMT__OUTPUT_MANAGER_H
+#define CVC4__SMT__OUTPUT_MANAGER_H
+
+#include <ostream>
+
+namespace CVC4 {
+
+class Printer;
+class SmtEngine;
+
+/** This utility class provides helper functions for printing commands
+ * internally */
+class OutputManager
+{
+ public:
+ /** Constructor
+ *
+ * @param smt SMT engine to manage output for
+ */
+ explicit OutputManager(SmtEngine* smt);
+
+ /** Get the current printer based on the current options
+ *
+ * @return the current printer
+ */
+ const Printer& getPrinter() const;
+
+ /** Get the output stream that --dump=X should print to
+ *
+ * @return the output stream
+ */
+ std::ostream& getDumpOut() const;
+
+ private:
+ SmtEngine* d_smt;
+};
+
+} // namespace CVC4
+
+#endif // CVC4__SMT__OUTPUT_MANAGER_H
diff --git a/src/smt/preprocess_proof_generator.cpp b/src/smt/preprocess_proof_generator.cpp
index 969ffa9bb..bab56a0d2 100644
--- a/src/smt/preprocess_proof_generator.cpp
+++ b/src/smt/preprocess_proof_generator.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,38 +16,99 @@
#include "smt/preprocess_proof_generator.h"
#include "expr/proof.h"
+#include "options/smt_options.h"
#include "theory/rewriter.h"
namespace CVC4 {
namespace smt {
-PreprocessProofGenerator::PreprocessProofGenerator(ProofNodeManager* pnm)
- : d_pnm(pnm)
+PreprocessProofGenerator::PreprocessProofGenerator(ProofNodeManager* pnm,
+ context::Context* c,
+ std::string name,
+ PfRule ra,
+ PfRule rpp)
+ : d_pnm(pnm),
+ d_ctx(c ? c : &d_context),
+ d_src(d_ctx),
+ d_helperProofs(pnm, d_ctx),
+ d_inputPf(pnm, nullptr),
+ d_name(name),
+ d_ra(ra),
+ d_rpp(rpp)
{
}
+void PreprocessProofGenerator::notifyInput(Node n)
+{
+ notifyNewAssert(n, &d_inputPf);
+}
+
void PreprocessProofGenerator::notifyNewAssert(Node n, ProofGenerator* pg)
{
- Trace("smt-proof-pp-debug") << "- notifyNewAssert: " << n << std::endl;
- d_src[n] = theory::TrustNode::mkTrustLemma(n, pg);
+ Trace("smt-proof-pp-debug")
+ << "PreprocessProofGenerator::notifyNewAssert: " << n << std::endl;
+ if (d_src.find(n) == d_src.end())
+ {
+ // if no proof generator provided for (non-true) assertion
+ if (pg == nullptr && (!n.isConst() || !n.getConst<bool>()))
+ {
+ checkEagerPedantic(d_ra);
+ }
+ d_src[n] = theory::TrustNode::mkTrustLemma(n, pg);
+ }
+ else
+ {
+ Trace("smt-proof-pp-debug") << "...already proven" << std::endl;
+ }
+}
+
+void PreprocessProofGenerator::notifyNewTrustedAssert(theory::TrustNode tn)
+{
+ notifyNewAssert(tn.getProven(), tn.getGenerator());
}
void PreprocessProofGenerator::notifyPreprocessed(Node n,
Node np,
ProofGenerator* pg)
{
- // only keep if indeed it rewrote
- if (n != np)
+ // only do anything if indeed it rewrote
+ if (n == np)
{
- Trace("smt-proof-pp-debug")
- << "- notifyPreprocessed: " << n << "..." << np << std::endl;
- d_src[np] = theory::TrustNode::mkTrustRewrite(n, np, pg);
+ return;
+ }
+ // call the trusted version
+ notifyTrustedPreprocessed(theory::TrustNode::mkTrustRewrite(n, np, pg));
+}
+
+void PreprocessProofGenerator::notifyTrustedPreprocessed(theory::TrustNode tnp)
+{
+ if (tnp.isNull())
+ {
+ // no rewrite, nothing to do
+ return;
+ }
+ Assert(tnp.getKind() == theory::TrustNodeKind::REWRITE);
+ Node np = tnp.getNode();
+ Trace("smt-proof-pp-debug")
+ << "PreprocessProofGenerator::notifyPreprocessed: " << tnp.getProven()
+ << std::endl;
+ if (d_src.find(np) == d_src.end())
+ {
+ if (tnp.getGenerator() == nullptr)
+ {
+ checkEagerPedantic(d_rpp);
+ }
+ d_src[np] = tnp;
+ }
+ else
+ {
+ Trace("smt-proof-pp-debug") << "...already proven" << std::endl;
}
}
std::shared_ptr<ProofNode> PreprocessProofGenerator::getProofFor(Node f)
{
- std::map<Node, theory::TrustNode>::iterator it = d_src.find(f);
+ NodeTrustNodeMap::iterator it = d_src.find(f);
if (it == d_src.end())
{
// could be an assumption, return nullptr
@@ -56,67 +117,100 @@ std::shared_ptr<ProofNode> PreprocessProofGenerator::getProofFor(Node f)
// make CDProof to construct the proof below
CDProof cdp(d_pnm);
+ Trace("smt-pppg") << "PreprocessProofGenerator::getProofFor: (" << d_name
+ << ") input " << f << std::endl;
Node curr = f;
std::vector<Node> transChildren;
+ std::unordered_set<Node, NodeHashFunction> processed;
bool success;
+ // we connect the proof of f to its source via the map d_src until we
+ // discover that its source is a preprocessing lemma (a lemma stored in d_src)
+ // or otherwise it is assumed to be an input assumption.
do
{
success = false;
if (it != d_src.end())
{
- Assert(it->second.getNode() == curr);
+ Assert((*it).second.getNode() == curr);
+ // get the proven node
+ Node proven = (*it).second.getProven();
+ Assert(!proven.isNull());
+ Trace("smt-pppg") << "...process proven " << proven << std::endl;
+ if (processed.find(proven) != processed.end())
+ {
+ Unhandled() << "Cyclic steps in preprocess proof generator";
+ continue;
+ }
+ processed.insert(proven);
bool proofStepProcessed = false;
- std::shared_ptr<ProofNode> pfr = it->second.toProofNode();
+
+ // if a generator for the step was provided, it is stored in the proof
+ Trace("smt-pppg") << "...get provided proof" << std::endl;
+ std::shared_ptr<ProofNode> pfr = (*it).second.toProofNode();
if (pfr != nullptr)
{
- Assert(pfr->getResult() == it->second.getProven());
+ Trace("smt-pppg") << "...add provided" << std::endl;
+ Assert(pfr->getResult() == proven);
cdp.addProof(pfr);
proofStepProcessed = true;
}
- if (it->second.getKind() == theory::TrustNodeKind::REWRITE)
+ Trace("smt-pppg") << "...update" << std::endl;
+ theory::TrustNodeKind tnk = (*it).second.getKind();
+ if (tnk == theory::TrustNodeKind::REWRITE)
{
- Node eq = it->second.getProven();
- Assert(eq.getKind() == kind::EQUAL);
+ Trace("smt-pppg") << "...rewritten from " << proven[0] << std::endl;
+ Assert(proven.getKind() == kind::EQUAL);
if (!proofStepProcessed)
{
// maybe its just a simple rewrite?
- if (eq[1] == theory::Rewriter::rewrite(eq[0]))
+ if (proven[1] == theory::Rewriter::rewrite(proven[0]))
{
- cdp.addStep(eq, PfRule::REWRITE, {}, {eq[0]});
+ cdp.addStep(proven, PfRule::REWRITE, {}, {proven[0]});
proofStepProcessed = true;
}
}
- transChildren.push_back(eq);
+ transChildren.push_back(proven);
// continue with source
- curr = eq[0];
+ curr = proven[0];
success = true;
// find the next node
it = d_src.find(curr);
}
else
{
- Assert(it->second.getKind() == theory::TrustNodeKind::LEMMA);
+ Trace("smt-pppg") << "...lemma" << std::endl;
+ Assert(tnk == theory::TrustNodeKind::LEMMA);
}
if (!proofStepProcessed)
{
- // add trusted step
- Node proven = it->second.getProven();
- cdp.addStep(proven, PfRule::PREPROCESS, {}, {proven});
+ Trace("smt-pppg") << "...add missing step" << std::endl;
+ // add trusted step, the rule depends on the kind of trust node
+ cdp.addStep(proven,
+ tnk == theory::TrustNodeKind::LEMMA ? d_ra : d_rpp,
+ {},
+ {proven});
}
}
} while (success);
- Assert(curr != f);
- // prove ( curr == f )
- Node fullRewrite = curr.eqNode(f);
- if (transChildren.size() >= 2)
+ // prove ( curr == f ), which is not necessary if they are the same
+ // modulo symmetry.
+ if (!CDProof::isSame(f, curr))
{
- cdp.addStep(fullRewrite, PfRule::TRANS, transChildren, {});
+ Node fullRewrite = curr.eqNode(f);
+ if (transChildren.size() >= 2)
+ {
+ Trace("smt-pppg") << "...apply trans to get " << fullRewrite << std::endl;
+ std::reverse(transChildren.begin(), transChildren.end());
+ cdp.addStep(fullRewrite, PfRule::TRANS, transChildren, {});
+ }
+ Trace("smt-pppg") << "...eq_resolve to prove" << std::endl;
+ // prove f
+ cdp.addStep(f, PfRule::EQ_RESOLVE, {curr, fullRewrite}, {});
+ Trace("smt-pppg") << "...finished" << std::endl;
}
- // prove f
- cdp.addStep(f, PfRule::EQ_RESOLVE, {curr, fullRewrite}, {});
// overall, proof is:
// --------- from proof generator ---------- from proof generator
@@ -130,9 +224,29 @@ std::shared_ptr<ProofNode> PreprocessProofGenerator::getProofFor(Node f)
return cdp.getProofFor(f);
}
-std::string PreprocessProofGenerator::identify() const
+ProofNodeManager* PreprocessProofGenerator::getManager() { return d_pnm; }
+
+LazyCDProof* PreprocessProofGenerator::allocateHelperProof()
+{
+ return d_helperProofs.allocateProof(nullptr, d_ctx);
+}
+
+std::string PreprocessProofGenerator::identify() const { return d_name; }
+
+void PreprocessProofGenerator::checkEagerPedantic(PfRule r)
{
- return "PreprocessProofGenerator";
+ if (options::proofNewEagerChecking())
+ {
+ // catch a pedantic failure now, which otherwise would not be
+ // triggered since we are doing lazy proof generation
+ ProofChecker* pc = d_pnm->getChecker();
+ std::stringstream serr;
+ if (pc->isPedanticFailure(r, serr))
+ {
+ Unhandled() << "PreprocessProofGenerator::checkEagerPedantic: "
+ << serr.str();
+ }
+ }
}
} // namespace smt
diff --git a/src/smt/preprocess_proof_generator.h b/src/smt/preprocess_proof_generator.h
index 3b960b051..41add5583 100644
--- a/src/smt/preprocess_proof_generator.h
+++ b/src/smt/preprocess_proof_generator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,18 +19,31 @@
#include <map>
+#include "context/cdhashmap.h"
+#include "context/cdlist.h"
+#include "expr/lazy_proof.h"
+#include "expr/proof_set.h"
#include "expr/proof_generator.h"
#include "expr/proof_node_manager.h"
+#include "theory/eager_proof_generator.h"
#include "theory/trust_node.h"
namespace CVC4 {
namespace smt {
/**
- * A proof generator storing proofs of preprocessing. This has two main
- * interfaces during solving:
+ * This is a proof generator that manages proofs for a set of formulas that
+ * may be replaced over time. This set of formulas is implicit; formulas that
+ * are not notified as assertions to this class are treated as assumptions.
+ *
+ * The main use case of this proof generator is for proofs of preprocessing,
+ * although it can be used in other scenarios where proofs for an evolving set
+ * of formulas is maintained. In the remainder of the description here, we
+ * describe its role as a proof generator for proofs of preprocessing.
+ *
+ * This class has two main interfaces during solving:
* (1) notifyNewAssert, for assertions that are not part of the input and are
- * added by preprocessing passes,
+ * added to the assertion pipeline by preprocessing passes,
* (2) notifyPreprocessed, which is called when a preprocessing pass rewrites
* an assertion into another.
* Notice that input assertions do not need to be provided to this class.
@@ -41,18 +54,42 @@ namespace smt {
*/
class PreprocessProofGenerator : public ProofGenerator
{
+ typedef context::CDHashMap<Node, theory::TrustNode, NodeHashFunction>
+ NodeTrustNodeMap;
+
public:
- PreprocessProofGenerator(ProofNodeManager* pnm);
+ /**
+ * @param pnm The proof node manager
+ * @param c The context this class depends on
+ * @param name The name of this generator (for debugging)
+ * @param ra The proof rule to use when no generator is provided for new
+ * assertions
+ * @param rpp The proof rule to use when no generator is provided for
+ * preprocessing steps.
+ */
+ PreprocessProofGenerator(ProofNodeManager* pnm,
+ context::Context* c = nullptr,
+ std::string name = "PreprocessProofGenerator",
+ PfRule ra = PfRule::PREPROCESS_LEMMA,
+ PfRule rpp = PfRule::PREPROCESS);
~PreprocessProofGenerator() {}
/**
+ * Notify that n is an input (its proof is ASSUME).
+ */
+ void notifyInput(Node n);
+ /**
* Notify that n is a new assertion, where pg can provide a proof of n.
*/
void notifyNewAssert(Node n, ProofGenerator* pg);
+ /** Notify a new assertion, trust node version. */
+ void notifyNewTrustedAssert(theory::TrustNode tn);
/**
* Notify that n was replaced by np due to preprocessing, where pg can
* provide a proof of the equality n=np.
*/
void notifyPreprocessed(Node n, Node np, ProofGenerator* pg);
+ /** Notify preprocessed, trust node version */
+ void notifyTrustedPreprocessed(theory::TrustNode tnp);
/**
* Get proof for f, which returns a proof based on proving an equality based
* on transitivity of preprocessing steps, and then using the original
@@ -61,10 +98,28 @@ class PreprocessProofGenerator : public ProofGenerator
std::shared_ptr<ProofNode> getProofFor(Node f) override;
/** Identify */
std::string identify() const override;
+ /** Get the proof manager */
+ ProofNodeManager* getManager();
+ /**
+ * Allocate a helper proof. This returns a fresh lazy proof object that
+ * remains alive in the context. This feature is used to construct
+ * helper proofs for preprocessing, e.g. to support the skeleton of proofs
+ * that connect AssertionPipeline::conjoin steps.
+ */
+ LazyCDProof* allocateHelperProof();
private:
+ /**
+ * Possibly check pedantic failure for null proof generator provided
+ * to this class.
+ */
+ void checkEagerPedantic(PfRule r);
/** The proof node manager */
ProofNodeManager* d_pnm;
+ /** A dummy context used by this class if none is provided */
+ context::Context d_context;
+ /** The context used here */
+ context::Context* d_ctx;
/**
* The trust node that was the source of each node constructed during
* preprocessing. For each n, d_src[n] is a trust node whose node is n. This
@@ -72,7 +127,20 @@ class PreprocessProofGenerator : public ProofGenerator
* (1) A trust node REWRITE proving (n_src = n) for some n_src, or
* (2) A trust node LEMMA proving n.
*/
- std::map<Node, theory::TrustNode> d_src;
+ NodeTrustNodeMap d_src;
+ /** A context-dependent list of LazyCDProof, allocated for conjoin steps */
+ CDProofSet<LazyCDProof> d_helperProofs;
+ /**
+ * A cd proof for input assertions, this is an empty proof that intentionally
+ * returns (ASSUME f) for all f.
+ */
+ CDProof d_inputPf;
+ /** Name for debugging */
+ std::string d_name;
+ /** The trust rule for new assertions with no provided proof generator */
+ PfRule d_ra;
+ /** The trust rule for rewrites with no provided proof generator */
+ PfRule d_rpp;
};
} // namespace smt
diff --git a/src/smt/preprocessor.cpp b/src/smt/preprocessor.cpp
new file mode 100644
index 000000000..98a2a7a36
--- /dev/null
+++ b/src/smt/preprocessor.cpp
@@ -0,0 +1,165 @@
+/********************* */
+/*! \file preprocessor.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Morgan Deters, Aina Niemetz
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The preprocessor of the SMT engine.
+ **/
+
+#include "smt/preprocessor.h"
+
+#include "options/smt_options.h"
+#include "printer/printer.h"
+#include "smt/abstract_values.h"
+#include "smt/assertions.h"
+#include "smt/dump.h"
+#include "smt/smt_engine.h"
+
+using namespace CVC4::theory;
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace smt {
+
+Preprocessor::Preprocessor(SmtEngine& smt,
+ context::UserContext* u,
+ AbstractValues& abs,
+ SmtEngineStatistics& stats)
+ : d_context(u),
+ d_smt(smt),
+ d_absValues(abs),
+ d_propagator(true, true),
+ d_assertionsProcessed(u, false),
+ d_processor(smt, *smt.getResourceManager(), stats),
+ d_rtf(u),
+ d_pnm(nullptr)
+{
+}
+
+Preprocessor::~Preprocessor()
+{
+ if (d_propagator.getNeedsFinish())
+ {
+ d_propagator.finish();
+ d_propagator.setNeedsFinish(false);
+ }
+}
+
+void Preprocessor::finishInit()
+{
+ d_ppContext.reset(new preprocessing::PreprocessingPassContext(
+ &d_smt, &d_rtf, &d_propagator, d_pnm));
+
+ // initialize the preprocessing passes
+ d_processor.finishInit(d_ppContext.get());
+}
+
+bool Preprocessor::process(Assertions& as)
+{
+ preprocessing::AssertionPipeline& ap = as.getAssertionPipeline();
+
+ // should not be called if empty
+ Assert(ap.size() != 0)
+ << "Can only preprocess a non-empty list of assertions";
+
+ if (d_assertionsProcessed && options::incrementalSolving())
+ {
+ // TODO(b/1255): Substitutions in incremental mode should be managed with a
+ // proper data structure.
+ ap.enableStoreSubstsInAsserts();
+ }
+ else
+ {
+ ap.disableStoreSubstsInAsserts();
+ }
+
+ // process the assertions, return true if no conflict is discovered
+ return d_processor.apply(as);
+}
+
+void Preprocessor::postprocess(Assertions& as)
+{
+ preprocessing::AssertionPipeline& ap = as.getAssertionPipeline();
+ // if incremental, compute which variables are assigned
+ if (options::incrementalSolving())
+ {
+ d_ppContext->recordSymbolsInAssertions(ap.ref());
+ }
+
+ // mark that we've processed assertions
+ d_assertionsProcessed = true;
+}
+
+void Preprocessor::clearLearnedLiterals()
+{
+ d_propagator.getLearnedLiterals().clear();
+}
+
+void Preprocessor::cleanup() { d_processor.cleanup(); }
+
+RemoveTermFormulas& Preprocessor::getTermFormulaRemover() { return d_rtf; }
+
+Node Preprocessor::expandDefinitions(const Node& n, bool expandOnly)
+{
+ std::unordered_map<Node, Node, NodeHashFunction> cache;
+ return expandDefinitions(n, cache, expandOnly);
+}
+
+Node Preprocessor::expandDefinitions(
+ const Node& node,
+ std::unordered_map<Node, Node, NodeHashFunction>& cache,
+ bool expandOnly)
+{
+ Trace("smt") << "SMT expandDefinitions(" << node << ")" << endl;
+ // Substitute out any abstract values in node.
+ Node n = d_absValues.substituteAbstractValues(node);
+ if (options::typeChecking())
+ {
+ // Ensure node is type-checked at this point.
+ n.getType(true);
+ }
+ // expand only = true
+ return d_processor.expandDefinitions(n, cache, expandOnly);
+}
+
+Node Preprocessor::simplify(const Node& node, bool removeItes)
+{
+ Trace("smt") << "SMT simplify(" << node << ")" << endl;
+ if (Dump.isOn("benchmark"))
+ {
+ d_smt.getOutputManager().getPrinter().toStreamCmdSimplify(
+ d_smt.getOutputManager().getDumpOut(), node);
+ }
+ Node nas = d_absValues.substituteAbstractValues(node);
+ if (options::typeChecking())
+ {
+ // ensure node is type-checked at this point
+ nas.getType(true);
+ }
+ std::unordered_map<Node, Node, NodeHashFunction> cache;
+ Node n = d_processor.expandDefinitions(nas, cache);
+ TrustNode ts = d_ppContext->getTopLevelSubstitutions().apply(n);
+ Node ns = ts.isNull() ? n : ts.getNode();
+ if (removeItes)
+ {
+ // also remove ites if asked
+ ns = d_rtf.replace(ns);
+ }
+ return ns;
+}
+
+void Preprocessor::setProofGenerator(PreprocessProofGenerator* pppg)
+{
+ Assert(pppg != nullptr);
+ d_pnm = pppg->getManager();
+ d_rtf.setProofNodeManager(d_pnm);
+}
+
+} // namespace smt
+} // namespace CVC4
diff --git a/src/smt/preprocessor.h b/src/smt/preprocessor.h
new file mode 100644
index 000000000..cb83f969e
--- /dev/null
+++ b/src/smt/preprocessor.h
@@ -0,0 +1,145 @@
+/********************* */
+/*! \file preprocessor.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Morgan Deters, Haniel Barbosa
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The preprocessor of the SmtEngine.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__SMT__PREPROCESSOR_H
+#define CVC4__SMT__PREPROCESSOR_H
+
+#include <vector>
+
+#include "preprocessing/preprocessing_pass_context.h"
+#include "smt/process_assertions.h"
+#include "smt/term_formula_removal.h"
+#include "theory/booleans/circuit_propagator.h"
+
+namespace CVC4 {
+namespace smt {
+
+class AbstractValues;
+
+/**
+ * The preprocessor module of an SMT engine.
+ *
+ * This class is responsible for:
+ * (1) preprocessing the set of assertions from input before they are sent to
+ * the SMT solver,
+ * (2) implementing methods for expanding and simplifying formulas. The latter
+ * takes into account the substitutions inferred by this class.
+ */
+class Preprocessor
+{
+ public:
+ Preprocessor(SmtEngine& smt,
+ context::UserContext* u,
+ AbstractValues& abs,
+ SmtEngineStatistics& stats);
+ ~Preprocessor();
+ /**
+ * Finish initialization
+ */
+ void finishInit();
+ /**
+ * Process the assertions that have been asserted in argument as. Returns
+ * true if no conflict was discovered while preprocessing them.
+ */
+ bool process(Assertions& as);
+ /**
+ * Postprocess assertions, called after the SmtEngine has finished
+ * giving the assertions to the SMT solver and before the assertions are
+ * cleared.
+ */
+ void postprocess(Assertions& as);
+ /**
+ * Clear learned literals from the Boolean propagator.
+ */
+ void clearLearnedLiterals();
+ /**
+ * Cleanup, which deletes the processing passes owned by this module. This
+ * is required to be done explicitly so that passes are deleted before the
+ * objects they refer to in the SmtEngine destructor.
+ */
+ void cleanup();
+ /**
+ * Simplify a formula without doing "much" work. Does not involve
+ * the SAT Engine in the simplification, but uses the current
+ * definitions, assertions, and the current partial model, if one
+ * has been constructed. It also involves theory normalization.
+ *
+ * @param n The node to simplify
+ * @param removeItes Whether to remove ITE (and other terms with formulas in
+ * term positions) from the result.
+ * @return The simplified term.
+ */
+ Node simplify(const Node& n, bool removeItes = false);
+ /**
+ * Expand the definitions in a term or formula n. No other
+ * simplification or normalization is done.
+ *
+ * @param n The node to expand
+ * @param expandOnly if true, then the expandDefinitions function of
+ * TheoryEngine is not called on subterms of n.
+ * @return The expanded term.
+ */
+ Node expandDefinitions(const Node& n, bool expandOnly = false);
+ /** Same as above, with a cache of previous results. */
+ Node expandDefinitions(
+ const Node& n,
+ std::unordered_map<Node, Node, NodeHashFunction>& cache,
+ bool expandOnly = false);
+ /**
+ * Get the underlying term formula remover utility.
+ */
+ RemoveTermFormulas& getTermFormulaRemover();
+
+ /**
+ * Set proof node manager. Enables proofs in this preprocessor.
+ */
+ void setProofGenerator(PreprocessProofGenerator* pppg);
+
+ private:
+ /** A copy of the current context */
+ context::Context* d_context;
+ /** Reference to the parent SmtEngine */
+ SmtEngine& d_smt;
+ /** Reference to the abstract values utility */
+ AbstractValues& d_absValues;
+ /**
+ * A circuit propagator for non-clausal propositional deduction.
+ */
+ theory::booleans::CircuitPropagator d_propagator;
+ /**
+ * User-context-dependent flag of whether any assertions have been processed.
+ */
+ context::CDO<bool> d_assertionsProcessed;
+ /** The preprocessing pass context */
+ std::unique_ptr<preprocessing::PreprocessingPassContext> d_ppContext;
+ /**
+ * Process assertions module, responsible for implementing the preprocessing
+ * passes.
+ */
+ ProcessAssertions d_processor;
+ /**
+ * The term formula remover, responsible for eliminating formulas that occur
+ * in term contexts.
+ */
+ RemoveTermFormulas d_rtf;
+ /** Proof node manager */
+ ProofNodeManager* d_pnm;
+};
+
+} // namespace smt
+} // namespace CVC4
+
+#endif
diff --git a/src/smt/process_assertions.cpp b/src/smt/process_assertions.cpp
index 4fed33f3c..2011e7b83 100644
--- a/src/smt/process_assertions.cpp
+++ b/src/smt/process_assertions.cpp
@@ -2,10 +2,10 @@
/*! \file process_assertions.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Morgan Deters, Mathias Preiner
+ ** Andrew Reynolds, Tim King, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,17 +21,17 @@
#include "options/arith_options.h"
#include "options/base_options.h"
#include "options/bv_options.h"
-#include "options/proof_options.h"
#include "options/quantifiers_options.h"
#include "options/sep_options.h"
#include "options/smt_options.h"
#include "options/uf_options.h"
#include "preprocessing/assertion_pipeline.h"
#include "preprocessing/preprocessing_pass_registry.h"
+#include "printer/printer.h"
#include "smt/defined_function.h"
+#include "smt/dump.h"
#include "smt/smt_engine.h"
#include "theory/logic_info.h"
-#include "theory/quantifiers/fun_def_process.h"
#include "theory/theory_engine.h"
using namespace CVC4::preprocessing;
@@ -52,19 +52,19 @@ class ScopeCounter
unsigned& d_depth;
};
-ProcessAssertions::ProcessAssertions(SmtEngine& smt, ResourceManager& rm)
+ProcessAssertions::ProcessAssertions(SmtEngine& smt,
+ ResourceManager& rm,
+ SmtEngineStatistics& stats)
: d_smt(smt),
d_resourceManager(rm),
- d_preprocessingPassContext(nullptr),
- d_fmfRecFunctionsDefined(nullptr)
+ d_smtStats(stats),
+ d_preprocessingPassContext(nullptr)
{
d_true = NodeManager::currentNM()->mkConst(true);
- d_fmfRecFunctionsDefined = new (true) NodeList(d_smt.getUserContext());
}
ProcessAssertions::~ProcessAssertions()
{
- d_fmfRecFunctionsDefined->deleteSelf();
}
void ProcessAssertions::finishInit(PreprocessingPassContext* pc)
@@ -91,8 +91,9 @@ void ProcessAssertions::spendResource(ResourceManager::Resource r)
d_resourceManager.spendResource(r);
}
-bool ProcessAssertions::apply(AssertionPipeline& assertions)
+bool ProcessAssertions::apply(Assertions& as)
{
+ AssertionPipeline& assertions = as.getAssertionPipeline();
Assert(d_preprocessingPassContext != nullptr);
// Dump the assertions
dumpAssertions("pre-everything", assertions);
@@ -109,9 +110,6 @@ bool ProcessAssertions::apply(AssertionPipeline& assertions)
return true;
}
- SubstitutionMap& top_level_substs =
- d_preprocessingPassContext->getTopLevelSubstitutions();
-
if (options::bvGaussElim())
{
d_passes["bv-gauss"]->apply(&assertions);
@@ -134,11 +132,15 @@ bool ProcessAssertions::apply(AssertionPipeline& assertions)
Chat() << "expanding definitions..." << endl;
Trace("simplify") << "ProcessAssertions::simplify(): expanding definitions"
<< endl;
- TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_definitionExpansionTime);
+ TimerStat::CodeTimer codeTimer(d_smtStats.d_definitionExpansionTime);
unordered_map<Node, Node, NodeHashFunction> cache;
for (size_t i = 0, nasserts = assertions.size(); i < nasserts; ++i)
{
- assertions.replace(i, expandDefinitions(assertions[i], cache));
+ Node expd = expandDefinitions(assertions[i], cache);
+ if (expd != assertions[i])
+ {
+ assertions.replace(i, expd);
+ }
}
}
Trace("smt-proc")
@@ -146,19 +148,13 @@ bool ProcessAssertions::apply(AssertionPipeline& assertions)
<< endl;
dumpAssertions("post-definition-expansion", assertions);
- // save the assertions now
- THEORY_PROOF(
- for (size_t i = 0, nasserts = assertions.size(); i < nasserts; ++i) {
- ProofManager::currentPM()->addAssertion(assertions[i].toExpr());
- });
-
Debug("smt") << " assertions : " << assertions.size() << endl;
if (options::globalNegate())
{
// global negation of the formula
d_passes["global-negate"]->apply(&assertions);
- d_smt.d_globalNegation = !d_smt.d_globalNegation;
+ as.flipGlobalNegated();
}
if (options::nlExtPurify())
@@ -207,16 +203,6 @@ bool ProcessAssertions::apply(AssertionPipeline& assertions)
d_passes["bv-intro-pow2"]->apply(&assertions);
}
- // Since this pass is not robust for the information tracking necessary for
- // unsat cores, it's only applied if we are not doing unsat core computation
- if (!options::unsatCores())
- {
- d_passes["apply-substs"]->apply(&assertions);
- }
-
- // Assertions MUST BE guaranteed to be rewritten by this point
- d_passes["rewrite"]->apply(&assertions);
-
// Lift bit-vectors of size 1 to bool
if (options::bitvectorToBool())
{
@@ -225,8 +211,22 @@ bool ProcessAssertions::apply(AssertionPipeline& assertions)
if (options::solveBVAsInt() != options::SolveBVAsIntMode::OFF)
{
d_passes["bv-to-int"]->apply(&assertions);
+ // after running bv-to-int, we need to immediately run
+ // theory-preprocess and ite-removal so that newlly created
+ // terms and assertions are normalized (e.g., div is expanded).
+ d_passes["theory-preprocess"]->apply(&assertions);
}
+ // Since this pass is not robust for the information tracking necessary for
+ // unsat cores, it's only applied if we are not doing unsat core computation
+ if (!options::unsatCores())
+ {
+ d_passes["apply-substs"]->apply(&assertions);
+ }
+
+ // Assertions MUST BE guaranteed to be rewritten by this point
+ d_passes["rewrite"]->apply(&assertions);
+
// Convert non-top-level Booleans to bit-vectors of size 1
if (options::boolToBitvector() != options::BoolToBVMode::OFF)
{
@@ -237,7 +237,7 @@ bool ProcessAssertions::apply(AssertionPipeline& assertions)
d_passes["sep-skolem-emp"]->apply(&assertions);
}
- if (d_smt.d_logic.isQuantified())
+ if (d_smt.getLogicInfo().isQuantified())
{
// remove rewrite rules, apply pre-skolemization to existential quantifiers
d_passes["quantifiers-preprocess"]->apply(&assertions);
@@ -251,38 +251,7 @@ bool ProcessAssertions::apply(AssertionPipeline& assertions)
// to FMF
if (options::fmfFunWellDefined())
{
- quantifiers::FunDefFmf fdf;
- Assert(d_fmfRecFunctionsDefined != NULL);
- // must carry over current definitions (in case of incremental)
- for (context::CDList<Node>::const_iterator fit =
- d_fmfRecFunctionsDefined->begin();
- fit != d_fmfRecFunctionsDefined->end();
- ++fit)
- {
- Node f = (*fit);
- Assert(d_fmfRecFunctionsAbs.find(f) != d_fmfRecFunctionsAbs.end());
- TypeNode ft = d_fmfRecFunctionsAbs[f];
- fdf.d_sorts[f] = ft;
- std::map<Node, std::vector<Node>>::iterator fcit =
- d_fmfRecFunctionsConcrete.find(f);
- Assert(fcit != d_fmfRecFunctionsConcrete.end());
- for (const Node& fcc : fcit->second)
- {
- fdf.d_input_arg_inj[f].push_back(fcc);
- }
- }
- fdf.simplify(assertions.ref());
- // must store new definitions (in case of incremental)
- for (const Node& f : fdf.d_funcs)
- {
- d_fmfRecFunctionsAbs[f] = fdf.d_sorts[f];
- d_fmfRecFunctionsConcrete[f].clear();
- for (const Node& fcc : fdf.d_input_arg_inj[f])
- {
- d_fmfRecFunctionsConcrete[f].push_back(fcc);
- }
- d_fmfRecFunctionsDefined->push_back(f);
- }
+ d_passes["fun-def-fmf"]->apply(&assertions);
}
}
@@ -297,7 +266,7 @@ bool ProcessAssertions::apply(AssertionPipeline& assertions)
}
// rephrasing normal inputs as sygus problems
- if (!d_smt.d_isInternalSubsolver)
+ if (!d_smt.isInternalSubsolver())
{
if (options::sygusInference())
{
@@ -317,7 +286,7 @@ bool ProcessAssertions::apply(AssertionPipeline& assertions)
noConflict = simplifyAssertions(assertions);
if (!noConflict)
{
- ++(d_smt.d_stats->d_simplifiedToFalse);
+ ++(d_smtStats.d_simplifiedToFalse);
}
Trace("smt-proc") << "ProcessAssertions::processAssertions() : post-simplify"
<< endl;
@@ -330,13 +299,13 @@ bool ProcessAssertions::apply(AssertionPipeline& assertions)
Debug("smt") << " assertions : " << assertions.size() << endl;
{
- d_smt.d_stats->d_numAssertionsPre += assertions.size();
+ d_smtStats.d_numAssertionsPre += assertions.size();
d_passes["ite-removal"]->apply(&assertions);
// This is needed because when solving incrementally, removeITEs may
// introduce skolems that were solved for earlier and thus appear in the
// substitution map.
d_passes["apply-substs"]->apply(&assertions);
- d_smt.d_stats->d_numAssertionsPost += assertions.size();
+ d_smtStats.d_numAssertionsPost += assertions.size();
}
dumpAssertions("pre-repeat-simplify", assertions);
@@ -363,6 +332,8 @@ bool ProcessAssertions::apply(AssertionPipeline& assertions)
// First, find all skolems that appear in the substitution map - their
// associated iteExpr will need to be moved to the main assertion set
set<TNode> skolemSet;
+ SubstitutionMap& top_level_substs =
+ d_preprocessingPassContext->getTopLevelSubstitutions().get();
SubstitutionMap::iterator pos = top_level_substs.begin();
for (; pos != top_level_substs.end(); ++pos)
{
@@ -376,8 +347,7 @@ bool ProcessAssertions::apply(AssertionPipeline& assertions)
// assertion
IteSkolemMap::iterator it = iskMap.begin();
IteSkolemMap::iterator iend = iskMap.end();
- NodeBuilder<> builder(AND);
- builder << assertions[assertions.getRealAssertionsEnd() - 1];
+ std::vector<Node> newConj;
vector<TNode> toErase;
for (; it != iend; ++it)
{
@@ -404,19 +374,20 @@ bool ProcessAssertions::apply(AssertionPipeline& assertions)
}
}
// Move this iteExpr into the main assertions
- builder << assertions[(*it).second];
- assertions[(*it).second] = d_true;
+ newConj.push_back(assertions[(*it).second]);
+ assertions.replace((*it).second, d_true);
toErase.push_back((*it).first);
}
- if (builder.getNumChildren() > 1)
+ if (!newConj.empty())
{
while (!toErase.empty())
{
iskMap.erase(toErase.back());
toErase.pop_back();
}
- assertions[assertions.getRealAssertionsEnd() - 1] =
- Rewriter::rewrite(Node(builder));
+ size_t index = assertions.getRealAssertionsEnd() - 1;
+ Node newAssertion = NodeManager::currentNM()->mkAnd(newConj);
+ assertions.conjoin(index, newAssertion);
}
// TODO(b/1256): For some reason this is needed for some benchmarks, such
// as
@@ -445,6 +416,11 @@ bool ProcessAssertions::apply(AssertionPipeline& assertions)
Debug("smt") << " assertions : " << assertions.size() << endl;
d_passes["theory-preprocess"]->apply(&assertions);
+ // Must remove ITEs again since theory preprocessing may introduce them.
+ // Notice that we alternatively could ensure that the theory-preprocess
+ // pass above calls TheoryPreprocess::preprocess instead of
+ // TheoryPreprocess::theoryPreprocess, as the former also does ITE removal.
+ d_passes["ite-removal"]->apply(&assertions);
if (options::bitblastMode() == options::BitblastMode::EAGER)
{
@@ -461,7 +437,6 @@ bool ProcessAssertions::apply(AssertionPipeline& assertions)
bool ProcessAssertions::simplifyAssertions(AssertionPipeline& assertions)
{
spendResource(ResourceManager::Resource::PreprocessStep);
- Assert(d_smt.d_pendingPops == 0);
try
{
ScopeCounter depth(d_simplifyAssertionsDepth);
@@ -470,7 +445,7 @@ bool ProcessAssertions::simplifyAssertions(AssertionPipeline& assertions)
if (options::simplificationMode() != options::SimplificationMode::NONE)
{
- if (!options::unsatCores() && !options::fewerPreprocessingHoles())
+ if (!options::unsatCores())
{
// Perform non-clausal simplification
PreprocessingPassResult res =
@@ -486,7 +461,7 @@ bool ProcessAssertions::simplifyAssertions(AssertionPipeline& assertions)
if ( // check that option is on
options::arithMLTrick() &&
// only useful in arith
- d_smt.d_logic.isTheoryEnabled(THEORY_ARITH) &&
+ d_smt.getLogicInfo().isTheoryEnabled(THEORY_ARITH) &&
// we add new assertions and need this (in practice, this
// restriction only disables miplib processing during
// re-simplification, which we don't expect to be useful anyway)
@@ -503,9 +478,6 @@ bool ProcessAssertions::simplifyAssertions(AssertionPipeline& assertions)
Debug("smt") << " assertions : " << assertions.size() << endl;
- // before ppRewrite check if only core theory for BV theory
- d_smt.d_theoryEngine->staticInitializeBVOptions(assertions.ref());
-
// Theory preprocessing
bool doEarlyTheoryPp = !options::arithRewriteEq();
if (doEarlyTheoryPp)
@@ -535,7 +507,7 @@ bool ProcessAssertions::simplifyAssertions(AssertionPipeline& assertions)
if (options::repeatSimp()
&& options::simplificationMode() != options::SimplificationMode::NONE
- && !options::unsatCores() && !options::fewerPreprocessingHoles())
+ && !options::unsatCores())
{
PreprocessingPassResult res =
d_passes["non-clausal-simp"]->apply(&assertions);
@@ -572,7 +544,8 @@ void ProcessAssertions::dumpAssertions(const char* key,
for (unsigned i = 0; i < assertionList.size(); ++i)
{
TNode n = assertionList[i];
- Dump("assertions") << AssertCommand(Expr(n.toExpr()));
+ d_smt.getOutputManager().getPrinter().toStreamCmdAssert(
+ d_smt.getOutputManager().getDumpOut(), n);
}
}
}
@@ -582,7 +555,7 @@ Node ProcessAssertions::expandDefinitions(
unordered_map<Node, Node, NodeHashFunction>& cache,
bool expandOnly)
{
- NodeManager* nm = d_smt.d_nodeManager;
+ NodeManager* nm = d_smt.getNodeManager();
std::stack<std::tuple<Node, Node, bool>> worklist;
std::stack<Node> result;
worklist.push(std::make_tuple(Node(n), Node(n), false));
@@ -609,9 +582,9 @@ Node ProcessAssertions::expandDefinitions(
// we can short circuit (variable) leaves
if (n.isVar())
{
- SmtEngine::DefinedFunctionMap::const_iterator i =
- d_smt.d_definedFunctions->find(n);
- if (i != d_smt.d_definedFunctions->end())
+ SmtEngine::DefinedFunctionMap* dfuns = d_smt.getDefinedFunctionMap();
+ SmtEngine::DefinedFunctionMap::const_iterator i = dfuns->find(n);
+ if (i != dfuns->end())
{
Node f = (*i).second.getFormula();
// must expand its definition
@@ -683,9 +656,9 @@ Node ProcessAssertions::expandDefinitions(
{
// application of a user-defined symbol
TNode func = n.getOperator();
- SmtEngine::DefinedFunctionMap::const_iterator i =
- d_smt.d_definedFunctions->find(func);
- if (i == d_smt.d_definedFunctions->end())
+ SmtEngine::DefinedFunctionMap* dfuns = d_smt.getDefinedFunctionMap();
+ SmtEngine::DefinedFunctionMap::const_iterator i = dfuns->find(func);
+ if (i == dfuns->end())
{
throw TypeCheckingException(
n.toExpr(),
@@ -735,7 +708,7 @@ Node ProcessAssertions::expandDefinitions(
{
// do not do any theory stuff if expandOnly is true
- theory::Theory* t = d_smt.d_theoryEngine->theoryOf(node);
+ theory::Theory* t = d_smt.getTheoryEngine()->theoryOf(node);
Assert(t != NULL);
TrustNode trn = t->expandDefinition(n);
diff --git a/src/smt/process_assertions.h b/src/smt/process_assertions.h
index 4850d5589..d260edf14 100644
--- a/src/smt/process_assertions.h
+++ b/src/smt/process_assertions.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,6 +25,7 @@
#include "expr/type_node.h"
#include "preprocessing/preprocessing_pass.h"
#include "preprocessing/preprocessing_pass_context.h"
+#include "smt/assertions.h"
#include "smt/smt_engine_stats.h"
#include "util/resource_manager.h"
@@ -56,7 +57,9 @@ class ProcessAssertions
typedef unordered_map<Node, bool, NodeHashFunction> NodeToBoolHashMap;
public:
- ProcessAssertions(SmtEngine& smt, ResourceManager& rm);
+ ProcessAssertions(SmtEngine& smt,
+ ResourceManager& rm,
+ SmtEngineStatistics& stats);
~ProcessAssertions();
/** Finish initialize
*
@@ -69,16 +72,18 @@ class ProcessAssertions
*/
void cleanup();
/**
- * Process the formulas in assertions. Returns true if there
- * was no conflict when processing the assertions.
+ * Process the formulas in as. Returns true if there was no conflict when
+ * processing the assertions.
*/
- bool apply(preprocessing::AssertionPipeline& assertions);
+ bool apply(Assertions& as);
/**
* Expand definitions in term n. Return the expanded form of n.
*
- * If expandOnly is true, then the expandDefinitions function of TheoryEngine
- * of the SmtEngine this calls is associated with is not called on subterms of
- * n.
+ * @param n The node to expand
+ * @param cache Cache of previous results
+ * @param expandOnly if true, then the expandDefinitions function of
+ * TheoryEngine is not called on subterms of n.
+ * @return The expanded term.
*/
Node expandDefinitions(TNode n,
NodeToNodeHashMap& cache,
@@ -89,6 +94,8 @@ class ProcessAssertions
SmtEngine& d_smt;
/** Reference to resource manager */
ResourceManager& d_resourceManager;
+ /** Reference to the SMT stats */
+ SmtEngineStatistics& d_smtStats;
/** The preprocess context */
preprocessing::PreprocessingPassContext* d_preprocessingPassContext;
/** True node */
@@ -104,12 +111,6 @@ class ProcessAssertions
* Number of calls of simplify assertions active.
*/
unsigned d_simplifyAssertionsDepth;
- /** recursive function definition abstractions for fmf-fun */
- std::map<Node, TypeNode> d_fmfRecFunctionsAbs;
- /** map to concrete definitions for fmf-fun */
- std::map<Node, std::vector<Node>> d_fmfRecFunctionsConcrete;
- /** List of defined recursive functions processed by fmf-fun */
- NodeList* d_fmfRecFunctionsDefined;
/** Spend resource r by the resource manager of this class. */
void spendResource(ResourceManager::Resource r);
/**
diff --git a/src/smt/proof_manager.cpp b/src/smt/proof_manager.cpp
new file mode 100644
index 000000000..685032136
--- /dev/null
+++ b/src/smt/proof_manager.cpp
@@ -0,0 +1,151 @@
+/********************* */
+/*! \file proof_manager.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The proof manager of the SMT engine
+ **/
+
+#include "smt/proof_manager.h"
+
+#include "expr/proof_node_algorithm.h"
+#include "options/base_options.h"
+#include "options/smt_options.h"
+#include "smt/assertions.h"
+
+namespace CVC4 {
+namespace smt {
+
+PfManager::PfManager(context::UserContext* u, SmtEngine* smte)
+ : d_pchecker(new ProofChecker(options::proofNewPedantic())),
+ d_pnm(new ProofNodeManager(d_pchecker.get())),
+ d_pppg(new PreprocessProofGenerator(
+ d_pnm.get(), u, "smt::PreprocessProofGenerator")),
+ d_pfpp(new ProofPostproccess(d_pnm.get(), smte, d_pppg.get())),
+ d_finalProof(nullptr)
+{
+ // add rules to eliminate here
+ if (options::proofGranularityMode() != options::ProofGranularityMode::OFF)
+ {
+ d_pfpp->setEliminateRule(PfRule::MACRO_SR_EQ_INTRO);
+ d_pfpp->setEliminateRule(PfRule::MACRO_SR_PRED_INTRO);
+ d_pfpp->setEliminateRule(PfRule::MACRO_SR_PRED_ELIM);
+ d_pfpp->setEliminateRule(PfRule::MACRO_SR_PRED_TRANSFORM);
+ if (options::proofGranularityMode()
+ != options::ProofGranularityMode::REWRITE)
+ {
+ d_pfpp->setEliminateRule(PfRule::SUBS);
+ d_pfpp->setEliminateRule(PfRule::REWRITE);
+ if (options::proofGranularityMode()
+ != options::ProofGranularityMode::THEORY_REWRITE)
+ {
+ // this eliminates theory rewriting steps with finer-grained DSL rules
+ d_pfpp->setEliminateRule(PfRule::THEORY_REWRITE);
+ }
+ }
+ }
+ d_false = NodeManager::currentNM()->mkConst(false);
+}
+
+PfManager::~PfManager() {}
+
+void PfManager::setFinalProof(ProofGenerator* pg, context::CDList<Node>* al)
+{
+ Assert(al != nullptr);
+ // Note this assumes that setFinalProof is only called once per unsat
+ // response. This method would need to cache its result otherwise.
+ Trace("smt-proof") << "SmtEngine::setFinalProof(): get proof body...\n";
+
+ // d_finalProof should just be a ProofNode
+ std::shared_ptr<ProofNode> body = pg->getProofFor(d_false)->clone();
+
+ if (Trace.isOn("smt-proof-debug"))
+ {
+ Trace("smt-proof-debug")
+ << "SmtEngine::setFinalProof(): Proof node for false:\n";
+ Trace("smt-proof-debug") << *body.get() << std::endl;
+ Trace("smt-proof-debug") << "=====" << std::endl;
+ }
+
+ if (Trace.isOn("smt-proof"))
+ {
+ std::vector<Node> fassumps;
+ expr::getFreeAssumptions(body.get(), fassumps);
+ Trace("smt-proof")
+ << "SmtEngine::setFinalProof(): initial free assumptions are:\n";
+ for (const Node& a : fassumps)
+ {
+ Trace("smt-proof") << "- " << a << std::endl;
+ }
+ }
+
+ std::vector<Node> assertions;
+ Trace("smt-proof") << "SmtEngine::setFinalProof(): assertions are:\n";
+ for (context::CDList<Node>::const_iterator i = al->begin(); i != al->end();
+ ++i)
+ {
+ Node n = *i;
+ Trace("smt-proof") << "- " << n << std::endl;
+ assertions.push_back(n);
+ }
+ Trace("smt-proof") << "=====" << std::endl;
+
+ Trace("smt-proof") << "SmtEngine::setFinalProof(): postprocess...\n";
+ Assert(d_pfpp != nullptr);
+ d_pfpp->process(body);
+
+ Trace("smt-proof") << "SmtEngine::setFinalProof(): make scope...\n";
+
+ // Now make the final scope, which ensures that the only open leaves
+ // of the proof are the assertions.
+ d_finalProof = d_pnm->mkScope(body, assertions);
+ Trace("smt-proof") << "SmtEngine::setFinalProof(): finished.\n";
+}
+
+void PfManager::printProof(ProofGenerator* pg, Assertions& as)
+{
+ Trace("smt-proof") << "PfManager::printProof: start" << std::endl;
+ std::shared_ptr<ProofNode> fp = getFinalProof(pg, as);
+ // TODO (proj #37) according to the proof format, post process the proof node
+ // TODO (proj #37) according to the proof format, print the proof node
+ // leanPrinter(out, fp.get());
+ std::ostream& out = *options::out();
+ out << "(proof\n";
+ out << *fp;
+ out << "\n)\n";
+}
+
+void PfManager::checkProof(ProofGenerator* pg, Assertions& as)
+{
+ Trace("smt-proof") << "PfManager::checkProof: start" << std::endl;
+ std::shared_ptr<ProofNode> fp = getFinalProof(pg, as);
+ Trace("smt-proof") << "PfManager::checkProof: returned " << *fp.get()
+ << std::endl;
+}
+
+ProofChecker* PfManager::getProofChecker() const { return d_pchecker.get(); }
+
+ProofNodeManager* PfManager::getProofNodeManager() const { return d_pnm.get(); }
+
+smt::PreprocessProofGenerator* PfManager::getPreprocessProofGenerator() const
+{
+ return d_pppg.get();
+}
+
+std::shared_ptr<ProofNode> PfManager::getFinalProof(ProofGenerator* pg,
+ Assertions& as)
+{
+ context::CDList<Node>* al = as.getAssertionList();
+ setFinalProof(pg, al);
+ Assert(d_finalProof);
+ return d_finalProof;
+}
+
+} // namespace smt
+} // namespace CVC4
diff --git a/src/smt/proof_manager.h b/src/smt/proof_manager.h
new file mode 100644
index 000000000..118b82bec
--- /dev/null
+++ b/src/smt/proof_manager.h
@@ -0,0 +1,103 @@
+/********************* */
+/*! \file proof_manager.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The proof manager of SmtEngine
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__SMT__PROOF_MANAGER_H
+#define CVC4__SMT__PROOF_MANAGER_H
+
+#include "context/cdlist.h"
+#include "expr/expr.h"
+#include "expr/node.h"
+#include "expr/proof_checker.h"
+#include "expr/proof_node.h"
+#include "expr/proof_node_manager.h"
+#include "smt/preprocess_proof_generator.h"
+#include "smt/proof_post_processor.h"
+
+namespace CVC4 {
+
+class SmtEngine;
+
+namespace smt {
+
+class Assertions;
+
+/**
+ * This class is responsible for managing the proof output of SmtEngine, as
+ * well as setting up the global proof checker and proof node manager.
+ */
+class PfManager
+{
+ public:
+ PfManager(context::UserContext* u, SmtEngine* smte);
+ ~PfManager();
+ /**
+ * Print the proof on the output channel of the current options in scope.
+ *
+ * The argument pg is the module that can provide a proof for false in the
+ * current context.
+ *
+ * Throws an assertion failure if pg cannot provide a closed proof with
+ * respect to assertions in as.
+ */
+ void printProof(ProofGenerator* pg, Assertions& as);
+ /**
+ * Check proof, same as above, without printing.
+ */
+ void checkProof(ProofGenerator* pg, Assertions& as);
+
+ /**
+ * Get final proof.
+ *
+ * The argument pg is the module that can provide a proof for false in the
+ * current context.
+ */
+ std::shared_ptr<ProofNode> getFinalProof(ProofGenerator* pg, Assertions& as);
+ //--------------------------- access to utilities
+ /** Get a pointer to the ProofChecker owned by this. */
+ ProofChecker* getProofChecker() const;
+ /** Get a pointer to the ProofNodeManager owned by this. */
+ ProofNodeManager* getProofNodeManager() const;
+ /** Get the proof generator for proofs of preprocessing. */
+ smt::PreprocessProofGenerator* getPreprocessProofGenerator() const;
+ //--------------------------- end access to utilities
+ private:
+ /**
+ * Set final proof, which initializes d_finalProof to the proof of false
+ * from pg, postprocesses it, and stores it in d_finalProof.
+ */
+ void setFinalProof(ProofGenerator* pg, context::CDList<Node>* al);
+ /** The false node */
+ Node d_false;
+ /** For the new proofs module */
+ std::unique_ptr<ProofChecker> d_pchecker;
+ /** A proof node manager based on the above checker */
+ std::unique_ptr<ProofNodeManager> d_pnm;
+ /** The preprocess proof generator. */
+ std::unique_ptr<smt::PreprocessProofGenerator> d_pppg;
+ /** The proof post-processor */
+ std::unique_ptr<smt::ProofPostproccess> d_pfpp;
+ /**
+ * The final proof produced by the SMT engine.
+ * Combines the proofs of preprocessing, prop engine and theory engine, to be
+ * connected by setFinalProof().
+ */
+ std::shared_ptr<ProofNode> d_finalProof;
+}; /* class SmtEngine */
+
+} // namespace smt
+} // namespace CVC4
+
+#endif /* CVC4__SMT__PROOF_MANAGER_H */
diff --git a/src/smt/proof_post_processor.cpp b/src/smt/proof_post_processor.cpp
new file mode 100644
index 000000000..53608fa0a
--- /dev/null
+++ b/src/smt/proof_post_processor.cpp
@@ -0,0 +1,812 @@
+/********************* */
+/*! \file proof_post_processor.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of module for processing proof nodes
+ **/
+
+#include "smt/proof_post_processor.h"
+
+#include "expr/skolem_manager.h"
+#include "options/smt_options.h"
+#include "preprocessing/assertion_pipeline.h"
+#include "smt/smt_engine.h"
+#include "smt/smt_statistics_registry.h"
+#include "theory/builtin/proof_checker.h"
+#include "theory/rewriter.h"
+#include "theory/theory.h"
+
+using namespace CVC4::kind;
+using namespace CVC4::theory;
+
+namespace CVC4 {
+namespace smt {
+
+ProofPostprocessCallback::ProofPostprocessCallback(ProofNodeManager* pnm,
+ SmtEngine* smte,
+ ProofGenerator* pppg)
+ : d_pnm(pnm), d_smte(smte), d_pppg(pppg), d_wfpm(pnm)
+{
+ d_true = NodeManager::currentNM()->mkConst(true);
+ // always check whether to update ASSUME
+ d_elimRules.insert(PfRule::ASSUME);
+}
+
+void ProofPostprocessCallback::initializeUpdate()
+{
+ d_assumpToProof.clear();
+ d_wfAssumptions.clear();
+}
+
+void ProofPostprocessCallback::setEliminateRule(PfRule rule)
+{
+ d_elimRules.insert(rule);
+}
+
+bool ProofPostprocessCallback::shouldUpdate(std::shared_ptr<ProofNode> pn,
+ bool& continueUpdate)
+{
+ return d_elimRules.find(pn->getRule()) != d_elimRules.end();
+}
+
+bool ProofPostprocessCallback::update(Node res,
+ PfRule id,
+ const std::vector<Node>& children,
+ const std::vector<Node>& args,
+ CDProof* cdp,
+ bool& continueUpdate)
+{
+ Trace("smt-proof-pp-debug") << "- Post process " << id << " " << children
+ << " / " << args << std::endl;
+
+ if (id == PfRule::ASSUME)
+ {
+ // we cache based on the assumption node, not the proof node, since there
+ // may be multiple occurrences of the same node.
+ Node f = args[0];
+ std::shared_ptr<ProofNode> pfn;
+ std::map<Node, std::shared_ptr<ProofNode>>::iterator it =
+ d_assumpToProof.find(f);
+ if (it != d_assumpToProof.end())
+ {
+ Trace("smt-proof-pp-debug") << "...already computed" << std::endl;
+ pfn = it->second;
+ }
+ else
+ {
+ Trace("smt-proof-pp-debug") << "...get proof" << std::endl;
+ Assert(d_pppg != nullptr);
+ // get proof from preprocess proof generator
+ pfn = d_pppg->getProofFor(f);
+ Trace("smt-proof-pp-debug") << "...finished get proof" << std::endl;
+ // print for debugging
+ if (pfn == nullptr)
+ {
+ Trace("smt-proof-pp-debug")
+ << "...no proof, possibly an input assumption" << std::endl;
+ }
+ else
+ {
+ Assert(pfn->getResult() == f);
+ if (Trace.isOn("smt-proof-pp"))
+ {
+ Trace("smt-proof-pp")
+ << "=== Connect proof for preprocessing: " << f << std::endl;
+ Trace("smt-proof-pp") << *pfn.get() << std::endl;
+ }
+ }
+ d_assumpToProof[f] = pfn;
+ }
+ if (pfn == nullptr || pfn->getRule() == PfRule::ASSUME)
+ {
+ Trace("smt-proof-pp-debug") << "...do not add proof" << std::endl;
+ // no update
+ return false;
+ }
+ Trace("smt-proof-pp-debug") << "...add proof" << std::endl;
+ // connect the proof
+ cdp->addProof(pfn);
+ return true;
+ }
+ Node ret = expandMacros(id, children, args, cdp);
+ Trace("smt-proof-pp-debug") << "...expanded = " << !ret.isNull() << std::endl;
+ return !ret.isNull();
+}
+
+bool ProofPostprocessCallback::updateInternal(Node res,
+ PfRule id,
+ const std::vector<Node>& children,
+ const std::vector<Node>& args,
+ CDProof* cdp)
+{
+ bool continueUpdate = true;
+ return update(res, id, children, args, cdp, continueUpdate);
+}
+
+Node ProofPostprocessCallback::expandMacros(PfRule id,
+ const std::vector<Node>& children,
+ const std::vector<Node>& args,
+ CDProof* cdp)
+{
+ if (d_elimRules.find(id) == d_elimRules.end())
+ {
+ // not eliminated
+ return Node::null();
+ }
+ // macro elimination
+ if (id == PfRule::MACRO_SR_EQ_INTRO)
+ {
+ // (TRANS
+ // (SUBS <children> :args args[0:1])
+ // (REWRITE :args <t.substitute(x1,t1). ... .substitute(xn,tn)> args[2]))
+ std::vector<Node> tchildren;
+ Node t = args[0];
+ Node ts;
+ if (!children.empty())
+ {
+ std::vector<Node> sargs;
+ sargs.push_back(t);
+ MethodId sid = MethodId::SB_DEFAULT;
+ if (args.size() >= 2)
+ {
+ if (builtin::BuiltinProofRuleChecker::getMethodId(args[1], sid))
+ {
+ sargs.push_back(args[1]);
+ }
+ }
+ ts =
+ builtin::BuiltinProofRuleChecker::applySubstitution(t, children, sid);
+ Trace("smt-proof-pp-debug")
+ << "...eq intro subs equality is " << t << " == " << ts << ", from "
+ << sid << std::endl;
+ if (ts != t)
+ {
+ Node eq = t.eqNode(ts);
+ // apply SUBS proof rule if necessary
+ if (!updateInternal(eq, PfRule::SUBS, children, sargs, cdp))
+ {
+ // if we specified that we did not want to eliminate, add as step
+ cdp->addStep(eq, PfRule::SUBS, children, sargs);
+ }
+ tchildren.push_back(eq);
+ }
+ }
+ else
+ {
+ // no substitute
+ ts = t;
+ }
+ std::vector<Node> rargs;
+ rargs.push_back(ts);
+ MethodId rid = MethodId::RW_REWRITE;
+ if (args.size() >= 3)
+ {
+ if (builtin::BuiltinProofRuleChecker::getMethodId(args[2], rid))
+ {
+ rargs.push_back(args[2]);
+ }
+ }
+ builtin::BuiltinProofRuleChecker* builtinPfC =
+ static_cast<builtin::BuiltinProofRuleChecker*>(
+ d_pnm->getChecker()->getCheckerFor(PfRule::MACRO_SR_EQ_INTRO));
+ Node tr = builtinPfC->applyRewrite(ts, rid);
+ Trace("smt-proof-pp-debug")
+ << "...eq intro rewrite equality is " << ts << " == " << tr << ", from "
+ << rid << std::endl;
+ if (ts != tr)
+ {
+ Node eq = ts.eqNode(tr);
+ // apply REWRITE proof rule
+ if (!updateInternal(eq, PfRule::REWRITE, {}, rargs, cdp))
+ {
+ // if not elimianted, add as step
+ cdp->addStep(eq, PfRule::REWRITE, {}, rargs);
+ }
+ tchildren.push_back(eq);
+ }
+ if (t == tr)
+ {
+ // typically not necessary, but done to be robust
+ cdp->addStep(t.eqNode(tr), PfRule::REFL, {}, {t});
+ return t.eqNode(tr);
+ }
+ // must add TRANS if two step
+ return addProofForTrans(tchildren, cdp);
+ }
+ else if (id == PfRule::MACRO_SR_PRED_INTRO)
+ {
+ std::vector<Node> tchildren;
+ std::vector<Node> sargs = args;
+ // take into account witness form, if necessary
+ bool reqWitness = d_wfpm.requiresWitnessFormIntro(args[0]);
+ Trace("smt-proof-pp-debug")
+ << "...pred intro reqWitness=" << reqWitness << std::endl;
+ // (TRUE_ELIM
+ // (TRANS
+ // (MACRO_SR_EQ_INTRO <children> :args (t args[1:]))
+ // ... proof of apply_SR(t) = toWitness(apply_SR(t)) ...
+ // (MACRO_SR_EQ_INTRO {} {toWitness(apply_SR(t))})
+ // ))
+ // Notice this is an optimized, one sided version of the expansion of
+ // MACRO_SR_PRED_TRANSFORM below.
+ // We call the expandMacros method on MACRO_SR_EQ_INTRO, where notice
+ // that this rule application is immediately expanded in the recursive
+ // call and not added to the proof.
+ Node conc = expandMacros(PfRule::MACRO_SR_EQ_INTRO, children, sargs, cdp);
+ Trace("smt-proof-pp-debug")
+ << "...pred intro conclusion is " << conc << std::endl;
+ Assert(!conc.isNull());
+ Assert(conc.getKind() == EQUAL);
+ Assert(conc[0] == args[0]);
+ tchildren.push_back(conc);
+ if (reqWitness)
+ {
+ Node weq = addProofForWitnessForm(conc[1], cdp);
+ Trace("smt-proof-pp-debug") << "...weq is " << weq << std::endl;
+ if (addToTransChildren(weq, tchildren))
+ {
+ // toWitness(apply_SR(t)) = apply_SR(toWitness(apply_SR(t)))
+ // rewrite again, don't need substitution. Also we always use the
+ // default rewriter, due to the definition of MACRO_SR_PRED_INTRO.
+ Node weqr = expandMacros(PfRule::MACRO_SR_EQ_INTRO, {}, {weq[1]}, cdp);
+ addToTransChildren(weqr, tchildren);
+ }
+ }
+ // apply transitivity if necessary
+ Node eq = addProofForTrans(tchildren, cdp);
+ Assert(!eq.isNull());
+ Assert(eq.getKind() == EQUAL);
+ Assert(eq[0] == args[0]);
+ Assert(eq[1] == d_true);
+
+ cdp->addStep(eq[0], PfRule::TRUE_ELIM, {eq}, {});
+ return eq[0];
+ }
+ else if (id == PfRule::MACRO_SR_PRED_ELIM)
+ {
+ // (EQ_RESOLVE
+ // children[0]
+ // (MACRO_SR_EQ_INTRO children[1:] :args children[0] ++ args))
+ std::vector<Node> schildren(children.begin() + 1, children.end());
+ std::vector<Node> srargs;
+ srargs.push_back(children[0]);
+ srargs.insert(srargs.end(), args.begin(), args.end());
+ Node conc = expandMacros(PfRule::MACRO_SR_EQ_INTRO, schildren, srargs, cdp);
+ Assert(!conc.isNull());
+ Assert(conc.getKind() == EQUAL);
+ Assert(conc[0] == children[0]);
+ // apply equality resolve
+ cdp->addStep(conc[1], PfRule::EQ_RESOLVE, {children[0], conc}, {});
+ return conc[1];
+ }
+ else if (id == PfRule::MACRO_SR_PRED_TRANSFORM)
+ {
+ // (EQ_RESOLVE
+ // children[0]
+ // (TRANS
+ // (MACRO_SR_EQ_INTRO children[1:] :args (children[0] args[1:]))
+ // ... proof of c = wc
+ // (MACRO_SR_EQ_INTRO {} wc)
+ // (SYMM
+ // (MACRO_SR_EQ_INTRO children[1:] :args <args>)
+ // ... proof of a = wa
+ // (MACRO_SR_EQ_INTRO {} wa))))
+ // where
+ // wa = toWitness(apply_SR(args[0])) and
+ // wc = toWitness(apply_SR(children[0])).
+ Trace("smt-proof-pp-debug")
+ << "Transform " << children[0] << " == " << args[0] << std::endl;
+ if (CDProof::isSame(children[0], args[0]))
+ {
+ Trace("smt-proof-pp-debug") << "...nothing to do" << std::endl;
+ // nothing to do
+ return children[0];
+ }
+ std::vector<Node> tchildren;
+ std::vector<Node> schildren(children.begin() + 1, children.end());
+ std::vector<Node> sargs = args;
+ // first, compute if we need
+ bool reqWitness = d_wfpm.requiresWitnessFormTransform(children[0], args[0]);
+ Trace("smt-proof-pp-debug") << "...reqWitness=" << reqWitness << std::endl;
+ // convert both sides, in three steps, take symmetry of second chain
+ for (unsigned r = 0; r < 2; r++)
+ {
+ std::vector<Node> tchildrenr;
+ // first rewrite children[0], then args[0]
+ sargs[0] = r == 0 ? children[0] : args[0];
+ // t = apply_SR(t)
+ Node eq = expandMacros(PfRule::MACRO_SR_EQ_INTRO, schildren, sargs, cdp);
+ Trace("smt-proof-pp-debug")
+ << "transform subs_rewrite (" << r << "): " << eq << std::endl;
+ Assert(!eq.isNull() && eq.getKind() == EQUAL && eq[0] == sargs[0]);
+ addToTransChildren(eq, tchildrenr);
+ // apply_SR(t) = toWitness(apply_SR(t))
+ if (reqWitness)
+ {
+ Node weq = addProofForWitnessForm(eq[1], cdp);
+ Trace("smt-proof-pp-debug")
+ << "transform toWitness (" << r << "): " << weq << std::endl;
+ if (addToTransChildren(weq, tchildrenr))
+ {
+ // toWitness(apply_SR(t)) = apply_SR(toWitness(apply_SR(t)))
+ // rewrite again, don't need substitution. Also, we always use the
+ // default rewriter, due to the definition of MACRO_SR_PRED_TRANSFORM.
+ Node weqr =
+ expandMacros(PfRule::MACRO_SR_EQ_INTRO, {}, {weq[1]}, cdp);
+ Trace("smt-proof-pp-debug") << "transform rewrite_witness (" << r
+ << "): " << weqr << std::endl;
+ addToTransChildren(weqr, tchildrenr);
+ }
+ }
+ Trace("smt-proof-pp-debug")
+ << "transform connect (" << r << ")" << std::endl;
+ // add to overall chain
+ if (r == 0)
+ {
+ // add the current chain to the overall chain
+ tchildren.insert(tchildren.end(), tchildrenr.begin(), tchildrenr.end());
+ }
+ else
+ {
+ // add the current chain to cdp
+ Node eqr = addProofForTrans(tchildrenr, cdp);
+ if (!eqr.isNull())
+ {
+ Trace("smt-proof-pp-debug") << "transform connect sym " << tchildren
+ << " " << eqr << std::endl;
+ // take symmetry of above and add it to the overall chain
+ addToTransChildren(eqr, tchildren, true);
+ }
+ }
+ Trace("smt-proof-pp-debug")
+ << "transform finish (" << r << ")" << std::endl;
+ }
+
+ // apply transitivity if necessary
+ Node eq = addProofForTrans(tchildren, cdp);
+
+ cdp->addStep(args[0], PfRule::EQ_RESOLVE, {children[0], eq}, {});
+ return args[0];
+ }
+ else if (id == PfRule::SUBS)
+ {
+ NodeManager* nm = NodeManager::currentNM();
+ // Notice that a naive way to reconstruct SUBS is to do a term conversion
+ // proof for each substitution.
+ // The proof of f(a) * { a -> g(b) } * { b -> c } = f(g(c)) is:
+ // TRANS( CONG{f}( a=g(b) ), CONG{f}( CONG{g}( b=c ) ) )
+ // Notice that more optimal proofs are possible that do a single traversal
+ // over t. This is done by applying later substitutions to the range of
+ // previous substitutions, until a final simultaneous substitution is
+ // applied to t. For instance, in the above example, we first prove:
+ // CONG{g}( b = c )
+ // by applying the second substitution { b -> c } to the range of the first,
+ // giving us a proof of g(b)=g(c). We then construct the updated proof
+ // by tranitivity:
+ // TRANS( a=g(b), CONG{g}( b=c ) )
+ // We then apply the substitution { a -> g(c), b -> c } to f(a), to obtain:
+ // CONG{f}( TRANS( a=g(b), CONG{g}( b=c ) ) )
+ // which notice is more compact than the proof above.
+ Node t = args[0];
+ // get the kind of substitution
+ MethodId ids = MethodId::SB_DEFAULT;
+ if (args.size() >= 2)
+ {
+ builtin::BuiltinProofRuleChecker::getMethodId(args[1], ids);
+ }
+ std::vector<std::shared_ptr<CDProof>> pfs;
+ std::vector<TNode> vsList;
+ std::vector<TNode> ssList;
+ std::vector<TNode> fromList;
+ std::vector<ProofGenerator*> pgs;
+ // first, compute the entire substitution
+ for (size_t i = 0, nchild = children.size(); i < nchild; i++)
+ {
+ // get the substitution
+ builtin::BuiltinProofRuleChecker::getSubstitutionFor(
+ children[i], vsList, ssList, fromList, ids);
+ // ensure proofs for each formula in fromList
+ if (children[i].getKind() == AND && ids == MethodId::SB_DEFAULT)
+ {
+ for (size_t j = 0, nchildi = children[i].getNumChildren(); j < nchildi;
+ j++)
+ {
+ Node nodej = nm->mkConst(Rational(j));
+ cdp->addStep(
+ children[i][j], PfRule::AND_ELIM, {children[i]}, {nodej});
+ }
+ }
+ }
+ std::vector<Node> vvec;
+ std::vector<Node> svec;
+ for (size_t i = 0, nvs = vsList.size(); i < nvs; i++)
+ {
+ // Note we process in forward order, since later substitution should be
+ // applied to earlier ones, and the last child of a SUBS is processed
+ // first.
+ TNode var = vsList[i];
+ TNode subs = ssList[i];
+ TNode childFrom = fromList[i];
+ Trace("smt-proof-pp-debug")
+ << "...process " << var << " -> " << subs << " (" << childFrom << ", "
+ << ids << ")" << std::endl;
+ // apply the current substitution to the range
+ if (!vvec.empty())
+ {
+ Node ss =
+ subs.substitute(vvec.begin(), vvec.end(), svec.begin(), svec.end());
+ if (ss != subs)
+ {
+ Trace("smt-proof-pp-debug")
+ << "......updated to " << var << " -> " << ss
+ << " based on previous substitution" << std::endl;
+ // make the proof for the tranitivity step
+ std::shared_ptr<CDProof> pf = std::make_shared<CDProof>(d_pnm);
+ pfs.push_back(pf);
+ // prove the updated substitution
+ TConvProofGenerator tcg(d_pnm,
+ nullptr,
+ TConvPolicy::ONCE,
+ TConvCachePolicy::NEVER,
+ "nested_SUBS_TConvProofGenerator",
+ nullptr,
+ true);
+ // add previous rewrite steps
+ for (unsigned j = 0, nvars = vvec.size(); j < nvars; j++)
+ {
+ tcg.addRewriteStep(vvec[j], svec[j], pgs[j]);
+ }
+ // get the proof for the update to the current substitution
+ Node seqss = subs.eqNode(ss);
+ std::shared_ptr<ProofNode> pfn = tcg.getProofFor(seqss);
+ Assert(pfn != nullptr);
+ // add the proof
+ pf->addProof(pfn);
+ // get proof for childFrom from cdp
+ pfn = cdp->getProofFor(childFrom);
+ pf->addProof(pfn);
+ // ensure we have a proof of var = subs
+ Node veqs = addProofForSubsStep(var, subs, childFrom, pf.get());
+ // transitivity
+ pf->addStep(var.eqNode(ss), PfRule::TRANS, {veqs, seqss}, {});
+ // add to the substitution
+ vvec.push_back(var);
+ svec.push_back(ss);
+ pgs.push_back(pf.get());
+ continue;
+ }
+ }
+ // Just use equality from CDProof, but ensure we have a proof in cdp.
+ // This may involve a TRUE_INTRO/FALSE_INTRO if the substitution step
+ // uses the assumption childFrom as a Boolean assignment (e.g.
+ // childFrom = true if we are using MethodId::SB_LITERAL).
+ addProofForSubsStep(var, subs, childFrom, cdp);
+ vvec.push_back(var);
+ svec.push_back(subs);
+ pgs.push_back(cdp);
+ }
+ Node ts = t.substitute(vvec.begin(), vvec.end(), svec.begin(), svec.end());
+ Node eq = t.eqNode(ts);
+ if (ts != t)
+ {
+ // should be implied by the substitution now
+ TConvProofGenerator tcpg(d_pnm,
+ nullptr,
+ TConvPolicy::ONCE,
+ TConvCachePolicy::NEVER,
+ "SUBS_TConvProofGenerator",
+ nullptr,
+ true);
+ for (unsigned j = 0, nvars = vvec.size(); j < nvars; j++)
+ {
+ tcpg.addRewriteStep(vvec[j], svec[j], pgs[j]);
+ }
+ // add the proof constructed by the term conversion utility
+ std::shared_ptr<ProofNode> pfn = tcpg.getProofFor(eq);
+ // should give a proof, if not, then tcpg does not agree with the
+ // substitution.
+ Assert(pfn != nullptr);
+ if (pfn == nullptr)
+ {
+ cdp->addStep(eq, PfRule::TRUST_SUBS, {}, {eq});
+ }
+ else
+ {
+ cdp->addProof(pfn);
+ }
+ }
+ else
+ {
+ // should not be necessary typically
+ cdp->addStep(eq, PfRule::REFL, {}, {t});
+ }
+ return eq;
+ }
+ else if (id == PfRule::REWRITE)
+ {
+ // get the kind of rewrite
+ MethodId idr = MethodId::RW_REWRITE;
+ if (args.size() >= 2)
+ {
+ builtin::BuiltinProofRuleChecker::getMethodId(args[1], idr);
+ }
+ builtin::BuiltinProofRuleChecker* builtinPfC =
+ static_cast<builtin::BuiltinProofRuleChecker*>(
+ d_pnm->getChecker()->getCheckerFor(PfRule::REWRITE));
+ Node ret = builtinPfC->applyRewrite(args[0], idr);
+ Node eq = args[0].eqNode(ret);
+ if (idr == MethodId::RW_REWRITE || idr == MethodId::RW_REWRITE_EQ_EXT)
+ {
+ // rewrites from theory::Rewriter
+ bool isExtEq = (idr == MethodId::RW_REWRITE_EQ_EXT);
+ // use rewrite with proof interface
+ Rewriter* rr = d_smte->getRewriter();
+ TrustNode trn = rr->rewriteWithProof(args[0], isExtEq);
+ std::shared_ptr<ProofNode> pfn = trn.toProofNode();
+ if (pfn == nullptr)
+ {
+ Trace("smt-proof-pp-debug")
+ << "Use TRUST_REWRITE for " << eq << std::endl;
+ // did not have a proof of rewriting, probably isExtEq is true
+ if (isExtEq)
+ {
+ // update to THEORY_REWRITE with idr
+ Assert(args.size() >= 1);
+ TheoryId theoryId = Theory::theoryOf(args[0].getType());
+ Node tid = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(theoryId);
+ cdp->addStep(eq, PfRule::THEORY_REWRITE, {}, {eq, tid, args[1]});
+ }
+ else
+ {
+ // this should never be applied
+ cdp->addStep(eq, PfRule::TRUST_REWRITE, {}, {eq});
+ }
+ }
+ else
+ {
+ cdp->addProof(pfn);
+ }
+ Assert(trn.getNode() == ret)
+ << "Unexpected rewrite " << args[0] << std::endl
+ << "Got: " << trn.getNode() << std::endl
+ << "Expected: " << ret;
+ }
+ else if (idr == MethodId::RW_EVALUATE)
+ {
+ // change to evaluate, which is never eliminated
+ cdp->addStep(eq, PfRule::EVALUATE, {}, {args[0]});
+ }
+ else
+ {
+ // don't know how to eliminate
+ return Node::null();
+ }
+ if (args[0] == ret)
+ {
+ // should not be necessary typically
+ cdp->addStep(eq, PfRule::REFL, {}, {args[0]});
+ }
+ return eq;
+ }
+ else if (id == PfRule::THEORY_REWRITE)
+ {
+ Assert(!args.empty());
+ Node eq = args[0];
+ Assert(eq.getKind() == EQUAL);
+ // try to replay theory rewrite
+ // first, check that maybe its just an evaluation step
+ ProofChecker* pc = d_pnm->getChecker();
+ Node ceval =
+ pc->checkDebug(PfRule::EVALUATE, {}, {eq[0]}, eq, "smt-proof-pp-debug");
+ if (!ceval.isNull() && ceval == eq)
+ {
+ cdp->addStep(eq, PfRule::EVALUATE, {}, {eq[0]});
+ return eq;
+ }
+ // otherwise no update
+ Trace("final-pf-hole") << "hole: " << id << " : " << eq << std::endl;
+ }
+
+ // TRUST, PREPROCESS, THEORY_LEMMA, THEORY_PREPROCESS?
+
+ return Node::null();
+}
+
+Node ProofPostprocessCallback::addProofForWitnessForm(Node t, CDProof* cdp)
+{
+ Node tw = SkolemManager::getWitnessForm(t);
+ Node eq = t.eqNode(tw);
+ if (t == tw)
+ {
+ // not necessary, add REFL step
+ cdp->addStep(eq, PfRule::REFL, {}, {t});
+ return eq;
+ }
+ std::shared_ptr<ProofNode> pn = d_wfpm.getProofFor(eq);
+ if (pn != nullptr)
+ {
+ // add the proof
+ cdp->addProof(pn);
+ }
+ else
+ {
+ Assert(false) << "ProofPostprocessCallback::addProofForWitnessForm: failed "
+ "to add proof for witness form of "
+ << t;
+ }
+ return eq;
+}
+
+Node ProofPostprocessCallback::addProofForTrans(
+ const std::vector<Node>& tchildren, CDProof* cdp)
+{
+ size_t tsize = tchildren.size();
+ if (tsize > 1)
+ {
+ Node lhs = tchildren[0][0];
+ Node rhs = tchildren[tsize - 1][1];
+ Node eq = lhs.eqNode(rhs);
+ cdp->addStep(eq, PfRule::TRANS, tchildren, {});
+ return eq;
+ }
+ else if (tsize == 1)
+ {
+ return tchildren[0];
+ }
+ return Node::null();
+}
+
+Node ProofPostprocessCallback::addProofForSubsStep(Node var,
+ Node subs,
+ Node assump,
+ CDProof* cdp)
+{
+ // ensure we have a proof of var = subs
+ Node veqs = var.eqNode(subs);
+ if (veqs != assump)
+ {
+ // should be true intro or false intro
+ Assert(subs.isConst());
+ cdp->addStep(
+ veqs,
+ subs.getConst<bool>() ? PfRule::TRUE_INTRO : PfRule::FALSE_INTRO,
+ {assump},
+ {});
+ }
+ return veqs;
+}
+
+bool ProofPostprocessCallback::addToTransChildren(Node eq,
+ std::vector<Node>& tchildren,
+ bool isSymm)
+{
+ Assert(!eq.isNull());
+ Assert(eq.getKind() == kind::EQUAL);
+ if (eq[0] == eq[1])
+ {
+ return false;
+ }
+ Node equ = isSymm ? eq[1].eqNode(eq[0]) : eq;
+ Assert(tchildren.empty()
+ || (tchildren[tchildren.size() - 1].getKind() == kind::EQUAL
+ && tchildren[tchildren.size() - 1][1] == equ[0]));
+ tchildren.push_back(equ);
+ return true;
+}
+
+ProofPostprocessFinalCallback::ProofPostprocessFinalCallback(
+ ProofNodeManager* pnm)
+ : d_ruleCount("finalProof::ruleCount"),
+ d_totalRuleCount("finalProof::totalRuleCount", 0),
+ d_minPedanticLevel("finalProof::minPedanticLevel", 10),
+ d_numFinalProofs("finalProofs::numFinalProofs", 0),
+ d_pnm(pnm),
+ d_pedanticFailure(false)
+{
+ smtStatisticsRegistry()->registerStat(&d_ruleCount);
+ smtStatisticsRegistry()->registerStat(&d_totalRuleCount);
+ smtStatisticsRegistry()->registerStat(&d_minPedanticLevel);
+ smtStatisticsRegistry()->registerStat(&d_numFinalProofs);
+}
+
+ProofPostprocessFinalCallback::~ProofPostprocessFinalCallback()
+{
+ smtStatisticsRegistry()->unregisterStat(&d_ruleCount);
+ smtStatisticsRegistry()->unregisterStat(&d_totalRuleCount);
+ smtStatisticsRegistry()->unregisterStat(&d_minPedanticLevel);
+ smtStatisticsRegistry()->unregisterStat(&d_numFinalProofs);
+}
+
+void ProofPostprocessFinalCallback::initializeUpdate()
+{
+ d_pedanticFailure = false;
+ d_pedanticFailureOut.str("");
+ ++d_numFinalProofs;
+}
+
+bool ProofPostprocessFinalCallback::shouldUpdate(std::shared_ptr<ProofNode> pn,
+ bool& continueUpdate)
+{
+ PfRule r = pn->getRule();
+ // if not doing eager pedantic checking, fail if below threshold
+ if (!options::proofNewEagerChecking())
+ {
+ if (!d_pedanticFailure)
+ {
+ Assert(d_pedanticFailureOut.str().empty());
+ if (d_pnm->getChecker()->isPedanticFailure(r, d_pedanticFailureOut))
+ {
+ d_pedanticFailure = true;
+ }
+ }
+ }
+ uint32_t plevel = d_pnm->getChecker()->getPedanticLevel(r);
+ if (plevel != 0)
+ {
+ d_minPedanticLevel.minAssign(plevel);
+ }
+ // record stats for the rule
+ d_ruleCount << r;
+ ++d_totalRuleCount;
+ return false;
+}
+
+bool ProofPostprocessFinalCallback::wasPedanticFailure(std::ostream& out) const
+{
+ if (d_pedanticFailure)
+ {
+ out << d_pedanticFailureOut.str();
+ return true;
+ }
+ return false;
+}
+
+ProofPostproccess::ProofPostproccess(ProofNodeManager* pnm,
+ SmtEngine* smte,
+ ProofGenerator* pppg)
+ : d_pnm(pnm),
+ d_cb(pnm, smte, pppg),
+ // the update merges subproofs
+ d_updater(d_pnm, d_cb, true),
+ d_finalCb(pnm),
+ d_finalizer(d_pnm, d_finalCb)
+{
+}
+
+ProofPostproccess::~ProofPostproccess() {}
+
+void ProofPostproccess::process(std::shared_ptr<ProofNode> pf)
+{
+ // Initialize the callback, which computes necessary static information about
+ // how to process, including how to process assumptions in pf.
+ d_cb.initializeUpdate();
+ // now, process
+ d_updater.process(pf);
+ // take stats and check pedantic
+ d_finalCb.initializeUpdate();
+ d_finalizer.process(pf);
+
+ std::stringstream serr;
+ bool wasPedanticFailure = d_finalCb.wasPedanticFailure(serr);
+ if (wasPedanticFailure)
+ {
+ AlwaysAssert(!wasPedanticFailure)
+ << "ProofPostproccess::process: pedantic failure:" << std::endl
+ << serr.str();
+ }
+}
+
+void ProofPostproccess::setEliminateRule(PfRule rule)
+{
+ d_cb.setEliminateRule(rule);
+}
+
+} // namespace smt
+} // namespace CVC4
diff --git a/src/smt/proof_post_processor.h b/src/smt/proof_post_processor.h
new file mode 100644
index 000000000..3c0d4fbaa
--- /dev/null
+++ b/src/smt/proof_post_processor.h
@@ -0,0 +1,228 @@
+/********************* */
+/*! \file proof_post_processor.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The module for processing proof nodes
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__SMT__PROOF_POST_PROCESSOR_H
+#define CVC4__SMT__PROOF_POST_PROCESSOR_H
+
+#include <map>
+#include <unordered_set>
+
+#include "expr/proof_node_updater.h"
+#include "smt/witness_form.h"
+
+namespace CVC4 {
+
+class SmtEngine;
+
+namespace smt {
+
+/**
+ * A callback class used by SmtEngine for post-processing proof nodes by
+ * connecting proofs of preprocessing, and expanding macro PfRule applications.
+ */
+class ProofPostprocessCallback : public ProofNodeUpdaterCallback
+{
+ public:
+ ProofPostprocessCallback(ProofNodeManager* pnm,
+ SmtEngine* smte,
+ ProofGenerator* pppg);
+ ~ProofPostprocessCallback() {}
+ /**
+ * Initialize, called once for each new ProofNode to process. This initializes
+ * static information to be used by successive calls to update.
+ */
+ void initializeUpdate();
+ /**
+ * Set eliminate rule, which adds rule to the list of rules we will eliminate
+ * during update. This adds rule to d_elimRules. Supported rules for
+ * elimination include MACRO_*, SUBS and REWRITE. Otherwise, this method
+ * has no effect.
+ */
+ void setEliminateRule(PfRule rule);
+ /** Should proof pn be updated? */
+ bool shouldUpdate(std::shared_ptr<ProofNode> pn,
+ bool& continueUpdate) override;
+ /** Update the proof rule application. */
+ bool update(Node res,
+ PfRule id,
+ const std::vector<Node>& children,
+ const std::vector<Node>& args,
+ CDProof* cdp,
+ bool& continueUpdate) override;
+
+ private:
+ /** Common constants */
+ Node d_true;
+ /** The proof node manager */
+ ProofNodeManager* d_pnm;
+ /** Pointer to the SmtEngine, which should have proofs enabled */
+ SmtEngine* d_smte;
+ /** The preprocessing proof generator */
+ ProofGenerator* d_pppg;
+ /** The witness form proof generator */
+ WitnessFormGenerator d_wfpm;
+ /** The witness form assumptions used in the proof */
+ std::vector<Node> d_wfAssumptions;
+ /** Kinds of proof rules we are eliminating */
+ std::unordered_set<PfRule, PfRuleHashFunction> d_elimRules;
+ //---------------------------------reset at the begining of each update
+ /** Mapping assumptions to their proof from preprocessing */
+ std::map<Node, std::shared_ptr<ProofNode> > d_assumpToProof;
+ //---------------------------------end reset at the begining of each update
+ /**
+ * Expand rules in the given application, add the expanded proof to cdp.
+ * The set of rules we expand is configured by calls to setEliminateRule
+ * above. This method calls update to perform possible post-processing in the
+ * rules it introduces as a result of the expansion.
+ *
+ * @param id The rule of the application
+ * @param children The children of the application
+ * @param args The arguments of the application
+ * @param cdp The proof to add to
+ * @return The conclusion of the rule, or null if this rule is not eliminated.
+ */
+ Node expandMacros(PfRule id,
+ const std::vector<Node>& children,
+ const std::vector<Node>& args,
+ CDProof* cdp);
+ /**
+ * Update the proof rule application, called during expand macros when
+ * we wish to apply the update method. This method has the same behavior
+ * as update apart from ignoring the continueUpdate flag.
+ */
+ bool updateInternal(Node res,
+ PfRule id,
+ const std::vector<Node>& children,
+ const std::vector<Node>& args,
+ CDProof* cdp);
+ /**
+ * Add proof for witness form. This returns the equality t = toWitness(t)
+ * and ensures that the proof of this equality has been added to cdp.
+ * Notice the proof of this fact may have open assumptions of the form:
+ * k = toWitness(k)
+ * where k is a skolem. Furthermore, note that all open assumptions of this
+ * form are available via d_wfpm.getWitnessFormEqs() in the remainder of
+ * the lifetime of this class.
+ */
+ Node addProofForWitnessForm(Node t, CDProof* cdp);
+ /**
+ * Apply transivity if necessary for the arguments. The nodes in
+ * tchildren have been ordered such that they are legal arguments to TRANS.
+ *
+ * Returns the conclusion of the transitivity step, which is null if
+ * tchildren is empty. Also note if tchildren contains a single element,
+ * then no TRANS step is necessary to add to cdp.
+ *
+ * @param tchildren The children of a TRANS step
+ * @param cdp The proof to add the TRANS step to
+ * @return The conclusion of the TRANS step.
+ */
+ Node addProofForTrans(const std::vector<Node>& tchildren, CDProof* cdp);
+ /**
+ * Add proof for substitution step. Some substitutions are derived based
+ * on viewing a formula as a Boolean assignment (see MethodId::SB_LITERAL for
+ * example). This method ensures that the proof of var == subs exists
+ * in cdp, where var, subs were derived from BuiltinProofRuleChecker's
+ * getSubstitution method.
+ *
+ * @param var The variable of the substitution
+ * @param subs The substituted term
+ * @param assump The formula the substitution was derived from
+ * @param cdp The proof to add to
+ * @return var == subs, the conclusion of the substitution step.
+ */
+ Node addProofForSubsStep(Node var, Node subs, Node assump, CDProof* cdp);
+ /** Add eq (or its symmetry) to transivity children, if not reflexive */
+ bool addToTransChildren(Node eq,
+ std::vector<Node>& tchildren,
+ bool isSymm = false);
+};
+
+/** Final callback class, for stats and pedantic checking */
+class ProofPostprocessFinalCallback : public ProofNodeUpdaterCallback
+{
+ public:
+ ProofPostprocessFinalCallback(ProofNodeManager* pnm);
+ ~ProofPostprocessFinalCallback();
+ /**
+ * Initialize, called once for each new ProofNode to process. This initializes
+ * static information to be used by successive calls to update.
+ */
+ void initializeUpdate();
+ /** Should proof pn be updated? Returns false, adds to stats. */
+ bool shouldUpdate(std::shared_ptr<ProofNode> pn,
+ bool& continueUpdate) override;
+ /** was pedantic failure */
+ bool wasPedanticFailure(std::ostream& out) const;
+
+ private:
+ /** Counts number of postprocessed proof nodes for each kind of proof rule */
+ HistogramStat<PfRule> d_ruleCount;
+ /** Total number of postprocessed rule applications */
+ IntStat d_totalRuleCount;
+ /** The minimum pedantic level of any rule encountered */
+ IntStat d_minPedanticLevel;
+ /** The total number of final proofs */
+ IntStat d_numFinalProofs;
+ /** Proof node manager (used for pedantic checking) */
+ ProofNodeManager* d_pnm;
+ /** Was there a pedantic failure? */
+ bool d_pedanticFailure;
+ /** The pedantic failure string for debugging */
+ std::stringstream d_pedanticFailureOut;
+};
+
+/**
+ * The proof postprocessor module. This postprocesses the final proof
+ * produced by an SmtEngine. Its main two tasks are to:
+ * (1) Connect proofs of preprocessing,
+ * (2) Expand macro PfRule applications.
+ */
+class ProofPostproccess
+{
+ public:
+ ProofPostproccess(ProofNodeManager* pnm,
+ SmtEngine* smte,
+ ProofGenerator* pppg);
+ ~ProofPostproccess();
+ /** post-process */
+ void process(std::shared_ptr<ProofNode> pf);
+ /** set eliminate rule */
+ void setEliminateRule(PfRule rule);
+
+ private:
+ /** The proof node manager */
+ ProofNodeManager* d_pnm;
+ /** The post process callback */
+ ProofPostprocessCallback d_cb;
+ /**
+ * The updater, which is responsible for expanding macros in the final proof
+ * and connecting preprocessed assumptions to input assumptions.
+ */
+ ProofNodeUpdater d_updater;
+ /** The post process callback for finalization */
+ ProofPostprocessFinalCallback d_finalCb;
+ /**
+ * The finalizer, which is responsible for taking stats and checking for
+ * (lazy) pedantic failures.
+ */
+ ProofNodeUpdater d_finalizer;
+};
+
+} // namespace smt
+} // namespace CVC4
+
+#endif
diff --git a/src/smt/quant_elim_solver.cpp b/src/smt/quant_elim_solver.cpp
new file mode 100644
index 000000000..e5ecafd4a
--- /dev/null
+++ b/src/smt/quant_elim_solver.cpp
@@ -0,0 +1,131 @@
+/********************* */
+/*! \file quant_elim_solver.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Mathias Preiner
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The solver for quantifier elimination queries
+ **/
+
+#include "smt/quant_elim_solver.h"
+
+#include "expr/subs.h"
+#include "smt/smt_solver.h"
+#include "theory/quantifiers/cegqi/nested_qe.h"
+#include "theory/quantifiers/extended_rewrite.h"
+#include "theory/rewriter.h"
+#include "theory/theory_engine.h"
+
+using namespace CVC4::theory;
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace smt {
+
+QuantElimSolver::QuantElimSolver(SmtSolver& sms) : d_smtSolver(sms) {}
+
+QuantElimSolver::~QuantElimSolver() {}
+
+Node QuantElimSolver::getQuantifierElimination(Assertions& as,
+ Node q,
+ bool doFull)
+{
+ Trace("smt-qe") << "QuantElimSolver: get qe : " << q << std::endl;
+ if (q.getKind() != EXISTS && q.getKind() != FORALL)
+ {
+ throw ModalException(
+ "Expecting a quantified formula as argument to get-qe.");
+ }
+ // do nested quantifier elimination if necessary
+ q = quantifiers::NestedQe::doNestedQe(q, true);
+ Trace("smt-qe") << "QuantElimSolver: after nested quantifier elimination : "
+ << q << std::endl;
+ NodeManager* nm = NodeManager::currentNM();
+ // tag the quantified formula with the quant-elim attribute
+ TypeNode t = nm->booleanType();
+ Node n_attr = nm->mkSkolem("qe", t, "Auxiliary variable for qe attr.");
+ std::vector<Node> node_values;
+ TheoryEngine* te = d_smtSolver.getTheoryEngine();
+ Assert(te != nullptr);
+ te->setUserAttribute(
+ doFull ? "quant-elim" : "quant-elim-partial", n_attr, node_values, "");
+ n_attr = nm->mkNode(INST_ATTRIBUTE, n_attr);
+ n_attr = nm->mkNode(INST_PATTERN_LIST, n_attr);
+ std::vector<Node> children;
+ children.push_back(q[0]);
+ children.push_back(q.getKind() == EXISTS ? q[1] : q[1].negate());
+ children.push_back(n_attr);
+ Node ne = nm->mkNode(EXISTS, children);
+ Trace("smt-qe-debug") << "Query for quantifier elimination : " << ne
+ << std::endl;
+ Assert(ne.getNumChildren() == 3);
+ // We consider this to be an entailment check, which also avoids incorrect
+ // status reporting (see SmtEngineState::d_expectedStatus).
+ Result r =
+ d_smtSolver.checkSatisfiability(as, std::vector<Node>{ne}, false, true);
+ Trace("smt-qe") << "Query returned " << r << std::endl;
+ if (r.asSatisfiabilityResult().isSat() != Result::UNSAT)
+ {
+ if (r.asSatisfiabilityResult().isSat() != Result::SAT && doFull)
+ {
+ Notice()
+ << "While performing quantifier elimination, unexpected result : "
+ << r << " for query.";
+ // failed, return original
+ return q;
+ }
+ // must use original quantified formula to compute QE, which ensures that
+ // e.g. term formula removal is not run on the body. Notice that we assume
+ // that the (single) quantified formula is preprocessed, rewritten
+ // version of the input quantified formula q.
+ std::vector<Node> inst_qs;
+ te->getInstantiatedQuantifiedFormulas(inst_qs);
+ Assert(inst_qs.size() <= 1);
+ Node ret;
+ if (inst_qs.size() == 1)
+ {
+ Node topq = inst_qs[0];
+ Assert(topq.getKind() == FORALL);
+ Trace("smt-qe") << "Get qe based on preprocessed quantified formula "
+ << topq << std::endl;
+ std::vector<std::vector<Node>> insts;
+ te->getInstantiationTermVectors(topq, insts);
+ std::vector<Node> vars(ne[0].begin(), ne[0].end());
+ std::vector<Node> conjs;
+ // apply the instantiation on the original body
+ for (const std::vector<Node>& inst : insts)
+ {
+ // note we do not convert to witness form here, since we could be
+ // an internal subsolver
+ Subs s;
+ s.add(vars, inst);
+ Node c = s.apply(ne[1].negate());
+ conjs.push_back(c);
+ }
+ ret = nm->mkAnd(conjs);
+ Trace("smt-qe") << "QuantElimSolver returned : " << ret << std::endl;
+ if (q.getKind() == EXISTS)
+ {
+ ret = Rewriter::rewrite(ret.negate());
+ }
+ }
+ else
+ {
+ ret = nm->mkConst(q.getKind() != EXISTS);
+ }
+ // do extended rewrite to minimize the size of the formula aggressively
+ theory::quantifiers::ExtendedRewriter extr(true);
+ ret = extr.extendedRewrite(ret);
+ return ret;
+ }
+ // otherwise, just true/false
+ return nm->mkConst(q.getKind() == EXISTS);
+}
+
+} // namespace smt
+} // namespace CVC4
diff --git a/src/smt/quant_elim_solver.h b/src/smt/quant_elim_solver.h
new file mode 100644
index 000000000..96ed1f73d
--- /dev/null
+++ b/src/smt/quant_elim_solver.h
@@ -0,0 +1,93 @@
+/********************* */
+/*! \file quant_elim_solver.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The solver for quantifier elimination queries
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__SMT__QUANT_ELIM_SOLVER_H
+#define CVC4__SMT__QUANT_ELIM_SOLVER_H
+
+#include "expr/node.h"
+#include "smt/assertions.h"
+
+namespace CVC4 {
+namespace smt {
+
+class SmtSolver;
+
+/**
+ * A solver for quantifier elimination queries.
+ *
+ * This class is responsible for responding to get-qe and get-qe-partial
+ * commands. It uses an underlying SmtSolver, which it queries for
+ * quantifier instantiations used for unsat which are in turn used for
+ * constructing the solution for the quantifier elimination query.
+ */
+class QuantElimSolver
+{
+ public:
+ QuantElimSolver(SmtSolver& sms);
+ ~QuantElimSolver();
+
+ /**
+ * This function takes as input a quantified formula q
+ * of the form:
+ * Q x1...xn. P( x1...xn, y1...yn )
+ * where P( x1...xn, y1...yn ) is a quantifier-free
+ * formula in a logic that supports quantifier elimination.
+ * Currently, the only logics supported by quantifier
+ * elimination is LRA and LIA.
+ *
+ * This function returns a formula ret such that, given
+ * the current set of formulas A asserted to this SmtEngine :
+ *
+ * If doFull = true, then
+ * - ( A ^ q ) and ( A ^ ret ) are equivalent
+ * - ret is quantifier-free formula containing
+ * only free variables in y1...yn.
+ *
+ * If doFull = false, then
+ * - (A ^ q) => (A ^ ret) if Q is forall or
+ * (A ^ ret) => (A ^ q) if Q is exists,
+ * - ret is quantifier-free formula containing
+ * only free variables in y1...yn,
+ * - If Q is exists, let A^Q_n be the formula
+ * A ^ ~ret^Q_1 ^ ... ^ ~ret^Q_n
+ * where for each i=1,...n, formula ret^Q_i
+ * is the result of calling doQuantifierElimination
+ * for q with the set of assertions A^Q_{i-1}.
+ * Similarly, if Q is forall, then let A^Q_n be
+ * A ^ ret^Q_1 ^ ... ^ ret^Q_n
+ * where ret^Q_i is the same as above.
+ * In either case, we have that ret^Q_j will
+ * eventually be true or false, for some finite j.
+ *
+ * The former feature is quantifier elimination, and
+ * is run on invocations of the smt2 extended command get-qe.
+ * The latter feature is referred to as partial quantifier
+ * elimination, and is run on invocations of the smt2
+ * extended command get-qe-disjunct, which can be used
+ * for incrementally computing the result of a
+ * quantifier elimination.
+ */
+ Node getQuantifierElimination(Assertions& as, Node q, bool doFull);
+
+ private:
+ /** The SMT solver, which is used during doQuantifierElimination. */
+ SmtSolver& d_smtSolver;
+};
+
+} // namespace smt
+} // namespace CVC4
+
+#endif /* CVC4__SMT__QUANT_ELIM_SOLVER_H */
diff --git a/src/smt/set_defaults.cpp b/src/smt/set_defaults.cpp
index 8f6ab6c18..aaff29479 100644
--- a/src/smt/set_defaults.cpp
+++ b/src/smt/set_defaults.cpp
@@ -2,10 +2,10 @@
/*! \file set_defaults.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Andres Noetzli, Aina Niemetz
+ ** Andrew Reynolds, Andres Noetzli, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -27,7 +27,6 @@
#include "options/open_ostream.h"
#include "options/option_exception.h"
#include "options/printer_options.h"
-#include "options/proof_options.h"
#include "options/prop_options.h"
#include "options/quantifiers_options.h"
#include "options/sep_options.h"
@@ -72,21 +71,11 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
Notice() << "SmtEngine: setting unsatCores" << std::endl;
options::unsatCores.set(true);
}
- if (options::checkProofs() || options::dumpProofs())
- {
- Notice() << "SmtEngine: setting proof" << std::endl;
- options::proof.set(true);
- }
if (options::bitvectorAigSimplifications.wasSetByUser())
{
Notice() << "SmtEngine: setting bitvectorAig" << std::endl;
options::bitvectorAig.set(true);
}
- if (options::bitvectorEqualitySlicer.wasSetByUser())
- {
- Notice() << "SmtEngine: setting bitvectorEqualitySolver" << std::endl;
- options::bitvectorEqualitySolver.set(true);
- }
if (options::bitvectorAlgebraicBudget.wasSetByUser())
{
Notice() << "SmtEngine: setting bitvectorAlgebraicSolver" << std::endl;
@@ -100,8 +89,7 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
// set this option if the input format is SMT LIB 2.6. We also set this
// option if we are sygus, since we assume SMT LIB 2.6 semantics for sygus.
options::bitvectorDivByZeroConst.set(
- language::isInputLang_smt2_6(options::inputLanguage())
- || language::isInputLangSygus(options::inputLanguage()));
+ !language::isInputLang_smt2_5(options::inputLanguage(), true));
}
bool is_sygus = language::isInputLangSygus(options::inputLanguage());
@@ -136,6 +124,14 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
}
}
+ /* BVSolver::SIMPLE does not natively support int2bv and nat2bv, they need to
+ * to be eliminated eagerly. */
+ if (options::bvSolver() == options::BVSolver::SIMPLE)
+ {
+ options::bvLazyReduceExtf.set(false);
+ options::bvLazyRewriteExtf.set(false);
+ }
+
if (options::solveIntAsBV() > 0)
{
// not compatible with incremental
@@ -156,14 +152,7 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
if (options::solveBVAsInt() != options::SolveBVAsIntMode::OFF)
{
- // not compatible with incremental
- if (options::incrementalSolving())
- {
- throw OptionException(
- "solving bitvectors as integers is currently not supported "
- "when solving incrementally.");
- }
- else if (options::boolToBitvector() != options::BoolToBVMode::OFF)
+ if (options::boolToBitvector() != options::BoolToBVMode::OFF)
{
throw OptionException(
"solving bitvectors as integers is incompatible with --bool-to-bv.");
@@ -250,13 +239,6 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
options::fmfBound.set(true);
Trace("smt") << "turning on fmf-bound-int, for strings-exp" << std::endl;
}
- // Turn off E-matching, since some bounded quantifiers introduced by strings
- // (e.g. for replaceall) admit matching loops.
- if (!options::eMatching.wasSetByUser())
- {
- options::eMatching.set(false);
- Trace("smt") << "turning off E-matching, for strings-exp" << std::endl;
- }
// Do not eliminate extended arithmetic symbols from quantified formulas,
// since some strategies, e.g. --re-elim-agg, introduce them.
if (!options::elimExtArithQuant.wasSetByUser())
@@ -265,13 +247,9 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
Trace("smt") << "turning off elim-ext-arith-quant, for strings-exp"
<< std::endl;
}
+ // Note we allow E-matching by default to support combinations of sequences
+ // and quantifiers.
}
- // !!!!!!!!!!!!!!!! temporary, to support CI check for old proof system
- if (options::proof())
- {
- options::proofNew.set(false);
- }
-
if (options::arraysExp())
{
if (!logic.isQuantified())
@@ -328,11 +306,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
options::produceAssertions.set(true);
}
- // Disable options incompatible with incremental solving, unsat cores, and
- // proofs or output an error if enabled explicitly. It is also currently
- // incompatible with arithmetic, force the option off.
- if (options::incrementalSolving() || options::unsatCores()
- || options::proof())
+ // Disable options incompatible with incremental solving, unsat cores or
+ // output an error if enabled explicitly. It is also currently incompatible
+ // with arithmetic, force the option off.
+ if (options::incrementalSolving() || options::unsatCores())
{
if (options::unconstrainedSimp())
{
@@ -340,10 +317,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
{
throw OptionException(
"unconstrained simplification not supported with unsat "
- "cores/proofs/incremental solving");
+ "cores/incremental solving");
}
Notice() << "SmtEngine: turning off unconstrained simplification to "
- "support unsat cores/proofs/incremental solving"
+ "support unsat cores/incremental solving"
<< std::endl;
options::unconstrainedSimp.set(false);
}
@@ -365,17 +342,17 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
}
}
- if (options::incrementalSolving() || options::proof())
+ if (options::incrementalSolving())
{
if (options::sygusInference())
{
if (options::sygusInference.wasSetByUser())
{
throw OptionException(
- "sygus inference not supported with proofs/incremental solving");
+ "sygus inference not supported with incremental solving");
}
Notice() << "SmtEngine: turning off sygus inference to support "
- "proofs/incremental solving"
+ "incremental solving"
<< std::endl;
options::sygusInference.set(false);
}
@@ -392,19 +369,18 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
options::bitvectorToBool.set(true);
}
- // Disable options incompatible with unsat cores and proofs or output an
- // error if enabled explicitly
- if (options::unsatCores() || options::proof())
+ // Disable options incompatible with unsat cores or output an error if enabled
+ // explicitly
+ if (options::unsatCores())
{
if (options::simplificationMode() != options::SimplificationMode::NONE)
{
if (options::simplificationMode.wasSetByUser())
{
- throw OptionException(
- "simplification not supported with unsat cores/proofs");
+ throw OptionException("simplification not supported with unsat cores");
}
Notice() << "SmtEngine: turning off simplification to support unsat "
- "cores/proofs"
+ "cores"
<< std::endl;
options::simplificationMode.set(options::SimplificationMode::NONE);
}
@@ -414,10 +390,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
if (options::pbRewrites.wasSetByUser())
{
throw OptionException(
- "pseudoboolean rewrites not supported with unsat cores/proofs");
+ "pseudoboolean rewrites not supported with unsat cores");
}
Notice() << "SmtEngine: turning off pseudoboolean rewrites to support "
- "unsat cores/proofs"
+ "unsat cores"
<< std::endl;
options::pbRewrites.set(false);
}
@@ -426,11 +402,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
{
if (options::sortInference.wasSetByUser())
{
- throw OptionException(
- "sort inference not supported with unsat cores/proofs");
+ throw OptionException("sort inference not supported with unsat cores");
}
Notice() << "SmtEngine: turning off sort inference to support unsat "
- "cores/proofs"
+ "cores"
<< std::endl;
options::sortInference.set(false);
}
@@ -440,10 +415,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
if (options::preSkolemQuant.wasSetByUser())
{
throw OptionException(
- "pre-skolemization not supported with unsat cores/proofs");
+ "pre-skolemization not supported with unsat cores");
}
Notice() << "SmtEngine: turning off pre-skolemization to support unsat "
- "cores/proofs"
+ "cores"
<< std::endl;
options::preSkolemQuant.set(false);
}
@@ -453,11 +428,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
{
if (options::bitvectorToBool.wasSetByUser())
{
- throw OptionException(
- "bv-to-bool not supported with unsat cores/proofs");
+ throw OptionException("bv-to-bool not supported with unsat cores");
}
Notice() << "SmtEngine: turning off bitvector-to-bool to support unsat "
- "cores/proofs"
+ "cores"
<< std::endl;
options::bitvectorToBool.set(false);
}
@@ -467,10 +441,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
if (options::boolToBitvector.wasSetByUser())
{
throw OptionException(
- "bool-to-bv != off not supported with unsat cores/proofs");
+ "bool-to-bv != off not supported with unsat cores");
}
Notice() << "SmtEngine: turning off bool-to-bv to support unsat "
- "cores/proofs"
+ "cores"
<< std::endl;
options::boolToBitvector.set(options::BoolToBVMode::OFF);
}
@@ -479,11 +453,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
{
if (options::bvIntroducePow2.wasSetByUser())
{
- throw OptionException(
- "bv-intro-pow2 not supported with unsat cores/proofs");
+ throw OptionException("bv-intro-pow2 not supported with unsat cores");
}
Notice() << "SmtEngine: turning off bv-intro-pow2 to support "
- "unsat-cores/proofs"
+ "unsat-cores"
<< std::endl;
options::bvIntroducePow2.set(false);
}
@@ -492,11 +465,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
{
if (options::repeatSimp.wasSetByUser())
{
- throw OptionException(
- "repeat-simp not supported with unsat cores/proofs");
+ throw OptionException("repeat-simp not supported with unsat cores");
}
Notice() << "SmtEngine: turning off repeat-simp to support unsat "
- "cores/proofs"
+ "cores"
<< std::endl;
options::repeatSimp.set(false);
}
@@ -505,19 +477,17 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
{
if (options::globalNegate.wasSetByUser())
{
- throw OptionException(
- "global-negate not supported with unsat cores/proofs");
+ throw OptionException("global-negate not supported with unsat cores");
}
Notice() << "SmtEngine: turning off global-negate to support unsat "
- "cores/proofs"
+ "cores"
<< std::endl;
options::globalNegate.set(false);
}
if (options::bitvectorAig())
{
- throw OptionException(
- "bitblast-aig not supported with unsat cores/proofs");
+ throw OptionException("bitblast-aig not supported with unsat cores");
}
}
else
@@ -576,8 +546,7 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
LogicInfo log(logic.getUnlockedCopy());
// Strings requires arith for length constraints, and also UF
needsUf = true;
- if (!logic.isTheoryEnabled(THEORY_ARITH) || logic.isDifferenceLogic()
- || !logic.areIntegersUsed())
+ if (!logic.isTheoryEnabled(THEORY_ARITH) || logic.isDifferenceLogic())
{
Notice()
<< "Enabling linear integer arithmetic because strings are enabled"
@@ -586,6 +555,12 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
log.enableIntegers();
log.arithOnlyLinear();
}
+ else if (!logic.areIntegersUsed())
+ {
+ Notice() << "Enabling integer arithmetic because strings are enabled"
+ << std::endl;
+ log.enableIntegers();
+ }
logic = log;
logic.lock();
}
@@ -594,6 +569,7 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
|| logic.isTheoryEnabled(THEORY_ARRAYS)
|| logic.isTheoryEnabled(THEORY_DATATYPES)
|| logic.isTheoryEnabled(THEORY_SETS)
+ || logic.isTheoryEnabled(THEORY_BAGS)
// Non-linear arithmetic requires UF to deal with division/mod because
// their expansion introduces UFs for the division/mod-by-zero case.
// If we are eliminating non-linear arithmetic via solve-int-as-bv,
@@ -627,7 +603,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
{
if (logic.isSharingEnabled() && !logic.isTheoryEnabled(THEORY_BV)
&& !logic.isTheoryEnabled(THEORY_STRINGS)
- && !logic.isTheoryEnabled(THEORY_SETS))
+ && !logic.isTheoryEnabled(THEORY_SETS)
+ && !logic.isTheoryEnabled(THEORY_BAGS)
+ && !(logic.isTheoryEnabled(THEORY_ARITH) && !logic.isLinear()
+ && !logic.isQuantified()))
{
Trace("smt") << "setting theoryof-mode to term-based" << std::endl;
options::theoryOfMode.set(options::TheoryOfMode::THEORY_OF_TERM_BASED);
@@ -638,7 +617,7 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
if (!options::ufSymmetryBreaker.wasSetByUser())
{
bool qf_uf_noinc = logic.isPure(THEORY_UF) && !logic.isQuantified()
- && !options::incrementalSolving() && !options::proof()
+ && !options::incrementalSolving()
&& !options::unsatCores();
Trace("smt") << "setting uf symmetry breaker to " << qf_uf_noinc
<< std::endl;
@@ -646,7 +625,8 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
}
// If in arrays, set the UF handler to arrays
- if (logic.isTheoryEnabled(THEORY_ARRAYS)
+ if (logic.isTheoryEnabled(THEORY_ARRAYS) && !options::ufHo()
+ && !options::finiteModelFind()
&& (!logic.isQuantified()
|| (logic.isQuantified() && !logic.isTheoryEnabled(THEORY_UF))))
{
@@ -858,10 +838,7 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
options::cegqi.set(false);
}
// Do we need to track instantiations?
- // Needed for sygus due to single invocation techniques.
- if (options::cegqiNestedQE()
- || (options::proof() && !options::trackInstLemmas.wasSetByUser())
- || is_sygus)
+ if (options::unsatCores() && !options::trackInstLemmas.wasSetByUser())
{
options::trackInstLemmas.set(true);
}
@@ -943,6 +920,10 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
{
options::preSkolemQuant.set(true);
}
+ // must have separation logic
+ logic = logic.getUnlockedCopy();
+ logic.enableTheory(THEORY_SEP);
+ logic.lock();
}
// now, have determined whether finite model find is on/off
@@ -987,6 +968,12 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
{
options::cegqiMidpoint.set(true);
}
+ // must disable cegqi-bv since it may introduce witness terms, which
+ // cannot appear in synthesis solutions
+ if (!options::cegqiBv.wasSetByUser())
+ {
+ options::cegqiBv.set(false);
+ }
if (options::sygusRepairConst())
{
if (!options::cegqi.wasSetByUser())
@@ -1130,6 +1117,12 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
{
options::cegqiPreRegInst.set(true);
}
+ // use tangent planes by default, since we want to put effort into
+ // the verification step for sygus queries with non-linear arithmetic
+ if (!options::nlExtTangentPlanes.wasSetByUser())
+ {
+ options::nlExtTangentPlanes.set(true);
+ }
// not compatible with proofs
if (options::proofNew())
{
@@ -1192,13 +1185,7 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
// only supported in pure arithmetic or pure BV
options::cegqiNestedQE.set(false);
}
- // prenexing
- if (options::cegqiNestedQE())
- {
- // only complete with prenex = normal
- options::prenexQuant.set(options::PrenexQuantMode::NORMAL);
- }
- else if (options::globalNegate())
+ if (options::globalNegate())
{
if (!options::prenexQuant.wasSetByUser())
{
@@ -1303,7 +1290,9 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
// introduces new literals into the search. This includes quantifiers
// (quantifier instantiation), and the lemma schemas used in non-linear
// and sets. We also can't use it if models are enabled.
- if (logic.isTheoryEnabled(THEORY_SETS) || logic.isQuantified()
+ if (logic.isTheoryEnabled(THEORY_SETS)
+ || logic.isTheoryEnabled(THEORY_BAGS)
+ || logic.isQuantified()
|| options::produceModels() || options::produceAssignments()
|| options::checkModels()
|| (logic.isTheoryEnabled(THEORY_ARITH) && !logic.isLinear()))
@@ -1312,67 +1301,29 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
}
}
- // For now, these array theory optimizations do not support model-building
- if (options::produceModels() || options::produceAssignments()
- || options::checkModels())
- {
- options::arraysOptimizeLinear.set(false);
- options::arraysLazyRIntro1.set(false);
- }
-
- if (options::proof())
+ if (logic.isTheoryEnabled(THEORY_ARITH) && !logic.isLinear()
+ && options::nlRlvMode() != options::NlRlvMode::NONE)
{
- if (options::incrementalSolving())
- {
- if (options::incrementalSolving.wasSetByUser())
- {
- throw OptionException("--incremental is not supported with proofs");
- }
- Warning()
- << "SmtEngine: turning off incremental solving mode (not yet "
- "supported with --proof, try --tear-down-incremental instead)"
- << std::endl;
- options::incrementalSolving.set(false);
- }
- if (logic > LogicInfo("QF_AUFBVLRA"))
- {
- throw OptionException(
- "Proofs are only supported for sub-logics of QF_AUFBVLIA.");
- }
- if (options::bitvectorAlgebraicSolver())
- {
- if (options::bitvectorAlgebraicSolver.wasSetByUser())
- {
- throw OptionException(
- "--bv-algebraic-solver is not supported with proofs");
- }
- Notice() << "SmtEngine: turning off bv algebraic solver to support proofs"
- << std::endl;
- options::bitvectorAlgebraicSolver.set(false);
- }
- if (options::bitvectorEqualitySolver())
- {
- if (options::bitvectorEqualitySolver.wasSetByUser())
- {
- throw OptionException("--bv-eq-solver is not supported with proofs");
- }
- Notice() << "SmtEngine: turning off bv eq solver to support proofs"
- << std::endl;
- options::bitvectorEqualitySolver.set(false);
- }
- if (options::bitvectorInequalitySolver())
+ if (!options::relevanceFilter())
{
- if (options::bitvectorInequalitySolver.wasSetByUser())
+ if (options::relevanceFilter.wasSetByUser())
{
- throw OptionException(
- "--bv-inequality-solver is not supported with proofs");
+ Warning() << "SmtEngine: turning on relevance filtering to support "
+ "--nl-ext-rlv="
+ << options::nlRlvMode() << std::endl;
}
- Notice() << "SmtEngine: turning off bv ineq solver to support proofs"
- << std::endl;
- options::bitvectorInequalitySolver.set(false);
+ // must use relevance filtering techniques
+ options::relevanceFilter.set(true);
}
}
+ // For now, these array theory optimizations do not support model-building
+ if (options::produceModels() || options::produceAssignments()
+ || options::checkModels())
+ {
+ options::arraysOptimizeLinear.set(false);
+ }
+
if (!options::bitvectorEqualitySolver())
{
if (options::bvLazyRewriteExtf())
@@ -1477,6 +1428,42 @@ void setDefaults(LogicInfo& logic, bool isInternalSubsolver)
{
throw OptionException("--proof-new is not yet supported.");
}
+
+ if (logic == LogicInfo("QF_UFNRA"))
+ {
+#ifdef CVC4_USE_POLY
+ if (!options::nlCad() && !options::nlCad.wasSetByUser())
+ {
+ options::nlCad.set(true);
+ if (!options::nlExt.wasSetByUser())
+ {
+ options::nlExt.set(false);
+ }
+ if (!options::nlRlvMode.wasSetByUser())
+ {
+ options::nlRlvMode.set(options::NlRlvMode::INTERLEAVE);
+ }
+ }
+#endif
+ }
+#ifndef CVC4_USE_POLY
+ if (options::nlCad())
+ {
+ if (options::nlCad.wasSetByUser())
+ {
+ std::stringstream ss;
+ ss << "Cannot use " << options::nlCad.getName() << " without configuring with --poly.";
+ throw OptionException(ss.str());
+ }
+ else
+ {
+ Notice() << "Cannot use --" << options::nlCad.getName()
+ << " without configuring with --poly." << std::endl;
+ options::nlCad.set(false);
+ options::nlExt.set(true);
+ }
+ }
+#endif
}
} // namespace smt
diff --git a/src/smt/set_defaults.h b/src/smt/set_defaults.h
index 606921b7c..903eff5e9 100644
--- a/src/smt/set_defaults.h
+++ b/src/smt/set_defaults.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -28,7 +28,7 @@ namespace smt {
* updated by this method based on the current options and the logic itself.
* @param isInternalSubsolver Whether we are setting the options for an
* internal subsolver (see SmtEngine::isInternalSubsolver).
- *
+ *
* NOTE: we currently modify the current options in scope. This method
* can be further refactored to modify an options object provided as an
* explicit argument.
diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp
index ff5cff5b6..2a0cde015 100644
--- a/src/smt/smt_engine.cpp
+++ b/src/smt/smt_engine.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,113 +16,55 @@
#include "smt/smt_engine.h"
-#include <algorithm>
-#include <cctype>
-#include <iterator>
-#include <memory>
-#include <sstream>
-#include <stack>
-#include <string>
-#include <tuple>
-#include <unordered_map>
-#include <unordered_set>
-#include <utility>
-#include <vector>
-
#include "api/cvc4cpp.h"
#include "base/check.h"
-#include "base/configuration.h"
-#include "base/configuration_private.h"
#include "base/exception.h"
-#include "base/listener.h"
#include "base/modal_exception.h"
#include "base/output.h"
-#include "context/cdhashmap.h"
-#include "context/cdhashset.h"
-#include "context/cdlist.h"
-#include "context/context.h"
#include "decision/decision_engine.h"
-#include "expr/attribute.h"
-#include "expr/expr.h"
-#include "expr/kind.h"
-#include "expr/metakind.h"
#include "expr/node.h"
-#include "expr/node_algorithm.h"
-#include "expr/node_builder.h"
-#include "expr/node_self_iterator.h"
-#include "expr/node_visitor.h"
-#include "options/arith_options.h"
-#include "options/arrays_options.h"
#include "options/base_options.h"
-#include "options/booleans_options.h"
-#include "options/bv_options.h"
-#include "options/datatypes_options.h"
-#include "options/decision_options.h"
#include "options/language.h"
#include "options/main_options.h"
-#include "options/open_ostream.h"
-#include "options/option_exception.h"
#include "options/printer_options.h"
-#include "options/proof_options.h"
-#include "options/prop_options.h"
-#include "options/quantifiers_options.h"
-#include "options/sep_options.h"
-#include "options/set_language.h"
#include "options/smt_options.h"
-#include "options/strings_options.h"
#include "options/theory_options.h"
-#include "options/uf_options.h"
-#include "preprocessing/preprocessing_pass.h"
-#include "preprocessing/preprocessing_pass_context.h"
-#include "preprocessing/preprocessing_pass_registry.h"
#include "printer/printer.h"
-#include "proof/proof.h"
#include "proof/proof_manager.h"
-#include "proof/theory_proof.h"
#include "proof/unsat_core.h"
-#include "prop/prop_engine.h"
#include "smt/abduction_solver.h"
-#include "smt/command.h"
-#include "smt/command_list.h"
+#include "smt/abstract_values.h"
+#include "smt/assertions.h"
+#include "smt/check_models.h"
#include "smt/defined_function.h"
+#include "smt/dump_manager.h"
+#include "smt/interpolation_solver.h"
+#include "smt/listeners.h"
#include "smt/logic_request.h"
-#include "smt/managed_ostreams.h"
#include "smt/model_blocker.h"
#include "smt/model_core_builder.h"
-#include "smt/process_assertions.h"
-#include "smt/set_defaults.h"
+#include "smt/node_command.h"
+#include "smt/options_manager.h"
+#include "smt/preprocessor.h"
+#include "smt/proof_manager.h"
+#include "smt/quant_elim_solver.h"
#include "smt/smt_engine_scope.h"
+#include "smt/smt_engine_state.h"
#include "smt/smt_engine_stats.h"
-#include "smt/term_formula_removal.h"
-#include "smt/update_ostream.h"
-#include "smt_util/boolean_simplification.h"
-#include "smt_util/nary_builder.h"
-#include "theory/booleans/circuit_propagator.h"
-#include "theory/bv/theory_bv_rewriter.h"
-#include "theory/logic_info.h"
-#include "theory/quantifiers/fun_def_process.h"
-#include "theory/quantifiers/single_inv_partition.h"
-#include "theory/quantifiers/sygus/synth_engine.h"
-#include "theory/quantifiers/term_util.h"
-#include "theory/quantifiers_engine.h"
+#include "smt/smt_solver.h"
+#include "smt/sygus_solver.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
#include "theory/rewriter.h"
-#include "theory/sort_inference.h"
-#include "theory/strings/theory_strings.h"
-#include "theory/substitutions.h"
+#include "theory/smt_engine_subsolver.h"
#include "theory/theory_engine.h"
-#include "theory/theory_model.h"
-#include "theory/theory_traits.h"
-#include "util/hash.h"
-#include "util/proof.h"
#include "util/random.h"
#include "util/resource_manager.h"
-#if (IS_LFSC_BUILD && IS_PROOFS_BUILD)
-#include "lfscc.h"
-#endif
+// required for hacks related to old proofs for unsat cores
+#include "base/configuration.h"
+#include "base/configuration_private.h"
using namespace std;
-using namespace CVC4;
using namespace CVC4::smt;
using namespace CVC4::preprocessing;
using namespace CVC4::prop;
@@ -131,539 +73,35 @@ using namespace CVC4::theory;
namespace CVC4 {
-namespace proof {
-extern const char* const plf_signatures;
-} // namespace proof
-
-namespace smt {
-
-struct DeleteCommandFunction : public std::unary_function<const Command*, void>
-{
- void operator()(const Command* command) { delete command; }
-};
-
-void DeleteAndClearCommandVector(std::vector<Command*>& commands) {
- std::for_each(commands.begin(), commands.end(), DeleteCommandFunction());
- commands.clear();
-}
-
-class SoftResourceOutListener : public Listener {
- public:
- SoftResourceOutListener(SmtEngine& smt) : d_smt(&smt) {}
- void notify() override
- {
- SmtScope scope(d_smt);
- Assert(smt::smtEngineInScope());
- d_smt->interrupt();
- }
- private:
- SmtEngine* d_smt;
-}; /* class SoftResourceOutListener */
-
-
-class HardResourceOutListener : public Listener {
- public:
- HardResourceOutListener(SmtEngine& smt) : d_smt(&smt) {}
- void notify() override
- {
- SmtScope scope(d_smt);
- theory::Rewriter::clearCaches();
- }
- private:
- SmtEngine* d_smt;
-}; /* class HardResourceOutListener */
-
-class BeforeSearchListener : public Listener {
- public:
- BeforeSearchListener(SmtEngine& smt) : d_smt(&smt) {}
- void notify() override { d_smt->beforeSearch(); }
-
- private:
- SmtEngine* d_smt;
-}; /* class BeforeSearchListener */
-
-class SetDefaultExprDepthListener : public Listener {
- public:
- void notify() override
- {
- int depth = options::defaultExprDepth();
- Debug.getStream() << expr::ExprSetDepth(depth);
- Trace.getStream() << expr::ExprSetDepth(depth);
- Notice.getStream() << expr::ExprSetDepth(depth);
- Chat.getStream() << expr::ExprSetDepth(depth);
- Message.getStream() << expr::ExprSetDepth(depth);
- Warning.getStream() << expr::ExprSetDepth(depth);
- // intentionally exclude Dump stream from this list
- }
-};
-
-class SetDefaultExprDagListener : public Listener {
- public:
- void notify() override
- {
- int dag = options::defaultDagThresh();
- Debug.getStream() << expr::ExprDag(dag);
- Trace.getStream() << expr::ExprDag(dag);
- Notice.getStream() << expr::ExprDag(dag);
- Chat.getStream() << expr::ExprDag(dag);
- Message.getStream() << expr::ExprDag(dag);
- Warning.getStream() << expr::ExprDag(dag);
- Dump.getStream() << expr::ExprDag(dag);
- }
-};
-
-class SetPrintExprTypesListener : public Listener {
- public:
- void notify() override
- {
- bool value = options::printExprTypes();
- Debug.getStream() << expr::ExprPrintTypes(value);
- Trace.getStream() << expr::ExprPrintTypes(value);
- Notice.getStream() << expr::ExprPrintTypes(value);
- Chat.getStream() << expr::ExprPrintTypes(value);
- Message.getStream() << expr::ExprPrintTypes(value);
- Warning.getStream() << expr::ExprPrintTypes(value);
- // intentionally exclude Dump stream from this list
- }
-};
-
-class DumpModeListener : public Listener {
- public:
- void notify() override
- {
- const std::string& value = options::dumpModeString();
- Dump.setDumpFromString(value);
- }
-};
-
-class PrintSuccessListener : public Listener {
- public:
- void notify() override
- {
- bool value = options::printSuccess();
- Debug.getStream() << Command::printsuccess(value);
- Trace.getStream() << Command::printsuccess(value);
- Notice.getStream() << Command::printsuccess(value);
- Chat.getStream() << Command::printsuccess(value);
- Message.getStream() << Command::printsuccess(value);
- Warning.getStream() << Command::printsuccess(value);
- *options::out() << Command::printsuccess(value);
- }
-};
-
-
-
-/**
- * This is an inelegant solution, but for the present, it will work.
- * The point of this is to separate the public and private portions of
- * the SmtEngine class, so that smt_engine.h doesn't
- * include "expr/node.h", which is a private CVC4 header (and can lead
- * to linking errors due to the improper inlining of non-visible symbols
- * into user code!).
- *
- * The "real" solution (that which is usually implemented) is to move
- * ALL the implementation to SmtEnginePrivate and maintain a
- * heap-allocated instance of it in SmtEngine. SmtEngine (the public
- * one) becomes an "interface shell" which simply acts as a forwarder
- * of method calls.
- */
-class SmtEnginePrivate : public NodeManagerListener {
- SmtEngine& d_smt;
-
- typedef unordered_map<Node, Node, NodeHashFunction> NodeToNodeHashMap;
- typedef unordered_map<Node, bool, NodeHashFunction> NodeToBoolHashMap;
-
- /** Manager for the memory of regular-output-channel. */
- ManagedRegularOutputChannel d_managedRegularChannel;
-
- /** Manager for the memory of diagnostic-output-channel. */
- ManagedDiagnosticOutputChannel d_managedDiagnosticChannel;
-
- /** Manager for the memory of --dump-to. */
- ManagedDumpOStream d_managedDumpChannel;
-
- /**
- * This list contains:
- * softResourceOut
- * hardResourceOut
- * beforeSearchListener
- *
- * This needs to be deleted before both NodeManager's Options,
- * SmtEngine, d_resourceManager, and TheoryEngine.
- */
- ListenerRegistrationList* d_listenerRegistrations;
-
- /** A circuit propagator for non-clausal propositional deduction */
- booleans::CircuitPropagator d_propagator;
-
- /** Assertions in the preprocessing pipeline */
- AssertionPipeline d_assertions;
-
- /** Whether any assertions have been processed */
- CDO<bool> d_assertionsProcessed;
-
- // Cached true value
- Node d_true;
-
- /**
- * A context that never pushes/pops, for use by CD structures (like
- * SubstitutionMaps) that should be "global".
- */
- context::Context d_fakeContext;
-
- /**
- * A map of AbsractValues to their actual constants. Only used if
- * options::abstractValues() is on.
- */
- SubstitutionMap d_abstractValueMap;
-
- /**
- * A mapping of all abstract values (actual value |-> abstract) that
- * we've handed out. This is necessary to ensure that we give the
- * same AbstractValues for the same real constants. Only used if
- * options::abstractValues() is on.
- */
- NodeToNodeHashMap d_abstractValues;
-
- /** TODO: whether certain preprocess steps are necessary */
- //bool d_needsExpandDefs;
-
- /** The preprocessing pass context */
- std::unique_ptr<PreprocessingPassContext> d_preprocessingPassContext;
-
- /** Process assertions module */
- ProcessAssertions d_processor;
-
- //------------------------------- expression names
- /** mapping from expressions to name */
- context::CDHashMap< Node, std::string, NodeHashFunction > d_exprNames;
- //------------------------------- end expression names
- public:
- IteSkolemMap& getIteSkolemMap() { return d_assertions.getIteSkolemMap(); }
-
- /** Instance of the ITE remover */
- RemoveTermFormulas d_iteRemover;
-
- /* Finishes the initialization of the private portion of SMTEngine. */
- void finishInit();
-
- /*------------------- sygus utils ------------------*/
- /**
- * sygus variables declared (from "declare-var" and "declare-fun" commands)
- *
- * The SyGuS semantics for declared variables is that they are implicitly
- * universally quantified in the constraints.
- */
- std::vector<Node> d_sygusVars;
- /** sygus constraints */
- std::vector<Node> d_sygusConstraints;
- /** functions-to-synthesize */
- std::vector<Node> d_sygusFunSymbols;
- /**
- * Whether we need to reconstruct the sygus conjecture.
- */
- CDO<bool> d_sygusConjectureStale;
- /*------------------- end of sygus utils ------------------*/
-
- public:
- SmtEnginePrivate(SmtEngine& smt)
- : d_smt(smt),
- d_managedRegularChannel(),
- d_managedDiagnosticChannel(),
- d_managedDumpChannel(),
- d_listenerRegistrations(new ListenerRegistrationList()),
- d_propagator(true, true),
- d_assertions(),
- d_assertionsProcessed(smt.getUserContext(), false),
- d_fakeContext(),
- d_abstractValueMap(&d_fakeContext),
- d_abstractValues(),
- d_processor(smt, *smt.getResourceManager()),
- // d_needsExpandDefs(true), //TODO?
- d_exprNames(smt.getUserContext()),
- d_iteRemover(smt.getUserContext()),
- d_sygusConjectureStale(smt.getUserContext(), true)
- {
- d_smt.d_nodeManager->subscribeEvents(this);
- d_true = NodeManager::currentNM()->mkConst(true);
- ResourceManager* rm = d_smt.getResourceManager();
-
- d_listenerRegistrations->add(
- rm->registerSoftListener(new SoftResourceOutListener(d_smt)));
-
- d_listenerRegistrations->add(
- rm->registerHardListener(new HardResourceOutListener(d_smt)));
-
- try
- {
- Options& opts = d_smt.getOptions();
- // Multiple options reuse BeforeSearchListener so registration requires an
- // extra bit of care.
- // We can safely not call notify on this before search listener at
- // registration time. This d_smt cannot be beforeSearch at construction
- // time. Therefore the BeforeSearchListener is a no-op. Therefore it does
- // not have to be called.
- d_listenerRegistrations->add(
- opts.registerBeforeSearchListener(new BeforeSearchListener(d_smt)));
-
- // These do need registration calls.
- d_listenerRegistrations->add(opts.registerSetDefaultExprDepthListener(
- new SetDefaultExprDepthListener(), true));
- d_listenerRegistrations->add(opts.registerSetDefaultExprDagListener(
- new SetDefaultExprDagListener(), true));
- d_listenerRegistrations->add(opts.registerSetPrintExprTypesListener(
- new SetPrintExprTypesListener(), true));
- d_listenerRegistrations->add(
- opts.registerSetDumpModeListener(new DumpModeListener(), true));
- d_listenerRegistrations->add(opts.registerSetPrintSuccessListener(
- new PrintSuccessListener(), true));
- d_listenerRegistrations->add(opts.registerSetRegularOutputChannelListener(
- new SetToDefaultSourceListener(&d_managedRegularChannel), true));
- d_listenerRegistrations->add(
- opts.registerSetDiagnosticOutputChannelListener(
- new SetToDefaultSourceListener(&d_managedDiagnosticChannel),
- true));
- d_listenerRegistrations->add(opts.registerDumpToFileNameListener(
- new SetToDefaultSourceListener(&d_managedDumpChannel), true));
- }
- catch (OptionException& e)
- {
- // Registering the option listeners can lead to OptionExceptions, e.g.
- // when the user chooses a dump tag that does not exist. In that case, we
- // have to make sure that we delete existing listener registrations and
- // that we unsubscribe from NodeManager events. Otherwise we will have
- // errors in the deconstructors of the NodeManager (because the
- // NodeManager tries to notify an SmtEnginePrivate that does not exist)
- // and the ListenerCollection (because not all registrations have been
- // removed before calling the deconstructor).
- delete d_listenerRegistrations;
- d_smt.d_nodeManager->unsubscribeEvents(this);
- throw OptionException(e.getRawMessage());
- }
- }
-
- ~SmtEnginePrivate()
- {
- delete d_listenerRegistrations;
-
- if(d_propagator.getNeedsFinish()) {
- d_propagator.finish();
- d_propagator.setNeedsFinish(false);
- }
- d_smt.d_nodeManager->unsubscribeEvents(this);
- }
-
- void spendResource(ResourceManager::Resource r)
- {
- d_smt.getResourceManager()->spendResource(r);
- }
-
- ProcessAssertions* getProcessAssertions() { return &d_processor; }
-
- void nmNotifyNewSort(TypeNode tn, uint32_t flags) override
- {
- DeclareTypeCommand c(tn.getAttribute(expr::VarNameAttr()),
- 0,
- tn.toType());
- if((flags & ExprManager::SORT_FLAG_PLACEHOLDER) == 0) {
- d_smt.addToModelCommandAndDump(c, flags);
- }
- }
-
- void nmNotifyNewSortConstructor(TypeNode tn, uint32_t flags) override
- {
- DeclareTypeCommand c(tn.getAttribute(expr::VarNameAttr()),
- tn.getAttribute(expr::SortArityAttr()),
- tn.toType());
- if ((flags & ExprManager::SORT_FLAG_PLACEHOLDER) == 0)
- {
- d_smt.addToModelCommandAndDump(c);
- }
- }
-
- void nmNotifyNewDatatypes(const std::vector<DatatypeType>& dtts,
- uint32_t flags) override
- {
- if ((flags & ExprManager::DATATYPE_FLAG_PLACEHOLDER) == 0)
- {
- std::vector<Type> types(dtts.begin(), dtts.end());
- DatatypeDeclarationCommand c(types);
- d_smt.addToModelCommandAndDump(c);
- }
- }
-
- void nmNotifyNewVar(TNode n, uint32_t flags) override
- {
- DeclareFunctionCommand c(n.getAttribute(expr::VarNameAttr()),
- n.toExpr(),
- n.getType().toType());
- if((flags & ExprManager::VAR_FLAG_DEFINED) == 0) {
- d_smt.addToModelCommandAndDump(c, flags);
- }
- }
-
- void nmNotifyNewSkolem(TNode n,
- const std::string& comment,
- uint32_t flags) override
- {
- string id = n.getAttribute(expr::VarNameAttr());
- DeclareFunctionCommand c(id, n.toExpr(), n.getType().toType());
- if(Dump.isOn("skolems") && comment != "") {
- Dump("skolems") << CommentCommand(id + " is " + comment);
- }
- if((flags & ExprManager::VAR_FLAG_DEFINED) == 0) {
- d_smt.addToModelCommandAndDump(c, flags, false, "skolems");
- }
- }
-
- void nmNotifyDeleteNode(TNode n) override {}
-
- Node applySubstitutions(TNode node)
- {
- return Rewriter::rewrite(
- d_preprocessingPassContext->getTopLevelSubstitutions().apply(node));
- }
-
- /**
- * Process the assertions that have been asserted.
- */
- void processAssertions();
-
- /** Process a user push.
- */
- void notifyPush() {
-
- }
-
- /**
- * Process a user pop. Clears out the non-context-dependent stuff in this
- * SmtEnginePrivate. Necessary to clear out our assertion vectors in case
- * someone does a push-assert-pop without a check-sat. It also pops the
- * last map of expression names from notifyPush.
- */
- void notifyPop() {
- d_assertions.clear();
- d_propagator.getLearnedLiterals().clear();
- getIteSkolemMap().clear();
- }
-
- /**
- * Adds a formula to the current context. Action here depends on
- * the SimplificationMode (in the current Options scope); the
- * formula might be pushed out to the propositional layer
- * immediately, or it might be simplified and kept, or it might not
- * even be simplified.
- * The arguments isInput and isAssumption are used for bookkeeping for proofs.
- * The argument maybeHasFv should be set to true if the assertion may have
- * free variables. By construction, assertions from the smt2 parser are
- * guaranteed not to have free variables. However, other cases such as
- * assertions from the SyGuS parser may have free variables (say if the
- * input contains an assert or define-fun-rec command).
- *
- * @param isAssumption If true, the formula is considered to be an assumption
- * (this is used to distinguish assertions and assumptions)
- */
- void addFormula(TNode n,
- bool inUnsatCore,
- bool inInput = true,
- bool isAssumption = false,
- bool maybeHasFv = false);
- /**
- * Simplify node "in" by expanding definitions and applying any
- * substitutions learned from preprocessing.
- */
- Node simplify(TNode in) {
- // Substitute out any abstract values in ex.
- // Expand definitions.
- NodeToNodeHashMap cache;
- Node n = d_processor.expandDefinitions(in, cache).toExpr();
- // Make sure we've done all preprocessing, etc.
- Assert(d_assertions.size() == 0);
- return applySubstitutions(n).toExpr();
- }
-
- /**
- * Substitute away all AbstractValues in a node.
- */
- Node substituteAbstractValues(TNode n) {
- // We need to do this even if options::abstractValues() is off,
- // since the setting might have changed after we already gave out
- // some abstract values.
- return d_abstractValueMap.apply(n);
- }
-
- /**
- * Make a new (or return an existing) abstract value for a node.
- * Can only use this if options::abstractValues() is on.
- */
- Node mkAbstractValue(TNode n) {
- Assert(options::abstractValues());
- Node& val = d_abstractValues[n];
- if(val.isNull()) {
- val = d_smt.d_nodeManager->mkAbstractValue(n.getType());
- d_abstractValueMap.addSubstitution(val, n);
- }
- // We are supposed to ascribe types to all abstract values that go out.
- NodeManager* current = d_smt.d_nodeManager;
- Node ascription = current->mkConst(AscriptionType(n.getType().toType()));
- Node retval = current->mkNode(kind::APPLY_TYPE_ASCRIPTION, ascription, val);
- return retval;
- }
-
- //------------------------------- expression names
- // implements setExpressionName, as described in smt_engine.h
- void setExpressionName(Expr e, std::string name) {
- d_exprNames[Node::fromExpr(e)] = name;
- }
-
- // implements getExpressionName, as described in smt_engine.h
- bool getExpressionName(Expr e, std::string& name) const {
- context::CDHashMap< Node, std::string, NodeHashFunction >::const_iterator it = d_exprNames.find(e);
- if(it!=d_exprNames.end()) {
- name = (*it).second;
- return true;
- }else{
- return false;
- }
- }
- //------------------------------- end expression names
-};/* class SmtEnginePrivate */
-
-}/* namespace CVC4::smt */
-
SmtEngine::SmtEngine(ExprManager* em, Options* optr)
- : d_context(new Context()),
- d_userContext(new UserContext()),
- d_userLevels(),
+ : d_state(new SmtEngineState(*this)),
d_exprManager(em),
d_nodeManager(d_exprManager->getNodeManager()),
- d_theoryEngine(nullptr),
- d_propEngine(nullptr),
+ d_absValues(new AbstractValues(d_nodeManager)),
+ d_asserts(new Assertions(getUserContext(), *d_absValues.get())),
+ d_dumpm(new DumpManager(getUserContext())),
+ d_routListener(new ResourceOutListener(*this)),
+ d_snmListener(new SmtNodeManagerListener(*d_dumpm.get(), d_outMgr)),
+ d_smtSolver(nullptr),
d_proofManager(nullptr),
+ d_model(nullptr),
+ d_checkModels(nullptr),
+ d_pfManager(nullptr),
d_rewriter(new theory::Rewriter()),
d_definedFunctions(nullptr),
+ d_sygusSolver(nullptr),
d_abductSolver(nullptr),
- d_assertionList(nullptr),
- d_assignments(nullptr),
- d_modelGlobalCommands(),
- d_modelCommands(nullptr),
- d_dumpCommands(),
- d_defineCommands(),
+ d_interpolSolver(nullptr),
+ d_quantElimSolver(nullptr),
d_logic(),
d_originalOptions(),
d_isInternalSubsolver(false),
- d_pendingPops(0),
- d_fullyInited(false),
- d_queryMade(false),
- d_needPostsolve(false),
- d_globalNegation(false),
- d_status(),
- d_expectedStatus(),
- d_smtMode(SMT_MODE_START),
- d_private(nullptr),
d_statisticsRegistry(nullptr),
d_stats(nullptr),
+ d_outMgr(this),
d_resourceManager(nullptr),
+ d_optm(nullptr),
+ d_pp(nullptr),
d_scope(nullptr)
{
// !!!!!!!!!!!!!!!!!!!!!! temporary hack: this makes the current SmtEngine
@@ -688,9 +126,24 @@ SmtEngine::SmtEngine(ExprManager* em, Options* optr)
d_statisticsRegistry.reset(new StatisticsRegistry());
d_resourceManager.reset(
new ResourceManager(*d_statisticsRegistry.get(), d_options));
- d_private.reset(new smt::SmtEnginePrivate(*this));
+ d_optm.reset(new smt::OptionsManager(&d_options, d_resourceManager.get()));
+ // listen to node manager events
+ d_nodeManager->subscribeEvents(d_snmListener.get());
+ // listen to resource out
+ d_resourceManager->registerListener(d_routListener.get());
+ // make statistics
d_stats.reset(new SmtEngineStatistics());
- d_stats->d_resourceUnitsUsed.setData(d_resourceManager->getResourceUsage());
+ // reset the preprocessor
+ d_pp.reset(new smt::Preprocessor(
+ *this, getUserContext(), *d_absValues.get(), *d_stats));
+ // make the SMT solver
+ d_smtSolver.reset(
+ new SmtSolver(*this, *d_state, d_resourceManager.get(), *d_pp, *d_stats));
+ // make the SyGuS solver
+ d_sygusSolver.reset(
+ new SygusSolver(*d_smtSolver, *d_pp, getUserContext(), d_outMgr));
+ // make the quantifier elimination solver
+ d_quantElimSolver.reset(new QuantElimSolver(*d_smtSolver));
// The ProofManager is constructed before any other proof objects such as
// SatProof and TheoryProofs. The TheoryProofEngine and the SatProof are
@@ -705,96 +158,103 @@ SmtEngine::SmtEngine(ExprManager* em, Options* optr)
#endif
d_definedFunctions = new (true) DefinedFunctionMap(getUserContext());
- d_modelCommands = new (true) smt::CommandList(getUserContext());
}
-void SmtEngine::finishInit()
+bool SmtEngine::isFullyInited() const { return d_state->isFullyInited(); }
+bool SmtEngine::isQueryMade() const { return d_state->isQueryMade(); }
+size_t SmtEngine::getNumUserLevels() const
{
- // Notice that finishInit is called when options are finalized. If we are
- // parsing smt2, this occurs at the moment we enter "Assert mode", page 52
- // of SMT-LIB 2.6 standard.
+ return d_state->getNumUserLevels();
+}
+SmtMode SmtEngine::getSmtMode() const { return d_state->getMode(); }
+bool SmtEngine::isSmtModeSat() const
+{
+ SmtMode mode = getSmtMode();
+ return mode == SmtMode::SAT || mode == SmtMode::SAT_UNKNOWN;
+}
+Result SmtEngine::getStatusOfLastCommand() const
+{
+ return d_state->getStatus();
+}
+context::UserContext* SmtEngine::getUserContext()
+{
+ return d_state->getUserContext();
+}
+context::Context* SmtEngine::getContext() { return d_state->getContext(); }
- // Inialize the resource manager based on the options.
- d_resourceManager->setHardLimit(options::hardLimit());
- if (options::perCallResourceLimit() != 0)
- {
- d_resourceManager->setResourceLimit(options::perCallResourceLimit(), false);
- }
- if (options::cumulativeResourceLimit() != 0)
- {
- d_resourceManager->setResourceLimit(options::cumulativeResourceLimit(),
- true);
- }
- if (options::perCallMillisecondLimit() != 0)
- {
- d_resourceManager->setTimeLimit(options::perCallMillisecondLimit(), false);
- }
- if (options::cumulativeMillisecondLimit() != 0)
+TheoryEngine* SmtEngine::getTheoryEngine()
+{
+ return d_smtSolver->getTheoryEngine();
+}
+
+prop::PropEngine* SmtEngine::getPropEngine()
+{
+ return d_smtSolver->getPropEngine();
+}
+
+void SmtEngine::finishInit()
+{
+ if (d_state->isFullyInited())
{
- d_resourceManager->setTimeLimit(options::cumulativeMillisecondLimit(),
- true);
+ // already initialized, return
+ return;
}
- if (options::cpuTime())
+
+ // Notice that finishInitInternal is called when options are finalized. If we
+ // are parsing smt2, this occurs at the moment we enter "Assert mode", page 52
+ // of SMT-LIB 2.6 standard.
+
+ // set the logic
+ if (!d_logic.isLocked())
{
- d_resourceManager->useCPUTime(true);
+ setLogicInternal();
}
// set the random seed
Random::getRandom().setSeed(options::seed());
- // ensure that our heuristics are properly set up
- setDefaults(d_logic, d_isInternalSubsolver);
-
- Trace("smt-debug") << "SmtEngine::finishInit" << std::endl;
- // We have mutual dependency here, so we add the prop engine to the theory
- // engine later (it is non-essential there)
- d_theoryEngine.reset(new TheoryEngine(getContext(),
- getUserContext(),
- getResourceManager(),
- d_private->d_iteRemover,
- const_cast<const LogicInfo&>(d_logic)));
-
- // Add the theories
- for(TheoryId id = theory::THEORY_FIRST; id < theory::THEORY_LAST; ++id) {
- TheoryConstructor::addTheory(getTheoryEngine(), id);
- //register with proof engine if applicable
-#ifdef CVC4_PROOF
- ProofManager::currentPM()->getTheoryProofEngine()->registerTheory(d_theoryEngine->theoryOf(id));
-#endif
- }
+ // Call finish init on the options manager. This inializes the resource
+ // manager based on the options, and sets up the best default options
+ // based on our heuristics.
+ d_optm->finishInit(d_logic, d_isInternalSubsolver);
- Trace("smt-debug") << "Making decision engine..." << std::endl;
+ ProofNodeManager* pnm = nullptr;
+ if (options::proofNew())
+ {
+ d_pfManager.reset(new PfManager(getUserContext(), this));
+ PreprocessProofGenerator* pppg = d_pfManager->getPreprocessProofGenerator();
+ // use this proof node manager
+ pnm = d_pfManager->getProofNodeManager();
+ // enable proof support in the rewriter
+ d_rewriter->setProofNodeManager(pnm);
+ // enable it in the assertions pipeline
+ d_asserts->setProofGenerator(pppg);
+ // enable it in the SmtSolver
+ d_smtSolver->setProofNodeManager(pnm);
+ // enabled proofs in the preprocessor
+ d_pp->setProofGenerator(pppg);
+ }
- Trace("smt-debug") << "Making prop engine..." << std::endl;
- /* force destruction of referenced PropEngine to enforce that statistics
- * are unregistered by the obsolete PropEngine object before registered
- * again by the new PropEngine object */
- d_propEngine.reset(nullptr);
- d_propEngine.reset(new PropEngine(
- getTheoryEngine(), getContext(), getUserContext(), getResourceManager()));
+ Trace("smt-debug") << "SmtEngine::finishInit" << std::endl;
+ d_smtSolver->finishInit(const_cast<const LogicInfo&>(d_logic));
- Trace("smt-debug") << "Setting up theory engine..." << std::endl;
- d_theoryEngine->setPropEngine(getPropEngine());
- Trace("smt-debug") << "Finishing init for theory engine..." << std::endl;
- d_theoryEngine->finishInit();
+ // now can construct the SMT-level model object
+ TheoryEngine* te = d_smtSolver->getTheoryEngine();
+ Assert(te != nullptr);
+ TheoryModel* tm = te->getModel();
+ if (tm != nullptr)
+ {
+ d_model.reset(new Model(*this, tm));
+ // make the check models utility
+ d_checkModels.reset(new CheckModels(*d_smtSolver.get()));
+ }
// global push/pop around everything, to ensure proper destruction
// of context-dependent data structures
- d_userContext->push();
- d_context->push();
-
- Trace("smt-debug") << "Set up assertion list..." << std::endl;
- // [MGD 10/20/2011] keep around in incremental mode, due to a
- // cleanup ordering issue and Nodes/TNodes. If SAT is popped
- // first, some user-context-dependent TNodes might still exist
- // with rc == 0.
- if(options::produceAssertions() ||
- options::incrementalSolving()) {
- // In the case of incremental solving, we appear to need these to
- // ensure the relevant Nodes remain live.
- d_assertionList = new (true) AssertionList(getUserContext());
- d_globalDefineFunRecLemmas.reset(new std::vector<Node>());
- }
+ d_state->setup();
+
+ Trace("smt-debug") << "Set up assertions..." << std::endl;
+ d_asserts->finishInit();
// dump out a set-logic command only when raw-benchmark is disabled to avoid
// dumping the command twice.
@@ -802,74 +262,45 @@ void SmtEngine::finishInit()
{
LogicInfo everything;
everything.lock();
- Dump("benchmark") << CommentCommand(
+ getOutputManager().getPrinter().toStreamCmdComment(
+ getOutputManager().getDumpOut(),
"CVC4 always dumps the most general, all-supported logic (below), as "
"some internals might require the use of a logic more general than "
- "the input.")
- << SetBenchmarkLogicCommand(
- everything.getLogicString());
+ "the input.");
+ getOutputManager().getPrinter().toStreamCmdSetBenchmarkLogic(
+ getOutputManager().getDumpOut(), everything.getLogicString());
}
- Trace("smt-debug") << "Dump declaration commands..." << std::endl;
- // dump out any pending declaration commands
- for(unsigned i = 0; i < d_dumpCommands.size(); ++i) {
- Dump("declarations") << *d_dumpCommands[i];
- delete d_dumpCommands[i];
- }
- d_dumpCommands.clear();
+ // initialize the dump manager
+ d_dumpm->finishInit();
// subsolvers
if (options::produceAbducts())
{
d_abductSolver.reset(new AbductionSolver(this));
}
-
- PROOF( ProofManager::currentPM()->setLogic(d_logic); );
- PROOF({
- for(TheoryId id = theory::THEORY_FIRST; id < theory::THEORY_LAST; ++id) {
- ProofManager::currentPM()->getTheoryProofEngine()->
- finishRegisterTheory(d_theoryEngine->theoryOf(id));
- }
- });
- d_private->finishInit();
- Trace("smt-debug") << "SmtEngine::finishInit done" << std::endl;
-}
-
-void SmtEngine::finalOptionsAreSet() {
- if(d_fullyInited) {
- return;
- }
-
- if(! d_logic.isLocked()) {
- setLogicInternal();
+ if (options::produceInterpols() != options::ProduceInterpols::NONE)
+ {
+ d_interpolSolver.reset(new InterpolationSolver(this));
}
- // finish initialization, create the prop engine, etc.
- finishInit();
+ d_pp->finishInit();
- AlwaysAssert(d_propEngine->getAssertionLevel() == 0)
+ AlwaysAssert(getPropEngine()->getAssertionLevel() == 0)
<< "The PropEngine has pushed but the SmtEngine "
"hasn't finished initializing!";
- d_fullyInited = true;
Assert(d_logic.isLocked());
+
+ // store that we are finished initializing
+ d_state->finishInit();
+ Trace("smt-debug") << "SmtEngine::finishInit done" << std::endl;
}
void SmtEngine::shutdown() {
- doPendingPops();
+ d_state->shutdown();
- while(options::incrementalSolving() && d_userContext->getLevel() > 1) {
- internalPop(true);
- }
-
- if (d_propEngine != nullptr)
- {
- d_propEngine->shutdown();
- }
- if (d_theoryEngine != nullptr)
- {
- d_theoryEngine->shutdown();
- }
+ d_smtSolver->shutdown();
}
SmtEngine::~SmtEngine()
@@ -881,35 +312,12 @@ SmtEngine::~SmtEngine()
// global push/pop around everything, to ensure proper destruction
// of context-dependent data structures
- d_context->popto(0);
- d_userContext->popto(0);
-
- if(d_assignments != NULL) {
- d_assignments->deleteSelf();
- }
-
- d_globalDefineFunRecLemmas.reset();
-
- if(d_assertionList != NULL) {
- d_assertionList->deleteSelf();
- }
-
- for(unsigned i = 0; i < d_dumpCommands.size(); ++i) {
- delete d_dumpCommands[i];
- d_dumpCommands[i] = NULL;
- }
- d_dumpCommands.clear();
-
- DeleteAndClearCommandVector(d_modelGlobalCommands);
-
- if(d_modelCommands != NULL) {
- d_modelCommands->deleteSelf();
- }
+ d_state->cleanup();
d_definedFunctions->deleteSelf();
//destroy all passes before destroying things that they refer to
- d_private->getProcessAssertions()->cleanup();
+ d_pp->cleanup();
// d_proofManager is always created when proofs are enabled at configure
// time. Because of this, this code should not be wrapped in PROOF() which
@@ -922,18 +330,25 @@ SmtEngine::~SmtEngine()
d_proofManager.reset(nullptr);
#endif
- d_theoryEngine.reset(nullptr);
- d_propEngine.reset(nullptr);
+ d_absValues.reset(nullptr);
+ d_asserts.reset(nullptr);
+ d_dumpm.reset(nullptr);
+
+ d_sygusSolver.reset(nullptr);
+
+ d_smtSolver.reset(nullptr);
d_stats.reset(nullptr);
- d_private.reset(nullptr);
+ d_nodeManager->unsubscribeEvents(d_snmListener.get());
+ d_snmListener.reset(nullptr);
+ d_routListener.reset(nullptr);
+ d_optm.reset(nullptr);
+ d_pp.reset(nullptr);
// d_resourceManager must be destroyed before d_statisticsRegistry
d_resourceManager.reset(nullptr);
d_statisticsRegistry.reset(nullptr);
-
-
- d_userContext.reset(nullptr);
- d_context.reset(nullptr);
+ // destroy the state
+ d_state.reset(nullptr);
} catch(Exception& e) {
Warning() << "CVC4 threw an exception during cleanup." << endl
<< e << endl;
@@ -943,7 +358,8 @@ SmtEngine::~SmtEngine()
void SmtEngine::setLogic(const LogicInfo& logic)
{
SmtScope smts(this);
- if(d_fullyInited) {
+ if (d_state->isFullyInited())
+ {
throw ModalException("Cannot set logic in SmtEngine after the engine has "
"finished initializing.");
}
@@ -961,8 +377,8 @@ void SmtEngine::setLogic(const std::string& s)
// dump out a set-logic command
if (Dump.isOn("raw-benchmark"))
{
- Dump("raw-benchmark")
- << SetBenchmarkLogicCommand(d_logic.getLogicString());
+ getOutputManager().getPrinter().toStreamCmdSetBenchmarkLogic(
+ getOutputManager().getDumpOut(), d_logic.getLogicString());
}
}
catch (IllegalArgumentException& e)
@@ -972,9 +388,8 @@ void SmtEngine::setLogic(const std::string& s)
}
void SmtEngine::setLogic(const char* logic) { setLogic(string(logic)); }
-LogicInfo SmtEngine::getLogicInfo() const {
- return d_logic;
-}
+
+const LogicInfo& SmtEngine::getLogicInfo() const { return d_logic; }
LogicInfo SmtEngine::getUserLogicInfo() const
{
@@ -987,30 +402,26 @@ LogicInfo SmtEngine::getUserLogicInfo() const
void SmtEngine::notifyStartParsing(std::string filename)
{
- d_filename = filename;
-
+ d_state->setFilename(filename);
// Copy the original options. This is called prior to beginning parsing.
// Hence reset should revert to these options, which note is after reading
// the command line.
d_originalOptions.copyValues(d_options);
}
-std::string SmtEngine::getFilename() const { return d_filename; }
+const std::string& SmtEngine::getFilename() const
+{
+ return d_state->getFilename();
+}
void SmtEngine::setLogicInternal()
{
- Assert(!d_fullyInited)
+ Assert(!d_state->isFullyInited())
<< "setting logic in SmtEngine but the engine has already"
" finished initializing for this run";
d_logic.lock();
d_userLogic.lock();
}
-void SmtEngine::setProblemExtended()
-{
- d_smtMode = SMT_MODE_ASSERT;
- d_assumptions.clear();
-}
-
void SmtEngine::setInfo(const std::string& key, const CVC4::SExpr& value)
{
SmtScope smts(this);
@@ -1020,12 +431,14 @@ void SmtEngine::setInfo(const std::string& key, const CVC4::SExpr& value)
if(Dump.isOn("benchmark")) {
if(key == "status") {
string s = value.getValue();
- BenchmarkStatus status =
- (s == "sat") ? SMT_SATISFIABLE :
- ((s == "unsat") ? SMT_UNSATISFIABLE : SMT_UNKNOWN);
- Dump("benchmark") << SetBenchmarkStatusCommand(status);
+ Result::Sat status =
+ (s == "sat") ? Result::SAT
+ : ((s == "unsat") ? Result::UNSAT : Result::SAT_UNKNOWN);
+ getOutputManager().getPrinter().toStreamCmdSetBenchmarkStatus(
+ getOutputManager().getDumpOut(), status);
} else {
- Dump("benchmark") << SetInfoCommand(key, value);
+ getOutputManager().getPrinter().toStreamCmdSetInfo(
+ getOutputManager().getDumpOut(), key, value);
}
}
@@ -1038,7 +451,7 @@ void SmtEngine::setInfo(const std::string& key, const CVC4::SExpr& value)
}
else if (key == "filename")
{
- d_filename = value.getValue();
+ d_state->setFilename(value.getValue());
return;
}
else if (key == "smt-lib-version" && !options::inputLanguage.wasSetByUser())
@@ -1082,7 +495,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_expectedStatus = Result(s, d_filename);
+ d_state->notifyExpectedStatus(s);
return;
}
throw UnrecognizedOptionException();
@@ -1157,7 +570,8 @@ CVC4::SExpr SmtEngine::getInfo(const std::string& key) const
if (key == "status")
{
// sat | unsat | unknown
- switch (d_status.asSatisfiabilityResult().isSat())
+ Result status = d_state->getStatus();
+ switch (status.asSatisfiabilityResult().isSat())
{
case Result::SAT: return SExpr(SExpr::Keyword("sat"));
case Result::UNSAT: return SExpr(SExpr::Keyword("unsat"));
@@ -1166,10 +580,11 @@ CVC4::SExpr SmtEngine::getInfo(const std::string& key) const
}
if (key == "reason-unknown")
{
- if (!d_status.isNull() && d_status.isUnknown())
+ Result status = d_state->getStatus();
+ if (!status.isNull() && status.isUnknown())
{
- stringstream ss;
- ss << d_status.whyUnknown();
+ std::stringstream ss;
+ ss << status.whyUnknown();
string s = ss.str();
transform(s.begin(), s.end(), s.begin(), ::tolower);
return SExpr(SExpr::Keyword(s));
@@ -1183,9 +598,9 @@ CVC4::SExpr SmtEngine::getInfo(const std::string& key) const
}
if (key == "assertion-stack-levels")
{
- AlwaysAssert(d_userLevels.size()
- <= std::numeric_limits<unsigned long int>::max());
- return SExpr(static_cast<unsigned long int>(d_userLevels.size()));
+ size_t ulevel = d_state->getNumUserLevels();
+ AlwaysAssert(ulevel <= std::numeric_limits<unsigned long int>::max());
+ return SExpr(static_cast<unsigned long int>(ulevel));
}
Assert(key == "all-options");
// get the options, like all-statistics
@@ -1194,33 +609,36 @@ CVC4::SExpr SmtEngine::getInfo(const std::string& key) const
return SExpr::parseListOfListOfAtoms(current_options);
}
-void SmtEngine::debugCheckFormals(const std::vector<Expr>& formals, Expr func)
+void SmtEngine::debugCheckFormals(const std::vector<Node>& formals, Node func)
{
- for(std::vector<Expr>::const_iterator i = formals.begin(); i != formals.end(); ++i) {
+ for (std::vector<Node>::const_iterator i = formals.begin();
+ i != formals.end();
+ ++i)
+ {
if((*i).getKind() != kind::BOUND_VARIABLE) {
stringstream ss;
ss << "All formal arguments to defined functions must be BOUND_VARIABLEs, but in the\n"
<< "definition of function " << func << ", formal\n"
<< " " << *i << "\n"
<< "has kind " << (*i).getKind();
- throw TypeCheckingException(func, ss.str());
+ throw TypeCheckingException(func.toExpr(), ss.str());
}
}
}
-void SmtEngine::debugCheckFunctionBody(Expr formula,
- const std::vector<Expr>& formals,
- Expr func)
+void SmtEngine::debugCheckFunctionBody(Node formula,
+ const std::vector<Node>& formals,
+ Node func)
{
- Type formulaType = formula.getType(options::typeChecking());
- Type funcType = func.getType();
+ TypeNode formulaType = formula.getType(options::typeChecking());
+ TypeNode funcType = func.getType();
// We distinguish here between definitions of constants and functions,
// because the type checking for them is subtly different. Perhaps we
// should instead have SmtEngine::defineFunction() and
// SmtEngine::defineConstant() for better clarity, although then that
// doesn't match the SMT-LIBv2 standard...
if(formals.size() > 0) {
- Type rangeType = FunctionType(funcType).getRangeType();
+ TypeNode rangeType = funcType.getRangeType();
if(! formulaType.isComparableTo(rangeType)) {
stringstream ss;
ss << "Type of defined function does not match its declaration\n"
@@ -1228,29 +646,29 @@ void SmtEngine::debugCheckFunctionBody(Expr formula,
<< "Declared type : " << rangeType << "\n"
<< "The body : " << formula << "\n"
<< "Body type : " << formulaType;
- throw TypeCheckingException(func, ss.str());
+ throw TypeCheckingException(func.toExpr(), ss.str());
}
} else {
if(! formulaType.isComparableTo(funcType)) {
stringstream ss;
ss << "Declared type of defined constant does not match its definition\n"
<< "The constant : " << func << "\n"
- << "Declared type : " << funcType << " " << Type::getTypeNode(funcType)->getId() << "\n"
+ << "Declared type : " << funcType << "\n"
<< "The definition : " << formula << "\n"
- << "Definition type: " << formulaType << " " << Type::getTypeNode(formulaType)->getId();
- throw TypeCheckingException(func, ss.str());
+ << "Definition type: " << formulaType;
+ throw TypeCheckingException(func.toExpr(), ss.str());
}
}
}
-void SmtEngine::defineFunction(Expr func,
- const std::vector<Expr>& formals,
- Expr formula,
+void SmtEngine::defineFunction(Node func,
+ const std::vector<Node>& formals,
+ Node formula,
bool global)
{
SmtScope smts(this);
- finalOptionsAreSet();
- doPendingPops();
+ finishInit();
+ d_state->doPendingPops();
Trace("smt") << "SMT defineFunction(" << func << ")" << endl;
debugCheckFormals(formals, func);
@@ -1258,53 +676,48 @@ void SmtEngine::defineFunction(Expr func,
ss << language::SetLanguage(
language::SetLanguage::getLanguage(Dump.getStream()))
<< func;
- DefineFunctionCommand c(ss.str(), func, formals, formula, global);
- addToModelCommandAndDump(
- c, ExprManager::VAR_FLAG_DEFINED, true, "declarations");
+ std::vector<Node> nFormals;
+ nFormals.reserve(formals.size());
+
+ for (const Node& formal : formals)
+ {
+ nFormals.push_back(formal);
+ }
- PROOF(if (options::checkUnsatCores()) {
- d_defineCommands.push_back(c.clone());
- });
+ DefineFunctionNodeCommand nc(ss.str(), func, nFormals, formula);
+ d_dumpm->addToModelCommandAndDump(
+ nc, ExprManager::VAR_FLAG_DEFINED, true, "declarations");
// type check body
debugCheckFunctionBody(formula, formals, func);
// Substitute out any abstract values in formula
- Node formNode = d_private->substituteAbstractValues(Node::fromExpr(formula));
-
- TNode funcNode = func.getTNode();
- vector<Node> formalsNodes;
- for(vector<Expr>::const_iterator i = formals.begin(),
- iend = formals.end();
- i != iend;
- ++i) {
- formalsNodes.push_back((*i).getNode());
- }
- DefinedFunction def(funcNode, formalsNodes, formNode);
+ Node formNode = d_absValues->substituteAbstractValues(formula);
+ DefinedFunction def(func, formals, formNode);
// Permit (check-sat) (define-fun ...) (get-value ...) sequences.
// Otherwise, (check-sat) (get-value ((! foo :named bar))) breaks
// d_haveAdditions = true;
- Debug("smt") << "definedFunctions insert " << funcNode << " " << formNode << endl;
+ Debug("smt") << "definedFunctions insert " << func << " " << formNode << endl;
if (global)
{
- d_definedFunctions->insertAtContextLevelZero(funcNode, def);
+ d_definedFunctions->insertAtContextLevelZero(func, def);
}
else
{
- d_definedFunctions->insert(funcNode, def);
+ d_definedFunctions->insert(func, def);
}
}
void SmtEngine::defineFunctionsRec(
- const std::vector<Expr>& funcs,
- const std::vector<std::vector<Expr>>& formals,
- const std::vector<Expr>& formulas,
+ const std::vector<Node>& funcs,
+ const std::vector<std::vector<Node>>& formals,
+ const std::vector<Node>& formulas,
bool global)
{
SmtScope smts(this);
- finalOptionsAreSet();
- doPendingPops();
+ finishInit();
+ d_state->doPendingPops();
Trace("smt") << "SMT defineFunctionsRec(...)" << endl;
if (funcs.size() != formals.size() && funcs.size() != formulas.size())
@@ -1328,24 +741,15 @@ void SmtEngine::defineFunctionsRec(
if (Dump.isOn("raw-benchmark"))
{
- std::vector<api::Term> tFuncs = api::exprVectorToTerms(d_solver, funcs);
- std::vector<std::vector<api::Term>> tFormals;
- for (const std::vector<Expr>& formal : formals)
- {
- tFormals.emplace_back(api::exprVectorToTerms(d_solver, formal));
- }
- std::vector<api::Term> tFormulas =
- api::exprVectorToTerms(d_solver, formulas);
- Dump("raw-benchmark") << DefineFunctionRecCommand(
- d_solver, tFuncs, tFormals, tFormulas, global);
+ getOutputManager().getPrinter().toStreamCmdDefineFunctionRec(
+ getOutputManager().getDumpOut(), funcs, formals, formulas);
}
- ExprManager* em = getExprManager();
- bool maybeHasFv = language::isInputLangSygus(options::inputLanguage());
+ NodeManager* nm = getNodeManager();
for (unsigned i = 0, size = funcs.size(); i < size; i++)
{
// we assert a quantified formula
- Expr func_app;
+ Node func_app;
// make the function application
if (formals[i].empty())
{
@@ -1354,120 +758,60 @@ void SmtEngine::defineFunctionsRec(
}
else
{
- std::vector<Expr> children;
+ std::vector<Node> children;
children.push_back(funcs[i]);
children.insert(children.end(), formals[i].begin(), formals[i].end());
- func_app = em->mkExpr(kind::APPLY_UF, children);
+ func_app = nm->mkNode(kind::APPLY_UF, children);
}
- Expr lem = em->mkExpr(kind::EQUAL, func_app, formulas[i]);
+ Node lem = nm->mkNode(kind::EQUAL, func_app, formulas[i]);
if (!formals[i].empty())
{
// set the attribute to denote this is a function definition
- std::string attr_name("fun-def");
- Expr aexpr = em->mkExpr(kind::INST_ATTRIBUTE, func_app);
- aexpr = em->mkExpr(kind::INST_PATTERN_LIST, aexpr);
- std::vector<Expr> expr_values;
- std::string str_value;
- setUserAttribute(attr_name, func_app, expr_values, str_value);
+ Node aexpr = nm->mkNode(kind::INST_ATTRIBUTE, func_app);
+ aexpr = nm->mkNode(kind::INST_PATTERN_LIST, aexpr);
+ FunDefAttribute fda;
+ func_app.setAttribute(fda, true);
// make the quantified formula
- Expr boundVars = em->mkExpr(kind::BOUND_VAR_LIST, formals[i]);
- lem = em->mkExpr(kind::FORALL, boundVars, lem, aexpr);
+ Node boundVars = nm->mkNode(kind::BOUND_VAR_LIST, formals[i]);
+ lem = nm->mkNode(kind::FORALL, boundVars, lem, aexpr);
}
// assert the quantified formula
// notice we don't call assertFormula directly, since this would
// duplicate the output on raw-benchmark.
- Node n = d_private->substituteAbstractValues(Node::fromExpr(lem));
- if (d_assertionList != nullptr)
- {
- d_assertionList->push_back(n);
- }
- if (global && d_globalDefineFunRecLemmas != nullptr)
- {
- // Global definitions are asserted at check-sat-time because we have to
- // make sure that they are always present
- Assert(!language::isInputLangSygus(options::inputLanguage()));
- d_globalDefineFunRecLemmas->emplace_back(n);
- }
- else
- {
- d_private->addFormula(n, false, true, false, maybeHasFv);
- }
+ // add define recursive definition to the assertions
+ d_asserts->addDefineFunRecDefinition(lem, global);
}
}
-void SmtEngine::defineFunctionRec(Expr func,
- const std::vector<Expr>& formals,
- Expr formula,
+void SmtEngine::defineFunctionRec(Node func,
+ const std::vector<Node>& formals,
+ Node formula,
bool global)
{
- std::vector<Expr> funcs;
+ std::vector<Node> funcs;
funcs.push_back(func);
- std::vector<std::vector<Expr> > formals_multi;
+ std::vector<std::vector<Node>> formals_multi;
formals_multi.push_back(formals);
- std::vector<Expr> formulas;
+ std::vector<Node> formulas;
formulas.push_back(formula);
defineFunctionsRec(funcs, formals_multi, formulas, global);
}
-bool SmtEngine::isDefinedFunction( Expr func ){
- Node nf = Node::fromExpr( func );
- Debug("smt") << "isDefined function " << nf << "?" << std::endl;
- return d_definedFunctions->find(nf) != d_definedFunctions->end();
-}
-
-void SmtEnginePrivate::finishInit()
+bool SmtEngine::isDefinedFunction(Node func)
{
- d_preprocessingPassContext.reset(
- new PreprocessingPassContext(&d_smt, &d_iteRemover, &d_propagator));
-
- // initialize the preprocessing passes
- d_processor.finishInit(d_preprocessingPassContext.get());
-}
-
-Result SmtEngine::check() {
- Assert(d_fullyInited);
- Assert(d_pendingPops == 0);
-
- Trace("smt") << "SmtEngine::check()" << endl;
-
- d_resourceManager->beginCall();
-
- // Only way we can be out of resource is if cumulative budget is on
- if (d_resourceManager->cumulativeLimitOn() && d_resourceManager->out())
- {
- Result::UnknownExplanation why = d_resourceManager->outOfResources()
- ? Result::RESOURCEOUT
- : Result::TIMEOUT;
- return Result(Result::ENTAILMENT_UNKNOWN, why, d_filename);
- }
-
- // Make sure the prop layer has all of the assertions
- Trace("smt") << "SmtEngine::check(): processing assertions" << endl;
- d_private->processAssertions();
- Trace("smt") << "SmtEngine::check(): done processing assertions" << endl;
-
- TimerStat::CodeTimer solveTimer(d_stats->d_solveTime);
-
- Chat() << "solving..." << endl;
- Trace("smt") << "SmtEngine::check(): running check" << endl;
- Result result = d_propEngine->checkSat();
-
- d_resourceManager->endCall();
- Trace("limit") << "SmtEngine::check(): cumulative millis "
- << d_resourceManager->getTimeUsage() << ", resources "
- << d_resourceManager->getResourceUsage() << endl;
-
- return Result(result, d_filename);
+ Debug("smt") << "isDefined function " << func << "?" << std::endl;
+ return d_definedFunctions->find(func) != d_definedFunctions->end();
}
Result SmtEngine::quickCheck() {
- Assert(d_fullyInited);
+ Assert(d_state->isFullyInited());
Trace("smt") << "SMT quickCheck()" << endl;
+ const std::string& filename = d_state->getFilename();
return Result(
- Result::ENTAILMENT_UNKNOWN, Result::REQUIRES_FULL_CHECK, d_filename);
+ Result::ENTAILMENT_UNKNOWN, Result::REQUIRES_FULL_CHECK, filename);
}
-theory::TheoryModel* SmtEngine::getAvailableModel(const char* c) const
+Model* SmtEngine::getAvailableModel(const char* c) const
{
if (!options::assignFunctionValues())
{
@@ -1476,7 +820,8 @@ theory::TheoryModel* SmtEngine::getAvailableModel(const char* c) const
throw RecoverableModalException(ss.str().c_str());
}
- if (d_smtMode != SMT_MODE_SAT && d_smtMode != SMT_MODE_SAT_UNKNOWN)
+ if (d_state->getMode() != SmtMode::SAT
+ && d_state->getMode() != SmtMode::SAT_UNKNOWN)
{
std::stringstream ss;
ss << "Cannot " << c
@@ -1492,330 +837,128 @@ theory::TheoryModel* SmtEngine::getAvailableModel(const char* c) const
throw ModalException(ss.str().c_str());
}
- TheoryModel* m = d_theoryEngine->getBuiltModel();
+ TheoryEngine* te = d_smtSolver->getTheoryEngine();
+ Assert(te != nullptr);
+ TheoryModel* m = te->getBuiltModel();
if (m == nullptr)
{
std::stringstream ss;
ss << "Cannot " << c
<< " since model is not available. Perhaps the most recent call to "
- "check-sat was interupted?";
+ "check-sat was interrupted?";
throw RecoverableModalException(ss.str().c_str());
}
- return m;
+ return d_model.get();
}
-void SmtEnginePrivate::processAssertions() {
- TimerStat::CodeTimer paTimer(d_smt.d_stats->d_processAssertionsTime);
- spendResource(ResourceManager::Resource::PreprocessStep);
- Assert(d_smt.d_fullyInited);
- Assert(d_smt.d_pendingPops == 0);
-
- if (d_assertions.size() == 0) {
- // nothing to do
- return;
- }
- if (d_assertionsProcessed && options::incrementalSolving()) {
- // TODO(b/1255): Substitutions in incremental mode should be managed with a
- // proper data structure.
+void SmtEngine::notifyPushPre() { d_smtSolver->processAssertions(*d_asserts); }
- d_assertions.enableStoreSubstsInAsserts();
- }
- else
- {
- d_assertions.disableStoreSubstsInAsserts();
- }
+void SmtEngine::notifyPushPost()
+{
+ TimerStat::CodeTimer pushPopTimer(d_stats->d_pushPopTime);
+ Assert(getPropEngine() != nullptr);
+ getPropEngine()->push();
+}
- // process the assertions
- bool noConflict = d_processor.apply(d_assertions);
+void SmtEngine::notifyPopPre()
+{
+ TimerStat::CodeTimer pushPopTimer(d_stats->d_pushPopTime);
+ PropEngine* pe = getPropEngine();
+ Assert(pe != nullptr);
+ pe->pop();
+}
- //notify theory engine new preprocessed assertions
- d_smt.d_theoryEngine->notifyPreprocessedAssertions( d_assertions.ref() );
+void SmtEngine::notifyPostSolvePre()
+{
+ PropEngine* pe = getPropEngine();
+ Assert(pe != nullptr);
+ pe->resetTrail();
+}
- // Push the formula to decision engine
- if (noConflict)
- {
- Chat() << "pushing to decision engine..." << endl;
- d_smt.d_propEngine->addAssertionsToDecisionEngine(d_assertions);
- }
+void SmtEngine::notifyPostSolvePost()
+{
+ TheoryEngine* te = getTheoryEngine();
+ Assert(te != nullptr);
+ te->postsolve();
+}
- // end: INVARIANT to maintain: no reordering of assertions or
- // introducing new ones
+Result SmtEngine::checkSat()
+{
+ Node nullNode;
+ return checkSat(nullNode);
+}
- // if incremental, compute which variables are assigned
- if (options::incrementalSolving())
+Result SmtEngine::checkSat(const Node& assumption, bool inUnsatCore)
+{
+ if (Dump.isOn("benchmark"))
{
- d_preprocessingPassContext->recordSymbolsInAssertions(d_assertions.ref());
+ getOutputManager().getPrinter().toStreamCmdCheckSat(
+ getOutputManager().getDumpOut(), assumption);
}
-
- // Push the formula to SAT
+ std::vector<Node> assump;
+ if (!assumption.isNull())
{
- Chat() << "converting to CNF..." << endl;
- TimerStat::CodeTimer codeTimer(d_smt.d_stats->d_cnfConversionTime);
- for (unsigned i = 0; i < d_assertions.size(); ++ i) {
- Chat() << "+ " << d_assertions[i] << std::endl;
- d_smt.d_propEngine->assertFormula(d_assertions[i]);
- }
+ assump.push_back(assumption);
}
-
- d_assertionsProcessed = true;
-
- d_assertions.clear();
- getIteSkolemMap().clear();
+ return checkSatInternal(assump, inUnsatCore, false);
}
-void SmtEnginePrivate::addFormula(
- TNode n, bool inUnsatCore, bool inInput, bool isAssumption, bool maybeHasFv)
+Result SmtEngine::checkSat(const std::vector<Node>& assumptions,
+ bool inUnsatCore)
{
- if (n == d_true) {
- // nothing to do
- return;
- }
-
- Trace("smt") << "SmtEnginePrivate::addFormula(" << n
- << "), inUnsatCore = " << inUnsatCore
- << ", inInput = " << inInput
- << ", isAssumption = " << isAssumption << endl;
-
- // Ensure that it does not contain free variables
- if (maybeHasFv)
+ if (Dump.isOn("benchmark"))
{
- if (expr::hasFreeVar(n))
+ if (assumptions.empty())
{
- std::stringstream se;
- se << "Cannot process assertion with free variable.";
- if (language::isInputLangSygus(options::inputLanguage()))
- {
- // Common misuse of SyGuS is to use top-level assert instead of
- // constraint when defining the synthesis conjecture.
- se << " Perhaps you meant `constraint` instead of `assert`?";
- }
- throw ModalException(se.str().c_str());
+ getOutputManager().getPrinter().toStreamCmdCheckSat(
+ getOutputManager().getDumpOut());
}
- }
-
- // Give it to proof manager
- PROOF(
- if( inInput ){
- // n is an input assertion
- if (inUnsatCore || options::unsatCores() || options::dumpUnsatCores() || options::checkUnsatCores() || options::fewerPreprocessingHoles()) {
-
- ProofManager::currentPM()->addCoreAssertion(n.toExpr());
- }
- }else{
- // n is the result of an unknown preprocessing step, add it to dependency map to null
- ProofManager::currentPM()->addDependence(n, Node::null());
+ else
+ {
+ getOutputManager().getPrinter().toStreamCmdCheckSatAssuming(
+ getOutputManager().getDumpOut(), assumptions);
}
- );
-
- // Add the normalized formula to the queue
- d_assertions.push_back(n, isAssumption);
- //d_assertions.push_back(Rewriter::rewrite(n));
-}
-
-void SmtEngine::ensureBoolean(const Node& n)
-{
- TypeNode type = n.getType(options::typeChecking());
- TypeNode boolType = NodeManager::currentNM()->booleanType();
- if(type != boolType) {
- stringstream ss;
- ss << "Expected " << boolType << "\n"
- << "The assertion : " << n << "\n"
- << "Its type : " << type;
- throw TypeCheckingException(n.toExpr(), ss.str());
}
+ return checkSatInternal(assumptions, inUnsatCore, false);
}
-Result SmtEngine::checkSat(const Expr& assumption, bool inUnsatCore)
+Result SmtEngine::checkEntailed(const Node& node, bool inUnsatCore)
{
- Dump("benchmark") << CheckSatCommand(assumption);
- return checkSatisfiability(assumption, inUnsatCore, false);
-}
-
-Result SmtEngine::checkSat(const vector<Expr>& assumptions, bool inUnsatCore)
-{
- if (assumptions.empty())
- {
- Dump("benchmark") << CheckSatCommand();
- }
- else
+ if (Dump.isOn("benchmark"))
{
- Dump("benchmark") << CheckSatAssumingCommand(assumptions);
+ getOutputManager().getPrinter().toStreamCmdQuery(
+ getOutputManager().getDumpOut(), node);
}
-
- return checkSatisfiability(assumptions, inUnsatCore, false);
-}
-
-Result SmtEngine::checkEntailed(const Expr& expr, bool inUnsatCore)
-{
- Dump("benchmark") << QueryCommand(expr, inUnsatCore);
- return checkSatisfiability(
- expr.isNull() ? std::vector<Expr>() : std::vector<Expr>{expr},
+ return checkSatInternal(
+ node.isNull() ? std::vector<Node>() : std::vector<Node>{node},
inUnsatCore,
true)
.asEntailmentResult();
}
-Result SmtEngine::checkEntailed(const vector<Expr>& exprs, bool inUnsatCore)
+Result SmtEngine::checkEntailed(const std::vector<Node>& nodes,
+ bool inUnsatCore)
{
- return checkSatisfiability(exprs, inUnsatCore, true).asEntailmentResult();
+ return checkSatInternal(nodes, inUnsatCore, true).asEntailmentResult();
}
-Result SmtEngine::checkSatisfiability(const Expr& expr,
- bool inUnsatCore,
- bool isEntailmentCheck)
-{
- return checkSatisfiability(
- expr.isNull() ? std::vector<Expr>() : std::vector<Expr>{expr},
- inUnsatCore,
- isEntailmentCheck);
-}
-
-Result SmtEngine::checkSatisfiability(const vector<Expr>& assumptions,
- bool inUnsatCore,
- bool isEntailmentCheck)
+Result SmtEngine::checkSatInternal(const std::vector<Node>& assumptions,
+ bool inUnsatCore,
+ bool isEntailmentCheck)
{
try
{
SmtScope smts(this);
- finalOptionsAreSet();
- doPendingPops();
+ finishInit();
Trace("smt") << "SmtEngine::"
<< (isEntailmentCheck ? "checkEntailed" : "checkSat") << "("
<< assumptions << ")" << endl;
-
- if(d_queryMade && !options::incrementalSolving()) {
- throw ModalException("Cannot make multiple queries unless "
- "incremental solving is enabled "
- "(try --incremental)");
- }
-
- // Note that a query has been made
- d_queryMade = true;
- // reset global negation
- d_globalNegation = false;
-
- bool didInternalPush = false;
-
- setProblemExtended();
-
- if (isEntailmentCheck)
- {
- size_t size = assumptions.size();
- if (size > 1)
- {
- /* Assume: not (BIGAND assumptions) */
- d_assumptions.push_back(
- d_exprManager->mkExpr(kind::AND, assumptions).notExpr());
- }
- else if (size == 1)
- {
- /* Assume: not expr */
- d_assumptions.push_back(assumptions[0].notExpr());
- }
- }
- else
- {
- /* Assume: BIGAND assumptions */
- d_assumptions = assumptions;
- }
-
- if (!d_assumptions.empty())
- {
- internalPush();
- didInternalPush = true;
- }
-
- Result r(Result::SAT_UNKNOWN, Result::UNKNOWN_REASON);
- for (Expr e : d_assumptions)
- {
- // Substitute out any abstract values in ex.
- Node n = d_private->substituteAbstractValues(Node::fromExpr(e));
- // Ensure expr is type-checked at this point.
- ensureBoolean(n);
-
- /* Add assumption */
- if (d_assertionList != NULL)
- {
- d_assertionList->push_back(n);
- }
- d_private->addFormula(n, inUnsatCore, true, true);
- }
-
- if (d_globalDefineFunRecLemmas != nullptr)
- {
- // Global definitions are asserted at check-sat-time because we have to
- // make sure that they are always present (they are essentially level
- // zero assertions)
- for (const Node& lemma : *d_globalDefineFunRecLemmas)
- {
- d_private->addFormula(lemma, false, true, false, false);
- }
- }
-
- r = check();
-
- if ((options::solveRealAsInt() || options::solveIntAsBV() > 0)
- && r.asSatisfiabilityResult().isSat() == Result::UNSAT)
- {
- r = Result(Result::SAT_UNKNOWN, Result::UNKNOWN_REASON);
- }
- // flipped if we did a global negation
- if (d_globalNegation)
- {
- Trace("smt") << "SmtEngine::process global negate " << r << std::endl;
- if (r.asSatisfiabilityResult().isSat() == Result::UNSAT)
- {
- r = Result(Result::SAT);
- }
- else if (r.asSatisfiabilityResult().isSat() == Result::SAT)
- {
- // only if satisfaction complete
- if (d_logic.isPure(THEORY_ARITH) || d_logic.isPure(THEORY_BV))
- {
- r = Result(Result::UNSAT);
- }
- else
- {
- r = Result(Result::SAT_UNKNOWN, Result::UNKNOWN_REASON);
- }
- }
- Trace("smt") << "SmtEngine::global negate returned " << r << std::endl;
- }
-
- d_needPostsolve = true;
-
- // Pop the context
- if (didInternalPush)
- {
- internalPop();
- }
-
- // Remember the status
- d_status = r;
- // Check against expected status
- if (!d_expectedStatus.isUnknown() && !d_status.isUnknown()
- && d_status != d_expectedStatus)
- {
- CVC4_FATAL() << "Expected result " << d_expectedStatus << " but got "
- << d_status;
- }
- d_expectedStatus = Result();
- // Update the SMT mode
- if (d_status.asSatisfiabilityResult().isSat() == Result::UNSAT)
- {
- d_smtMode = SMT_MODE_UNSAT;
- }
- else if (d_status.asSatisfiabilityResult().isSat() == Result::SAT)
- {
- d_smtMode = SMT_MODE_SAT;
- }
- else
- {
- d_smtMode = SMT_MODE_SAT_UNKNOWN;
- }
+ // check the satisfiability with the solver object
+ Result r = d_smtSolver->checkSatisfiability(
+ *d_asserts.get(), assumptions, inUnsatCore, isEntailmentCheck);
Trace("smt") << "SmtEngine::" << (isEntailmentCheck ? "query" : "checkSat")
<< "(" << assumptions << ") => " << r << endl;
@@ -1827,12 +970,6 @@ Result SmtEngine::checkSatisfiability(const vector<Expr>& assumptions,
checkModel();
}
}
- // Check that UNSAT results generate a proof correctly.
- if(options::checkProofs()) {
- if(r.asSatisfiabilityResult().isSat() == Result::UNSAT) {
- checkProof();
- }
- }
// Check that UNSAT results generate an unsat core correctly.
if(options::checkUnsatCores()) {
if(r.asSatisfiabilityResult().isSat() == Result::UNSAT) {
@@ -1844,14 +981,18 @@ Result SmtEngine::checkSatisfiability(const vector<Expr>& assumptions,
return r;
} catch (UnsafeInterruptException& e) {
AlwaysAssert(d_resourceManager->out());
+ // Notice that we do not notify the state of this result. If we wanted to
+ // make the solver resume a working state after an interupt, then we would
+ // implement a different callback and use it here, e.g.
+ // d_state.notifyCheckSatInterupt.
Result::UnknownExplanation why = d_resourceManager->outOfResources()
? Result::RESOURCEOUT
: Result::TIMEOUT;
- return Result(Result::SAT_UNKNOWN, why, d_filename);
+ return Result(Result::SAT_UNKNOWN, why, d_state->getFilename());
}
}
-vector<Expr> SmtEngine::getUnsatAssumptions(void)
+std::vector<Node> SmtEngine::getUnsatAssumptions(void)
{
Trace("smt") << "SMT getUnsatAssumptions()" << endl;
SmtScope smts(this);
@@ -1861,22 +1002,27 @@ vector<Expr> SmtEngine::getUnsatAssumptions(void)
"Cannot get unsat assumptions when produce-unsat-assumptions option "
"is off.");
}
- if (d_smtMode != SMT_MODE_UNSAT)
+ if (d_state->getMode() != SmtMode::UNSAT)
{
throw RecoverableModalException(
"Cannot get unsat assumptions unless immediately preceded by "
"UNSAT/ENTAILED.");
}
- finalOptionsAreSet();
+ finishInit();
if (Dump.isOn("benchmark"))
{
- Dump("benchmark") << GetUnsatAssumptionsCommand();
+ getOutputManager().getPrinter().toStreamCmdGetUnsatAssumptions(
+ getOutputManager().getDumpOut());
}
UnsatCore core = getUnsatCoreInternal();
- vector<Expr> res;
- for (const Expr& e : d_assumptions)
+ std::vector<Node> res;
+ std::vector<Node>& assumps = d_asserts->getAssumptions();
+ for (const Node& e : assumps)
{
- if (find(core.begin(), core.end(), e) != core.end()) { res.push_back(e); }
+ if (std::find(core.begin(), core.end(), e) != core.end())
+ {
+ res.push_back(e);
+ }
}
return res;
}
@@ -1884,24 +1030,20 @@ vector<Expr> SmtEngine::getUnsatAssumptions(void)
Result SmtEngine::assertFormula(const Node& formula, bool inUnsatCore)
{
SmtScope smts(this);
- finalOptionsAreSet();
- doPendingPops();
+ finishInit();
+ d_state->doPendingPops();
Trace("smt") << "SmtEngine::assertFormula(" << formula << ")" << endl;
if (Dump.isOn("raw-benchmark")) {
- Dump("raw-benchmark") << AssertCommand(formula.toExpr());
+ getOutputManager().getPrinter().toStreamCmdAssert(
+ getOutputManager().getDumpOut(), formula);
}
// Substitute out any abstract values in ex
- Node n = d_private->substituteAbstractValues(formula);
+ Node n = d_absValues->substituteAbstractValues(formula);
- ensureBoolean(n);
- if(d_assertionList != NULL) {
- d_assertionList->push_back(n);
- }
- bool maybeHasFv = language::isInputLangSygus(options::inputLanguage());
- d_private->addFormula(n, inUnsatCore, true, false, maybeHasFv);
+ d_asserts->assertFormula(n, inUnsatCore);
return quickCheck().asEntailmentResult();
}/* SmtEngine::assertFormula() */
@@ -1911,223 +1053,77 @@ Result SmtEngine::assertFormula(const Node& formula, bool inUnsatCore)
--------------------------------------------------------------------------
*/
-void SmtEngine::declareSygusVar(const std::string& id, Expr var, Type type)
-{
- SmtScope smts(this);
- finalOptionsAreSet();
- d_private->d_sygusVars.push_back(Node::fromExpr(var));
- Trace("smt") << "SmtEngine::declareSygusVar: " << var << "\n";
- Dump("raw-benchmark") << DeclareSygusVarCommand(id, var, type);
- // don't need to set that the conjecture is stale
-}
-
-void SmtEngine::declareSygusFunctionVar(const std::string& id,
- Expr var,
- Type type)
+void SmtEngine::declareSygusVar(const std::string& id, Node var, TypeNode type)
{
SmtScope smts(this);
- finalOptionsAreSet();
- d_private->d_sygusVars.push_back(Node::fromExpr(var));
- Trace("smt") << "SmtEngine::declareSygusFunctionVar: " << var << "\n";
- Dump("raw-benchmark") << DeclareSygusVarCommand(id, var, type);
-
+ d_sygusSolver->declareSygusVar(id, var, type);
+ if (Dump.isOn("raw-benchmark"))
+ {
+ getOutputManager().getPrinter().toStreamCmdDeclareVar(
+ getOutputManager().getDumpOut(), var, type);
+ }
// don't need to set that the conjecture is stale
}
void SmtEngine::declareSynthFun(const std::string& id,
- Expr func,
- Type sygusType,
+ Node func,
+ TypeNode sygusType,
bool isInv,
- const std::vector<Expr>& vars)
+ const std::vector<Node>& vars)
{
SmtScope smts(this);
- finalOptionsAreSet();
- doPendingPops();
- Node fn = Node::fromExpr(func);
- d_private->d_sygusFunSymbols.push_back(fn);
- if (!vars.empty())
- {
- Expr bvl = d_exprManager->mkExpr(kind::BOUND_VAR_LIST, vars);
- std::vector<Expr> attr_val_bvl;
- attr_val_bvl.push_back(bvl);
- setUserAttribute("sygus-synth-fun-var-list", func, attr_val_bvl, "");
- }
- // whether sygus type encodes syntax restrictions
- if (sygusType.isDatatype()
- && static_cast<DatatypeType>(sygusType).getDatatype().isSygus())
+ d_state->doPendingPops();
+ d_sygusSolver->declareSynthFun(id, func, sygusType, isInv, vars);
+
+ // !!! TEMPORARY: We cannot construct a SynthFunCommand since we cannot
+ // construct a Term-level Grammar from a Node-level sygus TypeNode. Thus we
+ // must print the command using the Node-level utility method for now.
+
+ if (Dump.isOn("raw-benchmark"))
{
- TypeNode stn = TypeNode::fromType(sygusType);
- Node sym = d_nodeManager->mkBoundVar("sfproxy", stn);
- std::vector<Expr> attr_value;
- attr_value.push_back(sym.toExpr());
- setUserAttribute("sygus-synth-grammar", func, attr_value, "");
+ getOutputManager().getPrinter().toStreamCmdSynthFun(
+ getOutputManager().getDumpOut(),
+ id,
+ vars,
+ func.getType().isFunction() ? func.getType().getRangeType()
+ : func.getType(),
+ isInv,
+ sygusType);
}
- Trace("smt") << "SmtEngine::declareSynthFun: " << func << "\n";
- Dump("raw-benchmark") << SynthFunCommand(id, func, sygusType, isInv, vars);
- // sygus conjecture is now stale
- setSygusConjectureStale();
}
-void SmtEngine::assertSygusConstraint(Expr constraint)
+void SmtEngine::assertSygusConstraint(Node constraint)
{
SmtScope smts(this);
- finalOptionsAreSet();
- d_private->d_sygusConstraints.push_back(constraint);
-
- Trace("smt") << "SmtEngine::assertSygusConstrant: " << constraint << "\n";
- Dump("raw-benchmark") << SygusConstraintCommand(constraint);
- // sygus conjecture is now stale
- setSygusConjectureStale();
+ finishInit();
+ d_sygusSolver->assertSygusConstraint(constraint);
+ if (Dump.isOn("raw-benchmark"))
+ {
+ getOutputManager().getPrinter().toStreamCmdConstraint(
+ getOutputManager().getDumpOut(), constraint);
+ }
}
-void SmtEngine::assertSygusInvConstraint(const Expr& inv,
- const Expr& pre,
- const Expr& trans,
- const Expr& post)
+void SmtEngine::assertSygusInvConstraint(Node inv,
+ Node pre,
+ Node trans,
+ Node post)
{
SmtScope smts(this);
- finalOptionsAreSet();
- // build invariant constraint
-
- // get variables (regular and their respective primed versions)
- std::vector<Node> terms, vars, primed_vars;
- terms.push_back(Node::fromExpr(inv));
- terms.push_back(Node::fromExpr(pre));
- terms.push_back(Node::fromExpr(trans));
- terms.push_back(Node::fromExpr(post));
- // variables are built based on the invariant type
- FunctionType t = static_cast<FunctionType>(inv.getType());
- std::vector<Type> argTypes = t.getArgTypes();
- for (const Type& ti : argTypes)
- {
- TypeNode tn = TypeNode::fromType(ti);
- vars.push_back(d_nodeManager->mkBoundVar(tn));
- d_private->d_sygusVars.push_back(vars.back());
- std::stringstream ss;
- ss << vars.back() << "'";
- primed_vars.push_back(d_nodeManager->mkBoundVar(ss.str(), tn));
- d_private->d_sygusVars.push_back(primed_vars.back());
- }
-
- // make relevant terms; 0 -> Inv, 1 -> Pre, 2 -> Trans, 3 -> Post
- for (unsigned i = 0; i < 4; ++i)
+ finishInit();
+ d_sygusSolver->assertSygusInvConstraint(inv, pre, trans, post);
+ if (Dump.isOn("raw-benchmark"))
{
- Node op = terms[i];
- Trace("smt-debug") << "Make inv-constraint term #" << i << " : " << op
- << " with type " << op.getType() << "...\n";
- std::vector<Node> children;
- children.push_back(op);
- // transition relation applied over both variable lists
- if (i == 2)
- {
- children.insert(children.end(), vars.begin(), vars.end());
- children.insert(children.end(), primed_vars.begin(), primed_vars.end());
- }
- else
- {
- children.insert(children.end(), vars.begin(), vars.end());
- }
- terms[i] = d_nodeManager->mkNode(kind::APPLY_UF, children);
- // make application of Inv on primed variables
- if (i == 0)
- {
- children.clear();
- children.push_back(op);
- children.insert(children.end(), primed_vars.begin(), primed_vars.end());
- terms.push_back(d_nodeManager->mkNode(kind::APPLY_UF, children));
- }
+ getOutputManager().getPrinter().toStreamCmdInvConstraint(
+ getOutputManager().getDumpOut(), inv, pre, trans, post);
}
- // make constraints
- std::vector<Node> conj;
- conj.push_back(d_nodeManager->mkNode(kind::IMPLIES, terms[1], terms[0]));
- Node term0_and_2 = d_nodeManager->mkNode(kind::AND, terms[0], terms[2]);
- conj.push_back(d_nodeManager->mkNode(kind::IMPLIES, term0_and_2, terms[4]));
- conj.push_back(d_nodeManager->mkNode(kind::IMPLIES, terms[0], terms[3]));
- Node constraint = d_nodeManager->mkNode(kind::AND, conj);
-
- d_private->d_sygusConstraints.push_back(constraint);
-
- Trace("smt") << "SmtEngine::assertSygusInvConstrant: " << constraint << "\n";
- Dump("raw-benchmark") << SygusInvConstraintCommand(inv, pre, trans, post);
- // sygus conjecture is now stale
- setSygusConjectureStale();
}
Result SmtEngine::checkSynth()
{
SmtScope smts(this);
-
- if (options::incrementalSolving())
- {
- // TODO (project #7)
- throw ModalException(
- "Cannot make check-synth commands when incremental solving is enabled");
- }
- Expr query;
- if (d_private->d_sygusConjectureStale)
- {
- // build synthesis conjecture from asserted constraints and declared
- // variables/functions
- Node sygusVar =
- d_nodeManager->mkSkolem("sygus", d_nodeManager->booleanType());
- Node inst_attr = d_nodeManager->mkNode(kind::INST_ATTRIBUTE, sygusVar);
- Node sygusAttr = d_nodeManager->mkNode(kind::INST_PATTERN_LIST, inst_attr);
- std::vector<Node> bodyv;
- Trace("smt") << "Sygus : Constructing sygus constraint...\n";
- unsigned n_constraints = d_private->d_sygusConstraints.size();
- Node body = n_constraints == 0
- ? d_nodeManager->mkConst(true)
- : (n_constraints == 1
- ? d_private->d_sygusConstraints[0]
- : d_nodeManager->mkNode(
- kind::AND, d_private->d_sygusConstraints));
- body = body.notNode();
- Trace("smt") << "...constructed sygus constraint " << body << std::endl;
- if (!d_private->d_sygusVars.empty())
- {
- Node boundVars =
- d_nodeManager->mkNode(kind::BOUND_VAR_LIST, d_private->d_sygusVars);
- body = d_nodeManager->mkNode(kind::EXISTS, boundVars, body);
- Trace("smt") << "...constructed exists " << body << std::endl;
- }
- if (!d_private->d_sygusFunSymbols.empty())
- {
- Node boundVars = d_nodeManager->mkNode(kind::BOUND_VAR_LIST,
- d_private->d_sygusFunSymbols);
- body = d_nodeManager->mkNode(kind::FORALL, boundVars, body, sygusAttr);
- }
- Trace("smt") << "...constructed forall " << body << std::endl;
-
- // set attribute for synthesis conjecture
- setUserAttribute("sygus", sygusVar.toExpr(), {}, "");
-
- Trace("smt") << "Check synthesis conjecture: " << body << std::endl;
- Dump("raw-benchmark") << CheckSynthCommand();
-
- d_private->d_sygusConjectureStale = false;
-
- if (options::incrementalSolving())
- {
- // we push a context so that this conjecture is removed if we modify it
- // later
- internalPush();
- assertFormula(body, true);
- }
- else
- {
- query = body.toExpr();
- }
- }
-
- Result r = checkSatisfiability(query, true, false);
-
- // Check that synthesis solutions satisfy the conjecture
- if (options::checkSynthSol()
- && r.asSatisfiabilityResult().isSat() == Result::UNSAT)
- {
- checkSynthSolution();
- }
- return r;
+ finishInit();
+ return d_sygusSolver->checkSynth(*d_asserts);
}
/*
@@ -2136,85 +1132,42 @@ Result SmtEngine::checkSynth()
--------------------------------------------------------------------------
*/
-Node SmtEngine::postprocess(TNode node, TypeNode expectedType) const {
- return node;
-}
-
-Expr SmtEngine::simplify(const Expr& ex)
+Node SmtEngine::simplify(const Node& ex)
{
- Assert(ex.getExprManager() == d_exprManager);
SmtScope smts(this);
- finalOptionsAreSet();
- doPendingPops();
- Trace("smt") << "SMT simplify(" << ex << ")" << endl;
-
- if(Dump.isOn("benchmark")) {
- Dump("benchmark") << SimplifyCommand(ex);
- }
-
- Expr e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
- if( options::typeChecking() ) {
- e.getType(true); // ensure expr is type-checked at this point
- }
-
- // Make sure all preprocessing is done
- d_private->processAssertions();
- Node n = d_private->simplify(Node::fromExpr(e));
- n = postprocess(n, TypeNode::fromType(e.getType()));
- return n.toExpr();
+ finishInit();
+ d_state->doPendingPops();
+ // ensure we've processed assertions
+ d_smtSolver->processAssertions(*d_asserts);
+ return d_pp->simplify(ex);
}
Node SmtEngine::expandDefinitions(const Node& ex)
{
- d_private->spendResource(ResourceManager::Resource::PreprocessStep);
+ d_resourceManager->spendResource(ResourceManager::Resource::PreprocessStep);
SmtScope smts(this);
- finalOptionsAreSet();
- doPendingPops();
- Trace("smt") << "SMT expandDefinitions(" << ex << ")" << endl;
-
- // Substitute out any abstract values in ex.
- Node e = d_private->substituteAbstractValues(ex);
- if(options::typeChecking()) {
- // Ensure expr is type-checked at this point.
- e.getType(true);
- }
-
- unordered_map<Node, Node, NodeHashFunction> cache;
- Node n = d_private->getProcessAssertions()->expandDefinitions(
- e, cache, /* expandOnly = */ true);
- n = postprocess(n, e.getType());
-
- return n;
+ finishInit();
+ d_state->doPendingPops();
+ // set expandOnly flag to true
+ return d_pp->expandDefinitions(ex, true);
}
// TODO(#1108): Simplify the error reporting of this method.
-Expr SmtEngine::getValue(const Expr& ex) const
+Node SmtEngine::getValue(const Node& ex) const
{
- Assert(ex.getExprManager() == d_exprManager);
SmtScope smts(this);
Trace("smt") << "SMT getValue(" << ex << ")" << endl;
if(Dump.isOn("benchmark")) {
- Dump("benchmark") << GetValueCommand(ex);
+ d_outMgr.getPrinter().toStreamCmdGetValue(d_outMgr.getDumpOut(), {ex});
}
+ TypeNode expectedType = ex.getType();
- // Substitute out any abstract values in ex.
- Expr e = d_private->substituteAbstractValues(Node::fromExpr(ex)).toExpr();
-
- // Ensure expr is type-checked at this point.
- e.getType(options::typeChecking());
+ // Substitute out any abstract values in ex and expand
+ Node n = d_pp->expandDefinitions(ex);
- // do not need to apply preprocessing substitutions (should be recorded
- // in model already)
-
- Node n = Node::fromExpr(e);
Trace("smt") << "--- getting value of " << n << endl;
- TypeNode expectedType = n.getType();
-
- // Expand, then normalize
- unordered_map<Node, Node, NodeHashFunction> cache;
- n = d_private->getProcessAssertions()->expandDefinitions(n, cache);
// There are two ways model values for terms are computed (for historical
// reasons). One way is that used in check-model; the other is that
// used by the Model classes. It's not clear to me exactly how these
@@ -2227,16 +1180,12 @@ Expr SmtEngine::getValue(const Expr& ex) const
}
Trace("smt") << "--- getting value of " << n << endl;
- TheoryModel* m = getAvailableModel("get-value");
- Node resultNode;
- if(m != NULL) {
- resultNode = m->getValue(n);
- }
+ Model* m = getAvailableModel("get-value");
+ Assert(m != nullptr);
+ Node resultNode = m->getValue(n);
Trace("smt") << "--- got value " << n << " = " << resultNode << endl;
- resultNode = postprocess(resultNode, expectedType);
- Trace("smt") << "--- model-post returned " << resultNode << endl;
- Trace("smt") << "--- model-post returned " << resultNode.getType() << endl;
- Trace("smt") << "--- model-post expected " << expectedType << endl;
+ Trace("smt") << "--- type " << resultNode.getType() << endl;
+ Trace("smt") << "--- expected type " << expectedType << endl;
// type-check the result we got
// Notice that lambdas have function type, which does not respect the subtype
@@ -2251,171 +1200,56 @@ Expr SmtEngine::getValue(const Expr& ex) const
|| resultNode.isConst());
if(options::abstractValues() && resultNode.getType().isArray()) {
- resultNode = d_private->mkAbstractValue(resultNode);
+ resultNode = d_absValues->mkAbstractValue(resultNode);
Trace("smt") << "--- abstract value >> " << resultNode << endl;
}
- return resultNode.toExpr();
+ return resultNode;
}
-vector<Expr> SmtEngine::getValues(const vector<Expr>& exprs)
+std::vector<Node> SmtEngine::getValues(const std::vector<Node>& exprs)
{
- vector<Expr> result;
- for (const Expr& e : exprs)
+ std::vector<Node> result;
+ for (const Node& e : exprs)
{
result.push_back(getValue(e));
}
return result;
}
-bool SmtEngine::addToAssignment(const Expr& ex) {
- SmtScope smts(this);
- finalOptionsAreSet();
- doPendingPops();
- // Substitute out any abstract values in ex
- Node n = d_private->substituteAbstractValues(Node::fromExpr(ex));
- TypeNode type = n.getType(options::typeChecking());
- // must be Boolean
- PrettyCheckArgument(type.isBoolean(),
- n,
- "expected Boolean-typed variable or function application "
- "in addToAssignment()");
- // must be a defined constant, or a variable
- PrettyCheckArgument(
- (((d_definedFunctions->find(n) != d_definedFunctions->end())
- && n.getNumChildren() == 0)
- || n.isVar()),
- n,
- "expected variable or defined-function application "
- "in addToAssignment(),\ngot %s",
- n.toString().c_str());
- if(!options::produceAssignments()) {
- return false;
- }
- if(d_assignments == NULL) {
- d_assignments = new (true) AssignmentSet(getContext());
- }
- d_assignments->insert(n);
-
- return true;
-}
-
-// TODO(#1108): Simplify the error reporting of this method.
-vector<pair<Expr, Expr>> SmtEngine::getAssignment()
-{
- Trace("smt") << "SMT getAssignment()" << endl;
- SmtScope smts(this);
- finalOptionsAreSet();
- if(Dump.isOn("benchmark")) {
- Dump("benchmark") << GetAssignmentCommand();
- }
- if(!options::produceAssignments()) {
- const char* msg =
- "Cannot get the current assignment when "
- "produce-assignments option is off.";
- throw ModalException(msg);
- }
-
- // Get the model here, regardless of whether d_assignments is null, since
- // we should throw errors related to model availability whether or not
- // assignments is null.
- TheoryModel* m = getAvailableModel("get assignment");
-
- vector<pair<Expr,Expr>> res;
- if (d_assignments != nullptr)
- {
- TypeNode boolType = d_nodeManager->booleanType();
- for (AssignmentSet::key_iterator i = d_assignments->key_begin(),
- iend = d_assignments->key_end();
- i != iend;
- ++i)
- {
- Node as = *i;
- Assert(as.getType() == boolType);
-
- Trace("smt") << "--- getting value of " << as << endl;
-
- // Expand, then normalize
- unordered_map<Node, Node, NodeHashFunction> cache;
- Node n = d_private->getProcessAssertions()->expandDefinitions(as, cache);
- n = Rewriter::rewrite(n);
-
- Trace("smt") << "--- getting value of " << n << endl;
- Node resultNode;
- if (m != nullptr)
- {
- resultNode = m->getValue(n);
- }
-
- // type-check the result we got
- Assert(resultNode.isNull() || resultNode.getType() == boolType);
-
- // ensure it's a constant
- Assert(resultNode.isConst());
-
- Assert(as.isVar());
- res.emplace_back(as.toExpr(), resultNode.toExpr());
- }
- }
- return res;
-}
-
-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
- // produce-models. So let's keep any commands around just in
- // case. This is useful in two cases: (1) SMT-LIBv1 auto-declares
- // sort "U" in QF_UF before setLogic() is run and we still want to
- // support finding card(U) with --finite-model-find, and (2) to
- // decouple SmtEngine and ExprManager if the user does a few
- // ExprManager::mkSort() before SmtEngine::setOption("produce-models")
- // and expects to find their cardinalities in the model.
- if(/* userVisible && */
- (!d_fullyInited || options::produceModels()) &&
- (flags & ExprManager::VAR_FLAG_DEFINED) == 0) {
- if(flags & ExprManager::VAR_FLAG_GLOBAL) {
- d_modelGlobalCommands.push_back(c.clone());
- } else {
- d_modelCommands->push_back(c.clone());
- }
- }
- if(Dump.isOn(dumpTag)) {
- if(d_fullyInited) {
- Dump(dumpTag) << c;
- } else {
- d_dumpCommands.push_back(c.clone());
- }
- }
-}
-
// TODO(#1108): Simplify the error reporting of this method.
Model* SmtEngine::getModel() {
Trace("smt") << "SMT getModel()" << endl;
SmtScope smts(this);
- finalOptionsAreSet();
+ finishInit();
if(Dump.isOn("benchmark")) {
- Dump("benchmark") << GetModelCommand();
+ getOutputManager().getPrinter().toStreamCmdGetModel(
+ getOutputManager().getDumpOut());
}
- TheoryModel* m = getAvailableModel("get model");
+ Model* m = getAvailableModel("get model");
// Since model m is being returned to the user, we must ensure that this
// model object remains valid with future check-sat calls. Hence, we set
// the theory engine into "eager model building" mode. TODO #2648: revisit.
- d_theoryEngine->setEagerModelBuilding();
+ TheoryEngine* te = getTheoryEngine();
+ Assert(te != nullptr);
+ te->setEagerModelBuilding();
if (options::modelCoresMode() != options::ModelCoresMode::NONE)
{
// If we enabled model cores, we compute a model core for m based on our
// (expanded) assertions using the model core builder utility
- std::vector<Expr> eassertsProc = getExpandedAssertions();
- ModelCoreBuilder::setModelCore(eassertsProc, m, options::modelCoresMode());
- }
- m->d_inputName = d_filename;
- m->d_isKnownSat = (d_smtMode == SMT_MODE_SAT);
+ std::vector<Node> eassertsProc = getExpandedAssertions();
+ ModelCoreBuilder::setModelCore(
+ eassertsProc, m->getTheoryModel(), options::modelCoresMode());
+ }
+ // set the information on the SMT-level model
+ Assert(m != nullptr);
+ m->d_inputName = d_state->getFilename();
+ m->d_isKnownSat = (d_state->getMode() == SmtMode::SAT);
return m;
}
@@ -2424,55 +1258,57 @@ Result SmtEngine::blockModel()
Trace("smt") << "SMT blockModel()" << endl;
SmtScope smts(this);
- finalOptionsAreSet();
+ finishInit();
if (Dump.isOn("benchmark"))
{
- Dump("benchmark") << BlockModelCommand();
+ getOutputManager().getPrinter().toStreamCmdBlockModel(
+ getOutputManager().getDumpOut());
}
- TheoryModel* m = getAvailableModel("block model");
+ Model* m = getAvailableModel("block model");
if (options::blockModelsMode() == options::BlockModelsMode::NONE)
{
std::stringstream ss;
ss << "Cannot block model when block-models is set to none.";
- throw ModalException(ss.str().c_str());
+ throw RecoverableModalException(ss.str().c_str());
}
// get expanded assertions
- std::vector<Expr> eassertsProc = getExpandedAssertions();
- Expr eblocker = ModelBlocker::getModelBlocker(
- eassertsProc, m, options::blockModelsMode());
- return assertFormula(Node::fromExpr(eblocker));
+ std::vector<Node> eassertsProc = getExpandedAssertions();
+ Node eblocker = ModelBlocker::getModelBlocker(
+ eassertsProc, m->getTheoryModel(), options::blockModelsMode());
+ return assertFormula(eblocker);
}
-Result SmtEngine::blockModelValues(const std::vector<Expr>& exprs)
+Result SmtEngine::blockModelValues(const std::vector<Node>& exprs)
{
Trace("smt") << "SMT blockModelValues()" << endl;
SmtScope smts(this);
- finalOptionsAreSet();
+ finishInit();
- PrettyCheckArgument(
- !exprs.empty(),
- "block model values must be called on non-empty set of terms");
if (Dump.isOn("benchmark"))
{
- Dump("benchmark") << BlockModelValuesCommand(exprs);
+ getOutputManager().getPrinter().toStreamCmdBlockModelValues(
+ getOutputManager().getDumpOut(), exprs);
}
- TheoryModel* m = getAvailableModel("block model values");
+ Model* m = getAvailableModel("block model values");
// get expanded assertions
- std::vector<Expr> eassertsProc = getExpandedAssertions();
+ std::vector<Node> eassertsProc = getExpandedAssertions();
// we always do block model values mode here
- Expr eblocker = ModelBlocker::getModelBlocker(
- eassertsProc, m, options::BlockModelsMode::VALUES, exprs);
- return assertFormula(Node::fromExpr(eblocker));
+ Node eblocker =
+ ModelBlocker::getModelBlocker(eassertsProc,
+ m->getTheoryModel(),
+ options::BlockModelsMode::VALUES,
+ exprs);
+ return assertFormula(eblocker);
}
-std::pair<Expr, Expr> SmtEngine::getSepHeapAndNilExpr(void)
+std::pair<Node, Node> SmtEngine::getSepHeapAndNilExpr(void)
{
if (!d_logic.isTheoryEnabled(THEORY_SEP))
{
@@ -2482,74 +1318,60 @@ std::pair<Expr, Expr> SmtEngine::getSepHeapAndNilExpr(void)
throw RecoverableModalException(msg);
}
NodeManagerScope nms(d_nodeManager);
- Expr heap;
- Expr nil;
+ Node heap;
+ Node nil;
Model* m = getAvailableModel("get separation logic heap and nil");
- if (!m->getHeapModel(heap, nil))
+ TheoryModel* tm = m->getTheoryModel();
+ if (!tm->getHeapModel(heap, nil))
{
- InternalError()
- << "SmtEngine::getSepHeapAndNilExpr(): failed to obtain heap/nil "
- "expressions from theory model.";
+ const char* msg =
+ "Failed to obtain heap/nil "
+ "expressions from theory model.";
+ throw RecoverableModalException(msg);
}
return std::make_pair(heap, nil);
}
-std::vector<Expr> SmtEngine::getExpandedAssertions()
+std::vector<Node> SmtEngine::getExpandedAssertions()
{
- std::vector<Expr> easserts = getAssertions();
+ std::vector<Node> easserts = getAssertions();
// must expand definitions
- std::vector<Expr> eassertsProc;
+ std::vector<Node> eassertsProc;
std::unordered_map<Node, Node, NodeHashFunction> cache;
- for (const Expr& e : easserts)
+ for (const Node& e : easserts)
{
- Node ea = Node::fromExpr(e);
- Node eae = d_private->getProcessAssertions()->expandDefinitions(ea, cache);
- eassertsProc.push_back(eae.toExpr());
+ Node eae = d_pp->expandDefinitions(e, cache);
+ eassertsProc.push_back(eae);
}
return eassertsProc;
}
-Expr SmtEngine::getSepHeapExpr() { return getSepHeapAndNilExpr().first; }
-
-Expr SmtEngine::getSepNilExpr() { return getSepHeapAndNilExpr().second; }
-
-void SmtEngine::checkProof()
+void SmtEngine::declareSepHeap(TypeNode locT, TypeNode dataT)
{
-#if (IS_LFSC_BUILD && IS_PROOFS_BUILD)
-
- Chat() << "generating proof..." << endl;
-
- const Proof& pf = getProof();
-
- Chat() << "checking proof..." << endl;
-
- std::string logicString = d_logic.getLogicString();
-
- std::stringstream pfStream;
-
- pfStream << proof::plf_signatures << endl;
- int64_t sizeBeforeProof = static_cast<int64_t>(pfStream.tellp());
-
- pf.toStream(pfStream);
- d_stats->d_proofsSize +=
- static_cast<int64_t>(pfStream.tellp()) - sizeBeforeProof;
-
+ if (!d_logic.isTheoryEnabled(THEORY_SEP))
{
- TimerStat::CodeTimer checkProofTimer(d_stats->d_lfscCheckProofTime);
- lfscc_init();
- lfscc_check_file(pfStream, false, false, false, false, false, false, false);
+ const char* msg =
+ "Cannot declare heap if not using the separation logic theory.";
+ throw RecoverableModalException(msg);
}
- // FIXME: we should actually call lfscc_cleanup here, but lfscc_cleanup
- // segfaults on regress0/bv/core/bitvec7.smt
- // lfscc_cleanup();
+ SmtScope smts(this);
+ finishInit();
+ TheoryEngine* te = getTheoryEngine();
+ te->declareSepHeap(locT, dataT);
+}
-#else /* (IS_LFSC_BUILD && IS_PROOFS_BUILD) */
- Unreachable()
- << "This version of CVC4 was built without proof support; cannot check "
- "proofs.";
-#endif /* (IS_LFSC_BUILD && IS_PROOFS_BUILD) */
+bool SmtEngine::getSepHeapTypes(TypeNode& locT, TypeNode& dataT)
+{
+ SmtScope smts(this);
+ finishInit();
+ TheoryEngine* te = getTheoryEngine();
+ return te->getSepHeapTypes(locT, dataT);
}
+Node SmtEngine::getSepHeapExpr() { return getSepHeapAndNilExpr().first; }
+
+Node SmtEngine::getSepNilExpr() { return getSepHeapAndNilExpr().second; }
+
UnsatCore SmtEngine::getUnsatCoreInternal()
{
#if IS_PROOFS_BUILD
@@ -2558,7 +1380,7 @@ UnsatCore SmtEngine::getUnsatCoreInternal()
throw ModalException(
"Cannot get an unsat core when produce-unsat-cores option is off.");
}
- if (d_smtMode != SMT_MODE_UNSAT)
+ if (d_state->getMode() != SmtMode::UNSAT)
{
throw RecoverableModalException(
"Cannot get an unsat core unless immediately preceded by "
@@ -2566,7 +1388,7 @@ UnsatCore SmtEngine::getUnsatCoreInternal()
}
d_proofManager->traceUnsatCore(); // just to trigger core creation
- return UnsatCore(this, d_proofManager->extractUnsatCore());
+ return UnsatCore(d_proofManager->extractUnsatCore());
#else /* IS_PROOFS_BUILD */
throw ModalException(
"This build of CVC4 doesn't have proof support (required for unsat "
@@ -2581,27 +1403,29 @@ void SmtEngine::checkUnsatCore() {
Notice() << "SmtEngine::checkUnsatCore(): generating unsat core" << endl;
UnsatCore core = getUnsatCore();
- SmtEngine coreChecker(d_exprManager, &d_options);
- coreChecker.setIsInternalSubsolver();
- coreChecker.setLogic(getLogicInfo());
- coreChecker.getOptions().set(options::checkUnsatCores, false);
- coreChecker.getOptions().set(options::checkProofs, false);
+ // initialize the core checker
+ std::unique_ptr<SmtEngine> coreChecker;
+ initializeSubsolver(coreChecker);
+ coreChecker->getOptions().set(options::checkUnsatCores, false);
- PROOF(
- std::vector<Command*>::const_iterator itg = d_defineCommands.begin();
- for (; itg != d_defineCommands.end(); ++itg) {
- (*itg)->invoke(&coreChecker);
+ // set up separation logic heap if necessary
+ TypeNode sepLocType, sepDataType;
+ if (getSepHeapTypes(sepLocType, sepDataType))
+ {
+ coreChecker->declareSepHeap(sepLocType, sepDataType);
}
- );
- Notice() << "SmtEngine::checkUnsatCore(): pushing core assertions (size == " << core.size() << ")" << endl;
+ Notice() << "SmtEngine::checkUnsatCore(): pushing core assertions"
+ << std::endl;
for(UnsatCore::iterator i = core.begin(); i != core.end(); ++i) {
- Notice() << "SmtEngine::checkUnsatCore(): pushing core member " << *i << endl;
- coreChecker.assertFormula(Node::fromExpr(*i));
+ Node assertionAfterExpansion = expandDefinitions(*i);
+ Notice() << "SmtEngine::checkUnsatCore(): pushing core member " << *i
+ << ", expanded to " << assertionAfterExpansion << "\n";
+ coreChecker->assertFormula(assertionAfterExpansion);
}
Result r;
try {
- r = coreChecker.checkSat();
+ r = coreChecker->checkSat();
} catch(...) {
throw;
}
@@ -2619,543 +1443,93 @@ void SmtEngine::checkUnsatCore() {
}
void SmtEngine::checkModel(bool hardFailure) {
+ context::CDList<Node>* al = d_asserts->getAssertionList();
// --check-model implies --produce-assertions, which enables the
// assertion list, so we should be ok.
- Assert(d_assertionList != NULL)
+ Assert(al != nullptr)
<< "don't have an assertion list to check in SmtEngine::checkModel()";
TimerStat::CodeTimer checkModelTimer(d_stats->d_checkModelTime);
- // Throughout, we use Notice() to give diagnostic output.
- //
- // If this function is running, the user gave --check-model (or equivalent),
- // and if Notice() is on, the user gave --verbose (or equivalent).
-
Notice() << "SmtEngine::checkModel(): generating model" << endl;
- TheoryModel* m = getAvailableModel("check model");
-
- // check-model is not guaranteed to succeed if approximate values were used.
- // Thus, we intentionally abort here.
- if (m->hasApproximations())
- {
- throw RecoverableModalException(
- "Cannot run check-model on a model with approximate values.");
- }
-
- // Check individual theory assertions
- if (options::debugCheckModels())
- {
- d_theoryEngine->checkTheoryAssertionsWithModel(hardFailure);
- }
-
- // Output the model
- Notice() << *m;
-
- // We have a "fake context" for the substitution map (we don't need it
- // to be context-dependent)
- context::Context fakeContext;
- SubstitutionMap substitutions(&fakeContext, /* substituteUnderQuantifiers = */ false);
-
- for(size_t k = 0; k < m->getNumCommands(); ++k) {
- const DeclareFunctionCommand* c = dynamic_cast<const DeclareFunctionCommand*>(m->getCommand(k));
- Notice() << "SmtEngine::checkModel(): model command " << k << " : " << m->getCommand(k) << endl;
- if(c == NULL) {
- // we don't care about DECLARE-DATATYPES, DECLARE-SORT, ...
- Notice() << "SmtEngine::checkModel(): skipping..." << endl;
- } else {
- // We have a DECLARE-FUN:
- //
- // We'll first do some checks, then add to our substitution map
- // the mapping: function symbol |-> value
-
- Expr func = c->getFunction();
- Node val = m->getValue(func);
-
- Notice() << "SmtEngine::checkModel(): adding substitution: " << func << " |-> " << val << endl;
-
- // (1) if the value is a lambda, ensure the lambda doesn't contain the
- // function symbol (since then the definition is recursive)
- if (val.getKind() == kind::LAMBDA) {
- // first apply the model substitutions we have so far
- Debug("boolean-terms") << "applying subses to " << val[1] << endl;
- Node n = substitutions.apply(val[1]);
- Debug("boolean-terms") << "++ got " << n << endl;
- // now check if n contains func by doing a substitution
- // [func->func2] and checking equality of the Nodes.
- // (this just a way to check if func is in n.)
- SubstitutionMap subs(&fakeContext);
- Node func2 = NodeManager::currentNM()->mkSkolem("", TypeNode::fromType(func.getType()), "", NodeManager::SKOLEM_NO_NOTIFY);
- subs.addSubstitution(func, func2);
- if(subs.apply(n) != n) {
- Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE DEFINED IN TERMS OF ITSELF ***" << endl;
- stringstream ss;
- ss << "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
- << "considering model value for " << func << endl
- << "body of lambda is: " << val << endl;
- if(n != val[1]) {
- ss << "body substitutes to: " << n << endl;
- }
- ss << "so " << func << " is defined in terms of itself." << endl
- << "Run with `--check-models -v' for additional diagnostics.";
- InternalError() << ss.str();
- }
- }
-
- // (2) check that the value is actually a value
- else if (!val.isConst())
- {
- // This is only a warning since it could have been assigned an
- // unevaluable term (e.g. an application of a transcendental function).
- // This parallels the behavior (warnings for non-constant expressions)
- // when checking whether assertions are satisfied below.
- Warning() << "Warning : SmtEngine::checkModel(): "
- << "model value for " << func << endl
- << " is " << val << endl
- << "and that is not a constant (.isConst() == false)."
- << std::endl
- << "Run with `--check-models -v' for additional diagnostics."
- << std::endl;
- }
-
- // (3) check that it's the correct (sub)type
- // This was intended to be a more general check, but for now we can't do that because
- // e.g. "1" is an INT, which isn't a subrange type [1..10] (etc.).
- else if(func.getType().isInteger() && !val.getType().isInteger()) {
- Notice() << "SmtEngine::checkModel(): *** PROBLEM: MODEL VALUE NOT CORRECT TYPE ***" << endl;
- InternalError()
- << "SmtEngine::checkModel(): ERRORS SATISFYING ASSERTIONS WITH "
- "MODEL:"
- << endl
- << "model value for " << func << endl
- << " is " << val << endl
- << "value type is " << val.getType() << endl
- << "should be of type " << func.getType() << endl
- << "Run with `--check-models -v' for additional diagnostics.";
- }
-
- // (4) checks complete, add the substitution
- Debug("boolean-terms") << "cm: adding subs " << func << " :=> " << val << endl;
- substitutions.addSubstitution(func, val);
- }
- }
-
- // Now go through all our user assertions checking if they're satisfied.
- for (const Node& assertion : *d_assertionList)
- {
- Notice() << "SmtEngine::checkModel(): checking assertion " << assertion
- << endl;
- Node n = assertion;
-
- // Apply any define-funs from the problem.
- {
- unordered_map<Node, Node, NodeHashFunction> cache;
- n = d_private->getProcessAssertions()->expandDefinitions(n, cache);
- }
- Notice() << "SmtEngine::checkModel(): -- expands to " << n << endl;
-
- // Apply our model value substitutions.
- Debug("boolean-terms") << "applying subses to " << n << endl;
- n = substitutions.apply(n);
- Debug("boolean-terms") << "++ got " << n << endl;
- Notice() << "SmtEngine::checkModel(): -- substitutes to " << n << endl;
-
- // We look up the value before simplifying. If n contains quantifiers,
- // this may increases the chance of finding its value before the node is
- // altered by simplification below.
- n = m->getValue(n);
- Notice() << "SmtEngine::checkModel(): -- get value : " << n << std::endl;
-
- // Simplify the result.
- n = d_private->simplify(n);
- Notice() << "SmtEngine::checkModel(): -- simplifies to " << n << endl;
-
- // Replace the already-known ITEs (this is important for ground ITEs under quantifiers).
- n = d_private->d_iteRemover.replace(n);
- Notice() << "SmtEngine::checkModel(): -- ite replacement gives " << n << endl;
-
- // Apply our model value substitutions (again), as things may have been simplified.
- Debug("boolean-terms") << "applying subses to " << n << endl;
- n = substitutions.apply(n);
- Debug("boolean-terms") << "++ got " << n << endl;
- Notice() << "SmtEngine::checkModel(): -- re-substitutes to " << n << endl;
-
- // As a last-ditch effort, ask model to simplify it.
- // Presently, this is only an issue for quantifiers, which can have a value
- // but don't show up in our substitution map above.
- n = m->getValue(n);
- Notice() << "SmtEngine::checkModel(): -- model-substitutes to " << n << endl;
-
- if (n.isConst())
- {
- if (n.getConst<bool>())
- {
- // assertion is true, everything is fine
- continue;
- }
- }
-
- // Otherwise, we did not succeed in showing the current assertion to be
- // true. This may either indicate that our model is wrong, or that we cannot
- // check it. The latter may be the case for several reasons.
- // For example, quantified formulas are not checkable, although we assign
- // them to true/false based on the satisfying assignment. However,
- // quantified formulas can be modified during preprocess, so they may not
- // correspond to those in the satisfying assignment. Hence we throw
- // warnings for assertions that do not simplify to either true or false.
- // Other theories such as non-linear arithmetic (in particular,
- // transcendental functions) also have the property of not being able to
- // be checked precisely here.
- // Note that warnings like these can be avoided for quantified formulas
- // by making preprocessing passes explicitly record how they
- // rewrite quantified formulas (see cvc4-wishues#43).
- if (!n.isConst())
- {
- // Not constant, print a less severe warning message here.
- Warning() << "Warning : SmtEngine::checkModel(): cannot check simplified "
- "assertion : "
- << n << endl;
- continue;
- }
- // Assertions that simplify to false result in an InternalError or
- // Warning being thrown below (when hardFailure is false).
- Notice() << "SmtEngine::checkModel(): *** PROBLEM: EXPECTED `TRUE' ***"
- << endl;
- stringstream ss;
- ss << "SmtEngine::checkModel(): "
- << "ERRORS SATISFYING ASSERTIONS WITH MODEL:" << endl
- << "assertion: " << assertion << endl
- << "simplifies to: " << n << endl
- << "expected `true'." << endl
- << "Run with `--check-models -v' for additional diagnostics.";
- if (hardFailure)
- {
- // internal error if hardFailure is true
- InternalError() << ss.str();
- }
- else
- {
- Warning() << ss.str() << endl;
- }
- }
- Notice() << "SmtEngine::checkModel(): all assertions checked out OK !" << endl;
-}
-
-void SmtEngine::checkSynthSolution()
-{
- NodeManager* nm = NodeManager::currentNM();
- Notice() << "SmtEngine::checkSynthSolution(): checking synthesis solution" << endl;
- std::map<Node, std::map<Node, Node>> sol_map;
- /* Get solutions and build auxiliary vectors for substituting */
- if (!d_theoryEngine->getSynthSolutions(sol_map))
- {
- InternalError() << "SmtEngine::checkSynthSolution(): No solution to check!";
- return;
- }
- if (sol_map.empty())
- {
- InternalError() << "SmtEngine::checkSynthSolution(): Got empty solution!";
- return;
- }
- Trace("check-synth-sol") << "Got solution map:\n";
- // the set of synthesis conjectures in our assertions
- std::unordered_set<Node, NodeHashFunction> conjs;
- // For each of the above conjectures, the functions-to-synthesis and their
- // solutions. This is used as a substitution below.
- std::map<Node, std::vector<Node>> fvarMap;
- std::map<Node, std::vector<Node>> fsolMap;
- for (const std::pair<const Node, std::map<Node, Node>>& cmap : sol_map)
- {
- Trace("check-synth-sol") << "For conjecture " << cmap.first << ":\n";
- conjs.insert(cmap.first);
- std::vector<Node>& fvars = fvarMap[cmap.first];
- std::vector<Node>& fsols = fsolMap[cmap.first];
- for (const std::pair<const Node, Node>& pair : cmap.second)
- {
- Trace("check-synth-sol")
- << " " << pair.first << " --> " << pair.second << "\n";
- fvars.push_back(pair.first);
- fsols.push_back(pair.second);
- }
- }
- Trace("check-synth-sol") << "Starting new SMT Engine\n";
- /* Start new SMT engine to check solutions */
- SmtEngine solChecker(d_exprManager, &d_options);
- solChecker.setIsInternalSubsolver();
- solChecker.setLogic(getLogicInfo());
- solChecker.getOptions().set(options::checkSynthSol, false);
- solChecker.getOptions().set(options::sygusRecFun, false);
+ Model* m = getAvailableModel("check model");
+ Assert(m != nullptr);
- Trace("check-synth-sol") << "Retrieving assertions\n";
- // Build conjecture from original assertions
- if (d_assertionList == NULL)
- {
- Trace("check-synth-sol") << "No assertions to check\n";
- return;
- }
- // auxiliary assertions
- std::vector<Node> auxAssertions;
- // expand definitions cache
- std::unordered_map<Node, Node, NodeHashFunction> cache;
- for (const Node& assertion : *d_assertionList)
- {
- Notice() << "SmtEngine::checkSynthSolution(): checking assertion "
- << assertion << endl;
- Trace("check-synth-sol") << "Retrieving assertion " << assertion << "\n";
- // Apply any define-funs from the problem.
- Node n =
- d_private->getProcessAssertions()->expandDefinitions(assertion, cache);
- Notice() << "SmtEngine::checkSynthSolution(): -- expands to " << n << endl;
- Trace("check-synth-sol") << "Expanded assertion " << n << "\n";
- if (conjs.find(n) == conjs.end())
- {
- Trace("check-synth-sol") << "It is an auxiliary assertion\n";
- auxAssertions.push_back(n);
- }
- else
- {
- Trace("check-synth-sol") << "It is a synthesis conjecture\n";
- }
- }
- // check all conjectures
- for (const Node& conj : conjs)
- {
- // get the solution for this conjecture
- std::vector<Node>& fvars = fvarMap[conj];
- std::vector<Node>& fsols = fsolMap[conj];
- // Apply solution map to conjecture body
- Node conjBody;
- /* Whether property is quantifier free */
- if (conj[1].getKind() != kind::EXISTS)
- {
- conjBody = conj[1].substitute(
- fvars.begin(), fvars.end(), fsols.begin(), fsols.end());
- }
- else
- {
- conjBody = conj[1][1].substitute(
- fvars.begin(), fvars.end(), fsols.begin(), fsols.end());
-
- /* Skolemize property */
- std::vector<Node> vars, skos;
- for (unsigned j = 0, size = conj[1][0].getNumChildren(); j < size; ++j)
- {
- vars.push_back(conj[1][0][j]);
- std::stringstream ss;
- ss << "sk_" << j;
- skos.push_back(nm->mkSkolem(ss.str(), conj[1][0][j].getType()));
- Trace("check-synth-sol") << "\tSkolemizing " << conj[1][0][j] << " to "
- << skos.back() << "\n";
- }
- conjBody = conjBody.substitute(
- vars.begin(), vars.end(), skos.begin(), skos.end());
- }
- Notice() << "SmtEngine::checkSynthSolution(): -- body substitutes to "
- << conjBody << endl;
- Trace("check-synth-sol") << "Substituted body of assertion to " << conjBody
- << "\n";
- solChecker.assertFormula(conjBody);
- // Assert all auxiliary assertions. This may include recursive function
- // definitions that were added as assertions to the sygus problem.
- for (const Node& a : auxAssertions)
- {
- solChecker.assertFormula(a);
- }
- Result r = solChecker.checkSat();
- Notice() << "SmtEngine::checkSynthSolution(): result is " << r << endl;
- Trace("check-synth-sol") << "Satsifiability check: " << r << "\n";
- if (r.asSatisfiabilityResult().isUnknown())
- {
- InternalError() << "SmtEngine::checkSynthSolution(): could not check "
- "solution, result "
- "unknown.";
- }
- else if (r.asSatisfiabilityResult().isSat())
- {
- InternalError()
- << "SmtEngine::checkSynthSolution(): produced solution leads to "
- "satisfiable negated conjecture.";
- }
- solChecker.resetAssertions();
- }
-}
-
-void SmtEngine::checkInterpol(Expr interpol,
- const std::vector<Expr>& easserts,
- const Node& conj)
-{
-}
-
-void SmtEngine::checkAbduct(Node a)
-{
- Assert(a.getType().isBoolean());
- // check it with the abduction solver
- return d_abductSolver->checkAbduct(a);
+ // check the model with the check models utility
+ Assert(d_checkModels != nullptr);
+ d_checkModels->checkModel(m, al, hardFailure);
}
// TODO(#1108): Simplify the error reporting of this method.
UnsatCore SmtEngine::getUnsatCore() {
Trace("smt") << "SMT getUnsatCore()" << endl;
SmtScope smts(this);
- finalOptionsAreSet();
+ finishInit();
if(Dump.isOn("benchmark")) {
- Dump("benchmark") << GetUnsatCoreCommand();
+ getOutputManager().getPrinter().toStreamCmdGetUnsatCore(
+ getOutputManager().getDumpOut());
}
return getUnsatCoreInternal();
}
-// TODO(#1108): Simplify the error reporting of this method.
-const Proof& SmtEngine::getProof()
-{
- Trace("smt") << "SMT getProof()" << endl;
- SmtScope smts(this);
- finalOptionsAreSet();
- if(Dump.isOn("benchmark")) {
- Dump("benchmark") << GetProofCommand();
- }
-#if IS_PROOFS_BUILD
- if(!options::proof()) {
- throw ModalException("Cannot get a proof when produce-proofs option is off.");
- }
- if (d_smtMode != SMT_MODE_UNSAT)
- {
- throw RecoverableModalException(
- "Cannot get a proof unless immediately preceded by UNSAT/ENTAILED "
- "response.");
- }
-
- return ProofManager::getProof(this);
-#else /* IS_PROOFS_BUILD */
- throw ModalException("This build of CVC4 doesn't have proof support.");
-#endif /* IS_PROOFS_BUILD */
-}
-
void SmtEngine::printInstantiations( std::ostream& out ) {
SmtScope smts(this);
- finalOptionsAreSet();
+ finishInit();
if (options::instFormatMode() == options::InstFormatMode::SZS)
{
- out << "% SZS output start Proof for " << d_filename.c_str() << std::endl;
- }
- if( d_theoryEngine ){
- d_theoryEngine->printInstantiations( out );
- }else{
- Assert(false);
+ out << "% SZS output start Proof for " << d_state->getFilename()
+ << std::endl;
}
+ TheoryEngine* te = getTheoryEngine();
+ Assert(te != nullptr);
+ te->printInstantiations(out);
if (options::instFormatMode() == options::InstFormatMode::SZS)
{
- out << "% SZS output end Proof for " << d_filename.c_str() << std::endl;
+ out << "% SZS output end Proof for " << d_state->getFilename() << std::endl;
}
}
void SmtEngine::printSynthSolution( std::ostream& out ) {
SmtScope smts(this);
- finalOptionsAreSet();
- if( d_theoryEngine ){
- d_theoryEngine->printSynthSolution( out );
- }else{
- Assert(false);
- }
+ finishInit();
+ TheoryEngine* te = getTheoryEngine();
+ Assert(te != nullptr);
+ te->printSynthSolution(out);
}
-bool SmtEngine::getSynthSolutions(std::map<Expr, Expr>& sol_map)
+bool SmtEngine::getSynthSolutions(std::map<Node, Node>& solMap)
{
SmtScope smts(this);
- finalOptionsAreSet();
- std::map<Node, std::map<Node, Node>> sol_mapn;
- Assert(d_theoryEngine != nullptr);
- // fail if the theory engine does not have synthesis solutions
- if (!d_theoryEngine->getSynthSolutions(sol_mapn))
- {
- return false;
- }
- for (std::pair<const Node, std::map<Node, Node>>& cs : sol_mapn)
- {
- for (std::pair<const Node, Node>& s : cs.second)
- {
- sol_map[s.first.toExpr()] = s.second.toExpr();
- }
- }
- return true;
+ finishInit();
+ return d_sygusSolver->getSynthSolutions(solMap);
}
-Expr SmtEngine::doQuantifierElimination(const Expr& e, bool doFull, bool strict)
+Node SmtEngine::getQuantifierElimination(Node q, bool doFull, bool strict)
{
SmtScope smts(this);
- finalOptionsAreSet();
+ finishInit();
if(!d_logic.isPure(THEORY_ARITH) && strict){
Warning() << "Unexpected logic for quantifier elimination " << d_logic << endl;
}
- Trace("smt-qe") << "Do quantifier elimination " << e << std::endl;
- Node n_e = Node::fromExpr( e );
- if (n_e.getKind() != kind::EXISTS && n_e.getKind() != kind::FORALL)
- {
- throw ModalException(
- "Expecting a quantified formula as argument to get-qe.");
- }
- //tag the quantified formula with the quant-elim attribute
- TypeNode t = NodeManager::currentNM()->booleanType();
- Node n_attr = NodeManager::currentNM()->mkSkolem("qe", t, "Auxiliary variable for qe attr.");
- std::vector< Node > node_values;
- d_theoryEngine->setUserAttribute( doFull ? "quant-elim" : "quant-elim-partial", n_attr, node_values, "");
- n_attr = NodeManager::currentNM()->mkNode(kind::INST_ATTRIBUTE, n_attr);
- n_attr = NodeManager::currentNM()->mkNode(kind::INST_PATTERN_LIST, n_attr);
- std::vector< Node > e_children;
- e_children.push_back( n_e[0] );
- e_children.push_back(n_e.getKind() == kind::EXISTS ? n_e[1]
- : n_e[1].negate());
- e_children.push_back( n_attr );
- Node nn_e = NodeManager::currentNM()->mkNode( kind::EXISTS, e_children );
- Trace("smt-qe-debug") << "Query for quantifier elimination : " << nn_e << std::endl;
- Assert(nn_e.getNumChildren() == 3);
- Result r = checkSatisfiability(nn_e.toExpr(), true, true);
- Trace("smt-qe") << "Query returned " << r << std::endl;
- if(r.asSatisfiabilityResult().isSat() != Result::UNSAT ) {
- if( r.asSatisfiabilityResult().isSat() != Result::SAT && doFull ){
- Notice()
- << "While performing quantifier elimination, unexpected result : "
- << r << " for query.";
- // failed, return original
- return e;
- }
- std::vector< Node > inst_qs;
- d_theoryEngine->getInstantiatedQuantifiedFormulas( inst_qs );
- Assert(inst_qs.size() <= 1);
- Node ret_n;
- if( inst_qs.size()==1 ){
- Node top_q = inst_qs[0];
- //Node top_q = Rewriter::rewrite( nn_e ).negate();
- Assert(top_q.getKind() == kind::FORALL);
- Trace("smt-qe") << "Get qe for " << top_q << std::endl;
- ret_n = d_theoryEngine->getInstantiatedConjunction( top_q );
- Trace("smt-qe") << "Returned : " << ret_n << std::endl;
- if (n_e.getKind() == kind::EXISTS)
- {
- ret_n = Rewriter::rewrite(ret_n.negate());
- }
- }else{
- ret_n = NodeManager::currentNM()->mkConst(n_e.getKind() != kind::EXISTS);
- }
- // do extended rewrite to minimize the size of the formula aggressively
- theory::quantifiers::ExtendedRewriter extr(true);
- ret_n = extr.extendedRewrite(ret_n);
- return ret_n.toExpr();
- }else {
- return NodeManager::currentNM()
- ->mkConst(n_e.getKind() == kind::EXISTS)
- .toExpr();
- }
+ return d_quantElimSolver->getQuantifierElimination(*d_asserts, q, doFull);
}
-bool SmtEngine::getInterpol(const Expr& conj,
- const Type& grammarType,
- Expr& interpol)
+bool SmtEngine::getInterpol(const Node& conj,
+ const TypeNode& grammarType,
+ Node& interpol)
{
- return false;
+ SmtScope smts(this);
+ finishInit();
+ bool success = d_interpolSolver->getInterpol(conj, grammarType, interpol);
+ // notify the state of whether the get-interpol call was successfuly, which
+ // impacts the SMT mode.
+ d_state->notifyGetInterpol(success);
+ return success;
}
-bool SmtEngine::getInterpol(const Expr& conj, Expr& interpol)
+bool SmtEngine::getInterpol(const Node& conj, Node& interpol)
{
- Type grammarType;
+ TypeNode grammarType;
return getInterpol(conj, grammarType, interpol);
}
@@ -3163,15 +1537,13 @@ bool SmtEngine::getAbduct(const Node& conj,
const TypeNode& grammarType,
Node& abd)
{
- if (d_abductSolver->getAbduct(conj, grammarType, abd))
- {
- // successfully generated an abduct, update to abduct state
- d_smtMode = SMT_MODE_ABDUCT;
- return true;
- }
- // failed, we revert to the assert state
- d_smtMode = SMT_MODE_ASSERT;
- return false;
+ SmtScope smts(this);
+ finishInit();
+ bool success = d_abductSolver->getAbduct(conj, grammarType, abd);
+ // notify the state of whether the get-abduct call was successfuly, which
+ // impacts the SMT mode.
+ d_state->notifyGetAbduct(success);
+ return success;
}
bool SmtEngine::getAbduct(const Node& conj, Node& abd)
@@ -3180,56 +1552,31 @@ bool SmtEngine::getAbduct(const Node& conj, Node& abd)
return getAbduct(conj, grammarType, abd);
}
-void SmtEngine::getInstantiatedQuantifiedFormulas( std::vector< Expr >& qs ) {
+void SmtEngine::getInstantiatedQuantifiedFormulas(std::vector<Node>& qs)
+{
SmtScope smts(this);
- if( d_theoryEngine ){
- std::vector< Node > qs_n;
- d_theoryEngine->getInstantiatedQuantifiedFormulas( qs_n );
- for( unsigned i=0; i<qs_n.size(); i++ ){
- qs.push_back( qs_n[i].toExpr() );
- }
- }else{
- Assert(false);
- }
+ TheoryEngine* te = getTheoryEngine();
+ Assert(te != nullptr);
+ te->getInstantiatedQuantifiedFormulas(qs);
}
-void SmtEngine::getInstantiations( Expr q, std::vector< Expr >& insts ) {
- SmtScope smts(this);
- if( d_theoryEngine ){
- std::vector< Node > insts_n;
- d_theoryEngine->getInstantiations( Node::fromExpr( q ), insts_n );
- for( unsigned i=0; i<insts_n.size(); i++ ){
- insts.push_back( insts_n[i].toExpr() );
- }
- }else{
- Assert(false);
- }
-}
-
-void SmtEngine::getInstantiationTermVectors( Expr q, std::vector< std::vector< Expr > >& tvecs ) {
+void SmtEngine::getInstantiationTermVectors(
+ Node q, std::vector<std::vector<Node>>& tvecs)
+{
SmtScope smts(this);
- Assert(options::trackInstLemmas());
- if( d_theoryEngine ){
- std::vector< std::vector< Node > > tvecs_n;
- d_theoryEngine->getInstantiationTermVectors( Node::fromExpr( q ), tvecs_n );
- for( unsigned i=0; i<tvecs_n.size(); i++ ){
- std::vector< Expr > tvec;
- for( unsigned j=0; j<tvecs_n[i].size(); j++ ){
- tvec.push_back( tvecs_n[i][j].toExpr() );
- }
- tvecs.push_back( tvec );
- }
- }else{
- Assert(false);
- }
+ TheoryEngine* te = getTheoryEngine();
+ Assert(te != nullptr);
+ te->getInstantiationTermVectors(q, tvecs);
}
-vector<Expr> SmtEngine::getAssertions() {
+std::vector<Node> SmtEngine::getAssertions()
+{
SmtScope smts(this);
- finalOptionsAreSet();
- doPendingPops();
+ finishInit();
+ d_state->doPendingPops();
if(Dump.isOn("benchmark")) {
- Dump("benchmark") << GetAssertionsCommand();
+ getOutputManager().getPrinter().toStreamCmdGetAssertions(
+ getOutputManager().getDumpOut());
}
Trace("smt") << "SMT getAssertions()" << endl;
if(!options::produceAssertions()) {
@@ -3237,11 +1584,12 @@ vector<Expr> SmtEngine::getAssertions() {
"Cannot query the current assertion list when not in produce-assertions mode.";
throw ModalException(msg);
}
- Assert(d_assertionList != NULL);
- std::vector<Expr> res;
- for (const Node& n : *d_assertionList)
+ context::CDList<Node>* al = d_asserts->getAssertionList();
+ Assert(al != nullptr);
+ std::vector<Node> res;
+ for (const Node& n : *al)
{
- res.emplace_back(n.toExpr());
+ res.emplace_back(n);
}
// copy the result out
return res;
@@ -3250,188 +1598,102 @@ vector<Expr> SmtEngine::getAssertions() {
void SmtEngine::push()
{
SmtScope smts(this);
- finalOptionsAreSet();
- doPendingPops();
+ finishInit();
+ d_state->doPendingPops();
Trace("smt") << "SMT push()" << endl;
- d_private->notifyPush();
- d_private->processAssertions();
+ d_smtSolver->processAssertions(*d_asserts);
if(Dump.isOn("benchmark")) {
- Dump("benchmark") << PushCommand();
- }
- if(!options::incrementalSolving()) {
- throw ModalException("Cannot push when not solving incrementally (use --incremental)");
+ getOutputManager().getPrinter().toStreamCmdPush(
+ getOutputManager().getDumpOut());
}
-
-
- // The problem isn't really "extended" yet, but this disallows
- // get-model after a push, simplifying our lives somewhat and
- // staying symmetric with pop.
- setProblemExtended();
-
- d_userLevels.push_back(d_userContext->getLevel());
- internalPush();
- Trace("userpushpop") << "SmtEngine: pushed to level "
- << d_userContext->getLevel() << endl;
+ d_state->userPush();
}
void SmtEngine::pop() {
SmtScope smts(this);
- finalOptionsAreSet();
+ finishInit();
Trace("smt") << "SMT pop()" << endl;
if(Dump.isOn("benchmark")) {
- Dump("benchmark") << PopCommand();
- }
- if(!options::incrementalSolving()) {
- throw ModalException("Cannot pop when not solving incrementally (use --incremental)");
+ getOutputManager().getPrinter().toStreamCmdPop(
+ getOutputManager().getDumpOut());
}
- if(d_userLevels.size() == 0) {
- throw ModalException("Cannot pop beyond the first user frame");
- }
-
- // 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!).
- setProblemExtended();
-
- AlwaysAssert(d_userContext->getLevel() > 0);
- AlwaysAssert(d_userLevels.back() < d_userContext->getLevel());
- while (d_userLevels.back() < d_userContext->getLevel()) {
- internalPop(true);
- }
- d_userLevels.pop_back();
+ d_state->userPop();
// Clear out assertion queues etc., in case anything is still in there
- d_private->notifyPop();
+ d_asserts->clearCurrent();
+ // clear the learned literals from the preprocessor
+ d_pp->clearLearnedLiterals();
Trace("userpushpop") << "SmtEngine: popped to level "
- << d_userContext->getLevel() << endl;
- // FIXME: should we reset d_status here?
+ << getUserContext()->getLevel() << endl;
+ // should we reset d_status here?
// SMT-LIBv2 spec seems to imply no, but it would make sense to..
}
-void SmtEngine::internalPush() {
- Assert(d_fullyInited);
- Trace("smt") << "SmtEngine::internalPush()" << endl;
- doPendingPops();
- if(options::incrementalSolving()) {
- d_private->processAssertions();
- TimerStat::CodeTimer pushPopTimer(d_stats->d_pushPopTime);
- d_userContext->push();
- // the d_context push is done inside of the SAT solver
- d_propEngine->push();
- }
-}
-
-void SmtEngine::internalPop(bool immediate) {
- Assert(d_fullyInited);
- Trace("smt") << "SmtEngine::internalPop()" << endl;
- if(options::incrementalSolving()) {
- ++d_pendingPops;
- }
- if(immediate) {
- doPendingPops();
- }
-}
-
-void SmtEngine::doPendingPops() {
- Trace("smt") << "SmtEngine::doPendingPops()" << endl;
- Assert(d_pendingPops == 0 || options::incrementalSolving());
- // check to see if a postsolve() is pending
- if (d_needPostsolve)
- {
- d_propEngine->resetTrail();
- }
- while(d_pendingPops > 0) {
- TimerStat::CodeTimer pushPopTimer(d_stats->d_pushPopTime);
- d_propEngine->pop();
- // the d_context pop is done inside of the SAT solver
- d_userContext->pop();
- --d_pendingPops;
- }
- if (d_needPostsolve)
- {
- d_theoryEngine->postsolve();
- d_needPostsolve = false;
- }
-}
-
void SmtEngine::reset()
{
SmtScope smts(this);
ExprManager *em = d_exprManager;
Trace("smt") << "SMT reset()" << endl;
if(Dump.isOn("benchmark")) {
- Dump("benchmark") << ResetCommand();
+ getOutputManager().getPrinter().toStreamCmdReset(
+ getOutputManager().getDumpOut());
}
+ std::string filename = d_state->getFilename();
Options opts;
opts.copyValues(d_originalOptions);
this->~SmtEngine();
new (this) SmtEngine(em, &opts);
+ // Restore data set after creation
+ notifyStartParsing(filename);
}
void SmtEngine::resetAssertions()
{
SmtScope smts(this);
- if (!d_fullyInited)
+ if (!d_state->isFullyInited())
{
// We're still in Start Mode, nothing asserted yet, do nothing.
// (see solver execution modes in the SMT-LIB standard)
- Assert(d_context->getLevel() == 0);
- Assert(d_userContext->getLevel() == 0);
- DeleteAndClearCommandVector(d_modelGlobalCommands);
+ Assert(getContext()->getLevel() == 0);
+ Assert(getUserContext()->getLevel() == 0);
+ d_dumpm->resetAssertions();
return;
}
- doPendingPops();
Trace("smt") << "SMT resetAssertions()" << endl;
if (Dump.isOn("benchmark"))
{
- Dump("benchmark") << ResetAssertionsCommand();
- }
-
- while (!d_userLevels.empty())
- {
- pop();
+ getOutputManager().getPrinter().toStreamCmdResetAssertions(
+ getOutputManager().getDumpOut());
}
- // Remember the global push/pop around everything when beyond Start mode
- // (see solver execution modes in the SMT-LIB standard)
- Assert(d_userLevels.size() == 0 && d_userContext->getLevel() == 1);
- d_context->popto(0);
- d_userContext->popto(0);
- DeleteAndClearCommandVector(d_modelGlobalCommands);
- d_userContext->push();
- d_context->push();
+ d_asserts->clearCurrent();
+ d_state->notifyResetAssertions();
+ d_dumpm->resetAssertions();
+ // push the state to maintain global context around everything
+ d_state->setup();
- /* Create new PropEngine.
- * First force destruction of referenced PropEngine to enforce that
- * statistics are unregistered by the obsolete PropEngine object before
- * registered again by the new PropEngine object */
- d_propEngine.reset(nullptr);
- d_propEngine.reset(new PropEngine(
- getTheoryEngine(), getContext(), getUserContext(), getResourceManager()));
- d_theoryEngine->setPropEngine(getPropEngine());
+ d_smtSolver->resetAssertions();
}
void SmtEngine::interrupt()
{
- if(!d_fullyInited) {
+ if (!d_state->isFullyInited())
+ {
return;
}
- d_propEngine->interrupt();
- d_theoryEngine->interrupt();
+ d_smtSolver->interrupt();
}
void SmtEngine::setResourceLimit(unsigned long units, bool cumulative) {
d_resourceManager->setResourceLimit(units, cumulative);
}
-void SmtEngine::setTimeLimit(unsigned long milis, bool cumulative) {
- d_resourceManager->setTimeLimit(milis, cumulative);
+void SmtEngine::setTimeLimit(unsigned long milis)
+{
+ d_resourceManager->setTimeLimit(milis);
}
unsigned long SmtEngine::getResourceUsage() const {
@@ -3447,11 +1709,6 @@ unsigned long SmtEngine::getResourceRemaining() const
return d_resourceManager->getResourceRemaining();
}
-unsigned long SmtEngine::getTimeRemaining() const
-{
- return d_resourceManager->getTimeRemaining();
-}
-
NodeManager* SmtEngine::getNodeManager() const
{
return d_exprManager->getNodeManager();
@@ -3477,52 +1734,32 @@ void SmtEngine::setUserAttribute(const std::string& attr,
const std::string& str_value)
{
SmtScope smts(this);
- finalOptionsAreSet();
+ finishInit();
std::vector<Node> node_values;
- for( unsigned i=0; i<expr_values.size(); i++ ){
+ for (std::size_t i = 0, n = expr_values.size(); i < n; i++)
+ {
node_values.push_back( expr_values[i].getNode() );
}
- d_theoryEngine->setUserAttribute(attr, expr.getNode(), node_values, str_value);
-}
-
-void SmtEngine::setPrintFuncInModel(Expr f, bool p) {
- Trace("setp-model") << "Set printInModel " << f << " to " << p << std::endl;
- for( unsigned i=0; i<d_modelGlobalCommands.size(); i++ ){
- Command * c = d_modelGlobalCommands[i];
- DeclareFunctionCommand* dfc = dynamic_cast<DeclareFunctionCommand*>(c);
- if(dfc != NULL) {
- if( dfc->getFunction()==f ){
- dfc->setPrintInModel( p );
- }
- }
- }
- for( unsigned i=0; i<d_modelCommands->size(); i++ ){
- Command * c = (*d_modelCommands)[i];
- DeclareFunctionCommand* dfc = dynamic_cast<DeclareFunctionCommand*>(c);
- if(dfc != NULL) {
- if( dfc->getFunction()==f ){
- dfc->setPrintInModel( p );
- }
- }
- }
-}
-
-void SmtEngine::beforeSearch()
-{
- if(d_fullyInited) {
- throw ModalException(
- "SmtEngine::beforeSearch called after initialization.");
- }
+ TheoryEngine* te = getTheoryEngine();
+ Assert(te != nullptr);
+ te->setUserAttribute(attr, expr.getNode(), node_values, str_value);
}
-
void SmtEngine::setOption(const std::string& key, const CVC4::SExpr& value)
{
+ // Always check whether the SmtEngine has been initialized (which is done
+ // upon entering Assert mode the first time). No option can be set after
+ // initialized.
+ if (d_state->isFullyInited())
+ {
+ throw ModalException("SmtEngine::setOption called after initialization.");
+ }
NodeManagerScope nms(d_nodeManager);
Trace("smt") << "SMT setOption(" << key << ", " << value << ")" << endl;
if(Dump.isOn("benchmark")) {
- Dump("benchmark") << SetOptionCommand(key, value);
+ getOutputManager().getPrinter().toStreamCmdSetOption(
+ getOutputManager().getDumpOut(), key, value);
}
if(key == "command-verbosity") {
@@ -3575,7 +1812,7 @@ CVC4::SExpr SmtEngine::getOption(const std::string& key) const
}
if(Dump.isOn("benchmark")) {
- Dump("benchmark") << GetOptionCommand(key);
+ d_outMgr.getPrinter().toStreamCmdGetOption(d_outMgr.getDumpOut(), key);
}
if(key == "command-verbosity") {
@@ -3610,15 +1847,6 @@ CVC4::SExpr SmtEngine::getOption(const std::string& key) const
return SExpr::parseAtom(d_options.getOption(key));
}
-bool SmtEngine::getExpressionName(Expr e, std::string& name) const {
- return d_private->getExpressionName(e, name);
-}
-
-void SmtEngine::setExpressionName(Expr e, const std::string& name) {
- Trace("smt-debug") << "Set expression name " << e << " to " << name << std::endl;
- d_private->setExpressionName(e,name);
-}
-
Options& SmtEngine::getOptions() { return d_options; }
const Options& SmtEngine::getOptions() const { return d_options; }
@@ -3628,18 +1856,13 @@ ResourceManager* SmtEngine::getResourceManager()
return d_resourceManager.get();
}
-void SmtEngine::setSygusConjectureStale()
+DumpManager* SmtEngine::getDumpManager() { return d_dumpm.get(); }
+
+const Printer* SmtEngine::getPrinter() const
{
- if (d_private->d_sygusConjectureStale)
- {
- // already stale
- return;
- }
- d_private->d_sygusConjectureStale = true;
- if (options::incrementalSolving())
- {
- internalPop();
- }
+ return Printer::getPrinter(d_options[options::outputLanguage]);
}
+OutputManager& SmtEngine::getOutputManager() { return d_outMgr; }
+
}/* CVC4 namespace */
diff --git a/src/smt/smt_engine.h b/src/smt/smt_engine.h
index 3ed2b987c..1c83fa61f 100644
--- a/src/smt/smt_engine.h
+++ b/src/smt/smt_engine.h
@@ -2,10 +2,10 @@
/*! \file smt_engine.h
** \verbatim
** Top contributors (to current version):
- ** Morgan Deters, Andrew Reynolds, Aina Niemetz
+ ** Andrew Reynolds, Morgan Deters, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -29,11 +29,11 @@
#include "expr/expr.h"
#include "expr/expr_manager.h"
#include "options/options.h"
-#include "proof/unsat_core.h"
#include "smt/logic_exception.h"
+#include "smt/output_manager.h"
+#include "smt/smt_mode.h"
#include "theory/logic_info.h"
#include "util/hash.h"
-#include "util/proof.h"
#include "util/result.h"
#include "util/sexpr.h"
#include "util/statistics.h"
@@ -50,18 +50,14 @@ typedef NodeTemplate<true> Node;
typedef NodeTemplate<false> TNode;
struct NodeHashFunction;
-class Command;
-class GetModelCommand;
-
class SmtEngine;
class DecisionEngine;
class TheoryEngine;
-
class ProofManager;
-
-class Model;
+class UnsatCore;
class LogicRequest;
class StatisticsRegistry;
+class Printer;
/* -------------------------------------------------------------------------- */
@@ -91,8 +87,24 @@ namespace prop {
/* -------------------------------------------------------------------------- */
namespace smt {
+/** Utilities */
+class Model;
+class SmtEngineState;
+class AbstractValues;
+class Assertions;
+class ExprNames;
+class DumpManager;
+class ResourceOutListener;
+class SmtNodeManagerListener;
+class OptionsManager;
+class Preprocessor;
+class CheckModels;
/** Subsolvers */
+class SmtSolver;
+class SygusSolver;
class AbductionSolver;
+class InterpolationSolver;
+class QuantElimSolver;
/**
* Representation of a defined function. We keep these around in
* SmtEngine to permit expanding definitions late (and lazily), to
@@ -102,14 +114,11 @@ class AbductionSolver;
class DefinedFunction;
struct SmtEngineStatistics;
-class SmtEnginePrivate;
class SmtScope;
class ProcessAssertions;
+class PfManager;
ProofManager* currentProofManager();
-
-struct CommandCleanup;
-typedef context::CDList<Command*, CommandCleanup> CommandList;
}/* CVC4::smt namespace */
/* -------------------------------------------------------------------------- */
@@ -119,61 +128,21 @@ namespace theory {
class Rewriter;
}/* CVC4::theory namespace */
-// TODO: SAT layer (esp. CNF- versus non-clausal solvers under the
-// hood): use a type parameter and have check() delegate, or subclass
-// SmtEngine and override check()?
-//
-// Probably better than that is to have a configuration object that
-// indicates which passes are desired. The configuration occurs
-// elsewhere (and can even occur at runtime). A simple "pass manager"
-// of sorts determines check()'s behavior.
-//
-// The CNF conversion can go on in PropEngine.
/* -------------------------------------------------------------------------- */
class CVC4_PUBLIC SmtEngine
{
friend class ::CVC4::api::Solver;
- // TODO (Issue #1096): Remove this friend relationship.
- friend class ::CVC4::preprocessing::PreprocessingPassContext;
- friend class ::CVC4::smt::SmtEnginePrivate;
+ friend class ::CVC4::smt::SmtEngineState;
friend class ::CVC4::smt::SmtScope;
- friend class ::CVC4::smt::ProcessAssertions;
- friend ProofManager* ::CVC4::smt::currentProofManager();
friend class ::CVC4::LogicRequest;
- friend class ::CVC4::Model; // to access d_modelCommands
- friend class ::CVC4::theory::TheoryModel;
- friend class ::CVC4::theory::Rewriter;
/* ....................................................................... */
public:
/* ....................................................................... */
/**
- * The current mode of the solver, which is an extension of Figure 4.1 on
- * page 52 of the SMT-LIB version 2.6 standard
- * http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.6-r2017-07-18.pdf
- */
- enum SmtMode
- {
- // the initial state of the solver
- SMT_MODE_START,
- // normal state of the solver, after assert/push/pop/declare/define
- SMT_MODE_ASSERT,
- // immediately after a check-sat returning "sat"
- SMT_MODE_SAT,
- // immediately after a check-sat returning "unknown"
- SMT_MODE_SAT_UNKNOWN,
- // immediately after a check-sat returning "unsat"
- SMT_MODE_UNSAT,
- // immediately after a successful call to get-abduct
- SMT_MODE_ABDUCT,
- // immediately after a successful call to get-interpol
- SMT_MODE_INTERPOL
- };
-
- /**
* Construct an SmtEngine with the given expression manager.
* If provided, optr is a pointer to a set of options that should initialize the values
* of the options object owned by this class.
@@ -182,24 +151,49 @@ class CVC4_PUBLIC SmtEngine
/** Destruct the SMT engine. */
~SmtEngine();
+ //--------------------------------------------- concerning the state
+
/**
- * Return true if this SmtEngine is fully initialized (post-construction).
+ * This is the main initialization procedure of the SmtEngine.
+ *
+ * Should be called whenever the final options and logic for the problem are
+ * set (at least, those options that are not permitted to change after
+ * assertions and queries are made).
+ *
+ * Internally, this creates the theory engine, prop engine, decision engine,
+ * and other utilities whose initialization depends on the final set of
+ * options being set.
+ *
* This post-construction initialization is automatically triggered by the
* use of the SmtEngine; e.g. when the first formula is asserted, a call
* to simplify() is issued, a scope is pushed, etc.
*/
- bool isFullyInited() { return d_fullyInited; }
-
+ void finishInit();
+ /**
+ * Return true if this SmtEngine is fully initialized (post-construction)
+ * by the above call.
+ */
+ bool isFullyInited() const;
/**
* Return true if a checkEntailed() or checkSatisfiability() has been made.
*/
- bool isQueryMade() { return d_queryMade; }
-
+ bool isQueryMade() const;
/** Return the user context level. */
- size_t getNumUserLevels() { return d_userLevels.size(); }
-
+ size_t getNumUserLevels() const;
/** Return the current mode of the solver. */
- SmtMode getSmtMode() { return d_smtMode; }
+ SmtMode getSmtMode() const;
+ /**
+ * Whether the SmtMode allows for get-value, get-model, get-assignment, etc.
+ * This is equivalent to:
+ * getSmtMode()==SmtMode::SAT || getSmtMode()==SmtMode::SAT_UNKNOWN
+ */
+ bool isSmtModeSat() const;
+ /**
+ * Returns the most recent result of checkSat/checkEntailed or
+ * (set-info :status).
+ */
+ Result getStatusOfLastCommand() const;
+ //--------------------------------------------- end concerning the state
/**
* Set the logic of the script.
@@ -220,7 +214,7 @@ class CVC4_PUBLIC SmtEngine
void setLogic(const LogicInfo& logic);
/** Get the logic information currently set. */
- LogicInfo getLogicInfo() const;
+ const LogicInfo& getLogicInfo() const;
/** Get the logic information set by the user. */
LogicInfo getUserLogicInfo() const;
@@ -264,13 +258,13 @@ class CVC4_PUBLIC SmtEngine
*/
void notifyStartParsing(std::string filename);
/** return the input name (if any) */
- std::string getFilename() const;
+ const std::string& getFilename() const;
/**
* Get the model (only if immediately preceded by a SAT or NOT_ENTAILED
* query). Only permitted if produce-models is on.
*/
- Model* getModel();
+ smt::Model* getModel();
/**
* Block the current model. Can be called only if immediately preceded by
@@ -296,13 +290,30 @@ class CVC4_PUBLIC SmtEngine
*
* The return value has the same meaning as that of assertFormula.
*/
- Result blockModelValues(const std::vector<Expr>& exprs);
+ Result blockModelValues(const std::vector<Node>& exprs);
+
+ /**
+ * Declare heap. For smt2 inputs, this is called when the command
+ * (declare-heap (locT datat)) is invoked by the user. This sets locT as the
+ * location type and dataT is the data type for the heap. This command should
+ * be executed only once, and must be invoked before solving separation logic
+ * inputs.
+ */
+ void declareSepHeap(TypeNode locT, TypeNode dataT);
+
+ /**
+ * Get the separation heap types, which extracts which types were passed to
+ * the method above.
+ *
+ * @return true if the separation logic heap types have been declared.
+ */
+ bool getSepHeapTypes(TypeNode& locT, TypeNode& dataT);
/** When using separation logic, obtain the expression for the heap. */
- Expr getSepHeapExpr();
+ Node getSepHeapExpr();
/** When using separation logic, obtain the expression for nil. */
- Expr getSepNilExpr();
+ Node getSepNilExpr();
/**
* Get an aspect of the current SMT execution environment.
@@ -323,13 +334,13 @@ class CVC4_PUBLIC SmtEngine
* @param global True if this definition is global (i.e. should persist when
* popping the user context)
*/
- void defineFunction(Expr func,
- const std::vector<Expr>& formals,
- Expr formula,
+ void defineFunction(Node func,
+ const std::vector<Node>& formals,
+ Node formula,
bool global = false);
/** Return true if given expression is a defined function. */
- bool isDefinedFunction(Expr func);
+ bool isDefinedFunction(Node func);
/**
* Define functions recursive
@@ -349,17 +360,17 @@ class CVC4_PUBLIC SmtEngine
* @param global True if this definition is global (i.e. should persist when
* popping the user context)
*/
- void defineFunctionsRec(const std::vector<Expr>& funcs,
- const std::vector<std::vector<Expr>>& formals,
- const std::vector<Expr>& formulas,
+ void defineFunctionsRec(const std::vector<Node>& funcs,
+ const std::vector<std::vector<Node>>& formals,
+ const std::vector<Node>& formulas,
bool global = false);
/**
* Define function recursive
* Same as above, but for a single function.
*/
- void defineFunctionRec(Expr func,
- const std::vector<Expr>& formals,
- Expr formula,
+ void defineFunctionRec(Node func,
+ const std::vector<Node>& formals,
+ Node formula,
bool global = false);
/**
* Add a formula to the current context: preprocess, do per-theory
@@ -381,9 +392,8 @@ class CVC4_PUBLIC SmtEngine
*
* @throw Exception
*/
- Result checkEntailed(const Expr& assumption = Expr(),
- bool inUnsatCore = true);
- Result checkEntailed(const std::vector<Expr>& assumptions,
+ Result checkEntailed(const Node& assumption, bool inUnsatCore = true);
+ Result checkEntailed(const std::vector<Node>& assumptions,
bool inUnsatCore = true);
/**
@@ -392,8 +402,9 @@ class CVC4_PUBLIC SmtEngine
*
* @throw Exception
*/
- Result checkSat(const Expr& assumption = Expr(), bool inUnsatCore = true);
- Result checkSat(const std::vector<Expr>& assumptions,
+ Result checkSat();
+ Result checkSat(const Node& assumption, bool inUnsatCore = true);
+ Result checkSat(const std::vector<Node>& assumptions,
bool inUnsatCore = true);
/**
@@ -406,27 +417,23 @@ class CVC4_PUBLIC SmtEngine
* Note that the returned set of failed assumptions is not necessarily
* minimal.
*/
- std::vector<Expr> getUnsatAssumptions(void);
+ std::vector<Node> getUnsatAssumptions(void);
/*---------------------------- sygus commands ---------------------------*/
/**
- * Add variable declaration.
+ * Add sygus variable declaration.
*
* Declared SyGuS variables may be used in SyGuS constraints, in which they
* are assumed to be universally quantified.
- */
- void declareSygusVar(const std::string& id, Expr var, Type type);
-
- /**
- * Add a function variable declaration.
*
- * Is SyGuS semantics declared functions are treated in the same manner as
+ * In SyGuS semantics, declared functions are treated in the same manner as
* declared variables, i.e. as universally quantified (function) variables
* which can occur in the SyGuS constraints that compose the conjecture to
- * which a function is being synthesized.
+ * which a function is being synthesized. Thus declared functions should use
+ * this method as well.
*/
- void declareSygusFunctionVar(const std::string& id, Expr var, Type type);
+ void declareSygusVar(const std::string& id, Node var, TypeNode type);
/**
* Add a function-to-synthesize declaration.
@@ -444,13 +451,13 @@ class CVC4_PUBLIC SmtEngine
* corresponding to this declaration, so that it can be properly printed.
*/
void declareSynthFun(const std::string& id,
- Expr func,
- Type type,
+ Node func,
+ TypeNode type,
bool isInv,
- const std::vector<Expr>& vars);
+ const std::vector<Node>& vars);
/** Add a regular sygus constraint.*/
- void assertSygusConstraint(Expr constraint);
+ void assertSygusConstraint(Node constraint);
/**
* Add an invariant constraint.
@@ -467,10 +474,7 @@ class CVC4_PUBLIC SmtEngine
* The regular and primed variables are retrieved from the declaration of the
* invariant-to-synthesize.
*/
- void assertSygusInvConstraint(const Expr& inv,
- const Expr& pre,
- const Expr& trans,
- const Expr& post);
+ void assertSygusInvConstraint(Node inv, Node pre, Node trans, Node post);
/**
* Assert a synthesis conjecture to the current context and call
* check(). Returns sat, unsat, or unknown result.
@@ -502,7 +506,7 @@ class CVC4_PUBLIC SmtEngine
* @todo (design) is this meant to give an equivalent or an
* equisatisfiable formula?
*/
- Expr simplify(const Expr& e);
+ Node simplify(const Node& e);
/**
* Expand the definitions in a term or formula. No other
@@ -520,40 +524,12 @@ class CVC4_PUBLIC SmtEngine
* @throw ModalException, TypeCheckingException, LogicException,
* UnsafeInterruptException
*/
- Expr getValue(const Expr& e) const;
+ Node getValue(const Node& e) const;
/**
* Same as getValue but for a vector of expressions
*/
- std::vector<Expr> getValues(const std::vector<Expr>& exprs);
-
- /**
- * Add a function to the set of expressions whose value is to be
- * later returned by a call to getAssignment(). The expression
- * should be a Boolean zero-ary defined function or a Boolean
- * variable. Rather than throwing a ModalException on modal
- * failures (not in interactive mode or not producing assignments),
- * this function returns true if the expression was added and false
- * if this request was ignored.
- */
- bool addToAssignment(const Expr& e);
-
- /**
- * Get the assignment (only if immediately preceded by a SAT or
- * NOT_ENTAILED query). Only permitted if the SmtEngine is set to
- * operate interactively and produce-assignments is on.
- */
- std::vector<std::pair<Expr, Expr> > getAssignment();
-
- /**
- * Get the last proof (only if immediately preceded by an UNSAT or ENTAILED
- * query). Only permitted if CVC4 was built with proof support and
- * produce-proofs is on.
- *
- * The Proof object is owned by this SmtEngine until the SmtEngine is
- * destroyed.
- */
- const Proof& getProof();
+ std::vector<Node> getValues(const std::vector<Node>& exprs);
/** Print all instantiations made by the quantifiers module. */
void printInstantiations(std::ostream& out);
@@ -567,26 +543,26 @@ class CVC4_PUBLIC SmtEngine
/**
* Get synth solution.
*
- * This method returns true if we are in a state immediately preceeded by
+ * This method returns true if we are in a state immediately preceded by
* a successful call to checkSynth.
*
- * This method adds entries to sol_map that map functions-to-synthesize with
+ * This method adds entries to solMap that map functions-to-synthesize with
* their solutions, for all active conjectures. This should be called
* immediately after the solver answers unsat for sygus input.
*
* Specifically, given a sygus conjecture of the form
* exists x1...xn. forall y1...yn. P( x1...xn, y1...yn )
* where x1...xn are second order bound variables, we map each xi to
- * lambda term in sol_map such that
- * forall y1...yn. P( sol_map[x1]...sol_map[xn], y1...yn )
+ * lambda term in solMap such that
+ * forall y1...yn. P( solMap[x1]...solMap[xn], y1...yn )
* is a valid formula.
*/
- bool getSynthSolutions(std::map<Expr, Expr>& sol_map);
+ bool getSynthSolutions(std::map<Node, Node>& solMap);
/**
* Do quantifier elimination.
*
- * This function takes as input a quantified formula e
+ * This function takes as input a quantified formula q
* of the form:
* Q x1...xn. P( x1...xn, y1...yn )
* where P( x1...xn, y1...yn ) is a quantifier-free
@@ -598,20 +574,20 @@ class CVC4_PUBLIC SmtEngine
* the current set of formulas A asserted to this SmtEngine :
*
* If doFull = true, then
- * - ( A ^ e ) and ( A ^ ret ) are equivalent
+ * - ( A ^ q ) and ( A ^ ret ) are equivalent
* - ret is quantifier-free formula containing
* only free variables in y1...yn.
*
* If doFull = false, then
- * - (A ^ e) => (A ^ ret) if Q is forall or
- * (A ^ ret) => (A ^ e) if Q is exists,
+ * - (A ^ q) => (A ^ ret) if Q is forall or
+ * (A ^ ret) => (A ^ q) if Q is exists,
* - ret is quantifier-free formula containing
* only free variables in y1...yn,
* - If Q is exists, let A^Q_n be the formula
* A ^ ~ret^Q_1 ^ ... ^ ~ret^Q_n
* where for each i=1,...n, formula ret^Q_i
* is the result of calling doQuantifierElimination
- * for e with the set of assertions A^Q_{i-1}.
+ * for q with the set of assertions A^Q_{i-1}.
* Similarly, if Q is forall, then let A^Q_n be
* A ^ ret^Q_1 ^ ... ^ ret^Q_n
* where ret^Q_i is the same as above.
@@ -631,7 +607,7 @@ class CVC4_PUBLIC SmtEngine
*
* throw@ Exception
*/
- Expr doQuantifierElimination(const Expr& e, bool doFull, bool strict = true);
+ Node getQuantifierElimination(Node q, bool doFull, bool strict = true);
/**
* This method asks this SMT engine to find an interpolant with respect to
@@ -645,10 +621,12 @@ class CVC4_PUBLIC SmtEngine
* This method invokes a separate copy of the SMT engine for solving the
* corresponding sygus problem for generating such a solution.
*/
- bool getInterpol(const Expr& conj, const Type& grammarType, Expr& interpol);
+ bool getInterpol(const Node& conj,
+ const TypeNode& grammarType,
+ Node& interpol);
/** Same as above, but without user-provided grammar restrictions */
- bool getInterpol(const Expr& conj, Expr& interpol);
+ bool getInterpol(const Node& conj, Node& interpol);
/**
* This method asks this SMT engine to find an abduct with respect to the
@@ -671,21 +649,9 @@ class CVC4_PUBLIC SmtEngine
* Get list of quantified formulas that were instantiated on the last call
* to check-sat.
*/
- void getInstantiatedQuantifiedFormulas(std::vector<Expr>& qs);
+ void getInstantiatedQuantifiedFormulas(std::vector<Node>& qs);
/**
- * Get instantiations for quantified formula q.
- *
- * If q was a quantified formula that was instantiated on the last call to
- * check-sat (i.e. q is returned as part of the vector in the method
- * getInstantiatedQuantifiedFormulas above), then the list of instantiations
- * of that formula that were generated are added to insts.
- *
- * In particular, if q is of the form forall x. P(x), then insts is a list
- * of formulas of the form P(t1), ..., P(tn).
- */
- void getInstantiations(Expr q, std::vector<Expr>& insts);
- /**
* Get instantiation term vectors for quantified formula q.
*
* This method is similar to above, but in the example above, we return the
@@ -694,8 +660,8 @@ class CVC4_PUBLIC SmtEngine
* Notice that these are not guaranteed to come in the same order as the
* instantiation lemmas above.
*/
- void getInstantiationTermVectors(Expr q,
- std::vector<std::vector<Expr> >& tvecs);
+ void getInstantiationTermVectors(Node q,
+ std::vector<std::vector<Node>>& tvecs);
/**
* Get an unsatisfiable core (only if immediately preceded by an UNSAT or
@@ -708,7 +674,7 @@ class CVC4_PUBLIC SmtEngine
* Get the current set of assertions. Only permitted if the
* SmtEngine is set to operate interactively.
*/
- std::vector<Expr> getAssertions();
+ std::vector<Node> getAssertions();
/**
* Push a user-level context.
@@ -775,18 +741,14 @@ class CVC4_PUBLIC SmtEngine
void setResourceLimit(unsigned long units, bool cumulative = false);
/**
- * Set a time limit for SmtEngine operations.
+ * Set a per-call time limit for SmtEngine operations.
*
- * A cumulative and non-cumulative (per-call) time limit can be
- * set at the same time. A call to setTimeLimit() with
- * cumulative==true replaces any cumulative time limit currently
- * in effect; a call with cumulative==false replaces any per-call
- * time limit currently in effect. Resource limits can be set in
- * addition to time limits; the SmtEngine obeys both. That means
- * that up to four independent limits can control the SmtEngine
- * at the same time.
+ * A per-call time limit can be set at the same time and replaces
+ * any per-call time limit currently in effect.
+ * Resource limits (either per-call or cumulative) can be set in
+ * addition to a time limit; the SmtEngine obeys all three of them.
*
- * Note that the cumulative timer only ticks away when one of the
+ * Note that the per-call timer only ticks away when one of the
* SmtEngine's workhorse functions (things like assertFormula(),
* checkEntailed(), checkSat(), and simplify()) are running.
* Between calls, the timer is still.
@@ -800,11 +762,8 @@ class CVC4_PUBLIC SmtEngine
* We reserve the right to change this in the future.
*
* @param millis the time limit in milliseconds, or 0 for no limit
- * @param cumulative whether this time limit is to be a cumulative
- * time limit for all remaining calls into the SmtEngine (true), or
- * whether it's a per-call time limit (false); the default is false
*/
- void setTimeLimit(unsigned long millis, bool cumulative = false);
+ void setTimeLimit(unsigned long millis);
/**
* Get the current resource usage count for this SmtEngine. This
@@ -826,16 +785,6 @@ class CVC4_PUBLIC SmtEngine
*/
unsigned long getResourceRemaining() const;
- /**
- * Get the remaining number of milliseconds that can be consumed by
- * this SmtEngine according to the currently-set cumulative time limit.
- * If there is not a cumulative resource limit set, this function
- * throws a ModalException.
- *
- * @throw ModalException
- */
- unsigned long getTimeRemaining() const;
-
/** Permit access to the underlying ExprManager. */
ExprManager* getExprManager() const { return d_exprManager; }
@@ -852,12 +801,6 @@ class CVC4_PUBLIC SmtEngine
void safeFlushStatistics(int fd) const;
/**
- * Returns the most recent result of checkSat/checkEntailed or
- * (set-info :status).
- */
- Result getStatusOfLastCommand() const { return d_status; }
-
- /**
* Set user attribute.
* This function is called when an attribute is set by a user.
* In SMT-LIBv2 this is done via the syntax (! expr :attr)
@@ -867,57 +810,60 @@ class CVC4_PUBLIC SmtEngine
const std::vector<Expr>& expr_values,
const std::string& str_value);
- /** Set print function in model. */
- void setPrintFuncInModel(Expr f, bool p);
+ /** Get the options object (const and non-const versions) */
+ Options& getOptions();
+ const Options& getOptions() const;
- /**
- * Check and throw a ModalException if the SmtEngine has been fully
- * initialized.
- *
- * throw@ ModalException
- */
- void beforeSearch();
+ /** Get a pointer to the UserContext owned by this SmtEngine. */
+ context::UserContext* getUserContext();
- /**
- * Get expression name.
- *
- * Return true if given expressoion has a name in the current context.
- * If it returns true, the name of expression 'e' is stored in 'name'.
- */
- bool getExpressionName(Expr e, std::string& name) const;
+ /** Get a pointer to the Context owned by this SmtEngine. */
+ context::Context* getContext();
+
+ /** Get a pointer to the TheoryEngine owned by this SmtEngine. */
+ TheoryEngine* getTheoryEngine();
+
+ /** Get a pointer to the PropEngine owned by this SmtEngine. */
+ prop::PropEngine* getPropEngine();
/**
- * Set name of given expression 'e' to 'name'.
- *
- * This information is user-context-dependent.
- * If 'e' already has a name, it is overwritten.
+ * Get a pointer to the ProofManager owned by this SmtEngine.
+ * TODO (project #37): this is the old proof manager and will be deleted
*/
- void setExpressionName(Expr e, const std::string& name);
-
- /** Get the options object (const and non-const versions) */
- Options& getOptions();
- const Options& getOptions() const;
+ ProofManager* getProofManager() { return d_proofManager.get(); };
/** Get the resource manager of this SMT engine */
ResourceManager* getResourceManager();
+ /** Permit access to the underlying dump manager. */
+ smt::DumpManager* getDumpManager();
+
+ /** Get the printer used by this SMT engine */
+ const Printer* getPrinter() const;
+
+ /** Get the output manager for this SMT engine */
+ OutputManager& getOutputManager();
+
+ /** Get a pointer to the Rewriter owned by this SmtEngine. */
+ theory::Rewriter* getRewriter() { return d_rewriter.get(); }
+
+ /** The type of our internal map of defined functions */
+ using DefinedFunctionMap =
+ context::CDHashMap<Node, smt::DefinedFunction, NodeHashFunction>;
+
+ /** Get the defined function map */
+ DefinedFunctionMap* getDefinedFunctionMap() { return d_definedFunctions; }
/**
* Get expanded assertions.
*
* Return the set of assertions, after expanding definitions.
*/
- std::vector<Expr> getExpandedAssertions();
+ std::vector<Node> getExpandedAssertions();
/* ....................................................................... */
private:
/* ....................................................................... */
-
- /** The type of our internal map of defined functions */
- typedef context::CDHashMap<Node, smt::DefinedFunction, NodeHashFunction>
- DefinedFunctionMap;
/** The type of our internal assertion list */
typedef context::CDList<Node> AssertionList;
- /** The type of our internal assignment set */
- typedef context::CDHashSet<Node, NodeHashFunction> AssignmentSet;
// disallow copy/assignment
SmtEngine(const SmtEngine&) = delete;
@@ -926,24 +872,6 @@ class CVC4_PUBLIC SmtEngine
/** Set solver instance that owns this SmtEngine. */
void setSolver(api::Solver* solver) { d_solver = solver; }
- /** Get a pointer to the TheoryEngine owned by this SmtEngine. */
- TheoryEngine* getTheoryEngine() { return d_theoryEngine.get(); }
-
- /** Get a pointer to the PropEngine owned by this SmtEngine. */
- prop::PropEngine* getPropEngine() { return d_propEngine.get(); }
-
- /** Get a pointer to the UserContext owned by this SmtEngine. */
- context::UserContext* getUserContext() { return d_userContext.get(); };
-
- /** Get a pointer to the Context owned by this SmtEngine. */
- context::Context* getContext() { return d_context.get(); };
-
- /** Get a pointer to the ProofManager owned by this SmtEngine. */
- ProofManager* getProofManager() { return d_proofManager.get(); };
-
- /** Get a pointer to the Rewriter owned by this SmtEngine. */
- theory::Rewriter* getRewriter() { return d_rewriter.get(); }
-
/** Get a pointer to the StatisticsRegistry owned by this SmtEngine. */
StatisticsRegistry* getStatisticsRegistry()
{
@@ -951,11 +879,6 @@ class CVC4_PUBLIC SmtEngine
};
/**
- * Check that a generated proof (via getProof()) checks.
- */
- void checkProof();
-
- /**
* Internal method to get an unsatisfiable core (only if immediately preceded
* by an UNSAT or ENTAILED query). Only permitted if CVC4 was built with
* unsat-core support and produce-unsat-cores is on. Does not dump the
@@ -975,65 +898,17 @@ class CVC4_PUBLIC SmtEngine
void checkModel(bool hardFailure = true);
/**
- * Check that a solution to a synthesis conjecture is indeed a solution.
- *
- * The check is made by determining if the negation of the synthesis
- * conjecture in which the functions-to-synthesize have been replaced by the
- * synthesized solutions, which is a quantifier-free formula, is
- * unsatisfiable. If not, then the found solutions are wrong.
- */
- void checkSynthSolution();
-
- /**
* Check that a solution to an interpolation problem is indeed a solution.
*
* The check is made by determining that the assertions imply the solution of
* the interpolation problem (interpol), and the solution implies the goal
* (conj). If these criteria are not met, an internal error is thrown.
*/
- void checkInterpol(Expr interpol,
- const std::vector<Expr>& easserts,
+ void checkInterpol(Node interpol,
+ const std::vector<Node>& easserts,
const Node& conj);
/**
- * Check that a solution to an abduction conjecture is indeed a solution.
- *
- * The check is made by determining that the assertions conjoined with the
- * solution to the abduction problem (a) is SAT, and the assertions conjoined
- * with the abduct and the goal is UNSAT. If these criteria are not met, an
- * internal error is thrown.
- */
- void checkAbduct(Node a);
-
- /**
- * Postprocess a value for output to the user. Involves doing things
- * like turning datatypes back into tuples, length-1-bitvectors back
- * into booleans, etc.
- */
- Node postprocess(TNode n, TypeNode expectedType) const;
-
- /**
- * This is something of an "init" procedure, but is idempotent; call
- * as often as you like. Should be called whenever the final options
- * and logic for the problem are set (at least, those options that are
- * not permitted to change after assertions and queries are made).
- */
- void finalOptionsAreSet();
-
- /**
- * Sets that the problem has been extended. This sets the smt mode of the
- * solver to SMT_MODE_ASSERT, and clears the list of assumptions from the
- * previous call to checkSatisfiability.
- */
- void setProblemExtended();
-
- /**
- * Create theory engine, prop engine, decision engine. Called by
- * finalOptionsAreSet()
- */
- void finishInit();
-
- /**
* This is called by the destructor, just before destroying the
* PropEngine, TheoryEngine, and DecisionEngine (in that order). It
* is important because there are destruction ordering issues
@@ -1042,12 +917,6 @@ class CVC4_PUBLIC SmtEngine
void shutdown();
/**
- * Full check of consistency in current context. Returns true iff
- * consistent.
- */
- Result check();
-
- /**
* Quick check of consistency in current context: calls
* processAssertionList() then look for inconsistency (based only on
* that).
@@ -1055,30 +924,47 @@ class CVC4_PUBLIC SmtEngine
Result quickCheck();
/**
- * Get the model, if it is available and return a pointer to it
+ * Get the (SMT-level) model pointer, if we are in SAT mode. Otherwise,
+ * return nullptr.
*
- * This ensures that the model is currently available, which means that
- * CVC4 is producing models, and is in "SAT mode", otherwise an exception
- * is thrown.
+ * This ensures that the underlying theory model of the SmtSolver maintained
+ * by this class is currently available, which means that CVC4 is producing
+ * models, and is in "SAT mode", otherwise a recoverable exception is thrown.
*
* The flag c is used for giving an error message to indicate the context
* this method was called.
*/
- theory::TheoryModel* getAvailableModel(const char* c) const;
+ smt::Model* getAvailableModel(const char* c) const;
+ // --------------------------------------- callbacks from the state
/**
- * Fully type-check the argument, and also type-check that it's
- * actually Boolean.
- *
- * throw@ TypeCheckingException
+ * Notify push pre, which is called just before the user context of the state
+ * pushes. This processes all pending assertions.
*/
- void ensureBoolean(const Node& n);
-
- void internalPush();
-
- void internalPop(bool immediate = false);
-
- void doPendingPops();
+ void notifyPushPre();
+ /**
+ * Notify push post, which is called just after the user context of the state
+ * pushes. This performs a push on the underlying prop engine.
+ */
+ void notifyPushPost();
+ /**
+ * Notify pop pre, which is called just before the user context of the state
+ * pops. This performs a pop on the underlying prop engine.
+ */
+ void notifyPopPre();
+ /**
+ * Notify post solve pre, which is called once per check-sat query. It
+ * is triggered when the first d_state.doPendingPops() is issued after the
+ * check-sat. This method is called before the contexts pop in the method
+ * doPendingPops.
+ */
+ void notifyPostSolvePre();
+ /**
+ * Same as above, but after contexts are popped. This calls the postsolve
+ * method of the underlying TheoryEngine.
+ */
+ void notifyPostSolvePost();
+ // --------------------------------------- end callbacks from the state
/**
* Internally handle the setting of a logic. This function should always
@@ -1086,70 +972,84 @@ class CVC4_PUBLIC SmtEngine
*/
void setLogicInternal();
- /**
- * Add to Model command. This is used for recording a command
- * that should be reported during a get-model call.
+ /*
+ * Check satisfiability (used to check satisfiability and entailment).
*/
- void addToModelCommandAndDump(const Command& c,
- uint32_t flags = 0,
- bool userVisible = true,
- const char* dumpTag = "declarations");
-
- /* Check satisfiability (used to check satisfiability and entailment). */
- Result checkSatisfiability(const Expr& assumption,
- bool inUnsatCore,
- bool isEntailmentCheck);
- Result checkSatisfiability(const std::vector<Expr>& assumptions,
- bool inUnsatCore,
- bool isEntailmentCheck);
+ Result checkSatInternal(const std::vector<Node>& assumptions,
+ bool inUnsatCore,
+ bool isEntailmentCheck);
/**
* Check that all Expr in formals are of BOUND_VARIABLE kind, where func is
* the function that the formal argument list is for. This method is used
* as a helper function when defining (recursive) functions.
*/
- void debugCheckFormals(const std::vector<Expr>& formals, Expr func);
+ void debugCheckFormals(const std::vector<Node>& formals, Node func);
/**
* Checks whether formula is a valid function body for func whose formal
* argument list is stored in formals. This method is
* used as a helper function when defining (recursive) functions.
*/
- void debugCheckFunctionBody(Expr formula,
- const std::vector<Expr>& formals,
- Expr func);
+ void debugCheckFunctionBody(Node formula,
+ const std::vector<Node>& formals,
+ Node func);
/**
* Helper method to obtain both the heap and nil from the solver. Returns a
* std::pair where the first element is the heap expression and the second
* element is the nil expression.
*/
- std::pair<Expr, Expr> getSepHeapAndNilExpr();
+ std::pair<Node, Node> getSepHeapAndNilExpr();
/* Members -------------------------------------------------------------- */
/** Solver instance that owns this SmtEngine instance. */
api::Solver* d_solver = nullptr;
- /** Expr manager context */
- std::unique_ptr<context::Context> d_context;
- /** User level context */
- std::unique_ptr<context::UserContext> d_userContext;
- /** The context levels of user pushes */
- std::vector<int> d_userLevels;
+ /**
+ * The state of this SmtEngine, which is responsible for maintaining which
+ * SMT mode we are in, the contexts, the last result, etc.
+ */
+ std::unique_ptr<smt::SmtEngineState> d_state;
/** Our expression manager */
ExprManager* d_exprManager;
/** Our internal expression/node manager */
NodeManager* d_nodeManager;
+ /** Abstract values */
+ std::unique_ptr<smt::AbstractValues> d_absValues;
+ /** Assertions manager */
+ std::unique_ptr<smt::Assertions> d_asserts;
+ /** The dump manager */
+ std::unique_ptr<smt::DumpManager> d_dumpm;
+ /** Resource out listener */
+ std::unique_ptr<smt::ResourceOutListener> d_routListener;
+ /** Node manager listener */
+ std::unique_ptr<smt::SmtNodeManagerListener> d_snmListener;
+
+ /** The SMT solver */
+ std::unique_ptr<smt::SmtSolver> d_smtSolver;
+
+ /** The (old) proof manager TODO (project #37): delete this */
+ std::unique_ptr<ProofManager> d_proofManager;
+ /**
+ * The SMT-level model object, which contains information about how to
+ * print the model, as well as a pointer to the underlying TheoryModel
+ * implementation maintained by the SmtSolver.
+ */
+ std::unique_ptr<smt::Model> d_model;
- /** The theory engine */
- std::unique_ptr<TheoryEngine> d_theoryEngine;
- /** The propositional engine */
- std::unique_ptr<prop::PropEngine> d_propEngine;
+ /**
+ * The utility used for checking models
+ */
+ std::unique_ptr<smt::CheckModels> d_checkModels;
- /** The proof manager */
- std::unique_ptr<ProofManager> d_proofManager;
+ /**
+ * The proof manager, which manages all things related to checking,
+ * processing, and printing proofs.
+ */
+ std::unique_ptr<smt::PfManager> d_pfManager;
/**
* The rewriter associated with this SmtEngine. We have a different instance
@@ -1162,62 +1062,15 @@ class CVC4_PUBLIC SmtEngine
/** An index of our defined functions */
DefinedFunctionMap* d_definedFunctions;
+ /** The solver for sygus queries */
+ std::unique_ptr<smt::SygusSolver> d_sygusSolver;
+
/** The solver for abduction queries */
std::unique_ptr<smt::AbductionSolver> d_abductSolver;
-
- /**
- * The assertion list (before any conversion) for supporting
- * getAssertions(). Only maintained if in incremental mode.
- */
- AssertionList* d_assertionList;
-
- /**
- * List of lemmas generated for global recursive function definitions. We
- * assert this list of definitions in each check-sat call.
- */
- std::unique_ptr<std::vector<Node>> d_globalDefineFunRecLemmas;
-
- /**
- * The list of assumptions from the previous call to checkSatisfiability.
- * Note that if the last call to checkSatisfiability was an entailment check,
- * i.e., a call to checkEntailed(a1, ..., an), then d_assumptions contains
- * one single assumption ~(a1 AND ... AND an).
- */
- std::vector<Expr> d_assumptions;
-
- /**
- * List of items for which to retrieve values using getAssignment().
- */
- AssignmentSet* d_assignments;
-
- /**
- * A list of commands that should be in the Model globally (i.e.,
- * regardless of push/pop). Only maintained if produce-models option
- * is on.
- */
- std::vector<Command*> d_modelGlobalCommands;
-
- /**
- * A list of commands that should be in the Model locally (i.e.,
- * it is context-dependent on push/pop). Only maintained if
- * produce-models option is on.
- */
- smt::CommandList* d_modelCommands;
-
- /**
- * A vector of declaration commands waiting to be dumped out.
- * Once the SmtEngine is fully initialized, we'll dump them.
- * This ensures the declarations come after the set-logic and
- * any necessary set-option commands are dumped.
- */
- std::vector<Command*> d_dumpCommands;
-
- /**
- * A vector of command definitions to be imported in the new
- * SmtEngine when checking unsat-cores.
- */
- std::vector<Command*> d_defineCommands;
-
+ /** The solver for interpolation queries */
+ std::unique_ptr<smt::InterpolationSolver> d_interpolSolver;
+ /** The solver for quantifier elimination queries */
+ std::unique_ptr<smt::QuantElimSolver> d_quantElimSolver;
/**
* The logic we're in. This logic may be an extension of the logic set by the
* user.
@@ -1236,104 +1089,42 @@ class CVC4_PUBLIC SmtEngine
bool d_isInternalSubsolver;
/**
- * Number of internal pops that have been deferred.
- */
- unsigned d_pendingPops;
-
- /**
- * Whether or not this SmtEngine is fully initialized (post-construction).
- * This post-construction initialization is automatically triggered by the
- * use of the SmtEngine; e.g. when the first formula is asserted, a call
- * to simplify() is issued, a scope is pushed, etc.
- */
- bool d_fullyInited;
-
- /**
- * Whether or not a checkEntailed() or checkSatisfiability() has already been
- * made through this SmtEngine. If true, and incrementalSolving is false,
- * then attempting an additional checkEntailed() or checkSat() will fail with
- * a ModalException.
- */
- bool d_queryMade;
-
- /**
- * Internal status flag to indicate whether we've sent a theory
- * presolve() notification and need to match it with a postsolve().
- */
- bool d_needPostsolve;
-
- /*
- * Whether to call theory preprocessing during simplification - on
- * by default* but gets turned off if arithRewriteEq is on
- */
- bool d_earlyTheoryPP;
-
- /*
- * Whether we did a global negation of the formula.
- */
- bool d_globalNegation;
-
- /**
- * Most recent result of last checkSatisfiability/checkEntailed or
- * (set-info :status).
- */
- Result d_status;
-
- /**
- * The expected status of the next satisfiability check.
- */
- Result d_expectedStatus;
-
- SmtMode d_smtMode;
-
- /**
- * The input file name (if any) or the name set through setInfo (if any)
- */
- std::string d_filename;
-
- /**
* Verbosity of various commands.
*/
std::map<std::string, Integer> d_commandVerbosity;
- /**
- * A private utility class to SmtEngine.
- */
- std::unique_ptr<smt::SmtEnginePrivate> d_private;
-
+ /** The statistics registry */
std::unique_ptr<StatisticsRegistry> d_statisticsRegistry;
+ /** The statistics class */
std::unique_ptr<smt::SmtEngineStatistics> d_stats;
/** The options object */
Options d_options;
+
+ /** the output manager for commands */
+ mutable OutputManager d_outMgr;
+
/**
* Manager for limiting time and abstract resource usage.
*/
std::unique_ptr<ResourceManager> d_resourceManager;
/**
+ * The options manager, which is responsible for implementing core options
+ * such as those related to time outs and printing. It is also responsible
+ * for set default options based on the logic.
+ */
+ std::unique_ptr<smt::OptionsManager> d_optm;
+ /**
+ * The preprocessor.
+ */
+ std::unique_ptr<smt::Preprocessor> d_pp;
+ /**
* The global scope object. Upon creation of this SmtEngine, it becomes the
* SmtEngine in scope. It says the SmtEngine in scope until it is destructed,
* or another SmtEngine is created.
*/
std::unique_ptr<smt::SmtScope> d_scope;
- /*---------------------------- sygus commands ---------------------------*/
-
- /**
- * Set sygus conjecture is stale. The sygus conjecture is stale if either:
- * (1) no sygus conjecture has been added as an assertion to this SMT engine,
- * (2) there is a sygus conjecture that has been added as an assertion
- * internally to this SMT engine, and there have been further calls such that
- * the asserted conjecture is no longer up-to-date.
- *
- * This method should be called when new sygus constraints are asserted and
- * when functions-to-synthesize are declared. This function pops a user
- * context if we are in incremental mode and the sygus conjecture was
- * previously not stale.
- */
- void setSygusConjectureStale();
-
- /*------------------------- end of sygus commands ------------------------*/
}; /* class SmtEngine */
/* -------------------------------------------------------------------------- */
diff --git a/src/smt/smt_engine_scope.cpp b/src/smt/smt_engine_scope.cpp
index 1e9c91767..a876a59d3 100644
--- a/src/smt/smt_engine_scope.cpp
+++ b/src/smt/smt_engine_scope.cpp
@@ -2,10 +2,10 @@
/*! \file smt_engine_scope.cpp
** \verbatim
** Top contributors (to current version):
- ** Andres Noetzli, Morgan Deters, Mathias Preiner
+ ** Andres Noetzli, Morgan Deters, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,7 +20,6 @@
#include "base/check.h"
#include "base/configuration_private.h"
#include "base/output.h"
-#include "proof/proof.h"
#include "smt/smt_engine.h"
namespace CVC4 {
diff --git a/src/smt/smt_engine_scope.h b/src/smt/smt_engine_scope.h
index 5cccde9b8..105ce3632 100644
--- a/src/smt/smt_engine_scope.h
+++ b/src/smt/smt_engine_scope.h
@@ -2,10 +2,10 @@
/*! \file smt_engine_scope.h
** \verbatim
** Top contributors (to current version):
- ** Andres Noetzli, Morgan Deters, Tim King
+ ** Andrew Reynolds, Andres Noetzli, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/smt/smt_engine_state.cpp b/src/smt/smt_engine_state.cpp
new file mode 100644
index 000000000..dada78d9a
--- /dev/null
+++ b/src/smt/smt_engine_state.cpp
@@ -0,0 +1,312 @@
+/********************* */
+/*! \file smt_engine_state.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Morgan Deters, Aina Niemetz
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utility for maintaining the state of the SMT engine.
+ **/
+
+#include "smt/smt_engine_state.h"
+
+#include "options/smt_options.h"
+#include "smt/smt_engine.h"
+
+namespace CVC4 {
+namespace smt {
+
+SmtEngineState::SmtEngineState(SmtEngine& smt)
+ : d_smt(smt),
+ d_context(new context::Context()),
+ d_userContext(new context::UserContext()),
+ d_pendingPops(0),
+ d_fullyInited(false),
+ d_queryMade(false),
+ d_needPostsolve(false),
+ d_status(),
+ d_expectedStatus(),
+ d_smtMode(SmtMode::START)
+{
+}
+
+void SmtEngineState::notifyExpectedStatus(const std::string& status)
+{
+ Assert(status == "sat" || status == "unsat" || status == "unknown")
+ << "SmtEngineState::notifyExpectedStatus: unexpected status string "
+ << status;
+ d_expectedStatus = Result(status, d_filename);
+}
+
+void SmtEngineState::notifyResetAssertions()
+{
+ doPendingPops();
+ while (!d_userLevels.empty())
+ {
+ userPop();
+ }
+ // Remember the global push/pop around everything when beyond Start mode
+ // (see solver execution modes in the SMT-LIB standard)
+ Assert(d_userLevels.size() == 0 && d_userContext->getLevel() == 1);
+ popto(0);
+}
+
+void SmtEngineState::notifyCheckSat(bool hasAssumptions)
+{
+ // process the pending pops
+ doPendingPops();
+ if (d_queryMade && !options::incrementalSolving())
+ {
+ throw ModalException(
+ "Cannot make multiple queries unless "
+ "incremental solving is enabled "
+ "(try --incremental)");
+ }
+
+ // Note that a query has been made and we are in assert mode
+ d_queryMade = true;
+ d_smtMode = SmtMode::ASSERT;
+
+ // push if there are assumptions
+ if (hasAssumptions)
+ {
+ internalPush();
+ }
+}
+
+void SmtEngineState::notifyCheckSatResult(bool hasAssumptions, Result r)
+{
+ d_needPostsolve = true;
+
+ // Pop the context
+ if (hasAssumptions)
+ {
+ internalPop();
+ }
+
+ // Remember the status
+ d_status = r;
+ // Check against expected status
+ if (!d_expectedStatus.isUnknown() && !d_status.isUnknown()
+ && d_status != d_expectedStatus)
+ {
+ CVC4_FATAL() << "Expected result " << d_expectedStatus << " but got "
+ << d_status;
+ }
+ // clear expected status
+ d_expectedStatus = Result();
+ // Update the SMT mode
+ switch (d_status.asSatisfiabilityResult().isSat())
+ {
+ case Result::UNSAT: d_smtMode = SmtMode::UNSAT; break;
+ case Result::SAT: d_smtMode = SmtMode::SAT; break;
+ default: d_smtMode = SmtMode::SAT_UNKNOWN;
+ }
+}
+
+void SmtEngineState::notifyGetAbduct(bool success)
+{
+ if (success)
+ {
+ // successfully generated an abduct, update to abduct state
+ d_smtMode = SmtMode::ABDUCT;
+ }
+ else
+ {
+ // failed, we revert to the assert state
+ d_smtMode = SmtMode::ASSERT;
+ }
+}
+
+void SmtEngineState::notifyGetInterpol(bool success)
+{
+ if (success)
+ {
+ // successfully generated an interpolant, update to interpol state
+ d_smtMode = SmtMode::INTERPOL;
+ }
+ else
+ {
+ // failed, we revert to the assert state
+ d_smtMode = SmtMode::ASSERT;
+ }
+}
+
+void SmtEngineState::setup()
+{
+ // push a context
+ push();
+}
+
+void SmtEngineState::finishInit()
+{
+ // set the flag to remember that we are fully initialized
+ d_fullyInited = true;
+}
+
+void SmtEngineState::shutdown()
+{
+ doPendingPops();
+
+ while (options::incrementalSolving() && d_userContext->getLevel() > 1)
+ {
+ internalPop(true);
+ }
+}
+
+void SmtEngineState::cleanup()
+{
+ // pop to level zero
+ popto(0);
+}
+
+void SmtEngineState::setFilename(const std::string& filename)
+{
+ d_filename = filename;
+}
+
+void SmtEngineState::userPush()
+{
+ if (!options::incrementalSolving())
+ {
+ throw ModalException(
+ "Cannot push when not solving incrementally (use --incremental)");
+ }
+ // The problem isn't really "extended" yet, but this disallows
+ // get-model after a push, simplifying our lives somewhat and
+ // staying symmetric with pop.
+ d_smtMode = SmtMode::ASSERT;
+
+ d_userLevels.push_back(d_userContext->getLevel());
+ internalPush();
+ Trace("userpushpop") << "SmtEngineState: pushed to level "
+ << d_userContext->getLevel() << std::endl;
+}
+
+void SmtEngineState::userPop()
+{
+ if (!options::incrementalSolving())
+ {
+ throw ModalException(
+ "Cannot pop when not solving incrementally (use --incremental)");
+ }
+ if (d_userLevels.size() == 0)
+ {
+ throw ModalException("Cannot pop beyond the first user frame");
+ }
+ // 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_smtMode = SmtMode::ASSERT;
+
+ AlwaysAssert(d_userContext->getLevel() > 0);
+ AlwaysAssert(d_userLevels.back() < d_userContext->getLevel());
+ while (d_userLevels.back() < d_userContext->getLevel())
+ {
+ internalPop(true);
+ }
+ d_userLevels.pop_back();
+}
+
+void SmtEngineState::push()
+{
+ d_userContext->push();
+ d_context->push();
+}
+
+void SmtEngineState::pop()
+{
+ d_userContext->pop();
+ d_context->pop();
+}
+
+void SmtEngineState::popto(int toLevel)
+{
+ d_context->popto(toLevel);
+ d_userContext->popto(toLevel);
+}
+
+context::UserContext* SmtEngineState::getUserContext()
+{
+ return d_userContext.get();
+}
+
+context::Context* SmtEngineState::getContext() { return d_context.get(); }
+
+Result SmtEngineState::getStatus() const { return d_status; }
+
+bool SmtEngineState::isFullyInited() const { return d_fullyInited; }
+bool SmtEngineState::isFullyReady() const
+{
+ return d_fullyInited && d_pendingPops == 0;
+}
+bool SmtEngineState::isQueryMade() const { return d_queryMade; }
+size_t SmtEngineState::getNumUserLevels() const { return d_userLevels.size(); }
+
+SmtMode SmtEngineState::getMode() const { return d_smtMode; }
+
+const std::string& SmtEngineState::getFilename() const { return d_filename; }
+
+void SmtEngineState::internalPush()
+{
+ Assert(d_fullyInited);
+ Trace("smt") << "SmtEngineState::internalPush()" << std::endl;
+ doPendingPops();
+ if (options::incrementalSolving())
+ {
+ // notifies the SmtEngine to process the assertions immediately
+ d_smt.notifyPushPre();
+ d_userContext->push();
+ // the context push is done inside of the SAT solver
+ d_smt.notifyPushPost();
+ }
+}
+
+void SmtEngineState::internalPop(bool immediate)
+{
+ Assert(d_fullyInited);
+ Trace("smt") << "SmtEngineState::internalPop()" << std::endl;
+ if (options::incrementalSolving())
+ {
+ ++d_pendingPops;
+ }
+ if (immediate)
+ {
+ doPendingPops();
+ }
+}
+
+void SmtEngineState::doPendingPops()
+{
+ Trace("smt") << "SmtEngineState::doPendingPops()" << std::endl;
+ Assert(d_pendingPops == 0 || options::incrementalSolving());
+ // check to see if a postsolve() is pending
+ if (d_needPostsolve)
+ {
+ d_smt.notifyPostSolvePre();
+ }
+ while (d_pendingPops > 0)
+ {
+ // the context pop is done inside of the SAT solver
+ d_smt.notifyPopPre();
+ // pop the context
+ d_userContext->pop();
+ --d_pendingPops;
+ // no need for pop post (for now)
+ }
+ if (d_needPostsolve)
+ {
+ d_smt.notifyPostSolvePost();
+ d_needPostsolve = false;
+ }
+}
+
+} // namespace smt
+} // namespace CVC4
diff --git a/src/smt/smt_engine_state.h b/src/smt/smt_engine_state.h
new file mode 100644
index 000000000..f033be031
--- /dev/null
+++ b/src/smt/smt_engine_state.h
@@ -0,0 +1,266 @@
+/********************* */
+/*! \file smt_engine_state.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Aina Niemetz, Morgan Deters
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utility for maintaining the state of the SMT engine.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__SMT__SMT_ENGINE_STATE_H
+#define CVC4__SMT__SMT_ENGINE_STATE_H
+
+#include <string>
+
+#include "context/context.h"
+#include "smt/smt_mode.h"
+#include "util/result.h"
+
+namespace CVC4 {
+
+class SmtEngine;
+
+namespace smt {
+
+/**
+ * This utility is responsible for maintaining the basic state of the SmtEngine.
+ *
+ * It has no concept of anything related to the assertions of the SmtEngine,
+ * or more generally it does not depend on Node.
+ *
+ * This class has three sets of interfaces:
+ * (1) notification methods that are used by SmtEngine to notify when an event
+ * occurs (e.g. the beginning of a check-sat call),
+ * (2) maintaining the SAT and user contexts to be used by the SmtEngine,
+ * (3) general information queries, including the mode that the SmtEngine is
+ * in, based on the notifications it has received.
+ *
+ * It maintains a reference to the SmtEngine for the sake of making callbacks.
+ */
+class SmtEngineState
+{
+ public:
+ SmtEngineState(SmtEngine& smt);
+ ~SmtEngineState() {}
+ /**
+ * Notify that the expected status of the next check-sat is given by the
+ * string status, which should be one of "sat", "unsat" or "unknown".
+ */
+ void notifyExpectedStatus(const std::string& status);
+ /**
+ * Notify that the SmtEngine is fully initialized, which is called when
+ * options are finalized.
+ */
+ void notifyFullyInited();
+ /**
+ * Notify that we are resetting the assertions, called when a reset-assertions
+ * command is issued by the user.
+ */
+ void notifyResetAssertions();
+ /**
+ * Notify that we are about to call check-sat. This call is made prior to
+ * initializing the assertions. It processes pending pops and pushes a
+ * (user) context if necessary.
+ *
+ * @param hasAssumptions Whether the call to check-sat has assumptions. If
+ * so, we push a context.
+ */
+ void notifyCheckSat(bool hasAssumptions);
+ /**
+ * Notify that the result of the last check-sat was r. This should be called
+ * once immediately following notifyCheckSat() if the check-sat call
+ * returned normal (i.e. it was not interupted).
+ *
+ * @param hasAssumptions Whether the prior call to check-sat had assumptions.
+ * If so, we pop a context.
+ * @param r The result of the check-sat call.
+ */
+ void notifyCheckSatResult(bool hasAssumptions, Result r);
+ /**
+ * Notify that we finished an abduction query, where success is whether the
+ * command was successful. This is managed independently of the above
+ * calls for notifying check-sat. In other words, if a get-abduct command
+ * is issued to an SmtEngine, it may use a satisfiability call (if desired)
+ * to solve the abduction query. This method is called *in addition* to
+ * the above calls to notifyCheckSat / notifyCheckSatResult in this case.
+ * In particular, it is called after these two methods are completed.
+ * This overwrites the SMT mode to the "ABDUCT" mode if the call to abduction
+ * was successful.
+ */
+ void notifyGetAbduct(bool success);
+ /**
+ * Notify that we finished an interpolation query, where success is whether
+ * the command was successful. This is managed independently of the above
+ * calls for notifying check-sat. In other words, if a get-interpol command
+ * is issued to an SmtEngine, it may use a satisfiability call (if desired)
+ * to solve the interpolation query. This method is called *in addition* to
+ * the above calls to notifyCheckSat / notifyCheckSatResult in this case.
+ * In particular, it is called after these two methods are completed.
+ * This overwrites the SMT mode to the "INTERPOL" mode if the call to
+ * interpolation was successful.
+ */
+ void notifyGetInterpol(bool success);
+ /**
+ * Setup the context, which makes a single push to maintain a global
+ * context around everything.
+ */
+ void setup();
+ /**
+ * Set that we are in a fully initialized state.
+ */
+ void finishInit();
+ /**
+ * Prepare for a shutdown of the SmtEngine, which does pending pops and
+ * pops the user context to zero.
+ */
+ void shutdown();
+ /**
+ * Cleanup, which pops all contexts to level zero.
+ */
+ void cleanup();
+ /**
+ * Set that the file name of the current instance is the given string. This
+ * is used for various purposes (e.g. get-info, SZS status).
+ */
+ void setFilename(const std::string& filename);
+
+ //---------------------------- context management
+ /**
+ * Do all pending pops, which ensures that the context levels are up-to-date.
+ * This method should be called by the SmtEngine before using any of its
+ * members that rely on the context (e.g. PropEngine or TheoryEngine).
+ */
+ void doPendingPops();
+ /**
+ * Called when the user of SmtEngine issues a push. This corresponds to
+ * the SMT-LIB command push.
+ */
+ void userPush();
+ /**
+ * Called when the user of SmtEngine issues a pop. This corresponds to
+ * the SMT-LIB command pop.
+ */
+ void userPop();
+ /** Get a pointer to the UserContext owned by this SmtEngine. */
+ context::UserContext* getUserContext();
+ /** Get a pointer to the Context owned by this SmtEngine. */
+ context::Context* getContext();
+ //---------------------------- end context management
+
+ //---------------------------- queries
+ /**
+ * Return true if the SmtEngine is fully initialized (post-construction).
+ * This post-construction initialization is automatically triggered by the
+ * use of the SmtEngine; e.g. when the first formula is asserted, a call
+ * to simplify() is issued, a scope is pushed, etc.
+ */
+ bool isFullyInited() const;
+ /**
+ * Return true if the SmtEngine is fully initialized and there are no
+ * pending pops.
+ */
+ bool isFullyReady() const;
+ /**
+ * Return true if a notifyCheckSat call has been made, e.g. a query has been
+ * issued to the SmtEngine.
+ */
+ bool isQueryMade() const;
+ /** Return the user context level. */
+ size_t getNumUserLevels() const;
+ /** Get the status of the last check-sat */
+ Result getStatus() const;
+ /** Get the SMT mode we are in */
+ SmtMode getMode() const;
+ /** return the input name (if any) */
+ const std::string& getFilename() const;
+ //---------------------------- end queries
+
+ private:
+ /** Pushes the user and SAT contexts */
+ void push();
+ /** Pops the user and SAT contexts */
+ void pop();
+ /** Pops the user and SAT contexts to the given level */
+ void popto(int toLevel);
+ /**
+ * Internal push, which processes any pending pops, and pushes (if in
+ * incremental mode).
+ */
+ void internalPush();
+ /**
+ * Internal pop. If immediate is true, this processes any pending pops, and
+ * pops (if in incremental mode). Otherwise, it increments the pending pop
+ * counter and does nothing.
+ */
+ void internalPop(bool immediate = false);
+ /** Reference to the SmtEngine */
+ SmtEngine& d_smt;
+ /** Expr manager context */
+ std::unique_ptr<context::Context> d_context;
+ /** User level context */
+ std::unique_ptr<context::UserContext> d_userContext;
+ /** The context levels of user pushes */
+ std::vector<int> d_userLevels;
+
+ /**
+ * Number of internal pops that have been deferred.
+ */
+ unsigned d_pendingPops;
+
+ /**
+ * Whether or not the SmtEngine is fully initialized (post-construction).
+ * This post-construction initialization is automatically triggered by the
+ * use of the SmtEngine which calls the finishInit method above; e.g. when
+ * the first formula is asserted, a call to simplify() is issued, a scope is
+ * pushed, etc.
+ */
+ bool d_fullyInited;
+
+ /**
+ * Whether or not a notifyCheckSat call has been made, which corresponds to
+ * when a checkEntailed() or checkSatisfiability() has already been
+ * made through the SmtEngine. If true, and incrementalSolving is false,
+ * then attempting an additional checks for satisfiability will fail with
+ * a ModalException during notifyCheckSat.
+ */
+ bool d_queryMade;
+
+ /**
+ * Internal status flag to indicate whether we have been issued a
+ * notifyCheckSat call and have yet to process the "postsolve" methods of
+ * SmtEngine via SmtEngine::notifyPostSolvePre/notifyPostSolvePost.
+ */
+ bool d_needPostsolve;
+
+ /**
+ * Most recent result of last checkSatisfiability/checkEntailed in the
+ * SmtEngine.
+ */
+ Result d_status;
+
+ /**
+ * The expected status of the next satisfiability check.
+ */
+ Result d_expectedStatus;
+
+ /** The SMT mode, for details see enumeration above. */
+ SmtMode d_smtMode;
+
+ /**
+ * The input file name or the name set through (set-info :filename ...), if
+ * any.
+ */
+ std::string d_filename;
+};
+
+} // namespace smt
+} // namespace CVC4
+
+#endif
diff --git a/src/smt/smt_engine_stats.cpp b/src/smt/smt_engine_stats.cpp
index 964237499..d32f0e564 100644
--- a/src/smt/smt_engine_stats.cpp
+++ b/src/smt/smt_engine_stats.cpp
@@ -2,10 +2,10 @@
/*! \file smt_engine_stats.cpp
** \verbatim
** Top contributors (to current version):
- ** Tim King, Andres Noetzli, Morgan Deters
+ ** Tim King, Andrew Reynolds, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,30 +25,24 @@ SmtEngineStatistics::SmtEngineStatistics()
d_cnfConversionTime("smt::SmtEngine::cnfConversionTime"),
d_numAssertionsPre("smt::SmtEngine::numAssertionsPreITERemoval", 0),
d_numAssertionsPost("smt::SmtEngine::numAssertionsPostITERemoval", 0),
- d_proofsSize("smt::SmtEngine::proofsSize", 0),
d_checkModelTime("smt::SmtEngine::checkModelTime"),
- d_lfscCheckProofTime("smt::SmtEngine::lfscCheckProofTime"),
d_checkUnsatCoreTime("smt::SmtEngine::checkUnsatCoreTime"),
d_solveTime("smt::SmtEngine::solveTime"),
d_pushPopTime("smt::SmtEngine::pushPopTime"),
d_processAssertionsTime("smt::SmtEngine::processAssertionsTime"),
- d_simplifiedToFalse("smt::SmtEngine::simplifiedToFalse", 0),
- d_resourceUnitsUsed("smt::SmtEngine::resourceUnitsUsed")
+ d_simplifiedToFalse("smt::SmtEngine::simplifiedToFalse", 0)
{
smtStatisticsRegistry()->registerStat(&d_definitionExpansionTime);
smtStatisticsRegistry()->registerStat(&d_numConstantProps);
smtStatisticsRegistry()->registerStat(&d_cnfConversionTime);
smtStatisticsRegistry()->registerStat(&d_numAssertionsPre);
smtStatisticsRegistry()->registerStat(&d_numAssertionsPost);
- smtStatisticsRegistry()->registerStat(&d_proofsSize);
smtStatisticsRegistry()->registerStat(&d_checkModelTime);
- smtStatisticsRegistry()->registerStat(&d_lfscCheckProofTime);
smtStatisticsRegistry()->registerStat(&d_checkUnsatCoreTime);
smtStatisticsRegistry()->registerStat(&d_solveTime);
smtStatisticsRegistry()->registerStat(&d_pushPopTime);
smtStatisticsRegistry()->registerStat(&d_processAssertionsTime);
smtStatisticsRegistry()->registerStat(&d_simplifiedToFalse);
- smtStatisticsRegistry()->registerStat(&d_resourceUnitsUsed);
}
SmtEngineStatistics::~SmtEngineStatistics()
@@ -58,15 +52,12 @@ SmtEngineStatistics::~SmtEngineStatistics()
smtStatisticsRegistry()->unregisterStat(&d_cnfConversionTime);
smtStatisticsRegistry()->unregisterStat(&d_numAssertionsPre);
smtStatisticsRegistry()->unregisterStat(&d_numAssertionsPost);
- smtStatisticsRegistry()->unregisterStat(&d_proofsSize);
smtStatisticsRegistry()->unregisterStat(&d_checkModelTime);
- smtStatisticsRegistry()->unregisterStat(&d_lfscCheckProofTime);
smtStatisticsRegistry()->unregisterStat(&d_checkUnsatCoreTime);
smtStatisticsRegistry()->unregisterStat(&d_solveTime);
smtStatisticsRegistry()->unregisterStat(&d_pushPopTime);
smtStatisticsRegistry()->unregisterStat(&d_processAssertionsTime);
smtStatisticsRegistry()->unregisterStat(&d_simplifiedToFalse);
- smtStatisticsRegistry()->unregisterStat(&d_resourceUnitsUsed);
}
} // namespace smt
diff --git a/src/smt/smt_engine_stats.h b/src/smt/smt_engine_stats.h
index 3ea46eaa4..9cbb6ce9e 100644
--- a/src/smt/smt_engine_stats.h
+++ b/src/smt/smt_engine_stats.h
@@ -2,10 +2,10 @@
/*! \file smt_engine_stats.h
** \verbatim
** Top contributors (to current version):
- ** Morgan Deters, Andrew Reynolds, Liana Hadarean
+ ** Morgan Deters, Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -36,12 +36,8 @@ struct SmtEngineStatistics
IntStat d_numAssertionsPre;
/** Number of assertions after ite removal */
IntStat d_numAssertionsPost;
- /** Size of all proofs generated */
- IntStat d_proofsSize;
/** time spent in checkModel() */
TimerStat d_checkModelTime;
- /** time spent checking the proof with LFSC */
- TimerStat d_lfscCheckProofTime;
/** time spent in checkUnsatCore() */
TimerStat d_checkUnsatCoreTime;
/** time spent in PropEngine::checkSat() */
@@ -53,8 +49,6 @@ struct SmtEngineStatistics
/** Has something simplified to false? */
IntStat d_simplifiedToFalse;
- /** Number of resource units spent. */
- ReferenceStat<uint64_t> d_resourceUnitsUsed;
}; /* struct SmtEngineStatistics */
} // namespace smt
diff --git a/src/smt/smt_mode.cpp b/src/smt/smt_mode.cpp
new file mode 100644
index 000000000..be1d0627a
--- /dev/null
+++ b/src/smt/smt_mode.cpp
@@ -0,0 +1,37 @@
+/********************* */
+/*! \file smt_mode.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Enumeration type for the mode of an SmtEngine.
+ **/
+
+#include "smt/smt_mode.h"
+
+#include <iostream>
+
+namespace CVC4 {
+
+std::ostream& operator<<(std::ostream& out, SmtMode m)
+{
+ switch (m)
+ {
+ case SmtMode::START: out << "START"; break;
+ case SmtMode::ASSERT: out << "ASSERT"; break;
+ case SmtMode::SAT: out << "SAT"; break;
+ case SmtMode::SAT_UNKNOWN: out << "SAT_UNKNOWN"; break;
+ case SmtMode::UNSAT: out << "UNSAT"; break;
+ case SmtMode::ABDUCT: out << "ABDUCT"; break;
+ case SmtMode::INTERPOL: out << "INTERPOL"; break;
+ default: out << "SmtMode!Unknown"; break;
+ }
+ return out;
+}
+
+} // namespace CVC4
diff --git a/src/smt/smt_mode.h b/src/smt/smt_mode.h
new file mode 100644
index 000000000..61f0fe1f6
--- /dev/null
+++ b/src/smt/smt_mode.h
@@ -0,0 +1,57 @@
+/********************* */
+/*! \file smt_mode.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Ying Sheng, Morgan Deters
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Enumeration type for the mode of an SmtEngine.
+ **/
+
+#include "cvc4_public.h"
+
+#ifndef CVC4__SMT__SMT_MODE_H
+#define CVC4__SMT__SMT_MODE_H
+
+#include <iosfwd>
+
+namespace CVC4 {
+
+/**
+ * The mode of the solver, which is an extension of Figure 4.1 on
+ * page 52 of the SMT-LIB version 2.6 standard
+ * http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.6-r2017-07-18.pdf
+ */
+enum class SmtMode
+{
+ // the initial state of the solver
+ START,
+ // normal state of the solver, after assert/push/pop/declare/define
+ ASSERT,
+ // immediately after a check-sat returning "sat"
+ SAT,
+ // immediately after a check-sat returning "unknown"
+ SAT_UNKNOWN,
+ // immediately after a check-sat returning "unsat"
+ UNSAT,
+ // immediately after a successful call to get-abduct
+ ABDUCT,
+ // immediately after a successful call to get-interpol
+ INTERPOL
+};
+/**
+ * Writes a SmtMode to a stream.
+ *
+ * @param out The stream to write to
+ * @param m The mode to write to the stream
+ * @return The stream
+ */
+std::ostream& operator<<(std::ostream& out, SmtMode m);
+
+} // namespace CVC4
+
+#endif
diff --git a/src/smt/smt_solver.cpp b/src/smt/smt_solver.cpp
new file mode 100644
index 000000000..26a2ff3e1
--- /dev/null
+++ b/src/smt/smt_solver.cpp
@@ -0,0 +1,266 @@
+/********************* */
+/*! \file smt_solver.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Aina Niemetz, Morgan Deters
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The solver for SMT queries in an SmtEngine.
+ **/
+
+#include "smt/smt_solver.h"
+
+#include "prop/prop_engine.h"
+#include "smt/assertions.h"
+#include "smt/preprocessor.h"
+#include "smt/smt_engine.h"
+#include "smt/smt_engine_state.h"
+#include "theory/theory_engine.h"
+#include "theory/theory_traits.h"
+
+namespace CVC4 {
+namespace smt {
+
+SmtSolver::SmtSolver(SmtEngine& smt,
+ SmtEngineState& state,
+ ResourceManager* rm,
+ Preprocessor& pp,
+ SmtEngineStatistics& stats)
+ : d_smt(smt),
+ d_state(state),
+ d_rm(rm),
+ d_pp(pp),
+ d_stats(stats),
+ d_pnm(nullptr),
+ d_theoryEngine(nullptr),
+ d_propEngine(nullptr)
+{
+}
+
+SmtSolver::~SmtSolver() {}
+
+void SmtSolver::finishInit(const LogicInfo& logicInfo)
+{
+ // We have mutual dependency here, so we add the prop engine to the theory
+ // engine later (it is non-essential there)
+ d_theoryEngine.reset(new TheoryEngine(d_smt.getContext(),
+ d_smt.getUserContext(),
+ d_rm,
+ d_pp.getTermFormulaRemover(),
+ logicInfo,
+ d_smt.getOutputManager(),
+ d_pnm));
+
+ // Add the theories
+ for (theory::TheoryId id = theory::THEORY_FIRST; id < theory::THEORY_LAST;
+ ++id)
+ {
+ theory::TheoryConstructor::addTheory(d_theoryEngine.get(), id);
+ }
+
+ Trace("smt-debug") << "Making prop engine..." << std::endl;
+ /* force destruction of referenced PropEngine to enforce that statistics
+ * are unregistered by the obsolete PropEngine object before registered
+ * again by the new PropEngine object */
+ d_propEngine.reset(nullptr);
+ d_propEngine.reset(new PropEngine(d_theoryEngine.get(),
+ d_smt.getContext(),
+ d_smt.getUserContext(),
+ d_rm,
+ d_smt.getOutputManager()));
+
+ Trace("smt-debug") << "Setting up theory engine..." << std::endl;
+ d_theoryEngine->setPropEngine(getPropEngine());
+ Trace("smt-debug") << "Finishing init for theory engine..." << std::endl;
+ d_theoryEngine->finishInit();
+ d_propEngine->finishInit();
+}
+
+void SmtSolver::resetAssertions()
+{
+ /* Create new PropEngine.
+ * First force destruction of referenced PropEngine to enforce that
+ * statistics are unregistered by the obsolete PropEngine object before
+ * registered again by the new PropEngine object */
+ d_propEngine.reset(nullptr);
+ d_propEngine.reset(new PropEngine(d_theoryEngine.get(),
+ d_smt.getContext(),
+ d_smt.getUserContext(),
+ d_rm,
+ d_smt.getOutputManager()));
+ d_theoryEngine->setPropEngine(getPropEngine());
+ // Notice that we do not reset TheoryEngine, nor does it require calling
+ // finishInit again. In particular, TheoryEngine::finishInit does not
+ // depend on knowing the associated PropEngine.
+ d_propEngine->finishInit();
+}
+
+void SmtSolver::interrupt()
+{
+ if (d_propEngine != nullptr)
+ {
+ d_propEngine->interrupt();
+ }
+ if (d_theoryEngine != nullptr)
+ {
+ d_theoryEngine->interrupt();
+ }
+}
+
+void SmtSolver::shutdown()
+{
+ if (d_propEngine != nullptr)
+ {
+ d_propEngine->shutdown();
+ }
+ if (d_theoryEngine != nullptr)
+ {
+ d_theoryEngine->shutdown();
+ }
+}
+
+Result SmtSolver::checkSatisfiability(Assertions& as,
+ const std::vector<Node>& assumptions,
+ bool inUnsatCore,
+ bool isEntailmentCheck)
+{
+ // update the state to indicate we are about to run a check-sat
+ bool hasAssumptions = !assumptions.empty();
+ d_state.notifyCheckSat(hasAssumptions);
+
+ // then, initialize the assertions
+ as.initializeCheckSat(assumptions, inUnsatCore, isEntailmentCheck);
+
+ // make the check
+ Assert(d_smt.isFullyInited());
+
+ Trace("smt") << "SmtSolver::check()" << endl;
+
+ const std::string& filename = d_state.getFilename();
+ if (d_rm->out())
+ {
+ Result::UnknownExplanation why =
+ d_rm->outOfResources() ? Result::RESOURCEOUT : Result::TIMEOUT;
+ return Result(Result::ENTAILMENT_UNKNOWN, why, filename);
+ }
+ d_rm->beginCall();
+
+ // Make sure the prop layer has all of the assertions
+ Trace("smt") << "SmtSolver::check(): processing assertions" << endl;
+ processAssertions(as);
+ Trace("smt") << "SmtSolver::check(): done processing assertions" << endl;
+
+ TimerStat::CodeTimer solveTimer(d_stats.d_solveTime);
+
+ Chat() << "solving..." << endl;
+ Trace("smt") << "SmtSolver::check(): running check" << endl;
+ Result result = d_propEngine->checkSat();
+
+ d_rm->endCall();
+ Trace("limit") << "SmtSolver::check(): cumulative millis "
+ << d_rm->getTimeUsage() << ", resources "
+ << d_rm->getResourceUsage() << endl;
+
+ if ((options::solveRealAsInt() || options::solveIntAsBV() > 0)
+ && result.asSatisfiabilityResult().isSat() == Result::UNSAT)
+ {
+ result = Result(Result::SAT_UNKNOWN, Result::UNKNOWN_REASON);
+ }
+ // flipped if we did a global negation
+ if (as.isGlobalNegated())
+ {
+ Trace("smt") << "SmtSolver::process global negate " << result << std::endl;
+ if (result.asSatisfiabilityResult().isSat() == Result::UNSAT)
+ {
+ result = Result(Result::SAT);
+ }
+ else if (result.asSatisfiabilityResult().isSat() == Result::SAT)
+ {
+ // Only can answer unsat if the theory is satisfaction complete. This
+ // includes linear arithmetic and bitvectors, which are the primary
+ // targets for the global negate option. Other logics are possible here
+ // but not considered.
+ LogicInfo logic = d_smt.getLogicInfo();
+ if ((logic.isPure(theory::THEORY_ARITH) && logic.isLinear()) ||
+ logic.isPure(theory::THEORY_BV))
+ {
+ result = Result(Result::UNSAT);
+ }
+ else
+ {
+ result = Result(Result::SAT_UNKNOWN, Result::UNKNOWN_REASON);
+ }
+ }
+ Trace("smt") << "SmtSolver::global negate returned " << result << std::endl;
+ }
+
+ // set the filename on the result
+ Result r = Result(result, filename);
+
+ // notify our state of the check-sat result
+ d_state.notifyCheckSatResult(hasAssumptions, r);
+
+ return r;
+}
+
+void SmtSolver::processAssertions(Assertions& as)
+{
+ TimerStat::CodeTimer paTimer(d_stats.d_processAssertionsTime);
+ d_rm->spendResource(ResourceManager::Resource::PreprocessStep);
+ Assert(d_state.isFullyReady());
+
+ preprocessing::AssertionPipeline& ap = as.getAssertionPipeline();
+
+ if (ap.size() == 0)
+ {
+ // nothing to do
+ return;
+ }
+
+ // process the assertions with the preprocessor
+ bool noConflict = d_pp.process(as);
+
+ // notify theory engine new preprocessed assertions
+ d_theoryEngine->notifyPreprocessedAssertions(ap.ref());
+
+ // Push the formula to decision engine
+ if (noConflict)
+ {
+ Chat() << "pushing to decision engine..." << endl;
+ d_propEngine->addAssertionsToDecisionEngine(ap);
+ }
+
+ // end: INVARIANT to maintain: no reordering of assertions or
+ // introducing new ones
+
+ d_pp.postprocess(as);
+
+ // Push the formula to SAT
+ {
+ Chat() << "converting to CNF..." << endl;
+ TimerStat::CodeTimer codeTimer(d_stats.d_cnfConversionTime);
+ for (const Node& assertion : ap.ref())
+ {
+ Chat() << "+ " << assertion << std::endl;
+ d_propEngine->assertFormula(assertion);
+ }
+ }
+
+ // clear the current assertions
+ as.clearCurrent();
+}
+
+void SmtSolver::setProofNodeManager(ProofNodeManager* pnm) { d_pnm = pnm; }
+
+TheoryEngine* SmtSolver::getTheoryEngine() { return d_theoryEngine.get(); }
+
+prop::PropEngine* SmtSolver::getPropEngine() { return d_propEngine.get(); }
+
+Preprocessor* SmtSolver::getPreprocessor() { return &d_pp; }
+
+} // namespace smt
+} // namespace CVC4
diff --git a/src/smt/smt_solver.h b/src/smt/smt_solver.h
new file mode 100644
index 000000000..e3cbea152
--- /dev/null
+++ b/src/smt/smt_solver.h
@@ -0,0 +1,150 @@
+/********************* */
+/*! \file smt_solver.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Morgan Deters, Aina Niemetz
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The solver for SMT queries in an SmtEngine.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__SMT__SMT_SOLVER_H
+#define CVC4__SMT__SMT_SOLVER_H
+
+#include <vector>
+
+#include "expr/node.h"
+#include "theory/logic_info.h"
+#include "util/result.h"
+
+namespace CVC4 {
+
+class SmtEngine;
+class TheoryEngine;
+class ResourceManager;
+class ProofNodeManager;
+
+namespace prop {
+class PropEngine;
+}
+
+namespace smt {
+
+class Assertions;
+class SmtEngineState;
+class Preprocessor;
+class SmtEngineStatistics;
+
+/**
+ * A solver for SMT queries.
+ *
+ * This class manages the initialization of the theory engine and propositional
+ * engines and implements the method for checking satisfiability of the current
+ * set of assertions.
+ *
+ * Notice that this class is only conceptually responsible for running
+ * check-sat commands and an interface for sending formulas to the underlying
+ * classes. It does not implement any query techniques beyond getting the result
+ * (unsat/sat/unknown) of check-sat calls. More detailed information (e.g.
+ * models) can be queries using other classes that examine the state of the
+ * TheoryEngine directly, which can be accessed via getTheoryEngine.
+ */
+class SmtSolver
+{
+ public:
+ SmtSolver(SmtEngine& smt,
+ SmtEngineState& state,
+ ResourceManager* rm,
+ Preprocessor& pp,
+ SmtEngineStatistics& stats);
+ ~SmtSolver();
+ /**
+ * Create theory engine, prop engine based on the logic info.
+ */
+ void finishInit(const LogicInfo& logicInfo);
+ /** Reset all assertions, global declarations, etc. */
+ void resetAssertions();
+ /**
+ * Interrupt a running query. This can be called from another thread
+ * or from a signal handler. Throws a ModalException if the SmtSolver
+ * isn't currently in a query.
+ */
+ void interrupt();
+ /**
+ * This is called by the destructor of SmtEngine, just before destroying the
+ * PropEngine, TheoryEngine, and DecisionEngine (in that order). It
+ * is important because there are destruction ordering issues
+ * between PropEngine and Theory.
+ */
+ void shutdown();
+ /**
+ * Check satisfiability (used to check satisfiability and entailment)
+ * in SmtEngine. This is done via adding assumptions (when necessary) to
+ * assertions as, preprocessing and pushing assertions into the prop engine
+ * of this class, and checking for satisfiability via the prop engine.
+ *
+ * @param as The object managing the assertions in SmtEngine. This class
+ * maintains a current set of (unprocessed) assertions which are pushed
+ * into the internal members of this class (TheoryEngine and PropEngine)
+ * during this call.
+ * @param assumptions The assumptions for this check-sat call, which are
+ * temporary assertions.
+ * @param inUnsatCore Whether assumptions are in the unsat core.
+ * @param isEntailmentCheck Whether this is an entailment check (assumptions
+ * are negated in this case).
+ */
+ Result checkSatisfiability(Assertions& as,
+ const std::vector<Node>& assumptions,
+ bool inUnsatCore,
+ bool isEntailmentCheck);
+ /**
+ * Process the assertions that have been asserted in as. This moves the set of
+ * assertions that have been buffered into as, preprocesses them, pushes them
+ * into the SMT solver, and clears the buffer.
+ */
+ void processAssertions(Assertions& as);
+ /**
+ * Set proof node manager. Enables proofs in this SmtSolver. Should be
+ * called before finishInit.
+ */
+ void setProofNodeManager(ProofNodeManager* pnm);
+ //------------------------------------------ access methods
+ /** Get a pointer to the TheoryEngine owned by this solver. */
+ TheoryEngine* getTheoryEngine();
+ /** Get a pointer to the PropEngine owned by this solver. */
+ prop::PropEngine* getPropEngine();
+ /** Get a pointer to the preprocessor */
+ Preprocessor* getPreprocessor();
+ //------------------------------------------ end access methods
+ private:
+ /** Reference to the parent SMT engine */
+ SmtEngine& d_smt;
+ /** Reference to the state of the SmtEngine */
+ SmtEngineState& d_state;
+ /** Pointer to a resource manager (owned by SmtEngine) */
+ ResourceManager* d_rm;
+ /** Reference to the preprocessor of SmtEngine */
+ Preprocessor& d_pp;
+ /** Reference to the statistics of SmtEngine */
+ SmtEngineStatistics& d_stats;
+ /**
+ * Pointer to the proof node manager used by this SmtSolver. A non-null
+ * proof node manager indicates that proofs are enabled.
+ */
+ ProofNodeManager* d_pnm;
+ /** The theory engine */
+ std::unique_ptr<TheoryEngine> d_theoryEngine;
+ /** The propositional engine */
+ std::unique_ptr<prop::PropEngine> d_propEngine;
+};
+
+} // namespace smt
+} // namespace CVC4
+
+#endif /* CVC4__SMT__SMT_SOLVER_H */
diff --git a/src/smt/smt_statistics_registry.cpp b/src/smt/smt_statistics_registry.cpp
index 7191da012..47591a8e2 100644
--- a/src/smt/smt_statistics_registry.cpp
+++ b/src/smt/smt_statistics_registry.cpp
@@ -5,7 +5,7 @@
** Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/smt/smt_statistics_registry.h b/src/smt/smt_statistics_registry.h
index c54e881f5..a35d62d78 100644
--- a/src/smt/smt_statistics_registry.h
+++ b/src/smt/smt_statistics_registry.h
@@ -5,7 +5,7 @@
** Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/smt/sygus_solver.cpp b/src/smt/sygus_solver.cpp
new file mode 100644
index 000000000..0b40bf894
--- /dev/null
+++ b/src/smt/sygus_solver.cpp
@@ -0,0 +1,410 @@
+/********************* */
+/*! \file sygus_solver.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Haniel Barbosa, Andres Noetzli
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The solver for sygus queries
+ **/
+
+#include "smt/sygus_solver.h"
+
+#include "expr/dtype.h"
+#include "options/quantifiers_options.h"
+#include "options/smt_options.h"
+#include "printer/printer.h"
+#include "smt/dump.h"
+#include "smt/preprocessor.h"
+#include "smt/smt_solver.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
+#include "theory/quantifiers/sygus/sygus_grammar_cons.h"
+#include "theory/smt_engine_subsolver.h"
+
+using namespace CVC4::theory;
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace smt {
+
+SygusSolver::SygusSolver(SmtSolver& sms,
+ Preprocessor& pp,
+ context::UserContext* u,
+ OutputManager& outMgr)
+ : d_smtSolver(sms),
+ d_pp(pp),
+ d_sygusConjectureStale(u, true),
+ d_outMgr(outMgr)
+{
+}
+
+SygusSolver::~SygusSolver() {}
+
+void SygusSolver::declareSygusVar(const std::string& id,
+ Node var,
+ TypeNode type)
+{
+ Trace("smt") << "SygusSolver::declareSygusVar: " << id << " " << var << " "
+ << type << "\n";
+ Assert(var.getType() == type);
+ d_sygusVars.push_back(var);
+ // don't need to set that the conjecture is stale
+}
+
+void SygusSolver::declareSynthFun(const std::string& id,
+ Node fn,
+ TypeNode sygusType,
+ bool isInv,
+ const std::vector<Node>& vars)
+{
+ Trace("smt") << "SygusSolver::declareSynthFun: " << id << "\n";
+ NodeManager* nm = NodeManager::currentNM();
+ d_sygusFunSymbols.push_back(fn);
+ if (!vars.empty())
+ {
+ Node bvl = nm->mkNode(BOUND_VAR_LIST, vars);
+ // use an attribute to mark its bound variable list
+ SygusSynthFunVarListAttribute ssfvla;
+ fn.setAttribute(ssfvla, bvl);
+ }
+ // whether sygus type encodes syntax restrictions
+ if (sygusType.isDatatype() && sygusType.getDType().isSygus())
+ {
+ Node sym = nm->mkBoundVar("sfproxy", sygusType);
+ // use an attribute to mark its grammar
+ SygusSynthGrammarAttribute ssfga;
+ fn.setAttribute(ssfga, sym);
+ }
+
+ // sygus conjecture is now stale
+ setSygusConjectureStale();
+}
+
+void SygusSolver::assertSygusConstraint(Node constraint)
+{
+ Trace("smt") << "SygusSolver::assertSygusConstrant: " << constraint << "\n";
+ d_sygusConstraints.push_back(constraint);
+
+ // sygus conjecture is now stale
+ setSygusConjectureStale();
+}
+
+void SygusSolver::assertSygusInvConstraint(Node inv,
+ Node pre,
+ Node trans,
+ Node post)
+{
+ Trace("smt") << "SygusSolver::assertSygusInvConstrant: " << inv << " " << pre
+ << " " << trans << " " << post << "\n";
+ // build invariant constraint
+
+ // get variables (regular and their respective primed versions)
+ std::vector<Node> terms;
+ std::vector<Node> vars;
+ std::vector<Node> primed_vars;
+ terms.push_back(inv);
+ terms.push_back(pre);
+ terms.push_back(trans);
+ terms.push_back(post);
+ // variables are built based on the invariant type
+ NodeManager* nm = NodeManager::currentNM();
+ std::vector<TypeNode> argTypes = inv.getType().getArgTypes();
+ for (const TypeNode& tn : argTypes)
+ {
+ vars.push_back(nm->mkBoundVar(tn));
+ d_sygusVars.push_back(vars.back());
+ std::stringstream ss;
+ ss << vars.back() << "'";
+ primed_vars.push_back(nm->mkBoundVar(ss.str(), tn));
+ d_sygusVars.push_back(primed_vars.back());
+ }
+
+ // make relevant terms; 0 -> Inv, 1 -> Pre, 2 -> Trans, 3 -> Post
+ for (unsigned i = 0; i < 4; ++i)
+ {
+ Node op = terms[i];
+ Trace("smt-debug") << "Make inv-constraint term #" << i << " : " << op
+ << " with type " << op.getType() << "...\n";
+ std::vector<Node> children;
+ children.push_back(op);
+ // transition relation applied over both variable lists
+ if (i == 2)
+ {
+ children.insert(children.end(), vars.begin(), vars.end());
+ children.insert(children.end(), primed_vars.begin(), primed_vars.end());
+ }
+ else
+ {
+ children.insert(children.end(), vars.begin(), vars.end());
+ }
+ terms[i] = nm->mkNode(APPLY_UF, children);
+ // make application of Inv on primed variables
+ if (i == 0)
+ {
+ children.clear();
+ children.push_back(op);
+ children.insert(children.end(), primed_vars.begin(), primed_vars.end());
+ terms.push_back(nm->mkNode(APPLY_UF, children));
+ }
+ }
+ // make constraints
+ std::vector<Node> conj;
+ conj.push_back(nm->mkNode(IMPLIES, terms[1], terms[0]));
+ Node term0_and_2 = nm->mkNode(AND, terms[0], terms[2]);
+ conj.push_back(nm->mkNode(IMPLIES, term0_and_2, terms[4]));
+ conj.push_back(nm->mkNode(IMPLIES, terms[0], terms[3]));
+ Node constraint = nm->mkNode(AND, conj);
+
+ d_sygusConstraints.push_back(constraint);
+
+ // sygus conjecture is now stale
+ setSygusConjectureStale();
+}
+
+Result SygusSolver::checkSynth(Assertions& as)
+{
+ if (options::incrementalSolving())
+ {
+ // TODO (project #7)
+ throw ModalException(
+ "Cannot make check-synth commands when incremental solving is enabled");
+ }
+ Trace("smt") << "SygusSolver::checkSynth" << std::endl;
+ std::vector<Node> query;
+ if (d_sygusConjectureStale)
+ {
+ NodeManager* nm = NodeManager::currentNM();
+ // build synthesis conjecture from asserted constraints and declared
+ // variables/functions
+ Node sygusVar = nm->mkSkolem("sygus", nm->booleanType());
+ Node inst_attr = nm->mkNode(INST_ATTRIBUTE, sygusVar);
+ Node sygusAttr = nm->mkNode(INST_PATTERN_LIST, inst_attr);
+ std::vector<Node> bodyv;
+ Trace("smt") << "Sygus : Constructing sygus constraint...\n";
+ size_t nconstraints = d_sygusConstraints.size();
+ Node body = nconstraints == 0
+ ? nm->mkConst(true)
+ : (nconstraints == 1 ? d_sygusConstraints[0]
+ : nm->mkNode(AND, d_sygusConstraints));
+ body = body.notNode();
+ Trace("smt") << "...constructed sygus constraint " << body << std::endl;
+ if (!d_sygusVars.empty())
+ {
+ Node boundVars = nm->mkNode(BOUND_VAR_LIST, d_sygusVars);
+ body = nm->mkNode(EXISTS, boundVars, body);
+ Trace("smt") << "...constructed exists " << body << std::endl;
+ }
+ if (!d_sygusFunSymbols.empty())
+ {
+ Node boundVars = nm->mkNode(BOUND_VAR_LIST, d_sygusFunSymbols);
+ body = nm->mkNode(FORALL, boundVars, body, sygusAttr);
+ }
+ Trace("smt") << "...constructed forall " << body << std::endl;
+
+ // set attribute for synthesis conjecture
+ SygusAttribute sa;
+ sygusVar.setAttribute(sa, true);
+
+ Trace("smt") << "Check synthesis conjecture: " << body << std::endl;
+ if (Dump.isOn("raw-benchmark"))
+ {
+ d_outMgr.getPrinter().toStreamCmdCheckSynth(d_outMgr.getDumpOut());
+ }
+
+ d_sygusConjectureStale = false;
+
+ // TODO (project #7): if incremental, we should push a context and assert
+ query.push_back(body);
+ }
+
+ Result r = d_smtSolver.checkSatisfiability(as, query, false, false);
+
+ // Check that synthesis solutions satisfy the conjecture
+ if (options::checkSynthSol()
+ && r.asSatisfiabilityResult().isSat() == Result::UNSAT)
+ {
+ checkSynthSolution(as);
+ }
+ return r;
+}
+
+bool SygusSolver::getSynthSolutions(std::map<Node, Node>& sol_map)
+{
+ Trace("smt") << "SygusSolver::getSynthSolutions" << std::endl;
+ std::map<Node, std::map<Node, Node>> sol_mapn;
+ // fail if the theory engine does not have synthesis solutions
+ TheoryEngine* te = d_smtSolver.getTheoryEngine();
+ Assert(te != nullptr);
+ if (!te->getSynthSolutions(sol_mapn))
+ {
+ return false;
+ }
+ for (std::pair<const Node, std::map<Node, Node>>& cs : sol_mapn)
+ {
+ for (std::pair<const Node, Node>& s : cs.second)
+ {
+ sol_map[s.first] = s.second;
+ }
+ }
+ return true;
+}
+
+void SygusSolver::checkSynthSolution(Assertions& as)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ Notice() << "SygusSolver::checkSynthSolution(): checking synthesis solution"
+ << std::endl;
+ std::map<Node, std::map<Node, Node>> sol_map;
+ // Get solutions and build auxiliary vectors for substituting
+ TheoryEngine* te = d_smtSolver.getTheoryEngine();
+ if (!te->getSynthSolutions(sol_map))
+ {
+ InternalError()
+ << "SygusSolver::checkSynthSolution(): No solution to check!";
+ return;
+ }
+ if (sol_map.empty())
+ {
+ InternalError() << "SygusSolver::checkSynthSolution(): Got empty solution!";
+ return;
+ }
+ Trace("check-synth-sol") << "Got solution map:\n";
+ // the set of synthesis conjectures in our assertions
+ std::unordered_set<Node, NodeHashFunction> conjs;
+ // For each of the above conjectures, the functions-to-synthesis and their
+ // solutions. This is used as a substitution below.
+ std::map<Node, std::vector<Node>> fvarMap;
+ std::map<Node, std::vector<Node>> fsolMap;
+ for (const std::pair<const Node, std::map<Node, Node>>& cmap : sol_map)
+ {
+ Trace("check-synth-sol") << "For conjecture " << cmap.first << ":\n";
+ conjs.insert(cmap.first);
+ std::vector<Node>& fvars = fvarMap[cmap.first];
+ std::vector<Node>& fsols = fsolMap[cmap.first];
+ for (const std::pair<const Node, Node>& pair : cmap.second)
+ {
+ Trace("check-synth-sol")
+ << " " << pair.first << " --> " << pair.second << "\n";
+ fvars.push_back(pair.first);
+ fsols.push_back(pair.second);
+ }
+ }
+ Trace("check-synth-sol") << "Starting new SMT Engine\n";
+
+ Trace("check-synth-sol") << "Retrieving assertions\n";
+ // Build conjecture from original assertions
+ context::CDList<Node>* alist = as.getAssertionList();
+ if (alist == nullptr)
+ {
+ Trace("check-synth-sol") << "No assertions to check\n";
+ return;
+ }
+ // auxiliary assertions
+ std::vector<Node> auxAssertions;
+ // expand definitions cache
+ std::unordered_map<Node, Node, NodeHashFunction> cache;
+ for (Node assertion : *alist)
+ {
+ Notice() << "SygusSolver::checkSynthSolution(): checking assertion "
+ << assertion << std::endl;
+ Trace("check-synth-sol") << "Retrieving assertion " << assertion << "\n";
+ // Apply any define-funs from the problem.
+ Node n = d_pp.expandDefinitions(assertion, cache);
+ Notice() << "SygusSolver::checkSynthSolution(): -- expands to " << n
+ << std::endl;
+ Trace("check-synth-sol") << "Expanded assertion " << n << "\n";
+ if (conjs.find(n) == conjs.end())
+ {
+ Trace("check-synth-sol") << "It is an auxiliary assertion\n";
+ auxAssertions.push_back(n);
+ }
+ else
+ {
+ Trace("check-synth-sol") << "It is a synthesis conjecture\n";
+ }
+ }
+ // check all conjectures
+ for (Node conj : conjs)
+ {
+ // Start new SMT engine to check solutions
+ std::unique_ptr<SmtEngine> solChecker;
+ initializeSubsolver(solChecker);
+ solChecker->getOptions().set(options::checkSynthSol, false);
+ solChecker->getOptions().set(options::sygusRecFun, false);
+ // get the solution for this conjecture
+ std::vector<Node>& fvars = fvarMap[conj];
+ std::vector<Node>& fsols = fsolMap[conj];
+ // Apply solution map to conjecture body
+ Node conjBody;
+ /* Whether property is quantifier free */
+ if (conj[1].getKind() != EXISTS)
+ {
+ conjBody = conj[1].substitute(
+ fvars.begin(), fvars.end(), fsols.begin(), fsols.end());
+ }
+ else
+ {
+ conjBody = conj[1][1].substitute(
+ fvars.begin(), fvars.end(), fsols.begin(), fsols.end());
+
+ /* Skolemize property */
+ std::vector<Node> vars, skos;
+ for (unsigned j = 0, size = conj[1][0].getNumChildren(); j < size; ++j)
+ {
+ vars.push_back(conj[1][0][j]);
+ std::stringstream ss;
+ ss << "sk_" << j;
+ skos.push_back(nm->mkSkolem(ss.str(), conj[1][0][j].getType()));
+ Trace("check-synth-sol") << "\tSkolemizing " << conj[1][0][j] << " to "
+ << skos.back() << "\n";
+ }
+ conjBody = conjBody.substitute(
+ vars.begin(), vars.end(), skos.begin(), skos.end());
+ }
+ Notice() << "SygusSolver::checkSynthSolution(): -- body substitutes to "
+ << conjBody << std::endl;
+ Trace("check-synth-sol")
+ << "Substituted body of assertion to " << conjBody << "\n";
+ solChecker->assertFormula(conjBody);
+ // Assert all auxiliary assertions. This may include recursive function
+ // definitions that were added as assertions to the sygus problem.
+ for (Node a : auxAssertions)
+ {
+ solChecker->assertFormula(a);
+ }
+ Result r = solChecker->checkSat();
+ Notice() << "SygusSolver::checkSynthSolution(): result is " << r
+ << std::endl;
+ Trace("check-synth-sol") << "Satsifiability check: " << r << "\n";
+ if (r.asSatisfiabilityResult().isUnknown())
+ {
+ InternalError() << "SygusSolver::checkSynthSolution(): could not check "
+ "solution, result "
+ "unknown.";
+ }
+ else if (r.asSatisfiabilityResult().isSat())
+ {
+ InternalError()
+ << "SygusSolver::checkSynthSolution(): produced solution leads to "
+ "satisfiable negated conjecture.";
+ }
+ }
+}
+
+void SygusSolver::setSygusConjectureStale()
+{
+ if (d_sygusConjectureStale)
+ {
+ // already stale
+ return;
+ }
+ d_sygusConjectureStale = true;
+ // TODO (project #7): if incremental, we should pop a context
+}
+
+} // namespace smt
+} // namespace CVC4
diff --git a/src/smt/sygus_solver.h b/src/smt/sygus_solver.h
new file mode 100644
index 000000000..b523ff5b7
--- /dev/null
+++ b/src/smt/sygus_solver.h
@@ -0,0 +1,190 @@
+/********************* */
+/*! \file sygus_solver.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Haniel Barbosa, Morgan Deters
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The solver for sygus queries
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__SMT__SYGUS_SOLVER_H
+#define CVC4__SMT__SYGUS_SOLVER_H
+
+#include "context/cdo.h"
+#include "expr/node.h"
+#include "expr/type_node.h"
+#include "smt/assertions.h"
+#include "util/result.h"
+
+namespace CVC4 {
+
+class OutputManager;
+
+namespace smt {
+
+class Preprocessor;
+class SmtSolver;
+
+/**
+ * A solver for sygus queries.
+ *
+ * This class is responsible for responding to check-synth commands. It calls
+ * check satisfiability using an underlying SmtSolver object.
+ *
+ * It also maintains a reference to a preprocessor for implementing
+ * checkSynthSolution.
+ */
+class SygusSolver
+{
+ public:
+ SygusSolver(SmtSolver& sms,
+ Preprocessor& pp,
+ context::UserContext* u,
+ OutputManager& outMgr);
+ ~SygusSolver();
+
+ /**
+ * Add variable declaration.
+ *
+ * Declared SyGuS variables may be used in SyGuS constraints, in which they
+ * are assumed to be universally quantified.
+ *
+ * In SyGuS semantics, declared functions are treated in the same manner as
+ * declared variables, i.e. as universally quantified (function) variables
+ * which can occur in the SyGuS constraints that compose the conjecture to
+ * which a function is being synthesized. Thus declared functions should use
+ * this method as well.
+ */
+ void declareSygusVar(const std::string& id, Node var, TypeNode type);
+
+ /**
+ * Add a function-to-synthesize declaration.
+ *
+ * The given type may not correspond to the actual function type but to a
+ * datatype encoding the syntax restrictions for the
+ * function-to-synthesize. In this case this information is stored to be used
+ * during solving.
+ *
+ * vars contains the arguments of the function-to-synthesize. These variables
+ * are also stored to be used during solving.
+ *
+ * isInv determines whether the function-to-synthesize is actually an
+ * invariant. This information is necessary if we are dumping a command
+ * corresponding to this declaration, so that it can be properly printed.
+ */
+ void declareSynthFun(const std::string& id,
+ Node func,
+ TypeNode type,
+ bool isInv,
+ const std::vector<Node>& vars);
+
+ /** Add a regular sygus constraint.*/
+ void assertSygusConstraint(Node constraint);
+
+ /**
+ * Add an invariant constraint.
+ *
+ * Invariant constraints are not explicitly declared: they are given in terms
+ * of the invariant-to-synthesize, the pre condition, transition relation and
+ * post condition. The actual constraint is built based on the inputs of these
+ * place holder predicates :
+ *
+ * PRE(x) -> INV(x)
+ * INV() ^ TRANS(x, x') -> INV(x')
+ * INV(x) -> POST(x)
+ *
+ * The regular and primed variables are retrieved from the declaration of the
+ * invariant-to-synthesize.
+ */
+ void assertSygusInvConstraint(Node inv, Node pre, Node trans, Node post);
+ /**
+ * Assert a synthesis conjecture to the current context and call
+ * check(). Returns sat, unsat, or unknown result.
+ *
+ * The actual synthesis conjecture is built based on the previously
+ * communicated information to this module (universal variables, defined
+ * functions, functions-to-synthesize, and which constraints compose it). The
+ * built conjecture is a higher-order formula of the form
+ *
+ * exists f1...fn . forall v1...vm . F
+ *
+ * in which f1...fn are the functions-to-synthesize, v1...vm are the declared
+ * universal variables and F is the set of declared constraints.
+ */
+ Result checkSynth(Assertions& as);
+ /**
+ * Get synth solution.
+ *
+ * This method returns true if we are in a state immediately preceded by
+ * a successful call to checkSynth.
+ *
+ * This method adds entries to sol_map that map functions-to-synthesize with
+ * their solutions, for all active conjectures. This should be called
+ * immediately after the solver answers unsat for sygus input.
+ *
+ * Specifically, given a sygus conjecture of the form
+ * exists x1...xn. forall y1...yn. P( x1...xn, y1...yn )
+ * where x1...xn are second order bound variables, we map each xi to
+ * lambda term in sol_map such that
+ * forall y1...yn. P( sol_map[x1]...sol_map[xn], y1...yn )
+ * is a valid formula.
+ */
+ bool getSynthSolutions(std::map<Node, Node>& sol_map);
+
+ private:
+ /**
+ * Check that a solution to a synthesis conjecture is indeed a solution.
+ *
+ * The check is made by determining if the negation of the synthesis
+ * conjecture in which the functions-to-synthesize have been replaced by the
+ * synthesized solutions, which is a quantifier-free formula, is
+ * unsatisfiable. If not, then the found solutions are wrong.
+ */
+ void checkSynthSolution(Assertions& as);
+ /**
+ * Set sygus conjecture is stale. The sygus conjecture is stale if either:
+ * (1) no sygus conjecture has been added as an assertion to this SMT engine,
+ * (2) there is a sygus conjecture that has been added as an assertion
+ * internally to this SMT engine, and there have been further calls such that
+ * the asserted conjecture is no longer up-to-date.
+ *
+ * This method should be called when new sygus constraints are asserted and
+ * when functions-to-synthesize are declared. This function pops a user
+ * context if we are in incremental mode and the sygus conjecture was
+ * previously not stale.
+ */
+ void setSygusConjectureStale();
+ /** The SMT solver, which is used during checkSynth. */
+ SmtSolver& d_smtSolver;
+ /** The preprocessor, used for checkSynthSolution. */
+ Preprocessor& d_pp;
+ /**
+ * sygus variables declared (from "declare-var" and "declare-fun" commands)
+ *
+ * The SyGuS semantics for declared variables is that they are implicitly
+ * universally quantified in the constraints.
+ */
+ std::vector<Node> d_sygusVars;
+ /** sygus constraints */
+ std::vector<Node> d_sygusConstraints;
+ /** functions-to-synthesize */
+ std::vector<Node> d_sygusFunSymbols;
+ /**
+ * Whether we need to reconstruct the sygus conjecture.
+ */
+ context::CDO<bool> d_sygusConjectureStale;
+ /** Reference to the output manager of the smt engine */
+ OutputManager& d_outMgr;
+};
+
+} // namespace smt
+} // namespace CVC4
+
+#endif /* CVC4__SMT__SYGUS_SOLVER_H */
diff --git a/src/smt/term_formula_removal.cpp b/src/smt/term_formula_removal.cpp
index 89091d309..f3e0d0bd6 100644
--- a/src/smt/term_formula_removal.cpp
+++ b/src/smt/term_formula_removal.cpp
@@ -2,10 +2,10 @@
/*! \file term_formula_removal.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Morgan Deters, Dejan Jovanovic
+ ** Andrew Reynolds, Dejan Jovanovic, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,7 +18,8 @@
#include <vector>
#include "expr/node_algorithm.h"
-#include "options/proof_options.h"
+#include "expr/skolem_manager.h"
+#include "options/smt_options.h"
#include "proof/proof_manager.h"
using namespace std;
@@ -26,85 +27,227 @@ using namespace std;
namespace CVC4 {
RemoveTermFormulas::RemoveTermFormulas(context::UserContext* u)
- : d_tfCache(u), d_skolem_cache(u)
+ : d_tfCache(u),
+ d_skolem_cache(u),
+ d_pnm(nullptr),
+ d_tpg(nullptr),
+ d_lp(nullptr)
{
}
RemoveTermFormulas::~RemoveTermFormulas() {}
-void RemoveTermFormulas::run(std::vector<Node>& output, IteSkolemMap& iteSkolemMap, bool reportDeps)
+theory::TrustNode RemoveTermFormulas::run(
+ Node assertion,
+ std::vector<theory::TrustNode>& newAsserts,
+ std::vector<Node>& newSkolems,
+ bool reportDeps)
{
- size_t n = output.size();
- for (unsigned i = 0, i_end = output.size(); i < i_end; ++ i) {
- // 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, false, false);
- // In some calling contexts, not necessary to report dependence information.
- if (reportDeps &&
- (options::unsatCores() || options::fewerPreprocessingHoles())) {
- // new assertions have a dependence on the node
- PROOF( ProofManager::currentPM()->addDependence(itesRemoved, output[i]); )
- while(n < output.size()) {
- PROOF( ProofManager::currentPM()->addDependence(output[n], output[i]); )
- ++n;
+ Node itesRemoved = runInternal(assertion, newAsserts, newSkolems);
+ // In some calling contexts, not necessary to report dependence information.
+ if (reportDeps && options::unsatCores())
+ {
+ // new assertions have a dependence on the node
+ if (options::unsatCores())
+ {
+ ProofManager::currentPM()->addDependence(itesRemoved, assertion);
+ }
+ unsigned n = 0;
+ while (n < newAsserts.size())
+ {
+ if (options::unsatCores())
+ {
+ ProofManager::currentPM()->addDependence(newAsserts[n].getProven(),
+ assertion);
}
+ ++n;
}
- output[i] = itesRemoved;
}
+ // The rewriting of assertion can be justified by the term conversion proof
+ // generator d_tpg.
+ return theory::TrustNode::mkTrustRewrite(assertion, itesRemoved, d_tpg.get());
}
-Node RemoveTermFormulas::run(TNode node, std::vector<Node>& output,
- IteSkolemMap& iteSkolemMap, bool inQuant, bool inTerm) {
- // Current node
- Debug("ite") << "removeITEs(" << node << ")" << " " << inQuant << " " << inTerm << endl;
-
- //if(node.isVar() || node.isConst()){
- // (options::biasedITERemoval() && !containsTermITE(node))){
- //if(node.isVar()){
- // return Node(node);
- //}
- if( node.getKind()==kind::INST_PATTERN_LIST ){
- return Node(node);
+Node RemoveTermFormulas::runInternal(Node assertion,
+ std::vector<theory::TrustNode>& output,
+ std::vector<Node>& newSkolems)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ TCtxStack ctx(&d_rtfc);
+ std::vector<bool> processedChildren;
+ ctx.pushInitial(assertion);
+ processedChildren.push_back(false);
+ std::pair<Node, uint32_t> initial = ctx.getCurrent();
+ std::pair<Node, uint32_t> curr;
+ Node node;
+ uint32_t nodeVal;
+ TermFormulaCache::const_iterator itc;
+ while (!ctx.empty())
+ {
+ curr = ctx.getCurrent();
+ itc = d_tfCache.find(curr);
+ node = curr.first;
+ nodeVal = curr.second;
+ Trace("rtf-debug") << "Visit " << node << ", " << nodeVal << std::endl;
+ if (itc != d_tfCache.end())
+ {
+ Trace("rtf-debug") << "...already computed" << std::endl;
+ ctx.pop();
+ processedChildren.pop_back();
+ // already computed
+ continue;
+ }
+ // if we have yet to process children
+ if (!processedChildren.back())
+ {
+ // check if we should replace the current node
+ Node currt = runCurrent(curr, output, newSkolems);
+ // if null, we need to recurse
+ if (!currt.isNull())
+ {
+ Trace("rtf-debug") << "...replace by skolem" << std::endl;
+ d_tfCache.insert(curr, currt);
+ ctx.pop();
+ processedChildren.pop_back();
+ }
+ else
+ {
+ size_t nchild = node.getNumChildren();
+ if (nchild > 0)
+ {
+ Trace("rtf-debug") << "...recurse to children" << std::endl;
+ // recurse if we have children
+ processedChildren[processedChildren.size() - 1] = true;
+ for (size_t i = 0; i < nchild; i++)
+ {
+ ctx.pushChild(node, nodeVal, i);
+ processedChildren.push_back(false);
+ }
+ }
+ else
+ {
+ Trace("rtf-debug") << "...base case" << std::endl;
+ d_tfCache.insert(curr, node);
+ ctx.pop();
+ processedChildren.pop_back();
+ }
+ }
+ continue;
+ }
+ Trace("rtf-debug") << "...reconstruct" << std::endl;
+ // otherwise, we are now finished processing children, pop the current node
+ // and compute the result
+ ctx.pop();
+ processedChildren.pop_back();
+ // if we have not already computed the result
+ std::vector<Node> newChildren;
+ bool childChanged = false;
+ if (node.getMetaKind() == kind::metakind::PARAMETERIZED)
+ {
+ newChildren.push_back(node.getOperator());
+ }
+ // reconstruct from the children
+ std::pair<Node, uint32_t> currChild;
+ for (size_t i = 0, nchild = node.getNumChildren(); i < nchild; i++)
+ {
+ // recompute the value of the child
+ uint32_t val = d_rtfc.computeValue(node, nodeVal, i);
+ currChild = std::pair<Node, uint32_t>(node[i], val);
+ itc = d_tfCache.find(currChild);
+ Assert(itc != d_tfCache.end());
+ Node newChild = (*itc).second;
+ Assert(!newChild.isNull());
+ childChanged |= (newChild != node[i]);
+ newChildren.push_back(newChild);
+ }
+ // If changes, we reconstruct the node
+ Node ret = node;
+ if (childChanged)
+ {
+ ret = nm->mkNode(node.getKind(), newChildren);
+ }
+ // cache
+ d_tfCache.insert(curr, ret);
}
+ itc = d_tfCache.find(initial);
+ Assert(itc != d_tfCache.end());
+ return (*itc).second;
+}
- // The result may be cached already
- int cv = cacheVal( inQuant, inTerm );
- std::pair<Node, int> cacheKey(node, cv);
- NodeManager *nodeManager = NodeManager::currentNM();
- TermFormulaCache::const_iterator i = d_tfCache.find(cacheKey);
- if (i != d_tfCache.end())
+Node RemoveTermFormulas::runCurrent(std::pair<Node, uint32_t>& curr,
+ std::vector<theory::TrustNode>& output,
+ std::vector<Node>& newSkolems)
+{
+ TNode node = curr.first;
+ if (node.getKind() == kind::INST_PATTERN_LIST)
{
- Node cached = (*i).second;
- Debug("ite") << "removeITEs: in-cache: " << cached << endl;
- return cached.isNull() ? Node(node) : cached;
+ return Node(node);
}
+ uint32_t cval = curr.second;
+ bool inQuant, inTerm;
+ RtfTermContext::getFlags(curr.second, inQuant, inTerm);
+ Debug("ite") << "removeITEs(" << node << ")"
+ << " " << inQuant << " " << inTerm << std::endl;
+ NodeManager *nodeManager = NodeManager::currentNM();
TypeNode nodeType = node.getType();
Node skolem;
Node newAssertion;
+ // the exists form of the assertion
+ ProofGenerator* newAssertionPg = nullptr;
// Handle non-Boolean ITEs here. Boolean ones (within terms) are handled
// in the "non-variable Boolean term within term" case below.
if (node.getKind() == kind::ITE && !nodeType.isBoolean())
{
- // Here, we eliminate the ITE if we are not Boolean and if we do not contain
- // a free variable.
- if (!inQuant || !expr::hasFreeVar(node))
+ // Here, we eliminate the ITE if we are not Boolean and if we are
+ // not in a quantified formula. This policy should be in sync with
+ // the policy for when to apply theory preprocessing to terms, see PR
+ // #5497.
+ if (!inQuant)
{
skolem = getSkolemForNode(node);
if (skolem.isNull())
{
+ Trace("rtf-proof-debug")
+ << "RemoveTermFormulas::run: make ITE skolem" << std::endl;
// Make the skolem to represent the ITE
- skolem = nodeManager->mkSkolem(
+ SkolemManager* sm = nodeManager->getSkolemManager();
+ skolem = sm->mkPurifySkolem(
+ node,
"termITE",
- nodeType,
"a variable introduced due to term-level ITE removal");
d_skolem_cache.insert(node, skolem);
// The new assertion
newAssertion = nodeManager->mkNode(
kind::ITE, node[0], skolem.eqNode(node[1]), skolem.eqNode(node[2]));
+
+ // we justify it internally
+ if (isProofEnabled())
+ {
+ Trace("rtf-proof-debug")
+ << "RemoveTermFormulas::run: justify " << newAssertion
+ << " with ITE axiom" << std::endl;
+ // ---------------------- REMOVE_TERM_FORMULA_AXIOM
+ // (ite node[0]
+ // (= node node[1]) ------------- MACRO_SR_PRED_INTRO
+ // (= node node[2])) node = skolem
+ // ------------------------------------------ MACRO_SR_PRED_TRANSFORM
+ // (ite node[0] (= skolem node[1]) (= skolem node[2]))
+ //
+ // Note that the MACRO_SR_PRED_INTRO step holds due to conversion
+ // of skolem into its witness form, which is node.
+ Node axiom = getAxiomFor(node);
+ d_lp->addStep(axiom, PfRule::REMOVE_TERM_FORMULA_AXIOM, {}, {node});
+ Node eq = node.eqNode(skolem);
+ d_lp->addStep(eq, PfRule::MACRO_SR_PRED_INTRO, {}, {eq});
+ d_lp->addStep(newAssertion,
+ PfRule::MACRO_SR_PRED_TRANSFORM,
+ {axiom, eq},
+ {newAssertion});
+ newAssertionPg = d_lp.get();
+ }
}
}
}
@@ -116,10 +259,13 @@ Node RemoveTermFormulas::run(TNode node, std::vector<Node>& output,
skolem = getSkolemForNode(node);
if (skolem.isNull())
{
+ Trace("rtf-proof-debug")
+ << "RemoveTermFormulas::run: make LAMBDA skolem" << std::endl;
// Make the skolem to represent the lambda
- skolem = nodeManager->mkSkolem(
+ SkolemManager* sm = nodeManager->getSkolemManager();
+ skolem = sm->mkPurifySkolem(
+ node,
"lambdaF",
- nodeType,
"a function introduced due to term-level lambda removal");
d_skolem_cache.insert(node, skolem);
@@ -135,6 +281,15 @@ Node RemoveTermFormulas::run(TNode node, std::vector<Node>& output,
children.push_back(skolem_app.eqNode(node[1]));
// axiom defining skolem
newAssertion = nodeManager->mkNode(kind::FORALL, children);
+
+ // Lambda lifting is trivial to justify, hence we don't set a proof
+ // generator here. In particular, replacing the skolem introduced
+ // here with its original lambda ensures the new assertion rewrites
+ // to true.
+ // For example, if (lambda y. t[y]) has skolem k, then this lemma is:
+ // forall x. k(x)=t[x]
+ // whose witness form rewrites
+ // forall x. (lambda y. t[y])(x)=t[x] --> forall x. t[x]=t[x] --> true
}
}
}
@@ -145,13 +300,18 @@ Node RemoveTermFormulas::run(TNode node, std::vector<Node>& output,
// http://planetmath.org/hilbertsvarepsilonoperator.
if (!inQuant || !expr::hasFreeVar(node))
{
+ // NOTE: we can replace by t if body is of the form (and (= z t) ...)
skolem = getSkolemForNode(node);
if (skolem.isNull())
{
- // Make the skolem to witness the choice
- skolem = nodeManager->mkSkolem(
+ Trace("rtf-proof-debug")
+ << "RemoveTermFormulas::run: make WITNESS skolem" << std::endl;
+ // Make the skolem to witness the choice, which notice is handled
+ // as a special case within SkolemManager::mkPurifySkolem.
+ SkolemManager* sm = nodeManager->getSkolemManager();
+ skolem = sm->mkPurifySkolem(
+ node,
"witnessK",
- nodeType,
"a skolem introduced due to term-level witness removal");
d_skolem_cache.insert(node, skolem);
@@ -160,6 +320,28 @@ Node RemoveTermFormulas::run(TNode node, std::vector<Node>& output,
// The new assertion is the assumption that the body
// of the witness operator holds for the Skolem
newAssertion = node[1].substitute(node[0][0], skolem);
+
+ // Get the proof generator, if one exists, which was responsible for
+ // constructing this witness term. This may not exist, in which case
+ // the witness term was trivial to justify. This is the case e.g. for
+ // purification witness terms.
+ if (isProofEnabled())
+ {
+ Node existsAssertion =
+ nodeManager->mkNode(kind::EXISTS, node[0], node[1]);
+ // -------------------- from skolem manager
+ // (exists x. node[1])
+ // -------------------- SKOLEMIZE
+ // node[1] * { x -> skolem }
+ ProofGenerator* expg = sm->getProofGenerator(existsAssertion);
+ d_lp->addLazyStep(existsAssertion,
+ expg,
+ PfRule::WITNESS_AXIOM,
+ true,
+ "RemoveTermFormulas::run:skolem_pf");
+ d_lp->addStep(newAssertion, PfRule::SKOLEMIZE, {existsAssertion}, {});
+ newAssertionPg = d_lp.get();
+ }
}
}
}
@@ -171,74 +353,117 @@ Node RemoveTermFormulas::run(TNode node, std::vector<Node>& output,
skolem = getSkolemForNode(node);
if (skolem.isNull())
{
+ Trace("rtf-proof-debug")
+ << "RemoveTermFormulas::run: make BOOLEAN_TERM_VARIABLE skolem"
+ << std::endl;
// Make the skolem to represent the Boolean term
// Skolems introduced for Boolean formulas appearing in terms have a
// special kind (BOOLEAN_TERM_VARIABLE) that ensures they are handled
// properly in theory combination. We must use this kind here instead of a
- // generic skolem.
- skolem = nodeManager->mkBooleanTermVariable();
+ // generic skolem. Notice that the name/comment are currently ignored
+ // within SkolemManager::mkPurifySkolem, since BOOLEAN_TERM_VARIABLE
+ // variables cannot be given names.
+ SkolemManager* sm = nodeManager->getSkolemManager();
+ skolem = sm->mkPurifySkolem(
+ node,
+ "btvK",
+ "a Boolean term variable introduced during term formula removal",
+ NodeManager::SKOLEM_BOOL_TERM_VAR);
d_skolem_cache.insert(node, skolem);
// The new assertion
newAssertion = skolem.eqNode(node);
+
+ // Boolean term removal is trivial to justify, hence we don't set a proof
+ // generator here. It is trivial to justify since it is an instance of
+ // purification, which is justified by conversion to witness forms.
}
}
// if the term should be replaced by a skolem
if( !skolem.isNull() ){
- // Attach the skolem
- d_tfCache.insert(cacheKey, skolem);
+ // this must be done regardless of whether the assertion was new below,
+ // since a formula-term may rewrite to the same skolem in multiple contexts.
+ if (isProofEnabled())
+ {
+ // justify the introduction of the skolem
+ // ------------------- MACRO_SR_PRED_INTRO
+ // t = witness x. x=t
+ // The above step is trivial, since the skolems introduced above are
+ // all purification skolems. We record this equality in the term
+ // conversion proof generator.
+ d_tpg->addRewriteStep(node,
+ skolem,
+ PfRule::MACRO_SR_PRED_INTRO,
+ {},
+ {node.eqNode(skolem)},
+ cval);
+ }
// if the skolem was introduced in this call
if (!newAssertion.isNull())
{
- Debug("ite") << "*** term formula removal introduced " << skolem
- << " for " << node << std::endl;
+ Trace("rtf-proof-debug")
+ << "RemoveTermFormulas::run: setup proof for new assertion "
+ << newAssertion << std::endl;
+ // if proofs are enabled
+ if (isProofEnabled())
+ {
+ // justify the axiom that defines the skolem, if not already done so
+ if (newAssertionPg == nullptr)
+ {
+ // Should have trivial justification if not yet provided. This is the
+ // case of lambda lifting and Boolean term removal.
+ // ---------------- MACRO_SR_PRED_INTRO
+ // newAssertion
+ d_lp->addStep(
+ newAssertion, PfRule::MACRO_SR_PRED_INTRO, {}, {newAssertion});
+ }
+ }
+ Trace("rtf-debug") << "*** term formula removal introduced " << skolem
+ << " for " << node << std::endl;
// Remove ITEs from the new assertion, rewrite it and push it to the
// output
- newAssertion = run(newAssertion, output, iteSkolemMap, false, false);
+ Node newAssertionPre = newAssertion;
+ newAssertion = runInternal(newAssertion, output, newSkolems);
+
+ if (isProofEnabled())
+ {
+ if (newAssertionPre != newAssertion)
+ {
+ Trace("rtf-proof-debug")
+ << "RemoveTermFormulas::run: setup proof for processed new lemma"
+ << std::endl;
+ // for new assertions that rewrite recursively
+ Node naEq = newAssertionPre.eqNode(newAssertion);
+ d_lp->addLazyStep(naEq, d_tpg.get());
+ // ---------------- from lp ------------------------------- from tpg
+ // newAssertionPre newAssertionPre = newAssertion
+ // ------------------------------------------------------- EQ_RESOLVE
+ // newAssertion
+ d_lp->addStep(
+ newAssertion, PfRule::EQ_RESOLVE, {newAssertionPre, naEq}, {});
+ }
+ }
+
+ theory::TrustNode trna =
+ theory::TrustNode::mkTrustLemma(newAssertion, d_lp.get());
+
+ Trace("rtf-proof-debug") << "Checking closed..." << std::endl;
+ trna.debugCheckClosed("rtf-proof-debug",
+ "RemoveTermFormulas::run:new_assert");
- iteSkolemMap[skolem] = output.size();
- output.push_back(newAssertion);
+ output.push_back(trna);
+ newSkolems.push_back(skolem);
}
// The representation is now the skolem
return skolem;
}
- if (node.isClosure())
- {
- // Remember if we're inside a quantifier
- inQuant = true;
- }else if( !inTerm && hasNestedTermChildren( node ) ){
- // Remember if we're inside a term
- Debug("ite") << "In term because of " << node << " " << node.getKind() << std::endl;
- inTerm = true;
- }
-
- // If not an ITE, go deep
- vector<Node> newChildren;
- bool somethingChanged = false;
- if(node.getMetaKind() == kind::metakind::PARAMETERIZED) {
- newChildren.push_back(node.getOperator());
- }
- // Remove the ITEs from the children
- for(TNode::const_iterator it = node.begin(), end = node.end(); it != end; ++it) {
- Node newChild = run(*it, output, iteSkolemMap, inQuant, inTerm);
- somethingChanged |= (newChild != *it);
- newChildren.push_back(newChild);
- }
-
- // If changes, we rewrite
- if(somethingChanged) {
- Node cached = nodeManager->mkNode(node.getKind(), newChildren);
- d_tfCache.insert(cacheKey, cached);
- return cached;
- } else {
- d_tfCache.insert(cacheKey, Node::null());
- return node;
- }
+ // return null, indicating we will traverse children within runInternal
+ return Node::null();
}
Node RemoveTermFormulas::getSkolemForNode(Node node) const
@@ -252,57 +477,87 @@ Node RemoveTermFormulas::getSkolemForNode(Node node) const
return Node::null();
}
-Node RemoveTermFormulas::replace(TNode node, bool inQuant, bool inTerm) const {
+Node RemoveTermFormulas::replace(TNode node) const
+{
+ TCtxStack ctx(&d_rtfc);
+ ctx.pushInitial(node);
+ return replaceInternal(ctx);
+}
+
+Node RemoveTermFormulas::replaceInternal(TCtxStack& ctx) const
+{
+ // get the current node, tagged with a term context identifier
+ Assert(!ctx.empty());
+ std::pair<Node, uint32_t> curr = ctx.getCurrent();
+ ctx.pop();
+ TNode node = curr.first;
+
if( node.getKind()==kind::INST_PATTERN_LIST ){
return Node(node);
}
// Check the cache
- NodeManager *nodeManager = NodeManager::currentNM();
- int cv = cacheVal( inQuant, inTerm );
- TermFormulaCache::const_iterator i = d_tfCache.find(make_pair(node, cv));
- if (i != d_tfCache.end())
+ TermFormulaCache::const_iterator itc = d_tfCache.find(curr);
+ if (itc != d_tfCache.end())
{
- Node cached = (*i).second;
- return cached.isNull() ? Node(node) : cached;
+ return (*itc).second;
}
- if (node.isClosure())
- {
- // Remember if we're inside a quantifier
- inQuant = true;
- }else if( !inTerm && hasNestedTermChildren( node ) ){
- // Remember if we're inside a term
- inTerm = true;
- }
-
vector<Node> newChildren;
bool somethingChanged = false;
if(node.getMetaKind() == kind::metakind::PARAMETERIZED) {
newChildren.push_back(node.getOperator());
}
// Replace in children
- for(TNode::const_iterator it = node.begin(), end = node.end(); it != end; ++it) {
- Node newChild = replace(*it, inQuant, inTerm);
- somethingChanged |= (newChild != *it);
+ uint32_t cval = curr.second;
+ for (size_t i = 0, nchild = node.getNumChildren(); i < nchild; i++)
+ {
+ ctx.pushChild(node, cval, i);
+ Node newChild = replaceInternal(ctx);
+ somethingChanged |= (newChild != node[i]);
newChildren.push_back(newChild);
}
// If changes, we rewrite
if(somethingChanged) {
- return nodeManager->mkNode(node.getKind(), newChildren);
- } else {
- return node;
+ return NodeManager::currentNM()->mkNode(node.getKind(), newChildren);
+ }
+ return node;
+}
+
+Node RemoveTermFormulas::getAxiomFor(Node n)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ Kind k = n.getKind();
+ if (k == kind::ITE)
+ {
+ return nm->mkNode(kind::ITE, n[0], n.eqNode(n[1]), n.eqNode(n[2]));
+ }
+ return Node::null();
+}
+
+void RemoveTermFormulas::setProofNodeManager(ProofNodeManager* pnm)
+{
+ if (d_tpg == nullptr)
+ {
+ d_pnm = pnm;
+ d_tpg.reset(
+ new TConvProofGenerator(d_pnm,
+ nullptr,
+ TConvPolicy::FIXPOINT,
+ TConvCachePolicy::NEVER,
+ "RemoveTermFormulas::TConvProofGenerator",
+ &d_rtfc));
+ d_lp.reset(new LazyCDProof(
+ d_pnm, nullptr, nullptr, "RemoveTermFormulas::LazyCDProof"));
}
}
-// returns true if the children of node should be considered nested terms
-bool RemoveTermFormulas::hasNestedTermChildren( TNode node ) {
- return theory::kindToTheoryId(node.getKind())!=theory::THEORY_BOOL &&
- node.getKind()!=kind::EQUAL && node.getKind()!=kind::SEP_STAR &&
- node.getKind()!=kind::SEP_WAND && node.getKind()!=kind::SEP_LABEL &&
- node.getKind()!=kind::BITVECTOR_EAGER_ATOM;
- // dont' worry about FORALL or EXISTS (handled separately)
+ProofGenerator* RemoveTermFormulas::getTConvProofGenerator()
+{
+ return d_tpg.get();
}
+bool RemoveTermFormulas::isProofEnabled() const { return d_pnm != nullptr; }
+
}/* CVC4 namespace */
diff --git a/src/smt/term_formula_removal.h b/src/smt/term_formula_removal.h
index 9ec12cb12..25dcd0295 100644
--- a/src/smt/term_formula_removal.h
+++ b/src/smt/term_formula_removal.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -23,8 +23,12 @@
#include "context/cdinsert_hashmap.h"
#include "context/context.h"
+#include "expr/lazy_proof.h"
#include "expr/node.h"
-#include "smt/dump.h"
+#include "expr/term_context_stack.h"
+#include "expr/term_conversion_proof_generator.h"
+#include "theory/eager_proof_generator.h"
+#include "theory/trust_node.h"
#include "util/bool.h"
#include "util/hash.h"
@@ -33,52 +37,7 @@ namespace CVC4 {
typedef std::unordered_map<Node, unsigned, NodeHashFunction> IteSkolemMap;
class RemoveTermFormulas {
- typedef context::
- CDInsertHashMap<std::pair<Node, int>,
- Node,
- PairHashFunction<Node, int, NodeHashFunction> >
- TermFormulaCache;
- /** term formula removal cache
- *
- * This stores the results of term formula removal for inputs to the run(...)
- * function below, where the integer in the pair we hash on is the
- * result of cacheVal below.
- */
- TermFormulaCache d_tfCache;
-
- /** return the integer cache value for the input flags to run(...) */
- static inline int cacheVal( bool inQuant, bool inTerm ) { return (inQuant ? 1 : 0) + 2*(inTerm ? 1 : 0); }
-
- /** skolem cache
- *
- * This is a cache that maps terms to the skolem we use to replace them.
- *
- * Notice that this cache is necessary in addition to d_tfCache, since
- * we should use the same skolem to replace terms, regardless of the input
- * arguments to run(...). For example:
- *
- * ite( G, a, b ) = c ^ forall x. P( ite( G, a, b ), x )
- *
- * should be processed to:
- *
- * k = c ^ forall x. P( k, x ) ^ ite( G, k=a, k=b )
- *
- * where notice
- * d_skolem_cache[ite( G, a, b )] = k, and
- * d_tfCache[<ite( G, a, b ),0>] = d_tfCache[<ite( G, a, b ),1>] = k.
- */
- context::CDInsertHashMap<Node, Node, NodeHashFunction> d_skolem_cache;
-
- /** gets the skolem for node
- *
- * This returns the d_skolem_cache value for node, if it exists as a key
- * in the above map, or the null node otherwise.
- */
- inline Node getSkolemForNode(Node node) const;
-
- static bool hasNestedTermChildren( TNode node );
-public:
-
+ public:
RemoveTermFormulas(context::UserContext* u);
~RemoveTermFormulas();
@@ -119,34 +78,140 @@ public:
*
* With reportDeps true, report reasoning dependences to the proof
* manager (for unsat cores).
- */
- void run(std::vector<Node>& assertions, IteSkolemMap& iteSkolemMap, bool reportDeps = false);
-
- /**
- * Removes terms of the form (1), (2), (3) described above from node.
- * All additional assertions are pushed into
- * assertions. iteSkolemMap contains a map from introduced skolem
- * variables to the index in assertions containing the new Boolean
- * ite created in conjunction with that skolem variable.
*
- * inQuant is whether we are processing node in the body of quantified formula
- * inTerm is whether we are are processing node in a "term" position, that is, it is a subterm
- * of a parent term that is not a Boolean connective.
+ * @param assertion The assertion to remove term formulas from
+ * @param newAsserts The new assertions corresponding to axioms for newly
+ * introduced skolems.
+ * @param newSkolems The skolems corresponding to each of the newAsserts.
+ * @param reportDeps Used for unsat cores in the old proof infrastructure.
+ * @return a trust node of kind TrustNodeKind::REWRITE whose
+ * right hand side is assertion after removing term formulas, and the proof
+ * generator (if provided) that can prove the equivalence.
*/
- Node run(TNode node, std::vector<Node>& additionalAssertions,
- IteSkolemMap& iteSkolemMap, bool inQuant, bool inTerm);
+ theory::TrustNode run(Node assertion,
+ std::vector<theory::TrustNode>& newAsserts,
+ std::vector<Node>& newSkolems,
+ bool reportDeps = false);
/**
* Substitute under node using pre-existing cache. Do not remove
* any ITEs not seen during previous runs.
*/
- Node replace(TNode node, bool inQuant = false, bool inTerm = false) const;
+ Node replace(TNode node) const;
/** Returns true if e contains a term ite. */
bool containsTermITE(TNode e) const;
/** Garbage collects non-context dependent data-structures. */
void garbageCollect();
+
+ /**
+ * Set proof node manager, which signals this class to enable proofs using the
+ * given proof node manager.
+ */
+ void setProofNodeManager(ProofNodeManager* pnm);
+
+ /**
+ * Get proof generator that is responsible for all proofs for removing term
+ * formulas from nodes. When proofs are enabled, the returned trust node
+ * of the run method use this proof generator (the trust nodes in newAsserts
+ * do not use this generator).
+ */
+ ProofGenerator* getTConvProofGenerator();
+
+ /**
+ * Get axiom for term n. This returns the axiom that this class uses to
+ * eliminate the term n, which is determined by its top-most symbol. For
+ * example, if n is (ite n1 n2 n3), this returns the formula:
+ * (ite n1 (= (ite n1 n2 n3) n2) (= (ite n1 n2 n3) n3))
+ */
+ static Node getAxiomFor(Node n);
+
+ private:
+ typedef context::CDInsertHashMap<
+ std::pair<Node, uint32_t>,
+ Node,
+ PairHashFunction<Node, uint32_t, NodeHashFunction> >
+ TermFormulaCache;
+ /** term formula removal cache
+ *
+ * This stores the results of term formula removal for inputs to the run(...)
+ * function below, where the integer in the pair we hash on is the
+ * result of cacheVal below.
+ */
+ TermFormulaCache d_tfCache;
+
+ /** skolem cache
+ *
+ * This is a cache that maps terms to the skolem we use to replace them.
+ *
+ * Notice that this cache is necessary in addition to d_tfCache, since
+ * we should use the same skolem to replace terms, regardless of the input
+ * arguments to run(...). For example:
+ *
+ * ite( G, a, b ) = c ^ forall x. P( ite( G, a, b ), x )
+ *
+ * should be processed to:
+ *
+ * k = c ^ forall x. P( k, x ) ^ ite( G, k=a, k=b )
+ *
+ * where notice
+ * d_skolem_cache[ite( G, a, b )] = k, and
+ * d_tfCache[<ite( G, a, b ),0>] = d_tfCache[<ite( G, a, b ),1>] = k.
+ */
+ context::CDInsertHashMap<Node, Node, NodeHashFunction> d_skolem_cache;
+
+ /** gets the skolem for node
+ *
+ * This returns the d_skolem_cache value for node, if it exists as a key
+ * in the above map, or the null node otherwise.
+ */
+ inline Node getSkolemForNode(Node node) const;
+
+ /** Pointer to a proof node manager */
+ ProofNodeManager* d_pnm;
+ /**
+ * A proof generator for the term conversion.
+ */
+ std::unique_ptr<TConvProofGenerator> d_tpg;
+ /**
+ * A proof generator for skolems we introduce that are based on axioms that
+ * this class is responsible for.
+ */
+ std::unique_ptr<LazyCDProof> d_lp;
+ /**
+ * The remove term formula context, which computes hash values for term
+ * contexts.
+ */
+ RtfTermContext d_rtfc;
+
+ /**
+ * Removes terms of the forms described above from formula assertion.
+ * All additional assertions and skolems are pushed into newAsserts and
+ * newSkolems, which are always of the same length.
+ *
+ * This uses a term-context-sensitive stack to process assertion. It returns
+ * the version of assertion with all term formulas removed.
+ */
+ Node runInternal(Node assertion,
+ std::vector<theory::TrustNode>& newAsserts,
+ std::vector<Node>& newSkolems);
+ /**
+ * This is called on curr of the form (t, val) where t is a term and val is
+ * a term context identifier computed by RtfTermContext. If curr should be
+ * replaced by a skolem, this method returns this skolem k, adds k to
+ * newSkolems and adds the axiom defining that skolem to newAsserts, where
+ * runInternal is called on that axiom. Otherwise, this method returns the
+ * null node.
+ */
+ Node runCurrent(std::pair<Node, uint32_t>& curr,
+ std::vector<theory::TrustNode>& newAsserts,
+ std::vector<Node>& newSkolems);
+ /** Replace internal */
+ Node replaceInternal(TCtxStack& ctx) const;
+
+ /** Whether proofs are enabled */
+ bool isProofEnabled() const;
};/* class RemoveTTE */
}/* CVC4 namespace */
diff --git a/src/smt/update_ostream.h b/src/smt/update_ostream.h
index 51fbc66e1..e2a482e30 100644
--- a/src/smt/update_ostream.h
+++ b/src/smt/update_ostream.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -37,21 +37,18 @@ class ChannelSettings {
ChannelSettings(std::ostream& out)
: d_dagSetting(expr::ExprDag::getDag(out)),
d_exprDepthSetting(expr::ExprSetDepth::getDepth(out)),
- d_printtypesSetting(expr::ExprPrintTypes::getPrintTypes(out)),
d_languageSetting(language::SetLanguage::getLanguage(out))
{}
void apply(std::ostream& out) {
out << expr::ExprDag(d_dagSetting);
out << expr::ExprSetDepth(d_exprDepthSetting);
- out << expr::ExprPrintTypes(d_printtypesSetting);
out << language::SetLanguage(d_languageSetting);
}
private:
const int d_dagSetting;
const size_t d_exprDepthSetting;
- const bool d_printtypesSetting;
const OutputLanguage d_languageSetting;
}; /* class ChannelSettings */
diff --git a/src/smt/witness_form.cpp b/src/smt/witness_form.cpp
new file mode 100644
index 000000000..9c2c035a8
--- /dev/null
+++ b/src/smt/witness_form.cpp
@@ -0,0 +1,182 @@
+/********************* */
+/*! \file witness_form.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The module for managing witness form conversion in proofs
+ **/
+
+#include "smt/witness_form.h"
+
+#include "expr/skolem_manager.h"
+#include "theory/rewriter.h"
+
+namespace CVC4 {
+namespace smt {
+
+WitnessFormGenerator::WitnessFormGenerator(ProofNodeManager* pnm)
+ : d_tcpg(pnm,
+ nullptr,
+ TConvPolicy::FIXPOINT,
+ TConvCachePolicy::NEVER,
+ "WfGenerator::TConvProofGenerator",
+ nullptr,
+ true),
+ d_wintroPf(pnm, nullptr, nullptr, "WfGenerator::LazyCDProof"),
+ d_pskPf(pnm, nullptr, "WfGenerator::PurifySkolemProof")
+{
+}
+
+std::shared_ptr<ProofNode> WitnessFormGenerator::getProofFor(Node eq)
+{
+ if (eq.getKind() != kind::EQUAL)
+ {
+ // expecting an equality
+ return nullptr;
+ }
+ Node lhs = eq[0];
+ Node rhs = convertToWitnessForm(eq[0]);
+ if (rhs != eq[1])
+ {
+ // expecting witness form
+ return nullptr;
+ }
+ std::shared_ptr<ProofNode> pn = d_tcpg.getProofFor(eq);
+ Assert(pn != nullptr);
+ return pn;
+}
+
+std::string WitnessFormGenerator::identify() const
+{
+ return "WitnessFormGenerator";
+}
+
+Node WitnessFormGenerator::convertToWitnessForm(Node t)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ SkolemManager* skm = nm->getSkolemManager();
+ Node tw = SkolemManager::getWitnessForm(t);
+ if (t == tw)
+ {
+ // trivial case
+ return tw;
+ }
+ std::unordered_set<TNode, TNodeHashFunction>::iterator it;
+ std::vector<TNode> visit;
+ TNode cur;
+ TNode curw;
+ visit.push_back(t);
+ do
+ {
+ cur = visit.back();
+ visit.pop_back();
+ it = d_visited.find(cur);
+ if (it == d_visited.end())
+ {
+ d_visited.insert(cur);
+ curw = SkolemManager::getWitnessForm(cur);
+ // if its witness form is different
+ if (cur != curw)
+ {
+ if (cur.isVar())
+ {
+ Node eq = cur.eqNode(curw);
+ // equality between a variable and its witness form
+ d_eqs.insert(eq);
+ Assert(curw.getKind() == kind::WITNESS);
+ Node skBody = SkolemManager::getSkolemForm(curw[1]);
+ Node exists = nm->mkNode(kind::EXISTS, curw[0], skBody);
+ ProofGenerator* pg = skm->getProofGenerator(exists);
+ if (pg == nullptr)
+ {
+ // it may be a purification skolem
+ pg = convertExistsInternal(exists);
+ if (pg == nullptr)
+ {
+ // if no proof generator is provided, we justify the existential
+ // using the WITNESS_AXIOM trusted rule by providing it to the
+ // call to addLazyStep below.
+ Trace("witness-form")
+ << "WitnessFormGenerator: No proof generator for " << exists
+ << std::endl;
+ }
+ }
+ // --------------------------- from pg
+ // (exists ((x T)) (P x))
+ // --------------------------- WITNESS_INTRO
+ // k = (witness ((x T)) (P x))
+ d_wintroPf.addLazyStep(
+ exists,
+ pg,
+ PfRule::WITNESS_AXIOM,
+ true,
+ "WitnessFormGenerator::convertToWitnessForm:witness_axiom");
+ d_wintroPf.addStep(eq, PfRule::WITNESS_INTRO, {exists}, {});
+ d_tcpg.addRewriteStep(cur, curw, &d_wintroPf, PfRule::ASSUME, true);
+ }
+ else
+ {
+ // A term whose witness form is different from itself, recurse.
+ // It should be the case that cur has children, since the witness
+ // form of constants are themselves.
+ Assert(cur.getNumChildren() > 0);
+ if (cur.hasOperator())
+ {
+ visit.push_back(cur.getOperator());
+ }
+ visit.insert(visit.end(), cur.begin(), cur.end());
+ }
+ }
+ }
+ } while (!visit.empty());
+ return tw;
+}
+
+bool WitnessFormGenerator::requiresWitnessFormTransform(Node t, Node s) const
+{
+ return theory::Rewriter::rewrite(t) != theory::Rewriter::rewrite(s);
+}
+
+bool WitnessFormGenerator::requiresWitnessFormIntro(Node t) const
+{
+ Node tr = theory::Rewriter::rewrite(t);
+ return !tr.isConst() || !tr.getConst<bool>();
+}
+
+const std::unordered_set<Node, NodeHashFunction>&
+WitnessFormGenerator::getWitnessFormEqs() const
+{
+ return d_eqs;
+}
+
+ProofGenerator* WitnessFormGenerator::convertExistsInternal(Node exists)
+{
+ Assert(exists.getKind() == kind::EXISTS);
+ if (exists[0].getNumChildren() == 1 && exists[1].getKind() == kind::EQUAL
+ && exists[1][0] == exists[0][0])
+ {
+ Node tpurified = exists[1][1];
+ Trace("witness-form") << "convertExistsInternal: infer purification "
+ << exists << " for " << tpurified << std::endl;
+ // ------ REFL
+ // t = t
+ // ---------------- EXISTS_INTRO
+ // exists x. x = t
+ // The concluded existential is then used to construct the witness term
+ // via witness intro.
+ Node teq = tpurified.eqNode(tpurified);
+ d_pskPf.addStep(teq, PfRule::REFL, {}, {tpurified});
+ d_pskPf.addStep(exists, PfRule::EXISTS_INTRO, {teq}, {exists});
+ return &d_pskPf;
+ }
+ return nullptr;
+}
+
+} // namespace smt
+} // namespace CVC4
diff --git a/src/smt/witness_form.h b/src/smt/witness_form.h
new file mode 100644
index 000000000..eb0cf3005
--- /dev/null
+++ b/src/smt/witness_form.h
@@ -0,0 +1,103 @@
+/********************* */
+/*! \file witness_form.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The module for managing witness form conversion in proofs
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__SMT__WITNESS_FORM_H
+#define CVC4__SMT__WITNESS_FORM_H
+
+#include <unordered_set>
+
+#include "expr/node_manager.h"
+#include "expr/proof.h"
+#include "expr/proof_generator.h"
+#include "expr/term_conversion_proof_generator.h"
+
+namespace CVC4 {
+namespace smt {
+
+/**
+ * The witness form proof generator, which acts as a wrapper around a
+ * TConvProofGenerator for adding rewrite steps for witness introduction.
+ *
+ * The proof steps managed by this class are stored in a context-independent
+ * manager, which matches how witness forms are managed in SkolemManager.
+ */
+class WitnessFormGenerator : public ProofGenerator
+{
+ public:
+ WitnessFormGenerator(ProofNodeManager* pnm);
+ ~WitnessFormGenerator() {}
+ /**
+ * Get proof for, which expects an equality of the form t = toWitness(t).
+ * This returns a proof based on the term conversion proof generator utility.
+ * This proof may contain open assumptions of the form:
+ * k = toWitness(k)
+ * Each of these assumptions are included in the set getWitnessFormEqs()
+ * below after returning this call.
+ */
+ std::shared_ptr<ProofNode> getProofFor(Node eq) override;
+ /** Identify */
+ std::string identify() const override;
+ /**
+ * Does the rewrite require witness form conversion?
+ * When calling this method, it should be the case that:
+ * Rewriter::rewrite(toWitness(t)) == Rewriter::rewrite(toWitness(s))
+ * The rule MACRO_SR_PRED_TRANSFORM concludes t == s if the above holds.
+ * This method returns false if:
+ * Rewriter::rewrite(t) == Rewriter::rewrite(s)
+ * which means that the proof of the above fact does not need to do
+ * witness form conversion to prove conclusions of MACRO_SR_PRED_TRANSFORM.
+ */
+ bool requiresWitnessFormTransform(Node t, Node s) const;
+ /**
+ * Same as above, with s = true. This is intended for use with
+ * MACRO_SR_PRED_INTRO.
+ */
+ bool requiresWitnessFormIntro(Node t) const;
+ /**
+ * Get witness form equalities. This returns a set of equalities of the form:
+ * k = toWitness(k)
+ * where k is a skolem, containing all rewrite steps used in calls to
+ * getProofFor during the entire lifetime of this generator.
+ */
+ const std::unordered_set<Node, NodeHashFunction>& getWitnessFormEqs() const;
+
+ private:
+ /**
+ * Convert to witness form. This internally constructs rewrite steps that
+ * suffice to show t = toWitness(t) using the term conversion proof generator
+ * of this class (d_tcpg).
+ */
+ Node convertToWitnessForm(Node t);
+ /**
+ * Return a proof generator that can prove the given axiom exists.
+ */
+ ProofGenerator* convertExistsInternal(Node exists);
+ /** The term conversion proof generator */
+ TConvProofGenerator d_tcpg;
+ /** The nodes we have already added rewrite steps for in d_tcpg */
+ std::unordered_set<TNode, TNodeHashFunction> d_visited;
+ /** The set of equalities added as proof steps */
+ std::unordered_set<Node, NodeHashFunction> d_eqs;
+ /** Lazy proof storing witness intro steps */
+ LazyCDProof d_wintroPf;
+ /** CDProof for justifying purification existentials */
+ CDProof d_pskPf;
+};
+
+} // namespace smt
+} // namespace CVC4
+
+#endif
diff --git a/src/smt_util/boolean_simplification.cpp b/src/smt_util/boolean_simplification.cpp
index 657ed1f51..cc2ca48b9 100644
--- a/src/smt_util/boolean_simplification.cpp
+++ b/src/smt_util/boolean_simplification.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/smt_util/boolean_simplification.h b/src/smt_util/boolean_simplification.h
index 57857baaa..78d7f8c38 100644
--- a/src/smt_util/boolean_simplification.h
+++ b/src/smt_util/boolean_simplification.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -202,18 +202,6 @@ class BooleanSimplification {
}
/**
- * Negates an Expr, doing all the double-negation elimination that's
- * possible.
- *
- * @param e the Expr to negate (cannot be the null Expr)
- */
- static Expr negate(Expr e)
- {
- ExprManagerScope ems(e);
- return negate(Node::fromExpr(e)).toExpr();
- }
-
- /**
* Simplify an OR, AND, or IMPLIES. This function is the identity
* for all other kinds.
*/
diff --git a/src/smt_util/nary_builder.cpp b/src/smt_util/nary_builder.cpp
index 612937b43..60a7daf8f 100644
--- a/src/smt_util/nary_builder.cpp
+++ b/src/smt_util/nary_builder.cpp
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/smt_util/nary_builder.h b/src/smt_util/nary_builder.h
index 0573b0712..b0ccafdef 100644
--- a/src/smt_util/nary_builder.h
+++ b/src/smt_util/nary_builder.h
@@ -5,7 +5,7 @@
** Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/CMakeLists.txt b/src/theory/CMakeLists.txt
index 4c2f66a0e..d63e297a1 100644
--- a/src/theory/CMakeLists.txt
+++ b/src/theory/CMakeLists.txt
@@ -1,3 +1,13 @@
+#####################
+## CMakeLists.txt
+## Top contributors (to current version):
+## Aina Niemetz, Mathias Preiner
+## This file is part of the CVC4 project.
+## Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+## in the top-level source directory and their institutional affiliations.
+## All rights reserved. See the file COPYING in the top-level source
+## directory for licensing information.
+##
libcvc4_add_sources(GENERATED
rewriter_tables.h
theory_traits.h
diff --git a/src/theory/arith/approx_simplex.cpp b/src/theory/arith/approx_simplex.cpp
index a006d43b3..7c89a9e39 100644
--- a/src/theory/arith/approx_simplex.cpp
+++ b/src/theory/arith/approx_simplex.cpp
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/approx_simplex.h b/src/theory/arith/approx_simplex.h
index e72b25274..2c7400a35 100644
--- a/src/theory/arith/approx_simplex.h
+++ b/src/theory/arith/approx_simplex.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/arith_ite_utils.cpp b/src/theory/arith/arith_ite_utils.cpp
index 4892389f2..5fb11d77f 100644
--- a/src/theory/arith/arith_ite_utils.cpp
+++ b/src/theory/arith/arith_ite_utils.cpp
@@ -5,7 +5,7 @@
** Tim King, Aina Niemetz, Piotr Trojanek
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -151,7 +151,6 @@ ArithIteUtils::ArithIteUtils(
d_subcount(uc, 0),
d_skolems(uc),
d_implies(),
- d_skolemsAdded(),
d_orBinEqs()
{
d_subs = new SubstitutionMap(uc);
@@ -313,16 +312,7 @@ void ArithIteUtils::learnSubstitutions(const std::vector<Node>& assertions){
d_orBinEqs.resize(writePos);
}while(solvedSomething);
- for(size_t i = 0, N=d_skolemsAdded.size(); i<N; ++i){
- Node sk = d_skolemsAdded[i];
- Node to = d_skolems[sk];
- if(!to.isNull()){
- Node fp = applySubstitutions(to);
- addSubstitution(sk, fp);
- }
- }
d_implies.clear();
- d_skolemsAdded.clear();
d_orBinEqs.clear();
}
@@ -457,7 +447,6 @@ bool ArithIteUtils::solveBinOr(TNode binor){
Node sk = nm->mkSkolem("deor", nm->booleanType());
Node ite = sk.iteNode(otherL, otherR);
d_skolems.insert(sk, cnd);
- d_skolemsAdded.push_back(sk);
addSubstitution(sel, ite);
return true;
}
diff --git a/src/theory/arith/arith_ite_utils.h b/src/theory/arith/arith_ite_utils.h
index f86328d5d..5aa22d8e5 100644
--- a/src/theory/arith/arith_ite_utils.h
+++ b/src/theory/arith/arith_ite_utils.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -69,8 +69,6 @@ class ArithIteUtils {
typedef std::map<Node, std::set<Node> > ImpMap;
ImpMap d_implies;
- std::vector<Node> d_skolemsAdded;
-
std::vector<Node> d_orBinEqs;
public:
diff --git a/src/theory/arith/theory_arith_private_forward.h b/src/theory/arith/arith_lemma.cpp
index 363debf30..9b8222586 100644
--- a/src/theory/arith/theory_arith_private_forward.h
+++ b/src/theory/arith/arith_lemma.cpp
@@ -1,31 +1,28 @@
/********************* */
-/*! \file theory_arith_private_forward.h
+/*! \file arith_lemma.cpp
** \verbatim
** Top contributors (to current version):
- ** Tim King
+ ** Gereon Kremer
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
+ ** \brief ArithLemma class, derived from Lemma.
**/
-
-#include "cvc4_private.h"
-
-#pragma once
+#include "theory/arith/arith_lemma.h"
namespace CVC4 {
namespace theory {
namespace arith {
-class TheoryArithPrivate;
+std::ostream& operator<<(std::ostream& out, const ArithLemma& al)
+{
+ return out << al.d_node;
+}
-}/* CVC4::theory::arith namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/arith_lemma.h b/src/theory/arith/arith_lemma.h
new file mode 100644
index 000000000..1c90066fb
--- /dev/null
+++ b/src/theory/arith/arith_lemma.h
@@ -0,0 +1,61 @@
+/********************* */
+/*! \file arith_lemma.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief ArithLemma class, derived from Lemma.
+ **/
+
+#ifndef CVC4__THEORY__ARITH__ARITH_LEMMA_H
+#define CVC4__THEORY__ARITH__ARITH_LEMMA_H
+
+#include <tuple>
+#include <vector>
+
+#include "expr/node.h"
+#include "theory/arith/inference_id.h"
+#include "theory/inference_manager_buffered.h"
+#include "theory/output_channel.h"
+#include "theory/theory_inference.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+/**
+ * The data structure for a single lemma to process by the arithmetic theory,
+ * derived from theory::SimpleTheoryLemma.
+ *
+ * This also includes the inference type that produced this lemma.
+ */
+class ArithLemma : public SimpleTheoryLemma
+{
+ public:
+ ArithLemma(Node n,
+ LemmaProperty p,
+ ProofGenerator* pg,
+ InferenceId inf = InferenceId::UNKNOWN)
+ : SimpleTheoryLemma(n, p, pg), d_inference(inf)
+ {
+ }
+ virtual ~ArithLemma() {}
+
+ /** The inference id for the lemma */
+ InferenceId d_inference;
+};
+/**
+ * Writes an arithmetic lemma to a stream.
+ */
+std::ostream& operator<<(std::ostream& out, const ArithLemma& al);
+
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__ARITH__ARITH_LEMMA_H */
diff --git a/src/theory/arith/arith_msum.cpp b/src/theory/arith/arith_msum.cpp
index 5c654a90b..a2b3d41d5 100644
--- a/src/theory/arith/arith_msum.cpp
+++ b/src/theory/arith/arith_msum.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/arith_msum.h b/src/theory/arith/arith_msum.h
index 4458bdecd..bdc0d85de 100644
--- a/src/theory/arith/arith_msum.h
+++ b/src/theory/arith/arith_msum.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/arith_preprocess.cpp b/src/theory/arith/arith_preprocess.cpp
new file mode 100644
index 000000000..577407c07
--- /dev/null
+++ b/src/theory/arith/arith_preprocess.cpp
@@ -0,0 +1,68 @@
+/********************* */
+/*! \file arith_preprocess.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Arithmetic preprocess
+ **/
+
+#include "theory/arith/arith_preprocess.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+ArithPreprocess::ArithPreprocess(ArithState& state,
+ InferenceManager& im,
+ ProofNodeManager* pnm,
+ const LogicInfo& info)
+ : d_im(im), d_opElim(pnm, info), d_reduced(state.getUserContext())
+{
+}
+TrustNode ArithPreprocess::eliminate(TNode n) { return d_opElim.eliminate(n); }
+bool ArithPreprocess::reduceAssertion(TNode atom)
+{
+ context::CDHashMap<Node, bool, NodeHashFunction>::const_iterator it =
+ d_reduced.find(atom);
+ if (it != d_reduced.end())
+ {
+ // already computed
+ return (*it).second;
+ }
+ TrustNode tn = eliminate(atom);
+ if (tn.isNull())
+ {
+ // did not reduce
+ d_reduced[atom] = false;
+ return false;
+ }
+ Assert(tn.getKind() == TrustNodeKind::REWRITE);
+ // tn is of kind REWRITE, turn this into a LEMMA here
+ TrustNode tlem = TrustNode::mkTrustLemma(tn.getProven(), tn.getGenerator());
+ // must preprocess
+ d_im.trustedLemma(tlem, LemmaProperty::PREPROCESS);
+ // mark the atom as reduced
+ d_reduced[atom] = true;
+ return true;
+}
+
+bool ArithPreprocess::isReduced(TNode atom) const
+{
+ context::CDHashMap<Node, bool, NodeHashFunction>::const_iterator it =
+ d_reduced.find(atom);
+ if (it == d_reduced.end())
+ {
+ return false;
+ }
+ return (*it).second;
+}
+
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/arith_preprocess.h b/src/theory/arith/arith_preprocess.h
new file mode 100644
index 000000000..165209bd9
--- /dev/null
+++ b/src/theory/arith/arith_preprocess.h
@@ -0,0 +1,80 @@
+/********************* */
+/*! \file arith_preprocess.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Arithmetic preprocess
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__ARITH__ARITH_PREPROCESS_H
+#define CVC4__THEORY__ARITH__ARITH_PREPROCESS_H
+
+#include "context/cdhashmap.h"
+#include "theory/arith/arith_state.h"
+#include "theory/arith/inference_manager.h"
+#include "theory/arith/operator_elim.h"
+#include "theory/logic_info.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+/**
+ * This module can be used for (on demand) elimination of extended arithmetic
+ * operators like div, mod, to_int, is_int, sqrt, and so on. It uses the
+ * operator elimination utility for determining how to reduce formulas. It
+ * extends that utility with the ability to generate lemmas on demand via
+ * the provided inference manager.
+ */
+class ArithPreprocess
+{
+ public:
+ ArithPreprocess(ArithState& state,
+ InferenceManager& im,
+ ProofNodeManager* pnm,
+ const LogicInfo& info);
+ ~ArithPreprocess() {}
+ /**
+ * Call eliminate operators on formula n, return the resulting trust node,
+ * which is of TrustNodeKind REWRITE and whose node is the result of
+ * eliminating extended operators from n.
+ */
+ TrustNode eliminate(TNode n);
+ /**
+ * Reduce assertion. This sends a lemma via the inference manager if atom
+ * contains any extended operators. When applicable, the lemma is of the form:
+ * atom == d_opElim.eliminate(atom)
+ * This method returns true if a lemma of the above form was added to
+ * the inference manager. Note this returns true even if this lemma was added
+ * on a previous call.
+ */
+ bool reduceAssertion(TNode atom);
+ /**
+ * Is the atom reduced? Returns true if a call to method reduceAssertion was
+ * made for the given atom and returned a lemma. In this case, the atom
+ * can be ignored.
+ */
+ bool isReduced(TNode atom) const;
+
+ private:
+ /** Reference to the inference manager */
+ InferenceManager& d_im;
+ /** The operator elimination utility */
+ OperatorElim d_opElim;
+ /** The set of assertions that were reduced */
+ context::CDHashMap<Node, bool, NodeHashFunction> d_reduced;
+};
+
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/arith_rewriter.cpp b/src/theory/arith/arith_rewriter.cpp
index 188ef47e6..a65fbd961 100644
--- a/src/theory/arith/arith_rewriter.cpp
+++ b/src/theory/arith/arith_rewriter.cpp
@@ -5,7 +5,7 @@
** Tim King, Andrew Reynolds, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -119,8 +119,7 @@ RewriteResponse ArithRewriter::preRewriteTerm(TNode t){
case kind::ARCCOTANGENT:
case kind::SQRT: return preRewriteTranscendental(t);
case kind::INTS_DIVISION:
- case kind::INTS_MODULUS:
- return RewriteResponse(REWRITE_DONE, t);
+ case kind::INTS_MODULUS: return rewriteIntsDivMod(t, true);
case kind::INTS_DIVISION_TOTAL:
case kind::INTS_MODULUS_TOTAL:
return rewriteIntsDivModTotal(t,true);
@@ -139,7 +138,7 @@ RewriteResponse ArithRewriter::preRewriteTerm(TNode t){
case kind::TO_INTEGER:
return RewriteResponse(REWRITE_DONE, t);
case kind::TO_REAL:
- return RewriteResponse(REWRITE_DONE, t[0]);
+ case kind::CAST_TO_REAL: return RewriteResponse(REWRITE_DONE, t[0]);
case kind::POW:
return RewriteResponse(REWRITE_DONE, t);
case kind::PI:
@@ -183,8 +182,7 @@ RewriteResponse ArithRewriter::postRewriteTerm(TNode t){
case kind::ARCCOTANGENT:
case kind::SQRT: return postRewriteTranscendental(t);
case kind::INTS_DIVISION:
- case kind::INTS_MODULUS:
- return RewriteResponse(REWRITE_DONE, t);
+ case kind::INTS_MODULUS: return rewriteIntsDivMod(t, false);
case kind::INTS_DIVISION_TOTAL:
case kind::INTS_MODULUS_TOTAL:
return rewriteIntsDivModTotal(t, false);
@@ -200,7 +198,7 @@ RewriteResponse ArithRewriter::postRewriteTerm(TNode t){
}
return RewriteResponse(REWRITE_DONE, t);
case kind::TO_REAL:
- return RewriteResponse(REWRITE_DONE, t[0]);
+ case kind::CAST_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())));
@@ -229,8 +227,9 @@ RewriteResponse ArithRewriter::postRewriteTerm(TNode t){
if(exp.sgn() == 0){
return RewriteResponse(REWRITE_DONE, mkRationalNode(Rational(1)));
}else if(exp.sgn() > 0 && exp.isIntegral()){
- CVC4::Rational r(INT_MAX);
- if( exp<r ){
+ CVC4::Rational r(expr::NodeValue::MAX_CHILDREN);
+ if (exp <= r)
+ {
unsigned num = exp.getNumerator().toUnsignedInt();
if( num==1 ){
return RewriteResponse(REWRITE_AGAIN, base);
@@ -249,8 +248,10 @@ RewriteResponse ArithRewriter::postRewriteTerm(TNode t){
// Todo improve the exception thrown
std::stringstream ss;
- ss << "The POW(^) operator can only be used with a natural number ";
- ss << "in the exponent. Exception occurred in:" << std::endl;
+ ss << "The exponent of the POW(^) operator can only be a positive "
+ "integral constant below "
+ << (expr::NodeValue::MAX_CHILDREN + 1) << ". ";
+ ss << "Exception occurred in:" << std::endl;
ss << " " << t;
throw LogicException(ss.str());
}
@@ -760,42 +761,68 @@ RewriteResponse ArithRewriter::rewriteDiv(TNode t, bool pre){
}
}
-RewriteResponse ArithRewriter::rewriteIntsDivModTotal(TNode t, bool pre){
+RewriteResponse ArithRewriter::rewriteIntsDivMod(TNode t, bool pre)
+{
+ NodeManager* nm = NodeManager::currentNM();
Kind k = t.getKind();
- // Assert(k == kind::INTS_MODULUS || k == kind::INTS_MODULUS_TOTAL ||
- // k == kind::INTS_DIVISION || k == kind::INTS_DIVISION_TOTAL);
+ Node zero = nm->mkConst(Rational(0));
+ if (k == kind::INTS_MODULUS)
+ {
+ if (t[1].isConst() && !t[1].getConst<Rational>().isZero())
+ {
+ // can immediately replace by INTS_MODULUS_TOTAL
+ Node ret = nm->mkNode(kind::INTS_MODULUS_TOTAL, t[0], t[1]);
+ return returnRewrite(t, ret, Rewrite::MOD_TOTAL_BY_CONST);
+ }
+ }
+ if (k == kind::INTS_DIVISION)
+ {
+ if (t[1].isConst() && !t[1].getConst<Rational>().isZero())
+ {
+ // can immediately replace by INTS_DIVISION_TOTAL
+ Node ret = nm->mkNode(kind::INTS_DIVISION_TOTAL, t[0], t[1]);
+ return returnRewrite(t, ret, Rewrite::DIV_TOTAL_BY_CONST);
+ }
+ }
+ return RewriteResponse(REWRITE_DONE, t);
+}
- //Leaving the function as before (INTS_MODULUS can be handled),
- // but restricting its use here
+RewriteResponse ArithRewriter::rewriteIntsDivModTotal(TNode t, bool pre)
+{
+ if (pre)
+ {
+ // do not rewrite at prewrite.
+ return RewriteResponse(REWRITE_DONE, t);
+ }
+ NodeManager* nm = NodeManager::currentNM();
+ Kind k = t.getKind();
Assert(k == kind::INTS_MODULUS_TOTAL || k == kind::INTS_DIVISION_TOTAL);
- TNode n = t[0], d = t[1];
+ TNode n = t[0];
+ TNode d = t[1];
bool dIsConstant = d.getKind() == kind::CONST_RATIONAL;
if(dIsConstant && d.getConst<Rational>().isZero()){
- if(k == kind::INTS_MODULUS_TOTAL || k == kind::INTS_DIVISION_TOTAL){
- return RewriteResponse(REWRITE_DONE, mkRationalNode(0));
- }else{
- // Do nothing for k == INTS_MODULUS
- return RewriteResponse(REWRITE_DONE, t);
- }
+ // (div x 0) ---> 0 or (mod x 0) ---> 0
+ return returnRewrite(t, mkRationalNode(0), Rewrite::DIV_MOD_BY_ZERO);
}else if(dIsConstant && d.getConst<Rational>().isOne()){
- 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, n);
+ if (k == kind::INTS_MODULUS_TOTAL)
+ {
+ // (mod x 1) --> 0
+ return returnRewrite(t, mkRationalNode(0), Rewrite::MOD_BY_ONE);
}
+ Assert(k == kind::INTS_DIVISION_TOTAL);
+ // (div x 1) --> x
+ return returnRewrite(t, n, Rewrite::DIV_BY_ONE);
}
else if (dIsConstant && d.getConst<Rational>().sgn() < 0)
{
// pull negation
- // (div x (- c)) ---> (- (div x c))
- // (mod x (- c)) ---> (mod x c)
- NodeManager* nm = NodeManager::currentNM();
+ // (div x (- c)) ---> (- (div x c))
+ // (mod x (- c)) ---> (mod x c)
Node nn = nm->mkNode(k, t[0], nm->mkConst(-t[1].getConst<Rational>()));
Node ret = (k == kind::INTS_DIVISION || k == kind::INTS_DIVISION_TOTAL)
? nm->mkNode(kind::UMINUS, nn)
: nn;
- return RewriteResponse(REWRITE_AGAIN_FULL, ret);
+ return returnRewrite(t, ret, Rewrite::DIV_MOD_PULL_NEG_DEN);
}
else if (dIsConstant && n.getKind() == kind::CONST_RATIONAL)
{
@@ -809,13 +836,66 @@ RewriteResponse ArithRewriter::rewriteIntsDivModTotal(TNode t, bool pre){
Integer result = isDiv ? ni.euclidianDivideQuotient(di) : ni.euclidianDivideRemainder(di);
+ // constant evaluation
+ // (mod c1 c2) ---> c3 or (div c1 c2) ---> c3
Node resultNode = mkRationalNode(Rational(result));
- return RewriteResponse(REWRITE_DONE, resultNode);
+ return returnRewrite(t, resultNode, Rewrite::CONST_EVAL);
+ }
+ if (k == kind::INTS_MODULUS_TOTAL)
+ {
+ // Note these rewrites do not need to account for modulus by zero as being
+ // a UF, which is handled by the reduction of INTS_MODULUS.
+ Kind k0 = t[0].getKind();
+ if (k0 == kind::INTS_MODULUS_TOTAL && t[0][1] == t[1])
+ {
+ // (mod (mod x c) c) --> (mod x c)
+ return returnRewrite(t, t[0], Rewrite::MOD_OVER_MOD);
+ }
+ else if (k0 == kind::NONLINEAR_MULT || k0 == kind::MULT || k0 == kind::PLUS)
+ {
+ // can drop all
+ std::vector<Node> newChildren;
+ bool childChanged = false;
+ for (const Node& tc : t[0])
+ {
+ if (tc.getKind() == kind::INTS_MODULUS_TOTAL && tc[1] == t[1])
+ {
+ newChildren.push_back(tc[0]);
+ childChanged = true;
+ continue;
+ }
+ newChildren.push_back(tc);
+ }
+ if (childChanged)
+ {
+ // (mod (op ... (mod x c) ...) c) ---> (mod (op ... x ...) c) where
+ // op is one of { NONLINEAR_MULT, MULT, PLUS }.
+ Node ret = nm->mkNode(k0, newChildren);
+ ret = nm->mkNode(kind::INTS_MODULUS_TOTAL, ret, t[1]);
+ return returnRewrite(t, ret, Rewrite::MOD_CHILD_MOD);
+ }
+ }
}
else
{
- return RewriteResponse(REWRITE_DONE, t);
+ Assert(k == kind::INTS_DIVISION_TOTAL);
+ // Note these rewrites do not need to account for division by zero as being
+ // a UF, which is handled by the reduction of INTS_DIVISION.
+ if (t[0].getKind() == kind::INTS_MODULUS_TOTAL && t[0][1] == t[1])
+ {
+ // (div (mod x c) c) --> 0
+ Node ret = mkRationalNode(0);
+ return returnRewrite(t, ret, Rewrite::DIV_OVER_MOD);
+ }
}
+ return RewriteResponse(REWRITE_DONE, t);
+}
+
+RewriteResponse ArithRewriter::returnRewrite(TNode t, Node ret, Rewrite r)
+{
+ Trace("arith-rewrite") << "ArithRewriter : " << t << " == " << ret << " by "
+ << r << std::endl;
+ return RewriteResponse(REWRITE_AGAIN_FULL, ret);
}
}/* CVC4::theory::arith namespace */
diff --git a/src/theory/arith/arith_rewriter.h b/src/theory/arith/arith_rewriter.h
index 1dc756514..8f35acd1c 100644
--- a/src/theory/arith/arith_rewriter.h
+++ b/src/theory/arith/arith_rewriter.h
@@ -5,7 +5,7 @@
** Dejan Jovanovic, Tim King, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,6 +20,7 @@
#ifndef CVC4__THEORY__ARITH__ARITH_REWRITER_H
#define CVC4__THEORY__ARITH__ARITH_REWRITER_H
+#include "theory/arith/rewrites.h"
#include "theory/theory.h"
#include "theory/theory_rewriter.h"
@@ -45,6 +46,7 @@ class ArithRewriter : public TheoryRewriter
static RewriteResponse rewriteMinus(TNode t, bool pre);
static RewriteResponse rewriteUMinus(TNode t, bool pre);
static RewriteResponse rewriteDiv(TNode t, bool pre);
+ static RewriteResponse rewriteIntsDivMod(TNode t, bool pre);
static RewriteResponse rewriteIntsDivModTotal(TNode t, bool pre);
static RewriteResponse preRewritePlus(TNode t);
@@ -66,7 +68,8 @@ class ArithRewriter : public TheoryRewriter
static inline bool isTerm(TNode n) {
return !isAtom(n);
}
-
+ /** return rewrite */
+ static RewriteResponse returnRewrite(TNode t, Node ret, Rewrite r);
}; /* class ArithRewriter */
}/* CVC4::theory::arith namespace */
diff --git a/src/theory/arith/arith_state.cpp b/src/theory/arith/arith_state.cpp
new file mode 100644
index 000000000..c2533723a
--- /dev/null
+++ b/src/theory/arith/arith_state.cpp
@@ -0,0 +1,38 @@
+/********************* */
+/*! \file arith_state.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Arithmetic theory state.
+ **/
+
+#include "theory/arith/arith_state.h"
+
+#include "theory/arith/theory_arith_private.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+ArithState::ArithState(TheoryArithPrivate& parent,
+ context::Context* c,
+ context::UserContext* u,
+ Valuation val)
+ : TheoryState(c, u, val), d_parent(parent)
+{
+}
+
+bool ArithState::isInConflict() const
+{
+ return d_parent.anyConflict() || d_conflict;
+}
+
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/arith_state.h b/src/theory/arith/arith_state.h
new file mode 100644
index 000000000..b3c299433
--- /dev/null
+++ b/src/theory/arith/arith_state.h
@@ -0,0 +1,57 @@
+/********************* */
+/*! \file arith_state.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Arithmetic theory state.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__ARITH__ARITH_STATE_H
+#define CVC4__THEORY__ARITH__ARITH_STATE_H
+
+#include "theory/theory_state.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+class TheoryArithPrivate;
+
+/**
+ * The arithmetic state.
+ *
+ * Note this object is intended to use TheoryArithPrivate
+ * as a black box, and moreover the internals of TheoryArithPrivate will not
+ * be refactored to use this state. Instead, the main theory solver TheoryArith
+ * will be refactored to be a standard layer on top of TheoryArithPrivate,
+ * which will include using this state in the standard way.
+ */
+class ArithState : public TheoryState
+{
+ public:
+ ArithState(TheoryArithPrivate& parent,
+ context::Context* c,
+ context::UserContext* u,
+ Valuation val);
+ ~ArithState() {}
+ /** Are we currently in conflict? */
+ bool isInConflict() const override;
+
+ private:
+ /** reference to parent */
+ TheoryArithPrivate& d_parent;
+};
+
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/arith_static_learner.cpp b/src/theory/arith/arith_static_learner.cpp
index 9bd5ad774..1e031c322 100644
--- a/src/theory/arith/arith_static_learner.cpp
+++ b/src/theory/arith/arith_static_learner.cpp
@@ -5,7 +5,7 @@
** Tim King, Dejan Jovanovic, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/arith_static_learner.h b/src/theory/arith/arith_static_learner.h
index 5abada539..9c78942b1 100644
--- a/src/theory/arith/arith_static_learner.h
+++ b/src/theory/arith/arith_static_learner.h
@@ -5,7 +5,7 @@
** Tim King, Dejan Jovanovic, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/arith_utilities.cpp b/src/theory/arith/arith_utilities.cpp
index 3d708c94e..1a5bc356f 100644
--- a/src/theory/arith/arith_utilities.cpp
+++ b/src/theory/arith/arith_utilities.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -106,7 +106,11 @@ bool isTranscendentalKind(Kind k)
Node getApproximateConstant(Node c, bool isLower, unsigned prec)
{
- Assert(c.isConst());
+ if (!c.isConst())
+ {
+ Assert(false) << "getApproximateConstant: non-constant input " << c;
+ return Node::null();
+ }
Rational cr = c.getConst<Rational>();
unsigned lower = 0;
@@ -178,7 +182,12 @@ Node getApproximateConstant(Node c, bool isLower, unsigned prec)
void printRationalApprox(const char* c, Node cr, unsigned prec)
{
- Assert(cr.isConst());
+ if (!cr.isConst())
+ {
+ Assert(false) << "printRationalApprox: non-constant input " << cr;
+ Trace(c) << cr;
+ return;
+ }
Node ca = getApproximateConstant(cr, true, prec);
if (ca != cr)
{
@@ -278,6 +287,40 @@ Node mkBounded(Node l, Node a, Node u)
return nm->mkNode(AND, nm->mkNode(GEQ, a, l), nm->mkNode(LEQ, a, u));
}
+Rational leastIntGreaterThan(const Rational& q) { return q.floor() + 1; }
+
+Rational greatestIntLessThan(const Rational& q) { return q.ceiling() - 1; }
+
+Node negateProofLiteral(TNode n)
+{
+ auto nm = NodeManager::currentNM();
+ switch (n.getKind())
+ {
+ case Kind::GT:
+ {
+ return nm->mkNode(Kind::LEQ, n[0], n[1]);
+ }
+ case Kind::LT:
+ {
+ return nm->mkNode(Kind::GEQ, n[0], n[1]);
+ }
+ case Kind::LEQ:
+ {
+ return nm->mkNode(Kind::GT, n[0], n[1]);
+ }
+ case Kind::GEQ:
+ {
+ return nm->mkNode(Kind::LT, n[0], n[1]);
+ }
+ case Kind::EQUAL:
+ case Kind::NOT:
+ {
+ return n.negate();
+ }
+ default: Unhandled() << n;
+ }
+}
+
} // namespace arith
} // namespace theory
} // namespace CVC4
diff --git a/src/theory/arith/arith_utilities.h b/src/theory/arith/arith_utilities.h
index bfc1fbf88..55bbe67cc 100644
--- a/src/theory/arith/arith_utilities.h
+++ b/src/theory/arith/arith_utilities.h
@@ -5,7 +5,7 @@
** Tim King, Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -245,8 +245,7 @@ inline Node getIdentity(Kind k){
case kind::MULT:
case kind::NONLINEAR_MULT:
return mkRationalNode(1);
- default:
- Unreachable();
+ default: Unreachable(); return {}; // silence warning
}
}
@@ -338,6 +337,13 @@ Node arithSubstitute(Node n, std::vector<Node>& vars, std::vector<Node>& subs);
/** Make the node u >= a ^ a >= l */
Node mkBounded(Node l, Node a, Node u);
+Rational leastIntGreaterThan(const Rational&);
+
+Rational greatestIntLessThan(const Rational&);
+
+/** Negates a node in arithmetic proof normal form. */
+Node negateProofLiteral(TNode n);
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/arith/arithvar.cpp b/src/theory/arith/arithvar.cpp
index 7f2535004..7dab58531 100644
--- a/src/theory/arith/arithvar.cpp
+++ b/src/theory/arith/arithvar.cpp
@@ -5,7 +5,7 @@
** Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/arithvar.h b/src/theory/arith/arithvar.h
index 7e0894afa..815b70d6d 100644
--- a/src/theory/arith/arithvar.h
+++ b/src/theory/arith/arithvar.h
@@ -5,7 +5,7 @@
** Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/arithvar_node_map.h b/src/theory/arith/arithvar_node_map.h
index a6569bded..a73146042 100644
--- a/src/theory/arith/arithvar_node_map.h
+++ b/src/theory/arith/arithvar_node_map.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/attempt_solution_simplex.cpp b/src/theory/arith/attempt_solution_simplex.cpp
index 91e922fa1..b8e08add8 100644
--- a/src/theory/arith/attempt_solution_simplex.cpp
+++ b/src/theory/arith/attempt_solution_simplex.cpp
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/attempt_solution_simplex.h b/src/theory/arith/attempt_solution_simplex.h
index 4c05372ad..b41b634c3 100644
--- a/src/theory/arith/attempt_solution_simplex.h
+++ b/src/theory/arith/attempt_solution_simplex.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/bound_counts.h b/src/theory/arith/bound_counts.h
index a9466ef45..d1044f36b 100644
--- a/src/theory/arith/bound_counts.h
+++ b/src/theory/arith/bound_counts.h
@@ -5,7 +5,7 @@
** Tim King, Clark Barrett
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,8 +18,6 @@
#include "cvc4_private.h"
#pragma once
-#include <stdint.h>
-
#include "base/check.h"
#include "theory/arith/arithvar.h"
#include "util/dense_map.h"
diff --git a/src/theory/arith/bound_inference.cpp b/src/theory/arith/bound_inference.cpp
new file mode 100644
index 000000000..c8a9527c7
--- /dev/null
+++ b/src/theory/arith/bound_inference.cpp
@@ -0,0 +1,250 @@
+/********************* */
+/*! \file bound_inference.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief
+ **/
+
+#include "theory/arith/bound_inference.h"
+
+#include "theory/arith/normal_form.h"
+#include "theory/rewriter.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+std::ostream& operator<<(std::ostream& os, const Bounds& b) {
+ return os << (b.lower_strict ? '(' : '[') << b.lower_value << " .. "
+ << b.upper_value << (b.upper_strict ? ')' : ']');
+}
+
+void BoundInference::reset() { d_bounds.clear(); }
+
+Bounds& BoundInference::get_or_add(const Node& lhs)
+{
+ auto it = d_bounds.find(lhs);
+ if (it == d_bounds.end())
+ {
+ it = d_bounds.emplace(lhs, Bounds()).first;
+ }
+ return it->second;
+}
+Bounds BoundInference::get(const Node& lhs) const
+{
+ auto it = d_bounds.find(lhs);
+ if (it == d_bounds.end())
+ {
+ return Bounds{};
+ }
+ return it->second;
+}
+
+const std::map<Node, Bounds>& BoundInference::get() const { return d_bounds; }
+bool BoundInference::add(const Node& n, bool onlyVariables)
+{
+ Node tmp = Rewriter::rewrite(n);
+ if (tmp.getKind() == Kind::CONST_BOOLEAN)
+ {
+ return false;
+ }
+ // Parse the node as a comparison
+ auto comp = Comparison::parseNormalForm(tmp);
+ auto dec = comp.decompose(true);
+ if (onlyVariables && !std::get<0>(dec).isVariable())
+ {
+ return false;
+ }
+
+ Node lhs = std::get<0>(dec).getNode();
+ Kind relation = std::get<1>(dec);
+ if (relation == Kind::DISTINCT) return false;
+ Node bound = std::get<2>(dec).getNode();
+ // has the form lhs ~relation~ bound
+
+ if (lhs.getType().isInteger())
+ {
+ Rational br = bound.getConst<Rational>();
+ auto* nm = NodeManager::currentNM();
+ switch (relation)
+ {
+ case Kind::LEQ: bound = nm->mkConst<Rational>(br.floor()); break;
+ case Kind::LT:
+ bound = nm->mkConst<Rational>((br - 1).ceiling());
+ relation = Kind::LEQ;
+ break;
+ case Kind::GT:
+ bound = nm->mkConst<Rational>((br + 1).floor());
+ relation = Kind::GEQ;
+ break;
+ case Kind::GEQ: bound = nm->mkConst<Rational>(br.ceiling()); break;
+ default:;
+ }
+ Trace("bound-inf") << "Strengthened " << n << " to " << lhs << " "
+ << relation << " " << bound << std::endl;
+ }
+
+ switch (relation)
+ {
+ case Kind::LEQ: update_upper_bound(n, lhs, bound, false); break;
+ case Kind::LT: update_upper_bound(n, lhs, bound, true); break;
+ case Kind::EQUAL:
+ update_lower_bound(n, lhs, bound, false);
+ update_upper_bound(n, lhs, bound, false);
+ break;
+ case Kind::GT: update_lower_bound(n, lhs, bound, true); break;
+ case Kind::GEQ: update_lower_bound(n, lhs, bound, false); break;
+ default: Assert(false);
+ }
+ return true;
+}
+
+void BoundInference::replaceByOrigins(std::vector<Node>& nodes) const
+{
+ std::vector<Node> toAdd;
+ for (auto& n : nodes)
+ {
+ for (const auto& b : d_bounds)
+ {
+ if (n == b.second.lower_bound && n == b.second.upper_bound)
+ {
+ if (n != b.second.lower_origin && n != b.second.upper_origin)
+ {
+ Trace("bound-inf")
+ << "Replace " << n << " by origins " << b.second.lower_origin
+ << " and " << b.second.upper_origin << std::endl;
+ n = b.second.lower_origin;
+ toAdd.emplace_back(b.second.upper_origin);
+ }
+ }
+ else if (n == b.second.lower_bound)
+ {
+ if (n != b.second.lower_origin)
+ {
+ Trace("bound-inf") << "Replace " << n << " by origin "
+ << b.second.lower_origin << std::endl;
+ n = b.second.lower_origin;
+ }
+ }
+ else if (n == b.second.upper_bound)
+ {
+ if (n != b.second.upper_origin)
+ {
+ Trace("bound-inf") << "Replace " << n << " by origin "
+ << b.second.upper_origin << std::endl;
+ n = b.second.upper_origin;
+ }
+ }
+ }
+ }
+ nodes.insert(nodes.end(), toAdd.begin(), toAdd.end());
+}
+
+void BoundInference::update_lower_bound(const Node& origin,
+ const Node& lhs,
+ const Node& value,
+ bool strict)
+{
+ // lhs > or >= value because of origin
+ Trace("bound-inf") << "\tNew bound " << lhs << (strict ? ">" : ">=") << value
+ << " due to " << origin << std::endl;
+ Bounds& b = get_or_add(lhs);
+ if (b.lower_value.isNull()
+ || b.lower_value.getConst<Rational>() < value.getConst<Rational>())
+ {
+ auto* nm = NodeManager::currentNM();
+ b.lower_value = value;
+ b.lower_strict = strict;
+
+ b.lower_origin = origin;
+
+ if (!b.lower_strict && !b.upper_strict && b.lower_value == b.upper_value)
+ {
+ b.lower_bound = b.upper_bound =
+ Rewriter::rewrite(nm->mkNode(Kind::EQUAL, lhs, value));
+ }
+ else
+ {
+ b.lower_bound = Rewriter::rewrite(
+ nm->mkNode(strict ? Kind::GT : Kind::GEQ, lhs, value));
+ }
+ }
+ else if (strict && b.lower_value == value)
+ {
+ auto* nm = NodeManager::currentNM();
+ b.lower_strict = strict;
+ b.lower_bound = Rewriter::rewrite(nm->mkNode(Kind::GT, lhs, value));
+ b.lower_origin = origin;
+ }
+}
+void BoundInference::update_upper_bound(const Node& origin,
+ const Node& lhs,
+ const Node& value,
+ bool strict)
+{
+ // lhs < or <= value because of origin
+ Trace("bound-inf") << "\tNew bound " << lhs << (strict ? "<" : "<=") << value
+ << " due to " << origin << std::endl;
+ Bounds& b = get_or_add(lhs);
+ if (b.upper_value.isNull()
+ || b.upper_value.getConst<Rational>() > value.getConst<Rational>())
+ {
+ auto* nm = NodeManager::currentNM();
+ b.upper_value = value;
+ b.upper_strict = strict;
+ b.upper_origin = origin;
+ if (!b.lower_strict && !b.upper_strict && b.lower_value == b.upper_value)
+ {
+ b.lower_bound = b.upper_bound =
+ Rewriter::rewrite(nm->mkNode(Kind::EQUAL, lhs, value));
+ }
+ else
+ {
+ b.upper_bound = Rewriter::rewrite(
+ nm->mkNode(strict ? Kind::LT : Kind::LEQ, lhs, value));
+ }
+ }
+ else if (strict && b.upper_value == value)
+ {
+ auto* nm = NodeManager::currentNM();
+ b.upper_strict = strict;
+ b.upper_bound = Rewriter::rewrite(nm->mkNode(Kind::LT, lhs, value));
+ b.upper_origin = origin;
+ }
+}
+
+std::ostream& operator<<(std::ostream& os, const BoundInference& bi)
+{
+ os << "Bounds:" << std::endl;
+ for (const auto& b : bi.get())
+ {
+ os << "\t" << b.first << " -> " << b.second.lower_value << ".."
+ << b.second.upper_value << std::endl;
+ }
+ return os;
+}
+
+std::map<Node, std::pair<Node,Node>> getBounds(const std::vector<Node>& assertions) {
+ BoundInference bi;
+ for (const auto& a: assertions) {
+ bi.add(a);
+ }
+ std::map<Node, std::pair<Node,Node>> res;
+ for (const auto& b : bi.get())
+ {
+ res.emplace(b.first,
+ std::make_pair(b.second.lower_value, b.second.upper_value));
+ }
+ return res;
+}
+
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/bound_inference.h b/src/theory/arith/bound_inference.h
new file mode 100644
index 000000000..174ba3a0f
--- /dev/null
+++ b/src/theory/arith/bound_inference.h
@@ -0,0 +1,118 @@
+/********************* */
+/*! \file bound_inference.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Extract bounds on variables from theory atoms.
+ **/
+
+#ifndef CVC4__THEORY__ARITH__BOUND_INFERENCE_H
+#define CVC4__THEORY__ARITH__BOUND_INFERENCE_H
+
+#include <map>
+#include <utility>
+#include <vector>
+
+#include "expr/node.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+ struct Bounds
+ {
+ /** The lower bound value */
+ Node lower_value;
+ /** Whether the lower bound is strict or weak */
+ bool lower_strict = true;
+ /** The lower bound as constraint */
+ Node lower_bound;
+ /** The origin of the lower bound */
+ Node lower_origin;
+ /** The upper bound value */
+ Node upper_value;
+ /** Whether the upper bound is strict or weak */
+ bool upper_strict = true;
+ /** The upper bound as constraint */
+ Node upper_bound;
+ /** The origin of the upper bound */
+ Node upper_origin;
+ };
+
+ /** Print the current bounds. */
+ std::ostream& operator<<(std::ostream& os, const Bounds& b);
+
+ /**
+ * A utility class that extracts direct bounds on arithmetic terms from theory
+ * atoms.
+ */
+ class BoundInference
+ {
+ public:
+ void reset();
+
+ /**
+ * Get the current interval for lhs. Creates a new (full) interval if
+ * necessary.
+ */
+ Bounds& get_or_add(const Node& lhs);
+ /**
+ * Get the current interval for lhs. Returns a full interval if no interval
+ * was derived yet.
+ */
+ Bounds get(const Node& lhs) const;
+
+ /** Return the current term bounds as an interval assignment. */
+ const std::map<Node, Bounds>& get() const;
+
+ /**
+ * Add a new theory atom. Return true if the theory atom induces a new
+ * term bound.
+ * If onlyVariables is true, the left hand side needs to be a single
+ * variable to induce a bound.
+ */
+ bool add(const Node& n, bool onlyVariables = true);
+
+ /**
+ * Post-processes a set of nodes and replaces bounds by their origins.
+ * This utility sometimes creates new bounds, either due to tightening of
+ * integer terms or because an equality was derived from two weak
+ * inequalities. While the origins of these new bounds are recorded in
+ * lower_origin and upper_origin, this method can be used to conveniently
+ * replace these new nodes by their origins.
+ * This can be used, for example, when constructing conflicts.
+ */
+ void replaceByOrigins(std::vector<Node>& nodes) const;
+
+ private:
+ /** The currently strictest bounds for every lhs. */
+ std::map<Node, Bounds> d_bounds;
+
+ /** Updates the lower bound for the given lhs */
+ void update_lower_bound(const Node& origin,
+ const Node& lhs,
+ const Node& value,
+ bool strict);
+ /** Updates the upper bound for the given lhs */
+ void update_upper_bound(const Node& origin,
+ const Node& lhs,
+ const Node& value,
+ bool strict);
+ };
+
+/** Print the current variable bounds. */
+std::ostream& operator<<(std::ostream& os, const BoundInference& bi);
+
+std::map<Node, std::pair<Node,Node>> getBounds(const std::vector<Node>& assertions);
+
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif \ No newline at end of file
diff --git a/src/theory/arith/callbacks.cpp b/src/theory/arith/callbacks.cpp
index 758a337ba..e1cb1c3ca 100644
--- a/src/theory/arith/callbacks.cpp
+++ b/src/theory/arith/callbacks.cpp
@@ -2,10 +2,10 @@
/*! \file callbacks.cpp
** \verbatim
** Top contributors (to current version):
- ** Tim King, Mathias Preiner
+ ** Tim King, Haniel Barbosa, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,6 +16,8 @@
**/
#include "theory/arith/callbacks.h"
+
+#include "theory/arith/proof_macros.h"
#include "theory/arith/theory_arith_private.h"
namespace CVC4 {
@@ -87,17 +89,17 @@ void FarkasConflictBuilder::reset(){
d_consequent = NullConstraint;
d_constraints.clear();
d_consequentSet = false;
- PROOF(d_farkas.clear());
+ ARITH_PROOF(d_farkas.clear());
Assert(!underConstruction());
}
/* Adds a constraint to the constraint under construction. */
void FarkasConflictBuilder::addConstraint(ConstraintCP c, const Rational& fc){
Assert(
- !PROOF_ON()
+ !ARITH_PROOF_ON()
|| (!underConstruction() && d_constraints.empty() && d_farkas.empty())
|| (underConstruction() && d_constraints.size() + 1 == d_farkas.size()));
- Assert(PROOF_ON() || d_farkas.empty());
+ Assert(ARITH_PROOF_ON() || d_farkas.empty());
Assert(c->isTrue());
if(d_consequent == NullConstraint){
@@ -105,17 +107,20 @@ void FarkasConflictBuilder::addConstraint(ConstraintCP c, const Rational& fc){
} else {
d_constraints.push_back(c);
}
- PROOF(d_farkas.push_back(fc););
- Assert(!PROOF_ON() || d_constraints.size() + 1 == d_farkas.size());
- Assert(PROOF_ON() || d_farkas.empty());
+ ARITH_PROOF(d_farkas.push_back(fc));
+ Assert(!ARITH_PROOF_ON() || d_constraints.size() + 1 == d_farkas.size());
+ Assert(ARITH_PROOF_ON() || d_farkas.empty());
}
void FarkasConflictBuilder::addConstraint(ConstraintCP c, const Rational& fc, const Rational& mult){
Assert(!mult.isZero());
- if(PROOF_ON() && !mult.isOne()){
+ if (ARITH_PROOF_ON() && !mult.isOne())
+ {
Rational prod = fc * mult;
addConstraint(c, prod);
- }else{
+ }
+ else
+ {
addConstraint(c, fc);
}
}
@@ -132,7 +137,7 @@ void FarkasConflictBuilder::makeLastConsequent(){
ConstraintCP last = d_constraints.back();
d_constraints.back() = d_consequent;
d_consequent = last;
- PROOF( std::swap( d_farkas.front(), d_farkas.back() ) );
+ ARITH_PROOF(std::swap(d_farkas.front(), d_farkas.back()));
d_consequentSet = true;
}
@@ -145,14 +150,14 @@ ConstraintCP FarkasConflictBuilder::commitConflict(){
Assert(underConstruction());
Assert(!d_constraints.empty());
Assert(
- !PROOF_ON()
+ !ARITH_PROOF_ON()
|| (!underConstruction() && d_constraints.empty() && d_farkas.empty())
|| (underConstruction() && d_constraints.size() + 1 == d_farkas.size()));
- Assert(PROOF_ON() || d_farkas.empty());
+ Assert(ARITH_PROOF_ON() || d_farkas.empty());
Assert(d_consequentSet);
ConstraintP not_c = d_consequent->getNegation();
- RationalVectorCP coeffs = NULLPROOF(&d_farkas);
+ RationalVectorCP coeffs = ARITH_NULLPROOF(&d_farkas);
not_c->impliedByFarkas(d_constraints, coeffs, true );
reset();
@@ -167,11 +172,12 @@ RaiseEqualityEngineConflict::RaiseEqualityEngineConflict(TheoryArithPrivate& ta)
{}
/* If you are not an equality engine, don't use this! */
-void RaiseEqualityEngineConflict::raiseEEConflict(Node n) const{
- d_ta.raiseBlackBoxConflict(n);
+void RaiseEqualityEngineConflict::raiseEEConflict(
+ Node n, std::shared_ptr<ProofNode> pf) const
+{
+ d_ta.raiseBlackBoxConflict(n, pf);
}
-
BoundCountingLookup::BoundCountingLookup(TheoryArithPrivate& ta)
: d_ta(ta)
{}
diff --git a/src/theory/arith/callbacks.h b/src/theory/arith/callbacks.h
index f947ca03b..796a93ea4 100644
--- a/src/theory/arith/callbacks.h
+++ b/src/theory/arith/callbacks.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner, Clark Barrett
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,16 +19,18 @@
#pragma once
#include "expr/node.h"
+#include "expr/proof_node.h"
#include "theory/arith/arithvar.h"
#include "theory/arith/bound_counts.h"
#include "theory/arith/constraint_forward.h"
-#include "theory/arith/theory_arith_private_forward.h"
#include "util/rational.h"
namespace CVC4 {
namespace theory {
namespace arith {
+class TheoryArithPrivate;
+
/**
* ArithVarCallBack provides a mechanism for agreeing on callbacks while
* breaking mutual recursion inclusion order problems.
@@ -176,8 +178,11 @@ private:
public:
RaiseEqualityEngineConflict(TheoryArithPrivate& ta);
- /* If you are not an equality engine, don't use this! */
- void raiseEEConflict(Node n) const;
+ /* If you are not an equality engine, don't use this!
+ *
+ * The proof should prove that `n` is a conflict.
+ * */
+ void raiseEEConflict(Node n, std::shared_ptr<ProofNode> pf) const;
};
class BoundCountingLookup {
diff --git a/src/theory/arith/congruence_manager.cpp b/src/theory/arith/congruence_manager.cpp
index 858098b70..57214e0f8 100644
--- a/src/theory/arith/congruence_manager.cpp
+++ b/src/theory/arith/congruence_manager.cpp
@@ -2,10 +2,10 @@
/*! \file congruence_manager.cpp
** \verbatim
** Top contributors (to current version):
- ** Tim King, Dejan Jovanovic, Paul Meng
+ ** Tim King, Andrew Reynolds, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -29,10 +29,12 @@ namespace arith {
ArithCongruenceManager::ArithCongruenceManager(
context::Context* c,
+ context::UserContext* u,
ConstraintDatabase& cd,
SetupLiteralCallBack setup,
const ArithVariables& avars,
- RaiseEqualityEngineConflict raiseConflict)
+ RaiseEqualityEngineConflict raiseConflict,
+ ProofNodeManager* pnm)
: d_inConflict(c),
d_raiseConflict(raiseConflict),
d_notify(*this),
@@ -42,16 +44,44 @@ ArithCongruenceManager::ArithCongruenceManager(
d_constraintDatabase(cd),
d_setupLiteral(setup),
d_avariables(avars),
- d_ee(d_notify, c, "theory::arith::ArithCongruenceManager", true)
+ d_ee(nullptr),
+ d_satContext(c),
+ d_userContext(u),
+ d_pnm(pnm),
+ // Construct d_pfGenEe with the SAT context, since its proof include
+ // unclosed assumptions of theory literals.
+ d_pfGenEe(
+ new EagerProofGenerator(pnm, c, "ArithCongruenceManager::pfGenEe")),
+ // Construct d_pfGenEe with the USER context, since its proofs are closed.
+ d_pfGenExplain(new EagerProofGenerator(
+ pnm, u, "ArithCongruenceManager::pfGenExplain")),
+ d_pfee(nullptr)
{
- d_ee.addFunctionKind(kind::NONLINEAR_MULT);
- d_ee.addFunctionKind(kind::EXPONENTIAL);
- d_ee.addFunctionKind(kind::SINE);
- d_ee.addFunctionKind(kind::IAND);
}
ArithCongruenceManager::~ArithCongruenceManager() {}
+bool ArithCongruenceManager::needsEqualityEngine(EeSetupInfo& esi)
+{
+ esi.d_notify = &d_notify;
+ esi.d_name = "theory::arith::ArithCongruenceManager";
+ return true;
+}
+
+void ArithCongruenceManager::finishInit(eq::EqualityEngine* ee,
+ eq::ProofEqEngine* pfee)
+{
+ Assert(ee != nullptr);
+ d_ee = ee;
+ d_ee->addFunctionKind(kind::NONLINEAR_MULT);
+ d_ee->addFunctionKind(kind::EXPONENTIAL);
+ d_ee->addFunctionKind(kind::SINE);
+ d_ee->addFunctionKind(kind::IAND);
+ // have proof equality engine only if proofs are enabled
+ Assert(isProofEnabled() == (pfee != nullptr));
+ d_pfee = pfee;
+}
+
ArithCongruenceManager::Statistics::Statistics():
d_watchedVariables("theory::arith::congruence::watchedVariables", 0),
d_watchedVariableIsZero("theory::arith::congruence::watchedVariableIsZero", 0),
@@ -84,16 +114,17 @@ ArithCongruenceManager::ArithCongruenceNotify::ArithCongruenceNotify(ArithCongru
: d_acm(acm)
{}
-bool ArithCongruenceManager::ArithCongruenceNotify::eqNotifyTriggerEquality(TNode equality, bool value) {
- Debug("arith::congruences") << "ArithCongruenceNotify::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false") << ")" << std::endl;
+bool ArithCongruenceManager::ArithCongruenceNotify::eqNotifyTriggerPredicate(
+ TNode predicate, bool value)
+{
+ Assert(predicate.getKind() == kind::EQUAL);
+ Debug("arith::congruences")
+ << "ArithCongruenceNotify::eqNotifyTriggerPredicate(" << predicate << ", "
+ << (value ? "true" : "false") << ")" << std::endl;
if (value) {
- return d_acm.propagate(equality);
- } else {
- return d_acm.propagate(equality.notNode());
+ return d_acm.propagate(predicate);
}
-}
-bool ArithCongruenceManager::ArithCongruenceNotify::eqNotifyTriggerPredicate(TNode predicate, bool value) {
- Unreachable();
+ return d_acm.propagate(predicate.notNode());
}
bool ArithCongruenceManager::ArithCongruenceNotify::eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) {
@@ -110,18 +141,20 @@ void ArithCongruenceManager::ArithCongruenceNotify::eqNotifyConstantTermMerge(TN
}
void ArithCongruenceManager::ArithCongruenceNotify::eqNotifyNewClass(TNode t) {
}
-void ArithCongruenceManager::ArithCongruenceNotify::eqNotifyPreMerge(TNode t1, TNode t2) {
-}
-void ArithCongruenceManager::ArithCongruenceNotify::eqNotifyPostMerge(TNode t1, TNode t2) {
+void ArithCongruenceManager::ArithCongruenceNotify::eqNotifyMerge(TNode t1,
+ TNode t2)
+{
}
void ArithCongruenceManager::ArithCongruenceNotify::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
}
-void ArithCongruenceManager::raiseConflict(Node conflict){
+void ArithCongruenceManager::raiseConflict(Node conflict,
+ std::shared_ptr<ProofNode> pf)
+{
Assert(!inConflict());
Debug("arith::conflict") << "difference manager conflict " << conflict << std::endl;
d_inConflict.raise();
- d_raiseConflict.raiseEEConflict(conflict);
+ d_raiseConflict.raiseEEConflict(conflict, pf);
}
bool ArithCongruenceManager::inConflict() const{
return d_inConflict.isRaised();
@@ -141,10 +174,6 @@ bool ArithCongruenceManager::canExplain(TNode n) const {
return d_explanationMap.find(n) != d_explanationMap.end();
}
-void ArithCongruenceManager::setMasterEqualityEngine(eq::EqualityEngine* eq) {
- d_ee.setMasterEqualityEngine(eq);
-}
-
Node ArithCongruenceManager::externalToInternal(TNode n) const{
Assert(canExplain(n));
ExplainMap::const_iterator iter = d_explanationMap.find(n);
@@ -184,13 +213,32 @@ void ArithCongruenceManager::watchedVariableIsZero(ConstraintCP lb, ConstraintCP
++(d_statistics.d_watchedVariableIsZero);
ArithVar s = lb->getVariable();
- Node reason = Constraint::externalExplainByAssertions(lb,ub);
+ TNode eq = d_watchedEqualities[s];
+ ConstraintCP eqC = d_constraintDatabase.getConstraint(
+ s, ConstraintType::Equality, lb->getValue());
+ NodeBuilder<> reasonBuilder(Kind::AND);
+ auto pfLb = lb->externalExplainByAssertions(reasonBuilder);
+ auto pfUb = ub->externalExplainByAssertions(reasonBuilder);
+ Node reason = safeConstructNary(reasonBuilder);
+ std::shared_ptr<ProofNode> pf{};
+ if (isProofEnabled())
+ {
+ pf = d_pnm->mkNode(
+ PfRule::ARITH_TRICHOTOMY, {pfLb, pfUb}, {eqC->getProofLiteral()});
+ pf = d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM, {pf}, {eq});
+ }
d_keepAlive.push_back(reason);
- assertionToEqualityEngine(true, s, reason);
+ Trace("arith-ee") << "Asserting an equality on " << s << ", on trichotomy"
+ << std::endl;
+ Trace("arith-ee") << " based on " << lb << std::endl;
+ Trace("arith-ee") << " based on " << ub << std::endl;
+ assertionToEqualityEngine(true, s, reason, pf);
}
void ArithCongruenceManager::watchedVariableIsZero(ConstraintCP eq){
+ Debug("arith::cong") << "Cong::watchedVariableIsZero: " << *eq << std::endl;
+
Assert(eq->isEquality());
Assert(eq->getValue().sgn() == 0);
@@ -201,23 +249,86 @@ void ArithCongruenceManager::watchedVariableIsZero(ConstraintCP eq){
//Explain for conflict is correct as these proofs are generated
//and stored eagerly
//These will be safe for propagation later as well
- Node reason = eq->externalExplainByAssertions();
+ NodeBuilder<> nb(Kind::AND);
+ // An open proof of eq from literals now in reason.
+ if (Debug.isOn("arith::cong"))
+ {
+ eq->printProofTree(Debug("arith::cong"));
+ }
+ auto pf = eq->externalExplainByAssertions(nb);
+ if (isProofEnabled())
+ {
+ pf = d_pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM, {pf}, {d_watchedEqualities[s]});
+ }
+ Node reason = safeConstructNary(nb);
d_keepAlive.push_back(reason);
- assertionToEqualityEngine(true, s, reason);
+ assertionToEqualityEngine(true, s, reason, pf);
}
void ArithCongruenceManager::watchedVariableCannotBeZero(ConstraintCP c){
+ Debug("arith::cong::notzero")
+ << "Cong::watchedVariableCannotBeZero " << *c << std::endl;
++(d_statistics.d_watchedVariableIsNotZero);
ArithVar s = c->getVariable();
+ Node disEq = d_watchedEqualities[s].negate();
//Explain for conflict is correct as these proofs are generated and stored eagerly
//These will be safe for propagation later as well
- Node reason = c->externalExplainByAssertions();
-
+ NodeBuilder<> nb(Kind::AND);
+ // An open proof of eq from literals now in reason.
+ auto pf = c->externalExplainByAssertions(nb);
+ if (Debug.isOn("arith::cong::notzero"))
+ {
+ Debug("arith::cong::notzero") << " original proof ";
+ pf->printDebug(Debug("arith::cong::notzero"));
+ Debug("arith::cong::notzero") << std::endl;
+ }
+ Node reason = safeConstructNary(nb);
+ if (isProofEnabled())
+ {
+ if (c->getType() == ConstraintType::Disequality)
+ {
+ Assert(c->getLiteral() == d_watchedEqualities[s].negate());
+ // We have to prove equivalence to the watched disequality.
+ pf = d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM, {pf}, {disEq});
+ }
+ else
+ {
+ Debug("arith::cong::notzero")
+ << " proof modification needed" << std::endl;
+
+ // Four cases:
+ // c has form x_i = d, d > 0 => multiply c by -1 in Farkas proof
+ // c has form x_i = d, d > 0 => multiply c by 1 in Farkas proof
+ // c has form x_i <= d, d < 0 => multiply c by 1 in Farkas proof
+ // c has form x_i >= d, d > 0 => multiply c by -1 in Farkas proof
+ const bool scaleCNegatively = c->getType() == ConstraintType::LowerBound
+ || (c->getType() == ConstraintType::Equality
+ && c->getValue().sgn() > 0);
+ const int cSign = scaleCNegatively ? -1 : 1;
+ TNode isZero = d_watchedEqualities[s];
+ const auto isZeroPf = d_pnm->mkAssume(isZero);
+ const auto nm = NodeManager::currentNM();
+ const auto sumPf = d_pnm->mkNode(
+ PfRule::ARITH_SCALE_SUM_UPPER_BOUNDS,
+ {isZeroPf, pf},
+ // Trick for getting correct, opposing signs.
+ {nm->mkConst(Rational(-1 * cSign)), nm->mkConst(Rational(cSign))});
+ const auto botPf = d_pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM, {sumPf}, {nm->mkConst(false)});
+ std::vector<Node> assumption = {isZero};
+ pf = d_pnm->mkScope(botPf, assumption, false);
+ Debug("arith::cong::notzero") << " new proof ";
+ pf->printDebug(Debug("arith::cong::notzero"));
+ Debug("arith::cong::notzero") << std::endl;
+ }
+ Assert(pf->getResult() == disEq);
+ }
d_keepAlive.push_back(reason);
- assertionToEqualityEngine(false, s, reason);
+ assertionToEqualityEngine(false, s, reason, pf);
}
@@ -236,11 +347,22 @@ bool ArithCongruenceManager::propagate(TNode x){
if(rewritten.getConst<bool>()){
return true;
}else{
+ // x rewrites to false.
++(d_statistics.d_conflicts);
-
- Node conf = flattenAnd(explainInternal(x));
- raiseConflict(conf);
+ TrustNode trn = explainInternal(x);
+ Node conf = flattenAnd(trn.getNode());
Debug("arith::congruenceManager") << "rewritten to false "<<x<<" with explanation "<< conf << std::endl;
+ if (isProofEnabled())
+ {
+ auto pf = trn.getGenerator()->getProofFor(trn.getProven());
+ auto confPf = d_pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM, {pf}, {conf.negate()});
+ raiseConflict(conf, confPf);
+ }
+ else
+ {
+ raiseConflict(conf);
+ }
return false;
}
}
@@ -262,9 +384,10 @@ bool ArithCongruenceManager::propagate(TNode x){
<< c->negationHasProof() << std::endl;
if(c->negationHasProof()){
- Node expC = explainInternal(x);
+ TrustNode texpC = explainInternal(x);
+ Node expC = texpC.getNode();
ConstraintCP negC = c->getNegation();
- Node neg = negC->externalExplainByAssertions();
+ Node neg = Constraint::externalExplainByAssertions({negC});
Node conf = expC.andNode(neg);
Node final = flattenAnd(conf);
@@ -320,9 +443,9 @@ bool ArithCongruenceManager::propagate(TNode x){
void ArithCongruenceManager::explain(TNode literal, std::vector<TNode>& assumptions) {
if (literal.getKind() != kind::NOT) {
- d_ee.explainEquality(literal[0], literal[1], true, assumptions);
+ d_ee->explainEquality(literal[0], literal[1], true, assumptions);
} else {
- d_ee.explainEquality(literal[0][0], literal[0][1], false, assumptions);
+ d_ee->explainEquality(literal[0][0], literal[0][1], false, assumptions);
}
}
@@ -334,28 +457,44 @@ void ArithCongruenceManager::enqueueIntoNB(const std::set<TNode> s, NodeBuilder<
}
}
-Node ArithCongruenceManager::explainInternal(TNode internal){
- std::vector<TNode> assumptions;
- explain(internal, assumptions);
-
- std::set<TNode> assumptionSet;
- assumptionSet.insert(assumptions.begin(), assumptions.end());
-
- if (assumptionSet.size() == 1) {
- // All the same, or just one
- return assumptions[0];
- }else{
- NodeBuilder<> conjunction(kind::AND);
- enqueueIntoNB(assumptionSet, conjunction);
- return conjunction;
+TrustNode ArithCongruenceManager::explainInternal(TNode internal)
+{
+ if (isProofEnabled())
+ {
+ return d_pfee->explain(internal);
}
+ // otherwise, explain without proof generator
+ Node exp = d_ee->mkExplainLit(internal);
+ return TrustNode::mkTrustPropExp(internal, exp, nullptr);
}
-Node ArithCongruenceManager::explain(TNode external){
+TrustNode ArithCongruenceManager::explain(TNode external)
+{
Trace("arith-ee") << "Ask for explanation of " << external << std::endl;
Node internal = externalToInternal(external);
Trace("arith-ee") << "...internal = " << internal << std::endl;
- return explainInternal(internal);
+ TrustNode trn = explainInternal(internal);
+ if (isProofEnabled() && trn.getProven()[1] != external)
+ {
+ Assert(trn.getKind() == TrustNodeKind::PROP_EXP);
+ Assert(trn.getProven().getKind() == Kind::IMPLIES);
+ Assert(trn.getGenerator() != nullptr);
+ Trace("arith-ee") << "tweaking proof to prove " << external << " not "
+ << trn.getProven()[1] << std::endl;
+ std::vector<std::shared_ptr<ProofNode>> assumptionPfs;
+ std::vector<Node> assumptions = andComponents(trn.getNode());
+ assumptionPfs.push_back(trn.toProofNode());
+ for (const auto& a : assumptions)
+ {
+ assumptionPfs.push_back(
+ d_pnm->mkNode(PfRule::TRUE_INTRO, {d_pnm->mkAssume(a)}, {}));
+ }
+ auto litPf = d_pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM, {assumptionPfs}, {external});
+ auto extPf = d_pnm->mkScope(litPf, assumptions);
+ return d_pfGenExplain->mkTrustedPropagation(external, trn.getNode(), extPf);
+ }
+ return trn;
}
void ArithCongruenceManager::explain(TNode external, NodeBuilder<>& out){
@@ -384,18 +523,86 @@ void ArithCongruenceManager::addWatchedPair(ArithVar s, TNode x, TNode y){
d_watchedEqualities.set(s, eq);
}
-void ArithCongruenceManager::assertionToEqualityEngine(bool isEquality, ArithVar s, TNode reason){
+void ArithCongruenceManager::assertLitToEqualityEngine(
+ Node lit, TNode reason, std::shared_ptr<ProofNode> pf)
+{
+ bool isEquality = lit.getKind() != Kind::NOT;
+ Node eq = isEquality ? lit : lit[0];
+ Assert(eq.getKind() == Kind::EQUAL);
+
+ Trace("arith-ee") << "Assert to Eq " << lit << ", reason " << reason
+ << std::endl;
+ if (isProofEnabled())
+ {
+ if (CDProof::isSame(lit, reason))
+ {
+ Trace("arith-pfee") << "Asserting only, b/c implied by symm" << std::endl;
+ // The equality engine doesn't ref-count for us...
+ d_keepAlive.push_back(eq);
+ d_keepAlive.push_back(reason);
+ d_ee->assertEquality(eq, isEquality, reason);
+ }
+ else if (hasProofFor(lit))
+ {
+ Trace("arith-pfee") << "Skipping b/c already done" << std::endl;
+ }
+ else
+ {
+ setProofFor(lit, pf);
+ Trace("arith-pfee") << "Actually asserting" << std::endl;
+ if (Debug.isOn("arith-pfee"))
+ {
+ Trace("arith-pfee") << "Proof: ";
+ pf->printDebug(Trace("arith-pfee"));
+ Trace("arith-pfee") << std::endl;
+ }
+ // The proof equality engine *does* ref-count for us...
+ d_pfee->assertFact(lit, reason, d_pfGenEe.get());
+ }
+ }
+ else
+ {
+ // The equality engine doesn't ref-count for us...
+ d_keepAlive.push_back(eq);
+ d_keepAlive.push_back(reason);
+ d_ee->assertEquality(eq, isEquality, reason);
+ }
+}
+
+void ArithCongruenceManager::assertionToEqualityEngine(
+ bool isEquality, ArithVar s, TNode reason, std::shared_ptr<ProofNode> pf)
+{
Assert(isWatchedVariable(s));
TNode eq = d_watchedEqualities[s];
Assert(eq.getKind() == kind::EQUAL);
- Trace("arith-ee") << "Assert " << eq << ", pol " << isEquality << ", reason " << reason << std::endl;
- if(isEquality){
- d_ee.assertEquality(eq, true, reason);
- }else{
- d_ee.assertEquality(eq, false, reason);
+ Node lit = isEquality ? Node(eq) : eq.notNode();
+ Trace("arith-ee") << "Assert to Eq " << eq << ", pol " << isEquality
+ << ", reason " << reason << std::endl;
+ assertLitToEqualityEngine(lit, reason, pf);
+}
+
+bool ArithCongruenceManager::hasProofFor(TNode f) const
+{
+ Assert(isProofEnabled());
+ if (d_pfGenEe->hasProofFor(f))
+ {
+ return true;
}
+ Node sym = CDProof::getSymmFact(f);
+ Assert(!sym.isNull());
+ return d_pfGenEe->hasProofFor(sym);
+}
+
+void ArithCongruenceManager::setProofFor(TNode f,
+ std::shared_ptr<ProofNode> pf) const
+{
+ Assert(!hasProofFor(f));
+ d_pfGenEe->mkTrustNode(f, pf);
+ Node symF = CDProof::getSymmFact(f);
+ auto symPf = d_pnm->mkNode(PfRule::SYMM, {pf}, {});
+ d_pfGenEe->mkTrustNode(symF, symPf);
}
void ArithCongruenceManager::equalsConstant(ConstraintCP c){
@@ -408,16 +615,18 @@ void ArithCongruenceManager::equalsConstant(ConstraintCP c){
Node xAsNode = d_avariables.asNode(x);
Node asRational = mkRationalNode(c->getValue().getNoninfinitesimalPart());
-
- //No guarentee this is in normal form!
+ // No guarentee this is in normal form!
+ // Note though, that it happens to be in proof normal form!
Node eq = xAsNode.eqNode(asRational);
d_keepAlive.push_back(eq);
- Node reason = c->externalExplainByAssertions();
+ NodeBuilder<> nb(Kind::AND);
+ auto pf = c->externalExplainByAssertions(nb);
+ Node reason = safeConstructNary(nb);
d_keepAlive.push_back(reason);
Trace("arith-ee") << "Assert equalsConstant " << eq << ", reason " << reason << std::endl;
- d_ee.assertEquality(eq, true, reason);
+ assertLitToEqualityEngine(eq, reason, pf);
}
void ArithCongruenceManager::equalsConstant(ConstraintCP lb, ConstraintCP ub){
@@ -430,22 +639,47 @@ void ArithCongruenceManager::equalsConstant(ConstraintCP lb, ConstraintCP ub){
<< ub << std::endl;
ArithVar x = lb->getVariable();
- Node reason = Constraint::externalExplainByAssertions(lb,ub);
+ NodeBuilder<> nb(Kind::AND);
+ auto pfLb = lb->externalExplainByAssertions(nb);
+ auto pfUb = ub->externalExplainByAssertions(nb);
+ Node reason = safeConstructNary(nb);
Node xAsNode = d_avariables.asNode(x);
Node asRational = mkRationalNode(lb->getValue().getNoninfinitesimalPart());
- //No guarentee this is in normal form!
+ // No guarentee this is in normal form!
+ // Note though, that it happens to be in proof normal form!
Node eq = xAsNode.eqNode(asRational);
+ std::shared_ptr<ProofNode> pf;
+ if (isProofEnabled())
+ {
+ pf = d_pnm->mkNode(PfRule::ARITH_TRICHOTOMY, {pfLb, pfUb}, {eq});
+ }
d_keepAlive.push_back(eq);
d_keepAlive.push_back(reason);
Trace("arith-ee") << "Assert equalsConstant2 " << eq << ", reason " << reason << std::endl;
- d_ee.assertEquality(eq, true, reason);
+
+ assertLitToEqualityEngine(eq, reason, pf);
}
-void ArithCongruenceManager::addSharedTerm(Node x){
- d_ee.addTriggerTerm(x, THEORY_ARITH);
+bool ArithCongruenceManager::isProofEnabled() const { return d_pnm != nullptr; }
+
+std::vector<Node> andComponents(TNode an)
+{
+ auto nm = NodeManager::currentNM();
+ if (an == nm->mkConst(true))
+ {
+ return {};
+ }
+ else if (an.getKind() != Kind::AND)
+ {
+ return {an};
+ }
+ std::vector<Node> a{};
+ a.reserve(an.getNumChildren());
+ a.insert(a.end(), an.begin(), an.end());
+ return a;
}
}/* CVC4::theory::arith namespace */
diff --git a/src/theory/arith/congruence_manager.h b/src/theory/arith/congruence_manager.h
index 96f82b059..3698f46d8 100644
--- a/src/theory/arith/congruence_manager.h
+++ b/src/theory/arith/congruence_manager.h
@@ -2,10 +2,10 @@
/*! \file congruence_manager.h
** \verbatim
** Top contributors (to current version):
- ** Tim King, Mathias Preiner, Dejan Jovanovic
+ ** Tim King, Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -24,20 +24,20 @@
#include "context/cdo.h"
#include "context/cdtrail_queue.h"
#include "context/context.h"
+#include "expr/proof_node_manager.h"
#include "theory/arith/arithvar.h"
#include "theory/arith/constraint_forward.h"
#include "theory/arith/partial_model.h"
+#include "theory/eager_proof_generator.h"
+#include "theory/ee_setup_info.h"
+#include "theory/trust_node.h"
#include "theory/uf/equality_engine.h"
+#include "theory/uf/proof_equality_engine.h"
#include "util/dense_map.h"
#include "util/statistics_registry.h"
namespace CVC4 {
namespace theory {
-
-namespace quantifiers {
-class EqualityInference;
-}
-
namespace arith {
class ArithCongruenceManager {
@@ -61,8 +61,6 @@ private:
public:
ArithCongruenceNotify(ArithCongruenceManager& acm);
- bool eqNotifyTriggerEquality(TNode equality, bool value) override;
-
bool eqNotifyTriggerPredicate(TNode predicate, bool value) override;
bool eqNotifyTriggerTermEquality(TheoryId tag,
@@ -72,8 +70,7 @@ private:
void eqNotifyConstantTermMerge(TNode t1, TNode t2) override;
void eqNotifyNewClass(TNode t) override;
- void eqNotifyPreMerge(TNode t1, TNode t2) override;
- void eqNotifyPostMerge(TNode t1, TNode t2) override;
+ void eqNotifyMerge(TNode t1, TNode t2) override;
void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override;
};
ArithCongruenceNotify d_notify;
@@ -96,11 +93,55 @@ private:
const ArithVariables& d_avariables;
- eq::EqualityEngine d_ee;
-
- void raiseConflict(Node conflict);
-public:
+ /** The equality engine being used by this class */
+ eq::EqualityEngine* d_ee;
+ /** The sat context */
+ context::Context* d_satContext;
+ /** The user context */
+ context::UserContext* d_userContext;
+
+ /** proof manager */
+ ProofNodeManager* d_pnm;
+ /** A proof generator for storing proofs of facts that are asserted to the EQ
+ * engine. Note that these proofs **are not closed**; they may contain
+ * literals from the explanation of their fact as unclosed assumptions.
+ * This makes these proofs SAT-context depdent.
+ *
+ * This is why this generator is separate from the TheoryArithPrivate
+ * generator, which stores closed proofs.
+ */
+ std::unique_ptr<EagerProofGenerator> d_pfGenEe;
+ /** A proof generator for TrustNodes sent to TheoryArithPrivate.
+ *
+ * When TheoryArithPrivate requests an explanation from
+ * ArithCongruenceManager, it can request a TrustNode for that explanation.
+ * This proof generator is the one used in that TrustNode: it stores the
+ * (closed) proofs of implications proved by the
+ * ArithCongruenceManager/EqualityEngine.
+ *
+ * It is insufficient to just use the ProofGenerator from the ProofEqEngine,
+ * since sometimes the ArithCongruenceManager needs to add some
+ * arith-specific reasoning to extend the proof (e.g. rewriting the result
+ * into a normal form).
+ * */
+ std::unique_ptr<EagerProofGenerator> d_pfGenExplain;
+
+ /** Pointer to the proof equality engine of TheoryArith */
+ theory::eq::ProofEqEngine* d_pfee;
+
+ /** Raise a conflict node `conflict` to the theory of arithmetic.
+ *
+ * When proofs are enabled, a (closed) proof of the conflict should be
+ * provided.
+ */
+ void raiseConflict(Node conflict, std::shared_ptr<ProofNode> pf = nullptr);
+ /**
+ * Are proofs enabled? This is true if a non-null proof manager was provided
+ * to the constructor of this class.
+ */
+ bool isProofEnabled() const;
+ public:
bool inConflict() const;
bool hasMorePropagations() const;
@@ -109,8 +150,6 @@ public:
bool canExplain(TNode n) const;
- void setMasterEqualityEngine(eq::EqualityEngine* eq);
-
private:
Node externalToInternal(TNode n) const;
@@ -123,9 +162,36 @@ private:
bool propagate(TNode x);
void explain(TNode literal, std::vector<TNode>& assumptions);
-
+ /** Assert this literal to the eq engine. Common functionality for
+ * * assertionToEqualityEngine(..)
+ * * equalsConstant(c)
+ * * equalsConstant(lb, ub)
+ * If proofNew is off, then just asserts.
+ */
+ void assertLitToEqualityEngine(Node lit,
+ TNode reason,
+ std::shared_ptr<ProofNode> pf);
/** This sends a shared term to the uninterpreted equality engine. */
- void assertionToEqualityEngine(bool eq, ArithVar s, TNode reason);
+ void assertionToEqualityEngine(bool eq,
+ ArithVar s,
+ TNode reason,
+ std::shared_ptr<ProofNode> pf);
+
+ /** Check for proof for this or a symmetric fact
+ *
+ * The proof submitted to this method are stored in `d_pfGenEe`, and should
+ * have closure properties consistent with the documentation for that member.
+ *
+ * @returns whether this or a symmetric fact has a proof.
+ */
+ bool hasProofFor(TNode f) const;
+ /**
+ * Sets the proof for this fact and the symmetric one.
+ *
+ * The proof submitted to this method are stored in `d_pfGenEe`, and should
+ * have closure properties consistent with the documentation for that member.
+ * */
+ void setProofFor(TNode f, std::shared_ptr<ProofNode> pf) const;
/** Dequeues the delay queue and asserts these equalities.*/
void enableSharedTerms();
@@ -133,13 +199,43 @@ private:
void enqueueIntoNB(const std::set<TNode> all, NodeBuilder<>& nb);
- Node explainInternal(TNode internal);
-public:
-
- ArithCongruenceManager(context::Context* satContext, ConstraintDatabase&, SetupLiteralCallBack, const ArithVariables&, RaiseEqualityEngineConflict raiseConflict);
+ /**
+ * Determine an explaination for `internal`. That is a conjunction of theory
+ * literals which imply `internal`.
+ *
+ * The TrustNode here is a trusted propagation.
+ */
+ TrustNode explainInternal(TNode internal);
+
+ public:
+ ArithCongruenceManager(context::Context* satContext,
+ context::UserContext* u,
+ ConstraintDatabase&,
+ SetupLiteralCallBack,
+ const ArithVariables&,
+ RaiseEqualityEngineConflict raiseConflict,
+ ProofNodeManager* pnm);
~ArithCongruenceManager();
- Node explain(TNode literal);
+ //--------------------------------- initialization
+ /**
+ * Returns true if we need an equality engine, see
+ * Theory::needsEqualityEngine.
+ */
+ bool needsEqualityEngine(EeSetupInfo& esi);
+ /**
+ * Finish initialize. This class is instructed by TheoryArithPrivate to use
+ * the equality engine ee and proof equality engine pfee.
+ */
+ void finishInit(eq::EqualityEngine* ee, eq::ProofEqEngine* pfee);
+ //--------------------------------- end initialization
+
+ /**
+ * Return the trust node for the explanation of literal. The returned
+ * trust node is generated by the proof equality engine of this class.
+ */
+ TrustNode explain(TNode literal);
+
void explain(TNode lit, NodeBuilder<>& out);
void addWatchedPair(ArithVar s, TNode x, TNode y);
@@ -165,12 +261,7 @@ public:
void equalsConstant(ConstraintCP eq);
void equalsConstant(ConstraintCP lb, ConstraintCP ub);
-
- void addSharedTerm(Node x);
-
- eq::EqualityEngine * getEqualityEngine() { return &d_ee; }
-
-private:
+ private:
class Statistics {
public:
IntStat d_watchedVariables;
@@ -189,6 +280,8 @@ private:
};/* class ArithCongruenceManager */
+std::vector<Node> andComponents(TNode an);
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/arith/constraint.cpp b/src/theory/arith/constraint.cpp
index abfaca954..b0be108f7 100644
--- a/src/theory/arith/constraint.cpp
+++ b/src/theory/arith/constraint.cpp
@@ -2,10 +2,10 @@
/*! \file constraint.cpp
** \verbatim
** Top contributors (to current version):
- ** Tim King, Alex Ozdemir, Mathias Preiner
+ ** Tim King, Alex Ozdemir, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,7 +21,6 @@
#include <unordered_set>
#include "base/output.h"
-#include "proof/proof.h"
#include "smt/smt_statistics_registry.h"
#include "theory/arith/arith_utilities.h"
#include "theory/arith/normal_form.h"
@@ -478,6 +477,29 @@ bool Constraint::isInternalAssumption() const {
return getProofType() == InternalAssumeAP;
}
+TrustNode Constraint::externalExplainByAssertions() const
+{
+ NodeBuilder<> nb(kind::AND);
+ auto pfFromAssumptions = externalExplain(nb, AssertionOrderSentinel);
+ Node exp = safeConstructNary(nb);
+ if (d_database->isProofEnabled())
+ {
+ std::vector<Node> assumptions;
+ if (exp.getKind() == Kind::AND)
+ {
+ assumptions.insert(assumptions.end(), exp.begin(), exp.end());
+ }
+ else
+ {
+ assumptions.push_back(exp);
+ }
+ auto pf = d_database->d_pnm->mkScope(pfFromAssumptions, assumptions);
+ return d_database->d_pfGen->mkTrustedPropagation(
+ getLiteral(), safeConstructNary(Kind::AND, assumptions), pf);
+ }
+ return TrustNode::mkTrustPropExp(getLiteral(), exp);
+}
+
bool Constraint::isAssumption() const {
return getProofType() == AssumeAP;
}
@@ -506,18 +528,8 @@ bool Constraint::hasSimpleFarkasProof() const
for (ConstraintCP a = d_database->getAntecedent(i); a != NullConstraint;
a = d_database->getAntecedent(--i))
{
- // ... that antecdent must be an assumption ...
- if (a->isAssumption())
- {
- continue;
- }
-
- // ... OR a tightened assumption ...
- if (a->hasIntTightenProof()
- && a->getConstraintRule().d_antecedentEnd != AntecedentIdSentinel
- && d_database->getAntecedent(a->getConstraintRule().d_antecedentEnd)
- ->isAssumption())
-
+ // ... that antecdent must be an assumption OR a tightened assumption ...
+ if (a->isPossiblyTightenedAssumption())
{
continue;
}
@@ -536,6 +548,17 @@ bool Constraint::hasSimpleFarkasProof() const
return true;
}
+bool Constraint::isPossiblyTightenedAssumption() const
+{
+ // ... that antecdent must be an assumption ...
+
+ if (isAssumption()) return true;
+ if (!hasIntTightenProof()) return false;
+ if (getConstraintRule().d_antecedentEnd == AntecedentIdSentinel) return false;
+ return d_database->getAntecedent(getConstraintRule().d_antecedentEnd)
+ ->isAssumption();
+}
+
bool Constraint::hasIntTightenProof() const {
return getProofType() == IntTightenAP;
}
@@ -550,46 +573,46 @@ bool Constraint::hasTrichotomyProof() const {
void Constraint::printProofTree(std::ostream& out, size_t depth) const
{
-#if IS_PROOFS_BUILD
- const ConstraintRule& rule = getConstraintRule();
- out << std::string(2 * depth, ' ') << "* " << getVariable() << " [";
- if (hasLiteral())
+ if (ARITH_PROOF_ON())
{
- out << getLiteral();
- }
- else
- {
- out << "NOLIT";
- };
- out << "]" << ' ' << getType() << ' ' << getValue() << " (" << getProofType()
- << ")";
- if (getProofType() == FarkasAP)
- {
- out << " [";
- bool first = true;
- for (const auto& coeff : *rule.d_farkasCoefficients)
+ const ConstraintRule& rule = getConstraintRule();
+ out << std::string(2 * depth, ' ') << "* " << getVariable() << " [";
+ out << getProofLiteral();
+ if (assertedToTheTheory())
+ {
+ out << " | wit: " << getWitness();
+ }
+ out << "]" << ' ' << getType() << ' ' << getValue() << " ("
+ << getProofType() << ")";
+ if (getProofType() == FarkasAP)
{
- if (not first)
+ out << " [";
+ bool first = true;
+ for (const auto& coeff : *rule.d_farkasCoefficients)
{
- out << ", ";
+ if (not first)
+ {
+ out << ", ";
+ }
+ first = false;
+ out << coeff;
}
- first = false;
- out << coeff;
+ out << "]";
}
- out << "]";
- }
- out << endl;
+ out << endl;
- for (AntecedentId i = rule.d_antecedentEnd; i != AntecedentIdSentinel; --i) {
- ConstraintCP antecdent = d_database->getAntecedent(i);
- if (antecdent == NullConstraint) {
- break;
+ for (AntecedentId i = rule.d_antecedentEnd; i != AntecedentIdSentinel; --i)
+ {
+ ConstraintCP antecdent = d_database->getAntecedent(i);
+ if (antecdent == NullConstraint)
+ {
+ break;
+ }
+ antecdent->printProofTree(out, depth + 1);
}
- antecdent->printProofTree(out, depth + 1);
+ return;
}
-#else /* IS_PROOFS_BUILD */
out << "Cannot print proof. This is not a proof build." << endl;
-#endif /* IS_PROOFS_BUILD */
}
bool Constraint::sanityChecking(Node n) const {
@@ -647,8 +670,7 @@ ConstraintCP ConstraintDatabase::getAntecedent (AntecedentId p) const {
void ConstraintRule::print(std::ostream& out) const {
-
- RationalVectorCP coeffs = NULLPROOF(d_farkasCoefficients);
+ RationalVectorCP coeffs = ARITH_NULLPROOF(d_farkasCoefficients);
out << "{ConstraintRule, ";
out << d_constraint << std::endl;
out << "d_proofType= " << d_proofType << ", " << std::endl;
@@ -657,7 +679,7 @@ void ConstraintRule::print(std::ostream& out) const {
if (d_constraint != NullConstraint && d_antecedentEnd != AntecedentIdSentinel)
{
const ConstraintDatabase& database = d_constraint->getDatabase();
-
+
size_t coeffIterator = (coeffs != RationalVectorCPSentinel) ? coeffs->size()-1 : 0;
AntecedentId p = d_antecedentEnd;
// must have at least one antecedent
@@ -699,9 +721,11 @@ bool Constraint::wellFormedFarkasProof() const {
ConstraintCP antecedent = d_database->d_antecedents[p];
if(antecedent == NullConstraint) { return false; }
-#if IS_PROOFS_BUILD
- if(!PROOF_ON()){ return cr.d_farkasCoefficients == RationalVectorCPSentinel; }
- Assert(PROOF_ON());
+ if (!ARITH_PROOF_ON())
+ {
+ return cr.d_farkasCoefficients == RationalVectorCPSentinel;
+ }
+ Assert(ARITH_PROOF_ON());
if(cr.d_farkasCoefficients == RationalVectorCPSentinel){ return false; }
if(cr.d_farkasCoefficients->size() < 2){ return false; }
@@ -754,7 +778,7 @@ bool Constraint::wellFormedFarkasProof() const {
default:
return false;
}
-
+
if(coeffIterator == coeffBegin){ return false; }
--coeffIterator;
--p;
@@ -799,10 +823,6 @@ bool Constraint::wellFormedFarkasProof() const {
// 0 = lhs <= rhs < 0
return (lhs.isNull() || (Constant::isMember(lhs) && Constant(lhs).isZero()))
&& rhs.sgn() < 0;
-
-#else /* IS_PROOFS_BUILD */
- return true;
-#endif /* IS_PROOFS_BUILD */
}
ConstraintP Constraint::makeNegation(ArithVar v, ConstraintType t, const DeltaRational& r){
@@ -847,19 +867,26 @@ ConstraintP Constraint::makeNegation(ArithVar v, ConstraintType t, const DeltaRa
}
}
-ConstraintDatabase::ConstraintDatabase(context::Context* satContext, context::Context* userContext, const ArithVariables& avars, ArithCongruenceManager& cm, RaiseConflict raiseConflict)
- : d_varDatabases()
- , d_toPropagate(satContext)
- , d_antecedents(satContext, false)
- , d_watches(new Watches(satContext, userContext))
- , d_avariables(avars)
- , d_congruenceManager(cm)
- , d_satContext(satContext)
- , d_raiseConflict(raiseConflict)
- , d_one(1)
- , d_negOne(-1)
+ConstraintDatabase::ConstraintDatabase(context::Context* satContext,
+ context::Context* userContext,
+ const ArithVariables& avars,
+ ArithCongruenceManager& cm,
+ RaiseConflict raiseConflict,
+ EagerProofGenerator* pfGen,
+ ProofNodeManager* pnm)
+ : d_varDatabases(),
+ d_toPropagate(satContext),
+ d_antecedents(satContext, false),
+ d_watches(new Watches(satContext, userContext)),
+ d_avariables(avars),
+ d_congruenceManager(cm),
+ d_satContext(satContext),
+ d_pfGen(pfGen),
+ d_pnm(pnm),
+ d_raiseConflict(raiseConflict),
+ d_one(1),
+ d_negOne(-1)
{
-
}
SortedConstraintMap& ConstraintDatabase::getVariableSCM(ArithVar v) const{
@@ -1035,7 +1062,8 @@ bool Constraint::contextDependentDataIsSet() const{
return hasProof() || isSplit() || canBePropagated() || assertedToTheTheory();
}
-Node Constraint::split(){
+TrustNode Constraint::split()
+{
Assert(isEquality() || isDisequality());
bool isEq = isEquality();
@@ -1049,15 +1077,48 @@ Node Constraint::split(){
TNode rhs = eqNode[1];
Node leqNode = NodeBuilder<2>(kind::LEQ) << lhs << rhs;
+ Node ltNode = NodeBuilder<2>(kind::LT) << lhs << rhs;
+ Node gtNode = NodeBuilder<2>(kind::GT) << lhs << rhs;
Node geqNode = NodeBuilder<2>(kind::GEQ) << lhs << rhs;
Node lemma = NodeBuilder<3>(OR) << leqNode << geqNode;
+ TrustNode trustedLemma;
+ if (options::proofNew())
+ {
+ // Farkas proof that this works.
+ auto nm = NodeManager::currentNM();
+ auto nLeqPf = d_database->d_pnm->mkAssume(leqNode.negate());
+ auto gtPf = d_database->d_pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM, {nLeqPf}, {gtNode});
+ auto nGeqPf = d_database->d_pnm->mkAssume(geqNode.negate());
+ auto ltPf = d_database->d_pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM, {nGeqPf}, {ltNode});
+ auto sumPf = d_database->d_pnm->mkNode(
+ PfRule::ARITH_SCALE_SUM_UPPER_BOUNDS,
+ {gtPf, ltPf},
+ {nm->mkConst<Rational>(-1), nm->mkConst<Rational>(1)});
+ auto botPf = d_database->d_pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM, {sumPf}, {nm->mkConst(false)});
+ std::vector<Node> a = {leqNode.negate(), geqNode.negate()};
+ auto notAndNotPf = d_database->d_pnm->mkScope(botPf, a);
+ // No need to ensure that the expected node aggrees with `a` because we are
+ // not providing an expected node.
+ auto orNotNotPf =
+ d_database->d_pnm->mkNode(PfRule::NOT_AND, {notAndNotPf}, {});
+ auto orPf = d_database->d_pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM, {orNotNotPf}, {lemma});
+ trustedLemma = d_database->d_pfGen->mkTrustNode(lemma, orPf);
+ }
+ else
+ {
+ trustedLemma = TrustNode::mkTrustLemma(lemma);
+ }
eq->d_database->pushSplitWatch(eq);
diseq->d_database->pushSplitWatch(diseq);
- return lemma;
+ return trustedLemma;
}
bool ConstraintDatabase::hasLiteral(TNode literal) const {
@@ -1108,7 +1169,7 @@ ConstraintP ConstraintDatabase::addLiteral(TNode literal){
return isNot ? hit->getNegation(): hit;
}else{
Comparison negCmp = Comparison::parseNormalForm(negationNode);
-
+
ConstraintType negType = Constraint::constraintTypeOfComparison(negCmp);
DeltaRational negDR = negCmp.normalizedDeltaRational();
@@ -1212,7 +1273,8 @@ void Constraint::impliedByUnate(ConstraintCP imp, bool nowInConflict){
AntecedentId antecedentEnd = d_database->d_antecedents.size() - 1;
RationalVectorP coeffs;
- if(PROOF_ON()){
+ if (ARITH_PROOF_ON())
+ {
std::pair<int, int> sgns = unateFarkasSigns(getNegation(), imp);
Rational first(sgns.first);
@@ -1221,10 +1283,11 @@ void Constraint::impliedByUnate(ConstraintCP imp, bool nowInConflict){
coeffs = new RationalVector();
coeffs->push_back(first);
coeffs->push_back(second);
- } else {
+ }
+ else
+ {
coeffs = RationalVectorPSentinel;
}
-
// no need to delete coeffs the memory is owned by ConstraintRule
d_database->pushConstraintRule(ConstraintRule(this, FarkasAP, antecedentEnd, coeffs));
@@ -1232,7 +1295,7 @@ void Constraint::impliedByUnate(ConstraintCP imp, bool nowInConflict){
if(Debug.isOn("constraint::conflictCommit") && inConflict()){
Debug("constraint::conflictCommit") << "inConflict@impliedByUnate " << this << std::endl;
}
-
+
if(Debug.isOn("constraints::wffp") && !wellFormedFarkasProof()){
getConstraintRule().print(Debug("constraints::wffp"));
}
@@ -1342,7 +1405,7 @@ void Constraint::impliedByIntHole(const ConstraintCPVec& b, bool nowInConflict){
* coeffs != RationalVectorSentinal,
* coeffs->size() = a.size() + 1,
* for i in [0,a.size) : coeff[i] corresponds to a[i], and
- * coeff.back() corresponds to the current constraint.
+ * coeff.back() corresponds to the current constraint.
*/
void Constraint::impliedByFarkas(const ConstraintCPVec& a, RationalVectorCP coeffs, bool nowInConflict){
Debug("constraints::pf") << "impliedByFarkas(" << this;
@@ -1358,10 +1421,9 @@ void Constraint::impliedByFarkas(const ConstraintCPVec& a, RationalVectorCP coef
Assert(negationHasProof() == nowInConflict);
Assert(allHaveProof(a));
- Assert(PROOF_ON() == (coeffs != RationalVectorCPSentinel));
- // !PROOF_ON() => coeffs == RationalVectorCPSentinel
- // PROOF_ON() => coeffs->size() == a.size() + 1
- Assert(!PROOF_ON() || coeffs->size() == a.size() + 1);
+ Assert(ARITH_PROOF_ON() == (coeffs != RationalVectorCPSentinel));
+ Assert(!ARITH_PROOF_ON() || coeffs->size() == a.size() + 1);
+
Assert(a.size() >= 1);
d_database->d_antecedents.push_back(NullConstraint);
@@ -1373,10 +1435,13 @@ void Constraint::impliedByFarkas(const ConstraintCPVec& a, RationalVectorCP coef
AntecedentId antecedentEnd = d_database->d_antecedents.size() - 1;
RationalVectorCP coeffsCopy;
- if(PROOF_ON()){
+ if (ARITH_PROOF_ON())
+ {
Assert(coeffs != RationalVectorCPSentinel);
coeffsCopy = new RationalVector(*coeffs);
- } else {
+ }
+ else
+ {
coeffsCopy = RationalVectorCPSentinel;
}
d_database->pushConstraintRule(ConstraintRule(this, FarkasAP, antecedentEnd, coeffsCopy));
@@ -1445,14 +1510,92 @@ Node Constraint::externalExplainByAssertions(const ConstraintCPVec& b){
return externalExplain(b, AssertionOrderSentinel);
}
-Node Constraint::externalExplainConflict() const{
+TrustNode Constraint::externalExplainForPropagation() const
+{
+ Assert(hasProof());
+ Assert(!isAssumption());
+ Assert(!isInternalAssumption());
+ NodeBuilder<> nb(Kind::AND);
+ auto pfFromAssumptions = externalExplain(nb, d_assertionOrder);
+ Node n = safeConstructNary(nb);
+ if (d_database->isProofEnabled())
+ {
+ std::vector<Node> assumptions;
+ if (n.getKind() == Kind::AND)
+ {
+ assumptions.insert(assumptions.end(), n.begin(), n.end());
+ }
+ else
+ {
+ assumptions.push_back(n);
+ }
+ if (getProofLiteral() != getLiteral())
+ {
+ pfFromAssumptions = d_database->d_pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM, {pfFromAssumptions}, {getLiteral()});
+ }
+ auto pf = d_database->d_pnm->mkScope(pfFromAssumptions, assumptions);
+ return d_database->d_pfGen->mkTrustedPropagation(
+ getLiteral(), safeConstructNary(Kind::AND, assumptions), pf);
+ }
+ else
+ {
+ return TrustNode::mkTrustPropExp(getLiteral(), n);
+ }
+}
+
+TrustNode Constraint::externalExplainConflict() const
+{
Debug("pf::arith::explain") << this << std::endl;
Assert(inConflict());
NodeBuilder<> nb(kind::AND);
- externalExplainByAssertions(nb);
- getNegation()->externalExplainByAssertions(nb);
-
- return safeConstructNary(nb);
+ auto pf1 = externalExplainByAssertions(nb);
+ auto not2 = getNegation()->getProofLiteral().negate();
+ auto pf2 = getNegation()->externalExplainByAssertions(nb);
+ Node n = safeConstructNary(nb);
+ if (d_database->isProofEnabled())
+ {
+ auto pfNot2 = d_database->d_pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM, {pf1}, {not2});
+ std::vector<Node> lits;
+ if (n.getKind() == Kind::AND)
+ {
+ lits.insert(lits.end(), n.begin(), n.end());
+ }
+ else
+ {
+ lits.push_back(n);
+ }
+ if (Debug.isOn("arith::pf::externalExplainConflict"))
+ {
+ Debug("arith::pf::externalExplainConflict") << "Lits:" << std::endl;
+ for (const auto& l : lits)
+ {
+ Debug("arith::pf::externalExplainConflict") << " : " << l << std::endl;
+ }
+ }
+ std::vector<Node> contraLits = {getProofLiteral(),
+ getNegation()->getProofLiteral()};
+ auto bot =
+ not2.getKind() == Kind::NOT
+ ? d_database->d_pnm->mkNode(PfRule::CONTRA, {pf2, pfNot2}, {})
+ : d_database->d_pnm->mkNode(PfRule::CONTRA, {pfNot2, pf2}, {});
+ if (Debug.isOn("arith::pf::tree"))
+ {
+ Debug("arith::pf::tree") << *this << std::endl;
+ Debug("arith::pf::tree") << *getNegation() << std::endl;
+ Debug("arith::pf::tree") << "\n\nTree:\n";
+ printProofTree(Debug("arith::pf::tree"));
+ getNegation()->printProofTree(Debug("arith::pf::tree"));
+ }
+ auto confPf = d_database->d_pnm->mkScope(bot, lits);
+ return d_database->d_pfGen->mkTrustNode(
+ safeConstructNary(Kind::AND, lits), confPf, true);
+ }
+ else
+ {
+ return TrustNode::mkTrustConflict(n);
+ }
}
struct ConstraintCPHash {
@@ -1511,68 +1654,201 @@ Node Constraint::externalExplain(const ConstraintCPVec& v, AssertionOrder order)
return safeConstructNary(nb);
}
-void Constraint::externalExplain(NodeBuilder<>& nb, AssertionOrder order) const{
- Assert(hasProof());
- Assert(!isAssumption() || assertedToTheTheory());
- Assert(!isInternalAssumption());
-
+std::shared_ptr<ProofNode> Constraint::externalExplain(
+ NodeBuilder<>& nb, AssertionOrder order) const
+{
if (Debug.isOn("pf::arith::explain"))
{
+ this->printProofTree(Debug("arith::pf::tree"));
Debug("pf::arith::explain") << "Explaining: " << this << " with rule ";
getConstraintRule().print(Debug("pf::arith::explain"));
Debug("pf::arith::explain") << std::endl;
}
+ Assert(hasProof());
+ Assert(!isAssumption() || assertedToTheTheory());
+ Assert(!isInternalAssumption());
+ std::shared_ptr<ProofNode> pf{};
- if(assertedBefore(order)){
+ ProofNodeManager* pnm = d_database->d_pnm;
+
+ if (assertedBefore(order))
+ {
+ Debug("pf::arith::explain") << " already asserted" << std::endl;
nb << getWitness();
- }else if(hasEqualityEngineProof()){
- d_database->eeExplain(this, nb);
- }else{
+ if (d_database->isProofEnabled())
+ {
+ pf = pnm->mkAssume(getWitness());
+ // If the witness and literal differ, prove the difference through a
+ // rewrite.
+ if (getWitness() != getProofLiteral())
+ {
+ pf = pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM, {pf}, {getProofLiteral()});
+ }
+ }
+ }
+ else if (hasEqualityEngineProof())
+ {
+ Debug("pf::arith::explain") << " going to ee:" << std::endl;
+ TrustNode exp = d_database->eeExplain(this);
+ if (d_database->isProofEnabled())
+ {
+ Assert(exp.getProven().getKind() == Kind::IMPLIES);
+ std::vector<std::shared_ptr<ProofNode>> hypotheses;
+ hypotheses.push_back(exp.getGenerator()->getProofFor(exp.getProven()));
+ if (exp.getNode().getKind() == Kind::AND)
+ {
+ for (const auto& h : exp.getNode())
+ {
+ hypotheses.push_back(
+ pnm->mkNode(PfRule::TRUE_INTRO, {pnm->mkAssume(h)}, {}));
+ }
+ }
+ else
+ {
+ hypotheses.push_back(pnm->mkNode(
+ PfRule::TRUE_INTRO, {pnm->mkAssume(exp.getNode())}, {}));
+ }
+ pf = pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM, {hypotheses}, {getProofLiteral()});
+ }
+ Debug("pf::arith::explain")
+ << " explanation: " << exp.getNode() << std::endl;
+ if (exp.getNode().getKind() == Kind::AND)
+ {
+ nb.append(exp.getNode().begin(), exp.getNode().end());
+ }
+ else
+ {
+ nb << exp.getNode();
+ }
+ }
+ else
+ {
+ Debug("pf::arith::explain") << " recursion!" << std::endl;
Assert(!isAssumption());
AntecedentId p = getEndAntecedent();
ConstraintCP antecedent = d_database->d_antecedents[p];
+ std::vector<std::shared_ptr<ProofNode>> children;
- while(antecedent != NullConstraint){
+ while (antecedent != NullConstraint)
+ {
Debug("pf::arith::explain") << "Explain " << antecedent << std::endl;
- antecedent->externalExplain(nb, order);
+ auto pn = antecedent->externalExplain(nb, order);
+ if (d_database->isProofEnabled())
+ {
+ children.push_back(pn);
+ }
--p;
antecedent = d_database->d_antecedents[p];
}
- }
-}
-Node Constraint::externalExplain(AssertionOrder order) const{
- Assert(hasProof());
- Assert(!isAssumption() || assertedBefore(order));
- Assert(!isInternalAssumption());
- if(assertedBefore(order)){
- return getWitness();
- }else if(hasEqualityEngineProof()){
- return d_database->eeExplain(this);
- }else{
- Assert(hasFarkasProof() || hasIntHoleProof() || hasIntTightenProof() || hasTrichotomyProof());
- Assert(!antecentListIsEmpty());
- //Force the selection of the layer above if the node is
- // assertedToTheTheory()!
-
- AntecedentId listEnd = getEndAntecedent();
- if(antecedentListLengthIsOne()){
- ConstraintCP antecedent = d_database->d_antecedents[listEnd];
- return antecedent->externalExplain(order);
- }else{
- NodeBuilder<> nb(kind::AND);
- Assert(!isAssumption());
-
- AntecedentId p = listEnd;
- ConstraintCP antecedent = d_database->d_antecedents[p];
- while(antecedent != NullConstraint){
- antecedent->externalExplain(nb, order);
- --p;
- antecedent = d_database->d_antecedents[p];
+ if (d_database->isProofEnabled())
+ {
+ switch (getProofType())
+ {
+ case ArithProofType::AssumeAP:
+ case ArithProofType::EqualityEngineAP:
+ {
+ Unreachable() << "These should be handled above";
+ break;
+ }
+ case ArithProofType::FarkasAP:
+ {
+ // Per docs in constraint.h,
+ // the 0th farkas coefficient is for the negation of the deduced
+ // constraint the 1st corresponds to the last antecedent the nth
+ // corresponds to the first antecedent Then, the farkas coefficients
+ // and the antecedents are in the same order.
+
+ // Enumerate child proofs (negation included) in d_farkasCoefficients
+ // order
+ std::vector<std::shared_ptr<ProofNode>> farkasChildren;
+ farkasChildren.push_back(
+ pnm->mkAssume(getNegation()->getProofLiteral()));
+ farkasChildren.insert(
+ farkasChildren.end(), children.rbegin(), children.rend());
+
+ NodeManager* nm = NodeManager::currentNM();
+
+ // Enumerate d_farkasCoefficients as nodes.
+ std::vector<Node> farkasCoeffs;
+ for (Rational r : *getFarkasCoefficients())
+ {
+ farkasCoeffs.push_back(nm->mkConst<Rational>(r));
+ }
+
+ // Apply the scaled-sum rule.
+ std::shared_ptr<ProofNode> sumPf =
+ pnm->mkNode(PfRule::ARITH_SCALE_SUM_UPPER_BOUNDS,
+ farkasChildren,
+ farkasCoeffs);
+
+ // Provable rewrite the result
+ auto botPf = pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM, {sumPf}, {nm->mkConst(false)});
+
+ // Scope out the negated constraint, yielding a proof of the
+ // constraint.
+ std::vector<Node> assump{getNegation()->getProofLiteral()};
+ auto maybeDoubleNotPf = pnm->mkScope(botPf, assump, false);
+
+ // No need to ensure that the expected node aggrees with `assump`
+ // because we are not providing an expected node.
+ //
+ // Prove that this is the literal (may need to clean a double-not)
+ pf = pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM,
+ {maybeDoubleNotPf},
+ {getProofLiteral()});
+
+ break;
+ }
+ case ArithProofType::IntTightenAP:
+ {
+ if (isUpperBound())
+ {
+ pf = pnm->mkNode(
+ PfRule::INT_TIGHT_UB, children, {}, getProofLiteral());
+ }
+ else if (isLowerBound())
+ {
+ pf = pnm->mkNode(
+ PfRule::INT_TIGHT_LB, children, {}, getProofLiteral());
+ }
+ else
+ {
+ Unreachable();
+ }
+ break;
+ }
+ case ArithProofType::IntHoleAP:
+ {
+ pf = pnm->mkNode(PfRule::INT_TRUST,
+ children,
+ {getProofLiteral()},
+ getProofLiteral());
+ break;
+ }
+ case ArithProofType::TrichotomyAP:
+ {
+ pf = pnm->mkNode(PfRule::ARITH_TRICHOTOMY,
+ children,
+ {getProofLiteral()},
+ getProofLiteral());
+ break;
+ }
+ case ArithProofType::InternalAssumeAP:
+ case ArithProofType::NoAP:
+ default:
+ {
+ Unreachable() << getProofType()
+ << " should not be visible in explanation";
+ break;
+ }
}
- return nb;
}
}
+ return pf;
}
Node Constraint::externalExplainByAssertions(ConstraintCP a, ConstraintCP b){
@@ -1695,13 +1971,16 @@ ConstraintP ConstraintDatabase::getBestImpliedBound(ArithVar v, ConstraintType t
}
}
}
-Node ConstraintDatabase::eeExplain(const Constraint* const c) const{
+TrustNode ConstraintDatabase::eeExplain(const Constraint* const c) const
+{
Assert(c->hasLiteral());
return d_congruenceManager.explain(c->getLiteral());
}
-void ConstraintDatabase::eeExplain(const Constraint* const c, NodeBuilder<>& nb) const{
+void ConstraintDatabase::eeExplain(ConstraintCP c, NodeBuilder<>& nb) const
+{
Assert(c->hasLiteral());
+ // NOTE: this is not a recommended method since it ignores proofs
d_congruenceManager.explain(c->getLiteral(), nb);
}
@@ -1719,6 +1998,8 @@ ConstraintDatabase::Watches::Watches(context::Context* satContext, context::Cont
void Constraint::setLiteral(Node n) {
+ Debug("arith::constraint") << "Mapping " << *this << " to " << n << std::endl;
+ Assert(Comparison::isNormalAtom(n));
Assert(!hasLiteral());
Assert(sanityChecking(n));
d_literal = n;
@@ -1727,30 +2008,135 @@ void Constraint::setLiteral(Node n) {
map.insert(make_pair(d_literal, this));
}
-void implies(std::vector<Node>& out, ConstraintP a, ConstraintP b){
+Node Constraint::getProofLiteral() const
+{
+ Assert(d_database != nullptr);
+ Assert(d_database->d_avariables.hasNode(d_variable));
+ Node varPart = d_database->d_avariables.asNode(d_variable);
+ Kind cmp;
+ bool neg = false;
+ switch (d_type)
+ {
+ case ConstraintType::UpperBound:
+ {
+ if (d_value.infinitesimalIsZero())
+ {
+ cmp = Kind::LEQ;
+ }
+ else
+ {
+ cmp = Kind::LT;
+ }
+ break;
+ }
+ case ConstraintType::LowerBound:
+ {
+ if (d_value.infinitesimalIsZero())
+ {
+ cmp = Kind::GEQ;
+ }
+ else
+ {
+ cmp = Kind::GT;
+ }
+ break;
+ }
+ case ConstraintType::Equality:
+ {
+ cmp = Kind::EQUAL;
+ break;
+ }
+ case ConstraintType::Disequality:
+ {
+ cmp = Kind::EQUAL;
+ neg = true;
+ break;
+ }
+ default: Unreachable() << d_type;
+ }
+ NodeManager* nm = NodeManager::currentNM();
+ Node constPart = nm->mkConst<Rational>(d_value.getNoninfinitesimalPart());
+ Node posLit = nm->mkNode(cmp, varPart, constPart);
+ return neg ? posLit.negate() : posLit;
+}
+
+void ConstraintDatabase::proveOr(std::vector<TrustNode>& out,
+ ConstraintP a,
+ ConstraintP b,
+ bool negateSecond) const
+{
+ Node la = a->getLiteral();
+ Node lb = b->getLiteral();
+ Node orN = (la < lb) ? la.orNode(lb) : lb.orNode(la);
+ if (options::proofNew())
+ {
+ Assert(b->getNegation()->getType() != ConstraintType::Disequality);
+ auto nm = NodeManager::currentNM();
+ auto pf_neg_la = d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM,
+ {d_pnm->mkAssume(la.negate())},
+ {a->getNegation()->getProofLiteral()});
+ auto pf_neg_lb = d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM,
+ {d_pnm->mkAssume(lb.negate())},
+ {b->getNegation()->getProofLiteral()});
+ int sndSign = negateSecond ? -1 : 1;
+ auto bot_pf =
+ d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM,
+ {d_pnm->mkNode(PfRule::ARITH_SCALE_SUM_UPPER_BOUNDS,
+ {pf_neg_la, pf_neg_lb},
+ {nm->mkConst<Rational>(-1 * sndSign),
+ nm->mkConst<Rational>(sndSign)})},
+ {nm->mkConst(false)});
+ std::vector<Node> as;
+ std::transform(orN.begin(), orN.end(), std::back_inserter(as), [](Node n) {
+ return n.negate();
+ });
+ // No need to ensure that the expected node aggrees with `as` because we
+ // are not providing an expected node.
+ auto pf = d_pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM,
+ {d_pnm->mkNode(PfRule::NOT_AND, {d_pnm->mkScope(bot_pf, as)}, {})},
+ {orN});
+ out.push_back(d_pfGen->mkTrustNode(orN, pf));
+ }
+ else
+ {
+ out.push_back(TrustNode::mkTrustLemma(orN));
+ }
+}
+
+void ConstraintDatabase::implies(std::vector<TrustNode>& out,
+ ConstraintP a,
+ ConstraintP b) const
+{
Node la = a->getLiteral();
Node lb = b->getLiteral();
Node neg_la = (la.getKind() == kind::NOT)? la[0] : la.notNode();
Assert(lb != neg_la);
- Node orderOr = (lb < neg_la) ? lb.orNode(neg_la) : neg_la.orNode(lb);
- out.push_back(orderOr);
+ Assert(b->getNegation()->getType() == ConstraintType::LowerBound
+ || b->getNegation()->getType() == ConstraintType::UpperBound);
+ proveOr(out,
+ a->getNegation(),
+ b,
+ b->getNegation()->getType() == ConstraintType::LowerBound);
}
-void mutuallyExclusive(std::vector<Node>& out, ConstraintP a, ConstraintP b){
+void ConstraintDatabase::mutuallyExclusive(std::vector<TrustNode>& out,
+ ConstraintP a,
+ ConstraintP b) const
+{
Node la = a->getLiteral();
Node lb = b->getLiteral();
- Node neg_la = (la.getKind() == kind::NOT)? la[0] : la.notNode();
- Node neg_lb = (lb.getKind() == kind::NOT)? lb[0] : lb.notNode();
-
- Assert(neg_la != neg_lb);
- Node orderOr = (neg_la < neg_lb) ? neg_la.orNode(neg_lb) : neg_lb.orNode(neg_la);
- out.push_back(orderOr);
+ Node neg_la = la.negate();
+ Node neg_lb = lb.negate();
+ proveOr(out, a->getNegation(), b->getNegation(), true);
}
-void ConstraintDatabase::outputUnateInequalityLemmas(std::vector<Node>& out, ArithVar v) const{
+void ConstraintDatabase::outputUnateInequalityLemmas(
+ std::vector<TrustNode>& out, ArithVar v) const
+{
SortedConstraintMap& scm = getVariableSCM(v);
SortedConstraintMapConstIterator scm_iter = scm.begin();
SortedConstraintMapConstIterator scm_end = scm.end();
@@ -1771,8 +2157,9 @@ void ConstraintDatabase::outputUnateInequalityLemmas(std::vector<Node>& out, Ari
}
}
-void ConstraintDatabase::outputUnateEqualityLemmas(std::vector<Node>& out, ArithVar v) const{
-
+void ConstraintDatabase::outputUnateEqualityLemmas(std::vector<TrustNode>& out,
+ ArithVar v) const
+{
vector<ConstraintP> equalities;
SortedConstraintMap& scm = getVariableSCM(v);
@@ -1824,13 +2211,17 @@ void ConstraintDatabase::outputUnateEqualityLemmas(std::vector<Node>& out, Arith
}
}
-void ConstraintDatabase::outputUnateEqualityLemmas(std::vector<Node>& lemmas) const{
+void ConstraintDatabase::outputUnateEqualityLemmas(
+ std::vector<TrustNode>& lemmas) const
+{
for(ArithVar v = 0, N = d_varDatabases.size(); v < N; ++v){
outputUnateEqualityLemmas(lemmas, v);
}
}
-void ConstraintDatabase::outputUnateInequalityLemmas(std::vector<Node>& lemmas) const{
+void ConstraintDatabase::outputUnateInequalityLemmas(
+ std::vector<TrustNode>& lemmas) const
+{
for(ArithVar v = 0, N = d_varDatabases.size(); v < N; ++v){
outputUnateInequalityLemmas(lemmas, v);
}
diff --git a/src/theory/arith/constraint.h b/src/theory/arith/constraint.h
index 873b33ced..952879182 100644
--- a/src/theory/arith/constraint.h
+++ b/src/theory/arith/constraint.h
@@ -2,10 +2,10 @@
/*! \file constraint.h
** \verbatim
** Top contributors (to current version):
- ** Tim King, Alex Ozdemir, Morgan Deters
+ ** Tim King, Alex Ozdemir, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -75,9 +75,9 @@
#ifndef CVC4__THEORY__ARITH__CONSTRAINT_H
#define CVC4__THEORY__ARITH__CONSTRAINT_H
-#include <unordered_map>
#include <list>
#include <set>
+#include <unordered_map>
#include <vector>
#include "base/configuration_private.h"
@@ -85,12 +85,14 @@
#include "context/cdqueue.h"
#include "context/context.h"
#include "expr/node.h"
-#include "proof/proof.h"
+#include "expr/proof_node_manager.h"
#include "theory/arith/arithvar.h"
#include "theory/arith/callbacks.h"
#include "theory/arith/congruence_manager.h"
#include "theory/arith/constraint_forward.h"
#include "theory/arith/delta_rational.h"
+#include "theory/arith/proof_macros.h"
+#include "theory/trust_node.h"
namespace CVC4 {
namespace theory {
@@ -252,11 +254,11 @@ struct PerVariableDatabase{
}
};
-
/**
* If proofs are on, there is a vector of rationals for farkas coefficients.
- * This is the owner of the memory for the vector, and calls delete upon cleanup.
- *
+ * This is the owner of the memory for the vector, and calls delete upon
+ * cleanup.
+ *
*/
struct ConstraintRule {
ConstraintP d_constraint;
@@ -302,17 +304,13 @@ struct ConstraintRule {
* We do however use all of the constraints by requiring non-zero
* coefficients.
*/
-#if IS_PROOFS_BUILD
RationalVectorCP d_farkasCoefficients;
-#endif /* IS_PROOFS_BUILD */
ConstraintRule()
: d_constraint(NullConstraint)
, d_proofType(NoAP)
, d_antecedentEnd(AntecedentIdSentinel)
{
-#if IS_PROOFS_BUILD
d_farkasCoefficients = RationalVectorCPSentinel;
-#endif /* IS_PROOFS_BUILD */
}
ConstraintRule(ConstraintP con, ArithProofType pt)
@@ -320,18 +318,14 @@ struct ConstraintRule {
, d_proofType(pt)
, d_antecedentEnd(AntecedentIdSentinel)
{
-#if IS_PROOFS_BUILD
d_farkasCoefficients = RationalVectorCPSentinel;
-#endif /* IS_PROOFS_BUILD */
}
ConstraintRule(ConstraintP con, ArithProofType pt, AntecedentId antecedentEnd)
: d_constraint(con)
, d_proofType(pt)
, d_antecedentEnd(antecedentEnd)
{
-#if IS_PROOFS_BUILD
d_farkasCoefficients = RationalVectorCPSentinel;
-#endif /* IS_PROOFS_BUILD */
}
ConstraintRule(ConstraintP con, ArithProofType pt, AntecedentId antecedentEnd, RationalVectorCP coeffs)
@@ -339,10 +333,8 @@ struct ConstraintRule {
, d_proofType(pt)
, d_antecedentEnd(antecedentEnd)
{
- Assert(PROOF_ON() || coeffs == RationalVectorCPSentinel);
-#if IS_PROOFS_BUILD
+ Assert(ARITH_PROOF_ON() || coeffs == RationalVectorCPSentinel);
d_farkasCoefficients = coeffs;
-#endif /* IS_PROOFS_BUILD */
}
void print(std::ostream& out) const;
@@ -419,7 +411,7 @@ class Constraint {
* Returns a lemma that is assumed to be true for the rest of the user context.
* Constraint must be an equality or disequality.
*/
- Node split();
+ TrustNode split();
bool canBePropagated() const {
return d_canBePropagated;
@@ -472,6 +464,14 @@ class Constraint {
return d_literal;
}
+ /** Gets a literal in the normal form suitable for proofs.
+ * That is, (sum of non-const monomials) >< const.
+ *
+ * This is a sister method to `getLiteral`, which returns a normal form
+ * literal, suitable for external solving use.
+ */
+ Node getProofLiteral() const;
+
/**
* Set the node as having a proof and being an assumption.
* The node must be assertedToTheTheory().
@@ -514,6 +514,11 @@ class Constraint {
*
*/
bool hasSimpleFarkasProof() const;
+ /**
+ * Returns whether this constraint is an assumption or a tightened
+ * assumption.
+ */
+ bool isPossiblyTightenedAssumption() const;
/** Returns true if the node has a int bound tightening proof. */
bool hasIntTightenProof() const;
@@ -548,9 +553,7 @@ class Constraint {
* This is the minimum fringe of the implication tree s.t.
* every constraint is assertedToTheTheory() or hasEqualityEngineProof().
*/
- Node externalExplainByAssertions() const {
- return externalExplain(AssertionOrderSentinel);
- }
+ TrustNode externalExplainByAssertions() const;
/**
* Writes an explanation of a constraint into the node builder.
@@ -563,8 +566,10 @@ class Constraint {
* This is not appropriate for propagation!
* Use explainForPropagation() instead.
*/
- void externalExplainByAssertions(NodeBuilder<>& nb) const{
- externalExplain(nb, AssertionOrderSentinel);
+ std::shared_ptr<ProofNode> externalExplainByAssertions(
+ NodeBuilder<>& nb) const
+ {
+ return externalExplain(nb, AssertionOrderSentinel);
}
/* Equivalent to calling externalExplainByAssertions on all constraints in b */
@@ -591,22 +596,19 @@ class Constraint {
* The constraint must have a proof.
* The constraint cannot be an assumption.
*
- * This is the minimum fringe of the implication tree (excluding the constraint itself)
- * s.t. every constraint is assertedToTheTheory() or hasEqualityEngineProof().
+ * This is the minimum fringe of the implication tree (excluding the
+ * constraint itself) s.t. every constraint is assertedToTheTheory() or
+ * hasEqualityEngineProof().
+ *
+ * All return conjuncts were asserted before this constraint.
*/
- Node externalExplainForPropagation() const {
- Assert(hasProof());
- Assert(!isAssumption());
- Assert(!isInternalAssumption());
- return externalExplain(d_assertionOrder);
- }
+ TrustNode externalExplainForPropagation() const;
/**
* Explain the constraint and its negation in terms of assertions.
* The constraint must be in conflict.
*/
- Node externalExplainConflict() const;
-
+ TrustNode externalExplainConflict() const;
/** The constraint is known to be true. */
inline bool hasProof() const {
@@ -745,7 +747,7 @@ class Constraint {
/**
* If the constraint
- * canBePropagated() and
+ * canBePropagated() and
* !assertedToTheTheory(),
* the constraint is added to the database's propagation queue.
*
@@ -784,9 +786,11 @@ class Constraint {
ConstraintP constraint = crp->d_constraint;
Assert(constraint->d_crid != ConstraintRuleIdSentinel);
constraint->d_crid = ConstraintRuleIdSentinel;
-
- PROOF(if (crp->d_farkasCoefficients != RationalVectorCPSentinel) {
- delete crp->d_farkasCoefficients;
+ ARITH_PROOF({
+ if (crp->d_farkasCoefficients != RationalVectorCPSentinel)
+ {
+ delete crp->d_farkasCoefficients;
+ }
});
}
};
@@ -850,7 +854,6 @@ class Constraint {
static std::pair<int, int> unateFarkasSigns(ConstraintCP a, ConstraintCP b);
Node externalExplain(AssertionOrder order) const;
-
/**
* Returns an explanation of that was assertedBefore(order).
* The constraint must have a proof.
@@ -859,7 +862,8 @@ class Constraint {
* This is the minimum fringe of the implication tree
* s.t. every constraint is assertedBefore(order) or hasEqualityEngineProof().
*/
- void externalExplain(NodeBuilder<>& nb, AssertionOrder order) const;
+ std::shared_ptr<ProofNode> externalExplain(NodeBuilder<>& nb,
+ AssertionOrder order) const;
static Node externalExplain(const ConstraintCPVec& b, AssertionOrder order);
@@ -871,10 +875,11 @@ class Constraint {
return getConstraintRule().d_antecedentEnd;
}
- inline RationalVectorCP getFarkasCoefficients() const {
- return NULLPROOF(getConstraintRule().d_farkasCoefficients);
+ inline RationalVectorCP getFarkasCoefficients() const
+ {
+ return ARITH_NULLPROOF(getConstraintRule().d_farkasCoefficients);
}
-
+
void debugPrint() const;
/**
@@ -1046,8 +1051,7 @@ private:
* The index in this list is the proper ordering of the proofs.
*/
ConstraintRuleList d_constraintProofs;
-
-
+
/**
* Contains the exact list of constraints that can be used for propagation.
*/
@@ -1089,22 +1093,27 @@ private:
ArithCongruenceManager& d_congruenceManager;
const context::Context * const d_satContext;
+ /** Owned by the TheoryArithPrivate, used here. */
+ EagerProofGenerator* d_pfGen;
+ /** Owned by the TheoryArithPrivate, used here. */
+ ProofNodeManager* d_pnm;
RaiseConflict d_raiseConflict;
const Rational d_one;
const Rational d_negOne;
-
+
friend class Constraint;
-
-public:
- ConstraintDatabase( context::Context* satContext,
- context::Context* userContext,
- const ArithVariables& variables,
- ArithCongruenceManager& dm,
- RaiseConflict conflictCallBack);
+ public:
+ ConstraintDatabase(context::Context* satContext,
+ context::Context* userContext,
+ const ArithVariables& variables,
+ ArithCongruenceManager& dm,
+ RaiseConflict conflictCallBack,
+ EagerProofGenerator* pfGen,
+ ProofNodeManager* pnm);
~ConstraintDatabase();
@@ -1141,7 +1150,10 @@ public:
bool variableDatabaseIsSetup(ArithVar v) const;
void removeVariable(ArithVar v);
- Node eeExplain(ConstraintCP c) const;
+ /** Get an explanation and proof for this constraint from the equality engine
+ */
+ TrustNode eeExplain(ConstraintCP c) const;
+ /** Get an explanation for this constraint from the equality engine */
void eeExplain(ConstraintCP c, NodeBuilder<>& nb) const;
/**
@@ -1179,14 +1191,39 @@ public:
void deleteConstraintAndNegation(ConstraintP c);
+ /** Given constraints `a` and `b` such that `a OR b` by unate reasoning,
+ * adds a TrustNode to `out` which proves `a OR b` as a lemma.
+ *
+ * Example: `x <= 5` OR `5 <= x`.
+ */
+ void proveOr(std::vector<TrustNode>& out,
+ ConstraintP a,
+ ConstraintP b,
+ bool negateSecond) const;
+ /** Given constraints `a` and `b` such that `a` implies `b` by unate
+ * reasoning, adds a TrustNode to `out` which proves `-a OR b` as a lemma.
+ *
+ * Example: `x >= 5` -> `x >= 4`.
+ */
+ void implies(std::vector<TrustNode>& out, ConstraintP a, ConstraintP b) const;
+ /** Given constraints `a` and `b` such that `not(a AND b)` by unate reasoning,
+ * adds a TrustNode to `out` which proves `-a OR -b` as a lemma.
+ *
+ * Example: `x >= 4` -> `x <= 3`.
+ */
+ void mutuallyExclusive(std::vector<TrustNode>& out,
+ ConstraintP a,
+ ConstraintP b) const;
+
/**
* Outputs a minimal set of unate implications onto the vector for the variable.
* This outputs lemmas of the general forms
* (= p c) implies (<= p d) for c < d, or
* (= p c) implies (not (= p d)) for c != d.
*/
- void outputUnateEqualityLemmas(std::vector<Node>& lemmas) const;
- void outputUnateEqualityLemmas(std::vector<Node>& lemmas, ArithVar v) const;
+ void outputUnateEqualityLemmas(std::vector<TrustNode>& lemmas) const;
+ void outputUnateEqualityLemmas(std::vector<TrustNode>& lemmas,
+ ArithVar v) const;
/**
* Outputs a minimal set of unate implications onto the vector for the variable.
@@ -1194,9 +1231,9 @@ public:
* If ineqs is true, this outputs lemmas of the general form
* (<= p c) implies (<= p d) for c < d.
*/
- void outputUnateInequalityLemmas(std::vector<Node>& lemmas) const;
- void outputUnateInequalityLemmas(std::vector<Node>& lemmas, ArithVar v) const;
-
+ void outputUnateInequalityLemmas(std::vector<TrustNode>& lemmas) const;
+ void outputUnateInequalityLemmas(std::vector<TrustNode>& lemmas,
+ ArithVar v) const;
void unatePropLowerBound(ConstraintP curr, ConstraintP prev);
void unatePropUpperBound(ConstraintP curr, ConstraintP prev);
@@ -1204,8 +1241,10 @@ public:
/** AntecendentID must be in range. */
ConstraintCP getAntecedent(AntecedentId p) const;
-
-private:
+
+ bool isProofEnabled() const { return d_pnm != nullptr; }
+
+ private:
/** returns true if cons is now in conflict. */
bool handleUnateProp(ConstraintP ant, ConstraintP cons);
diff --git a/src/theory/arith/constraint_forward.h b/src/theory/arith/constraint_forward.h
index 986104539..515c5cfc0 100644
--- a/src/theory/arith/constraint_forward.h
+++ b/src/theory/arith/constraint_forward.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/cut_log.cpp b/src/theory/arith/cut_log.cpp
index 7eb173f4f..73c589599 100644
--- a/src/theory/arith/cut_log.cpp
+++ b/src/theory/arith/cut_log.cpp
@@ -5,7 +5,7 @@
** Tim King, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/cut_log.h b/src/theory/arith/cut_log.h
index 691b4d7fd..12d8da991 100644
--- a/src/theory/arith/cut_log.h
+++ b/src/theory/arith/cut_log.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Kshitij Bansal
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/delta_rational.cpp b/src/theory/arith/delta_rational.cpp
index c983b5e76..f5a9a2a75 100644
--- a/src/theory/arith/delta_rational.cpp
+++ b/src/theory/arith/delta_rational.cpp
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/delta_rational.h b/src/theory/arith/delta_rational.h
index 1394bef8a..41a9bddd3 100644
--- a/src/theory/arith/delta_rational.h
+++ b/src/theory/arith/delta_rational.h
@@ -5,7 +5,7 @@
** Tim King, Dejan Jovanovic, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/dio_solver.cpp b/src/theory/arith/dio_solver.cpp
index 7b33d24f7..15d6b9f50 100644
--- a/src/theory/arith/dio_solver.cpp
+++ b/src/theory/arith/dio_solver.cpp
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/dio_solver.h b/src/theory/arith/dio_solver.h
index 1e5f4a97f..186816f1e 100644
--- a/src/theory/arith/dio_solver.h
+++ b/src/theory/arith/dio_solver.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/dual_simplex.cpp b/src/theory/arith/dual_simplex.cpp
index 643161758..3d6e92283 100644
--- a/src/theory/arith/dual_simplex.cpp
+++ b/src/theory/arith/dual_simplex.cpp
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/dual_simplex.h b/src/theory/arith/dual_simplex.h
index 5abce830b..f87b4e9c1 100644
--- a/src/theory/arith/dual_simplex.h
+++ b/src/theory/arith/dual_simplex.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/error_set.cpp b/src/theory/arith/error_set.cpp
index 236c09fde..8e98f2d8d 100644
--- a/src/theory/arith/error_set.cpp
+++ b/src/theory/arith/error_set.cpp
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/error_set.h b/src/theory/arith/error_set.h
index 795c86f3b..568be40d5 100644
--- a/src/theory/arith/error_set.h
+++ b/src/theory/arith/error_set.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/fc_simplex.cpp b/src/theory/arith/fc_simplex.cpp
index 2135944ab..7b482b314 100644
--- a/src/theory/arith/fc_simplex.cpp
+++ b/src/theory/arith/fc_simplex.cpp
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/fc_simplex.h b/src/theory/arith/fc_simplex.h
index 7451d5c48..1bd4416e0 100644
--- a/src/theory/arith/fc_simplex.h
+++ b/src/theory/arith/fc_simplex.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -52,8 +52,6 @@
#pragma once
-#include <stdint.h>
-
#include "theory/arith/simplex.h"
#include "util/dense_map.h"
#include "util/statistics_registry.h"
diff --git a/src/theory/arith/infer_bounds.cpp b/src/theory/arith/infer_bounds.cpp
index 1f7383a96..ec80ca0d4 100644
--- a/src/theory/arith/infer_bounds.cpp
+++ b/src/theory/arith/infer_bounds.cpp
@@ -2,10 +2,10 @@
/*! \file infer_bounds.cpp
** \verbatim
** Top contributors (to current version):
- ** Tim King
+ ** Tim King, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/infer_bounds.h b/src/theory/arith/infer_bounds.h
index 22e9f5154..bfed35252 100644
--- a/src/theory/arith/infer_bounds.h
+++ b/src/theory/arith/infer_bounds.h
@@ -2,10 +2,10 @@
/*! \file infer_bounds.h
** \verbatim
** Top contributors (to current version):
- ** Tim King
+ ** Tim King, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/inference_id.cpp b/src/theory/arith/inference_id.cpp
new file mode 100644
index 000000000..a93a980ba
--- /dev/null
+++ b/src/theory/arith/inference_id.cpp
@@ -0,0 +1,60 @@
+/********************* */
+/*! \file inference_id.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of inference enumeration.
+ **/
+
+#include "theory/arith/inference_id.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+const char* toString(InferenceId i)
+{
+ switch (i)
+ {
+ case InferenceId::NL_CONGRUENCE: return "CONGRUENCE";
+ case InferenceId::NL_SHARED_TERM_VALUE_SPLIT: return "SHARED_TERM_VALUE_SPLIT";
+ case InferenceId::NL_SPLIT_ZERO: return "SPLIT_ZERO";
+ case InferenceId::NL_SIGN: return "SIGN";
+ case InferenceId::NL_COMPARISON: return "COMPARISON";
+ case InferenceId::NL_INFER_BOUNDS: return "INFER_BOUNDS";
+ case InferenceId::NL_INFER_BOUNDS_NT: return "INFER_BOUNDS_NT";
+ case InferenceId::NL_FACTOR: return "FACTOR";
+ case InferenceId::NL_RES_INFER_BOUNDS: return "RES_INFER_BOUNDS";
+ case InferenceId::NL_TANGENT_PLANE: return "TANGENT_PLANE";
+ case InferenceId::NL_T_PURIFY_ARG: return "T_PURIFY_ARG";
+ case InferenceId::NL_T_INIT_REFINE: return "T_INIT_REFINE";
+ case InferenceId::NL_T_PI_BOUND: return "T_PI_BOUND";
+ case InferenceId::NL_T_MONOTONICITY: return "T_MONOTONICITY";
+ case InferenceId::NL_T_SECANT: return "T_SECANT";
+ case InferenceId::NL_T_TANGENT: return "T_TANGENT";
+ case InferenceId::NL_IAND_INIT_REFINE: return "IAND_INIT_REFINE";
+ case InferenceId::NL_IAND_VALUE_REFINE: return "IAND_VALUE_REFINE";
+ case InferenceId::NL_IAND_SUM_REFINE: return "IAND_SUM_REFINE";
+ case InferenceId::NL_CAD_CONFLICT: return "CAD_CONFLICT";
+ case InferenceId::NL_CAD_EXCLUDED_INTERVAL: return "CAD_EXCLUDED_INTERVAL";
+ case InferenceId::NL_ICP_CONFLICT: return "ICP_CONFLICT";
+ case InferenceId::NL_ICP_PROPAGATION: return "ICP_PROPAGATION";
+ default: return "?";
+ }
+}
+
+std::ostream& operator<<(std::ostream& out, InferenceId i)
+{
+ out << toString(i);
+ return out;
+}
+
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/nl/inference.h b/src/theory/arith/inference_id.h
index 99b7e681e..c01cd2c8e 100644
--- a/src/theory/arith/nl/inference.h
+++ b/src/theory/arith/inference_id.h
@@ -1,21 +1,21 @@
/********************* */
-/*! \file inference.h
+/*! \file inference_id.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds
+ ** Andrew Reynolds, Gereon Kremer
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
- ** \brief Inference enumeration for non-linear arithmetic.
+ ** \brief Inference enumeration for arithmetic.
**/
#include "cvc4_private.h"
-#ifndef CVC4__THEORY__ARITH__NL__INFER_INFO_H
-#define CVC4__THEORY__ARITH__NL__INFER_INFO_H
+#ifndef CVC4__THEORY__ARITH__INFERENCE_ID_H
+#define CVC4__THEORY__ARITH__INFERENCE_ID_H
#include <map>
#include <vector>
@@ -25,48 +25,64 @@
namespace CVC4 {
namespace theory {
namespace arith {
-namespace nl {
/**
* Types of inferences used in the procedure
*/
-enum class Inference : uint32_t
+enum class InferenceId : uint32_t
{
//-------------------- core
// simple congruence x=y => f(x)=f(y)
- CONGRUENCE,
+ NL_CONGRUENCE,
// shared term value split (for naive theory combination)
- SHARED_TERM_VALUE_SPLIT,
+ NL_SHARED_TERM_VALUE_SPLIT,
//-------------------- incremental linearization solver
// splitting on zero (NlSolver::checkSplitZero)
- SPLIT_ZERO,
+ NL_SPLIT_ZERO,
// based on sign (NlSolver::checkMonomialSign)
- SIGN,
+ NL_SIGN,
// based on comparing (abs) model values (NlSolver::checkMonomialMagnitude)
- COMPARISON,
+ NL_COMPARISON,
// based on inferring bounds (NlSolver::checkMonomialInferBounds)
- INFER_BOUNDS,
+ NL_INFER_BOUNDS,
// same as above, for inferences that introduce new terms
- INFER_BOUNDS_NT,
+ NL_INFER_BOUNDS_NT,
// factoring (NlSolver::checkFactoring)
- FACTOR,
+ NL_FACTOR,
// resolution bound inferences (NlSolver::checkMonomialInferResBounds)
- RES_INFER_BOUNDS,
+ NL_RES_INFER_BOUNDS,
// tangent planes (NlSolver::checkTangentPlanes)
- TANGENT_PLANE,
+ NL_TANGENT_PLANE,
//-------------------- transcendental solver
// purification of arguments to transcendental functions
- T_PURIFY_ARG,
+ NL_T_PURIFY_ARG,
// initial refinement (TranscendentalSolver::checkTranscendentalInitialRefine)
- T_INIT_REFINE,
+ NL_T_INIT_REFINE,
// pi bounds
- T_PI_BOUND,
+ NL_T_PI_BOUND,
// monotonicity (TranscendentalSolver::checkTranscendentalMonotonic)
- T_MONOTONICITY,
+ NL_T_MONOTONICITY,
// tangent refinement (TranscendentalSolver::checkTranscendentalTangentPlanes)
- T_TANGENT,
+ NL_T_TANGENT,
// secant refinement, the dual of the above inference
- T_SECANT,
+ NL_T_SECANT,
+ //-------------------- iand solver
+ // initial refinements (IAndSolver::checkInitialRefine)
+ NL_IAND_INIT_REFINE,
+ // value refinements (IAndSolver::checkFullRefine)
+ NL_IAND_VALUE_REFINE,
+ // sum refinements (IAndSulver::checkFullRefine)
+ NL_IAND_SUM_REFINE,
+ //-------------------- cad solver
+ // conflict / infeasible subset obtained from cad
+ NL_CAD_CONFLICT,
+ // excludes an interval for a single variable
+ NL_CAD_EXCLUDED_INTERVAL,
+ //-------------------- icp solver
+ // conflict obtained from icp
+ NL_ICP_CONFLICT,
+ // propagation / contraction of variable bounds from icp
+ NL_ICP_PROPAGATION,
//-------------------- unknown
UNKNOWN,
};
@@ -80,7 +96,7 @@ enum class Inference : uint32_t
* @param i The inference
* @return The name of the inference
*/
-const char* toString(Inference i);
+const char* toString(InferenceId i);
/**
* Writes an inference name to a stream.
@@ -89,11 +105,10 @@ const char* toString(Inference i);
* @param i The inference to write to the stream
* @return The stream
*/
-std::ostream& operator<<(std::ostream& out, Inference i);
+std::ostream& operator<<(std::ostream& out, InferenceId i);
-} // namespace nl
} // namespace arith
} // namespace theory
} // namespace CVC4
-#endif /* CVC4__THEORY__ARITH__NL__INFER_INFO_H */
+#endif /* CVC4__THEORY__ARITH__INFERENCE_H */
diff --git a/src/theory/arith/inference_manager.cpp b/src/theory/arith/inference_manager.cpp
new file mode 100644
index 000000000..08d223137
--- /dev/null
+++ b/src/theory/arith/inference_manager.cpp
@@ -0,0 +1,159 @@
+/********************* */
+/*! \file inference_manager.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer, Mathias Preiner
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of the inference manager for the theory of strings.
+ **/
+
+#include "theory/arith/inference_manager.h"
+
+#include "options/arith_options.h"
+#include "theory/arith/theory_arith.h"
+#include "theory/rewriter.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+InferenceManager::InferenceManager(TheoryArith& ta,
+ ArithState& astate,
+ ProofNodeManager* pnm)
+ : InferenceManagerBuffered(ta, astate, pnm), d_lemmasPp(ta.getUserContext())
+{
+}
+
+void InferenceManager::addPendingArithLemma(std::unique_ptr<ArithLemma> lemma,
+ bool isWaiting)
+{
+ Trace("arith::infman") << "Add " << lemma->d_inference << " " << lemma->d_node
+ << (isWaiting ? " as waiting" : "") << std::endl;
+ lemma->d_node = Rewriter::rewrite(lemma->d_node);
+ if (hasCachedLemma(lemma->d_node, lemma->d_property))
+ {
+ return;
+ }
+ if (isEntailedFalse(*lemma))
+ {
+ if (isWaiting)
+ {
+ d_waitingLem.clear();
+ }
+ else
+ {
+ d_pendingLem.clear();
+ d_theoryState.notifyInConflict();
+ }
+ }
+ if (isWaiting)
+ {
+ d_waitingLem.emplace_back(std::move(lemma));
+ }
+ else
+ {
+ d_pendingLem.emplace_back(std::move(lemma));
+ }
+}
+void InferenceManager::addPendingArithLemma(const ArithLemma& lemma,
+ bool isWaiting)
+{
+ addPendingArithLemma(std::unique_ptr<ArithLemma>(new ArithLemma(lemma)),
+ isWaiting);
+}
+void InferenceManager::addPendingArithLemma(const Node& lemma,
+ InferenceId inftype,
+ ProofGenerator* pg,
+ bool isWaiting)
+{
+ addPendingArithLemma(std::unique_ptr<ArithLemma>(new ArithLemma(
+ lemma, LemmaProperty::NONE, pg, inftype)),
+ isWaiting);
+}
+
+void InferenceManager::flushWaitingLemmas()
+{
+ for (auto& lem : d_waitingLem)
+ {
+ Trace("arith::infman") << "Flush waiting lemma to pending: "
+ << lem->d_inference << " " << lem->d_node
+ << std::endl;
+ d_pendingLem.emplace_back(std::move(lem));
+ }
+ d_waitingLem.clear();
+}
+void InferenceManager::clearWaitingLemmas()
+{
+ d_waitingLem.clear();
+}
+
+bool InferenceManager::hasUsed() const
+{
+ return hasSent() || hasPending();
+}
+
+bool InferenceManager::hasWaitingLemma() const
+{
+ return !d_waitingLem.empty();
+}
+
+std::size_t InferenceManager::numWaitingLemmas() const
+{
+ return d_waitingLem.size();
+}
+
+bool InferenceManager::hasCachedLemma(TNode lem, LemmaProperty p)
+{
+ if (isLemmaPropertyPreprocess(p))
+ {
+ return d_lemmasPp.find(lem) != d_lemmasPp.end();
+ }
+ return TheoryInferenceManager::hasCachedLemma(lem, p);
+}
+
+bool InferenceManager::cacheLemma(TNode lem, LemmaProperty p)
+{
+ if (isLemmaPropertyPreprocess(p))
+ {
+ if (d_lemmasPp.find(lem) != d_lemmasPp.end())
+ {
+ return false;
+ }
+ d_lemmasPp.insert(lem);
+ return true;
+ }
+ return TheoryInferenceManager::cacheLemma(lem, p);
+}
+
+bool InferenceManager::isEntailedFalse(const ArithLemma& lem)
+{
+ if (options::nlExtEntailConflicts())
+ {
+ Node ch_lemma = lem.d_node.negate();
+ ch_lemma = Rewriter::rewrite(ch_lemma);
+ Trace("arith-inf-manager") << "InferenceManager::Check entailment of "
+ << ch_lemma << "..." << std::endl;
+
+ std::pair<bool, Node> et = d_theory.getValuation().entailmentCheck(
+ options::TheoryOfMode::THEORY_OF_TYPE_BASED, ch_lemma);
+ Trace("arith-inf-manager") << "entailment test result : " << et.first << " "
+ << et.second << std::endl;
+ if (et.first)
+ {
+ Trace("arith-inf-manager")
+ << "*** Lemma entailed to be in conflict : " << lem.d_node
+ << std::endl;
+ return true;
+ }
+ }
+ return false;
+}
+
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/inference_manager.h b/src/theory/arith/inference_manager.h
new file mode 100644
index 000000000..66710cd7b
--- /dev/null
+++ b/src/theory/arith/inference_manager.h
@@ -0,0 +1,128 @@
+/********************* */
+/*! \file inference_manager.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Customized inference manager for the theory of nonlinear arithmetic
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__ARITH__INFERENCE_MANAGER_H
+#define CVC4__THEORY__ARITH__INFERENCE_MANAGER_H
+
+#include <map>
+#include <vector>
+
+#include "theory/arith/arith_lemma.h"
+#include "theory/arith/arith_state.h"
+#include "theory/arith/inference_id.h"
+#include "theory/arith/nl/nl_lemma_utils.h"
+#include "theory/inference_manager_buffered.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+class TheoryArith;
+
+/**
+ * A specialized variant of the InferenceManagerBuffered, tailored to the
+ * arithmetic theory.
+ *
+ * It adds some convenience methods to send ArithLemma and adds a mechanism for
+ * waiting lemmas that can be flushed into the pending lemmas of this
+ * buffered inference manager.
+ * It also extends the caching mechanism of TheoryInferenceManager to cache
+ * preprocessing lemmas and non-preprocessing lemmas separately. For the former,
+ * it uses the cache provided by the TheoryInferenceManager base class.
+ */
+class InferenceManager : public InferenceManagerBuffered
+{
+ using NodeSet = context::CDHashSet<Node, NodeHashFunction>;
+
+ public:
+ InferenceManager(TheoryArith& ta, ArithState& astate, ProofNodeManager* pnm);
+
+ /**
+ * Add a lemma as pending lemma to this inference manager.
+ * If isWaiting is true, the lemma is first stored as waiting lemma and only
+ * added as pending lemma when calling flushWaitingLemmas.
+ */
+ void addPendingArithLemma(std::unique_ptr<ArithLemma> lemma,
+ bool isWaiting = false);
+ /**
+ * Add a lemma as pending lemma to this inference manager.
+ * If isWaiting is true, the lemma is first stored as waiting lemma and only
+ * added as pending lemma when calling flushWaitingLemmas.
+ */
+ void addPendingArithLemma(const ArithLemma& lemma, bool isWaiting = false);
+ /**
+ * Add a lemma as pending lemma to this inference manager.
+ * If isWaiting is true, the lemma is first stored as waiting lemma and only
+ * added as pending lemma when calling flushWaitingLemmas.
+ */
+ void addPendingArithLemma(const Node& lemma,
+ InferenceId inftype,
+ ProofGenerator* pg = nullptr,
+ bool isWaiting = false);
+
+ /**
+ * Flush all waiting lemmas to this inference manager (as pending
+ * lemmas). To actually send them, call doPendingLemmas() afterwards.
+ */
+ void flushWaitingLemmas();
+
+ /**
+ * Removes all waiting lemmas without sending them anywhere.
+ */
+ void clearWaitingLemmas();
+
+ /**
+ * Checks whether we have made any progress, that is whether a conflict,
+ * lemma or fact was added or whether a lemma or fact is pending.
+ */
+ bool hasUsed() const;
+
+ /** Checks whether we have waiting lemmas. */
+ bool hasWaitingLemma() const;
+
+ /** Returns the number of pending lemmas. */
+ std::size_t numWaitingLemmas() const;
+
+ /** Checks whether the given lemma is already present in the cache. */
+ virtual bool hasCachedLemma(TNode lem, LemmaProperty p) override;
+
+ protected:
+ /**
+ * Adds the given lemma to the cache. Returns true if it has not been in the
+ * cache yet.
+ */
+ virtual bool cacheLemma(TNode lem, LemmaProperty p) override;
+
+ private:
+ /**
+ * Checks whether the lemma is entailed to be false. In this case, it is a
+ * conflict.
+ */
+ bool isEntailedFalse(const ArithLemma& lem);
+
+ /** The waiting lemmas. */
+ std::vector<std::unique_ptr<ArithLemma>> d_waitingLem;
+
+ /** cache of all preprocessed lemmas sent on the output channel
+ * (user-context-dependent) */
+ NodeSet d_lemmasPp;
+};
+
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/kinds b/src/theory/arith/kinds
index e563d8f66..fc8f76ee4 100644
--- a/src/theory/arith/kinds
+++ b/src/theory/arith/kinds
@@ -80,9 +80,16 @@ 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 predicate (parameter is a real-sorted term)"
-operator TO_INTEGER 1 "convert term to integer by the floor function (parameter is a real-sorted term)"
-operator TO_REAL 1 "cast term to real (parameter is an integer-sorted term; this is a no-op in CVC4, as integer is a subtype of real)"
+operator IS_INTEGER 1 "term-is-integer predicate (parameter is a real-sorted term)"
+operator TO_INTEGER 1 "convert term to integer by the floor function (parameter is a real-sorted term)"
+operator TO_REAL 1 "cast term to real (parameter is an integer-sorted term; this is a no-op in CVC4, as integer is a subtype of real)"
+
+# CAST_TO_REAL is added to distinguish between integers casted to reals internally, and
+# integers casted to reals or using the API \
+# Solver::mkReal(int val) would return an internal node (CAST_TO_REAL val), but in the api it appears as term (val) \
+# Solver::mkTerm(TO_REAL, Solver::mkInteger(int val)) would return both term and node (TO_REAL val) \
+# This way, we avoid having 2 nested TO_REAL nodess as a result of Solver::mkTerm(TO_REAL, Solver::mkReal(int val))
+operator CAST_TO_REAL 1 "cast term to real same as TO_REAL, but it is used internally, whereas TO_REAL is accessible in the API"
typerule PLUS ::CVC4::theory::arith::ArithOperatorTypeRule
typerule MULT ::CVC4::theory::arith::ArithOperatorTypeRule
@@ -99,9 +106,10 @@ typerule LEQ "SimpleTypeRule<RBool, AReal, AReal>"
typerule GT "SimpleTypeRule<RBool, AReal, AReal>"
typerule GEQ "SimpleTypeRule<RBool, AReal, AReal>"
-typerule TO_REAL ::CVC4::theory::arith::ArithOperatorTypeRule
-typerule TO_INTEGER ::CVC4::theory::arith::ArithOperatorTypeRule
-typerule IS_INTEGER "SimpleTypeRule<RBool, AReal>"
+typerule TO_REAL ::CVC4::theory::arith::ArithOperatorTypeRule
+typerule CAST_TO_REAL ::CVC4::theory::arith::ArithOperatorTypeRule
+typerule TO_INTEGER ::CVC4::theory::arith::ArithOperatorTypeRule
+typerule IS_INTEGER "SimpleTypeRule<RBool, AReal>"
typerule ABS "SimpleTypeRule<RInteger, AInteger>"
typerule INTS_DIVISION "SimpleTypeRule<RInteger, AInteger, AInteger>"
diff --git a/src/theory/arith/linear_equality.cpp b/src/theory/arith/linear_equality.cpp
index 7eb2f3f9e..32d2714e8 100644
--- a/src/theory/arith/linear_equality.cpp
+++ b/src/theory/arith/linear_equality.cpp
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -510,11 +510,11 @@ void LinearEqualityModule::propagateBasicFromRow(ConstraintP c){
RowIndex ridx = d_tableau.basicToRowIndex(basic);
ConstraintCPVec bounds;
- RationalVectorP coeffs = NULLPROOF(new RationalVector());
+ RationalVectorP coeffs = ARITH_NULLPROOF(new RationalVector());
propagateRow(bounds, ridx, upperBound, c, coeffs);
c->impliedByFarkas(bounds, coeffs, false);
c->tryToPropagate();
-
+
if(coeffs != RationalVectorPSentinel) { delete coeffs; }
}
@@ -524,9 +524,9 @@ void LinearEqualityModule::propagateBasicFromRow(ConstraintP c){
* The proof is in terms of the other constraints and the negation of c, ~c.
*
* A row has the form:
- * sum a_i * x_i = 0
+ * sum a_i * x_i = 0
* or
- * sx + sum r y + sum q z = 0
+ * sx + sum r y + sum q z = 0
* where r > 0 and q < 0.
*
* If rowUp, we are proving c
@@ -555,7 +555,7 @@ void LinearEqualityModule::propagateRow(ConstraintCPVec& into, RowIndex ridx, bo
Assert(farkas->empty());
farkas->push_back(Rational(0));
}
-
+
ArithVar v = c->getVariable();
Debug("arith::propagateRow") << "LinearEqualityModule::propagateRow("
<< ridx << ", " << rowUp << ", " << v << ") start" << endl;
@@ -563,7 +563,7 @@ void LinearEqualityModule::propagateRow(ConstraintCPVec& into, RowIndex ridx, bo
const Rational& multiple = rowUp ? d_one : d_negOne;
Debug("arith::propagateRow") << "multiple: " << multiple << endl;
-
+
Tableau::RowIterator iter = d_tableau.ridRowIterator(ridx);
for(; !iter.atEnd(); ++iter){
const Tableau::Entry& entry = *iter;
@@ -595,8 +595,8 @@ void LinearEqualityModule::propagateRow(ConstraintCPVec& into, RowIndex ridx, bo
if(farkas != RationalVectorPSentinel){
Assert(farkas->front().isZero());
Rational multAij = multiple * a_ij;
- Debug("arith::propagateRow") << "("<<multAij<<") ";
- farkas->front() = multAij;
+ Debug("arith::propagateRow") << "(" << multAij << ") ";
+ farkas->front() = multAij;
}
Debug("arith::propagateRow") << c << endl;
@@ -605,10 +605,10 @@ void LinearEqualityModule::propagateRow(ConstraintCPVec& into, RowIndex ridx, bo
ConstraintCP bound = selectUb
? d_variables.getUpperBoundConstraint(nonbasic)
: d_variables.getLowerBoundConstraint(nonbasic);
-
+
if(farkas != RationalVectorPSentinel){
Rational multAij = multiple * a_ij;
- Debug("arith::propagateRow") << "("<<multAij<<") ";
+ Debug("arith::propagateRow") << "(" << multAij << ") ";
farkas->push_back(multAij);
}
Assert(bound != NullConstraint);
@@ -678,7 +678,7 @@ ConstraintP LinearEqualityModule::weakestExplanation(bool aboveUpper, DeltaRatio
* If !aboveUpper, then the conflict is with the constraint c : x_b >= l_b.
*
* A row has the form:
- * -x_b sum a_i * x_i = 0
+ * -x_b sum a_i * x_i = 0
* or
* -x_b + sum r y + sum q z = 0,
* x_b = sum r y + sum q z
@@ -724,7 +724,7 @@ ConstraintCP LinearEqualityModule::minimallyWeakConflict(bool aboveUpper, ArithV
Assert(assignment < d_variables.getLowerBound(basicVar));
surplus = d_variables.getLowerBound(basicVar) - assignment;
}
-
+
bool anyWeakenings = false;
for(Tableau::RowIterator i = d_tableau.basicRowIterator(basicVar); !i.atEnd(); ++i){
const Tableau::Entry& entry = *i;
diff --git a/src/theory/arith/linear_equality.h b/src/theory/arith/linear_equality.h
index f19b3d6ef..beac70f64 100644
--- a/src/theory/arith/linear_equality.h
+++ b/src/theory/arith/linear_equality.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/matrix.cpp b/src/theory/arith/matrix.cpp
index 14593f550..7b6d478fa 100644
--- a/src/theory/arith/matrix.cpp
+++ b/src/theory/arith/matrix.cpp
@@ -5,7 +5,7 @@
** Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/matrix.h b/src/theory/arith/matrix.h
index 22a669f9b..ab9122755 100644
--- a/src/theory/arith/matrix.h
+++ b/src/theory/arith/matrix.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/nl/cad/cdcac.cpp b/src/theory/arith/nl/cad/cdcac.cpp
new file mode 100644
index 000000000..57a8b51df
--- /dev/null
+++ b/src/theory/arith/nl/cad/cdcac.cpp
@@ -0,0 +1,495 @@
+/********************* */
+/*! \file cdcac.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implements the CDCAC approach.
+ **
+ ** Implements the CDCAC approach as described in
+ ** https://arxiv.org/pdf/2003.05633.pdf.
+ **/
+
+#include "theory/arith/nl/cad/cdcac.h"
+
+#ifdef CVC4_POLY_IMP
+
+#include "options/arith_options.h"
+#include "theory/arith/nl/cad/projections.h"
+#include "theory/arith/nl/cad/variable_ordering.h"
+
+namespace std {
+/** Generic streaming operator for std::vector. */
+template <typename T>
+std::ostream& operator<<(std::ostream& os, const std::vector<T>& v)
+{
+ CVC4::container_to_stream(os, v);
+ return os;
+}
+} // namespace std
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace cad {
+
+namespace {
+/** Removed duplicates from a vector. */
+template <typename T>
+void removeDuplicates(std::vector<T>& v)
+{
+ std::sort(v.begin(), v.end());
+ v.erase(std::unique(v.begin(), v.end()), v.end());
+}
+} // namespace
+
+CDCAC::CDCAC() {}
+
+CDCAC::CDCAC(const std::vector<poly::Variable>& ordering)
+ : d_variableOrdering(ordering)
+{
+}
+
+void CDCAC::reset()
+{
+ d_constraints.reset();
+ d_assignment.clear();
+}
+
+void CDCAC::computeVariableOrdering()
+{
+ // Actually compute the variable ordering
+ d_variableOrdering = d_varOrder(d_constraints.getConstraints(),
+ VariableOrderingStrategy::BROWN);
+ Trace("cdcac") << "Variable ordering is now " << d_variableOrdering
+ << std::endl;
+
+ // Write variable ordering back to libpoly.
+ lp_variable_order_t* vo = poly::Context::get_context().get_variable_order();
+ lp_variable_order_clear(vo);
+ for (const auto& v : d_variableOrdering)
+ {
+ lp_variable_order_push(vo, v.get_internal());
+ }
+}
+
+void CDCAC::retrieveInitialAssignment(NlModel& model, const Node& ran_variable)
+{
+ if (!options::nlCadUseInitial()) return;
+ d_initialAssignment.clear();
+ Trace("cdcac") << "Retrieving initial assignment:" << std::endl;
+ for (const auto& var : d_variableOrdering)
+ {
+ Node v = getConstraints().varMapper()(var);
+ Node val = model.computeConcreteModelValue(v);
+ poly::Value value = node_to_value(val, ran_variable);
+ Trace("cdcac") << "\t" << var << " = " << value << std::endl;
+ d_initialAssignment.emplace_back(value);
+ }
+}
+Constraints& CDCAC::getConstraints() { return d_constraints; }
+const Constraints& CDCAC::getConstraints() const { return d_constraints; }
+
+const poly::Assignment& CDCAC::getModel() const { return d_assignment; }
+
+const std::vector<poly::Variable>& CDCAC::getVariableOrdering() const
+{
+ return d_variableOrdering;
+}
+
+std::vector<CACInterval> CDCAC::getUnsatIntervals(
+ std::size_t cur_variable) const
+{
+ std::vector<CACInterval> res;
+ for (const auto& c : d_constraints.getConstraints())
+ {
+ const poly::Polynomial& p = std::get<0>(c);
+ poly::SignCondition sc = std::get<1>(c);
+ const Node& n = std::get<2>(c);
+
+ if (main_variable(p) != d_variableOrdering[cur_variable])
+ {
+ // Constraint is in another variable, ignore it.
+ continue;
+ }
+
+ Trace("cdcac") << "Infeasible intervals for " << p << " " << sc
+ << " 0 over " << d_assignment << std::endl;
+ auto intervals = infeasible_regions(p, d_assignment, sc);
+ for (const auto& i : intervals)
+ {
+ Trace("cdcac") << "-> " << i << std::endl;
+ std::vector<poly::Polynomial> l, u, m, d;
+ if (!is_minus_infinity(get_lower(i))) l.emplace_back(p);
+ if (!is_plus_infinity(get_upper(i))) u.emplace_back(p);
+ m.emplace_back(p);
+ res.emplace_back(CACInterval{i, l, u, m, d, {n}});
+ }
+ }
+ cleanIntervals(res);
+ return res;
+}
+
+bool CDCAC::sampleOutsideWithInitial(const std::vector<CACInterval>& infeasible,
+ poly::Value& sample,
+ std::size_t cur_variable)
+{
+ if (options::nlCadUseInitial() && cur_variable < d_initialAssignment.size())
+ {
+ const poly::Value& suggested = d_initialAssignment[cur_variable];
+ for (const auto& i : infeasible)
+ {
+ if (poly::contains(i.d_interval, suggested))
+ {
+ d_initialAssignment.clear();
+ return sampleOutside(infeasible, sample);
+ }
+ }
+ Trace("cdcac") << "Using suggested initial value" << std::endl;
+ sample = suggested;
+ return true;
+ }
+ return sampleOutside(infeasible, sample);
+}
+
+std::vector<poly::Polynomial> CDCAC::requiredCoefficients(
+ const poly::Polynomial& p) const
+{
+ std::vector<poly::Polynomial> res;
+ for (long deg = degree(p); deg >= 0; --deg)
+ {
+ auto coeff = coefficient(p, deg);
+ if (lp_polynomial_is_constant(coeff.get_internal())) break;
+ res.emplace_back(coeff);
+ if (evaluate_constraint(coeff, d_assignment, poly::SignCondition::NE))
+ {
+ break;
+ }
+ }
+ return res;
+}
+
+std::vector<poly::Polynomial> CDCAC::constructCharacterization(
+ std::vector<CACInterval>& intervals)
+{
+ Assert(!intervals.empty()) << "A covering can not be empty";
+ Trace("cdcac") << "Constructing characterization now" << std::endl;
+ std::vector<poly::Polynomial> res;
+
+
+ for (std::size_t i = 0, n = intervals.size(); i < n - 1; ++i)
+ {
+ cad::makeFinestSquareFreeBasis(intervals[i], intervals[i + 1]);
+ }
+
+ for (const auto& i : intervals)
+ {
+ Trace("cdcac") << "Considering " << i.d_interval << std::endl;
+ Trace("cdcac") << "-> " << i.d_lowerPolys << " / " << i.d_upperPolys
+ << " and " << i.d_mainPolys << " / " << i.d_downPolys
+ << std::endl;
+ Trace("cdcac") << "-> " << i.d_origins << std::endl;
+ for (const auto& p : i.d_downPolys)
+ {
+ // Add all polynomial from lower levels.
+ addPolynomial(res, p);
+ }
+ for (const auto& p : i.d_mainPolys)
+ {
+ Trace("cdcac") << "Discriminant of " << p << " -> " << discriminant(p)
+ << std::endl;
+ // Add all discriminants
+ addPolynomial(res, discriminant(p));
+
+ for (const auto& q : requiredCoefficients(p))
+ {
+ // Add all required coefficients
+ Trace("cdcac") << "Coeff of " << p << " -> " << q << std::endl;
+ addPolynomial(res, q);
+ }
+ for (const auto& q : i.d_lowerPolys)
+ {
+ if (p == q) continue;
+ // Check whether p(s \times a) = 0 for some a <= l
+ if (!hasRootBelow(q, get_lower(i.d_interval))) continue;
+ Trace("cdcac") << "Resultant of " << p << " and " << q << " -> "
+ << resultant(p, q) << std::endl;
+ addPolynomial(res, resultant(p, q));
+ }
+ for (const auto& q : i.d_upperPolys)
+ {
+ if (p == q) continue;
+ // Check whether p(s \times a) = 0 for some a >= u
+ if (!hasRootAbove(q, get_upper(i.d_interval))) continue;
+ Trace("cdcac") << "Resultant of " << p << " and " << q << " -> "
+ << resultant(p, q) << std::endl;
+ addPolynomial(res, resultant(p, q));
+ }
+ }
+ }
+
+ for (std::size_t i = 0, n = intervals.size(); i < n - 1; ++i)
+ {
+ // Add resultants of consecutive intervals.
+ for (const auto& p : intervals[i].d_upperPolys)
+ {
+ for (const auto& q : intervals[i + 1].d_lowerPolys)
+ {
+ Trace("cdcac") << "Resultant of " << p << " and " << q << " -> "
+ << resultant(p, q) << std::endl;
+ addPolynomial(res, resultant(p, q));
+ }
+ }
+ }
+
+ removeDuplicates(res);
+ makeFinestSquareFreeBasis(res);
+
+ return res;
+}
+
+CACInterval CDCAC::intervalFromCharacterization(
+ const std::vector<poly::Polynomial>& characterization,
+ std::size_t cur_variable,
+ const poly::Value& sample)
+{
+ std::vector<poly::Polynomial> l;
+ std::vector<poly::Polynomial> u;
+ std::vector<poly::Polynomial> m;
+ std::vector<poly::Polynomial> d;
+
+ for (const auto& p : characterization)
+ {
+ // Add polynomials to either main or down
+ if (main_variable(p) == d_variableOrdering[cur_variable])
+ {
+ m.emplace_back(p);
+ }
+ else
+ {
+ d.emplace_back(p);
+ }
+ }
+
+ // Collect -oo, all roots, oo
+ std::vector<poly::Value> roots;
+ roots.emplace_back(poly::Value::minus_infty());
+ for (const auto& p : m)
+ {
+ auto tmp = isolate_real_roots(p, d_assignment);
+ roots.insert(roots.end(), tmp.begin(), tmp.end());
+ }
+ roots.emplace_back(poly::Value::plus_infty());
+ std::sort(roots.begin(), roots.end());
+
+ // Now find the interval bounds
+ poly::Value lower;
+ poly::Value upper;
+ for (std::size_t i = 0, n = roots.size(); i < n; ++i)
+ {
+ if (sample < roots[i])
+ {
+ lower = roots[i - 1];
+ upper = roots[i];
+ break;
+ }
+ if (roots[i] == sample)
+ {
+ lower = sample;
+ upper = sample;
+ break;
+ }
+ }
+ Assert(!is_none(lower) && !is_none(upper));
+
+ if (!is_minus_infinity(lower))
+ {
+ // Identify polynomials that have a root at the lower bound
+ d_assignment.set(d_variableOrdering[cur_variable], lower);
+ for (const auto& p : m)
+ {
+ if (evaluate_constraint(p, d_assignment, poly::SignCondition::EQ))
+ {
+ l.emplace_back(p);
+ }
+ }
+ d_assignment.unset(d_variableOrdering[cur_variable]);
+ }
+ if (!is_plus_infinity(upper))
+ {
+ // Identify polynomials that have a root at the upper bound
+ d_assignment.set(d_variableOrdering[cur_variable], upper);
+ for (const auto& p : m)
+ {
+ if (evaluate_constraint(p, d_assignment, poly::SignCondition::EQ))
+ {
+ u.emplace_back(p);
+ }
+ }
+ d_assignment.unset(d_variableOrdering[cur_variable]);
+ }
+
+ if (lower == upper)
+ {
+ // construct a point interval
+ return CACInterval{
+ poly::Interval(lower, false, upper, false), l, u, m, d, {}};
+ }
+ else
+ {
+ // construct an open interval
+ Assert(lower < upper);
+ return CACInterval{
+ poly::Interval(lower, true, upper, true), l, u, m, d, {}};
+ }
+}
+
+std::vector<CACInterval> CDCAC::getUnsatCover(std::size_t curVariable,
+ bool returnFirstInterval)
+{
+ Trace("cdcac") << "Looking for unsat cover for "
+ << d_variableOrdering[curVariable] << std::endl;
+ std::vector<CACInterval> intervals = getUnsatIntervals(curVariable);
+
+ if (Trace.isOn("cdcac"))
+ {
+ Trace("cdcac") << "Unsat intervals for " << d_variableOrdering[curVariable]
+ << ":" << std::endl;
+ for (const auto& i : intervals)
+ {
+ Trace("cdcac") << "-> " << i.d_interval << " from " << i.d_origins
+ << std::endl;
+ }
+ }
+ poly::Value sample;
+
+ while (sampleOutsideWithInitial(intervals, sample, curVariable))
+ {
+ if (!checkIntegrality(curVariable, sample))
+ {
+ // the variable is integral, but the sample is not.
+ Trace("cdcac") << "Used " << sample << " for integer variable "
+ << d_variableOrdering[curVariable] << std::endl;
+ auto newInterval = buildIntegralityInterval(curVariable, sample);
+ Trace("cdcac") << "Adding integrality interval " << newInterval.d_interval
+ << std::endl;
+ intervals.emplace_back(newInterval);
+ cleanIntervals(intervals);
+ continue;
+ }
+ d_assignment.set(d_variableOrdering[curVariable], sample);
+ Trace("cdcac") << "Sample: " << d_assignment << std::endl;
+ if (curVariable == d_variableOrdering.size() - 1)
+ {
+ // We have a full assignment. SAT!
+ Trace("cdcac") << "Found full assignment: " << d_assignment << std::endl;
+ return {};
+ }
+ // Recurse to next variable
+ auto cov = getUnsatCover(curVariable + 1);
+ if (cov.empty())
+ {
+ // Found SAT!
+ Trace("cdcac") << "SAT!" << std::endl;
+ return {};
+ }
+ Trace("cdcac") << "Refuting Sample: " << d_assignment << std::endl;
+ auto characterization = constructCharacterization(cov);
+ Trace("cdcac") << "Characterization: " << characterization << std::endl;
+
+ d_assignment.unset(d_variableOrdering[curVariable]);
+
+ auto newInterval =
+ intervalFromCharacterization(characterization, curVariable, sample);
+ newInterval.d_origins = collectConstraints(cov);
+ intervals.emplace_back(newInterval);
+
+ if (returnFirstInterval)
+ {
+ return intervals;
+ }
+
+ Trace("cdcac") << "Added " << intervals.back().d_interval << std::endl;
+ Trace("cdcac") << "\tlower: " << intervals.back().d_lowerPolys
+ << std::endl;
+ Trace("cdcac") << "\tupper: " << intervals.back().d_upperPolys
+ << std::endl;
+ Trace("cdcac") << "\tmain: " << intervals.back().d_mainPolys
+ << std::endl;
+ Trace("cdcac") << "\tdown: " << intervals.back().d_downPolys
+ << std::endl;
+ Trace("cdcac") << "\torigins: " << intervals.back().d_origins << std::endl;
+
+ // Remove redundant intervals
+ cleanIntervals(intervals);
+ }
+
+ if (Trace.isOn("cdcac"))
+ {
+ Trace("cdcac") << "Returning intervals for "
+ << d_variableOrdering[curVariable] << ":" << std::endl;
+ for (const auto& i : intervals)
+ {
+ Trace("cdcac") << "-> " << i.d_interval << std::endl;
+ }
+ }
+ return intervals;
+}
+
+bool CDCAC::checkIntegrality(std::size_t cur_variable, const poly::Value& value)
+{
+ Node var = d_constraints.varMapper()(d_variableOrdering[cur_variable]);
+ if (var.getType() != NodeManager::currentNM()->integerType())
+ {
+ // variable is not integral
+ return true;
+ }
+ return poly::represents_integer(value);
+}
+
+CACInterval CDCAC::buildIntegralityInterval(std::size_t cur_variable,
+ const poly::Value& value)
+{
+ poly::Variable var = d_variableOrdering[cur_variable];
+ poly::Integer below = poly::floor(value);
+ poly::Integer above = poly::ceil(value);
+ // construct var \in (below, above)
+ return CACInterval{poly::Interval(below, above),
+ {var - below},
+ {var - above},
+ {var - below, var - above},
+ {},
+ {}};
+}
+
+bool CDCAC::hasRootAbove(const poly::Polynomial& p,
+ const poly::Value& val) const
+{
+ auto roots = poly::isolate_real_roots(p, d_assignment);
+ return std::any_of(roots.begin(), roots.end(), [&val](const poly::Value& r) {
+ return r >= val;
+ });
+}
+
+bool CDCAC::hasRootBelow(const poly::Polynomial& p,
+ const poly::Value& val) const
+{
+ auto roots = poly::isolate_real_roots(p, d_assignment);
+ return std::any_of(roots.begin(), roots.end(), [&val](const poly::Value& r) {
+ return r <= val;
+ });
+}
+
+} // namespace cad
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/nl/cad/cdcac.h b/src/theory/arith/nl/cad/cdcac.h
new file mode 100644
index 000000000..a2e7ae682
--- /dev/null
+++ b/src/theory/arith/nl/cad/cdcac.h
@@ -0,0 +1,196 @@
+/********************* */
+/*! \file cdcac.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implements the CDCAC approach.
+ **
+ ** Implements the CDCAC approach as described in
+ ** https://arxiv.org/pdf/2003.05633.pdf.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__ARITH__NL__CAD__CDCAC_H
+#define CVC4__THEORY__ARITH__NL__CAD__CDCAC_H
+
+#include "util/real_algebraic_number.h"
+
+#ifdef CVC4_POLY_IMP
+
+#include <poly/polyxx.h>
+
+#include <vector>
+
+#include "theory/arith/nl/cad/cdcac_utils.h"
+#include "theory/arith/nl/cad/constraints.h"
+#include "theory/arith/nl/cad/variable_ordering.h"
+#include "theory/arith/nl/nl_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace cad {
+
+/**
+ * This class implements Cylindrical Algebraic Coverings as presented in
+ * https://arxiv.org/pdf/2003.05633.pdf
+ */
+class CDCAC
+{
+ public:
+ /** Initialize without a variable ordering. */
+ CDCAC();
+ /** Initialize this method with the given variable ordering. */
+ CDCAC(const std::vector<poly::Variable>& ordering);
+
+ /** Reset this instance. */
+ void reset();
+
+ /** Collect variables from the constraints and compute a variable ordering. */
+ void computeVariableOrdering();
+
+ /**
+ * Extract an initial assignment from the given model.
+ * This initial assignment is used to guide sampling if possible.
+ * The ran_variable should be the variable used to encode real algebraic
+ * numbers in the model and is simply passed on to node_to_value.
+ */
+ void retrieveInitialAssignment(NlModel& model, const Node& ran_variable);
+
+ /**
+ * Returns the constraints as a non-const reference. Can be used to add new
+ * constraints.
+ */
+ Constraints& getConstraints();
+ /** Returns the constraints as a const reference. */
+ const Constraints& getConstraints() const;
+
+ /**
+ * Returns the current assignment. This is a satisfying model if
+ * get_unsat_cover() returned an empty vector.
+ */
+ const poly::Assignment& getModel() const;
+
+ /** Returns the current variable ordering. */
+ const std::vector<poly::Variable>& getVariableOrdering() const;
+
+ /**
+ * Collect all unsatisfiable intervals for the given variable.
+ * Combines unsatisfiable regions from d_constraints evaluated over
+ * d_assignment. Implements Algorithm 2.
+ */
+ std::vector<CACInterval> getUnsatIntervals(std::size_t cur_variable) const;
+
+ /**
+ * Sample outside of the set of intervals.
+ * Uses a given initial value from mInitialAssignment if possible.
+ * Returns whether a sample was found (true) or the infeasible intervals cover
+ * the whole real line (false).
+ */
+ bool sampleOutsideWithInitial(const std::vector<CACInterval>& infeasible,
+ poly::Value& sample,
+ std::size_t cur_variable);
+
+ /**
+ * Collects the coefficients required for projection from the given
+ * polynomial. Implements Algorithm 6.
+ */
+ std::vector<poly::Polynomial> requiredCoefficients(
+ const poly::Polynomial& p) const;
+
+ /**
+ * Constructs a characterization of the given covering.
+ * A characterization contains polynomials whose roots bound the region around
+ * the current assignment. Implements Algorithm 4.
+ */
+ std::vector<poly::Polynomial> constructCharacterization(
+ std::vector<CACInterval>& intervals);
+
+ /**
+ * Constructs an infeasible interval from a characterization.
+ * Implements Algorithm 5.
+ */
+ CACInterval intervalFromCharacterization(
+ const std::vector<poly::Polynomial>& characterization,
+ std::size_t cur_variable,
+ const poly::Value& sample);
+
+ /**
+ * Main method that checks for the satisfiability of the constraints.
+ * Recursively explores possible assignments and excludes regions based on the
+ * coverings. Returns either a covering for the lowest dimension or an empty
+ * vector. If the covering is empty, the result is SAT and an assignment can
+ * be obtained from d_assignment. If the covering is not empty, the result is
+ * UNSAT and an infeasible subset can be extracted from the returned covering.
+ * Implements Algorithm 2.
+ * @param curVariable The id of the variable (within d_variableOrdering) to
+ * be considered. This argument is used to manage the recursion internally and
+ * should always be zero if called externally.
+ * @param returnFirstInterval If true, the function returns after the first
+ * interval obtained from a recursive call. The result is not (necessarily) an
+ * unsat cover, but merely a list of infeasible intervals.
+ */
+ std::vector<CACInterval> getUnsatCover(std::size_t curVariable = 0,
+ bool returnFirstInterval = false);
+
+ private:
+ /**
+ * Check whether the current sample satisfies the integrality condition of the
+ * current variable. Returns true if the variable is not integral or the
+ * sample is integral.
+ */
+ bool checkIntegrality(std::size_t cur_variable, const poly::Value& value);
+ /**
+ * Constructs an interval that excludes the non-integral region around the
+ * current sample. Assumes !check_integrality(cur_variable, value).
+ */
+ CACInterval buildIntegralityInterval(std::size_t cur_variable,
+ const poly::Value& value);
+
+ /**
+ * Check whether the polynomial has a real root above the given value (when
+ * evaluated over the current assignment).
+ */
+ bool hasRootAbove(const poly::Polynomial& p, const poly::Value& val) const;
+ /**
+ * Check whether the polynomial has a real root below the given value (when
+ * evaluated over the current assignment).
+ */
+ bool hasRootBelow(const poly::Polynomial& p, const poly::Value& val) const;
+
+ /**
+ * The current assignment. When the method terminates with SAT, it contains a
+ * model for the input constraints.
+ */
+ poly::Assignment d_assignment;
+
+ /** The set of input constraints to be checked for consistency. */
+ Constraints d_constraints;
+
+ /** The computed variable ordering used for this method. */
+ std::vector<poly::Variable> d_variableOrdering;
+
+ /** The object computing the variable ordering. */
+ VariableOrdering d_varOrder;
+
+ /** The linear assignment used as an initial guess. */
+ std::vector<poly::Value> d_initialAssignment;
+};
+
+} // namespace cad
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
+
+#endif
diff --git a/src/theory/arith/nl/cad/cdcac_utils.cpp b/src/theory/arith/nl/cad/cdcac_utils.cpp
new file mode 100644
index 000000000..f36ec775f
--- /dev/null
+++ b/src/theory/arith/nl/cad/cdcac_utils.cpp
@@ -0,0 +1,375 @@
+/********************* */
+/*! \file cdcac_utils.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implements utilities for cdcac.
+ **
+ ** Implements utilities for cdcac.
+ **/
+
+#include "theory/arith/nl/cad/cdcac_utils.h"
+
+#ifdef CVC4_POLY_IMP
+
+#include "theory/arith/nl/cad/projections.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace cad {
+
+using namespace poly;
+
+bool operator==(const CACInterval& lhs, const CACInterval& rhs)
+{
+ return lhs.d_interval == rhs.d_interval;
+}
+bool operator<(const CACInterval& lhs, const CACInterval& rhs)
+{
+ return lhs.d_interval < rhs.d_interval;
+}
+
+/**
+ * Induces an ordering on poly intervals that is suitable for redundancy
+ * removal as implemented in clean_intervals.
+ */
+inline bool compareForCleanup(const Interval& lhs, const Interval& rhs)
+{
+ const lp_value_t* ll = &(lhs.get_internal()->a);
+ const lp_value_t* lu =
+ lhs.get_internal()->is_point ? ll : &(lhs.get_internal()->b);
+ const lp_value_t* rl = &(rhs.get_internal()->a);
+ const lp_value_t* ru =
+ rhs.get_internal()->is_point ? rl : &(rhs.get_internal()->b);
+
+ int lc = lp_value_cmp(ll, rl);
+ // Lower bound is smaller
+ if (lc < 0) return true;
+ // Lower bound is larger
+ if (lc > 0) return false;
+ // Lower bound type is smaller
+ if (!lhs.get_internal()->a_open && rhs.get_internal()->a_open) return true;
+ // Lower bound type is larger
+ if (lhs.get_internal()->a_open && !rhs.get_internal()->a_open) return false;
+
+ // Attention: Here it differs from the regular interval ordering!
+ int uc = lp_value_cmp(lu, ru);
+ // Upper bound is smaller
+ if (uc < 0) return false;
+ // Upper bound is larger
+ if (uc > 0) return true;
+ // Upper bound type is smaller
+ if (lhs.get_internal()->b_open && !rhs.get_internal()->b_open) return false;
+ // Upper bound type is larger
+ if (!lhs.get_internal()->b_open && rhs.get_internal()->b_open) return true;
+
+ // Identical
+ return false;
+}
+
+bool intervalCovers(const Interval& lhs, const Interval& rhs)
+{
+ const lp_value_t* ll = &(lhs.get_internal()->a);
+ const lp_value_t* lu =
+ lhs.get_internal()->is_point ? ll : &(lhs.get_internal()->b);
+ const lp_value_t* rl = &(rhs.get_internal()->a);
+ const lp_value_t* ru =
+ rhs.get_internal()->is_point ? rl : &(rhs.get_internal()->b);
+
+ int lc = lp_value_cmp(ll, rl);
+ int uc = lp_value_cmp(lu, ru);
+
+ // Lower bound is smaller and upper bound is larger
+ if (lc < 0 && uc > 0) return true;
+ // Lower bound is larger or upper bound is smaller
+ if (lc > 0 || uc < 0) return false;
+
+ // Now both bounds are identical.
+ Assert(lc <= 0 && uc >= 0);
+ Assert(lc == 0 || uc == 0);
+
+ // Lower bound is the same and the bound type is stricter
+ if (lc == 0 && lhs.get_internal()->a_open && !rhs.get_internal()->a_open)
+ return false;
+ // Upper bound is the same and the bound type is stricter
+ if (uc == 0 && lhs.get_internal()->b_open && !rhs.get_internal()->b_open)
+ return false;
+
+ // Both bounds are weaker
+ return true;
+}
+
+bool intervalConnect(const Interval& lhs, const Interval& rhs)
+{
+ Assert(lhs < rhs) << "Can only check for a connection if lhs < rhs.";
+ const lp_value_t* lu = lhs.get_internal()->is_point
+ ? &(lhs.get_internal()->a)
+ : &(lhs.get_internal()->b);
+ const lp_value_t* rl = &(rhs.get_internal()->a);
+ int c = lp_value_cmp(lu, rl);
+ if (c < 0)
+ {
+ Trace("libpoly::interval_connect")
+ << lhs << " and " << rhs << " are separated." << std::endl;
+ return false;
+ }
+ if (c > 0)
+ {
+ Trace("libpoly::interval_connect")
+ << lhs << " and " << rhs << " overlap." << std::endl;
+ return true;
+ }
+ Assert(c == 0);
+ if (lhs.get_internal()->is_point || rhs.get_internal()->is_point
+ || !lhs.get_internal()->b_open || !rhs.get_internal()->a_open)
+ {
+ Trace("libpoly::interval_connect")
+ << lhs << " and " << rhs
+ << " touch and the intermediate point is covered." << std::endl;
+ return true;
+ }
+ return false;
+}
+
+void cleanIntervals(std::vector<CACInterval>& intervals)
+{
+ // Simplifies removal of redundancies later on.
+ if (intervals.size() < 2) return;
+
+ // Sort intervals.
+ std::sort(intervals.begin(),
+ intervals.end(),
+ [](const CACInterval& lhs, const CACInterval& rhs) {
+ return compareForCleanup(lhs.d_interval, rhs.d_interval);
+ });
+
+ // Remove intervals that are covered by others.
+ // Implementation roughly follows
+ // https://en.cppreference.com/w/cpp/algorithm/remove Find first interval that
+ // covers the next one.
+ std::size_t first = 0;
+ for (std::size_t n = intervals.size(); first < n - 1; ++first)
+ {
+ if (intervalCovers(intervals[first].d_interval,
+ intervals[first + 1].d_interval))
+ {
+ break;
+ }
+ }
+ // If such an interval exists, remove accordingly.
+ if (first < intervals.size() - 1)
+ {
+ for (std::size_t i = first + 2, n = intervals.size(); i < n; ++i)
+ {
+ if (!intervalCovers(intervals[first].d_interval, intervals[i].d_interval))
+ {
+ // Interval is not covered. Move it to the front and bump front.
+ ++first;
+ intervals[first] = std::move(intervals[i]);
+ }
+ // Else: Interval is covered as well.
+ }
+ // Erase trailing values
+ while (intervals.size() > first + 1)
+ {
+ intervals.pop_back();
+ }
+ }
+}
+
+std::vector<Node> collectConstraints(const std::vector<CACInterval>& intervals)
+{
+ std::vector<Node> res;
+ for (const auto& i : intervals)
+ {
+ res.insert(res.end(), i.d_origins.begin(), i.d_origins.end());
+ }
+ std::sort(res.begin(), res.end());
+ auto it = std::unique(res.begin(), res.end());
+ res.erase(it, res.end());
+ return res;
+}
+
+bool sampleOutside(const std::vector<CACInterval>& infeasible, Value& sample)
+{
+ if (infeasible.empty())
+ {
+ // No infeasible region, just take anything: zero
+ sample = poly::Integer();
+ return true;
+ }
+ if (!is_minus_infinity(get_lower(infeasible.front().d_interval)))
+ {
+ // First does not cover -oo, just take sufficiently low value
+ Trace("cdcac") << "Sample before " << infeasible.front().d_interval
+ << std::endl;
+ const auto* i = infeasible.front().d_interval.get_internal();
+ sample = value_between(
+ Value::minus_infty().get_internal(), true, &i->a, !i->a_open);
+ return true;
+ }
+ for (std::size_t i = 0, n = infeasible.size(); i < n - 1; ++i)
+ {
+ // Search for two subsequent intervals that do not connect
+ if (!intervalConnect(infeasible[i].d_interval,
+ infeasible[i + 1].d_interval))
+ {
+ // Two intervals do not connect, take something from the gap
+ const auto* l = infeasible[i].d_interval.get_internal();
+ const auto* r = infeasible[i + 1].d_interval.get_internal();
+
+ Trace("cdcac") << "Sample between " << infeasible[i].d_interval << " and "
+ << infeasible[i + 1].d_interval << std::endl;
+
+ if (l->is_point)
+ {
+ sample = value_between(&l->a, true, &r->a, !r->a_open);
+ }
+ else
+ {
+ sample = value_between(&l->b, !l->b_open, &r->a, !r->a_open);
+ }
+ return true;
+ }
+ else
+ {
+ Trace("cdcac") << infeasible[i].d_interval << " and "
+ << infeasible[i + 1].d_interval << " connect" << std::endl;
+ }
+ }
+ if (!is_plus_infinity(get_upper(infeasible.back().d_interval)))
+ {
+ // Last does not cover oo, just take something sufficiently large
+ Trace("cdcac") << "Sample above " << infeasible.back().d_interval
+ << std::endl;
+ const auto* i = infeasible.back().d_interval.get_internal();
+ if (i->is_point)
+ {
+ sample =
+ value_between(&i->a, true, Value::plus_infty().get_internal(), true);
+ }
+ else
+ {
+ sample = value_between(
+ &i->b, !i->b_open, Value::plus_infty().get_internal(), true);
+ }
+ return true;
+ }
+ return false;
+}
+
+namespace {
+/**
+ * Replace a polynomial at polys[id] with the given pair of polynomials.
+ * Also update d_mainPolys in the given interval accordingly.
+ * If one of the factors (from the pair) is from a lower level (has a different
+ * main variable), push this factor to the d_downPolys.
+ * The first factor needs to be a proper polynomial (!is_constant(subst.first)),
+ * but the second factor may be anything.
+ */
+void replace_polynomial(std::vector<poly::Polynomial>& polys,
+ std::size_t id,
+ std::pair<poly::Polynomial, poly::Polynomial> subst,
+ CACInterval& interval)
+{
+ Assert(polys[id] == subst.first * subst.second);
+ Assert(!is_constant(subst.first));
+ // Whether polys[id] has already been replaced
+ bool replaced = false;
+ poly::Variable var = main_variable(polys[id]);
+ // The position within interval.d_mainPolys to be replaced.
+ auto mit = std::find(
+ interval.d_mainPolys.begin(), interval.d_mainPolys.end(), polys[id]);
+ if (main_variable(subst.first) == var)
+ {
+ // Replace in polys[id] and *mit
+ polys[id] = subst.first;
+ if (mit != interval.d_mainPolys.end())
+ {
+ *mit = subst.first;
+ }
+ replaced = true;
+ }
+ else
+ {
+ // Push to d_downPolys
+ interval.d_downPolys.emplace_back(subst.first);
+ }
+ // Skip constant poly
+ if (!is_constant(subst.second))
+ {
+ if (main_variable(subst.second) == var)
+ {
+ if (replaced)
+ {
+ // Append to polys and d_mainPolys
+ polys.emplace_back(subst.second);
+ interval.d_mainPolys.emplace_back(subst.second);
+ }
+ else
+ {
+ // Replace in polys[id] and *mit
+ polys[id] = subst.second;
+ if (mit != interval.d_mainPolys.end())
+ {
+ *mit = subst.second;
+ }
+ replaced = true;
+ }
+ }
+ else
+ {
+ // Push to d_downPolys
+ interval.d_downPolys.emplace_back(subst.second);
+ }
+ }
+ Assert(replaced)
+ << "At least one of the factors should have the main variable";
+}
+} // namespace
+
+void makeFinestSquareFreeBasis(CACInterval& lhs, CACInterval& rhs)
+{
+ auto& l = lhs.d_upperPolys;
+ auto& r = rhs.d_lowerPolys;
+ if (l.empty()) return;
+ for (std::size_t i = 0, ln = l.size(); i < ln; ++i)
+ {
+ for (std::size_t j = 0, rn = r.size(); j < rn; ++j)
+ {
+ // All main variables should be the same
+ Assert(main_variable(l[i]) == main_variable(r[j]));
+ if (l[i] == r[j]) continue;
+ Polynomial g = gcd(l[i], r[j]);
+ if (!is_constant(g))
+ {
+ auto newl = div(l[i], g);
+ auto newr = div(r[j], g);
+ replace_polynomial(l, i, std::make_pair(g, newl), lhs);
+ replace_polynomial(r, j, std::make_pair(g, newr), rhs);
+ }
+ }
+ }
+ reduceProjectionPolynomials(l);
+ reduceProjectionPolynomials(r);
+ reduceProjectionPolynomials(lhs.d_mainPolys);
+ reduceProjectionPolynomials(rhs.d_mainPolys);
+ reduceProjectionPolynomials(lhs.d_downPolys);
+ reduceProjectionPolynomials(rhs.d_downPolys);
+}
+
+} // namespace cad
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/nl/cad/cdcac_utils.h b/src/theory/arith/nl/cad/cdcac_utils.h
new file mode 100644
index 000000000..43bef32aa
--- /dev/null
+++ b/src/theory/arith/nl/cad/cdcac_utils.h
@@ -0,0 +1,113 @@
+/********************* */
+/*! \file cdcac_utils.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implements utilities for cdcac.
+ **
+ ** Implements utilities for cdcac.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__ARITH__NL__CAD__CDCAC_UTILS_H
+#define CVC4__THEORY__ARITH__NL__CAD__CDCAC_UTILS_H
+
+#include "util/real_algebraic_number.h"
+
+#ifdef CVC4_POLY_IMP
+
+#include <poly/polyxx.h>
+
+#include <vector>
+
+#include "expr/node.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace cad {
+
+/**
+ * An interval as specified in section 4.1 of
+ * https://arxiv.org/pdf/2003.05633.pdf.
+ *
+ * It consists of
+ * - the actual interval, either an open or a point interal,
+ * - the characterizing polynomials of the lower and upper bound,
+ * - the characterizing polynomials in the main variable,
+ * - the characterizing polynomials in lower variables and
+ * - the constraints used to derive this interval.
+ */
+struct CACInterval
+{
+ /** The actual interval. */
+ poly::Interval d_interval;
+ /** The polynomials characterizing the lower bound. */
+ std::vector<poly::Polynomial> d_lowerPolys;
+ /** The polynomials characterizing the upper bound. */
+ std::vector<poly::Polynomial> d_upperPolys;
+ /** The characterizing polynomials in the main variable. */
+ std::vector<poly::Polynomial> d_mainPolys;
+ /** The characterizing polynomials in lower variables. */
+ std::vector<poly::Polynomial> d_downPolys;
+ /** The constraints used to derive this interval. */
+ std::vector<Node> d_origins;
+};
+/** Check whether to intervals are the same. */
+bool operator==(const CACInterval& lhs, const CACInterval& rhs);
+/** Compare two intervals. */
+bool operator<(const CACInterval& lhs, const CACInterval& rhs);
+
+/** Check whether lhs covers rhs. */
+bool intervalCovers(const poly::Interval& lhs, const poly::Interval& rhs);
+/**
+ * Check whether two intervals connect, assuming lhs < rhs.
+ * They connect, if their union has no gap.
+ */
+bool intervalConnect(const poly::Interval& lhs, const poly::Interval& rhs);
+
+/**
+ * Sort intervals according to section 4.4.1.
+ * Also removes fully redundant intervals as in 4.5. 1.
+ */
+void cleanIntervals(std::vector<CACInterval>& intervals);
+
+/**
+ * Collect all origins from the list of intervals to construct the origins for a
+ * whole covering.
+ */
+std::vector<Node> collectConstraints(const std::vector<CACInterval>& intervals);
+
+/**
+ * Sample a point outside of the infeasible intervals.
+ * Stores the sample in sample, returns whether such a sample exists.
+ * If false is returned, the infeasible intervals cover the real line.
+ * Implements sample_outside() from section 4.3
+ */
+bool sampleOutside(const std::vector<CACInterval>& infeasible,
+ poly::Value& sample);
+
+/**
+ * Compute the finest square of the upper polynomials of lhs and the lower
+ * polynomials of rhs. Also pushes reduced polynomials to lower level if
+ * necessary.
+ */
+void makeFinestSquareFreeBasis(CACInterval& lhs, CACInterval& rhs);
+
+} // namespace cad
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
+
+#endif
diff --git a/src/theory/arith/nl/cad/constraints.cpp b/src/theory/arith/nl/cad/constraints.cpp
new file mode 100644
index 000000000..f0a214919
--- /dev/null
+++ b/src/theory/arith/nl/cad/constraints.cpp
@@ -0,0 +1,84 @@
+/********************* */
+/*! \file constraints.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implements a container for CAD constraints.
+ **
+ ** Implements a container for CAD constraints.
+ **/
+
+#include "theory/arith/nl/cad/constraints.h"
+
+#ifdef CVC4_POLY_IMP
+
+#include <algorithm>
+
+#include "theory/arith/nl/poly_conversion.h"
+#include "util/poly_util.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace cad {
+
+void Constraints::addConstraint(const poly::Polynomial& lhs,
+ poly::SignCondition sc,
+ Node n)
+{
+ d_constraints.emplace_back(lhs, sc, n);
+ sortConstraints();
+}
+
+void Constraints::addConstraint(Node n)
+{
+ auto c = as_poly_constraint(n, d_varMapper);
+ addConstraint(c.first, c.second, n);
+ sortConstraints();
+}
+
+const Constraints::ConstraintVector& Constraints::getConstraints() const
+{
+ return d_constraints;
+}
+
+void Constraints::reset() { d_constraints.clear(); }
+
+void Constraints::sortConstraints()
+{
+ using Tpl = std::tuple<poly::Polynomial, poly::SignCondition, Node>;
+ std::sort(d_constraints.begin(),
+ d_constraints.end(),
+ [](const Tpl& at, const Tpl& bt) {
+ // Check if a is smaller than b
+ const poly::Polynomial& a = std::get<0>(at);
+ const poly::Polynomial& b = std::get<0>(bt);
+ bool ua = is_univariate(a);
+ bool ub = is_univariate(b);
+ if (ua != ub) return ua;
+ std::size_t tda = poly_utils::totalDegree(a);
+ std::size_t tdb = poly_utils::totalDegree(b);
+ if (tda != tdb) return tda < tdb;
+ return degree(a) < degree(b);
+ });
+ for (auto& c : d_constraints)
+ {
+ auto* p = std::get<0>(c).get_internal();
+ lp_polynomial_set_external(p);
+ }
+}
+
+} // namespace cad
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/nl/cad/constraints.h b/src/theory/arith/nl/cad/constraints.h
new file mode 100644
index 000000000..1df61e706
--- /dev/null
+++ b/src/theory/arith/nl/cad/constraints.h
@@ -0,0 +1,99 @@
+/********************* */
+/*! \file constraints.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implements a container for CAD constraints.
+ **
+ ** Implements a container for CAD constraints.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__ARITH__NL__CAD__CONSTRAINTS_H
+#define CVC4__THEORY__ARITH__NL__CAD__CONSTRAINTS_H
+
+#include "util/real_algebraic_number.h"
+
+#ifdef CVC4_POLY_IMP
+
+#include <poly/polyxx.h>
+
+#include <map>
+#include <tuple>
+#include <vector>
+
+#include "expr/kind.h"
+#include "expr/node_manager_attributes.h"
+#include "theory/arith/nl/poly_conversion.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace cad {
+
+class Constraints
+{
+ public:
+ /** Type alias for a list of constraints. */
+ using Constraint = std::tuple<poly::Polynomial, poly::SignCondition, Node>;
+ using ConstraintVector = std::vector<Constraint>;
+
+ VariableMapper& varMapper() { return d_varMapper; }
+
+ /**
+ * Add a constraint (represented by a polynomial and a sign condition) to the
+ * list of constraints.
+ */
+ void addConstraint(const poly::Polynomial& lhs,
+ poly::SignCondition sc,
+ Node n);
+
+ /**
+ * Add a constraints (represented by a node) to the list of constraints.
+ * The given node can either be a negation (NOT) or a suitable relation symbol
+ * as checked by is_suitable_relation().
+ */
+ void addConstraint(Node n);
+
+ /**
+ * Gives the list of added constraints.
+ */
+ const ConstraintVector& getConstraints() const;
+
+ /**
+ * Remove all constraints.
+ */
+ void reset();
+
+ private:
+ /**
+ * A list of constraints, each comprised of a polynomial and a sign
+ * condition.
+ */
+ ConstraintVector d_constraints;
+
+ /**
+ * A mapping from CVC4 variables to poly variables.
+ */
+ VariableMapper d_varMapper;
+
+ void sortConstraints();
+};
+
+} // namespace cad
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
+
+#endif
diff --git a/src/theory/arith/nl/cad/projections.cpp b/src/theory/arith/nl/cad/projections.cpp
new file mode 100644
index 000000000..162e9f7be
--- /dev/null
+++ b/src/theory/arith/nl/cad/projections.cpp
@@ -0,0 +1,104 @@
+/********************* */
+/*! \file projections.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implements utilities for CAD projection operators.
+ **
+ ** Implements utilities for CAD projection operators.
+ **/
+
+#include "theory/arith/nl/cad/projections.h"
+
+#ifdef CVC4_POLY_IMP
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace cad {
+
+using namespace poly;
+
+void reduceProjectionPolynomials(std::vector<Polynomial>& polys)
+{
+ std::sort(polys.begin(), polys.end());
+ auto it = std::unique(polys.begin(), polys.end());
+ polys.erase(it, polys.end());
+}
+
+void addPolynomial(std::vector<Polynomial>& polys, const Polynomial& poly)
+{
+ for (const auto& p : square_free_factors(poly))
+ {
+ if (is_constant(p)) continue;
+ polys.emplace_back(p);
+ }
+}
+
+void addPolynomials(std::vector<Polynomial>& polys,
+ const std::vector<Polynomial>& p)
+{
+ for (const auto& q : p) addPolynomial(polys, q);
+}
+
+void makeFinestSquareFreeBasis(std::vector<Polynomial>& polys)
+{
+ for (std::size_t i = 0, n = polys.size(); i < n; ++i)
+ {
+ for (std::size_t j = i + 1; j < n; ++j)
+ {
+ Polynomial g = gcd(polys[i], polys[j]);
+ if (!is_constant(g))
+ {
+ polys[i] = div(polys[i], g);
+ polys[j] = div(polys[j], g);
+ polys.emplace_back(g);
+ }
+ }
+ }
+ auto it = std::remove_if(polys.begin(), polys.end(), [](const Polynomial& p) {
+ return is_constant(p);
+ });
+ polys.erase(it, polys.end());
+ reduceProjectionPolynomials(polys);
+}
+
+std::vector<Polynomial> projection_mccallum(
+ const std::vector<Polynomial>& polys)
+{
+ std::vector<Polynomial> res;
+
+ for (const auto& p : polys)
+ {
+ for (const auto& coeff : coefficients(p))
+ {
+ addPolynomial(res, coeff);
+ }
+ addPolynomial(res, discriminant(p));
+ }
+ for (std::size_t i = 0, n = polys.size(); i < n; ++i)
+ {
+ for (std::size_t j = i + 1; j < n; ++j)
+ {
+ addPolynomial(res, resultant(polys[i], polys[j]));
+ }
+ }
+
+ reduceProjectionPolynomials(res);
+ return res;
+}
+
+} // namespace cad
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/nl/cad/projections.h b/src/theory/arith/nl/cad/projections.h
new file mode 100644
index 000000000..71c2d5e7f
--- /dev/null
+++ b/src/theory/arith/nl/cad/projections.h
@@ -0,0 +1,69 @@
+/********************* */
+/*! \file projections.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implements utilities for CAD projection operators.
+ **
+ ** Implements utilities for CAD projection operators.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__ARITH__NL__CAD_PROJECTIONS_H
+#define CVC4__THEORY__ARITH__NL__CAD_PROJECTIONS_H
+
+#include "util/real_algebraic_number.h"
+
+#ifdef CVC4_USE_POLY
+
+#include <poly/polyxx.h>
+
+#include <algorithm>
+#include <iostream>
+#include <vector>
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace cad {
+
+/** Sort and remove duplicates from the list of polynomials. */
+void reduceProjectionPolynomials(std::vector<poly::Polynomial>& polys);
+
+/**
+ * Adds a polynomial to the list of projection polynomials.
+ * Before adding, it factorizes the polynomials and removed constant factors.
+ */
+void addPolynomial(std::vector<poly::Polynomial>& polys,
+ const poly::Polynomial& poly);
+
+/** Adds a list of polynomials using add_polynomial(). */
+void addPolynomials(std::vector<poly::Polynomial>& polys,
+ const std::vector<poly::Polynomial>& p);
+
+/** Make a set of polynomials a finest square-free basis. */
+void makeFinestSquareFreeBasis(std::vector<poly::Polynomial>& polys);
+
+/**
+ * Computes McCallum's projection operator.
+ */
+std::vector<poly::Polynomial> projectionMcCallum(
+ const std::vector<poly::Polynomial>& polys);
+
+} // namespace cad
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
+
+#endif
diff --git a/src/theory/arith/nl/cad/variable_ordering.cpp b/src/theory/arith/nl/cad/variable_ordering.cpp
new file mode 100644
index 000000000..4897ed6b7
--- /dev/null
+++ b/src/theory/arith/nl/cad/variable_ordering.cpp
@@ -0,0 +1,137 @@
+/********************* */
+/*! \file variable_ordering.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implements variable orderings tailored to CAD.
+ **
+ ** Implements variable orderings tailored to CAD.
+ **/
+
+#include "theory/arith/nl/cad/variable_ordering.h"
+
+#ifdef CVC4_POLY_IMP
+
+#include "util/poly_util.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace cad {
+
+std::vector<poly_utils::VariableInformation> collectInformation(
+ const Constraints::ConstraintVector& polys, bool with_totals)
+{
+ poly::VariableCollector vc;
+ for (const auto& c : polys)
+ {
+ vc(std::get<0>(c));
+ }
+ std::vector<poly_utils::VariableInformation> res;
+ for (const auto& v : vc.get_variables())
+ {
+ res.emplace_back();
+ res.back().var = v;
+ for (const auto& c : polys)
+ {
+ poly_utils::getVariableInformation(res.back(), std::get<0>(c));
+ }
+ }
+ if (with_totals)
+ {
+ res.emplace_back();
+ for (const auto& c : polys)
+ {
+ poly_utils::getVariableInformation(res.back(), std::get<0>(c));
+ }
+ }
+ return res;
+}
+
+std::vector<poly::Variable> getVariables(
+ const std::vector<poly_utils::VariableInformation>& vi)
+{
+ std::vector<poly::Variable> res;
+ for (const auto& v : vi)
+ {
+ res.emplace_back(v.var);
+ }
+ return res;
+}
+
+std::vector<poly::Variable> sortByid(const Constraints::ConstraintVector& polys)
+{
+ auto vi = collectInformation(polys);
+ std::sort(
+ vi.begin(),
+ vi.end(),
+ [](const poly_utils::VariableInformation& a,
+ const poly_utils::VariableInformation& b) { return a.var < b.var; });
+ return getVariables(vi);
+};
+
+std::vector<poly::Variable> sortBrown(
+ const Constraints::ConstraintVector& polys)
+{
+ auto vi = collectInformation(polys);
+ std::sort(vi.begin(),
+ vi.end(),
+ [](const poly_utils::VariableInformation& a,
+ const poly_utils::VariableInformation& b) {
+ if (a.max_degree != b.max_degree)
+ return a.max_degree > b.max_degree;
+ if (a.max_terms_tdegree != b.max_terms_tdegree)
+ return a.max_terms_tdegree > b.max_terms_tdegree;
+ return a.num_terms > b.num_terms;
+ });
+ return getVariables(vi);
+};
+
+std::vector<poly::Variable> sortTriangular(
+ const Constraints::ConstraintVector& polys)
+{
+ auto vi = collectInformation(polys);
+ std::sort(vi.begin(),
+ vi.end(),
+ [](const poly_utils::VariableInformation& a,
+ const poly_utils::VariableInformation& b) {
+ if (a.max_degree != b.max_degree)
+ return a.max_degree > b.max_degree;
+ if (a.max_lc_degree != b.max_lc_degree)
+ return a.max_lc_degree > b.max_lc_degree;
+ return a.sum_poly_degree > b.sum_poly_degree;
+ });
+ return getVariables(vi);
+};
+
+VariableOrdering::VariableOrdering() {}
+VariableOrdering::~VariableOrdering() {}
+
+std::vector<poly::Variable> VariableOrdering::operator()(
+ const Constraints::ConstraintVector& polys,
+ VariableOrderingStrategy vos) const
+{
+ switch (vos)
+ {
+ case VariableOrderingStrategy::BYID: return sortByid(polys);
+ case VariableOrderingStrategy::BROWN: return sortBrown(polys);
+ case VariableOrderingStrategy::TRIANGULAR: return sortTriangular(polys);
+ default: Assert(false) << "Unsupported variable ordering.";
+ }
+ return {};
+}
+
+} // namespace cad
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/nl/cad/variable_ordering.h b/src/theory/arith/nl/cad/variable_ordering.h
new file mode 100644
index 000000000..2e56a64b4
--- /dev/null
+++ b/src/theory/arith/nl/cad/variable_ordering.h
@@ -0,0 +1,74 @@
+/********************* */
+/*! \file variable_ordering.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implements variable orderings tailored to CAD.
+ **
+ ** Implements variable orderings tailored to CAD.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__ARITH__NL__CAD__VARIABLE_ORDERING_H
+#define CVC4__THEORY__ARITH__NL__CAD__VARIABLE_ORDERING_H
+
+#include "util/real_algebraic_number.h"
+
+#ifdef CVC4_POLY_IMP
+
+#include <poly/polyxx.h>
+
+#include "theory/arith/nl/cad/constraints.h"
+#include "util/poly_util.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace cad {
+
+/** Variable orderings for real variables in the context of CAD. */
+enum class VariableOrderingStrategy
+{
+ /** Dummy ordering by variable ID. */
+ BYID,
+ /** Triangular as of DOI:10.1145/2755996.2756678 */
+ TRIANGULAR,
+ /** Brown as of DOI:10.1145/2755996.2756678 */
+ BROWN
+};
+
+class VariableOrdering
+{
+ public:
+ VariableOrdering();
+ ~VariableOrdering();
+ std::vector<poly::Variable> operator()(
+ const Constraints::ConstraintVector& polys,
+ VariableOrderingStrategy vos) const;
+};
+
+/**
+ * Retrieves variable information for all variables with the given polynomials.
+ * If with_totals is set, the last element of the vector contains totals as
+ * computed by get_variable_information if no variable is specified.
+ */
+std::vector<poly_utils::VariableInformation> collectInformation(
+ const Constraints::ConstraintVector& polys, bool with_totals = false);
+
+} // namespace cad
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
+
+#endif
diff --git a/src/theory/arith/nl/cad_solver.cpp b/src/theory/arith/nl/cad_solver.cpp
new file mode 100644
index 000000000..831530995
--- /dev/null
+++ b/src/theory/arith/nl/cad_solver.cpp
@@ -0,0 +1,195 @@
+/********************* */
+/*! \file cad_solver.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of new non-linear solver
+ **/
+
+#include "theory/arith/nl/cad_solver.h"
+
+#ifdef CVC4_POLY_IMP
+#include <poly/polyxx.h>
+#endif
+
+#include "options/arith_options.h"
+#include "theory/arith/inference_id.h"
+#include "theory/arith/nl/cad/cdcac.h"
+#include "theory/arith/nl/poly_conversion.h"
+#include "util/poly_util.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+CadSolver::CadSolver(InferenceManager& im, NlModel& model)
+ : d_foundSatisfiability(false), d_im(im), d_model(model)
+{
+ d_ranVariable =
+ NodeManager::currentNM()->mkSkolem("__z",
+ NodeManager::currentNM()->realType(),
+ "",
+ NodeManager::SKOLEM_EXACT_NAME);
+}
+
+CadSolver::~CadSolver() {}
+
+void CadSolver::initLastCall(const std::vector<Node>& assertions)
+{
+#ifdef CVC4_POLY_IMP
+ if (Trace.isOn("nl-cad"))
+ {
+ Trace("nl-cad") << "CadSolver::initLastCall" << std::endl;
+ Trace("nl-cad") << "* Assertions: " << std::endl;
+ for (const Node& a : assertions)
+ {
+ Trace("nl-cad") << " " << a << std::endl;
+ }
+ }
+ // store or process assertions
+ d_CAC.reset();
+ for (const Node& a : assertions)
+ {
+ d_CAC.getConstraints().addConstraint(a);
+ }
+ d_CAC.computeVariableOrdering();
+ d_CAC.retrieveInitialAssignment(d_model, d_ranVariable);
+#else
+ Warning() << "Tried to use CadSolver but libpoly is not available. Compile "
+ "with --poly."
+ << std::endl;
+#endif
+}
+
+void CadSolver::checkFull()
+{
+#ifdef CVC4_POLY_IMP
+ auto covering = d_CAC.getUnsatCover();
+ if (covering.empty())
+ {
+ d_foundSatisfiability = true;
+ Trace("nl-cad") << "SAT: " << d_CAC.getModel() << std::endl;
+ }
+ else
+ {
+ d_foundSatisfiability = false;
+ auto mis = collectConstraints(covering);
+ Trace("nl-cad") << "Collected MIS: " << mis << std::endl;
+ Assert(!mis.empty()) << "Infeasible subset can not be empty";
+ Trace("nl-cad") << "UNSAT with MIS: " << mis << std::endl;
+ for (auto& n : mis)
+ {
+ n = n.negate();
+ }
+ d_im.addPendingArithLemma(NodeManager::currentNM()->mkOr(mis),
+ InferenceId::NL_CAD_CONFLICT);
+ }
+#else
+ Warning() << "Tried to use CadSolver but libpoly is not available. Compile "
+ "with --poly."
+ << std::endl;
+#endif
+}
+
+void CadSolver::checkPartial()
+{
+#ifdef CVC4_POLY_IMP
+ auto covering = d_CAC.getUnsatCover(0, true);
+ if (covering.empty())
+ {
+ d_foundSatisfiability = true;
+ Trace("nl-cad") << "SAT: " << d_CAC.getModel() << std::endl;
+ }
+ else
+ {
+ auto* nm = NodeManager::currentNM();
+ Node first_var =
+ d_CAC.getConstraints().varMapper()(d_CAC.getVariableOrdering()[0]);
+ for (const auto& interval : covering)
+ {
+ Node premise;
+ Assert(!interval.d_origins.empty());
+ if (interval.d_origins.size() == 1)
+ {
+ premise = interval.d_origins[0];
+ }
+ else
+ {
+ premise = nm->mkNode(Kind::AND, interval.d_origins);
+ }
+ Node conclusion =
+ excluding_interval_to_lemma(first_var, interval.d_interval, false);
+ if (!conclusion.isNull())
+ {
+ Node lemma = nm->mkNode(Kind::IMPLIES, premise, conclusion);
+ Trace("nl-cad") << "Excluding " << first_var << " -> "
+ << interval.d_interval << " using " << lemma
+ << std::endl;
+ d_im.addPendingArithLemma(lemma, InferenceId::NL_CAD_EXCLUDED_INTERVAL);
+ }
+ }
+ }
+#else
+ Warning() << "Tried to use CadSolver but libpoly is not available. Compile "
+ "with --poly."
+ << std::endl;
+#endif
+}
+
+bool CadSolver::constructModelIfAvailable(std::vector<Node>& assertions)
+{
+#ifdef CVC4_POLY_IMP
+ if (!d_foundSatisfiability)
+ {
+ return false;
+ }
+ bool foundNonVariable = false;
+ for (const auto& v : d_CAC.getVariableOrdering())
+ {
+ Node variable = d_CAC.getConstraints().varMapper()(v);
+ if (!variable.isVar())
+ {
+ Trace("nl-cad") << "Not a variable: " << variable << std::endl;
+ foundNonVariable = true;
+ }
+ Node value = value_to_node(d_CAC.getModel().get(v), d_ranVariable);
+ if (value.isConst())
+ {
+ d_model.addCheckModelSubstitution(variable, value);
+ }
+ else
+ {
+ d_model.addCheckModelWitness(variable, value);
+ }
+ Trace("nl-cad") << "-> " << v << " = " << value << std::endl;
+ }
+ if (foundNonVariable)
+ {
+ Trace("nl-cad")
+ << "Some variable was an extended term, don't clear list of assertions."
+ << std::endl;
+ return false;
+ }
+ Trace("nl-cad") << "Constructed a full assignment, clear list of assertions."
+ << std::endl;
+ assertions.clear();
+ return true;
+#else
+ Warning() << "Tried to use CadSolver but libpoly is not available. Compile "
+ "with --poly."
+ << std::endl;
+ return false;
+#endif
+}
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/nl/cad_solver.h b/src/theory/arith/nl/cad_solver.h
new file mode 100644
index 000000000..4d537213f
--- /dev/null
+++ b/src/theory/arith/nl/cad_solver.h
@@ -0,0 +1,102 @@
+/********************* */
+/*! \file cad_solver.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief CAD-based solver based on https://arxiv.org/pdf/2003.05633.pdf.
+ **/
+
+#ifndef CVC4__THEORY__ARITH__CAD_SOLVER_H
+#define CVC4__THEORY__ARITH__CAD_SOLVER_H
+
+#include <vector>
+
+#include "expr/node.h"
+#include "theory/arith/inference_manager.h"
+#include "theory/arith/nl/cad/cdcac.h"
+#include "theory/arith/nl/nl_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+/**
+ * A solver for nonlinear arithmetic that implements the CAD-based method
+ * described in https://arxiv.org/pdf/2003.05633.pdf.
+ */
+class CadSolver
+{
+ public:
+ CadSolver(InferenceManager& im, NlModel& model);
+ ~CadSolver();
+
+ /**
+ * This is called at the beginning of last call effort check, where
+ * assertions are the set of assertions belonging to arithmetic,
+ * false_asserts is the subset of assertions that are false in the current
+ * model, and xts is the set of extended function terms that are active in
+ * the current context.
+ */
+ void initLastCall(const std::vector<Node>& assertions);
+
+ /**
+ * Perform a full check, returning either {} or a single lemma.
+ * If the result is empty, the input is satisfiable and a model is available
+ * for construct_model_if_available. Otherwise, the single lemma can be used
+ * as an infeasible subset.
+ */
+ void checkFull();
+
+ /**
+ * Perform a partial check, returning either {} or a list of lemmas.
+ * If the result is empty, the input is satisfiable and a model is available
+ * for construct_model_if_available. Otherwise, the lemmas exclude some part
+ * of the search space.
+ */
+ void checkPartial();
+
+ /**
+ * If a model is available (indicated by the last call to check_full() or
+ * check_partial()) this method puts a satisfying assignment in d_model,
+ * clears the list of assertions, and returns true.
+ * Otherwise, this method returns false.
+ */
+ bool constructModelIfAvailable(std::vector<Node>& assertions);
+
+ private:
+ /**
+ * The variable used to encode real algebraic numbers to nodes.
+ */
+ Node d_ranVariable;
+
+#ifdef CVC4_POLY_IMP
+ /**
+ * The object implementing the actual decision procedure.
+ */
+ cad::CDCAC d_CAC;
+#endif
+ /**
+ * Indicates whether we found satisfiability in the last call to
+ * checkFullRefine.
+ */
+ bool d_foundSatisfiability;
+
+ /** The inference manager we are pushing conflicts and lemmas to. */
+ InferenceManager& d_im;
+ /** Reference to the non-linear model object */
+ NlModel& d_model;
+}; /* class CadSolver */
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__ARITH__CAD_SOLVER_H */
diff --git a/src/theory/arith/nl/nl_constraint.cpp b/src/theory/arith/nl/ext/constraint.cpp
index ae678ccdf..f395ee2d4 100644
--- a/src/theory/arith/nl/nl_constraint.cpp
+++ b/src/theory/arith/nl/ext/constraint.cpp
@@ -1,18 +1,18 @@
/********************* */
-/*! \file nl_constraint.cpp
+/*! \file constraint.cpp
** \verbatim
** Top contributors (to current version):
** Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
** \brief Implementation of utilities for non-linear constraints
**/
-#include "theory/arith/nl/nl_constraint.h"
+#include "theory/arith/nl/ext/constraint.h"
#include "theory/arith/arith_msum.h"
#include "theory/arith/arith_utilities.h"
diff --git a/src/theory/arith/nl/nl_constraint.h b/src/theory/arith/nl/ext/constraint.h
index 113c573d8..699d5b350 100644
--- a/src/theory/arith/nl/nl_constraint.h
+++ b/src/theory/arith/nl/ext/constraint.h
@@ -1,26 +1,26 @@
/********************* */
-/*! \file nl_constraint.h
+/*! \file constraint.h
** \verbatim
** Top contributors (to current version):
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
** \brief Utilities for non-linear constraints
**/
-#ifndef CVC4__THEORY__ARITH__NL__NL_CONSTRAINT_H
-#define CVC4__THEORY__ARITH__NL__NL_CONSTRAINT_H
+#ifndef CVC4__THEORY__ARITH__NL__EXT__CONSTRAINT_H
+#define CVC4__THEORY__ARITH__NL__EXT__CONSTRAINT_H
#include <map>
#include <vector>
#include "expr/kind.h"
#include "expr/node.h"
-#include "theory/arith/nl/nl_monomial.h"
+#include "theory/arith/nl/ext/monomial.h"
namespace CVC4 {
namespace theory {
diff --git a/src/theory/arith/nl/ext/ext_state.cpp b/src/theory/arith/nl/ext/ext_state.cpp
new file mode 100644
index 000000000..3ac4699a7
--- /dev/null
+++ b/src/theory/arith/nl/ext/ext_state.cpp
@@ -0,0 +1,95 @@
+/********************* */
+/*! \file shared_check_data.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Common data shared by multiple checks
+ **/
+
+#include "theory/arith/nl/ext/ext_state.h"
+
+#include <vector>
+
+#include "expr/node.h"
+#include "theory/arith/inference_manager.h"
+#include "theory/arith/nl/ext/monomial.h"
+#include "theory/arith/nl/nl_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+ExtState::ExtState(InferenceManager& im, NlModel& model, context::Context* c)
+ : d_im(im), d_model(model)
+{
+ d_false = NodeManager::currentNM()->mkConst(false);
+ d_true = NodeManager::currentNM()->mkConst(true);
+ d_zero = NodeManager::currentNM()->mkConst(Rational(0));
+ d_one = NodeManager::currentNM()->mkConst(Rational(1));
+ d_neg_one = NodeManager::currentNM()->mkConst(Rational(-1));
+}
+
+void ExtState::init(const std::vector<Node>& xts)
+{
+ d_ms_vars.clear();
+ d_ms.clear();
+ d_mterms.clear();
+ d_tplane_refine.clear();
+
+ Trace("nl-ext-mv") << "Extended terms : " << std::endl;
+ // for computing congruence
+ std::map<Kind, ArgTrie> argTrie;
+ for (unsigned i = 0, xsize = xts.size(); i < xsize; i++)
+ {
+ Node a = xts[i];
+ d_model.computeConcreteModelValue(a);
+ d_model.computeAbstractModelValue(a);
+ d_model.printModelValue("nl-ext-mv", a);
+ Kind ak = a.getKind();
+ if (ak == Kind::NONLINEAR_MULT)
+ {
+ d_ms.push_back(a);
+
+ // context-independent registration
+ d_mdb.registerMonomial(a);
+
+ const std::vector<Node>& varList = d_mdb.getVariableList(a);
+ for (const Node& v : varList)
+ {
+ if (std::find(d_ms_vars.begin(), d_ms_vars.end(), v) == d_ms_vars.end())
+ {
+ d_ms_vars.push_back(v);
+ }
+ }
+ // mark processed if has a "one" factor (will look at reduced monomial)?
+ }
+ }
+
+ // register constants
+ d_mdb.registerMonomial(d_one);
+
+ // register variables
+ Trace("nl-ext-mv") << "Variables in monomials : " << std::endl;
+ for (unsigned i = 0; i < d_ms_vars.size(); i++)
+ {
+ Node v = d_ms_vars[i];
+ d_mdb.registerMonomial(v);
+ d_model.computeConcreteModelValue(v);
+ d_model.computeAbstractModelValue(v);
+ d_model.printModelValue("nl-ext-mv", v);
+ }
+
+ Trace("nl-ext") << "We have " << d_ms.size() << " monomials." << std::endl;
+}
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/nl/ext/ext_state.h b/src/theory/arith/nl/ext/ext_state.h
new file mode 100644
index 000000000..64c9c6b94
--- /dev/null
+++ b/src/theory/arith/nl/ext/ext_state.h
@@ -0,0 +1,67 @@
+/********************* */
+/*! \file shared_check_data.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Common data shared by multiple checks
+ **/
+
+#ifndef CVC4__THEORY__ARITH__NL__EXT__SHARED_CHECK_DATA_H
+#define CVC4__THEORY__ARITH__NL__EXT__SHARED_CHECK_DATA_H
+
+#include <vector>
+
+#include "expr/node.h"
+#include "expr/proof.h"
+#include "theory/arith/inference_manager.h"
+#include "theory/arith/nl/ext/monomial.h"
+#include "theory/arith/nl/nl_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+struct ExtState
+{
+ ExtState(InferenceManager& im, NlModel& model, context::Context* c);
+
+ void init(const std::vector<Node>& xts);
+
+ Node d_false;
+ Node d_true;
+ Node d_zero;
+ Node d_one;
+ Node d_neg_one;
+
+ /** The inference manager that we push conflicts and lemmas to. */
+ InferenceManager& d_im;
+ /** Reference to the non-linear model object */
+ NlModel& d_model;
+
+ // information about monomials
+ std::vector<Node> d_ms;
+ std::vector<Node> d_ms_vars;
+ std::vector<Node> d_mterms;
+
+ /** Context-independent database of monomial information */
+ MonomialDb d_mdb;
+
+ // ( x*y, x*z, y ) for each pair of monomials ( x*y, x*z ) with common factors
+ std::map<Node, std::map<Node, Node> > d_mono_diff;
+ /** the set of monomials we should apply tangent planes to */
+ std::unordered_set<Node, NodeHashFunction> d_tplane_refine;
+};
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/nl/ext/factoring_check.cpp b/src/theory/arith/nl/ext/factoring_check.cpp
new file mode 100644
index 000000000..e329db121
--- /dev/null
+++ b/src/theory/arith/nl/ext/factoring_check.cpp
@@ -0,0 +1,181 @@
+/********************* */
+/*! \file factoring_check.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of factoring check
+ **/
+
+#include "theory/arith/nl/ext/factoring_check.h"
+
+#include "expr/node.h"
+#include "theory/arith/arith_msum.h"
+#include "theory/arith/inference_manager.h"
+#include "theory/arith/nl/nl_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+FactoringCheck::FactoringCheck(InferenceManager& im, NlModel& model)
+ : d_im(im), d_model(model)
+{
+ d_zero = NodeManager::currentNM()->mkConst(Rational(0));
+ d_one = NodeManager::currentNM()->mkConst(Rational(1));
+}
+
+void FactoringCheck::check(const std::vector<Node>& asserts,
+ const std::vector<Node>& false_asserts)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ Trace("nl-ext") << "Get factoring lemmas..." << std::endl;
+ for (const Node& lit : asserts)
+ {
+ bool polarity = lit.getKind() != Kind::NOT;
+ Node atom = lit.getKind() == Kind::NOT ? lit[0] : lit;
+ Node litv = d_model.computeConcreteModelValue(lit);
+ bool considerLit = false;
+ // Only consider literals that are in false_asserts.
+ considerLit = std::find(false_asserts.begin(), false_asserts.end(), lit)
+ != false_asserts.end();
+
+ if (considerLit)
+ {
+ std::map<Node, Node> msum;
+ if (ArithMSum::getMonomialSumLit(atom, msum))
+ {
+ Trace("nl-ext-factor") << "Factoring for literal " << lit
+ << ", monomial sum is : " << std::endl;
+ if (Trace.isOn("nl-ext-factor"))
+ {
+ ArithMSum::debugPrintMonomialSum(msum, "nl-ext-factor");
+ }
+ std::map<Node, std::vector<Node> > factor_to_mono;
+ std::map<Node, std::vector<Node> > factor_to_mono_orig;
+ for (std::map<Node, Node>::iterator itm = msum.begin();
+ itm != msum.end();
+ ++itm)
+ {
+ if (!itm->first.isNull())
+ {
+ if (itm->first.getKind() == Kind::NONLINEAR_MULT)
+ {
+ std::vector<Node> children;
+ for (unsigned i = 0; i < itm->first.getNumChildren(); i++)
+ {
+ children.push_back(itm->first[i]);
+ }
+ std::map<Node, bool> processed;
+ for (unsigned i = 0; i < itm->first.getNumChildren(); i++)
+ {
+ if (processed.find(itm->first[i]) == processed.end())
+ {
+ processed[itm->first[i]] = true;
+ children[i] = d_one;
+ if (!itm->second.isNull())
+ {
+ children.push_back(itm->second);
+ }
+ Node val = nm->mkNode(Kind::MULT, children);
+ if (!itm->second.isNull())
+ {
+ children.pop_back();
+ }
+ children[i] = itm->first[i];
+ val = Rewriter::rewrite(val);
+ factor_to_mono[itm->first[i]].push_back(val);
+ factor_to_mono_orig[itm->first[i]].push_back(itm->first);
+ }
+ }
+ }
+ }
+ }
+ for (std::map<Node, std::vector<Node> >::iterator itf =
+ factor_to_mono.begin();
+ itf != factor_to_mono.end();
+ ++itf)
+ {
+ Node x = itf->first;
+ if (itf->second.size() == 1)
+ {
+ std::map<Node, Node>::iterator itm = msum.find(x);
+ if (itm != msum.end())
+ {
+ itf->second.push_back(itm->second.isNull() ? d_one : itm->second);
+ factor_to_mono_orig[x].push_back(x);
+ }
+ }
+ if (itf->second.size() <= 1)
+ {
+ continue;
+ }
+ Node sum = nm->mkNode(Kind::PLUS, itf->second);
+ sum = Rewriter::rewrite(sum);
+ Trace("nl-ext-factor")
+ << "* Factored sum for " << x << " : " << sum << std::endl;
+ Node kf = getFactorSkolem(sum);
+ std::vector<Node> poly;
+ poly.push_back(nm->mkNode(Kind::MULT, x, kf));
+ std::map<Node, std::vector<Node> >::iterator itfo =
+ factor_to_mono_orig.find(x);
+ Assert(itfo != factor_to_mono_orig.end());
+ for (std::map<Node, Node>::iterator itm = msum.begin();
+ itm != msum.end();
+ ++itm)
+ {
+ if (std::find(itfo->second.begin(), itfo->second.end(), itm->first)
+ == itfo->second.end())
+ {
+ poly.push_back(ArithMSum::mkCoeffTerm(
+ itm->second, itm->first.isNull() ? d_one : itm->first));
+ }
+ }
+ Node polyn =
+ poly.size() == 1 ? poly[0] : nm->mkNode(Kind::PLUS, poly);
+ Trace("nl-ext-factor")
+ << "...factored polynomial : " << polyn << std::endl;
+ Node conc_lit = nm->mkNode(atom.getKind(), polyn, d_zero);
+ conc_lit = Rewriter::rewrite(conc_lit);
+ if (!polarity)
+ {
+ conc_lit = conc_lit.negate();
+ }
+
+ std::vector<Node> lemma_disj;
+ lemma_disj.push_back(lit.negate());
+ lemma_disj.push_back(conc_lit);
+ Node flem = nm->mkNode(Kind::OR, lemma_disj);
+ Trace("nl-ext-factor") << "...lemma is " << flem << std::endl;
+ d_im.addPendingArithLemma(flem, InferenceId::NL_FACTOR);
+ }
+ }
+ }
+ }
+}
+
+Node FactoringCheck::getFactorSkolem(Node n)
+{
+ std::map<Node, Node>::iterator itf = d_factor_skolem.find(n);
+ if (itf == d_factor_skolem.end())
+ {
+ NodeManager* nm = NodeManager::currentNM();
+ Node k = nm->mkSkolem("kf", n.getType());
+ Node k_eq = Rewriter::rewrite(k.eqNode(n));
+ d_im.addPendingArithLemma(k_eq, InferenceId::NL_FACTOR);
+ d_factor_skolem[n] = k;
+ return k;
+ }
+ return itf->second;
+}
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4 \ No newline at end of file
diff --git a/src/theory/arith/nl/ext/factoring_check.h b/src/theory/arith/nl/ext/factoring_check.h
new file mode 100644
index 000000000..8474ac610
--- /dev/null
+++ b/src/theory/arith/nl/ext/factoring_check.h
@@ -0,0 +1,68 @@
+/********************* */
+/*! \file factoring_check.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Check for factoring lemma
+ **/
+
+#ifndef CVC4__THEORY__ARITH__NL__EXT__FACTORING_CHECK_H
+#define CVC4__THEORY__ARITH__NL__EXT__FACTORING_CHECK_H
+
+#include <vector>
+
+#include "expr/node.h"
+#include "theory/arith/inference_manager.h"
+#include "theory/arith/nl/nl_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+class FactoringCheck
+{
+ public:
+ FactoringCheck(InferenceManager& im, NlModel& model);
+
+ /** check factoring
+ *
+ * Returns a set of valid theory lemmas, based on a
+ * lemma schema that states a relationship betwen monomials
+ * with common factors that occur in the same constraint.
+ *
+ * Examples:
+ *
+ * x*z+y*z > t => ( k = x + y ^ k*z > t )
+ * ...where k is fresh and x*z + y*z > t is a
+ * constraint that occurs in the current context.
+ */
+ void check(const std::vector<Node>& asserts,
+ const std::vector<Node>& false_asserts);
+
+ private:
+ /** The inference manager that we push conflicts and lemmas to. */
+ InferenceManager& d_im;
+ /** Reference to the non-linear model object */
+ NlModel& d_model;
+ /** maps nodes to their factor skolems */
+ std::map<Node, Node> d_factor_skolem;
+
+ Node d_zero;
+ Node d_one;
+
+ Node getFactorSkolem(Node n);
+};
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/nl/nl_monomial.cpp b/src/theory/arith/nl/ext/monomial.cpp
index 1cd0a848d..0b46cc88e 100644
--- a/src/theory/arith/nl/nl_monomial.cpp
+++ b/src/theory/arith/nl/ext/monomial.cpp
@@ -1,18 +1,18 @@
/********************* */
-/*! \file nl_monomial.cpp
+/*! \file monomial.cpp
** \verbatim
** Top contributors (to current version):
** Andrew Reynolds, Tim King, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
** \brief Implementation of utilities for monomials
**/
-#include "theory/arith/nl/nl_monomial.h"
+#include "theory/arith/nl/ext/monomial.h"
#include "theory/arith/arith_utilities.h"
#include "theory/arith/nl/nl_lemma_utils.h"
diff --git a/src/theory/arith/nl/nl_monomial.h b/src/theory/arith/nl/ext/monomial.h
index e84233e8e..93a291ca0 100644
--- a/src/theory/arith/nl/nl_monomial.h
+++ b/src/theory/arith/nl/ext/monomial.h
@@ -1,19 +1,19 @@
/********************* */
-/*! \file nl_monomial.h
+/*! \file monomial.h
** \verbatim
** Top contributors (to current version):
** Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
** \brief Utilities for monomials
**/
-#ifndef CVC4__THEORY__ARITH__NL__NL_MONOMIAL_H
-#define CVC4__THEORY__ARITH__NL__NL_MONOMIAL_H
+#ifndef CVC4__THEORY__ARITH__NL__EXT__MONOMIAL_H
+#define CVC4__THEORY__ARITH__NL__EXT__MONOMIAL_H
#include <map>
#include <vector>
diff --git a/src/theory/arith/nl/ext/monomial_bounds_check.cpp b/src/theory/arith/nl/ext/monomial_bounds_check.cpp
new file mode 100644
index 000000000..de6a3c65d
--- /dev/null
+++ b/src/theory/arith/nl/ext/monomial_bounds_check.cpp
@@ -0,0 +1,500 @@
+/********************* */
+/*! \file monomial_bounds_check.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Check for monomial bound inference lemmas
+ **/
+
+#include "theory/arith/nl/ext/monomial_bounds_check.h"
+
+#include "expr/node.h"
+#include "options/arith_options.h"
+#include "theory/arith/arith_msum.h"
+#include "theory/arith/arith_utilities.h"
+#include "theory/arith/inference_manager.h"
+#include "theory/arith/nl/nl_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+namespace {
+void debugPrintBound(const char* c, Node coeff, Node x, Kind type, Node rhs)
+{
+ Node t = ArithMSum::mkCoeffTerm(coeff, x);
+ Trace(c) << t << " " << type << " " << rhs;
+}
+
+bool hasNewMonomials(Node n, const std::vector<Node>& existing)
+{
+ std::set<Node> visited;
+
+ std::vector<Node> worklist;
+ worklist.push_back(n);
+ while (!worklist.empty())
+ {
+ Node current = worklist.back();
+ worklist.pop_back();
+ if (visited.find(current) == visited.end())
+ {
+ visited.insert(current);
+ if (current.getKind() == Kind::NONLINEAR_MULT)
+ {
+ if (std::find(existing.begin(), existing.end(), current)
+ == existing.end())
+ {
+ return true;
+ }
+ }
+ else
+ {
+ worklist.insert(worklist.end(), current.begin(), current.end());
+ }
+ }
+ }
+ return false;
+}
+} // namespace
+
+MonomialBoundsCheck::MonomialBoundsCheck(ExtState* data)
+ : d_data(data), d_cdb(d_data->d_mdb)
+{
+}
+
+void MonomialBoundsCheck::init()
+{
+ d_ci.clear();
+ d_ci_exp.clear();
+ d_ci_max.clear();
+}
+
+void MonomialBoundsCheck::checkBounds(const std::vector<Node>& asserts,
+ const std::vector<Node>& false_asserts)
+{
+ // sort monomials by degree
+ Trace("nl-ext-proc") << "Sort monomials by degree..." << std::endl;
+ d_data->d_mdb.sortByDegree(d_data->d_ms);
+ // all monomials
+ d_data->d_mterms.insert(d_data->d_mterms.end(),
+ d_data->d_ms_vars.begin(),
+ d_data->d_ms_vars.end());
+ d_data->d_mterms.insert(
+ d_data->d_mterms.end(), d_data->d_ms.begin(), d_data->d_ms.end());
+
+ const std::map<Node, std::map<Node, ConstraintInfo> >& cim =
+ d_cdb.getConstraints();
+
+ NodeManager* nm = NodeManager::currentNM();
+ // register constraints
+ Trace("nl-ext-debug") << "Register bound constraints..." << std::endl;
+ for (const Node& lit : asserts)
+ {
+ bool polarity = lit.getKind() != Kind::NOT;
+ Node atom = lit.getKind() == Kind::NOT ? lit[0] : lit;
+ d_cdb.registerConstraint(atom);
+ bool is_false_lit =
+ std::find(false_asserts.begin(), false_asserts.end(), lit)
+ != false_asserts.end();
+ // add information about bounds to variables
+ std::map<Node, std::map<Node, ConstraintInfo> >::const_iterator itc =
+ cim.find(atom);
+ if (itc == cim.end())
+ {
+ continue;
+ }
+ for (const std::pair<const Node, ConstraintInfo>& itcc : itc->second)
+ {
+ Node x = itcc.first;
+ Node coeff = itcc.second.d_coeff;
+ Node rhs = itcc.second.d_rhs;
+ Kind type = itcc.second.d_type;
+ Node exp = lit;
+ if (!polarity)
+ {
+ // reverse
+ if (type == Kind::EQUAL)
+ {
+ // we will take the strict inequality in the direction of the
+ // model
+ Node lhs = ArithMSum::mkCoeffTerm(coeff, x);
+ Node query = nm->mkNode(Kind::GT, lhs, rhs);
+ Node query_mv = d_data->d_model.computeAbstractModelValue(query);
+ if (query_mv == d_data->d_true)
+ {
+ exp = query;
+ type = Kind::GT;
+ }
+ else
+ {
+ Assert(query_mv == d_data->d_false);
+ exp = nm->mkNode(Kind::LT, lhs, rhs);
+ type = Kind::LT;
+ }
+ }
+ else
+ {
+ type = negateKind(type);
+ }
+ }
+ // add to status if maximal degree
+ d_ci_max[x][coeff][rhs] = d_cdb.isMaximal(atom, x);
+ if (Trace.isOn("nl-ext-bound-debug2"))
+ {
+ Node t = ArithMSum::mkCoeffTerm(coeff, x);
+ Trace("nl-ext-bound-debug2") << "Add Bound: " << t << " " << type << " "
+ << rhs << " by " << exp << std::endl;
+ }
+ bool updated = true;
+ std::map<Node, Kind>::iterator its = d_ci[x][coeff].find(rhs);
+ if (its == d_ci[x][coeff].end())
+ {
+ d_ci[x][coeff][rhs] = type;
+ d_ci_exp[x][coeff][rhs] = exp;
+ }
+ else if (type != its->second)
+ {
+ Trace("nl-ext-bound-debug2")
+ << "Joining kinds : " << type << " " << its->second << std::endl;
+ Kind jk = joinKinds(type, its->second);
+ if (jk == Kind::UNDEFINED_KIND)
+ {
+ updated = false;
+ }
+ else if (jk != its->second)
+ {
+ if (jk == type)
+ {
+ d_ci[x][coeff][rhs] = type;
+ d_ci_exp[x][coeff][rhs] = exp;
+ }
+ else
+ {
+ d_ci[x][coeff][rhs] = jk;
+ d_ci_exp[x][coeff][rhs] =
+ nm->mkNode(Kind::AND, d_ci_exp[x][coeff][rhs], exp);
+ }
+ }
+ else
+ {
+ updated = false;
+ }
+ }
+ if (Trace.isOn("nl-ext-bound"))
+ {
+ if (updated)
+ {
+ Trace("nl-ext-bound") << "Bound: ";
+ debugPrintBound("nl-ext-bound", coeff, x, d_ci[x][coeff][rhs], rhs);
+ Trace("nl-ext-bound") << " by " << d_ci_exp[x][coeff][rhs];
+ if (d_ci_max[x][coeff][rhs])
+ {
+ Trace("nl-ext-bound") << ", is max degree";
+ }
+ Trace("nl-ext-bound") << std::endl;
+ }
+ }
+ // compute if bound is not satisfied, and store what is required
+ // for a possible refinement
+ if (options::nlExtTangentPlanes())
+ {
+ if (is_false_lit)
+ {
+ d_data->d_tplane_refine.insert(x);
+ }
+ }
+ }
+ }
+ // reflexive constraints
+ Node null_coeff;
+ for (unsigned j = 0; j < d_data->d_mterms.size(); j++)
+ {
+ Node n = d_data->d_mterms[j];
+ d_ci[n][null_coeff][n] = Kind::EQUAL;
+ d_ci_exp[n][null_coeff][n] = d_data->d_true;
+ d_ci_max[n][null_coeff][n] = false;
+ }
+
+ Trace("nl-ext") << "Get inferred bound lemmas..." << std::endl;
+ const std::map<Node, std::vector<Node> >& cpMap =
+ d_data->d_mdb.getContainsParentMap();
+ for (unsigned k = 0; k < d_data->d_mterms.size(); k++)
+ {
+ Node x = d_data->d_mterms[k];
+ Trace("nl-ext-bound-debug")
+ << "Process bounds for " << x << " : " << std::endl;
+ std::map<Node, std::vector<Node> >::const_iterator itm = cpMap.find(x);
+ if (itm == cpMap.end())
+ {
+ Trace("nl-ext-bound-debug") << "...has no parent monomials." << std::endl;
+ continue;
+ }
+ Trace("nl-ext-bound-debug")
+ << "...has " << itm->second.size() << " parent monomials." << std::endl;
+ // check derived bounds
+ std::map<Node, std::map<Node, std::map<Node, Kind> > >::iterator itc =
+ d_ci.find(x);
+ if (itc == d_ci.end())
+ {
+ continue;
+ }
+ for (std::map<Node, std::map<Node, Kind> >::iterator itcc =
+ itc->second.begin();
+ itcc != itc->second.end();
+ ++itcc)
+ {
+ Node coeff = itcc->first;
+ Node t = ArithMSum::mkCoeffTerm(coeff, x);
+ for (std::map<Node, Kind>::iterator itcr = itcc->second.begin();
+ itcr != itcc->second.end();
+ ++itcr)
+ {
+ Node rhs = itcr->first;
+ // only consider this bound if maximal degree
+ if (!d_ci_max[x][coeff][rhs])
+ {
+ continue;
+ }
+ Kind type = itcr->second;
+ for (unsigned j = 0; j < itm->second.size(); j++)
+ {
+ Node y = itm->second[j];
+ Node mult = d_data->d_mdb.getContainsDiff(x, y);
+ // x <k> t => m*x <k'> t where y = m*x
+ // get the sign of mult
+ Node mmv = d_data->d_model.computeConcreteModelValue(mult);
+ Trace("nl-ext-bound-debug2")
+ << "Model value of " << mult << " is " << mmv << std::endl;
+ if (!mmv.isConst())
+ {
+ Trace("nl-ext-bound-debug")
+ << " ...coefficient " << mult
+ << " is non-constant (probably transcendental)." << std::endl;
+ continue;
+ }
+ int mmv_sign = mmv.getConst<Rational>().sgn();
+ Trace("nl-ext-bound-debug2")
+ << " sign of " << mmv << " is " << mmv_sign << std::endl;
+ if (mmv_sign == 0)
+ {
+ Trace("nl-ext-bound-debug")
+ << " ...coefficient " << mult << " is zero." << std::endl;
+ continue;
+ }
+ Trace("nl-ext-bound-debug")
+ << " from " << x << " * " << mult << " = " << y << " and " << t
+ << " " << type << " " << rhs << ", infer : " << std::endl;
+ Kind infer_type = mmv_sign == -1 ? reverseRelationKind(type) : type;
+ Node infer_lhs = nm->mkNode(Kind::MULT, mult, t);
+ Node infer_rhs = nm->mkNode(Kind::MULT, mult, rhs);
+ Node infer = nm->mkNode(infer_type, infer_lhs, infer_rhs);
+ Trace("nl-ext-bound-debug") << " " << infer << std::endl;
+ infer = Rewriter::rewrite(infer);
+ Trace("nl-ext-bound-debug2")
+ << " ...rewritten : " << infer << std::endl;
+ // check whether it is false in model for abstraction
+ Node infer_mv = d_data->d_model.computeAbstractModelValue(infer);
+ Trace("nl-ext-bound-debug")
+ << " ...infer model value is " << infer_mv << std::endl;
+ if (infer_mv == d_data->d_false)
+ {
+ Node exp = nm->mkNode(
+ Kind::AND,
+ nm->mkNode(
+ mmv_sign == 1 ? Kind::GT : Kind::LT, mult, d_data->d_zero),
+ d_ci_exp[x][coeff][rhs]);
+ Node iblem = nm->mkNode(Kind::IMPLIES, exp, infer);
+ Node pr_iblem = iblem;
+ iblem = Rewriter::rewrite(iblem);
+ bool introNewTerms = hasNewMonomials(iblem, d_data->d_ms);
+ Trace("nl-ext-bound-lemma")
+ << "*** Bound inference lemma : " << iblem
+ << " (pre-rewrite : " << pr_iblem << ")" << std::endl;
+ // Trace("nl-ext-bound-lemma") << " intro new
+ // monomials = " << introNewTerms << std::endl;
+ d_data->d_im.addPendingArithLemma(
+ iblem, InferenceId::NL_INFER_BOUNDS_NT, nullptr, introNewTerms);
+ }
+ }
+ }
+ }
+ }
+}
+
+void MonomialBoundsCheck::checkResBounds()
+{
+ NodeManager* nm = NodeManager::currentNM();
+ Trace("nl-ext") << "Get monomial resolution inferred bound lemmas..."
+ << std::endl;
+ size_t nmterms = d_data->d_mterms.size();
+ for (unsigned j = 0; j < nmterms; j++)
+ {
+ Node a = d_data->d_mterms[j];
+ std::map<Node, std::map<Node, std::map<Node, Kind> > >::iterator itca =
+ d_ci.find(a);
+ if (itca == d_ci.end())
+ {
+ continue;
+ }
+ for (unsigned k = (j + 1); k < nmterms; k++)
+ {
+ Node b = d_data->d_mterms[k];
+ std::map<Node, std::map<Node, std::map<Node, Kind> > >::iterator itcb =
+ d_ci.find(b);
+ if (itcb == d_ci.end())
+ {
+ continue;
+ }
+ Trace("nl-ext-rbound-debug") << "resolution inferences : compare " << a
+ << " and " << b << std::endl;
+ // if they have common factors
+ std::map<Node, Node>::iterator ita = d_data->d_mono_diff[a].find(b);
+ if (ita == d_data->d_mono_diff[a].end())
+ {
+ continue;
+ }
+ Trace("nl-ext-rbound") << "Get resolution inferences for [a] " << a
+ << " vs [b] " << b << std::endl;
+ std::map<Node, Node>::iterator itb = d_data->d_mono_diff[b].find(a);
+ Assert(itb != d_data->d_mono_diff[b].end());
+ Node mv_a = d_data->d_model.computeAbstractModelValue(ita->second);
+ Assert(mv_a.isConst());
+ int mv_a_sgn = mv_a.getConst<Rational>().sgn();
+ if (mv_a_sgn == 0)
+ {
+ // we don't compare monomials whose current model value is zero
+ continue;
+ }
+ Node mv_b = d_data->d_model.computeAbstractModelValue(itb->second);
+ Assert(mv_b.isConst());
+ int mv_b_sgn = mv_b.getConst<Rational>().sgn();
+ if (mv_b_sgn == 0)
+ {
+ // we don't compare monomials whose current model value is zero
+ continue;
+ }
+ Trace("nl-ext-rbound") << " [a] factor is " << ita->second
+ << ", sign in model = " << mv_a_sgn << std::endl;
+ Trace("nl-ext-rbound") << " [b] factor is " << itb->second
+ << ", sign in model = " << mv_b_sgn << std::endl;
+
+ std::vector<Node> exp;
+ // bounds of a
+ for (std::map<Node, std::map<Node, Kind> >::iterator itcac =
+ itca->second.begin();
+ itcac != itca->second.end();
+ ++itcac)
+ {
+ Node coeff_a = itcac->first;
+ for (std::map<Node, Kind>::iterator itcar = itcac->second.begin();
+ itcar != itcac->second.end();
+ ++itcar)
+ {
+ Node rhs_a = itcar->first;
+ Node rhs_a_res_base = nm->mkNode(Kind::MULT, itb->second, rhs_a);
+ rhs_a_res_base = Rewriter::rewrite(rhs_a_res_base);
+ if (hasNewMonomials(rhs_a_res_base, d_data->d_ms))
+ {
+ continue;
+ }
+ Kind type_a = itcar->second;
+ exp.push_back(d_ci_exp[a][coeff_a][rhs_a]);
+
+ // bounds of b
+ for (std::map<Node, std::map<Node, Kind> >::iterator itcbc =
+ itcb->second.begin();
+ itcbc != itcb->second.end();
+ ++itcbc)
+ {
+ Node coeff_b = itcbc->first;
+ Node rhs_a_res = ArithMSum::mkCoeffTerm(coeff_b, rhs_a_res_base);
+ for (std::map<Node, Kind>::iterator itcbr = itcbc->second.begin();
+ itcbr != itcbc->second.end();
+ ++itcbr)
+ {
+ Node rhs_b = itcbr->first;
+ Node rhs_b_res = nm->mkNode(Kind::MULT, ita->second, rhs_b);
+ rhs_b_res = ArithMSum::mkCoeffTerm(coeff_a, rhs_b_res);
+ rhs_b_res = Rewriter::rewrite(rhs_b_res);
+ if (hasNewMonomials(rhs_b_res, d_data->d_ms))
+ {
+ continue;
+ }
+ Kind type_b = itcbr->second;
+ exp.push_back(d_ci_exp[b][coeff_b][rhs_b]);
+ if (Trace.isOn("nl-ext-rbound"))
+ {
+ Trace("nl-ext-rbound") << "* try bounds : ";
+ debugPrintBound("nl-ext-rbound", coeff_a, a, type_a, rhs_a);
+ Trace("nl-ext-rbound") << std::endl;
+ Trace("nl-ext-rbound") << " ";
+ debugPrintBound("nl-ext-rbound", coeff_b, b, type_b, rhs_b);
+ Trace("nl-ext-rbound") << std::endl;
+ }
+ Kind types[2];
+ for (unsigned r = 0; r < 2; r++)
+ {
+ Node pivot_factor = r == 0 ? itb->second : ita->second;
+ int pivot_factor_sign = r == 0 ? mv_b_sgn : mv_a_sgn;
+ types[r] = r == 0 ? type_a : type_b;
+ if (pivot_factor_sign == (r == 0 ? 1 : -1))
+ {
+ types[r] = reverseRelationKind(types[r]);
+ }
+ if (pivot_factor_sign == 1)
+ {
+ exp.push_back(
+ nm->mkNode(Kind::GT, pivot_factor, d_data->d_zero));
+ }
+ else
+ {
+ exp.push_back(
+ nm->mkNode(Kind::LT, pivot_factor, d_data->d_zero));
+ }
+ }
+ Kind jk = transKinds(types[0], types[1]);
+ Trace("nl-ext-rbound-debug")
+ << "trans kind : " << types[0] << " + " << types[1] << " = "
+ << jk << std::endl;
+ if (jk != Kind::UNDEFINED_KIND)
+ {
+ Node conc = nm->mkNode(jk, rhs_a_res, rhs_b_res);
+ Node conc_mv = d_data->d_model.computeAbstractModelValue(conc);
+ if (conc_mv == d_data->d_false)
+ {
+ Node rblem = nm->mkNode(Kind::IMPLIES, nm->mkAnd(exp), conc);
+ Trace("nl-ext-rbound-lemma-debug")
+ << "Resolution bound lemma "
+ "(pre-rewrite) "
+ ": "
+ << rblem << std::endl;
+ rblem = Rewriter::rewrite(rblem);
+ Trace("nl-ext-rbound-lemma")
+ << "Resolution bound lemma : " << rblem << std::endl;
+ d_data->d_im.addPendingArithLemma(
+ rblem, InferenceId::NL_RES_INFER_BOUNDS);
+ }
+ }
+ exp.pop_back();
+ exp.pop_back();
+ exp.pop_back();
+ }
+ }
+ exp.pop_back();
+ }
+ }
+ }
+ }
+}
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/nl/ext/monomial_bounds_check.h b/src/theory/arith/nl/ext/monomial_bounds_check.h
new file mode 100644
index 000000000..d919b1272
--- /dev/null
+++ b/src/theory/arith/nl/ext/monomial_bounds_check.h
@@ -0,0 +1,90 @@
+/********************* */
+/*! \file monomial_bounds_check.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Check for monomial bound inference lemmas
+ **/
+
+#ifndef CVC4__THEORY__ARITH__NL__EXT__MONOMIAL_BOUNDS_CHECK_H
+#define CVC4__THEORY__ARITH__NL__EXT__MONOMIAL_BOUNDS_CHECK_H
+
+#include "expr/node.h"
+#include "theory/arith/nl/ext/constraint.h"
+#include "theory/arith/nl/ext/ext_state.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+class MonomialBoundsCheck
+{
+ public:
+ MonomialBoundsCheck(ExtState* data);
+
+ void init();
+
+ /** check monomial inferred bounds
+ *
+ * Returns a set of valid theory lemmas, based on a
+ * lemma schema that infers new constraints about existing
+ * terms based on mulitplying both sides of an existing
+ * constraint by a term.
+ * For more details, see Section 5 of "Design Theory
+ * Solvers with Extensions" by Reynolds et al., FroCoS 2017,
+ * Figure 5, this is the schema "Multiply".
+ *
+ * Examples:
+ *
+ * x > 0 ^ (y > z + w) => x*y > x*(z+w)
+ * x < 0 ^ (y > z + w) => x*y < x*(z+w)
+ * ...where (y > z + w) and x*y are a constraint and term
+ * that occur in the current context.
+ */
+ void checkBounds(const std::vector<Node>& asserts,
+ const std::vector<Node>& false_asserts);
+
+ /** check monomial infer resolution bounds
+ *
+ * Returns a set of valid theory lemmas, based on a
+ * lemma schema which "resolves" upper bounds
+ * of one inequality with lower bounds for another.
+ * This schema is not enabled by default, and can
+ * be enabled by --nl-ext-rbound.
+ *
+ * Examples:
+ *
+ * ( y>=0 ^ s <= x*z ^ x*y <= t ) => y*s <= z*t
+ * ...where s <= x*z and x*y <= t are constraints
+ * that occur in the current context.
+ */
+ void checkResBounds();
+
+ private:
+ /** Basic data that is shared with other checks */
+ ExtState* d_data;
+
+ /** Context-independent database of constraint information */
+ ConstraintDb d_cdb;
+
+ // term -> coeff -> rhs -> ( status, exp, b ),
+ // where we have that : exp => ( coeff * term <status> rhs )
+ // b is true if degree( term ) >= degree( rhs )
+ std::map<Node, std::map<Node, std::map<Node, Kind> > > d_ci;
+ std::map<Node, std::map<Node, std::map<Node, Node> > > d_ci_exp;
+ std::map<Node, std::map<Node, std::map<Node, bool> > > d_ci_max;
+};
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/nl/ext/monomial_check.cpp b/src/theory/arith/nl/ext/monomial_check.cpp
new file mode 100644
index 000000000..3b8d52c13
--- /dev/null
+++ b/src/theory/arith/nl/ext/monomial_check.cpp
@@ -0,0 +1,740 @@
+/********************* */
+/*! \file monomial_check.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Check for some monomial lemmas
+ **/
+
+#include "theory/arith/nl/ext/monomial_check.h"
+
+#include "expr/node.h"
+#include "theory/arith/arith_msum.h"
+#include "theory/arith/inference_manager.h"
+#include "theory/arith/nl/nl_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+MonomialCheck::MonomialCheck(ExtState* data) : d_data(data)
+{
+ d_order_points.push_back(d_data->d_neg_one);
+ d_order_points.push_back(d_data->d_zero);
+ d_order_points.push_back(d_data->d_one);
+}
+
+void MonomialCheck::init(const std::vector<Node>& xts)
+{
+ d_ms_proc.clear();
+ d_m_nconst_factor.clear();
+
+ for (unsigned i = 0, xsize = xts.size(); i < xsize; i++)
+ {
+ Node a = xts[i];
+ if (a.getKind() == Kind::NONLINEAR_MULT)
+ {
+ const std::vector<Node>& varList = d_data->d_mdb.getVariableList(a);
+ for (const Node& v : varList)
+ {
+ Node mvk = d_data->d_model.computeAbstractModelValue(v);
+ if (!mvk.isConst())
+ {
+ d_m_nconst_factor[a] = true;
+ }
+ }
+ }
+ }
+
+ for (unsigned j = 0; j < d_order_points.size(); j++)
+ {
+ Node c = d_order_points[j];
+ d_data->d_model.computeConcreteModelValue(c);
+ d_data->d_model.computeAbstractModelValue(c);
+ }
+}
+
+void MonomialCheck::checkSign()
+{
+ std::map<Node, int> signs;
+ Trace("nl-ext") << "Get monomial sign lemmas..." << std::endl;
+ for (unsigned j = 0; j < d_data->d_ms.size(); j++)
+ {
+ Node a = d_data->d_ms[j];
+ if (d_ms_proc.find(a) == d_ms_proc.end())
+ {
+ std::vector<Node> exp;
+ if (Trace.isOn("nl-ext-debug"))
+ {
+ Node cmva = d_data->d_model.computeConcreteModelValue(a);
+ Trace("nl-ext-debug")
+ << " process " << a << ", mv=" << cmva << "..." << std::endl;
+ }
+ if (d_m_nconst_factor.find(a) == d_m_nconst_factor.end())
+ {
+ signs[a] = compareSign(a, a, 0, 1, exp);
+ if (signs[a] == 0)
+ {
+ d_ms_proc[a] = true;
+ Trace("nl-ext-debug")
+ << "...mark " << a << " reduced since its value is 0."
+ << std::endl;
+ }
+ }
+ else
+ {
+ Trace("nl-ext-debug")
+ << "...can't conclude sign lemma for " << a
+ << " since model value of a factor is non-constant." << std::endl;
+ }
+ }
+ }
+}
+
+void MonomialCheck::checkMagnitude(unsigned c)
+{
+ // ensure information is setup
+ if (c == 0)
+ {
+ // sort by absolute values of abstract model values
+ assignOrderIds(d_data->d_ms_vars, d_order_vars, false, true);
+
+ // sort individual variable lists
+ Trace("nl-ext-proc") << "Assign order var lists..." << std::endl;
+ d_data->d_mdb.sortVariablesByModel(d_data->d_ms, d_data->d_model);
+ }
+
+ unsigned r = 1;
+ std::vector<ArithLemma> lemmas;
+ // if (x,y,L) in cmp_infers, then x > y inferred as conclusion of L
+ // in lemmas
+ std::map<int, std::map<Node, std::map<Node, Node> > > cmp_infers;
+ Trace("nl-ext") << "Get monomial comparison lemmas (order=" << r
+ << ", compare=" << c << ")..." << std::endl;
+ for (unsigned j = 0; j < d_data->d_ms.size(); j++)
+ {
+ Node a = d_data->d_ms[j];
+ if (d_ms_proc.find(a) == d_ms_proc.end()
+ && d_m_nconst_factor.find(a) == d_m_nconst_factor.end())
+ {
+ if (c == 0)
+ {
+ // compare magnitude against 1
+ std::vector<Node> exp;
+ NodeMultiset a_exp_proc;
+ NodeMultiset b_exp_proc;
+ compareMonomial(a,
+ a,
+ a_exp_proc,
+ d_data->d_one,
+ d_data->d_one,
+ b_exp_proc,
+ exp,
+ lemmas,
+ cmp_infers);
+ }
+ else
+ {
+ const NodeMultiset& mea = d_data->d_mdb.getMonomialExponentMap(a);
+ if (c == 1)
+ {
+ // could compare not just against containing variables?
+ // compare magnitude against variables
+ for (unsigned k = 0; k < d_data->d_ms_vars.size(); k++)
+ {
+ Node v = d_data->d_ms_vars[k];
+ Node mvcv = d_data->d_model.computeConcreteModelValue(v);
+ if (mvcv.isConst())
+ {
+ std::vector<Node> exp;
+ NodeMultiset a_exp_proc;
+ NodeMultiset b_exp_proc;
+ if (mea.find(v) != mea.end())
+ {
+ a_exp_proc[v] = 1;
+ b_exp_proc[v] = 1;
+ setMonomialFactor(a, v, a_exp_proc);
+ setMonomialFactor(v, a, b_exp_proc);
+ compareMonomial(a,
+ a,
+ a_exp_proc,
+ v,
+ v,
+ b_exp_proc,
+ exp,
+ lemmas,
+ cmp_infers);
+ }
+ }
+ }
+ }
+ else
+ {
+ // compare magnitude against other non-linear monomials
+ for (unsigned k = (j + 1); k < d_data->d_ms.size(); k++)
+ {
+ Node b = d_data->d_ms[k];
+ //(signs[a]==signs[b])==(r==0)
+ if (d_ms_proc.find(b) == d_ms_proc.end()
+ && d_m_nconst_factor.find(b) == d_m_nconst_factor.end())
+ {
+ const NodeMultiset& meb = d_data->d_mdb.getMonomialExponentMap(b);
+
+ std::vector<Node> exp;
+ // take common factors of monomials, set minimum of
+ // common exponents as processed
+ NodeMultiset a_exp_proc;
+ NodeMultiset b_exp_proc;
+ for (NodeMultiset::const_iterator itmea2 = mea.begin();
+ itmea2 != mea.end();
+ ++itmea2)
+ {
+ NodeMultiset::const_iterator itmeb2 = meb.find(itmea2->first);
+ if (itmeb2 != meb.end())
+ {
+ unsigned min_exp = itmea2->second > itmeb2->second
+ ? itmeb2->second
+ : itmea2->second;
+ a_exp_proc[itmea2->first] = min_exp;
+ b_exp_proc[itmea2->first] = min_exp;
+ Trace("nl-ext-comp") << "Common exponent : " << itmea2->first
+ << " : " << min_exp << std::endl;
+ }
+ }
+ if (!a_exp_proc.empty())
+ {
+ setMonomialFactor(a, b, a_exp_proc);
+ setMonomialFactor(b, a, b_exp_proc);
+ }
+ /*
+ if( !a_exp_proc.empty() ){
+ //reduction based on common exponents a > 0 => ( a * b
+ <> a * c <=> b <> c ), a < 0 => ( a * b <> a * c <=> b
+ !<> c ) ? }else{ compareMonomial( a, a, a_exp_proc, b,
+ b, b_exp_proc, exp, lemmas );
+ }
+ */
+ compareMonomial(
+ a, a, a_exp_proc, b, b, b_exp_proc, exp, lemmas, cmp_infers);
+ }
+ }
+ }
+ }
+ }
+ }
+ // remove redundant lemmas, e.g. if a > b, b > c, a > c were
+ // inferred, discard lemma with conclusion a > c
+ Trace("nl-ext-comp") << "Compute redundancies for " << lemmas.size()
+ << " lemmas." << std::endl;
+ // naive
+ std::unordered_set<Node, NodeHashFunction> r_lemmas;
+ for (std::map<int, std::map<Node, std::map<Node, Node> > >::iterator itb =
+ cmp_infers.begin();
+ itb != cmp_infers.end();
+ ++itb)
+ {
+ for (std::map<Node, std::map<Node, Node> >::iterator itc =
+ itb->second.begin();
+ itc != itb->second.end();
+ ++itc)
+ {
+ for (std::map<Node, Node>::iterator itc2 = itc->second.begin();
+ itc2 != itc->second.end();
+ ++itc2)
+ {
+ std::map<Node, bool> visited;
+ for (std::map<Node, Node>::iterator itc3 = itc->second.begin();
+ itc3 != itc->second.end();
+ ++itc3)
+ {
+ if (itc3->first != itc2->first)
+ {
+ std::vector<Node> exp;
+ if (cmp_holds(itc3->first, itc2->first, itb->second, exp, visited))
+ {
+ r_lemmas.insert(itc2->second);
+ Trace("nl-ext-comp")
+ << "...inference of " << itc->first << " > " << itc2->first
+ << " was redundant." << std::endl;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ for (unsigned i = 0; i < lemmas.size(); i++)
+ {
+ if (r_lemmas.find(lemmas[i].d_node) == r_lemmas.end())
+ {
+ d_data->d_im.addPendingArithLemma(lemmas[i]);
+ }
+ }
+ // could only take maximal lower/minimial lower bounds?
+}
+
+// show a <> 0 by inequalities between variables in monomial a w.r.t 0
+int MonomialCheck::compareSign(
+ Node oa, Node a, unsigned a_index, int status, std::vector<Node>& exp)
+{
+ Trace("nl-ext-debug") << "Process " << a << " at index " << a_index
+ << ", status is " << status << std::endl;
+ NodeManager* nm = NodeManager::currentNM();
+ Node mvaoa = d_data->d_model.computeAbstractModelValue(oa);
+ const std::vector<Node>& vla = d_data->d_mdb.getVariableList(a);
+ if (a_index == vla.size())
+ {
+ if (mvaoa.getConst<Rational>().sgn() != status)
+ {
+ Node lemma =
+ nm->mkAnd(exp).impNode(mkLit(oa, d_data->d_zero, status * 2));
+ d_data->d_im.addPendingArithLemma(lemma, InferenceId::NL_SIGN);
+ }
+ return status;
+ }
+ Assert(a_index < vla.size());
+ Node av = vla[a_index];
+ unsigned aexp = d_data->d_mdb.getExponent(a, av);
+ // take current sign in model
+ Node mvaav = d_data->d_model.computeAbstractModelValue(av);
+ int sgn = mvaav.getConst<Rational>().sgn();
+ Trace("nl-ext-debug") << "Process var " << av << "^" << aexp
+ << ", model sign = " << sgn << std::endl;
+ if (sgn == 0)
+ {
+ if (mvaoa.getConst<Rational>().sgn() != 0)
+ {
+ Node lemma = av.eqNode(d_data->d_zero).impNode(oa.eqNode(d_data->d_zero));
+ d_data->d_im.addPendingArithLemma(lemma, InferenceId::NL_SIGN);
+ }
+ return 0;
+ }
+ if (aexp % 2 == 0)
+ {
+ exp.push_back(av.eqNode(d_data->d_zero).negate());
+ return compareSign(oa, a, a_index + 1, status, exp);
+ }
+ exp.push_back(nm->mkNode(sgn == 1 ? Kind::GT : Kind::LT, av, d_data->d_zero));
+ return compareSign(oa, a, a_index + 1, status * sgn, exp);
+}
+
+bool MonomialCheck::compareMonomial(
+ Node oa,
+ Node a,
+ NodeMultiset& a_exp_proc,
+ Node ob,
+ Node b,
+ NodeMultiset& b_exp_proc,
+ std::vector<Node>& exp,
+ std::vector<ArithLemma>& lem,
+ std::map<int, std::map<Node, std::map<Node, Node> > >& cmp_infers)
+{
+ Trace("nl-ext-comp-debug")
+ << "Check |" << a << "| >= |" << b << "|" << std::endl;
+ unsigned pexp_size = exp.size();
+ if (compareMonomial(
+ oa, a, 0, a_exp_proc, ob, b, 0, b_exp_proc, 0, exp, lem, cmp_infers))
+ {
+ return true;
+ }
+ exp.resize(pexp_size);
+ Trace("nl-ext-comp-debug")
+ << "Check |" << b << "| >= |" << a << "|" << std::endl;
+ if (compareMonomial(
+ ob, b, 0, b_exp_proc, oa, a, 0, a_exp_proc, 0, exp, lem, cmp_infers))
+ {
+ return true;
+ }
+ return false;
+}
+
+// trying to show a ( >, = ) b by inequalities between variables in
+// monomials a,b
+bool MonomialCheck::compareMonomial(
+ Node oa,
+ Node a,
+ unsigned a_index,
+ NodeMultiset& a_exp_proc,
+ Node ob,
+ Node b,
+ unsigned b_index,
+ NodeMultiset& b_exp_proc,
+ int status,
+ std::vector<Node>& exp,
+ std::vector<ArithLemma>& lem,
+ std::map<int, std::map<Node, std::map<Node, Node> > >& cmp_infers)
+{
+ Trace("nl-ext-comp-debug")
+ << "compareMonomial " << oa << " and " << ob << ", indices = " << a_index
+ << " " << b_index << std::endl;
+ Assert(status == 0 || status == 2);
+ const std::vector<Node>& vla = d_data->d_mdb.getVariableList(a);
+ const std::vector<Node>& vlb = d_data->d_mdb.getVariableList(b);
+ if (a_index == vla.size() && b_index == vlb.size())
+ {
+ // finished, compare absolute value of abstract model values
+ int modelStatus = d_data->d_model.compare(oa, ob, false, true) * -2;
+ Trace("nl-ext-comp") << "...finished comparison with " << oa << " <"
+ << status << "> " << ob
+ << ", model status = " << modelStatus << std::endl;
+ if (status != modelStatus)
+ {
+ Trace("nl-ext-comp-infer")
+ << "infer : " << oa << " <" << status << "> " << ob << std::endl;
+ if (status == 2)
+ {
+ // must state that all variables are non-zero
+ for (unsigned j = 0; j < vla.size(); j++)
+ {
+ exp.push_back(vla[j].eqNode(d_data->d_zero).negate());
+ }
+ }
+ NodeManager* nm = NodeManager::currentNM();
+ Node clem = nm->mkNode(
+ Kind::IMPLIES, nm->mkAnd(exp), mkLit(oa, ob, status, true));
+ Trace("nl-ext-comp-lemma") << "comparison lemma : " << clem << std::endl;
+ lem.emplace_back(
+ clem, LemmaProperty::NONE, nullptr, InferenceId::NL_COMPARISON);
+ cmp_infers[status][oa][ob] = clem;
+ }
+ return true;
+ }
+ // get a/b variable information
+ Node av;
+ unsigned aexp = 0;
+ unsigned avo = 0;
+ if (a_index < vla.size())
+ {
+ av = vla[a_index];
+ unsigned aexpTotal = d_data->d_mdb.getExponent(a, av);
+ Assert(a_exp_proc[av] <= aexpTotal);
+ aexp = aexpTotal - a_exp_proc[av];
+ if (aexp == 0)
+ {
+ return compareMonomial(oa,
+ a,
+ a_index + 1,
+ a_exp_proc,
+ ob,
+ b,
+ b_index,
+ b_exp_proc,
+ status,
+ exp,
+ lem,
+ cmp_infers);
+ }
+ Assert(d_order_vars.find(av) != d_order_vars.end());
+ avo = d_order_vars[av];
+ }
+ Node bv;
+ unsigned bexp = 0;
+ unsigned bvo = 0;
+ if (b_index < vlb.size())
+ {
+ bv = vlb[b_index];
+ unsigned bexpTotal = d_data->d_mdb.getExponent(b, bv);
+ Assert(b_exp_proc[bv] <= bexpTotal);
+ bexp = bexpTotal - b_exp_proc[bv];
+ if (bexp == 0)
+ {
+ return compareMonomial(oa,
+ a,
+ a_index,
+ a_exp_proc,
+ ob,
+ b,
+ b_index + 1,
+ b_exp_proc,
+ status,
+ exp,
+ lem,
+ cmp_infers);
+ }
+ Assert(d_order_vars.find(bv) != d_order_vars.end());
+ bvo = d_order_vars[bv];
+ }
+ // get "one" information
+ Assert(d_order_vars.find(d_data->d_one) != d_order_vars.end());
+ unsigned ovo = d_order_vars[d_data->d_one];
+ Trace("nl-ext-comp-debug") << "....vars : " << av << "^" << aexp << " " << bv
+ << "^" << bexp << std::endl;
+
+ //--- cases
+ if (av.isNull())
+ {
+ if (bvo <= ovo)
+ {
+ Trace("nl-ext-comp-debug") << "...take leading " << bv << std::endl;
+ // can multiply b by <=1
+ exp.push_back(mkLit(d_data->d_one, bv, bvo == ovo ? 0 : 2, true));
+ return compareMonomial(oa,
+ a,
+ a_index,
+ a_exp_proc,
+ ob,
+ b,
+ b_index + 1,
+ b_exp_proc,
+ bvo == ovo ? status : 2,
+ exp,
+ lem,
+ cmp_infers);
+ }
+ Trace("nl-ext-comp-debug")
+ << "...failure, unmatched |b|>1 component." << std::endl;
+ return false;
+ }
+ else if (bv.isNull())
+ {
+ if (avo >= ovo)
+ {
+ Trace("nl-ext-comp-debug") << "...take leading " << av << std::endl;
+ // can multiply a by >=1
+ exp.push_back(mkLit(av, d_data->d_one, avo == ovo ? 0 : 2, true));
+ return compareMonomial(oa,
+ a,
+ a_index + 1,
+ a_exp_proc,
+ ob,
+ b,
+ b_index,
+ b_exp_proc,
+ avo == ovo ? status : 2,
+ exp,
+ lem,
+ cmp_infers);
+ }
+ Trace("nl-ext-comp-debug")
+ << "...failure, unmatched |a|<1 component." << std::endl;
+ return false;
+ }
+ Assert(!av.isNull() && !bv.isNull());
+ if (avo >= bvo)
+ {
+ if (bvo < ovo && avo >= ovo)
+ {
+ Trace("nl-ext-comp-debug") << "...take leading " << av << std::endl;
+ // do avo>=1 instead
+ exp.push_back(mkLit(av, d_data->d_one, avo == ovo ? 0 : 2, true));
+ return compareMonomial(oa,
+ a,
+ a_index + 1,
+ a_exp_proc,
+ ob,
+ b,
+ b_index,
+ b_exp_proc,
+ avo == ovo ? status : 2,
+ exp,
+ lem,
+ cmp_infers);
+ }
+ unsigned min_exp = aexp > bexp ? bexp : aexp;
+ a_exp_proc[av] += min_exp;
+ b_exp_proc[bv] += min_exp;
+ Trace("nl-ext-comp-debug") << "...take leading " << min_exp << " from "
+ << av << " and " << bv << std::endl;
+ exp.push_back(mkLit(av, bv, avo == bvo ? 0 : 2, true));
+ bool ret = compareMonomial(oa,
+ a,
+ a_index,
+ a_exp_proc,
+ ob,
+ b,
+ b_index,
+ b_exp_proc,
+ avo == bvo ? status : 2,
+ exp,
+ lem,
+ cmp_infers);
+ a_exp_proc[av] -= min_exp;
+ b_exp_proc[bv] -= min_exp;
+ return ret;
+ }
+ if (bvo <= ovo)
+ {
+ Trace("nl-ext-comp-debug") << "...take leading " << bv << std::endl;
+ // try multiply b <= 1
+ exp.push_back(mkLit(d_data->d_one, bv, bvo == ovo ? 0 : 2, true));
+ return compareMonomial(oa,
+ a,
+ a_index,
+ a_exp_proc,
+ ob,
+ b,
+ b_index + 1,
+ b_exp_proc,
+ bvo == ovo ? status : 2,
+ exp,
+ lem,
+ cmp_infers);
+ }
+ Trace("nl-ext-comp-debug")
+ << "...failure, leading |b|>|a|>1 component." << std::endl;
+ return false;
+}
+
+bool MonomialCheck::cmp_holds(Node x,
+ Node y,
+ std::map<Node, std::map<Node, Node> >& cmp_infers,
+ std::vector<Node>& exp,
+ std::map<Node, bool>& visited)
+{
+ if (x == y)
+ {
+ return true;
+ }
+ else if (visited.find(x) != visited.end())
+ {
+ return false;
+ }
+ visited[x] = true;
+ std::map<Node, std::map<Node, Node> >::iterator it = cmp_infers.find(x);
+ if (it != cmp_infers.end())
+ {
+ for (std::map<Node, Node>::iterator itc = it->second.begin();
+ itc != it->second.end();
+ ++itc)
+ {
+ exp.push_back(itc->second);
+ if (cmp_holds(itc->first, y, cmp_infers, exp, visited))
+ {
+ return true;
+ }
+ exp.pop_back();
+ }
+ }
+ return false;
+}
+
+void MonomialCheck::assignOrderIds(std::vector<Node>& vars,
+ NodeMultiset& order,
+ bool isConcrete,
+ bool isAbsolute)
+{
+ SortNlModel smv;
+ smv.d_nlm = &d_data->d_model;
+ smv.d_isConcrete = isConcrete;
+ smv.d_isAbsolute = isAbsolute;
+ smv.d_reverse_order = false;
+ std::sort(vars.begin(), vars.end(), smv);
+
+ order.clear();
+ // assign ordering id's
+ unsigned counter = 0;
+ unsigned order_index = isConcrete ? 0 : 1;
+ Node prev;
+ for (unsigned j = 0; j < vars.size(); j++)
+ {
+ Node x = vars[j];
+ Node v = d_data->d_model.computeModelValue(x, isConcrete);
+ if (!v.isConst())
+ {
+ Trace("nl-ext-mvo") << "..do not assign order to " << x << " : " << v
+ << std::endl;
+ // don't assign for non-constant values (transcendental function apps)
+ break;
+ }
+ Trace("nl-ext-mvo") << " order " << x << " : " << v << std::endl;
+ if (v != prev)
+ {
+ // builtin points
+ bool success;
+ do
+ {
+ success = false;
+ if (order_index < d_order_points.size())
+ {
+ Node vv = d_data->d_model.computeModelValue(
+ d_order_points[order_index], isConcrete);
+ if (d_data->d_model.compareValue(v, vv, isAbsolute) <= 0)
+ {
+ counter++;
+ Trace("nl-ext-mvo") << "O[" << d_order_points[order_index]
+ << "] = " << counter << std::endl;
+ order[d_order_points[order_index]] = counter;
+ prev = vv;
+ order_index++;
+ success = true;
+ }
+ }
+ } while (success);
+ }
+ if (prev.isNull() || d_data->d_model.compareValue(v, prev, isAbsolute) != 0)
+ {
+ counter++;
+ }
+ Trace("nl-ext-mvo") << "O[" << x << "] = " << counter << std::endl;
+ order[x] = counter;
+ prev = v;
+ }
+ while (order_index < d_order_points.size())
+ {
+ counter++;
+ Trace("nl-ext-mvo") << "O[" << d_order_points[order_index]
+ << "] = " << counter << std::endl;
+ order[d_order_points[order_index]] = counter;
+ order_index++;
+ }
+}
+Node MonomialCheck::mkLit(Node a, Node b, int status, bool isAbsolute) const
+{
+ if (status == 0)
+ {
+ Node a_eq_b = a.eqNode(b);
+ if (!isAbsolute)
+ {
+ return a_eq_b;
+ }
+ Node negate_b = NodeManager::currentNM()->mkNode(Kind::UMINUS, b);
+ return a_eq_b.orNode(a.eqNode(negate_b));
+ }
+ else if (status < 0)
+ {
+ return mkLit(b, a, -status);
+ }
+ Assert(status == 1 || status == 2);
+ NodeManager* nm = NodeManager::currentNM();
+ Kind greater_op = status == 1 ? Kind::GEQ : Kind::GT;
+ if (!isAbsolute)
+ {
+ return nm->mkNode(greater_op, a, b);
+ }
+ // return nm->mkNode( greater_op, mkAbs( a ), mkAbs( b ) );
+ Node a_is_nonnegative = nm->mkNode(Kind::GEQ, a, d_data->d_zero);
+ Node b_is_nonnegative = nm->mkNode(Kind::GEQ, b, d_data->d_zero);
+ Node negate_a = nm->mkNode(Kind::UMINUS, a);
+ Node negate_b = nm->mkNode(Kind::UMINUS, b);
+ return a_is_nonnegative.iteNode(
+ b_is_nonnegative.iteNode(nm->mkNode(greater_op, a, b),
+ nm->mkNode(greater_op, a, negate_b)),
+ b_is_nonnegative.iteNode(nm->mkNode(greater_op, negate_a, b),
+ nm->mkNode(greater_op, negate_a, negate_b)));
+}
+
+void MonomialCheck::setMonomialFactor(Node a,
+ Node b,
+ const NodeMultiset& common)
+{
+ // Could not tell if this was being inserted intentionally or not.
+ std::map<Node, Node>& mono_diff_a = d_data->d_mono_diff[a];
+ if (mono_diff_a.find(b) == mono_diff_a.end())
+ {
+ Trace("nl-ext-mono-factor")
+ << "Set monomial factor for " << a << "/" << b << std::endl;
+ mono_diff_a[b] = d_data->d_mdb.mkMonomialRemFactor(a, common);
+ }
+}
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4 \ No newline at end of file
diff --git a/src/theory/arith/nl/ext/monomial_check.h b/src/theory/arith/nl/ext/monomial_check.h
new file mode 100644
index 000000000..89b5847a2
--- /dev/null
+++ b/src/theory/arith/nl/ext/monomial_check.h
@@ -0,0 +1,196 @@
+/********************* */
+/*! \file monomial_check.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Check for some monomial lemmas
+ **/
+
+#ifndef CVC4__THEORY__ARITH__NL__EXT__MONOMIAL_CHECK_H
+#define CVC4__THEORY__ARITH__NL__EXT__MONOMIAL_CHECK_H
+
+#include "expr/node.h"
+#include "theory/arith/nl/ext/ext_state.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+class MonomialCheck
+{
+ public:
+ MonomialCheck(ExtState* data);
+
+ void init(const std::vector<Node>& xts);
+
+ /** check monomial sign
+ *
+ * Returns a set of valid theory lemmas, based on a
+ * lemma schema which ensures that non-linear monomials
+ * respect sign information based on their facts.
+ * For more details, see Section 5 of "Design Theory
+ * Solvers with Extensions" by Reynolds et al., FroCoS 2017,
+ * Figure 5, this is the schema "Sign".
+ *
+ * Examples:
+ *
+ * x > 0 ^ y > 0 => x*y > 0
+ * x < 0 => x*y*y < 0
+ * x = 0 => x*y*z = 0
+ */
+ void checkSign();
+
+ /** check monomial magnitude
+ *
+ * Returns a set of valid theory lemmas, based on a
+ * lemma schema which ensures that comparisons between
+ * non-linear monomials respect the magnitude of their
+ * factors.
+ * For more details, see Section 5 of "Design Theory
+ * Solvers with Extensions" by Reynolds et al., FroCoS 2017,
+ * Figure 5, this is the schema "Magnitude".
+ *
+ * Examples:
+ *
+ * |x|>|y| => |x*z|>|y*z|
+ * |x|>|y| ^ |z|>|w| ^ |x|>=1 => |x*x*z*u|>|y*w|
+ *
+ * Argument c indicates the class of inferences to perform for the
+ * (non-linear) monomials in the vector d_ms. 0 : compare non-linear monomials
+ * against 1, 1 : compare non-linear monomials against variables, 2 : compare
+ * non-linear monomials against other non-linear monomials.
+ */
+ void checkMagnitude(unsigned c);
+
+ private:
+ /** In the following functions, status states a relationship
+ * between two arithmetic terms, where:
+ * 0 : equal
+ * 1 : greater than or equal
+ * 2 : greater than
+ * -X : (greater -> less)
+ * TODO (#1287) make this an enum?
+ */
+ /** compute the sign of a.
+ *
+ * Calls to this function are such that :
+ * exp => ( oa = a ^ a <status> 0 )
+ *
+ * This function iterates over the factors of a,
+ * where a_index is the index of the factor in a
+ * we are currently looking at.
+ *
+ * This function returns a status, which indicates
+ * a's relationship to 0.
+ * We add lemmas to lem of the form given by the
+ * lemma schema checkSign(...).
+ */
+ int compareSign(
+ Node oa, Node a, unsigned a_index, int status, std::vector<Node>& exp);
+ /** compare monomials a and b
+ *
+ * Initially, a call to this function is such that :
+ * exp => ( oa = a ^ ob = b )
+ *
+ * This function returns true if we can infer a valid
+ * arithmetic lemma of the form :
+ * P => abs( a ) >= abs( b )
+ * where P is true and abs( a ) >= abs( b ) is false in the
+ * current model.
+ *
+ * This function is implemented by "processing" factors
+ * of monomials a and b until an inference of the above
+ * form can be made. For example, if :
+ * a = x*x*y and b = z*w
+ * Assuming we are trying to show abs( a ) >= abs( c ),
+ * then if abs( M( x ) ) >= abs( M( z ) ) where M is the current model,
+ * then we can add abs( x ) >= abs( z ) to our explanation, and
+ * mark one factor of x as processed in a, and
+ * one factor of z as processed in b. The number of processed factors of a
+ * and b are stored in a_exp_proc and b_exp_proc respectively.
+ *
+ * cmp_infers stores information that is helpful
+ * in discarding redundant inferences. For example,
+ * we do not want to infer abs( x ) >= abs( z ) if
+ * we have already inferred abs( x ) >= abs( y ) and
+ * abs( y ) >= abs( z ).
+ * It stores entries of the form (status,t1,t2)->F,
+ * which indicates that we constructed a lemma F that
+ * showed t1 <status> t2.
+ *
+ * We add lemmas to lem of the form given by the
+ * lemma schema checkMagnitude(...).
+ */
+ bool compareMonomial(
+ Node oa,
+ Node a,
+ NodeMultiset& a_exp_proc,
+ Node ob,
+ Node b,
+ NodeMultiset& b_exp_proc,
+ std::vector<Node>& exp,
+ std::vector<ArithLemma>& lem,
+ std::map<int, std::map<Node, std::map<Node, Node> > >& cmp_infers);
+ /** helper function for above
+ *
+ * The difference is the inputs a_index and b_index, which are the indices of
+ * children (factors) in monomials a and b which we are currently looking at.
+ */
+ bool compareMonomial(
+ Node oa,
+ Node a,
+ unsigned a_index,
+ NodeMultiset& a_exp_proc,
+ Node ob,
+ Node b,
+ unsigned b_index,
+ NodeMultiset& b_exp_proc,
+ int status,
+ std::vector<Node>& exp,
+ std::vector<ArithLemma>& lem,
+ std::map<int, std::map<Node, std::map<Node, Node> > >& cmp_infers);
+ /** Check whether we have already inferred a relationship between monomials
+ * x and y based on the information in cmp_infers. This computes the
+ * transitive closure of the relation stored in cmp_infers.
+ */
+ bool cmp_holds(Node x,
+ Node y,
+ std::map<Node, std::map<Node, Node> >& cmp_infers,
+ std::vector<Node>& exp,
+ std::map<Node, bool>& visited);
+ /** assign order ids */
+ void assignOrderIds(std::vector<Node>& vars,
+ NodeMultiset& d_order,
+ bool isConcrete,
+ bool isAbsolute);
+ /** Make literal */
+ Node mkLit(Node a, Node b, int status, bool isAbsolute = false) const;
+ /** register monomial */
+ void setMonomialFactor(Node a, Node b, const NodeMultiset& common);
+
+ /** Basic data that is shared with other checks */
+ ExtState* d_data;
+
+ std::map<Node, bool> d_ms_proc;
+ // ordering, stores variables and 0,1,-1
+ std::map<Node, unsigned> d_order_vars;
+ std::vector<Node> d_order_points;
+
+ // list of monomials with factors whose model value is non-constant in model
+ // e.g. y*cos( x )
+ std::map<Node, bool> d_m_nconst_factor;
+};
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/nl/ext/split_zero_check.cpp b/src/theory/arith/nl/ext/split_zero_check.cpp
new file mode 100644
index 000000000..fcbf84be4
--- /dev/null
+++ b/src/theory/arith/nl/ext/split_zero_check.cpp
@@ -0,0 +1,54 @@
+/********************* */
+/*! \file split_zero_check.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of split zero check
+ **/
+
+#include "theory/arith/nl/ext/split_zero_check.h"
+
+#include "expr/node.h"
+#include "theory/arith/arith_msum.h"
+#include "theory/arith/inference_manager.h"
+#include "theory/arith/nl/nl_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+SplitZeroCheck::SplitZeroCheck(ExtState* data, context::Context* ctx)
+ : d_data(data), d_zero_split(ctx)
+{
+}
+
+void SplitZeroCheck::check()
+{
+ for (unsigned i = 0; i < d_data->d_ms_vars.size(); i++)
+ {
+ Node v = d_data->d_ms_vars[i];
+ if (d_zero_split.insert(v))
+ {
+ Node eq = v.eqNode(d_data->d_zero);
+ eq = Rewriter::rewrite(eq);
+ d_data->d_im.addPendingPhaseRequirement(eq, true);
+ ArithLemma lem(eq.orNode(eq.negate()),
+ LemmaProperty::NONE,
+ nullptr,
+ InferenceId::NL_SPLIT_ZERO);
+ d_data->d_im.addPendingArithLemma(lem);
+ }
+ }
+}
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4 \ No newline at end of file
diff --git a/src/theory/arith/nl/ext/split_zero_check.h b/src/theory/arith/nl/ext/split_zero_check.h
new file mode 100644
index 000000000..1a9f0a44d
--- /dev/null
+++ b/src/theory/arith/nl/ext/split_zero_check.h
@@ -0,0 +1,53 @@
+/********************* */
+/*! \file split_zero_check.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Check for split zero lemma
+ **/
+
+#ifndef CVC4__THEORY__ARITH__NL__EXT__SPLIT_ZERO_CHECK_H
+#define CVC4__THEORY__ARITH__NL__EXT__SPLIT_ZERO_CHECK_H
+
+#include "expr/node.h"
+#include "theory/arith/nl/ext/ext_state.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+class SplitZeroCheck
+{
+ public:
+ SplitZeroCheck(ExtState* data, context::Context* ctx);
+
+ /** check split zero
+ *
+ * Returns a set of theory lemmas of the form
+ * t = 0 V t != 0
+ * where t is a term that exists in the current context.
+ */
+ void check();
+
+ private:
+ using NodeSet = context::CDHashSet<Node, NodeHashFunction>;
+
+ /** Basic data that is shared with other checks */
+ ExtState* d_data;
+ /** cache of terms t for which we have added the lemma ( t = 0 V t != 0 ). */
+ NodeSet d_zero_split;
+};
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/nl/ext/tangent_plane_check.cpp b/src/theory/arith/nl/ext/tangent_plane_check.cpp
new file mode 100644
index 000000000..3849c8424
--- /dev/null
+++ b/src/theory/arith/nl/ext/tangent_plane_check.cpp
@@ -0,0 +1,148 @@
+/********************* */
+/*! \file tangent_plane_check.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of tangent_plane check
+ **/
+
+#include "theory/arith/nl/ext/tangent_plane_check.h"
+
+#include "expr/node.h"
+#include "theory/arith/arith_msum.h"
+#include "theory/arith/inference_manager.h"
+#include "theory/arith/nl/nl_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+TangentPlaneCheck::TangentPlaneCheck(ExtState* data) : d_data(data) {}
+
+void TangentPlaneCheck::check(bool asWaitingLemmas)
+{
+ Trace("nl-ext") << "Get monomial tangent plane lemmas..." << std::endl;
+ NodeManager* nm = NodeManager::currentNM();
+ const std::map<Node, std::vector<Node> >& ccMap =
+ d_data->d_mdb.getContainsChildrenMap();
+ unsigned kstart = d_data->d_ms_vars.size();
+ for (unsigned k = kstart; k < d_data->d_mterms.size(); k++)
+ {
+ Node t = d_data->d_mterms[k];
+ // if this term requires a refinement
+ if (d_data->d_tplane_refine.find(t) == d_data->d_tplane_refine.end())
+ {
+ continue;
+ }
+ Trace("nl-ext-tplanes")
+ << "Look at monomial requiring refinement : " << t << std::endl;
+ // get a decomposition
+ std::map<Node, std::vector<Node> >::const_iterator it = ccMap.find(t);
+ if (it == ccMap.end())
+ {
+ continue;
+ }
+ std::map<Node, std::map<Node, bool> > dproc;
+ for (unsigned j = 0; j < it->second.size(); j++)
+ {
+ Node tc = it->second[j];
+ if (tc != d_data->d_one)
+ {
+ Node tc_diff = d_data->d_mdb.getContainsDiffNl(tc, t);
+ Assert(!tc_diff.isNull());
+ Node a = tc < tc_diff ? tc : tc_diff;
+ Node b = tc < tc_diff ? tc_diff : tc;
+ if (dproc[a].find(b) == dproc[a].end())
+ {
+ dproc[a][b] = true;
+ Trace("nl-ext-tplanes")
+ << " decomposable into : " << a << " * " << b << std::endl;
+ Node a_v_c = d_data->d_model.computeAbstractModelValue(a);
+ Node b_v_c = d_data->d_model.computeAbstractModelValue(b);
+ // points we will add tangent planes for
+ std::vector<Node> pts[2];
+ pts[0].push_back(a_v_c);
+ pts[1].push_back(b_v_c);
+ // if previously refined
+ bool prevRefine = d_tangent_val_bound[0][a].find(b)
+ != d_tangent_val_bound[0][a].end();
+ // a_min, a_max, b_min, b_max
+ for (unsigned p = 0; p < 4; p++)
+ {
+ Node curr_v = p <= 1 ? a_v_c : b_v_c;
+ if (prevRefine)
+ {
+ Node pt_v = d_tangent_val_bound[p][a][b];
+ Assert(!pt_v.isNull());
+ if (curr_v != pt_v)
+ {
+ Node do_extend = nm->mkNode(
+ (p == 1 || p == 3) ? Kind::GT : Kind::LT, curr_v, pt_v);
+ do_extend = Rewriter::rewrite(do_extend);
+ if (do_extend == d_data->d_true)
+ {
+ for (unsigned q = 0; q < 2; q++)
+ {
+ pts[p <= 1 ? 0 : 1].push_back(curr_v);
+ pts[p <= 1 ? 1 : 0].push_back(
+ d_tangent_val_bound[p <= 1 ? 2 + q : q][a][b]);
+ }
+ }
+ }
+ }
+ else
+ {
+ d_tangent_val_bound[p][a][b] = curr_v;
+ }
+ }
+
+ for (unsigned p = 0; p < pts[0].size(); p++)
+ {
+ Node a_v = pts[0][p];
+ Node b_v = pts[1][p];
+
+ // tangent plane
+ Node tplane = nm->mkNode(Kind::MINUS,
+ nm->mkNode(Kind::PLUS,
+ nm->mkNode(Kind::MULT, b_v, a),
+ nm->mkNode(Kind::MULT, a_v, b)),
+ nm->mkNode(Kind::MULT, a_v, b_v));
+ // construct the following lemmas:
+ // t <= tplane <=> ((a <= a_v ^ b >= b_v) v (a >= a_v ^ b <= b_v))
+ // t >= tplane <=> ((a <= a_v ^ b <= b_v) v (a >= a_v ^ b >= b_v))
+
+ for (unsigned d = 0; d < 2; d++)
+ {
+ Node b1 = nm->mkNode(d == 0 ? Kind::GEQ : Kind::LEQ, b, b_v);
+ Node b2 = nm->mkNode(d == 0 ? Kind::LEQ : Kind::GEQ, b, b_v);
+ Node tlem = nm->mkNode(
+ Kind::EQUAL,
+ nm->mkNode(d == 0 ? Kind::LEQ : Kind::GEQ, t, tplane),
+ nm->mkNode(
+ Kind::OR,
+ nm->mkNode(Kind::AND, nm->mkNode(Kind::LEQ, a, a_v), b1),
+ nm->mkNode(
+ Kind::AND, nm->mkNode(Kind::GEQ, a, a_v), b2)));
+ Trace("nl-ext-tplanes")
+ << "Tangent plane lemma : " << tlem << std::endl;
+ d_data->d_im.addPendingArithLemma(
+ tlem, InferenceId::NL_TANGENT_PLANE, nullptr, asWaitingLemmas);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/nl/ext/tangent_plane_check.h b/src/theory/arith/nl/ext/tangent_plane_check.h
new file mode 100644
index 000000000..748ab6372
--- /dev/null
+++ b/src/theory/arith/nl/ext/tangent_plane_check.h
@@ -0,0 +1,69 @@
+/********************* */
+/*! \file tangent_plane_check.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Check for tangent_plane lemma
+ **/
+
+#ifndef CVC4__THEORY__ARITH__NL__EXT__TANGENT_PLANE_CHECK_H
+#define CVC4__THEORY__ARITH__NL__EXT__TANGENT_PLANE_CHECK_H
+
+#include "expr/node.h"
+#include "theory/arith/nl/ext/ext_state.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+class TangentPlaneCheck
+{
+ public:
+ TangentPlaneCheck(ExtState* data);
+
+ /** check tangent planes
+ *
+ * Returns a set of valid theory lemmas, based on an
+ * "incremental linearization" of non-linear monomials.
+ * This linearization is accomplished by adding constraints
+ * corresponding to "tangent planes" at the current
+ * model value of each non-linear monomial. In particular
+ * consider the definition for constants a,b :
+ * T_{a,b}( x*y ) = b*x + a*y - a*b.
+ * The lemmas added by this function are of the form :
+ * ( ( x>a ^ y<b) ^ (x<a ^ y>b) ) => x*y < T_{a,b}( x*y )
+ * ( ( x>a ^ y>b) ^ (x<a ^ y<b) ) => x*y > T_{a,b}( x*y )
+ * It is inspired by "Invariant Checking of NRA Transition
+ * Systems via Incremental Reduction to LRA with EUF" by
+ * Cimatti et al., TACAS 2017.
+ * This schema is not terminating in general.
+ * It is not enabled by default, and can
+ * be enabled by --nl-ext-tplanes.
+ *
+ * Examples:
+ *
+ * ( ( x>2 ^ y>5) ^ (x<2 ^ y<5) ) => x*y > 5*x + 2*y - 10
+ * ( ( x>2 ^ y<5) ^ (x<2 ^ y>5) ) => x*y < 5*x + 2*y - 10
+ */
+ void check(bool asWaitingLemmas);
+
+ private:
+ /** Basic data that is shared with other checks */
+ ExtState* d_data;
+ /** tangent plane bounds */
+ std::map<Node, std::map<Node, Node> > d_tangent_val_bound[4];
+};
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/nl/ext_theory_callback.cpp b/src/theory/arith/nl/ext_theory_callback.cpp
new file mode 100644
index 000000000..62e1fa904
--- /dev/null
+++ b/src/theory/arith/nl/ext_theory_callback.cpp
@@ -0,0 +1,131 @@
+/********************* */
+/*! \file ext_theory_callback.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Tim King, Tianyi Liang
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The extended theory callback for non-linear arithmetic
+ **/
+
+#include "theory/arith/nl/ext_theory_callback.h"
+
+#include "theory/arith/arith_utilities.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+NlExtTheoryCallback::NlExtTheoryCallback(eq::EqualityEngine* ee) : d_ee(ee)
+{
+ d_zero = NodeManager::currentNM()->mkConst(Rational(0));
+}
+
+bool NlExtTheoryCallback::getCurrentSubstitution(
+ int effort,
+ const std::vector<Node>& vars,
+ std::vector<Node>& subs,
+ std::map<Node, std::vector<Node>>& exp)
+{
+ // get the constant equivalence classes
+ std::map<Node, std::vector<int>> rep_to_subs_index;
+
+ bool retVal = false;
+ for (unsigned i = 0; i < vars.size(); i++)
+ {
+ Node n = vars[i];
+ if (d_ee->hasTerm(n))
+ {
+ Node nr = d_ee->getRepresentative(n);
+ if (nr.isConst())
+ {
+ subs.push_back(nr);
+ Trace("nl-subs") << "Basic substitution : " << n << " -> " << nr
+ << std::endl;
+ exp[n].push_back(n.eqNode(nr));
+ retVal = true;
+ }
+ else
+ {
+ rep_to_subs_index[nr].push_back(i);
+ subs.push_back(n);
+ }
+ }
+ else
+ {
+ subs.push_back(n);
+ }
+ }
+
+ // return true if the substitution is non-trivial
+ return retVal;
+}
+
+bool NlExtTheoryCallback::isExtfReduced(int effort,
+ Node n,
+ Node on,
+ std::vector<Node>& exp)
+{
+ if (n != d_zero)
+ {
+ Kind k = n.getKind();
+ return k != NONLINEAR_MULT && !isTranscendentalKind(k) && k != IAND;
+ }
+ Assert(n == d_zero);
+ if (on.getKind() == NONLINEAR_MULT)
+ {
+ Trace("nl-ext-zero-exp")
+ << "Infer zero : " << on << " == " << n << std::endl;
+ // minimize explanation if a substitution+rewrite results in zero
+ const std::set<Node> vars(on.begin(), on.end());
+
+ for (unsigned i = 0, size = exp.size(); i < size; i++)
+ {
+ Trace("nl-ext-zero-exp")
+ << " exp[" << i << "] = " << exp[i] << std::endl;
+ std::vector<Node> eqs;
+ if (exp[i].getKind() == EQUAL)
+ {
+ eqs.push_back(exp[i]);
+ }
+ else if (exp[i].getKind() == AND)
+ {
+ for (const Node& ec : exp[i])
+ {
+ if (ec.getKind() == EQUAL)
+ {
+ eqs.push_back(ec);
+ }
+ }
+ }
+
+ for (unsigned j = 0; j < eqs.size(); j++)
+ {
+ for (unsigned r = 0; r < 2; r++)
+ {
+ if (eqs[j][r] == d_zero && vars.find(eqs[j][1 - r]) != vars.end())
+ {
+ Trace("nl-ext-zero-exp")
+ << "...single exp : " << eqs[j] << std::endl;
+ exp.clear();
+ exp.push_back(eqs[j]);
+ return true;
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/nl/ext_theory_callback.h b/src/theory/arith/nl/ext_theory_callback.h
new file mode 100644
index 000000000..66c1ebc94
--- /dev/null
+++ b/src/theory/arith/nl/ext_theory_callback.h
@@ -0,0 +1,86 @@
+/********************* */
+/*! \file ext_theory_callback.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The extended theory callback for non-linear arithmetic
+ **/
+
+#ifndef CVC4__THEORY__ARITH__NL__EXT_THEORY_CALLBACK_H
+#define CVC4__THEORY__ARITH__NL__EXT_THEORY_CALLBACK_H
+
+#include "expr/node.h"
+#include "theory/ext_theory.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+class NlExtTheoryCallback : public ExtTheoryCallback
+{
+ public:
+ NlExtTheoryCallback(eq::EqualityEngine* ee);
+ ~NlExtTheoryCallback() {}
+ /** Get current substitution
+ *
+ * This function and the one below are
+ * used for context-dependent
+ * simplification, see Section 3.1 of
+ * "Designing Theory Solvers with Extensions"
+ * by Reynolds et al. FroCoS 2017.
+ *
+ * effort : an identifier indicating the stage where
+ * we are performing context-dependent simplification,
+ * vars : a set of arithmetic variables.
+ *
+ * This function populates subs and exp, such that for 0 <= i < vars.size():
+ * ( exp[vars[i]] ) => vars[i] = subs[i]
+ * where exp[vars[i]] is a set of assertions
+ * that hold in the current context. We call { vars -> subs } a "derivable
+ * substituion" (see Reynolds et al. FroCoS 2017).
+ */
+ bool getCurrentSubstitution(int effort,
+ const std::vector<Node>& vars,
+ std::vector<Node>& subs,
+ std::map<Node, std::vector<Node>>& exp) override;
+ /** Is the term n in reduced form?
+ *
+ * Used for context-dependent simplification.
+ *
+ * effort : an identifier indicating the stage where
+ * we are performing context-dependent simplification,
+ * on : the original term that we reduced to n,
+ * exp : an explanation such that ( exp => on = n ).
+ *
+ * We return a pair ( b, exp' ) such that
+ * if b is true, then:
+ * n is in reduced form
+ * if exp' is non-null, then ( exp' => on = n )
+ * The second part of the pair is used for constructing
+ * minimal explanations for context-dependent simplifications.
+ */
+ bool isExtfReduced(int effort,
+ Node n,
+ Node on,
+ std::vector<Node>& exp) override;
+
+ private:
+ /** The underlying equality engine. */
+ eq::EqualityEngine* d_ee;
+ /** Commonly used nodes */
+ Node d_zero;
+};
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__ARITH__NL__EXT_THEORY_CALLBACK_H */
diff --git a/src/theory/arith/nl/iand_solver.cpp b/src/theory/arith/nl/iand_solver.cpp
index b154326a4..e33cfa6cd 100644
--- a/src/theory/arith/nl/iand_solver.cpp
+++ b/src/theory/arith/nl/iand_solver.cpp
@@ -2,10 +2,10 @@
/*! \file iand_solver.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds
+ ** Andrew Reynolds, Gereon Kremer, Tim King
** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -28,8 +28,10 @@ namespace theory {
namespace arith {
namespace nl {
-IAndSolver::IAndSolver(TheoryArith& containing, NlModel& model)
- : d_model(model), d_initRefine(containing.getUserContext())
+IAndSolver::IAndSolver(InferenceManager& im, ArithState& state, NlModel& model)
+ : d_im(im),
+ d_model(model),
+ d_initRefine(state.getUserContext())
{
NodeManager* nm = NodeManager::currentNM();
d_true = nm->mkConst(true);
@@ -64,10 +66,9 @@ void IAndSolver::initLastCall(const std::vector<Node>& assertions,
Trace("iand") << "We have " << d_iands.size() << " IAND terms." << std::endl;
}
-std::vector<NlLemma> IAndSolver::checkInitialRefine()
+void IAndSolver::checkInitialRefine()
{
Trace("iand-check") << "IAndSolver::checkInitialRefine" << std::endl;
- std::vector<NlLemma> lems;
NodeManager* nm = NodeManager::currentNM();
for (const std::pair<const unsigned, std::vector<Node> >& is : d_iands)
{
@@ -99,17 +100,15 @@ std::vector<NlLemma> IAndSolver::checkInitialRefine()
Node lem = conj.size() == 1 ? conj[0] : nm->mkNode(AND, conj);
Trace("iand-lemma") << "IAndSolver::Lemma: " << lem << " ; INIT_REFINE"
<< std::endl;
- lems.push_back(lem);
+ d_im.addPendingArithLemma(lem, InferenceId::NL_IAND_INIT_REFINE);
}
}
- return lems;
}
-std::vector<NlLemma> IAndSolver::checkFullRefine()
+void IAndSolver::checkFullRefine()
{
Trace("iand-check") << "IAndSolver::checkFullRefine";
Trace("iand-check") << "IAND terms: " << std::endl;
- std::vector<NlLemma> lems;
for (const std::pair<const unsigned, std::vector<Node> >& is : d_iands)
{
// the reference bitwidth
@@ -149,7 +148,11 @@ std::vector<NlLemma> IAndSolver::checkFullRefine()
// ************* additional lemma schemas go here
if (options::iandMode() == options::IandMode::SUM)
{
- // add lemmas based on sum mode
+ Node lem = sumBasedLemma(i); // add lemmas based on sum mode
+ Trace("iand-lemma")
+ << "IAndSolver::Lemma: " << lem << " ; SUM_REFINE" << std::endl;
+ d_im.addPendingArithLemma(
+ lem, InferenceId::NL_IAND_SUM_REFINE, nullptr, true);
}
else if (options::iandMode() == options::IandMode::BITWISE)
{
@@ -161,12 +164,11 @@ std::vector<NlLemma> IAndSolver::checkFullRefine()
Node lem = valueBasedLemma(i);
Trace("iand-lemma")
<< "IAndSolver::Lemma: " << lem << " ; VALUE_REFINE" << std::endl;
- lems.push_back(lem);
+ d_im.addPendingArithLemma(
+ lem, InferenceId::NL_IAND_VALUE_REFINE, nullptr, true);
}
}
}
-
- return lems;
}
Node IAndSolver::convertToBvK(unsigned k, Node n) const
@@ -248,7 +250,18 @@ Node IAndSolver::valueBasedLemma(Node i)
return lem;
}
-bool oneBitAnd(bool a, bool b) { return (a && b); }
+Node IAndSolver::sumBasedLemma(Node i)
+{
+ Assert(i.getKind() == IAND);
+ Node x = i[0];
+ Node y = i[1];
+ size_t bvsize = i.getOperator().getConst<IntAnd>().d_size;
+ uint64_t granularity = options::BVAndIntegerGranularity();
+ NodeManager* nm = NodeManager::currentNM();
+ Node lem = nm->mkNode(
+ EQUAL, i, d_iandTable.createBitwiseNode(x, y, bvsize, granularity));
+ return lem;
+}
} // namespace nl
} // namespace arith
diff --git a/src/theory/arith/nl/iand_solver.h b/src/theory/arith/nl/iand_solver.h
index 360629c97..e00cb92a9 100644
--- a/src/theory/arith/nl/iand_solver.h
+++ b/src/theory/arith/nl/iand_solver.h
@@ -2,10 +2,10 @@
/*! \file iand_solver.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds
+ ** Andrew Reynolds, Tim King, Tianyi Liang
** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,9 +20,11 @@
#include "context/cdhashset.h"
#include "expr/node.h"
+#include "theory/arith/arith_state.h"
+#include "theory/arith/inference_manager.h"
+#include "theory/arith/nl/iand_table.h"
#include "theory/arith/nl/nl_lemma_utils.h"
#include "theory/arith/nl/nl_model.h"
-#include "theory/arith/theory_arith.h"
namespace CVC4 {
namespace theory {
@@ -37,7 +39,7 @@ class IAndSolver
typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
public:
- IAndSolver(TheoryArith& containing, NlModel& model);
+ IAndSolver(InferenceManager& im, ArithState& state, NlModel& model);
~IAndSolver();
/** init last call
@@ -66,16 +68,18 @@ class IAndSolver
* This should be a heuristic incomplete check that only introduces a
* small number of new terms in the lemmas it returns.
*/
- std::vector<NlLemma> checkInitialRefine();
+ void checkInitialRefine();
/** check full refine
*
* This should be a complete check that returns at least one lemma to
* rule out the current model.
*/
- std::vector<NlLemma> checkFullRefine();
+ void checkFullRefine();
//-------------------------------------------- end lemma schemas
private:
+ // The inference manager that we push conflicts and lemmas to.
+ InferenceManager& d_im;
/** Reference to the non-linear model object */
NlModel& d_model;
/** commonly used terms */
@@ -85,6 +89,7 @@ class IAndSolver
Node d_two;
Node d_true;
Node d_false;
+ IAndTable d_iandTable;
/** IAND terms that have been given initial refinement lemmas */
NodeSet d_initRefine;
/** all IAND terms, for each bit-width */
@@ -115,6 +120,13 @@ class IAndSolver
* ((_ iand k) x y) = Rewriter::rewrite(((_ iand k) M(x) M(y)))
*/
Node valueBasedLemma(Node i);
+ /**
+ * Sum-based refinement lemma for i of the form ((_ iand k) x y). Returns:
+ * i = 2^0*min(x[0],y[0])+...2^{k-1}*min(x[k-1],y[k-1])
+ * where x[i] is x div i mod 2
+ * and min is defined with an ite.
+ */
+ Node sumBasedLemma(Node i);
}; /* class IAndSolver */
} // namespace nl
diff --git a/src/theory/arith/nl/iand_table.cpp b/src/theory/arith/nl/iand_table.cpp
new file mode 100644
index 000000000..050e6baed
--- /dev/null
+++ b/src/theory/arith/nl/iand_table.cpp
@@ -0,0 +1,222 @@
+/********************* */
+/*! \file iand_table.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Yoni Zohar
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utilities to maintain finite tables that represent
+ ** the value of iand.
+ **/
+
+#include "theory/arith/nl/iand_table.h"
+
+#include <cmath>
+
+#include "cvc4_private.h"
+#include "theory/arith/nl/nl_model.h"
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+static Rational intpow2(uint64_t b)
+{
+ return Rational(Integer(2).pow(b), Integer(1));
+}
+
+Node pow2(uint64_t k)
+{
+ Assert(k >= 0);
+ NodeManager* nm = NodeManager::currentNM();
+ return nm->mkConst<Rational>(intpow2(k));
+}
+
+bool oneBitAnd(bool a, bool b) { return (a && b); }
+
+// computes (bv_to_int ((_ extract i+size-1 i) (int_to_bv x))))
+Node intExtract(Node x, uint64_t i, uint64_t size)
+{
+ Assert(size > 0);
+ NodeManager* nm = NodeManager::currentNM();
+ // extract definition in integers is:
+ // (mod (div a (two_to_the j)) (two_to_the (+ (- i j) 1))))
+ Node extract =
+ nm->mkNode(kind::INTS_MODULUS_TOTAL,
+ nm->mkNode(kind::INTS_DIVISION_TOTAL, x, pow2(i * size)),
+ pow2(size));
+ return extract;
+}
+
+Node IAndTable::createITEFromTable(
+ Node x,
+ Node y,
+ uint64_t granularity,
+ const std::map<std::pair<int64_t, int64_t>, uint64_t>& table)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ Assert(granularity <= 8);
+ uint64_t num_of_values = ((uint64_t)pow(2, granularity));
+ // The table represents a function from pairs of integers to integers, where
+ // all integers are between 0 (inclusive) and num_of_values (exclusive).
+ // additionally, there is a default value (-1, -1).
+ Assert(table.size() == 1 + ((uint64_t)(num_of_values * num_of_values)));
+ // start with the default, most common value.
+ // this value is represented in the table by (-1, -1).
+ Node ite = nm->mkConst<Rational>(table.at(std::make_pair(-1, -1)));
+ for (uint64_t i = 0; i < num_of_values; i++)
+ {
+ for (uint64_t j = 0; j < num_of_values; j++)
+ {
+ // skip the most common value, as it was already stored.
+ if (table.at(std::make_pair(i, j)) == table.at(std::make_pair(-1, -1)))
+ {
+ continue;
+ }
+ // append the current value to the ite.
+ ite = nm->mkNode(
+ kind::ITE,
+ nm->mkNode(kind::AND,
+ nm->mkNode(kind::EQUAL, x, nm->mkConst<Rational>(i)),
+ nm->mkNode(kind::EQUAL, y, nm->mkConst<Rational>(j))),
+ nm->mkConst<Rational>(table.at(std::make_pair(i, j))),
+ ite);
+ }
+ }
+ return ite;
+}
+
+Node IAndTable::createBitwiseNode(Node x,
+ Node y,
+ uint64_t bvsize,
+ uint64_t granularity)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ Assert(0 < granularity && granularity <= 8);
+ // Standardize granularity.
+ // If it is greater than bvsize, it is set to bvsize.
+ // Otherwise, it is set to the closest (going down) divider of bvsize.
+ if (granularity > bvsize)
+ {
+ granularity = bvsize;
+ }
+ else
+ {
+ while (bvsize % granularity != 0)
+ {
+ granularity = granularity - 1;
+ }
+ }
+
+ // Create the sum.
+ // For granularity 1, the sum has bvsize elements.
+ // In contrast, if bvsize = granularity, sum has one element.
+ // Each element in the sum is an ite that corresponds to the generated table,
+ // multiplied by the appropriate power of two.
+ // More details are in bv_to_int.h .
+
+ // number of elements in the sum expression
+ uint64_t sumSize = bvsize / granularity;
+ // initialize the sum
+ Node sumNode = nm->mkConst<Rational>(0);
+ // compute the table for the current granularity if needed
+ if (d_bvandTable.find(granularity) == d_bvandTable.end())
+ {
+ computeAndTable(granularity);
+ }
+ const std::map<std::pair<int64_t, int64_t>, uint64_t>& table =
+ d_bvandTable[granularity];
+ for (uint64_t i = 0; i < sumSize; i++)
+ {
+ // compute the current blocks of x and y
+ Node xExtract = intExtract(x, i, granularity);
+ Node yExtract = intExtract(y, i, granularity);
+ // compute the ite for this part
+ Node sumPart = createITEFromTable(xExtract, yExtract, granularity, table);
+ // append the current block to the sum
+ sumNode =
+ nm->mkNode(kind::PLUS,
+ sumNode,
+ nm->mkNode(kind::MULT, pow2(i * granularity), sumPart));
+ }
+ return sumNode;
+}
+
+void IAndTable::computeAndTable(uint64_t granularity)
+{
+ Assert(d_bvandTable.find(granularity) == d_bvandTable.end());
+ // the table was not yet computed
+ std::map<std::pair<int64_t, int64_t>, uint64_t> table;
+ uint64_t num_of_values = ((uint64_t)pow(2, granularity));
+ // populate the table with all the values
+ for (uint64_t i = 0; i < num_of_values; i++)
+ {
+ for (uint64_t j = 0; j < num_of_values; j++)
+ {
+ // compute
+ // (bv_to_int (bvand ((int_to_bv granularity) i) ((int_to_bv granularity)
+ // j)))
+ int64_t sum = 0;
+ for (uint64_t n = 0; n < granularity; n++)
+ {
+ // b is the result of f on the current bit
+ bool b = oneBitAnd((((i >> n) & 1) == 1), (((j >> n) & 1) == 1));
+ // add the corresponding power of 2 only if the result is 1
+ if (b)
+ {
+ sum += 1 << n;
+ }
+ }
+ table[std::make_pair(i, j)] = sum;
+ }
+ }
+ // optimize the table by identifying and adding the default value
+ addDefaultValue(table, num_of_values);
+ Assert(table.size() == 1 + (static_cast<uint64_t>(num_of_values * num_of_values)));
+ // store the table in the cache and return it
+ d_bvandTable[granularity] = table;
+}
+
+void IAndTable::addDefaultValue(
+ std::map<std::pair<int64_t, int64_t>, uint64_t>& table,
+ uint64_t num_of_values)
+{
+ // map each result to the number of times it occurs
+ std::map<uint64_t, uint64_t> counters;
+ for (uint64_t i = 0; i <= num_of_values; i++)
+ {
+ counters[i] = 0;
+ }
+ for (const std::pair<std::pair<int64_t, int64_t>, uint64_t>& element : table)
+ {
+ uint64_t result = element.second;
+ counters[result]++;
+ }
+
+ // compute the most common result
+ uint64_t most_common_result = 0;
+ uint64_t max_num_of_occ = 0;
+ for (uint64_t i = 0; i <= num_of_values; i++)
+ {
+ if (counters[i] >= max_num_of_occ)
+ {
+ max_num_of_occ = counters[i];
+ most_common_result = i;
+ }
+ }
+ // sanity check: some value appears at least once.
+ Assert(max_num_of_occ != 0);
+
+ // -1 is the default case of the table.
+ // add it to the table
+ table[std::make_pair(-1, -1)] = most_common_result;
+}
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/nl/iand_table.h b/src/theory/arith/nl/iand_table.h
new file mode 100644
index 000000000..6387885b7
--- /dev/null
+++ b/src/theory/arith/nl/iand_table.h
@@ -0,0 +1,136 @@
+/********************* */
+/*! \file iand_table.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Yoni Zohar
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utilities to maintain finite tables that represent
+ ** the value of iand.
+ **/
+
+#ifndef CVC4__THEORY__ARITH__IAND_TABLE_H
+#define CVC4__THEORY__ARITH__IAND_TABLE_H
+
+#include <tuple>
+#include <vector>
+#include "expr/node.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+/**
+ * A class that computes tables for iand values
+ * with various bit-widths
+ */
+class IAndTable
+{
+ public:
+ /**
+ * A generic function that creates a node that represents a bvand
+ * operation.
+ *
+ * For example: Suppose bvsize is 4, granularity is 1.
+ * Denote by ITE(a,b) the term: ite(a==0, 0, ite(b==1, 1, 0)).
+ * The result of this function would be:
+ * ITE(x[0], y[0])*2^0 + ... + ITE(x[3], y[3])*2^3
+ *
+ * For another example: Suppose bvsize is 4, granularity is 2,
+ * and f(x,y) = x && y.
+ * Denote by ITE(a,b) the term that corresponds to the following table:
+ * a | b | ITE(a,b)
+ * ----------------
+ * 0 | 0 | 0
+ * 0 | 1 | 0
+ * 0 | 2 | 0
+ * 0 | 3 | 0
+ * 1 | 0 | 0
+ * 1 | 1 | 1
+ * 1 | 2 | 0
+ * 1 | 3 | 1
+ * 2 | 0 | 0
+ * 2 | 1 | 0
+ * 2 | 2 | 2
+ * 2 | 3 | 2
+ * 3 | 0 | 0
+ * 3 | 1 | 1
+ * 3 | 2 | 2
+ * 3 | 3 | 3
+ *
+ * For example, 2 in binary is 10 and 1 in binary is 01, and so doing
+ * "bitwise f" on them gives 00.
+ * The result of this function would be:
+ * ITE(x[1:0], y[1:0])*2^0 + ITE(x[3:2], y[3:2])*2^2
+ *
+ * More precisely, the ITE term is optimized so that the most common
+ * result is in the final "else" branch.
+ * Hence in practice, the generated ITEs will be shorter.
+ *
+ * @param x is an integer operand that correspond to the first original
+ * bit-vector operand.
+ * @param y is an integer operand that correspond to the second original
+ * bit-vector operand.
+ * @param bvsize is the bit width of the original bit-vector variables.
+ * @param granularity is specified in the options for this preprocessing
+ * pass.
+ * @return A node that represents the operation, as described above.
+ */
+ Node createBitwiseNode(Node x, Node y, uint64_t bvsize, uint64_t granularity);
+
+ /**
+ * A helper function for createBitwiseNode
+ * @param x integer node corresponding to the original first bit-vector
+ * argument
+ * @param y integer node corresponding to the original second bit-vector
+ * argument nodes.
+ * @param granularity the bitwidth of the original bit-vector nodes.
+ * @param table a function from pairs of integers to integers.
+ * The domain of this function consists of pairs of
+ * integers between 0 (inclusive) and 2^{bitwidth} (exclusive).
+ * The domain also includes one additional pair (-1, -1), that
+ * represents the default (most common) value.
+ * @return An ite term that represents this table.
+ */
+ Node createITEFromTable(
+ Node x,
+ Node y,
+ uint64_t granularity,
+ const std::map<std::pair<int64_t, int64_t>, uint64_t>& table);
+
+ /**
+ * updates d_bvandTable[granularity] if it wasn't already computed.
+ */
+ void computeAndTable(uint64_t granularity);
+
+ /**
+ * @param table a table that represents integer conjunction
+ * @param num_of_values the number of rows in the table
+ * The function will add a single row to the table.
+ * the key will be (-1, -1) and the value will be the most common
+ * value of the original table.
+ */
+ void addDefaultValue(std::map<std::pair<int64_t, int64_t>, uint64_t>& table,
+ uint64_t num_of_values);
+
+ /**
+ * For each granularity between 1 and 8, we store a separate table
+ * in d_bvandTable[granularity].
+ * The definition of these tables is given in the description of
+ * createBitwiseNode.
+ */
+ std::map<uint64_t, std::map<std::pair<int64_t, int64_t>, uint64_t>>
+ d_bvandTable;
+};
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__ARITH__IAND_TABLE_H */
diff --git a/src/theory/arith/nl/icp/candidate.cpp b/src/theory/arith/nl/icp/candidate.cpp
new file mode 100644
index 000000000..df8e18818
--- /dev/null
+++ b/src/theory/arith/nl/icp/candidate.cpp
@@ -0,0 +1,120 @@
+/********************* */
+/*! \file candidate.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief
+ **/
+
+#include "theory/arith/nl/icp/candidate.h"
+
+#ifdef CVC4_POLY_IMP
+
+#include <iostream>
+
+#include "base/check.h"
+#include "base/output.h"
+#include "theory/arith/nl/icp/intersection.h"
+#include "theory/arith/nl/poly_conversion.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace icp {
+
+PropagationResult Candidate::propagate(poly::IntervalAssignment& ia,
+ std::size_t size_threshold) const
+{
+ // Evaluate the right hand side
+ auto res = poly::evaluate(rhs, ia) * poly::Interval(poly::Value(rhsmult));
+ if (get_lower(res) == poly::Value::minus_infty()
+ && get_upper(res) == poly::Value::plus_infty())
+ {
+ return PropagationResult::NOT_CHANGED;
+ }
+ Trace("nl-icp") << "Prop: " << *this << " -> " << res << std::endl;
+ // Remove bounds based on the sign condition
+ switch (rel)
+ {
+ case poly::SignCondition::LT:
+ res.set_lower(poly::Value::minus_infty(), true);
+ res.set_upper(get_upper(res), true);
+ break;
+ case poly::SignCondition::LE:
+ res.set_lower(poly::Value::minus_infty(), true);
+ break;
+ case poly::SignCondition::EQ: break;
+ case poly::SignCondition::NE: Assert(false); break;
+ case poly::SignCondition::GT:
+ res.set_lower(get_lower(res), true);
+ res.set_upper(poly::Value::plus_infty(), true);
+ break;
+ case poly::SignCondition::GE:
+ res.set_upper(poly::Value::plus_infty(), true);
+ break;
+ }
+ // Get the current interval for lhs
+ auto cur = ia.get(lhs);
+
+ // Update the current interval
+ PropagationResult result = intersect_interval_with(cur, res, size_threshold);
+ // Check for strong propagations
+ switch (result)
+ {
+ case PropagationResult::CONTRACTED:
+ case PropagationResult::CONTRACTED_WITHOUT_CURRENT:
+ {
+ Trace("nl-icp") << *this << " contracted " << lhs << " -> " << cur
+ << std::endl;
+ auto old = ia.get(lhs);
+ bool strong = false;
+ strong = strong
+ || (is_minus_infinity(get_lower(old))
+ && !is_minus_infinity(get_lower(cur)));
+ strong = strong
+ || (is_plus_infinity(get_upper(old))
+ && !is_plus_infinity(get_upper(cur)));
+ ia.set(lhs, cur);
+ if (strong)
+ {
+ if (result == PropagationResult::CONTRACTED)
+ {
+ result = PropagationResult::CONTRACTED_STRONGLY;
+ }
+ else if (result == PropagationResult::CONTRACTED_WITHOUT_CURRENT)
+ {
+ result = PropagationResult::CONTRACTED_STRONGLY_WITHOUT_CURRENT;
+ }
+ }
+ break;
+ }
+ case PropagationResult::CONTRACTED_STRONGLY:
+ case PropagationResult::CONTRACTED_STRONGLY_WITHOUT_CURRENT:
+ Assert(false) << "This method should not return strong flags.";
+ break;
+ default: break;
+ }
+ return result;
+}
+
+std::ostream& operator<<(std::ostream& os, const Candidate& c)
+{
+ os << c.lhs << " " << c.rel << " ";
+ if (c.rhsmult != poly::Rational(1)) os << c.rhsmult << " * ";
+ return os << c.rhs;
+}
+
+} // namespace icp
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/nl/icp/candidate.h b/src/theory/arith/nl/icp/candidate.h
new file mode 100644
index 000000000..7980e5c97
--- /dev/null
+++ b/src/theory/arith/nl/icp/candidate.h
@@ -0,0 +1,85 @@
+/********************* */
+/*! \file candidate.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Represents a contraction candidate for ICP-style propagation.
+ **/
+
+#ifndef CVC4__THEORY__ARITH__ICP__CANDIDATE_H
+#define CVC4__THEORY__ARITH__ICP__CANDIDATE_H
+
+#include "util/real_algebraic_number.h"
+
+#ifdef CVC4_POLY_IMP
+#include <poly/polyxx.h>
+
+#include "expr/node.h"
+#include "theory/arith/nl/icp/intersection.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace icp {
+
+/**
+ * A contraction candidate for ICP-style propagation with the following
+ * semantics:
+ *
+ * lhs ~rel~ rhsmult*rhs
+ *
+ * where lhs is the variable whose interval we aim to contract, rel is a
+ * relation symbol (other than disequality), rhsmult is a fractional constant
+ * and rhs a polynomial. As poly::Polynomial only holds integer polynomials,
+ * rhsmult is necessary to encode polynomials with rational coefficients.
+ *
+ * Additionally, we store the origin of this constraints (a single theory
+ * constraint) and the variables contained in rhs.
+ *
+ * A candidate is evaluated (or propagated) by evaluating the rhsmult*rhs over
+ * an interval assignment and then updating the interval assignment for lhs with
+ * the result of this evaluation, properly considering the relation.
+ */
+struct Candidate
+{
+ /** The target variable */
+ poly::Variable lhs;
+ /** The relation symbol */
+ poly::SignCondition rel;
+ /** The (integer) polynomial on the right hand side */
+ poly::Polynomial rhs;
+ /** The rational multiplier */
+ poly::Rational rhsmult;
+ /** The origin of this candidate */
+ Node origin;
+ /** The variable within rhs */
+ std::vector<Node> rhsVariables;
+
+ /**
+ * Contract the interval assignment based on this candidate.
+ * Only contract if the new interval is below the given threshold, see
+ * intersect_interval_with().
+ */
+ PropagationResult propagate(poly::IntervalAssignment& ia,
+ std::size_t size_threshold) const;
+};
+
+/** Print a candidate. */
+std::ostream& operator<<(std::ostream& os, const Candidate& c);
+
+} // namespace icp
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
+
+#endif
diff --git a/src/theory/arith/nl/icp/contraction_origins.cpp b/src/theory/arith/nl/icp/contraction_origins.cpp
new file mode 100644
index 000000000..779c000b7
--- /dev/null
+++ b/src/theory/arith/nl/icp/contraction_origins.cpp
@@ -0,0 +1,120 @@
+/********************* */
+/*! \file contraction_origins.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief
+ **/
+
+#include "theory/arith/nl/icp/contraction_origins.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace icp {
+
+void ContractionOriginManager::getOrigins(ContractionOrigin const* const origin,
+ std::set<Node>& res) const
+{
+ if (!origin->candidate.isNull())
+ {
+ res.insert(origin->candidate);
+ }
+ for (const auto& co : origin->origins)
+ {
+ getOrigins(co, res);
+ }
+}
+
+const std::map<Node, ContractionOriginManager::ContractionOrigin*>&
+ContractionOriginManager::currentOrigins() const
+{
+ return d_currentOrigins;
+}
+
+void ContractionOriginManager::add(const Node& targetVariable,
+ const Node& candidate,
+ const std::vector<Node>& originVariables,
+ bool addTarget)
+{
+ Trace("nl-icp") << "Adding contraction for " << targetVariable << std::endl;
+ std::vector<ContractionOrigin*> origins;
+ if (addTarget)
+ {
+ auto it = d_currentOrigins.find(targetVariable);
+ if (it != d_currentOrigins.end())
+ {
+ origins.emplace_back(it->second);
+ }
+ }
+ for (const auto& v : originVariables)
+ {
+ auto it = d_currentOrigins.find(v);
+ if (it != d_currentOrigins.end())
+ {
+ origins.emplace_back(it->second);
+ }
+ }
+ d_allocations.emplace_back(
+ new ContractionOrigin{candidate, std::move(origins)});
+ d_currentOrigins[targetVariable] = d_allocations.back().get();
+}
+
+std::vector<Node> ContractionOriginManager::getOrigins(
+ const Node& variable) const
+{
+ Trace("nl-icp") << "Obtaining origins for " << variable << std::endl;
+ std::set<Node> origins;
+ Assert(d_currentOrigins.find(variable) != d_currentOrigins.end())
+ << "Using variable as origin that is unknown yet.";
+ getOrigins(d_currentOrigins.at(variable), origins);
+ Assert(!origins.empty()) << "There should be at least one origin";
+ return std::vector<Node>(origins.begin(), origins.end());
+}
+
+bool ContractionOriginManager::isInOrigins(const Node& variable,
+ const Node& c) const
+{
+ std::set<Node> origins;
+ Assert(d_currentOrigins.find(variable) != d_currentOrigins.end())
+ << "Using variable as origin that is unknown yet.";
+ getOrigins(d_currentOrigins.at(variable), origins);
+ return origins.find(c) != origins.end();
+}
+
+void print(std::ostream& os,
+ const std::string& indent,
+ const ContractionOriginManager::ContractionOrigin* co)
+{
+ os << indent << co->candidate << std::endl;
+ for (const auto& o : co->origins)
+ {
+ print(os, indent + "\t", o);
+ }
+}
+
+inline std::ostream& operator<<(std::ostream& os,
+ const ContractionOriginManager& com)
+{
+ os << "ContractionOrigins:" << std::endl;
+ const auto& origins = com.currentOrigins();
+ for (const auto& vars : origins)
+ {
+ os << vars.first << ":" << std::endl;
+ print(os, "\t", vars.second);
+ }
+ return os;
+}
+
+} // namespace icp
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/nl/icp/contraction_origins.h b/src/theory/arith/nl/icp/contraction_origins.h
new file mode 100644
index 000000000..885fc740a
--- /dev/null
+++ b/src/theory/arith/nl/icp/contraction_origins.h
@@ -0,0 +1,104 @@
+/********************* */
+/*! \file contraction_origins.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implements a way to track the origins of ICP-style contractions.
+ **/
+
+#ifndef CVC4__THEORY__ARITH__ICP__CONTRACTION_ORIGINS_H
+#define CVC4__THEORY__ARITH__ICP__CONTRACTION_ORIGINS_H
+
+#include <memory>
+#include <vector>
+
+#include "expr/node.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace icp {
+
+/**
+ * This class tracks origins of ICP-style contractions of variable intervals.
+ * For every variable, it holds one origin object that may recursively depend on
+ * previous contraction origins. Initially, a immediate bound on a variable
+ * (like x>0) yields an origin for this variable. For every contraction, we then
+ * add a new origin that recursively holds the old origins, usually those of all
+ * variables involved in the contraction. When generating a conflict or a lemma,
+ * a recursive walk through this structure allow to retrieve all input theory
+ * atoms that contributed to the new fact or the conflict.
+ */
+class ContractionOriginManager
+{
+ public:
+ /**
+ * Origin of one particular contraction step.
+ * Usually, this is either a direct bound or the application of a contraction
+ * candidate. The direct bound is stored in the candidate while origins
+ * remains empty. The contraction candidate is stored in the candidate while
+ * origins hold the origins of all variables used in the contraction.
+ */
+ struct ContractionOrigin
+ {
+ /** The theory atom used to do this contraction. */
+ Node candidate;
+ /** All origins required for this contraction. */
+ std::vector<ContractionOrigin*> origins;
+ };
+
+ private:
+ /**
+ * Recursively walks through the data structure, collecting all theory atoms.
+ */
+ void getOrigins(ContractionOrigin const* const origin,
+ std::set<Node>& res) const;
+
+ public:
+ /** Return the current origins for all variables. */
+ const std::map<Node, ContractionOrigin*>& currentOrigins() const;
+ /**
+ * Add a new contraction for the targetVariable.
+ * Adds a new origin with the given candidate and origins.
+ * If addTarget is set to true, we also add the current origin of the
+ * targetVariable to origins. This corresponds to whether we intersected the
+ * new interval with the previous interval, or whether the new interval was a
+ * subset of the previous one in the first place.
+ */
+ void add(const Node& targetVariable,
+ const Node& candidate,
+ const std::vector<Node>& originVariables,
+ bool addTarget = true);
+
+ /**
+ * Collect all theory atoms from the origins of the given variable.
+ */
+ std::vector<Node> getOrigins(const Node& variable) const;
+
+ /** Check whether a node c is among the origins of a variable. */
+ bool isInOrigins(const Node& variable, const Node& c) const;
+
+ private:
+ /** The current origins for every variable. */
+ std::map<Node, ContractionOrigin*> d_currentOrigins;
+ /** All allocated origins to allow for proper deallocation. */
+ std::vector<std::unique_ptr<ContractionOrigin>> d_allocations;
+};
+
+/** Stream the constration origins to an ostream. */
+std::ostream& operator<<(std::ostream& os, const ContractionOriginManager& com);
+
+} // namespace icp
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/nl/icp/icp_solver.cpp b/src/theory/arith/nl/icp/icp_solver.cpp
new file mode 100644
index 000000000..b4cb54216
--- /dev/null
+++ b/src/theory/arith/nl/icp/icp_solver.cpp
@@ -0,0 +1,386 @@
+/********************* */
+/*! \file icp_solver.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implements a ICP-based solver for nonlinear arithmetic.
+ **/
+
+#include "theory/arith/nl/icp/icp_solver.h"
+
+#include <iostream>
+
+#include "base/check.h"
+#include "base/output.h"
+#include "expr/node_algorithm.h"
+#include "theory/arith/arith_msum.h"
+#include "theory/arith/nl/poly_conversion.h"
+#include "theory/arith/normal_form.h"
+#include "theory/rewriter.h"
+#include "util/poly_util.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace icp {
+
+#ifdef CVC4_POLY_IMP
+
+namespace {
+/** A simple wrapper to nicely print an interval assignment. */
+struct IAWrapper
+{
+ const poly::IntervalAssignment& ia;
+ const VariableMapper& vm;
+};
+inline std::ostream& operator<<(std::ostream& os, const IAWrapper& iaw)
+{
+ os << "{ ";
+ bool first = true;
+ for (const auto& v : iaw.vm.mVarpolyCVC)
+ {
+ if (iaw.ia.has(v.first))
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ os << ", ";
+ }
+ os << v.first << " -> " << iaw.ia.get(v.first);
+ }
+ }
+ return os << " }";
+}
+} // namespace
+
+std::vector<Node> ICPSolver::collectVariables(const Node& n) const
+{
+ std::unordered_set<TNode, TNodeHashFunction> tmp;
+ expr::getVariables(n, tmp);
+ std::vector<Node> res;
+ for (const auto& t : tmp)
+ {
+ res.emplace_back(t);
+ }
+ return res;
+}
+
+std::vector<Candidate> ICPSolver::constructCandidates(const Node& n)
+{
+ Node tmp = Rewriter::rewrite(n);
+ if (tmp.isConst())
+ {
+ return {};
+ }
+ auto comp = Comparison::parseNormalForm(tmp).decompose(false);
+ Kind k = std::get<1>(comp);
+ if (k == Kind::DISTINCT)
+ {
+ return {};
+ }
+ auto poly = std::get<0>(comp);
+
+ std::vector<Candidate> result;
+ std::unordered_set<TNode, TNodeHashFunction> vars;
+ expr::getVariables(n, vars);
+ for (const auto& v : vars)
+ {
+ Trace("nl-icp") << "\tChecking " << n << " for " << v << std::endl;
+
+ std::map<Node, Node> msum;
+ ArithMSum::getMonomialSum(poly.getNode(), msum);
+
+ Node veq_c;
+ Node val;
+
+ int isolated = ArithMSum::isolate(v, msum, veq_c, val, k);
+ if (isolated == 1)
+ {
+ poly::Variable lhs = d_mapper(v);
+ poly::SignCondition rel = poly::SignCondition::EQ;
+ switch (k)
+ {
+ case Kind::LT: rel = poly::SignCondition::LT; break;
+ case Kind::LEQ: rel = poly::SignCondition::LE; break;
+ case Kind::EQUAL: rel = poly::SignCondition::EQ; break;
+ case Kind::DISTINCT: rel = poly::SignCondition::NE; break;
+ case Kind::GT: rel = poly::SignCondition::GT; break;
+ case Kind::GEQ: rel = poly::SignCondition::GE; break;
+ default: Assert(false) << "Unexpected kind: " << k;
+ }
+ poly::Rational rhsmult;
+ poly::Polynomial rhs = as_poly_polynomial(val, d_mapper, rhsmult);
+ rhsmult = poly::Rational(1) / rhsmult;
+ // only correct up to a constant (denominator is thrown away!)
+ if (!veq_c.isNull())
+ {
+ rhsmult = poly_utils::toRational(veq_c.getConst<Rational>());
+ }
+ Candidate res{lhs, rel, rhs, rhsmult, n, collectVariables(val)};
+ Trace("nl-icp") << "\tAdded " << res << " from " << n << std::endl;
+ result.emplace_back(res);
+ }
+ else if (isolated == -1)
+ {
+ poly::Variable lhs = d_mapper(v);
+ poly::SignCondition rel = poly::SignCondition::EQ;
+ switch (k)
+ {
+ case Kind::LT: rel = poly::SignCondition::GT; break;
+ case Kind::LEQ: rel = poly::SignCondition::GE; break;
+ case Kind::EQUAL: rel = poly::SignCondition::EQ; break;
+ case Kind::DISTINCT: rel = poly::SignCondition::NE; break;
+ case Kind::GT: rel = poly::SignCondition::LT; break;
+ case Kind::GEQ: rel = poly::SignCondition::LE; break;
+ default: Assert(false) << "Unexpected kind: " << k;
+ }
+ poly::Rational rhsmult;
+ poly::Polynomial rhs = as_poly_polynomial(val, d_mapper, rhsmult);
+ rhsmult = poly::Rational(1) / rhsmult;
+ if (!veq_c.isNull())
+ {
+ rhsmult = poly_utils::toRational(veq_c.getConst<Rational>());
+ }
+ Candidate res{lhs, rel, rhs, rhsmult, n, collectVariables(val)};
+ Trace("nl-icp") << "\tAdded " << res << " from " << n << std::endl;
+ result.emplace_back(res);
+ }
+ }
+ return result;
+}
+
+void ICPSolver::addCandidate(const Node& n)
+{
+ auto it = d_candidateCache.find(n);
+ if (it != d_candidateCache.end())
+ {
+ for (const auto& c : it->second)
+ {
+ d_state.d_candidates.emplace_back(c);
+ }
+ }
+ else
+ {
+ auto cands = constructCandidates(n);
+ d_candidateCache.emplace(n, cands);
+ for (const auto& c : cands)
+ {
+ d_state.d_candidates.emplace_back(c);
+ Trace("nl-icp") << "Bumping budget because of the new candidate"
+ << std::endl;
+ d_budget += d_budgetIncrement;
+ }
+ }
+}
+
+void ICPSolver::initOrigins()
+{
+ for (const auto& vars : d_state.d_bounds.get())
+ {
+ const Bounds& i = vars.second;
+ Trace("nl-icp") << "Adding initial " << vars.first << " -> " << i
+ << std::endl;
+ if (!i.lower_origin.isNull())
+ {
+ Trace("nl-icp") << "\tAdding lower " << i.lower_origin << std::endl;
+ d_state.d_origins.add(vars.first, i.lower_origin, {});
+ }
+ if (!i.upper_origin.isNull())
+ {
+ Trace("nl-icp") << "\tAdding upper " << i.upper_origin << std::endl;
+ d_state.d_origins.add(vars.first, i.upper_origin, {});
+ }
+ }
+}
+
+PropagationResult ICPSolver::doPropagationRound()
+{
+ if (d_budget <= 0)
+ {
+ Trace("nl-icp") << "ICP budget exceeded" << std::endl;
+ return PropagationResult::NOT_CHANGED;
+ }
+ d_state.d_conflict.clear();
+ Trace("nl-icp") << "Starting propagation with "
+ << IAWrapper{d_state.d_assignment, d_mapper} << std::endl;
+ Trace("nl-icp") << "Current budget: " << d_budget << std::endl;
+ PropagationResult res = PropagationResult::NOT_CHANGED;
+ for (const auto& c : d_state.d_candidates)
+ {
+ --d_budget;
+ PropagationResult cres = c.propagate(d_state.d_assignment, 100);
+ switch (cres)
+ {
+ case PropagationResult::NOT_CHANGED: break;
+ case PropagationResult::CONTRACTED:
+ case PropagationResult::CONTRACTED_STRONGLY:
+ d_state.d_origins.add(d_mapper(c.lhs), c.origin, c.rhsVariables);
+ res = PropagationResult::CONTRACTED;
+ break;
+ case PropagationResult::CONTRACTED_WITHOUT_CURRENT:
+ case PropagationResult::CONTRACTED_STRONGLY_WITHOUT_CURRENT:
+ d_state.d_origins.add(d_mapper(c.lhs), c.origin, c.rhsVariables, false);
+ res = PropagationResult::CONTRACTED;
+ break;
+ case PropagationResult::CONFLICT:
+ d_state.d_origins.add(d_mapper(c.lhs), c.origin, c.rhsVariables);
+ d_state.d_conflict = d_state.d_origins.getOrigins(d_mapper(c.lhs));
+ return PropagationResult::CONFLICT;
+ }
+ switch (cres)
+ {
+ case PropagationResult::CONTRACTED_STRONGLY:
+ case PropagationResult::CONTRACTED_STRONGLY_WITHOUT_CURRENT:
+ Trace("nl-icp") << "Bumping budget because of a strong contraction"
+ << std::endl;
+ d_budget += d_budgetIncrement;
+ break;
+ default: break;
+ }
+ }
+ return res;
+}
+
+std::vector<Node> ICPSolver::generateLemmas() const
+{
+ auto nm = NodeManager::currentNM();
+ std::vector<Node> lemmas;
+
+ for (const auto& vars : d_mapper.mVarCVCpoly)
+ {
+ if (!d_state.d_assignment.has(vars.second)) continue;
+ Node v = vars.first;
+ poly::Interval i = d_state.d_assignment.get(vars.second);
+ if (!is_minus_infinity(get_lower(i)))
+ {
+ Kind rel = get_lower_open(i) ? Kind::GT : Kind::GEQ;
+ Node c = nm->mkNode(rel, v, value_to_node(get_lower(i), v));
+ if (!d_state.d_origins.isInOrigins(v, c))
+ {
+ Node premise = nm->mkAnd(d_state.d_origins.getOrigins(v));
+ Trace("nl-icp") << premise << " => " << c << std::endl;
+ Node lemma = Rewriter::rewrite(nm->mkNode(Kind::IMPLIES, premise, c));
+ if (lemma.isConst())
+ {
+ Assert(lemma == nm->mkConst<bool>(true));
+ }
+ else
+ {
+ Trace("nl-icp") << "Adding lemma " << lemma << std::endl;
+ lemmas.emplace_back(lemma);
+ }
+ }
+ }
+ if (!is_plus_infinity(get_upper(i)))
+ {
+ Kind rel = get_upper_open(i) ? Kind::LT : Kind::LEQ;
+ Node c = nm->mkNode(rel, v, value_to_node(get_upper(i), v));
+ if (!d_state.d_origins.isInOrigins(v, c))
+ {
+ Node premise = nm->mkAnd(d_state.d_origins.getOrigins(v));
+ Trace("nl-icp") << premise << " => " << c << std::endl;
+ Node lemma = Rewriter::rewrite(nm->mkNode(Kind::IMPLIES, premise, c));
+ if (lemma.isConst())
+ {
+ Assert(lemma == nm->mkConst<bool>(true));
+ }
+ else
+ {
+ Trace("nl-icp") << "Adding lemma " << lemma << std::endl;
+ lemmas.emplace_back(lemma);
+ }
+ }
+ }
+ }
+ return lemmas;
+}
+
+void ICPSolver::reset(const std::vector<Node>& assertions)
+{
+ d_state.reset();
+ for (const auto& n : assertions)
+ {
+ Trace("nl-icp") << "Adding " << n << std::endl;
+ if (n.getKind() != Kind::CONST_BOOLEAN)
+ {
+ if (!d_state.d_bounds.add(n))
+ {
+ addCandidate(n);
+ }
+ }
+ }
+}
+
+void ICPSolver::check()
+{
+ initOrigins();
+ d_state.d_assignment = getBounds(d_mapper, d_state.d_bounds);
+ bool did_progress = false;
+ bool progress = false;
+ do
+ {
+ switch (doPropagationRound())
+ {
+ case icp::PropagationResult::NOT_CHANGED: progress = false; break;
+ case icp::PropagationResult::CONTRACTED:
+ case icp::PropagationResult::CONTRACTED_STRONGLY:
+ case icp::PropagationResult::CONTRACTED_WITHOUT_CURRENT:
+ case icp::PropagationResult::CONTRACTED_STRONGLY_WITHOUT_CURRENT:
+ did_progress = true;
+ progress = true;
+ break;
+ case icp::PropagationResult::CONFLICT:
+ Trace("nl-icp") << "Found a conflict: " << d_state.d_conflict
+ << std::endl;
+
+ std::vector<Node> mis;
+ for (const auto& n : d_state.d_conflict)
+ {
+ mis.emplace_back(n.negate());
+ }
+ d_im.addPendingArithLemma(NodeManager::currentNM()->mkOr(mis),
+ InferenceId::NL_ICP_CONFLICT);
+ did_progress = true;
+ progress = false;
+ break;
+ }
+ } while (progress);
+ if (did_progress)
+ {
+ std::vector<Node> lemmas = generateLemmas();
+ for (const auto& l : lemmas)
+ {
+ d_im.addPendingArithLemma(l, InferenceId::NL_ICP_PROPAGATION);
+ }
+ }
+}
+
+#else /* CVC4_POLY_IMP */
+
+void ICPSolver::reset(const std::vector<Node>& assertions)
+{
+ Unimplemented() << "ICPSolver requires CVC4 to be configured with LibPoly";
+}
+
+void ICPSolver::check()
+{
+ Unimplemented() << "ICPSolver requires CVC4 to be configured with LibPoly";
+}
+
+#endif /* CVC4_POLY_IMP */
+
+} // namespace icp
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/nl/icp/icp_solver.h b/src/theory/arith/nl/icp/icp_solver.h
new file mode 100644
index 000000000..32861c641
--- /dev/null
+++ b/src/theory/arith/nl/icp/icp_solver.h
@@ -0,0 +1,156 @@
+/********************* */
+/*! \file icp_solver.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implements a ICP-based solver for nonlinear arithmetic.
+ **/
+
+#ifndef CVC4__THEORY__ARITH__ICP__ICP_SOLVER_H
+#define CVC4__THEORY__ARITH__ICP__ICP_SOLVER_H
+
+#include "util/real_algebraic_number.h"
+
+#ifdef CVC4_POLY_IMP
+#include <poly/polyxx.h>
+#endif /* CVC4_POLY_IMP */
+
+#include "expr/node.h"
+#include "theory/arith/bound_inference.h"
+#include "theory/arith/inference_manager.h"
+#include "theory/arith/nl/icp/candidate.h"
+#include "theory/arith/nl/icp/contraction_origins.h"
+#include "theory/arith/nl/icp/intersection.h"
+#include "theory/arith/nl/poly_conversion.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace icp {
+
+#ifdef CVC4_POLY_IMP
+
+/**
+ * This class implements an ICP-based solver. As it is intended to be used in
+ * conjunction with other solvers, it only performs contractions, but does not
+ * issue splits.
+ *
+ * In essence, interval constraint propagation has candidates (like x = y^2-z),
+ * evaluates their right hand side over the current (interval) assignment and
+ * uses the resulting interval to make the interval of the left-hand side
+ * variable smaller (contract it).
+ *
+ * These contractions can yield to a conflict (if the interval of some variable
+ * becomes empty) or shrink the search space for a variable.
+ */
+class ICPSolver
+{
+ /**
+ * This encapsulates the state of the ICP solver that is local to a single
+ * theory call. It contains the variable bounds and candidates derived from
+ * the assertions, the origins manager and the last conflict.
+ */
+ struct ICPState
+ {
+ /** The variable bounds extracted from the input assertions */
+ BoundInference d_bounds;
+ /** The contraction candidates generated from the theory atoms */
+ std::vector<Candidate> d_candidates;
+ /** The current assignment */
+ poly::IntervalAssignment d_assignment;
+ /** The origins for the current assignment */
+ ContractionOriginManager d_origins;
+ /** The conflict, if any way found. Initially empty */
+ std::vector<Node> d_conflict;
+
+ /** Initialized the variable bounds with a variable mapper */
+ ICPState(VariableMapper& vm) {}
+
+ /** Reset this state */
+ void reset()
+ {
+ d_bounds = BoundInference();
+ d_candidates.clear();
+ d_assignment.clear();
+ d_origins = ContractionOriginManager();
+ d_conflict.clear();
+ }
+ };
+
+ /** Maps Node (variables) to poly::Variable */
+ VariableMapper d_mapper;
+ /** The inference manager */
+ InferenceManager& d_im;
+ /** Cache candidates to avoid reconstruction for every theory call */
+ std::map<Node, std::vector<Candidate>> d_candidateCache;
+ /** The current state */
+ ICPState d_state;
+
+ /** The remaining budget */
+ std::int64_t d_budget = 0;
+ /** The budget increment for new candidates and strong contractions */
+ static constexpr std::int64_t d_budgetIncrement = 10;
+
+ /** Collect all variables from a node */
+ std::vector<Node> collectVariables(const Node& n) const;
+ /** Construct all possible candidates from a given theory atom */
+ std::vector<Candidate> constructCandidates(const Node& n);
+ /** Add the given node as candidate */
+ void addCandidate(const Node& n);
+ /** Initialize the origin manager from the variable bounds */
+ void initOrigins();
+
+ /**
+ * Perform one contraction with every candidate.
+ * If any candidate yields a conflict stops immediately and returns
+ * PropagationResult::CONFLICT. If any candidate yields a contraction returns
+ * PropagationResult::CONTRACTED. Otherwise returns
+ * PropagationResult::NOT_CHANGED.
+ */
+ PropagationResult doPropagationRound();
+
+ /**
+ * Construct lemmas for all bounds that have been improved.
+ * For every improved bound, all origins are collected and a lemma of the form
+ * (and origins) ==> (new bound)
+ * is constructed.
+ */
+ std::vector<Node> generateLemmas() const;
+
+ public:
+ ICPSolver(InferenceManager& im) : d_im(im), d_state(d_mapper) {}
+ /** Reset this solver for the next theory call */
+ void reset(const std::vector<Node>& assertions);
+
+ /**
+ * Performs a full ICP check.
+ */
+ void check();
+};
+
+#else /* CVC4_POLY_IMP */
+
+class ICPSolver
+{
+ public:
+ ICPSolver(InferenceManager& im) {}
+ void reset(const std::vector<Node>& assertions);
+ void check();
+};
+
+#endif /* CVC4_POLY_IMP */
+
+} // namespace icp
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/nl/icp/intersection.cpp b/src/theory/arith/nl/icp/intersection.cpp
new file mode 100644
index 000000000..148059db0
--- /dev/null
+++ b/src/theory/arith/nl/icp/intersection.cpp
@@ -0,0 +1,224 @@
+/********************* */
+/*! \file intersection.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief
+ **/
+
+#include "theory/arith/nl/icp/intersection.h"
+
+#ifdef CVC4_POLY_IMP
+
+#include <iostream>
+
+#include "base/check.h"
+#include "base/output.h"
+#include "theory/arith/nl/poly_conversion.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace icp {
+
+PropagationResult intersect_interval_with(poly::Interval& cur,
+ const poly::Interval& res,
+ std::size_t size_threshold)
+{
+ Trace("nl-icp") << cur << " := " << cur << " intersected with " << res
+ << std::endl;
+
+ if (bitsize(get_lower(res)) > size_threshold
+ || bitsize(get_upper(res)) > size_threshold)
+ {
+ Trace("nl-icp") << "Reached bitsize threshold" << std::endl;
+ return PropagationResult::NOT_CHANGED;
+ }
+
+ // Basic idea to organize this function:
+ // The bounds for res have 5 positions:
+ // 1 < 2 (lower(cur)) < 3 < 4 (upper(cur)) < 5
+
+ if (get_upper(res) < get_lower(cur))
+ {
+ // upper(res) at 1
+ Trace("nl-icp") << "res < cur -> conflict" << std::endl;
+ return PropagationResult::CONFLICT;
+ }
+ if (get_upper(res) == get_lower(cur))
+ {
+ // upper(res) at 2
+ if (get_upper_open(res) || get_lower_open(cur))
+ {
+ Trace("nl-icp") << "meet at lower, but one is open -> conflict"
+ << std::endl;
+ return PropagationResult::CONFLICT;
+ }
+ if (!is_point(cur))
+ {
+ Trace("nl-icp") << "contracts to point interval at lower" << std::endl;
+ cur = poly::Interval(get_upper(res));
+ return PropagationResult::CONTRACTED;
+ }
+ return PropagationResult::NOT_CHANGED;
+ }
+ Assert(get_upper(res) > get_lower(cur))
+ << "Comparison operator does weird stuff.";
+ if (get_upper(res) < get_upper(cur))
+ {
+ // upper(res) at 3
+ if (get_lower(res) < get_lower(cur))
+ {
+ // lower(res) at 1
+ Trace("nl-icp") << "lower(cur) .. upper(res)" << std::endl;
+ cur.set_upper(get_upper(res), get_upper_open(res));
+ return PropagationResult::CONTRACTED;
+ }
+ if (get_lower(res) == get_lower(cur))
+ {
+ // lower(res) at 2
+ Trace("nl-icp") << "meet at lower, lower(cur) .. upper(res)" << std::endl;
+ cur = poly::Interval(get_lower(cur),
+ get_lower_open(cur) || get_lower_open(res),
+ get_upper(res),
+ get_upper_open(res));
+ if (get_lower_open(cur) && !get_lower_open(res))
+ {
+ return PropagationResult::CONTRACTED;
+ }
+ return PropagationResult::CONTRACTED_WITHOUT_CURRENT;
+ }
+ Assert(get_lower(res) > get_lower(cur))
+ << "Comparison operator does weird stuff.";
+ // lower(res) at 3
+ Trace("nl-icp") << "cur covers res" << std::endl;
+ cur = res;
+ return PropagationResult::CONTRACTED_WITHOUT_CURRENT;
+ }
+ if (get_upper(res) == get_upper(cur))
+ {
+ // upper(res) at 4
+ if (get_lower(res) < get_lower(cur))
+ {
+ // lower(res) at 1
+ Trace("nl-icp") << "res covers cur but meet at upper" << std::endl;
+ if (get_upper_open(res) && !get_upper_open(cur))
+ {
+ cur.set_upper(get_upper(cur), true);
+ return PropagationResult::CONTRACTED;
+ }
+ return PropagationResult::NOT_CHANGED;
+ }
+ if (get_lower(res) == get_lower(cur))
+ {
+ // lower(res) at 2
+ Trace("nl-icp") << "same bounds but check openness" << std::endl;
+ bool changed = false;
+ if (get_lower_open(res) && !get_lower_open(cur))
+ {
+ changed = true;
+ cur.set_lower(get_lower(cur), true);
+ }
+ if (get_upper_open(res) && !get_upper_open(cur))
+ {
+ changed = true;
+ cur.set_upper(get_upper(cur), true);
+ }
+ if (changed)
+ {
+ if ((get_lower_open(res) || !get_upper_open(cur))
+ && (get_upper_open(res) || !get_upper_open(cur)))
+ {
+ return PropagationResult::CONTRACTED_WITHOUT_CURRENT;
+ }
+ return PropagationResult::CONTRACTED;
+ }
+ return PropagationResult::NOT_CHANGED;
+ }
+ Assert(get_lower(res) > get_lower(cur))
+ << "Comparison operator does weird stuff.";
+ // lower(res) at 3
+ Trace("nl-icp") << "cur covers res but meet at upper" << std::endl;
+ cur = poly::Interval(get_lower(res),
+ get_lower_open(res),
+ get_upper(res),
+ get_upper_open(cur) || get_upper_open(res));
+ if (get_upper_open(cur) && !get_upper_open(res))
+ {
+ return PropagationResult::CONTRACTED;
+ }
+ return PropagationResult::CONTRACTED_WITHOUT_CURRENT;
+ }
+
+ Assert(get_upper(res) > get_upper(cur))
+ << "Comparison operator does weird stuff.";
+ // upper(res) at 5
+
+ if (get_lower(res) < get_lower(cur))
+ {
+ // lower(res) at 1
+ Trace("nl-icp") << "res covers cur" << std::endl;
+ return PropagationResult::NOT_CHANGED;
+ }
+ if (get_lower(res) == get_lower(cur))
+ {
+ // lower(res) at 2
+ Trace("nl-icp") << "res covers cur but meet at lower" << std::endl;
+ if (get_lower_open(res) && is_point(cur))
+ {
+ return PropagationResult::CONFLICT;
+ }
+ else if (get_lower_open(res) && !get_lower_open(cur))
+ {
+ cur.set_lower(get_lower(cur), true);
+ return PropagationResult::CONTRACTED;
+ }
+ return PropagationResult::NOT_CHANGED;
+ }
+ Assert(get_lower(res) > get_lower(cur))
+ << "Comparison operator does weird stuff.";
+ if (get_lower(res) < get_upper(cur))
+ {
+ // lower(res) at 3
+ Trace("nl-icp") << "lower(res) .. upper(cur)" << std::endl;
+ cur.set_lower(get_lower(res), get_lower_open(res));
+ return PropagationResult::CONTRACTED;
+ }
+ if (get_lower(res) == get_upper(cur))
+ {
+ // lower(res) at 4
+ if (get_lower_open(res) || get_upper_open(cur))
+ {
+ Trace("nl-icp") << "meet at upper, but one is open -> conflict"
+ << std::endl;
+ return PropagationResult::CONFLICT;
+ }
+ if (!is_point(cur))
+ {
+ Trace("nl-icp") << "contracts to point interval at upper" << std::endl;
+ cur = poly::Interval(get_lower(res));
+ return PropagationResult::CONTRACTED;
+ }
+ return PropagationResult::NOT_CHANGED;
+ }
+
+ Assert(get_lower(res) > get_upper(cur));
+ // lower(res) at 5
+ Trace("nl-icp") << "res > cur -> conflict" << std::endl;
+ return PropagationResult::CONFLICT;
+}
+
+} // namespace icp
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/nl/icp/intersection.h b/src/theory/arith/nl/icp/intersection.h
new file mode 100644
index 000000000..8d772cb7a
--- /dev/null
+++ b/src/theory/arith/nl/icp/intersection.h
@@ -0,0 +1,79 @@
+/********************* */
+/*! \file intersection.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implement intersection of intervals for propagation.
+ **/
+
+#ifndef CVC4__THEORY__ARITH__ICP__INTERSECTION_H
+#define CVC4__THEORY__ARITH__ICP__INTERSECTION_H
+
+#include "util/real_algebraic_number.h"
+
+#ifdef CVC4_POLY_IMP
+#include <poly/polyxx.h>
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace icp {
+
+/**
+ * Represents the possible results of a single propagation step.
+ * A propagation tries to refine a current interval with a new interval by
+ * intersecting them.
+ */
+enum class PropagationResult
+{
+ /** The propagation did not change the current interval. */
+ NOT_CHANGED,
+ /** The propagation contracted the current interval. */
+ CONTRACTED,
+ /**
+ * The propagation contracted the current interval made at least one bound
+ * finite.
+ */
+ CONTRACTED_STRONGLY,
+ /**
+ * The propagation only used the new interval (as it was a subset of the
+ * current interval).
+ */
+ CONTRACTED_WITHOUT_CURRENT,
+ /**
+ * The propagation only used the new interval (as it was a subset of the
+ * current interval) and made at least one bound finite.
+ */
+ CONTRACTED_STRONGLY_WITHOUT_CURRENT,
+ /**
+ * The propagation found a conflict as the two intervals did not intersect.
+ */
+ CONFLICT
+};
+
+/**
+ * Update the current interval by intersection with the new interval and return
+ * the appropriate result. If the size of any of the bounds, as computed by
+ * bitsize(), would grow beyond the given threshold, no intersection is
+ * performed and PropagationResult::NOT_CHANGED is returned.
+ */
+PropagationResult intersect_interval_with(poly::Interval& cur,
+ const poly::Interval& res,
+ std::size_t size_threshold);
+
+} // namespace icp
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
+
+#endif
diff --git a/src/theory/arith/nl/icp/interval.h b/src/theory/arith/nl/icp/interval.h
new file mode 100644
index 000000000..374067961
--- /dev/null
+++ b/src/theory/arith/nl/icp/interval.h
@@ -0,0 +1,65 @@
+/********************* */
+/*! \file interval.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief
+ **/
+
+#ifndef CVC4__THEORY__ARITH__ICP__INTERVAL_H
+#define CVC4__THEORY__ARITH__ICP__INTERVAL_H
+
+#include "util/real_algebraic_number.h"
+
+#ifdef CVC4_POLY_IMP
+#include <poly/polyxx.h>
+
+#include "expr/node.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+namespace icp {
+
+/**
+ * Represents an interval with poly::Value bounds and origins for these bounds.
+ */
+struct Interval
+{
+ /** The lower bound */
+ poly::Value lower = poly::Value::minus_infty();
+ /** Whether the lower bound is strict or weak */
+ bool lower_strict = true;
+ /** The origin of the lower bound */
+ Node lower_origin;
+ /** The upper bound */
+ poly::Value upper = poly::Value::plus_infty();
+ /** Whether the upper bound is strict or weak */
+ bool upper_strict = true;
+ /** The origin of the upper bound */
+ Node upper_origin;
+};
+
+/** Print an interval */
+inline std::ostream& operator<<(std::ostream& os, const Interval& i)
+{
+ return os << (i.lower_strict ? '(' : '[') << i.lower << " .. " << i.upper
+ << (i.upper_strict ? ')' : ']');
+}
+
+} // namespace icp
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
+
+#endif
diff --git a/src/theory/arith/nl/inference.cpp b/src/theory/arith/nl/inference.cpp
deleted file mode 100644
index 34242e746..000000000
--- a/src/theory/arith/nl/inference.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/********************* */
-/*! \file inference.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of inference enumeration.
- **/
-
-#include "theory/arith/nl/inference.h"
-
-namespace CVC4 {
-namespace theory {
-namespace arith {
-namespace nl {
-
-const char* toString(Inference i)
-{
- switch (i)
- {
- case Inference::CONGRUENCE: return "CONGRUENCE";
- case Inference::SHARED_TERM_VALUE_SPLIT: return "SHARED_TERM_VALUE_SPLIT";
- case Inference::SPLIT_ZERO: return "SPLIT_ZERO";
- case Inference::SIGN: return "SIGN";
- case Inference::COMPARISON: return "COMPARISON";
- case Inference::INFER_BOUNDS: return "INFER_BOUNDS";
- case Inference::INFER_BOUNDS_NT: return "INFER_BOUNDS_NT";
- case Inference::FACTOR: return "FACTOR";
- case Inference::RES_INFER_BOUNDS: return "RES_INFER_BOUNDS";
- case Inference::TANGENT_PLANE: return "TANGENT_PLANE";
- case Inference::T_PURIFY_ARG: return "T_PURIFY_ARG";
- case Inference::T_INIT_REFINE: return "T_INIT_REFINE";
- case Inference::T_PI_BOUND: return "T_PI_BOUND";
- case Inference::T_MONOTONICITY: return "T_MONOTONICITY";
- case Inference::T_SECANT: return "T_SECANT";
- case Inference::T_TANGENT: return "T_TANGENT";
- default: return "?";
- }
-}
-
-std::ostream& operator<<(std::ostream& out, Inference i)
-{
- out << toString(i);
- return out;
-}
-
-} // namespace nl
-} // namespace arith
-} // namespace theory
-} // namespace CVC4
diff --git a/src/theory/arith/nl/nl_lemma_utils.cpp b/src/theory/arith/nl/nl_lemma_utils.cpp
index 0497b5822..8ae5ecc4b 100644
--- a/src/theory/arith/nl/nl_lemma_utils.cpp
+++ b/src/theory/arith/nl/nl_lemma_utils.cpp
@@ -2,10 +2,10 @@
/*! \file nl_lemma_utils.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds
+ ** Andrew Reynolds, Gereon Kremer
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -15,15 +15,26 @@
#include "theory/arith/nl/nl_lemma_utils.h"
#include "theory/arith/nl/nl_model.h"
+#include "theory/arith/nl/nonlinear_extension.h"
namespace CVC4 {
namespace theory {
namespace arith {
namespace nl {
+bool NlLemma::process(TheoryInferenceManager* im, bool asLemma)
+{
+ bool res = ArithLemma::process(im, asLemma);
+ if (d_nlext != nullptr)
+ {
+ d_nlext->processSideEffect(*this);
+ }
+ return res;
+}
+
std::ostream& operator<<(std::ostream& out, NlLemma& n)
{
- out << n.d_lemma;
+ out << n.d_node;
return out;
}
diff --git a/src/theory/arith/nl/nl_lemma_utils.h b/src/theory/arith/nl/nl_lemma_utils.h
index 2b5158f18..ac52e7d52 100644
--- a/src/theory/arith/nl/nl_lemma_utils.h
+++ b/src/theory/arith/nl/nl_lemma_utils.h
@@ -2,10 +2,10 @@
/*! \file nl_lemma_utils.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Tim King
+ ** Andrew Reynolds, Gereon Kremer, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -17,8 +17,10 @@
#include <tuple>
#include <vector>
+
#include "expr/node.h"
-#include "theory/arith/nl/inference.h"
+#include "theory/arith/arith_lemma.h"
+#include "theory/output_channel.h"
namespace CVC4 {
namespace theory {
@@ -26,6 +28,7 @@ namespace arith {
namespace nl {
class NlModel;
+class NonlinearExtension;
/**
* The data structure for a single lemma to process by the non-linear solver,
@@ -38,19 +41,24 @@ class NlModel;
* - A set of secant points to record (for transcendental secant plane
* inferences).
*/
-struct NlLemma
+class NlLemma : public ArithLemma
{
- NlLemma(Node lem, Inference id = Inference::UNKNOWN)
- : d_id(id), d_lemma(lem), d_preprocess(false)
+ public:
+ NlLemma(Node n,
+ LemmaProperty p,
+ ProofGenerator* pg,
+ InferenceId inf = InferenceId::UNKNOWN)
+ : ArithLemma(n, p, pg, inf)
+ {
+ }
+ NlLemma(Node n, InferenceId inf = InferenceId::UNKNOWN)
+ : ArithLemma(n, LemmaProperty::NONE, nullptr, inf)
{
}
~NlLemma() {}
- /** The inference id for the lemma */
- Inference d_id;
- /** The lemma */
- Node d_lemma;
- /** Whether to preprocess the lemma */
- bool d_preprocess;
+
+ bool process(TheoryInferenceManager* im, bool asLemma) override;
+
/** secant points to add
*
* A member (tf, d, c) in this vector indicates that point c should be added
@@ -61,6 +69,8 @@ struct NlLemma
* Cimatti et al., CADE 2017.
*/
std::vector<std::tuple<Node, unsigned, Node> > d_secantPoint;
+
+ NonlinearExtension* d_nlext;
};
/**
* Writes a non-linear lemma to a stream.
diff --git a/src/theory/arith/nl/nl_model.cpp b/src/theory/arith/nl/nl_model.cpp
index 2754d9c7f..79f2a2350 100644
--- a/src/theory/arith/nl/nl_model.cpp
+++ b/src/theory/arith/nl/nl_model.cpp
@@ -2,10 +2,10 @@
/*! \file nl_model.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Tim King, Mathias Preiner
+ ** Andrew Reynolds, Gereon Kremer, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,6 +16,8 @@
#include "expr/node_algorithm.h"
#include "options/arith_options.h"
+#include "options/smt_options.h"
+#include "options/theory_options.h"
#include "theory/arith/arith_msum.h"
#include "theory/arith/arith_utilities.h"
#include "theory/rewriter.h"
@@ -57,6 +59,7 @@ void NlModel::resetCheck()
d_used_approx = false;
d_check_model_solved.clear();
d_check_model_bounds.clear();
+ d_check_model_witnesses.clear();
d_check_model_vars.clear();
d_check_model_subs.clear();
}
@@ -156,7 +159,7 @@ Node NlModel::getRepresentative(Node n) const
return d_model->getRepresentative(n);
}
-Node NlModel::getValueInternal(Node n) const
+Node NlModel::getValueInternal(Node n)
{
if (n.isConst())
{
@@ -168,7 +171,11 @@ Node NlModel::getValueInternal(Node n) const
AlwaysAssert(it->second.isConst());
return it->second;
}
- // It is unconstrained in the model, return 0.
+ // It is unconstrained in the model, return 0. We additionally add it
+ // to mapping from the linear solver. This ensures that if the nonlinear
+ // solver assumes that n = 0, then this assumption is recorded in the overall
+ // model.
+ d_arithVal[n] = d_zero;
return d_zero;
}
@@ -212,8 +219,7 @@ int NlModel::compareValue(Node i, Node j, bool isAbsolute) const
bool NlModel::checkModel(const std::vector<Node>& assertions,
unsigned d,
- std::vector<NlLemma>& lemmas,
- std::vector<Node>& gs)
+ std::vector<NlLemma>& lemmas)
{
Trace("nl-ext-cm-debug") << " solve for equalities..." << std::endl;
for (const Node& atom : assertions)
@@ -257,10 +263,13 @@ bool NlModel::checkModel(const std::vector<Node>& assertions,
{
// set its exact model value in the substitution
Node curv = computeConcreteModelValue(cur);
- Trace("nl-ext-cm")
- << "check-model-bound : exact : " << cur << " = ";
- printRationalApprox("nl-ext-cm", curv);
- Trace("nl-ext-cm") << std::endl;
+ if (Trace.isOn("nl-ext-cm"))
+ {
+ Trace("nl-ext-cm")
+ << "check-model-bound : exact : " << cur << " = ";
+ printRationalApprox("nl-ext-cm", curv);
+ Trace("nl-ext-cm") << std::endl;
+ }
bool ret = addCheckModelSubstitution(cur, curv);
AlwaysAssert(ret);
}
@@ -278,11 +287,6 @@ bool NlModel::checkModel(const std::vector<Node>& assertions,
std::vector<Node> check_assertions;
for (const Node& a : assertions)
{
- // don't have to check tautological literals
- if (d_tautology.find(a) != d_tautology.end())
- {
- continue;
- }
if (d_check_model_solved.find(a) == d_check_model_solved.end())
{
Node av = a;
@@ -311,26 +315,6 @@ bool NlModel::checkModel(const std::vector<Node>& assertions,
return false;
}
Trace("nl-ext-cm") << "...simple check succeeded!" << std::endl;
-
- // must assert and re-check if produce models is true
- if (options::produceModels())
- {
- NodeManager* nm = NodeManager::currentNM();
- // model guard whose semantics is "the model we constructed holds"
- Node mg = nm->mkSkolem("model", nm->booleanType());
- gs.push_back(mg);
- // assert the constructed model as assertions
- for (const std::pair<const Node, std::pair<Node, Node>>& cb :
- d_check_model_bounds)
- {
- Node l = cb.second.first;
- Node u = cb.second.second;
- Node v = cb.first;
- Node pred = nm->mkNode(AND, nm->mkNode(GEQ, v, l), nm->mkNode(GEQ, u, v));
- pred = nm->mkNode(OR, mg.negate(), pred);
- lemmas.push_back(pred);
- }
- }
return true;
}
@@ -362,6 +346,9 @@ bool NlModel::addCheckModelSubstitution(TNode v, TNode s)
return false;
}
}
+ Assert(d_check_model_witnesses.find(v) == d_check_model_witnesses.end())
+ << "We tried to add a substitution where we already had a witness term."
+ << std::endl;
std::vector<Node> varsTmp;
varsTmp.push_back(v);
std::vector<Node> subsTmp;
@@ -415,12 +402,34 @@ bool NlModel::addCheckModelBound(TNode v, TNode l, TNode u)
return true;
}
+bool NlModel::addCheckModelWitness(TNode v, TNode w)
+{
+ Trace("nl-ext-model") << "* check model witness : " << v << " -> " << w
+ << std::endl;
+ // should not set a witness for a value that is already set
+ if (std::find(d_check_model_vars.begin(), d_check_model_vars.end(), v)
+ != d_check_model_vars.end())
+ {
+ Trace("nl-ext-model") << "...ERROR: setting witness for variable that "
+ "already has a constant value."
+ << std::endl;
+ Assert(false);
+ return false;
+ }
+ d_check_model_witnesses.emplace(v, w);
+ return true;
+}
+
bool NlModel::hasCheckModelAssignment(Node v) const
{
if (d_check_model_bounds.find(v) != d_check_model_bounds.end())
{
return true;
}
+ if (d_check_model_witnesses.find(v) != d_check_model_witnesses.end())
+ {
+ return true;
+ }
return std::find(d_check_model_vars.begin(), d_check_model_vars.end(), v)
!= d_check_model_vars.end();
}
@@ -429,52 +438,6 @@ void NlModel::setUsedApproximate() { d_used_approx = true; }
bool NlModel::usedApproximate() const { return d_used_approx; }
-void NlModel::addTautology(Node n)
-{
- // ensure rewritten
- n = Rewriter::rewrite(n);
- std::unordered_set<TNode, TNodeHashFunction> visited;
- std::vector<TNode> visit;
- TNode cur;
- visit.push_back(n);
- do
- {
- cur = visit.back();
- visit.pop_back();
- if (visited.find(cur) == visited.end())
- {
- visited.insert(cur);
- if (cur.getKind() == AND)
- {
- // children of AND are also implied
- for (const Node& cn : cur)
- {
- visit.push_back(cn);
- }
- }
- else
- {
- // is this an arithmetic literal?
- Node atom = cur.getKind() == NOT ? cur[0] : cur;
- if ((atom.getKind() == EQUAL && atom[0].getType().isReal())
- || atom.getKind() == LEQ)
- {
- // Add to tautological literals if it does not contain
- // non-linear multiplication. We cannot consider literals
- // with non-linear multiplication to be tautological since this
- // model object is responsible for checking whether they hold.
- // (TODO, cvc4-projects #113: revisit this).
- if (!expr::hasSubtermKind(NONLINEAR_MULT, atom))
- {
- Trace("nl-taut") << "Tautological literal: " << atom << std::endl;
- d_tautology.insert(cur);
- }
- }
- }
- }
- } while (!visit.empty());
-}
-
bool NlModel::solveEqualitySimple(Node eq,
unsigned d,
std::vector<NlLemma>& lemmas)
@@ -614,9 +577,12 @@ bool NlModel::solveEqualitySimple(Node eq,
if (uvf.isVar() && !hasCheckModelAssignment(uvf))
{
Node uvfv = computeConcreteModelValue(uvf);
- Trace("nl-ext-cm") << "check-model-bound : exact : " << uvf << " = ";
- printRationalApprox("nl-ext-cm", uvfv);
- Trace("nl-ext-cm") << std::endl;
+ if (Trace.isOn("nl-ext-cm"))
+ {
+ Trace("nl-ext-cm") << "check-model-bound : exact : " << uvf << " = ";
+ printRationalApprox("nl-ext-cm", uvfv);
+ Trace("nl-ext-cm") << std::endl;
+ }
bool ret = addCheckModelSubstitution(uvf, uvfv);
// recurse
return ret ? solveEqualitySimple(eq, d, lemmas) : false;
@@ -643,9 +609,12 @@ bool NlModel::solveEqualitySimple(Node eq,
return false;
}
Node val = nm->mkConst(-c.getConst<Rational>() / b.getConst<Rational>());
- Trace("nl-ext-cm") << "check-model-bound : exact : " << var << " = ";
- printRationalApprox("nl-ext-cm", val);
- Trace("nl-ext-cm") << std::endl;
+ if (Trace.isOn("nl-ext-cm"))
+ {
+ Trace("nl-ext-cm") << "check-model-bound : exact : " << var << " = ";
+ printRationalApprox("nl-ext-cm", val);
+ Trace("nl-ext-cm") << std::endl;
+ }
bool ret = addCheckModelSubstitution(var, val);
if (ret)
{
@@ -724,31 +693,40 @@ bool NlModel::solveEqualitySimple(Node eq,
nm->mkNode(MULT,
nm->mkConst(Rational(1) / Rational(2)),
nm->mkNode(PLUS, bounds[r][0], bounds[r][1])));
- Trace("nl-ext-cm-debug") << "Bound option #" << r << " : ";
- printRationalApprox("nl-ext-cm-debug", bounds[r][0]);
- Trace("nl-ext-cm-debug") << "...";
- printRationalApprox("nl-ext-cm-debug", bounds[r][1]);
- Trace("nl-ext-cm-debug") << std::endl;
+ if (Trace.isOn("nl-ext-cm-debug"))
+ {
+ Trace("nl-ext-cm-debug") << "Bound option #" << r << " : ";
+ printRationalApprox("nl-ext-cm-debug", bounds[r][0]);
+ Trace("nl-ext-cm-debug") << "...";
+ printRationalApprox("nl-ext-cm-debug", bounds[r][1]);
+ Trace("nl-ext-cm-debug") << std::endl;
+ }
diff = Rewriter::rewrite(diff);
Assert(diff.isConst());
diff = nm->mkConst(diff.getConst<Rational>().abs());
diff_bound[r] = diff;
- Trace("nl-ext-cm-debug") << "...diff from model value (";
- printRationalApprox("nl-ext-cm-debug", m_var);
- Trace("nl-ext-cm-debug") << ") is ";
- printRationalApprox("nl-ext-cm-debug", diff_bound[r]);
- Trace("nl-ext-cm-debug") << std::endl;
+ if (Trace.isOn("nl-ext-cm-debug"))
+ {
+ Trace("nl-ext-cm-debug") << "...diff from model value (";
+ printRationalApprox("nl-ext-cm-debug", m_var);
+ Trace("nl-ext-cm-debug") << ") is ";
+ printRationalApprox("nl-ext-cm-debug", diff_bound[r]);
+ Trace("nl-ext-cm-debug") << std::endl;
+ }
}
// take the one that var is closer to in the model
Node cmp = nm->mkNode(GEQ, diff_bound[0], diff_bound[1]);
cmp = Rewriter::rewrite(cmp);
Assert(cmp.isConst());
unsigned r_use_index = cmp == d_true ? 1 : 0;
- Trace("nl-ext-cm") << "check-model-bound : approximate (sqrt) : ";
- printRationalApprox("nl-ext-cm", bounds[r_use_index][0]);
- Trace("nl-ext-cm") << " <= " << var << " <= ";
- printRationalApprox("nl-ext-cm", bounds[r_use_index][1]);
- Trace("nl-ext-cm") << std::endl;
+ if (Trace.isOn("nl-ext-cm"))
+ {
+ Trace("nl-ext-cm") << "check-model-bound : approximate (sqrt) : ";
+ printRationalApprox("nl-ext-cm", bounds[r_use_index][0]);
+ Trace("nl-ext-cm") << " <= " << var << " <= ";
+ printRationalApprox("nl-ext-cm", bounds[r_use_index][1]);
+ Trace("nl-ext-cm") << std::endl;
+ }
bool ret =
addCheckModelBound(var, bounds[r_use_index][0], bounds[r_use_index][1]);
if (ret)
@@ -1087,6 +1065,11 @@ bool NlModel::simpleCheckModelMsum(const std::map<Node, Node>& msum, bool pol)
}
else
{
+ Assert(d_check_model_witnesses.find(vc)
+ == d_check_model_witnesses.end())
+ << "No variable should be assigned a witness term if we get "
+ "here. "
+ << vc << " is, though." << std::endl;
Trace("nl-ext-cms-debug") << std::endl;
Trace("nl-ext-cms")
<< " failed due to unknown bound for " << vc << std::endl;
@@ -1276,10 +1259,16 @@ void NlModel::printModelValue(const char* c, Node n, unsigned prec) const
void NlModel::getModelValueRepair(
std::map<Node, Node>& arithModel,
- std::map<Node, std::pair<Node, Node>>& approximations)
+ std::map<Node, std::pair<Node, Node>>& approximations,
+ std::map<Node, Node>& witnesses)
{
Trace("nl-model") << "NlModel::getModelValueRepair:" << std::endl;
-
+ // If we extended the model with entries x -> 0 for unconstrained values,
+ // we first update the map to the extended one.
+ if (d_arithVal.size() > arithModel.size())
+ {
+ arithModel = d_arithVal;
+ }
// Record the approximations we used. This code calls the
// recordApproximation method of the model, which overrides the model
// values for variables that we solved for, using techniques specific to
@@ -1314,6 +1303,11 @@ void NlModel::getModelValueRepair(
Trace("nl-model") << v << " exact approximation is " << l << std::endl;
}
}
+ for (const auto& vw : d_check_model_witnesses)
+ {
+ Trace("nl-model") << vw.first << " witness is " << vw.second << std::endl;
+ witnesses.emplace(vw.first, vw.second);
+ }
// Also record the exact values we used. An exact value can be seen as a
// special kind approximation of the form (witness x. x = exact_value).
// Notice that the above term gets rewritten such that the choice function
diff --git a/src/theory/arith/nl/nl_model.h b/src/theory/arith/nl/nl_model.h
index fdce446fc..cd2d15563 100644
--- a/src/theory/arith/nl/nl_model.h
+++ b/src/theory/arith/nl/nl_model.h
@@ -2,10 +2,10 @@
/*! \file nl_model.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Mathias Preiner
+ ** Andrew Reynolds, Gereon Kremer, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -48,21 +48,18 @@ class NlModel
public:
NlModel(context::Context* c);
~NlModel();
- /** reset
- *
+ /**
* This method is called once at the beginning of a last call effort check,
* where m is the model of the theory of arithmetic. This method resets the
* cache of computed model values.
*/
void reset(TheoryModel* m, std::map<Node, Node>& arithModel);
- /** reset check
- *
+ /**
* This method is called when the non-linear arithmetic solver restarts
* its computation of lemmas and models during a last call effort check.
*/
void resetCheck();
- /** compute model value
- *
+ /**
* This computes model values for terms based on two semantics, a "concrete"
* semantics and an "abstract" semantics.
*
@@ -88,7 +85,8 @@ class NlModel
Node computeAbstractModelValue(Node n);
Node computeModelValue(Node n, bool isConcrete);
- /** Compare arithmetic terms i and j based an ordering.
+ /**
+ * Compare arithmetic terms i and j based an ordering.
*
* This returns:
* -1 if i < j, 1 if i > j, or 0 if i == j
@@ -101,7 +99,8 @@ class NlModel
* values.
*/
int compare(Node i, Node j, bool isConcrete, bool isAbsolute);
- /** Compare arithmetic terms i and j based an ordering.
+ /**
+ * Compare arithmetic terms i and j based an ordering.
*
* This returns:
* -1 if i < j, 1 if i > j, or 0 if i == j
@@ -111,8 +110,7 @@ class NlModel
int compareValue(Node i, Node j, bool isAbsolute) const;
//------------------------------ recording model substitutions and bounds
- /** add check model substitution
- *
+ /**
* Adds the model substitution v -> s. This applies the substitution
* { v -> s } to each term in d_check_model_subs and adds v,s to
* d_check_model_vars and d_check_model_subs respectively.
@@ -120,24 +118,28 @@ class NlModel
* with the current substitution and bounds.
*/
bool addCheckModelSubstitution(TNode v, TNode s);
- /** add check model bound
- *
+ /**
* Adds the bound x -> < l, u > to the map above, and records the
* approximation ( x, l <= x <= u ) in the model. This method returns false
* if the bound is inconsistent with the current model substitution or
* bounds.
*/
bool addCheckModelBound(TNode v, TNode l, TNode u);
- /** has check model assignment
- *
+ /**
+ * Adds a model witness v -> w to the underlying theory model.
+ * The witness should only contain a single variable v and evaluate to true
+ * for exactly one value of v. The variable v is then (implicitly,
+ * declaratively) assigned to this single value that satisfies the witness w.
+ */
+ bool addCheckModelWitness(TNode v, TNode w);
+ /**
* Have we assigned v in the current checkModel(...) call?
*
* This method returns true if variable v is in the domain of
* d_check_model_bounds or if it occurs in d_check_model_vars.
*/
bool hasCheckModelAssignment(Node v) const;
- /** Check model
- *
+ /**
* Checks the current model based on solving for equalities, and using error
* bounds on the Taylor approximation.
*
@@ -152,8 +154,7 @@ class NlModel
*/
bool checkModel(const std::vector<Node>& assertions,
unsigned d,
- std::vector<NlLemma>& lemmas,
- std::vector<Node>& gs);
+ std::vector<NlLemma>& lemmas);
/**
* Set that we have used an approximation during this check. This flag is
* reset on a call to resetCheck. It is set when we use reasoning that
@@ -164,33 +165,14 @@ class NlModel
void setUsedApproximate();
/** Did we use an approximation during this check? */
bool usedApproximate() const;
- /** Set tautology
- *
- * This states that formula n is a tautology (satisfied in all models).
- * We call this on internally generated lemmas. This method computes a
- * set of literals that are implied by n, that are hence tautological
- * as well, such as:
- * l_pi <= real.pi <= u_pi (pi approximations)
- * sin(x) = -1*sin(-x)
- * where these literals are internally generated for the purposes
- * of guiding the models of the linear solver.
- *
- * TODO (cvc4-projects #113: would be helpful if we could do this even
- * more aggressively by ignoring all internally generated literals.
- *
- * Tautological literals do not need be checked during checkModel.
- */
- void addTautology(Node n);
//------------------------------ end recording model substitutions and bounds
- /** print model value, for debugging.
- *
+ /**
* This prints both the abstract and concrete model values for arithmetic
* term n on Trace c with precision prec.
*/
void printModelValue(const char* c, Node n, unsigned prec = 5) const;
- /** get model value repair
- *
+ /**
* This gets mappings that indicate how to repair the model generated by the
* linear arithmetic solver. This method should be called after a successful
* call to checkModel above.
@@ -199,25 +181,27 @@ class NlModel
* to their (exact) value that was computed during checkModel; the mapping
* approximations is updated to store approximate values in the form of a
* pair (P, w), where P is a predicate that describes the possible values of
- * v and w is a witness point that satisfies this predicate.
+ * v and w is a witness point that satisfies this predicate; the mapping
+ * witnesses is filled with witness terms that are satisfied by a single
+ * value.
*/
void getModelValueRepair(
std::map<Node, Node>& arithModel,
- std::map<Node, std::pair<Node, Node>>& approximations);
+ std::map<Node, std::pair<Node, Node>>& approximations,
+ std::map<Node, Node>& witnesses);
private:
/** The current model */
TheoryModel* d_model;
/** Get the model value of n from the model object above */
- Node getValueInternal(Node n) const;
+ Node getValueInternal(Node n);
/** Does the equality engine of the model have term n? */
bool hasTerm(Node n) const;
/** Get the representative of n in the model */
Node getRepresentative(Node n) const;
//---------------------------check model
- /** solve equality simple
- *
+ /**
* This method is used during checkModel(...). It takes as input an
* equality eq. If it returns true, then eq is correct-by-construction based
* on the information stored in our model representation (see
@@ -235,7 +219,8 @@ class NlModel
*/
bool solveEqualitySimple(Node eq, unsigned d, std::vector<NlLemma>& lemmas);
- /** simple check model for transcendental functions for literal
+ /**
+ * simple check model for transcendental functions for literal
*
* This method returns true if literal is true for all interpretations of
* transcendental functions within their error bounds (as stored
@@ -257,8 +242,7 @@ class NlModel
bool simpleCheckModelLit(Node lit);
bool simpleCheckModelMsum(const std::map<Node, Node>& msum, bool pol);
//---------------------------end check model
- /** get approximate sqrt
- *
+ /**
* This approximates the square root of positive constant c. If this method
* returns true, then l and u are updated to constants such that
* l <= sqrt( c ) <= u
@@ -278,11 +262,14 @@ class NlModel
Node d_null;
/**
* The values that the arithmetic theory solver assigned in the model. This
- * corresponds to exactly the set of equalities that TheoryArith is currently
- * sending to TheoryModel during collectModelInfo.
+ * corresponds to the set of equalities that linear solver (via TheoryArith)
+ * is currently sending to TheoryModel during collectModelValues, plus
+ * additional entries x -> 0 for variables that were unassigned by the linear
+ * solver.
*/
std::map<Node, Node> d_arithVal;
- /** cache of model values
+ /**
+ * cache of model values
*
* Stores the the concrete/abstract model values. This is a cache of the
* computeModelValue method.
@@ -296,7 +283,8 @@ class NlModel
*/
std::vector<Node> d_check_model_vars;
std::vector<Node> d_check_model_subs;
- /** lower and upper bounds for check model
+ /**
+ * lower and upper bounds for check model
*
* For each term t in the domain of this map, if this stores the pair
* (c_l, c_u) then the model M is such that c_l <= M( t ) <= c_u.
@@ -310,6 +298,14 @@ class NlModel
*/
std::map<Node, std::pair<Node, Node>> d_check_model_bounds;
/**
+ * witnesses for check model
+ *
+ * Stores witnesses for vatiables that define implicit variable assignments.
+ * For some variable v, we map to a formulas that is true for exactly one
+ * value of v.
+ */
+ std::map<Node, Node> d_check_model_witnesses;
+ /**
* The map from literals that our model construction solved, to the variable
* that was solved for. Examples of such literals are:
* (1) Equalities x = t, which we turned into a model substitution x -> t,
@@ -323,8 +319,6 @@ class NlModel
std::unordered_map<Node, Node, NodeHashFunction> d_check_model_solved;
/** did we use an approximation on this call to last-call effort? */
bool d_used_approx;
- /** the set of all tautological literals */
- std::unordered_set<Node, NodeHashFunction> d_tautology;
}; /* class NlModel */
} // namespace nl
diff --git a/src/theory/arith/nl/nl_solver.cpp b/src/theory/arith/nl/nl_solver.cpp
deleted file mode 100644
index 521539674..000000000
--- a/src/theory/arith/nl/nl_solver.cpp
+++ /dev/null
@@ -1,1592 +0,0 @@
-/********************* */
-/*! \file nl_solver.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Andrew Reynolds, Tim King, Ahmed Irfan
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of non-linear solver
- **/
-
-#include "theory/arith/nl/nl_solver.h"
-
-#include "options/arith_options.h"
-#include "theory/arith/arith_msum.h"
-#include "theory/arith/arith_utilities.h"
-#include "theory/arith/theory_arith.h"
-#include "theory/theory_model.h"
-
-using namespace CVC4::kind;
-
-namespace CVC4 {
-namespace theory {
-namespace arith {
-namespace nl {
-
-void debugPrintBound(const char* c, Node coeff, Node x, Kind type, Node rhs)
-{
- Node t = ArithMSum::mkCoeffTerm(coeff, x);
- Trace(c) << t << " " << type << " " << rhs;
-}
-
-bool hasNewMonomials(Node n, const std::vector<Node>& existing)
-{
- std::set<Node> visited;
-
- std::vector<Node> worklist;
- worklist.push_back(n);
- while (!worklist.empty())
- {
- Node current = worklist.back();
- worklist.pop_back();
- if (visited.find(current) == visited.end())
- {
- visited.insert(current);
- if (current.getKind() == NONLINEAR_MULT)
- {
- if (std::find(existing.begin(), existing.end(), current)
- == existing.end())
- {
- return true;
- }
- }
- else
- {
- worklist.insert(worklist.end(), current.begin(), current.end());
- }
- }
- }
- return false;
-}
-
-NlSolver::NlSolver(TheoryArith& containing, NlModel& model)
- : d_containing(containing),
- d_model(model),
- d_cdb(d_mdb),
- d_zero_split(containing.getUserContext())
-{
- NodeManager* nm = NodeManager::currentNM();
- d_true = nm->mkConst(true);
- d_false = nm->mkConst(false);
- d_zero = nm->mkConst(Rational(0));
- d_one = nm->mkConst(Rational(1));
- d_neg_one = nm->mkConst(Rational(-1));
- d_order_points.push_back(d_neg_one);
- d_order_points.push_back(d_zero);
- d_order_points.push_back(d_one);
-}
-
-NlSolver::~NlSolver() {}
-
-void NlSolver::initLastCall(const std::vector<Node>& assertions,
- const std::vector<Node>& false_asserts,
- const std::vector<Node>& xts)
-{
- d_ms_vars.clear();
- d_ms_proc.clear();
- d_ms.clear();
- d_mterms.clear();
- d_m_nconst_factor.clear();
- d_tplane_refine.clear();
- d_ci.clear();
- d_ci_exp.clear();
- d_ci_max.clear();
-
- Trace("nl-ext-mv") << "Extended terms : " << std::endl;
- // for computing congruence
- std::map<Kind, ArgTrie> argTrie;
- for (unsigned i = 0, xsize = xts.size(); i < xsize; i++)
- {
- Node a = xts[i];
- d_model.computeConcreteModelValue(a);
- d_model.computeAbstractModelValue(a);
- d_model.printModelValue("nl-ext-mv", a);
- Kind ak = a.getKind();
- if (ak == NONLINEAR_MULT)
- {
- d_ms.push_back(a);
-
- // context-independent registration
- d_mdb.registerMonomial(a);
-
- const std::vector<Node>& varList = d_mdb.getVariableList(a);
- for (const Node& v : varList)
- {
- if (std::find(d_ms_vars.begin(), d_ms_vars.end(), v) == d_ms_vars.end())
- {
- d_ms_vars.push_back(v);
- }
- Node mvk = d_model.computeAbstractModelValue(v);
- if (!mvk.isConst())
- {
- d_m_nconst_factor[a] = true;
- }
- }
- // mark processed if has a "one" factor (will look at reduced monomial)?
- }
- }
-
- // register constants
- d_mdb.registerMonomial(d_one);
- for (unsigned j = 0; j < d_order_points.size(); j++)
- {
- Node c = d_order_points[j];
- d_model.computeConcreteModelValue(c);
- d_model.computeAbstractModelValue(c);
- }
-
- // register variables
- Trace("nl-ext-mv") << "Variables in monomials : " << std::endl;
- for (unsigned i = 0; i < d_ms_vars.size(); i++)
- {
- Node v = d_ms_vars[i];
- d_mdb.registerMonomial(v);
- d_model.computeConcreteModelValue(v);
- d_model.computeAbstractModelValue(v);
- d_model.printModelValue("nl-ext-mv", v);
- }
-
- Trace("nl-ext") << "We have " << d_ms.size() << " monomials." << std::endl;
-}
-
-void NlSolver::setMonomialFactor(Node a, Node b, const NodeMultiset& common)
-{
- // Could not tell if this was being inserted intentionally or not.
- std::map<Node, Node>& mono_diff_a = d_mono_diff[a];
- if (mono_diff_a.find(b) == mono_diff_a.end())
- {
- Trace("nl-ext-mono-factor")
- << "Set monomial factor for " << a << "/" << b << std::endl;
- mono_diff_a[b] = d_mdb.mkMonomialRemFactor(a, common);
- }
-}
-
-std::vector<NlLemma> NlSolver::checkSplitZero()
-{
- std::vector<NlLemma> lemmas;
- for (unsigned i = 0; i < d_ms_vars.size(); i++)
- {
- Node v = d_ms_vars[i];
- if (d_zero_split.insert(v))
- {
- Node eq = v.eqNode(d_zero);
- eq = Rewriter::rewrite(eq);
- Node literal = d_containing.getValuation().ensureLiteral(eq);
- d_containing.getOutputChannel().requirePhase(literal, true);
- lemmas.emplace_back(literal.orNode(literal.negate()),
- Inference::SPLIT_ZERO);
- }
- }
- return lemmas;
-}
-
-void NlSolver::assignOrderIds(std::vector<Node>& vars,
- NodeMultiset& order,
- bool isConcrete,
- bool isAbsolute)
-{
- SortNlModel smv;
- smv.d_nlm = &d_model;
- smv.d_isConcrete = isConcrete;
- smv.d_isAbsolute = isAbsolute;
- smv.d_reverse_order = false;
- std::sort(vars.begin(), vars.end(), smv);
-
- order.clear();
- // assign ordering id's
- unsigned counter = 0;
- unsigned order_index = isConcrete ? 0 : 1;
- Node prev;
- for (unsigned j = 0; j < vars.size(); j++)
- {
- Node x = vars[j];
- Node v = d_model.computeModelValue(x, isConcrete);
- if (!v.isConst())
- {
- Trace("nl-ext-mvo") << "..do not assign order to " << x << " : " << v
- << std::endl;
- // don't assign for non-constant values (transcendental function apps)
- break;
- }
- Trace("nl-ext-mvo") << " order " << x << " : " << v << std::endl;
- if (v != prev)
- {
- // builtin points
- bool success;
- do
- {
- success = false;
- if (order_index < d_order_points.size())
- {
- Node vv = d_model.computeModelValue(d_order_points[order_index],
- isConcrete);
- if (d_model.compareValue(v, vv, isAbsolute) <= 0)
- {
- counter++;
- Trace("nl-ext-mvo") << "O[" << d_order_points[order_index]
- << "] = " << counter << std::endl;
- order[d_order_points[order_index]] = counter;
- prev = vv;
- order_index++;
- success = true;
- }
- }
- } while (success);
- }
- if (prev.isNull() || d_model.compareValue(v, prev, isAbsolute) != 0)
- {
- counter++;
- }
- Trace("nl-ext-mvo") << "O[" << x << "] = " << counter << std::endl;
- order[x] = counter;
- prev = v;
- }
- while (order_index < d_order_points.size())
- {
- counter++;
- Trace("nl-ext-mvo") << "O[" << d_order_points[order_index]
- << "] = " << counter << std::endl;
- order[d_order_points[order_index]] = counter;
- order_index++;
- }
-}
-
-// show a <> 0 by inequalities between variables in monomial a w.r.t 0
-int NlSolver::compareSign(Node oa,
- Node a,
- unsigned a_index,
- int status,
- std::vector<Node>& exp,
- std::vector<NlLemma>& lem)
-{
- Trace("nl-ext-debug") << "Process " << a << " at index " << a_index
- << ", status is " << status << std::endl;
- NodeManager* nm = NodeManager::currentNM();
- Node mvaoa = d_model.computeAbstractModelValue(oa);
- const std::vector<Node>& vla = d_mdb.getVariableList(a);
- if (a_index == vla.size())
- {
- if (mvaoa.getConst<Rational>().sgn() != status)
- {
- Node lemma =
- safeConstructNary(AND, exp).impNode(mkLit(oa, d_zero, status * 2));
- lem.emplace_back(lemma, Inference::SIGN);
- }
- return status;
- }
- Assert(a_index < vla.size());
- Node av = vla[a_index];
- unsigned aexp = d_mdb.getExponent(a, av);
- // take current sign in model
- Node mvaav = d_model.computeAbstractModelValue(av);
- int sgn = mvaav.getConst<Rational>().sgn();
- Trace("nl-ext-debug") << "Process var " << av << "^" << aexp
- << ", model sign = " << sgn << std::endl;
- if (sgn == 0)
- {
- if (mvaoa.getConst<Rational>().sgn() != 0)
- {
- Node lemma = av.eqNode(d_zero).impNode(oa.eqNode(d_zero));
- lem.emplace_back(lemma, Inference::SIGN);
- }
- return 0;
- }
- if (aexp % 2 == 0)
- {
- exp.push_back(av.eqNode(d_zero).negate());
- return compareSign(oa, a, a_index + 1, status, exp, lem);
- }
- exp.push_back(nm->mkNode(sgn == 1 ? GT : LT, av, d_zero));
- return compareSign(oa, a, a_index + 1, status * sgn, exp, lem);
-}
-
-bool NlSolver::compareMonomial(
- Node oa,
- Node a,
- NodeMultiset& a_exp_proc,
- Node ob,
- Node b,
- NodeMultiset& b_exp_proc,
- std::vector<Node>& exp,
- std::vector<NlLemma>& lem,
- std::map<int, std::map<Node, std::map<Node, Node> > >& cmp_infers)
-{
- Trace("nl-ext-comp-debug")
- << "Check |" << a << "| >= |" << b << "|" << std::endl;
- unsigned pexp_size = exp.size();
- if (compareMonomial(
- oa, a, 0, a_exp_proc, ob, b, 0, b_exp_proc, 0, exp, lem, cmp_infers))
- {
- return true;
- }
- exp.resize(pexp_size);
- Trace("nl-ext-comp-debug")
- << "Check |" << b << "| >= |" << a << "|" << std::endl;
- if (compareMonomial(
- ob, b, 0, b_exp_proc, oa, a, 0, a_exp_proc, 0, exp, lem, cmp_infers))
- {
- return true;
- }
- return false;
-}
-
-Node NlSolver::mkLit(Node a, Node b, int status, bool isAbsolute)
-{
- if (status == 0)
- {
- Node a_eq_b = a.eqNode(b);
- if (!isAbsolute)
- {
- return a_eq_b;
- }
- Node negate_b = NodeManager::currentNM()->mkNode(UMINUS, b);
- return a_eq_b.orNode(a.eqNode(negate_b));
- }
- else if (status < 0)
- {
- return mkLit(b, a, -status);
- }
- Assert(status == 1 || status == 2);
- NodeManager* nm = NodeManager::currentNM();
- Kind greater_op = status == 1 ? GEQ : GT;
- if (!isAbsolute)
- {
- return nm->mkNode(greater_op, a, b);
- }
- // return nm->mkNode( greater_op, mkAbs( a ), mkAbs( b ) );
- Node zero = mkRationalNode(0);
- Node a_is_nonnegative = nm->mkNode(GEQ, a, zero);
- Node b_is_nonnegative = nm->mkNode(GEQ, b, zero);
- Node negate_a = nm->mkNode(UMINUS, a);
- Node negate_b = nm->mkNode(UMINUS, b);
- return a_is_nonnegative.iteNode(
- b_is_nonnegative.iteNode(nm->mkNode(greater_op, a, b),
- nm->mkNode(greater_op, a, negate_b)),
- b_is_nonnegative.iteNode(nm->mkNode(greater_op, negate_a, b),
- nm->mkNode(greater_op, negate_a, negate_b)));
-}
-
-bool NlSolver::cmp_holds(Node x,
- Node y,
- std::map<Node, std::map<Node, Node> >& cmp_infers,
- std::vector<Node>& exp,
- std::map<Node, bool>& visited)
-{
- if (x == y)
- {
- return true;
- }
- else if (visited.find(x) != visited.end())
- {
- return false;
- }
- visited[x] = true;
- std::map<Node, std::map<Node, Node> >::iterator it = cmp_infers.find(x);
- if (it != cmp_infers.end())
- {
- for (std::map<Node, Node>::iterator itc = it->second.begin();
- itc != it->second.end();
- ++itc)
- {
- exp.push_back(itc->second);
- if (cmp_holds(itc->first, y, cmp_infers, exp, visited))
- {
- return true;
- }
- exp.pop_back();
- }
- }
- return false;
-}
-
-// trying to show a ( >, = ) b by inequalities between variables in
-// monomials a,b
-bool NlSolver::compareMonomial(
- Node oa,
- Node a,
- unsigned a_index,
- NodeMultiset& a_exp_proc,
- Node ob,
- Node b,
- unsigned b_index,
- NodeMultiset& b_exp_proc,
- int status,
- std::vector<Node>& exp,
- std::vector<NlLemma>& lem,
- std::map<int, std::map<Node, std::map<Node, Node> > >& cmp_infers)
-{
- Trace("nl-ext-comp-debug")
- << "compareMonomial " << oa << " and " << ob << ", indices = " << a_index
- << " " << b_index << std::endl;
- Assert(status == 0 || status == 2);
- const std::vector<Node>& vla = d_mdb.getVariableList(a);
- const std::vector<Node>& vlb = d_mdb.getVariableList(b);
- if (a_index == vla.size() && b_index == vlb.size())
- {
- // finished, compare absolute value of abstract model values
- int modelStatus = d_model.compare(oa, ob, false, true) * -2;
- Trace("nl-ext-comp") << "...finished comparison with " << oa << " <"
- << status << "> " << ob
- << ", model status = " << modelStatus << std::endl;
- if (status != modelStatus)
- {
- Trace("nl-ext-comp-infer")
- << "infer : " << oa << " <" << status << "> " << ob << std::endl;
- if (status == 2)
- {
- // must state that all variables are non-zero
- for (unsigned j = 0; j < vla.size(); j++)
- {
- exp.push_back(vla[j].eqNode(d_zero).negate());
- }
- }
- NodeManager* nm = NodeManager::currentNM();
- Node clem = nm->mkNode(
- IMPLIES, safeConstructNary(AND, exp), mkLit(oa, ob, status, true));
- Trace("nl-ext-comp-lemma") << "comparison lemma : " << clem << std::endl;
- lem.emplace_back(clem, Inference::COMPARISON);
- cmp_infers[status][oa][ob] = clem;
- }
- return true;
- }
- // get a/b variable information
- Node av;
- unsigned aexp = 0;
- unsigned avo = 0;
- if (a_index < vla.size())
- {
- av = vla[a_index];
- unsigned aexpTotal = d_mdb.getExponent(a, av);
- Assert(a_exp_proc[av] <= aexpTotal);
- aexp = aexpTotal - a_exp_proc[av];
- if (aexp == 0)
- {
- return compareMonomial(oa,
- a,
- a_index + 1,
- a_exp_proc,
- ob,
- b,
- b_index,
- b_exp_proc,
- status,
- exp,
- lem,
- cmp_infers);
- }
- Assert(d_order_vars.find(av) != d_order_vars.end());
- avo = d_order_vars[av];
- }
- Node bv;
- unsigned bexp = 0;
- unsigned bvo = 0;
- if (b_index < vlb.size())
- {
- bv = vlb[b_index];
- unsigned bexpTotal = d_mdb.getExponent(b, bv);
- Assert(b_exp_proc[bv] <= bexpTotal);
- bexp = bexpTotal - b_exp_proc[bv];
- if (bexp == 0)
- {
- return compareMonomial(oa,
- a,
- a_index,
- a_exp_proc,
- ob,
- b,
- b_index + 1,
- b_exp_proc,
- status,
- exp,
- lem,
- cmp_infers);
- }
- Assert(d_order_vars.find(bv) != d_order_vars.end());
- bvo = d_order_vars[bv];
- }
- // get "one" information
- Assert(d_order_vars.find(d_one) != d_order_vars.end());
- unsigned ovo = d_order_vars[d_one];
- Trace("nl-ext-comp-debug") << "....vars : " << av << "^" << aexp << " " << bv
- << "^" << bexp << std::endl;
-
- //--- cases
- if (av.isNull())
- {
- if (bvo <= ovo)
- {
- Trace("nl-ext-comp-debug") << "...take leading " << bv << std::endl;
- // can multiply b by <=1
- exp.push_back(mkLit(d_one, bv, bvo == ovo ? 0 : 2, true));
- return compareMonomial(oa,
- a,
- a_index,
- a_exp_proc,
- ob,
- b,
- b_index + 1,
- b_exp_proc,
- bvo == ovo ? status : 2,
- exp,
- lem,
- cmp_infers);
- }
- Trace("nl-ext-comp-debug")
- << "...failure, unmatched |b|>1 component." << std::endl;
- return false;
- }
- else if (bv.isNull())
- {
- if (avo >= ovo)
- {
- Trace("nl-ext-comp-debug") << "...take leading " << av << std::endl;
- // can multiply a by >=1
- exp.push_back(mkLit(av, d_one, avo == ovo ? 0 : 2, true));
- return compareMonomial(oa,
- a,
- a_index + 1,
- a_exp_proc,
- ob,
- b,
- b_index,
- b_exp_proc,
- avo == ovo ? status : 2,
- exp,
- lem,
- cmp_infers);
- }
- Trace("nl-ext-comp-debug")
- << "...failure, unmatched |a|<1 component." << std::endl;
- return false;
- }
- Assert(!av.isNull() && !bv.isNull());
- if (avo >= bvo)
- {
- if (bvo < ovo && avo >= ovo)
- {
- Trace("nl-ext-comp-debug") << "...take leading " << av << std::endl;
- // do avo>=1 instead
- exp.push_back(mkLit(av, d_one, avo == ovo ? 0 : 2, true));
- return compareMonomial(oa,
- a,
- a_index + 1,
- a_exp_proc,
- ob,
- b,
- b_index,
- b_exp_proc,
- avo == ovo ? status : 2,
- exp,
- lem,
- cmp_infers);
- }
- unsigned min_exp = aexp > bexp ? bexp : aexp;
- a_exp_proc[av] += min_exp;
- b_exp_proc[bv] += min_exp;
- Trace("nl-ext-comp-debug") << "...take leading " << min_exp << " from "
- << av << " and " << bv << std::endl;
- exp.push_back(mkLit(av, bv, avo == bvo ? 0 : 2, true));
- bool ret = compareMonomial(oa,
- a,
- a_index,
- a_exp_proc,
- ob,
- b,
- b_index,
- b_exp_proc,
- avo == bvo ? status : 2,
- exp,
- lem,
- cmp_infers);
- a_exp_proc[av] -= min_exp;
- b_exp_proc[bv] -= min_exp;
- return ret;
- }
- if (bvo <= ovo)
- {
- Trace("nl-ext-comp-debug") << "...take leading " << bv << std::endl;
- // try multiply b <= 1
- exp.push_back(mkLit(d_one, bv, bvo == ovo ? 0 : 2, true));
- return compareMonomial(oa,
- a,
- a_index,
- a_exp_proc,
- ob,
- b,
- b_index + 1,
- b_exp_proc,
- bvo == ovo ? status : 2,
- exp,
- lem,
- cmp_infers);
- }
- Trace("nl-ext-comp-debug")
- << "...failure, leading |b|>|a|>1 component." << std::endl;
- return false;
-}
-
-std::vector<NlLemma> NlSolver::checkMonomialSign()
-{
- std::vector<NlLemma> lemmas;
- std::map<Node, int> signs;
- Trace("nl-ext") << "Get monomial sign lemmas..." << std::endl;
- for (unsigned j = 0; j < d_ms.size(); j++)
- {
- Node a = d_ms[j];
- if (d_ms_proc.find(a) == d_ms_proc.end())
- {
- std::vector<Node> exp;
- if (Trace.isOn("nl-ext-debug"))
- {
- Node cmva = d_model.computeConcreteModelValue(a);
- Trace("nl-ext-debug")
- << " process " << a << ", mv=" << cmva << "..." << std::endl;
- }
- if (d_m_nconst_factor.find(a) == d_m_nconst_factor.end())
- {
- signs[a] = compareSign(a, a, 0, 1, exp, lemmas);
- if (signs[a] == 0)
- {
- d_ms_proc[a] = true;
- Trace("nl-ext-debug")
- << "...mark " << a << " reduced since its value is 0."
- << std::endl;
- }
- }
- else
- {
- Trace("nl-ext-debug")
- << "...can't conclude sign lemma for " << a
- << " since model value of a factor is non-constant." << std::endl;
- }
- }
- }
- return lemmas;
-}
-
-std::vector<NlLemma> NlSolver::checkMonomialMagnitude(unsigned c)
-{
- // ensure information is setup
- if (c == 0)
- {
- // sort by absolute values of abstract model values
- assignOrderIds(d_ms_vars, d_order_vars, false, true);
-
- // sort individual variable lists
- Trace("nl-ext-proc") << "Assign order var lists..." << std::endl;
- d_mdb.sortVariablesByModel(d_ms, d_model);
- }
-
- unsigned r = 1;
- std::vector<NlLemma> lemmas;
- // if (x,y,L) in cmp_infers, then x > y inferred as conclusion of L
- // in lemmas
- std::map<int, std::map<Node, std::map<Node, Node> > > cmp_infers;
- Trace("nl-ext") << "Get monomial comparison lemmas (order=" << r
- << ", compare=" << c << ")..." << std::endl;
- for (unsigned j = 0; j < d_ms.size(); j++)
- {
- Node a = d_ms[j];
- if (d_ms_proc.find(a) == d_ms_proc.end()
- && d_m_nconst_factor.find(a) == d_m_nconst_factor.end())
- {
- if (c == 0)
- {
- // compare magnitude against 1
- std::vector<Node> exp;
- NodeMultiset a_exp_proc;
- NodeMultiset b_exp_proc;
- compareMonomial(a,
- a,
- a_exp_proc,
- d_one,
- d_one,
- b_exp_proc,
- exp,
- lemmas,
- cmp_infers);
- }
- else
- {
- const NodeMultiset& mea = d_mdb.getMonomialExponentMap(a);
- if (c == 1)
- {
- // could compare not just against containing variables?
- // compare magnitude against variables
- for (unsigned k = 0; k < d_ms_vars.size(); k++)
- {
- Node v = d_ms_vars[k];
- Node mvcv = d_model.computeConcreteModelValue(v);
- if (mvcv.isConst())
- {
- std::vector<Node> exp;
- NodeMultiset a_exp_proc;
- NodeMultiset b_exp_proc;
- if (mea.find(v) != mea.end())
- {
- a_exp_proc[v] = 1;
- b_exp_proc[v] = 1;
- setMonomialFactor(a, v, a_exp_proc);
- setMonomialFactor(v, a, b_exp_proc);
- compareMonomial(a,
- a,
- a_exp_proc,
- v,
- v,
- b_exp_proc,
- exp,
- lemmas,
- cmp_infers);
- }
- }
- }
- }
- else
- {
- // compare magnitude against other non-linear monomials
- for (unsigned k = (j + 1); k < d_ms.size(); k++)
- {
- Node b = d_ms[k];
- //(signs[a]==signs[b])==(r==0)
- if (d_ms_proc.find(b) == d_ms_proc.end()
- && d_m_nconst_factor.find(b) == d_m_nconst_factor.end())
- {
- const NodeMultiset& meb = d_mdb.getMonomialExponentMap(b);
-
- std::vector<Node> exp;
- // take common factors of monomials, set minimum of
- // common exponents as processed
- NodeMultiset a_exp_proc;
- NodeMultiset b_exp_proc;
- for (NodeMultiset::const_iterator itmea2 = mea.begin();
- itmea2 != mea.end();
- ++itmea2)
- {
- NodeMultiset::const_iterator itmeb2 = meb.find(itmea2->first);
- if (itmeb2 != meb.end())
- {
- unsigned min_exp = itmea2->second > itmeb2->second
- ? itmeb2->second
- : itmea2->second;
- a_exp_proc[itmea2->first] = min_exp;
- b_exp_proc[itmea2->first] = min_exp;
- Trace("nl-ext-comp") << "Common exponent : " << itmea2->first
- << " : " << min_exp << std::endl;
- }
- }
- if (!a_exp_proc.empty())
- {
- setMonomialFactor(a, b, a_exp_proc);
- setMonomialFactor(b, a, b_exp_proc);
- }
- /*
- if( !a_exp_proc.empty() ){
- //reduction based on common exponents a > 0 => ( a * b
- <> a * c <=> b <> c ), a < 0 => ( a * b <> a * c <=> b
- !<> c ) ? }else{ compareMonomial( a, a, a_exp_proc, b,
- b, b_exp_proc, exp, lemmas );
- }
- */
- compareMonomial(
- a, a, a_exp_proc, b, b, b_exp_proc, exp, lemmas, cmp_infers);
- }
- }
- }
- }
- }
- }
- // remove redundant lemmas, e.g. if a > b, b > c, a > c were
- // inferred, discard lemma with conclusion a > c
- Trace("nl-ext-comp") << "Compute redundancies for " << lemmas.size()
- << " lemmas." << std::endl;
- // naive
- std::unordered_set<Node, NodeHashFunction> r_lemmas;
- for (std::map<int, std::map<Node, std::map<Node, Node> > >::iterator itb =
- cmp_infers.begin();
- itb != cmp_infers.end();
- ++itb)
- {
- for (std::map<Node, std::map<Node, Node> >::iterator itc =
- itb->second.begin();
- itc != itb->second.end();
- ++itc)
- {
- for (std::map<Node, Node>::iterator itc2 = itc->second.begin();
- itc2 != itc->second.end();
- ++itc2)
- {
- std::map<Node, bool> visited;
- for (std::map<Node, Node>::iterator itc3 = itc->second.begin();
- itc3 != itc->second.end();
- ++itc3)
- {
- if (itc3->first != itc2->first)
- {
- std::vector<Node> exp;
- if (cmp_holds(itc3->first, itc2->first, itb->second, exp, visited))
- {
- r_lemmas.insert(itc2->second);
- Trace("nl-ext-comp")
- << "...inference of " << itc->first << " > " << itc2->first
- << " was redundant." << std::endl;
- break;
- }
- }
- }
- }
- }
- }
- std::vector<NlLemma> nr_lemmas;
- for (unsigned i = 0; i < lemmas.size(); i++)
- {
- if (r_lemmas.find(lemmas[i].d_lemma) == r_lemmas.end())
- {
- nr_lemmas.push_back(lemmas[i]);
- }
- }
- // could only take maximal lower/minimial lower bounds?
-
- Trace("nl-ext-comp") << nr_lemmas.size() << " / " << lemmas.size()
- << " were non-redundant." << std::endl;
- return nr_lemmas;
-}
-
-std::vector<NlLemma> NlSolver::checkTangentPlanes()
-{
- std::vector<NlLemma> lemmas;
- Trace("nl-ext") << "Get monomial tangent plane lemmas..." << std::endl;
- NodeManager* nm = NodeManager::currentNM();
- const std::map<Node, std::vector<Node> >& ccMap =
- d_mdb.getContainsChildrenMap();
- unsigned kstart = d_ms_vars.size();
- for (unsigned k = kstart; k < d_mterms.size(); k++)
- {
- Node t = d_mterms[k];
- // if this term requires a refinement
- if (d_tplane_refine.find(t) == d_tplane_refine.end())
- {
- continue;
- }
- Trace("nl-ext-tplanes")
- << "Look at monomial requiring refinement : " << t << std::endl;
- // get a decomposition
- std::map<Node, std::vector<Node> >::const_iterator it = ccMap.find(t);
- if (it == ccMap.end())
- {
- continue;
- }
- std::map<Node, std::map<Node, bool> > dproc;
- for (unsigned j = 0; j < it->second.size(); j++)
- {
- Node tc = it->second[j];
- if (tc != d_one)
- {
- Node tc_diff = d_mdb.getContainsDiffNl(tc, t);
- Assert(!tc_diff.isNull());
- Node a = tc < tc_diff ? tc : tc_diff;
- Node b = tc < tc_diff ? tc_diff : tc;
- if (dproc[a].find(b) == dproc[a].end())
- {
- dproc[a][b] = true;
- Trace("nl-ext-tplanes")
- << " decomposable into : " << a << " * " << b << std::endl;
- Node a_v_c = d_model.computeAbstractModelValue(a);
- Node b_v_c = d_model.computeAbstractModelValue(b);
- // points we will add tangent planes for
- std::vector<Node> pts[2];
- pts[0].push_back(a_v_c);
- pts[1].push_back(b_v_c);
- // if previously refined
- bool prevRefine = d_tangent_val_bound[0][a].find(b)
- != d_tangent_val_bound[0][a].end();
- // a_min, a_max, b_min, b_max
- for (unsigned p = 0; p < 4; p++)
- {
- Node curr_v = p <= 1 ? a_v_c : b_v_c;
- if (prevRefine)
- {
- Node pt_v = d_tangent_val_bound[p][a][b];
- Assert(!pt_v.isNull());
- if (curr_v != pt_v)
- {
- Node do_extend =
- nm->mkNode((p == 1 || p == 3) ? GT : LT, curr_v, pt_v);
- do_extend = Rewriter::rewrite(do_extend);
- if (do_extend == d_true)
- {
- for (unsigned q = 0; q < 2; q++)
- {
- pts[p <= 1 ? 0 : 1].push_back(curr_v);
- pts[p <= 1 ? 1 : 0].push_back(
- d_tangent_val_bound[p <= 1 ? 2 + q : q][a][b]);
- }
- }
- }
- }
- else
- {
- d_tangent_val_bound[p][a][b] = curr_v;
- }
- }
-
- for (unsigned p = 0; p < pts[0].size(); p++)
- {
- Node a_v = pts[0][p];
- Node b_v = pts[1][p];
-
- // tangent plane
- Node tplane = nm->mkNode(
- MINUS,
- nm->mkNode(
- PLUS, nm->mkNode(MULT, b_v, a), nm->mkNode(MULT, a_v, b)),
- nm->mkNode(MULT, a_v, b_v));
- // conjuncts of the tangent plane lemma
- std::vector<Node> tplaneConj;
- for (unsigned d = 0; d < 4; d++)
- {
- Node aa = nm->mkNode(d == 0 || d == 3 ? GEQ : LEQ, a, a_v);
- Node ab = nm->mkNode(d == 1 || d == 3 ? GEQ : LEQ, b, b_v);
- Node conc = nm->mkNode(d <= 1 ? LEQ : GEQ, t, tplane);
- Node tlem = nm->mkNode(OR, aa.negate(), ab.negate(), conc);
- Trace("nl-ext-tplanes")
- << "Tangent plane lemma : " << tlem << std::endl;
- tplaneConj.push_back(tlem);
- }
-
- // tangent plane reverse implication
-
- // t <= tplane -> ( (a <= a_v ^ b >= b_v) v
- // (a >= a_v ^ b <= b_v) ).
- // in clause form, the above becomes
- // t <= tplane -> a <= a_v v b <= b_v.
- // t <= tplane -> b >= b_v v a >= a_v.
- Node a_leq_av = nm->mkNode(LEQ, a, a_v);
- Node b_leq_bv = nm->mkNode(LEQ, b, b_v);
- Node a_geq_av = nm->mkNode(GEQ, a, a_v);
- Node b_geq_bv = nm->mkNode(GEQ, b, b_v);
-
- Node t_leq_tplane = nm->mkNode(LEQ, t, tplane);
- Node a_leq_av_or_b_leq_bv = nm->mkNode(OR, a_leq_av, b_leq_bv);
- Node b_geq_bv_or_a_geq_av = nm->mkNode(OR, b_geq_bv, a_geq_av);
- Node ub_reverse1 =
- nm->mkNode(OR, t_leq_tplane.negate(), a_leq_av_or_b_leq_bv);
- Trace("nl-ext-tplanes")
- << "Tangent plane lemma (reverse) : " << ub_reverse1
- << std::endl;
- tplaneConj.push_back(ub_reverse1);
- Node ub_reverse2 =
- nm->mkNode(OR, t_leq_tplane.negate(), b_geq_bv_or_a_geq_av);
- Trace("nl-ext-tplanes")
- << "Tangent plane lemma (reverse) : " << ub_reverse2
- << std::endl;
- tplaneConj.push_back(ub_reverse2);
-
- // t >= tplane -> ( (a <= a_v ^ b <= b_v) v
- // (a >= a_v ^ b >= b_v) ).
- // in clause form, the above becomes
- // t >= tplane -> a <= a_v v b >= b_v.
- // t >= tplane -> b >= b_v v a <= a_v
- Node t_geq_tplane = nm->mkNode(GEQ, t, tplane);
- Node a_leq_av_or_b_geq_bv = nm->mkNode(OR, a_leq_av, b_geq_bv);
- Node a_geq_av_or_b_leq_bv = nm->mkNode(OR, a_geq_av, b_leq_bv);
- Node lb_reverse1 =
- nm->mkNode(OR, t_geq_tplane.negate(), a_leq_av_or_b_geq_bv);
- Trace("nl-ext-tplanes")
- << "Tangent plane lemma (reverse) : " << lb_reverse1
- << std::endl;
- tplaneConj.push_back(lb_reverse1);
- Node lb_reverse2 =
- nm->mkNode(OR, t_geq_tplane.negate(), a_geq_av_or_b_leq_bv);
- Trace("nl-ext-tplanes")
- << "Tangent plane lemma (reverse) : " << lb_reverse2
- << std::endl;
- tplaneConj.push_back(lb_reverse2);
-
- Node tlem = nm->mkNode(AND, tplaneConj);
- lemmas.emplace_back(tlem, Inference::TANGENT_PLANE);
- }
- }
- }
- }
- }
- Trace("nl-ext") << "...trying " << lemmas.size() << " tangent plane lemmas..."
- << std::endl;
- return lemmas;
-}
-
-std::vector<NlLemma> NlSolver::checkMonomialInferBounds(
- std::vector<NlLemma>& nt_lemmas,
- const std::vector<Node>& asserts,
- const std::vector<Node>& false_asserts)
-{
- // sort monomials by degree
- Trace("nl-ext-proc") << "Sort monomials by degree..." << std::endl;
- d_mdb.sortByDegree(d_ms);
- // all monomials
- d_mterms.insert(d_mterms.end(), d_ms_vars.begin(), d_ms_vars.end());
- d_mterms.insert(d_mterms.end(), d_ms.begin(), d_ms.end());
-
- const std::map<Node, std::map<Node, ConstraintInfo> >& cim =
- d_cdb.getConstraints();
-
- std::vector<NlLemma> lemmas;
- NodeManager* nm = NodeManager::currentNM();
- // register constraints
- Trace("nl-ext-debug") << "Register bound constraints..." << std::endl;
- for (const Node& lit : asserts)
- {
- bool polarity = lit.getKind() != NOT;
- Node atom = lit.getKind() == NOT ? lit[0] : lit;
- d_cdb.registerConstraint(atom);
- bool is_false_lit =
- std::find(false_asserts.begin(), false_asserts.end(), lit)
- != false_asserts.end();
- // add information about bounds to variables
- std::map<Node, std::map<Node, ConstraintInfo> >::const_iterator itc =
- cim.find(atom);
- if (itc == cim.end())
- {
- continue;
- }
- for (const std::pair<const Node, ConstraintInfo>& itcc : itc->second)
- {
- Node x = itcc.first;
- Node coeff = itcc.second.d_coeff;
- Node rhs = itcc.second.d_rhs;
- Kind type = itcc.second.d_type;
- Node exp = lit;
- if (!polarity)
- {
- // reverse
- if (type == EQUAL)
- {
- // we will take the strict inequality in the direction of the
- // model
- Node lhs = ArithMSum::mkCoeffTerm(coeff, x);
- Node query = nm->mkNode(GT, lhs, rhs);
- Node query_mv = d_model.computeAbstractModelValue(query);
- if (query_mv == d_true)
- {
- exp = query;
- type = GT;
- }
- else
- {
- Assert(query_mv == d_false);
- exp = nm->mkNode(LT, lhs, rhs);
- type = LT;
- }
- }
- else
- {
- type = negateKind(type);
- }
- }
- // add to status if maximal degree
- d_ci_max[x][coeff][rhs] = d_cdb.isMaximal(atom, x);
- if (Trace.isOn("nl-ext-bound-debug2"))
- {
- Node t = ArithMSum::mkCoeffTerm(coeff, x);
- Trace("nl-ext-bound-debug2") << "Add Bound: " << t << " " << type << " "
- << rhs << " by " << exp << std::endl;
- }
- bool updated = true;
- std::map<Node, Kind>::iterator its = d_ci[x][coeff].find(rhs);
- if (its == d_ci[x][coeff].end())
- {
- d_ci[x][coeff][rhs] = type;
- d_ci_exp[x][coeff][rhs] = exp;
- }
- else if (type != its->second)
- {
- Trace("nl-ext-bound-debug2")
- << "Joining kinds : " << type << " " << its->second << std::endl;
- Kind jk = joinKinds(type, its->second);
- if (jk == UNDEFINED_KIND)
- {
- updated = false;
- }
- else if (jk != its->second)
- {
- if (jk == type)
- {
- d_ci[x][coeff][rhs] = type;
- d_ci_exp[x][coeff][rhs] = exp;
- }
- else
- {
- d_ci[x][coeff][rhs] = jk;
- d_ci_exp[x][coeff][rhs] =
- nm->mkNode(AND, d_ci_exp[x][coeff][rhs], exp);
- }
- }
- else
- {
- updated = false;
- }
- }
- if (Trace.isOn("nl-ext-bound"))
- {
- if (updated)
- {
- Trace("nl-ext-bound") << "Bound: ";
- debugPrintBound("nl-ext-bound", coeff, x, d_ci[x][coeff][rhs], rhs);
- Trace("nl-ext-bound") << " by " << d_ci_exp[x][coeff][rhs];
- if (d_ci_max[x][coeff][rhs])
- {
- Trace("nl-ext-bound") << ", is max degree";
- }
- Trace("nl-ext-bound") << std::endl;
- }
- }
- // compute if bound is not satisfied, and store what is required
- // for a possible refinement
- if (options::nlExtTangentPlanes())
- {
- if (is_false_lit)
- {
- d_tplane_refine.insert(x);
- }
- }
- }
- }
- // reflexive constraints
- Node null_coeff;
- for (unsigned j = 0; j < d_mterms.size(); j++)
- {
- Node n = d_mterms[j];
- d_ci[n][null_coeff][n] = EQUAL;
- d_ci_exp[n][null_coeff][n] = d_true;
- d_ci_max[n][null_coeff][n] = false;
- }
-
- Trace("nl-ext") << "Get inferred bound lemmas..." << std::endl;
- const std::map<Node, std::vector<Node> >& cpMap =
- d_mdb.getContainsParentMap();
- for (unsigned k = 0; k < d_mterms.size(); k++)
- {
- Node x = d_mterms[k];
- Trace("nl-ext-bound-debug")
- << "Process bounds for " << x << " : " << std::endl;
- std::map<Node, std::vector<Node> >::const_iterator itm = cpMap.find(x);
- if (itm == cpMap.end())
- {
- Trace("nl-ext-bound-debug") << "...has no parent monomials." << std::endl;
- continue;
- }
- Trace("nl-ext-bound-debug")
- << "...has " << itm->second.size() << " parent monomials." << std::endl;
- // check derived bounds
- std::map<Node, std::map<Node, std::map<Node, Kind> > >::iterator itc =
- d_ci.find(x);
- if (itc == d_ci.end())
- {
- continue;
- }
- for (std::map<Node, std::map<Node, Kind> >::iterator itcc =
- itc->second.begin();
- itcc != itc->second.end();
- ++itcc)
- {
- Node coeff = itcc->first;
- Node t = ArithMSum::mkCoeffTerm(coeff, x);
- for (std::map<Node, Kind>::iterator itcr = itcc->second.begin();
- itcr != itcc->second.end();
- ++itcr)
- {
- Node rhs = itcr->first;
- // only consider this bound if maximal degree
- if (!d_ci_max[x][coeff][rhs])
- {
- continue;
- }
- Kind type = itcr->second;
- for (unsigned j = 0; j < itm->second.size(); j++)
- {
- Node y = itm->second[j];
- Node mult = d_mdb.getContainsDiff(x, y);
- // x <k> t => m*x <k'> t where y = m*x
- // get the sign of mult
- Node mmv = d_model.computeConcreteModelValue(mult);
- Trace("nl-ext-bound-debug2")
- << "Model value of " << mult << " is " << mmv << std::endl;
- if (!mmv.isConst())
- {
- Trace("nl-ext-bound-debug")
- << " ...coefficient " << mult
- << " is non-constant (probably transcendental)." << std::endl;
- continue;
- }
- int mmv_sign = mmv.getConst<Rational>().sgn();
- Trace("nl-ext-bound-debug2")
- << " sign of " << mmv << " is " << mmv_sign << std::endl;
- if (mmv_sign == 0)
- {
- Trace("nl-ext-bound-debug")
- << " ...coefficient " << mult << " is zero." << std::endl;
- continue;
- }
- Trace("nl-ext-bound-debug")
- << " from " << x << " * " << mult << " = " << y << " and " << t
- << " " << type << " " << rhs << ", infer : " << std::endl;
- Kind infer_type = mmv_sign == -1 ? reverseRelationKind(type) : type;
- Node infer_lhs = nm->mkNode(MULT, mult, t);
- Node infer_rhs = nm->mkNode(MULT, mult, rhs);
- Node infer = nm->mkNode(infer_type, infer_lhs, infer_rhs);
- Trace("nl-ext-bound-debug") << " " << infer << std::endl;
- infer = Rewriter::rewrite(infer);
- Trace("nl-ext-bound-debug2")
- << " ...rewritten : " << infer << std::endl;
- // check whether it is false in model for abstraction
- Node infer_mv = d_model.computeAbstractModelValue(infer);
- Trace("nl-ext-bound-debug")
- << " ...infer model value is " << infer_mv << std::endl;
- if (infer_mv == d_false)
- {
- Node exp =
- nm->mkNode(AND,
- nm->mkNode(mmv_sign == 1 ? GT : LT, mult, d_zero),
- d_ci_exp[x][coeff][rhs]);
- Node iblem = nm->mkNode(IMPLIES, exp, infer);
- Node pr_iblem = iblem;
- iblem = Rewriter::rewrite(iblem);
- bool introNewTerms = hasNewMonomials(iblem, d_ms);
- Trace("nl-ext-bound-lemma")
- << "*** Bound inference lemma : " << iblem
- << " (pre-rewrite : " << pr_iblem << ")" << std::endl;
- // Trace("nl-ext-bound-lemma") << " intro new
- // monomials = " << introNewTerms << std::endl;
- if (!introNewTerms)
- {
- lemmas.emplace_back(iblem, Inference::INFER_BOUNDS);
- }
- else
- {
- nt_lemmas.emplace_back(iblem, Inference::INFER_BOUNDS_NT);
- }
- }
- }
- }
- }
- }
- return lemmas;
-}
-
-std::vector<NlLemma> NlSolver::checkFactoring(
- const std::vector<Node>& asserts, const std::vector<Node>& false_asserts)
-{
- std::vector<NlLemma> lemmas;
- NodeManager* nm = NodeManager::currentNM();
- Trace("nl-ext") << "Get factoring lemmas..." << std::endl;
- for (const Node& lit : asserts)
- {
- bool polarity = lit.getKind() != NOT;
- Node atom = lit.getKind() == NOT ? lit[0] : lit;
- Node litv = d_model.computeConcreteModelValue(lit);
- bool considerLit = false;
- // Only consider literals that are in false_asserts.
- considerLit = std::find(false_asserts.begin(), false_asserts.end(), lit)
- != false_asserts.end();
-
- if (considerLit)
- {
- std::map<Node, Node> msum;
- if (ArithMSum::getMonomialSumLit(atom, msum))
- {
- Trace("nl-ext-factor") << "Factoring for literal " << lit
- << ", monomial sum is : " << std::endl;
- if (Trace.isOn("nl-ext-factor"))
- {
- ArithMSum::debugPrintMonomialSum(msum, "nl-ext-factor");
- }
- std::map<Node, std::vector<Node> > factor_to_mono;
- std::map<Node, std::vector<Node> > factor_to_mono_orig;
- for (std::map<Node, Node>::iterator itm = msum.begin();
- itm != msum.end();
- ++itm)
- {
- if (!itm->first.isNull())
- {
- if (itm->first.getKind() == NONLINEAR_MULT)
- {
- std::vector<Node> children;
- for (unsigned i = 0; i < itm->first.getNumChildren(); i++)
- {
- children.push_back(itm->first[i]);
- }
- std::map<Node, bool> processed;
- for (unsigned i = 0; i < itm->first.getNumChildren(); i++)
- {
- if (processed.find(itm->first[i]) == processed.end())
- {
- processed[itm->first[i]] = true;
- children[i] = d_one;
- if (!itm->second.isNull())
- {
- children.push_back(itm->second);
- }
- Node val = nm->mkNode(MULT, children);
- if (!itm->second.isNull())
- {
- children.pop_back();
- }
- children[i] = itm->first[i];
- val = Rewriter::rewrite(val);
- factor_to_mono[itm->first[i]].push_back(val);
- factor_to_mono_orig[itm->first[i]].push_back(itm->first);
- }
- }
- }
- }
- }
- for (std::map<Node, std::vector<Node> >::iterator itf =
- factor_to_mono.begin();
- itf != factor_to_mono.end();
- ++itf)
- {
- Node x = itf->first;
- if (itf->second.size() == 1)
- {
- std::map<Node, Node>::iterator itm = msum.find(x);
- if (itm != msum.end())
- {
- itf->second.push_back(itm->second.isNull() ? d_one : itm->second);
- factor_to_mono_orig[x].push_back(x);
- }
- }
- if (itf->second.size() <= 1)
- {
- continue;
- }
- Node sum = nm->mkNode(PLUS, itf->second);
- sum = Rewriter::rewrite(sum);
- Trace("nl-ext-factor")
- << "* Factored sum for " << x << " : " << sum << std::endl;
- Node kf = getFactorSkolem(sum, lemmas);
- std::vector<Node> poly;
- poly.push_back(nm->mkNode(MULT, x, kf));
- std::map<Node, std::vector<Node> >::iterator itfo =
- factor_to_mono_orig.find(x);
- Assert(itfo != factor_to_mono_orig.end());
- for (std::map<Node, Node>::iterator itm = msum.begin();
- itm != msum.end();
- ++itm)
- {
- if (std::find(itfo->second.begin(), itfo->second.end(), itm->first)
- == itfo->second.end())
- {
- poly.push_back(ArithMSum::mkCoeffTerm(
- itm->second, itm->first.isNull() ? d_one : itm->first));
- }
- }
- Node polyn = poly.size() == 1 ? poly[0] : nm->mkNode(PLUS, poly);
- Trace("nl-ext-factor")
- << "...factored polynomial : " << polyn << std::endl;
- Node conc_lit = nm->mkNode(atom.getKind(), polyn, d_zero);
- conc_lit = Rewriter::rewrite(conc_lit);
- if (!polarity)
- {
- conc_lit = conc_lit.negate();
- }
-
- std::vector<Node> lemma_disj;
- lemma_disj.push_back(lit.negate());
- lemma_disj.push_back(conc_lit);
- Node flem = nm->mkNode(OR, lemma_disj);
- Trace("nl-ext-factor") << "...lemma is " << flem << std::endl;
- lemmas.emplace_back(flem, Inference::FACTOR);
- }
- }
- }
- }
- return lemmas;
-}
-
-Node NlSolver::getFactorSkolem(Node n, std::vector<NlLemma>& lemmas)
-{
- std::map<Node, Node>::iterator itf = d_factor_skolem.find(n);
- if (itf == d_factor_skolem.end())
- {
- NodeManager* nm = NodeManager::currentNM();
- Node k = nm->mkSkolem("kf", n.getType());
- Node k_eq = Rewriter::rewrite(k.eqNode(n));
- lemmas.push_back(k_eq);
- d_factor_skolem[n] = k;
- return k;
- }
- return itf->second;
-}
-
-std::vector<NlLemma> NlSolver::checkMonomialInferResBounds()
-{
- std::vector<NlLemma> lemmas;
- NodeManager* nm = NodeManager::currentNM();
- Trace("nl-ext") << "Get monomial resolution inferred bound lemmas..."
- << std::endl;
- size_t nmterms = d_mterms.size();
- for (unsigned j = 0; j < nmterms; j++)
- {
- Node a = d_mterms[j];
- std::map<Node, std::map<Node, std::map<Node, Kind> > >::iterator itca =
- d_ci.find(a);
- if (itca == d_ci.end())
- {
- continue;
- }
- for (unsigned k = (j + 1); k < nmterms; k++)
- {
- Node b = d_mterms[k];
- std::map<Node, std::map<Node, std::map<Node, Kind> > >::iterator itcb =
- d_ci.find(b);
- if (itcb == d_ci.end())
- {
- continue;
- }
- Trace("nl-ext-rbound-debug") << "resolution inferences : compare " << a
- << " and " << b << std::endl;
- // if they have common factors
- std::map<Node, Node>::iterator ita = d_mono_diff[a].find(b);
- if (ita == d_mono_diff[a].end())
- {
- continue;
- }
- Trace("nl-ext-rbound") << "Get resolution inferences for [a] " << a
- << " vs [b] " << b << std::endl;
- std::map<Node, Node>::iterator itb = d_mono_diff[b].find(a);
- Assert(itb != d_mono_diff[b].end());
- Node mv_a = d_model.computeAbstractModelValue(ita->second);
- Assert(mv_a.isConst());
- int mv_a_sgn = mv_a.getConst<Rational>().sgn();
- if (mv_a_sgn == 0)
- {
- // we don't compare monomials whose current model value is zero
- continue;
- }
- Node mv_b = d_model.computeAbstractModelValue(itb->second);
- Assert(mv_b.isConst());
- int mv_b_sgn = mv_b.getConst<Rational>().sgn();
- if (mv_b_sgn == 0)
- {
- // we don't compare monomials whose current model value is zero
- continue;
- }
- Trace("nl-ext-rbound") << " [a] factor is " << ita->second
- << ", sign in model = " << mv_a_sgn << std::endl;
- Trace("nl-ext-rbound") << " [b] factor is " << itb->second
- << ", sign in model = " << mv_b_sgn << std::endl;
-
- std::vector<Node> exp;
- // bounds of a
- for (std::map<Node, std::map<Node, Kind> >::iterator itcac =
- itca->second.begin();
- itcac != itca->second.end();
- ++itcac)
- {
- Node coeff_a = itcac->first;
- for (std::map<Node, Kind>::iterator itcar = itcac->second.begin();
- itcar != itcac->second.end();
- ++itcar)
- {
- Node rhs_a = itcar->first;
- Node rhs_a_res_base = nm->mkNode(MULT, itb->second, rhs_a);
- rhs_a_res_base = Rewriter::rewrite(rhs_a_res_base);
- if (hasNewMonomials(rhs_a_res_base, d_ms))
- {
- continue;
- }
- Kind type_a = itcar->second;
- exp.push_back(d_ci_exp[a][coeff_a][rhs_a]);
-
- // bounds of b
- for (std::map<Node, std::map<Node, Kind> >::iterator itcbc =
- itcb->second.begin();
- itcbc != itcb->second.end();
- ++itcbc)
- {
- Node coeff_b = itcbc->first;
- Node rhs_a_res = ArithMSum::mkCoeffTerm(coeff_b, rhs_a_res_base);
- for (std::map<Node, Kind>::iterator itcbr = itcbc->second.begin();
- itcbr != itcbc->second.end();
- ++itcbr)
- {
- Node rhs_b = itcbr->first;
- Node rhs_b_res = nm->mkNode(MULT, ita->second, rhs_b);
- rhs_b_res = ArithMSum::mkCoeffTerm(coeff_a, rhs_b_res);
- rhs_b_res = Rewriter::rewrite(rhs_b_res);
- if (hasNewMonomials(rhs_b_res, d_ms))
- {
- continue;
- }
- Kind type_b = itcbr->second;
- exp.push_back(d_ci_exp[b][coeff_b][rhs_b]);
- if (Trace.isOn("nl-ext-rbound"))
- {
- Trace("nl-ext-rbound") << "* try bounds : ";
- debugPrintBound("nl-ext-rbound", coeff_a, a, type_a, rhs_a);
- Trace("nl-ext-rbound") << std::endl;
- Trace("nl-ext-rbound") << " ";
- debugPrintBound("nl-ext-rbound", coeff_b, b, type_b, rhs_b);
- Trace("nl-ext-rbound") << std::endl;
- }
- Kind types[2];
- for (unsigned r = 0; r < 2; r++)
- {
- Node pivot_factor = r == 0 ? itb->second : ita->second;
- int pivot_factor_sign = r == 0 ? mv_b_sgn : mv_a_sgn;
- types[r] = r == 0 ? type_a : type_b;
- if (pivot_factor_sign == (r == 0 ? 1 : -1))
- {
- types[r] = reverseRelationKind(types[r]);
- }
- if (pivot_factor_sign == 1)
- {
- exp.push_back(nm->mkNode(GT, pivot_factor, d_zero));
- }
- else
- {
- exp.push_back(nm->mkNode(LT, pivot_factor, d_zero));
- }
- }
- Kind jk = transKinds(types[0], types[1]);
- Trace("nl-ext-rbound-debug")
- << "trans kind : " << types[0] << " + " << types[1] << " = "
- << jk << std::endl;
- if (jk != UNDEFINED_KIND)
- {
- Node conc = nm->mkNode(jk, rhs_a_res, rhs_b_res);
- Node conc_mv = d_model.computeAbstractModelValue(conc);
- if (conc_mv == d_false)
- {
- Node rblem = nm->mkNode(IMPLIES, nm->mkNode(AND, exp), conc);
- Trace("nl-ext-rbound-lemma-debug")
- << "Resolution bound lemma "
- "(pre-rewrite) "
- ": "
- << rblem << std::endl;
- rblem = Rewriter::rewrite(rblem);
- Trace("nl-ext-rbound-lemma")
- << "Resolution bound lemma : " << rblem << std::endl;
- lemmas.emplace_back(rblem, Inference::RES_INFER_BOUNDS);
- }
- }
- exp.pop_back();
- exp.pop_back();
- exp.pop_back();
- }
- }
- exp.pop_back();
- }
- }
- }
- }
- return lemmas;
-}
-
-} // namespace nl
-} // namespace arith
-} // namespace theory
-} // namespace CVC4
diff --git a/src/theory/arith/nl/nl_solver.h b/src/theory/arith/nl/nl_solver.h
deleted file mode 100644
index b5176a4dd..000000000
--- a/src/theory/arith/nl/nl_solver.h
+++ /dev/null
@@ -1,370 +0,0 @@
-/********************* */
-/*! \file nl_solver.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Andrew Reynolds, Tim King, Tianyi Liang
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Solver for standard non-linear constraints
- **/
-
-#ifndef CVC4__THEORY__ARITH__NL_SOLVER_H
-#define CVC4__THEORY__ARITH__NL_SOLVER_H
-
-#include <map>
-#include <unordered_map>
-#include <utility>
-#include <vector>
-
-#include "context/cdhashset.h"
-#include "context/cdinsert_hashmap.h"
-#include "context/cdlist.h"
-#include "context/cdqueue.h"
-#include "context/context.h"
-#include "expr/kind.h"
-#include "expr/node.h"
-#include "theory/arith/nl/nl_constraint.h"
-#include "theory/arith/nl/nl_lemma_utils.h"
-#include "theory/arith/nl/nl_model.h"
-#include "theory/arith/nl/nl_monomial.h"
-#include "theory/arith/theory_arith.h"
-
-namespace CVC4 {
-namespace theory {
-namespace arith {
-namespace nl {
-
-typedef std::map<Node, unsigned> NodeMultiset;
-
-/** Non-linear solver class
- *
- * This class implements model-based refinement schemes
- * for non-linear arithmetic, described in:
- *
- * - "Invariant Checking of NRA Transition Systems
- * via Incremental Reduction to LRA with EUF" by
- * Cimatti et al., TACAS 2017.
- *
- * - Section 5 of "Desiging Theory Solvers with
- * Extensions" by Reynolds et al., FroCoS 2017.
- */
-class NlSolver
-{
- typedef std::map<Node, NodeMultiset> MonomialExponentMap;
- typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
-
- public:
- NlSolver(TheoryArith& containing, NlModel& model);
- ~NlSolver();
-
- /** init last call
- *
- * This is called at the beginning of last call effort check, where
- * assertions are the set of assertions belonging to arithmetic,
- * false_asserts is the subset of assertions that are false in the current
- * model, and xts is the set of extended function terms that are active in
- * the current context.
- */
- void initLastCall(const std::vector<Node>& assertions,
- const std::vector<Node>& false_asserts,
- const std::vector<Node>& xts);
- //-------------------------------------------- lemma schemas
- /** check split zero
- *
- * Returns a set of theory lemmas of the form
- * t = 0 V t != 0
- * where t is a term that exists in the current context.
- */
- std::vector<NlLemma> checkSplitZero();
-
- /** check monomial sign
- *
- * Returns a set of valid theory lemmas, based on a
- * lemma schema which ensures that non-linear monomials
- * respect sign information based on their facts.
- * For more details, see Section 5 of "Design Theory
- * Solvers with Extensions" by Reynolds et al., FroCoS 2017,
- * Figure 5, this is the schema "Sign".
- *
- * Examples:
- *
- * x > 0 ^ y > 0 => x*y > 0
- * x < 0 => x*y*y < 0
- * x = 0 => x*y*z = 0
- */
- std::vector<NlLemma> checkMonomialSign();
-
- /** check monomial magnitude
- *
- * Returns a set of valid theory lemmas, based on a
- * lemma schema which ensures that comparisons between
- * non-linear monomials respect the magnitude of their
- * factors.
- * For more details, see Section 5 of "Design Theory
- * Solvers with Extensions" by Reynolds et al., FroCoS 2017,
- * Figure 5, this is the schema "Magnitude".
- *
- * Examples:
- *
- * |x|>|y| => |x*z|>|y*z|
- * |x|>|y| ^ |z|>|w| ^ |x|>=1 => |x*x*z*u|>|y*w|
- *
- * Argument c indicates the class of inferences to perform for the
- * (non-linear) monomials in the vector d_ms. 0 : compare non-linear monomials
- * against 1, 1 : compare non-linear monomials against variables, 2 : compare
- * non-linear monomials against other non-linear monomials.
- */
- std::vector<NlLemma> checkMonomialMagnitude(unsigned c);
-
- /** check monomial inferred bounds
- *
- * Returns a set of valid theory lemmas, based on a
- * lemma schema that infers new constraints about existing
- * terms based on mulitplying both sides of an existing
- * constraint by a term.
- * For more details, see Section 5 of "Design Theory
- * Solvers with Extensions" by Reynolds et al., FroCoS 2017,
- * Figure 5, this is the schema "Multiply".
- *
- * Examples:
- *
- * x > 0 ^ (y > z + w) => x*y > x*(z+w)
- * x < 0 ^ (y > z + w) => x*y < x*(z+w)
- * ...where (y > z + w) and x*y are a constraint and term
- * that occur in the current context.
- */
- std::vector<NlLemma> checkMonomialInferBounds(
- std::vector<NlLemma>& nt_lemmas,
- const std::vector<Node>& asserts,
- const std::vector<Node>& false_asserts);
-
- /** check factoring
- *
- * Returns a set of valid theory lemmas, based on a
- * lemma schema that states a relationship betwen monomials
- * with common factors that occur in the same constraint.
- *
- * Examples:
- *
- * x*z+y*z > t => ( k = x + y ^ k*z > t )
- * ...where k is fresh and x*z + y*z > t is a
- * constraint that occurs in the current context.
- */
- std::vector<NlLemma> checkFactoring(const std::vector<Node>& asserts,
- const std::vector<Node>& false_asserts);
-
- /** check monomial infer resolution bounds
- *
- * Returns a set of valid theory lemmas, based on a
- * lemma schema which "resolves" upper bounds
- * of one inequality with lower bounds for another.
- * This schema is not enabled by default, and can
- * be enabled by --nl-ext-rbound.
- *
- * Examples:
- *
- * ( y>=0 ^ s <= x*z ^ x*y <= t ) => y*s <= z*t
- * ...where s <= x*z and x*y <= t are constraints
- * that occur in the current context.
- */
- std::vector<NlLemma> checkMonomialInferResBounds();
-
- /** check tangent planes
- *
- * Returns a set of valid theory lemmas, based on an
- * "incremental linearization" of non-linear monomials.
- * This linearization is accomplished by adding constraints
- * corresponding to "tangent planes" at the current
- * model value of each non-linear monomial. In particular
- * consider the definition for constants a,b :
- * T_{a,b}( x*y ) = b*x + a*y - a*b.
- * The lemmas added by this function are of the form :
- * ( ( x>a ^ y<b) ^ (x<a ^ y>b) ) => x*y < T_{a,b}( x*y )
- * ( ( x>a ^ y>b) ^ (x<a ^ y<b) ) => x*y > T_{a,b}( x*y )
- * It is inspired by "Invariant Checking of NRA Transition
- * Systems via Incremental Reduction to LRA with EUF" by
- * Cimatti et al., TACAS 2017.
- * This schema is not terminating in general.
- * It is not enabled by default, and can
- * be enabled by --nl-ext-tplanes.
- *
- * Examples:
- *
- * ( ( x>2 ^ y>5) ^ (x<2 ^ y<5) ) => x*y > 5*x + 2*y - 10
- * ( ( x>2 ^ y<5) ^ (x<2 ^ y>5) ) => x*y < 5*x + 2*y - 10
- */
- std::vector<NlLemma> checkTangentPlanes();
-
- //-------------------------------------------- end lemma schemas
- private:
- // The theory of arithmetic containing this extension.
- TheoryArith& d_containing;
- /** Reference to the non-linear model object */
- NlModel& d_model;
- /** commonly used terms */
- Node d_zero;
- Node d_one;
- Node d_neg_one;
- Node d_two;
- Node d_true;
- Node d_false;
- /** Context-independent database of monomial information */
- MonomialDb d_mdb;
- /** Context-independent database of constraint information */
- ConstraintDb d_cdb;
-
- // ( x*y, x*z, y ) for each pair of monomials ( x*y, x*z ) with common factors
- std::map<Node, std::map<Node, Node> > d_mono_diff;
-
- /** cache of terms t for which we have added the lemma ( t = 0 V t != 0 ). */
- NodeSet d_zero_split;
-
- // ordering, stores variables and 0,1,-1
- std::map<Node, unsigned> d_order_vars;
- std::vector<Node> d_order_points;
-
- // information about monomials
- std::vector<Node> d_ms;
- std::vector<Node> d_ms_vars;
- std::map<Node, bool> d_ms_proc;
- std::vector<Node> d_mterms;
-
- // list of monomials with factors whose model value is non-constant in model
- // e.g. y*cos( x )
- std::map<Node, bool> d_m_nconst_factor;
- /** the set of monomials we should apply tangent planes to */
- std::unordered_set<Node, NodeHashFunction> d_tplane_refine;
- /** maps nodes to their factor skolems */
- std::map<Node, Node> d_factor_skolem;
- /** tangent plane bounds */
- std::map<Node, std::map<Node, Node> > d_tangent_val_bound[4];
- // term -> coeff -> rhs -> ( status, exp, b ),
- // where we have that : exp => ( coeff * term <status> rhs )
- // b is true if degree( term ) >= degree( rhs )
- std::map<Node, std::map<Node, std::map<Node, Kind> > > d_ci;
- std::map<Node, std::map<Node, std::map<Node, Node> > > d_ci_exp;
- std::map<Node, std::map<Node, std::map<Node, bool> > > d_ci_max;
-
- /** Make literal */
- static Node mkLit(Node a, Node b, int status, bool isAbsolute = false);
- /** register monomial */
- void setMonomialFactor(Node a, Node b, const NodeMultiset& common);
- /** assign order ids */
- void assignOrderIds(std::vector<Node>& vars,
- NodeMultiset& d_order,
- bool isConcrete,
- bool isAbsolute);
-
- /** Check whether we have already inferred a relationship between monomials
- * x and y based on the information in cmp_infers. This computes the
- * transitive closure of the relation stored in cmp_infers.
- */
- bool cmp_holds(Node x,
- Node y,
- std::map<Node, std::map<Node, Node> >& cmp_infers,
- std::vector<Node>& exp,
- std::map<Node, bool>& visited);
- /** In the following functions, status states a relationship
- * between two arithmetic terms, where:
- * 0 : equal
- * 1 : greater than or equal
- * 2 : greater than
- * -X : (greater -> less)
- * TODO (#1287) make this an enum?
- */
- /** compute the sign of a.
- *
- * Calls to this function are such that :
- * exp => ( oa = a ^ a <status> 0 )
- *
- * This function iterates over the factors of a,
- * where a_index is the index of the factor in a
- * we are currently looking at.
- *
- * This function returns a status, which indicates
- * a's relationship to 0.
- * We add lemmas to lem of the form given by the
- * lemma schema checkSign(...).
- */
- int compareSign(Node oa,
- Node a,
- unsigned a_index,
- int status,
- std::vector<Node>& exp,
- std::vector<NlLemma>& lem);
- /** compare monomials a and b
- *
- * Initially, a call to this function is such that :
- * exp => ( oa = a ^ ob = b )
- *
- * This function returns true if we can infer a valid
- * arithmetic lemma of the form :
- * P => abs( a ) >= abs( b )
- * where P is true and abs( a ) >= abs( b ) is false in the
- * current model.
- *
- * This function is implemented by "processing" factors
- * of monomials a and b until an inference of the above
- * form can be made. For example, if :
- * a = x*x*y and b = z*w
- * Assuming we are trying to show abs( a ) >= abs( c ),
- * then if abs( M( x ) ) >= abs( M( z ) ) where M is the current model,
- * then we can add abs( x ) >= abs( z ) to our explanation, and
- * mark one factor of x as processed in a, and
- * one factor of z as processed in b. The number of processed factors of a
- * and b are stored in a_exp_proc and b_exp_proc respectively.
- *
- * cmp_infers stores information that is helpful
- * in discarding redundant inferences. For example,
- * we do not want to infer abs( x ) >= abs( z ) if
- * we have already inferred abs( x ) >= abs( y ) and
- * abs( y ) >= abs( z ).
- * It stores entries of the form (status,t1,t2)->F,
- * which indicates that we constructed a lemma F that
- * showed t1 <status> t2.
- *
- * We add lemmas to lem of the form given by the
- * lemma schema checkMagnitude(...).
- */
- bool compareMonomial(
- Node oa,
- Node a,
- NodeMultiset& a_exp_proc,
- Node ob,
- Node b,
- NodeMultiset& b_exp_proc,
- std::vector<Node>& exp,
- std::vector<NlLemma>& lem,
- std::map<int, std::map<Node, std::map<Node, Node> > >& cmp_infers);
- /** helper function for above
- *
- * The difference is the inputs a_index and b_index, which are the indices of
- * children (factors) in monomials a and b which we are currently looking at.
- */
- bool compareMonomial(
- Node oa,
- Node a,
- unsigned a_index,
- NodeMultiset& a_exp_proc,
- Node ob,
- Node b,
- unsigned b_index,
- NodeMultiset& b_exp_proc,
- int status,
- std::vector<Node>& exp,
- std::vector<NlLemma>& lem,
- std::map<int, std::map<Node, std::map<Node, Node> > >& cmp_infers);
- /** Get factor skolem for n, add resulting lemmas to lemmas */
- Node getFactorSkolem(Node n, std::vector<NlLemma>& lemmas);
-}; /* class NlSolver */
-
-} // namespace nl
-} // namespace arith
-} // namespace theory
-} // namespace CVC4
-
-#endif /* CVC4__THEORY__ARITH__NL_SOLVER_H */
diff --git a/src/theory/arith/nl/nonlinear_extension.cpp b/src/theory/arith/nl/nonlinear_extension.cpp
index 97f0ce2c1..22a69cadb 100644
--- a/src/theory/arith/nl/nonlinear_extension.cpp
+++ b/src/theory/arith/nl/nonlinear_extension.cpp
@@ -2,10 +2,10 @@
/*! \file nonlinear_extension.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Tim King, Aina Niemetz
+ ** Andrew Reynolds, Gereon Kremer, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,7 +18,10 @@
#include "theory/arith/nl/nonlinear_extension.h"
#include "options/arith_options.h"
+#include "options/theory_options.h"
+#include "theory/arith/arith_state.h"
#include "theory/arith/arith_utilities.h"
+#include "theory/arith/bound_inference.h"
#include "theory/arith/theory_arith.h"
#include "theory/ext_theory.h"
#include "theory/theory_model.h"
@@ -31,18 +34,36 @@ namespace arith {
namespace nl {
NonlinearExtension::NonlinearExtension(TheoryArith& containing,
+ ArithState& state,
eq::EqualityEngine* ee)
- : d_lemmas(containing.getUserContext()),
- d_lemmasPp(containing.getUserContext()),
- d_containing(containing),
+ : d_containing(containing),
+ d_im(containing.getInferenceManager()),
d_ee(ee),
d_needsLastCall(false),
+ d_checkCounter(0),
+ d_extTheoryCb(ee),
+ d_extTheory(d_extTheoryCb,
+ containing.getSatContext(),
+ containing.getUserContext(),
+ containing.getOutputChannel()),
d_model(containing.getSatContext()),
- d_trSlv(d_model),
- d_nlSlv(containing, d_model),
- d_iandSlv(containing, d_model),
+ d_trSlv(d_im, d_model),
+ d_extState(d_im, d_model, containing.getSatContext()),
+ d_factoringSlv(d_im, d_model),
+ d_monomialBoundsSlv(&d_extState),
+ d_monomialSlv(&d_extState),
+ d_splitZeroSlv(&d_extState, state.getUserContext()),
+ d_tangentPlaneSlv(&d_extState),
+ d_cadSlv(d_im, d_model),
+ d_icpSlv(d_im),
+ d_iandSlv(d_im, state, d_model),
d_builtModel(containing.getSatContext(), false)
{
+ d_extTheory.addFunctionKind(kind::NONLINEAR_MULT);
+ d_extTheory.addFunctionKind(kind::EXPONENTIAL);
+ d_extTheory.addFunctionKind(kind::SINE);
+ d_extTheory.addFunctionKind(kind::PI);
+ d_extTheory.addFunctionKind(kind::IAND);
d_true = NodeManager::currentNM()->mkConst(true);
d_zero = NodeManager::currentNM()->mkConst(Rational(0));
d_one = NodeManager::currentNM()->mkConst(Rational(1));
@@ -51,143 +72,55 @@ NonlinearExtension::NonlinearExtension(TheoryArith& containing,
NonlinearExtension::~NonlinearExtension() {}
-bool NonlinearExtension::getCurrentSubstitution(
- int effort,
- const std::vector<Node>& vars,
- std::vector<Node>& subs,
- std::map<Node, std::vector<Node>>& exp)
+void NonlinearExtension::preRegisterTerm(TNode n)
{
- // get the constant equivalence classes
- std::map<Node, std::vector<int>> rep_to_subs_index;
-
- bool retVal = false;
- for (unsigned i = 0; i < vars.size(); i++)
- {
- Node n = vars[i];
- if (d_ee->hasTerm(n))
- {
- Node nr = d_ee->getRepresentative(n);
- if (nr.isConst())
- {
- subs.push_back(nr);
- Trace("nl-subs") << "Basic substitution : " << n << " -> " << nr
- << std::endl;
- exp[n].push_back(n.eqNode(nr));
- retVal = true;
- }
- else
- {
- rep_to_subs_index[nr].push_back(i);
- subs.push_back(n);
- }
- }
- else
- {
- subs.push_back(n);
- }
- }
-
- // return true if the substitution is non-trivial
- return retVal;
+ // register terms with extended theory, to find extended terms that can be
+ // eliminated by context-depedendent simplification.
+ d_extTheory.registerTermRec(n);
}
-std::pair<bool, Node> NonlinearExtension::isExtfReduced(
- int effort, Node n, Node on, const std::vector<Node>& exp) const
+void NonlinearExtension::sendLemmas(const std::vector<NlLemma>& out)
{
- if (n != d_zero)
+ for (const NlLemma& nlem : out)
{
- Kind k = n.getKind();
- return std::make_pair(
- k != NONLINEAR_MULT && !isTranscendentalKind(k) && k != IAND,
- Node::null());
+ Trace("nl-ext-lemma") << "NonlinearExtension::Lemma : " << nlem.d_inference
+ << " : " << nlem.d_node << std::endl;
+ d_im.addPendingArithLemma(nlem);
+ d_stats.d_inferences << nlem.d_inference;
}
- Assert(n == d_zero);
- if (on.getKind() == NONLINEAR_MULT)
- {
- Trace("nl-ext-zero-exp")
- << "Infer zero : " << on << " == " << n << std::endl;
- // minimize explanation if a substitution+rewrite results in zero
- const std::set<Node> vars(on.begin(), on.end());
-
- for (unsigned i = 0, size = exp.size(); i < size; i++)
- {
- Trace("nl-ext-zero-exp")
- << " exp[" << i << "] = " << exp[i] << std::endl;
- std::vector<Node> eqs;
- if (exp[i].getKind() == EQUAL)
- {
- eqs.push_back(exp[i]);
- }
- else if (exp[i].getKind() == AND)
- {
- for (const Node& ec : exp[i])
- {
- if (ec.getKind() == EQUAL)
- {
- eqs.push_back(ec);
- }
- }
- }
+}
- for (unsigned j = 0; j < eqs.size(); j++)
- {
- for (unsigned r = 0; r < 2; r++)
- {
- if (eqs[j][r] == d_zero && vars.find(eqs[j][1 - r]) != vars.end())
- {
- Trace("nl-ext-zero-exp")
- << "...single exp : " << eqs[j] << std::endl;
- return std::make_pair(true, eqs[j]);
- }
- }
- }
- }
- }
- return std::make_pair(true, Node::null());
+void NonlinearExtension::processSideEffect(const NlLemma& se)
+{
+ d_trSlv.processSideEffect(se);
}
-void NonlinearExtension::sendLemmas(const std::vector<NlLemma>& out)
+void NonlinearExtension::computeRelevantAssertions(
+ const std::vector<Node>& assertions, std::vector<Node>& keep)
{
- for (const NlLemma& nlem : out)
+ Trace("nl-ext-rlv") << "Compute relevant assertions..." << std::endl;
+ Valuation v = d_containing.getValuation();
+ for (const Node& a : assertions)
{
- Node lem = nlem.d_lemma;
- bool preprocess = nlem.d_preprocess;
- Trace("nl-ext-lemma") << "NonlinearExtension::Lemma : " << nlem.d_id
- << " : " << lem << std::endl;
- d_containing.getOutputChannel().lemma(lem, false, preprocess);
- // process the side effect
- processSideEffect(nlem);
- // add to cache if not preprocess
- if (preprocess)
+ if (v.isRelevant(a))
{
- d_lemmasPp.insert(lem);
+ keep.push_back(a);
}
- else
- {
- d_lemmas.insert(lem);
- }
- d_stats.d_inferences << nlem.d_id;
- // also indicate this is a tautology
- d_model.addTautology(lem);
}
-}
-
-void NonlinearExtension::processSideEffect(const NlLemma& se)
-{
- d_trSlv.processSideEffect(se);
+ Trace("nl-ext-rlv") << "...keep " << keep.size() << "/" << assertions.size()
+ << " assertions" << std::endl;
}
unsigned NonlinearExtension::filterLemma(NlLemma lem, std::vector<NlLemma>& out)
{
Trace("nl-ext-lemma-debug")
- << "NonlinearExtension::Lemma pre-rewrite : " << lem.d_lemma << std::endl;
- lem.d_lemma = Rewriter::rewrite(lem.d_lemma);
- // get the proper cache
- NodeSet& lcache = lem.d_preprocess ? d_lemmasPp : d_lemmas;
- if (lcache.find(lem.d_lemma) != lcache.end())
+ << "NonlinearExtension::Lemma pre-rewrite : " << lem.d_node << std::endl;
+ lem.d_node = Rewriter::rewrite(lem.d_node);
+
+ if (d_im.hasCachedLemma(lem.d_node, lem.d_property))
{
Trace("nl-ext-lemma-debug")
- << "NonlinearExtension::Lemma duplicate : " << lem.d_lemma << std::endl;
+ << "NonlinearExtension::Lemma duplicate : " << lem.d_node << std::endl;
return 0;
}
out.emplace_back(lem);
@@ -202,7 +135,7 @@ unsigned NonlinearExtension::filterLemmas(std::vector<NlLemma>& lemmas,
// check if any are entailed to be false
for (const NlLemma& lem : lemmas)
{
- Node ch_lemma = lem.d_lemma.negate();
+ Node ch_lemma = lem.d_node.negate();
ch_lemma = Rewriter::rewrite(ch_lemma);
Trace("nl-ext-et-debug")
<< "Check entailment of " << ch_lemma << "..." << std::endl;
@@ -213,7 +146,7 @@ unsigned NonlinearExtension::filterLemmas(std::vector<NlLemma>& lemmas,
if (et.first)
{
Trace("nl-ext-et") << "*** Lemma entailed to be in conflict : "
- << lem.d_lemma << std::endl;
+ << lem.d_node << std::endl;
// return just this lemma
if (filterLemma(lem, out) > 0)
{
@@ -228,6 +161,8 @@ unsigned NonlinearExtension::filterLemmas(std::vector<NlLemma>& lemmas,
for (const NlLemma& lem : lemmas)
{
sum += filterLemma(lem, out);
+ d_containing.getOutputChannel().spendResource(
+ ResourceManager::Resource::ArithNlLemmaStep);
}
lemmas.clear();
return sum;
@@ -236,119 +171,78 @@ unsigned NonlinearExtension::filterLemmas(std::vector<NlLemma>& lemmas,
void NonlinearExtension::getAssertions(std::vector<Node>& assertions)
{
Trace("nl-ext") << "Getting assertions..." << std::endl;
- NodeManager* nm = NodeManager::currentNM();
- // get the assertions
- std::map<Node, Rational> init_bounds[2];
- std::map<Node, Node> init_bounds_lit[2];
- unsigned nassertions = 0;
+ bool useRelevance = false;
+ if (options::nlRlvMode() == options::NlRlvMode::INTERLEAVE)
+ {
+ useRelevance = (d_checkCounter % 2);
+ }
+ else if (options::nlRlvMode() == options::NlRlvMode::ALWAYS)
+ {
+ useRelevance = true;
+ }
+ Valuation v = d_containing.getValuation();
+
+ BoundInference bounds;
+
std::unordered_set<Node, NodeHashFunction> init_assertions;
+
for (Theory::assertions_iterator it = d_containing.facts_begin();
it != d_containing.facts_end();
++it)
{
- nassertions++;
const Assertion& assertion = *it;
+ Trace("nl-ext") << "Loaded " << assertion.d_assertion << " from theory"
+ << std::endl;
Node lit = assertion.d_assertion;
- init_assertions.insert(lit);
- // check for concrete bounds
- bool pol = lit.getKind() != NOT;
- Node atom_orig = lit.getKind() == NOT ? lit[0] : lit;
-
- std::vector<Node> atoms;
- if (atom_orig.getKind() == EQUAL)
+ if (useRelevance && !v.isRelevant(lit))
{
- if (pol)
- {
- // t = s is ( t >= s ^ t <= s )
- for (unsigned i = 0; i < 2; i++)
- {
- Node atom_new = nm->mkNode(GEQ, atom_orig[i], atom_orig[1 - i]);
- atom_new = Rewriter::rewrite(atom_new);
- atoms.push_back(atom_new);
- }
- }
+ // not relevant, skip
+ continue;
}
- else
+ if (bounds.add(lit, false))
{
- atoms.push_back(atom_orig);
+ continue;
}
+ init_assertions.insert(lit);
+ }
- for (const Node& atom : atoms)
+ for (const auto& vb : bounds.get())
+ {
+ const Bounds& b = vb.second;
+ if (!b.lower_bound.isNull())
{
- // non-strict bounds only
- if (atom.getKind() == GEQ || (!pol && atom.getKind() == GT))
- {
- Node p = atom[0];
- Assert(atom[1].isConst());
- Rational bound = atom[1].getConst<Rational>();
- if (!pol)
- {
- if (atom[0].getType().isInteger())
- {
- // ~( p >= c ) ---> ( p <= c-1 )
- bound = bound - Rational(1);
- }
- }
- unsigned bindex = pol ? 0 : 1;
- bool setBound = true;
- std::map<Node, Rational>::iterator itb = init_bounds[bindex].find(p);
- if (itb != init_bounds[bindex].end())
- {
- if (itb->second == bound)
- {
- setBound = atom_orig.getKind() == EQUAL;
- }
- else
- {
- setBound = pol ? itb->second < bound : itb->second > bound;
- }
- if (setBound)
- {
- // the bound is subsumed
- init_assertions.erase(init_bounds_lit[bindex][p]);
- }
- }
- if (setBound)
- {
- Trace("nl-ext-init") << (pol ? "Lower" : "Upper") << " bound for "
- << p << " : " << bound << std::endl;
- init_bounds[bindex][p] = bound;
- init_bounds_lit[bindex][p] = lit;
- }
- }
+ init_assertions.insert(b.lower_bound);
+ }
+ if (!b.upper_bound.isNull())
+ {
+ init_assertions.insert(b.upper_bound);
}
}
- // for each bound that is the same, ensure we've inferred the equality
- for (std::pair<const Node, Rational>& ib : init_bounds[0])
+
+ // Try to be "more deterministic" by adding assertions in the order they were
+ // given
+ for (auto it = d_containing.facts_begin(); it != d_containing.facts_end();
+ ++it)
{
- Node p = ib.first;
- Node lit1 = init_bounds_lit[0][p];
- if (lit1.getKind() != EQUAL)
+ Node lit = (*it).d_assertion;
+ auto iait = init_assertions.find(lit);
+ if (iait != init_assertions.end())
{
- std::map<Node, Rational>::iterator itb = init_bounds[1].find(p);
- if (itb != init_bounds[1].end())
- {
- if (ib.second == itb->second)
- {
- Node eq = p.eqNode(nm->mkConst(ib.second));
- eq = Rewriter::rewrite(eq);
- Node lit2 = init_bounds_lit[1][p];
- Assert(lit2.getKind() != EQUAL);
- // use the equality instead, thus these are redundant
- init_assertions.erase(lit1);
- init_assertions.erase(lit2);
- init_assertions.insert(eq);
- }
- }
+ Trace("nl-ext") << "Adding " << lit << std::endl;
+ assertions.push_back(lit);
+ init_assertions.erase(iait);
}
}
-
+ // Now add left over assertions that have been newly created within this
+ // function by the code above.
for (const Node& a : init_assertions)
{
+ Trace("nl-ext") << "Adding " << a << std::endl;
assertions.push_back(a);
}
- Trace("nl-ext") << "...keep " << assertions.size() << " / " << nassertions
- << " assertions." << std::endl;
+ Trace("nl-ext") << "...keep " << assertions.size() << " / "
+ << d_containing.numAssertions() << " assertions."
+ << std::endl;
}
std::vector<Node> NonlinearExtension::checkModelEval(
@@ -374,15 +268,16 @@ std::vector<Node> NonlinearExtension::checkModelEval(
return false_asserts;
}
-bool NonlinearExtension::checkModel(const std::vector<Node>& assertions,
- const std::vector<Node>& false_asserts,
- std::vector<NlLemma>& lemmas,
- std::vector<Node>& gs)
+bool NonlinearExtension::checkModel(const std::vector<Node>& assertions)
{
Trace("nl-ext-cm") << "--- check-model ---" << std::endl;
// get the presubstitution
Trace("nl-ext-cm-debug") << " apply pre-substitution..." << std::endl;
+ // Notice that we do not consider relevance here, since assertions were
+ // already filtered based on relevance. It is incorrect to filter based on
+ // relevance here, since we may have discarded literals that are relevant
+ // that are entailed based on the techniques in getAssertions.
std::vector<Node> passertions = assertions;
if (options::nlExt())
{
@@ -392,201 +287,20 @@ bool NonlinearExtension::checkModel(const std::vector<Node>& assertions,
return false;
}
}
+ if (options::nlCad())
+ {
+ d_cadSlv.constructModelIfAvailable(passertions);
+ }
Trace("nl-ext-cm") << "-----" << std::endl;
unsigned tdegree = d_trSlv.getTaylorDegree();
- bool ret = d_model.checkModel(passertions, tdegree, lemmas, gs);
- return ret;
-}
-
-int NonlinearExtension::checkLastCall(const std::vector<Node>& assertions,
- const std::vector<Node>& false_asserts,
- const std::vector<Node>& xts,
- std::vector<NlLemma>& lems,
- std::vector<NlLemma>& wlems)
-{
std::vector<NlLemma> lemmas;
-
- ++(d_stats.d_checkRuns);
-
- if (options::nlExt())
+ bool ret = d_model.checkModel(passertions, tdegree, lemmas);
+ for (const auto& al: lemmas)
{
- // initialize the non-linear solver
- d_nlSlv.initLastCall(assertions, false_asserts, xts);
- // initialize the trancendental function solver
- d_trSlv.initLastCall(assertions, false_asserts, xts, lemmas);
- // process lemmas that may have been generated by the transcendental solver
- filterLemmas(lemmas, lems);
+ d_im.addPendingArithLemma(al);
}
-
- // init last call with IAND
- d_iandSlv.initLastCall(assertions, false_asserts, xts);
-
- if (!lems.empty())
- {
- Trace("nl-ext") << " ...finished with " << lems.size()
- << " new lemmas during registration." << std::endl;
- return lems.size();
- }
-
- //----------------------------------- possibly split on zero
- if (options::nlExt() && options::nlExtSplitZero())
- {
- Trace("nl-ext") << "Get zero split lemmas..." << std::endl;
- lemmas = d_nlSlv.checkSplitZero();
- filterLemmas(lemmas, lems);
- if (!lems.empty())
- {
- Trace("nl-ext") << " ...finished with " << lems.size() << " new lemmas."
- << std::endl;
- return lems.size();
- }
- }
-
- //-----------------------------------initial lemmas for transcendental
- if (options::nlExt())
- {
- // functions
- lemmas = d_trSlv.checkTranscendentalInitialRefine();
- filterLemmas(lemmas, lems);
- if (!lems.empty())
- {
- Trace("nl-ext") << " ...finished with " << lems.size() << " new lemmas."
- << std::endl;
- return lems.size();
- }
- }
- //-----------------------------------initial lemmas for iand
- lemmas = d_iandSlv.checkInitialRefine();
- filterLemmas(lemmas, lems);
- if (!lems.empty())
- {
- Trace("nl-ext") << " ...finished with " << lems.size() << " new lemmas."
- << std::endl;
- return lems.size();
- }
-
- // main calls to nlExt
- if (options::nlExt())
- {
- //---------------------------------lemmas based on sign (comparison to zero)
- lemmas = d_nlSlv.checkMonomialSign();
- filterLemmas(lemmas, lems);
- if (!lems.empty())
- {
- Trace("nl-ext") << " ...finished with " << lems.size() << " new lemmas."
- << std::endl;
- return lems.size();
- }
-
- //-----------------------------------monotonicity of transdental functions
- lemmas = d_trSlv.checkTranscendentalMonotonic();
- filterLemmas(lemmas, lems);
- if (!lems.empty())
- {
- Trace("nl-ext") << " ...finished with " << lems.size() << " new lemmas."
- << std::endl;
- return lems.size();
- }
-
- //------------------------lemmas based on magnitude of non-zero monomials
- for (unsigned c = 0; c < 3; c++)
- {
- // c is effort level
- lemmas = d_nlSlv.checkMonomialMagnitude(c);
- unsigned nlem = lemmas.size();
- filterLemmas(lemmas, lems);
- if (!lems.empty())
- {
- Trace("nl-ext") << " ...finished with " << lems.size()
- << " new lemmas (out of possible " << nlem << ")."
- << std::endl;
- return lems.size();
- }
- }
-
- //-----------------------------------inferred bounds lemmas
- // e.g. x >= t => y*x >= y*t
- std::vector<NlLemma> nt_lemmas;
- lemmas =
- d_nlSlv.checkMonomialInferBounds(nt_lemmas, assertions, false_asserts);
- // Trace("nl-ext") << "Bound lemmas : " << lemmas.size() << ", " <<
- // nt_lemmas.size() << std::endl; prioritize lemmas that do not
- // introduce new monomials
- filterLemmas(lemmas, lems);
-
- if (options::nlExtTangentPlanes()
- && options::nlExtTangentPlanesInterleave())
- {
- lemmas = d_nlSlv.checkTangentPlanes();
- filterLemmas(lemmas, lems);
- }
-
- if (!lems.empty())
- {
- Trace("nl-ext") << " ...finished with " << lems.size() << " new lemmas."
- << std::endl;
- return lems.size();
- }
-
- // from inferred bound inferences : now do ones that introduce new terms
- filterLemmas(nt_lemmas, lems);
- if (!lems.empty())
- {
- Trace("nl-ext") << " ...finished with " << lems.size()
- << " new (monomial-introducing) lemmas." << std::endl;
- return lems.size();
- }
-
- //------------------------------------factoring lemmas
- // x*y + x*z >= t => exists k. k = y + z ^ x*k >= t
- if (options::nlExtFactor())
- {
- lemmas = d_nlSlv.checkFactoring(assertions, false_asserts);
- filterLemmas(lemmas, lems);
- if (!lems.empty())
- {
- Trace("nl-ext") << " ...finished with " << lems.size()
- << " new lemmas." << std::endl;
- return lems.size();
- }
- }
-
- //------------------------------------resolution bound inferences
- // e.g. ( y>=0 ^ s <= x*z ^ x*y <= t ) => y*s <= z*t
- if (options::nlExtResBound())
- {
- lemmas = d_nlSlv.checkMonomialInferResBounds();
- filterLemmas(lemmas, lems);
- if (!lems.empty())
- {
- Trace("nl-ext") << " ...finished with " << lems.size()
- << " new lemmas." << std::endl;
- return lems.size();
- }
- }
-
- //------------------------------------tangent planes
- if (options::nlExtTangentPlanes()
- && !options::nlExtTangentPlanesInterleave())
- {
- lemmas = d_nlSlv.checkTangentPlanes();
- filterLemmas(lemmas, wlems);
- }
- if (options::nlExtTfTangentPlanes())
- {
- lemmas = d_trSlv.checkTranscendentalTangentPlanes();
- filterLemmas(lemmas, wlems);
- }
- }
- // run the full refinement in the IAND solver
- lemmas = d_iandSlv.checkFullRefine();
- filterLemmas(lemmas, wlems);
-
- Trace("nl-ext") << " ...finished with " << wlems.size() << " waiting lemmas."
- << std::endl;
-
- return 0;
+ return ret;
}
void NonlinearExtension::check(Theory::Effort e)
@@ -596,12 +310,12 @@ void NonlinearExtension::check(Theory::Effort e)
<< ", built model = " << d_builtModel.get() << std::endl;
if (e == Theory::EFFORT_FULL)
{
- d_containing.getExtTheory()->clearCache();
+ d_extTheory.clearCache();
d_needsLastCall = true;
if (options::nlExtRewrites())
{
std::vector<Node> nred;
- if (!d_containing.getExtTheory()->doInferences(0, nred))
+ if (!d_extTheory.doInferences(0, nred))
{
Trace("nl-ext") << "...sent no lemmas, # extf to reduce = "
<< nred.size() << std::endl;
@@ -619,9 +333,12 @@ void NonlinearExtension::check(Theory::Effort e)
else
{
// If we computed lemmas during collectModelInfo, send them now.
- if (!d_cmiLemmas.empty())
+ if (d_im.hasPendingLemma())
{
- sendLemmas(d_cmiLemmas);
+ d_im.doPendingFacts();
+ d_im.doPendingLemmas();
+ d_im.doPendingPhaseRequirements();
+ d_im.reset();
return;
}
// Otherwise, we will answer SAT. The values that we approximated are
@@ -638,12 +355,17 @@ void NonlinearExtension::check(Theory::Effort e)
tm->recordApproximation(a.first, a.second.first, a.second.second);
}
}
+ for (const auto& vw : d_witnesses)
+ {
+ tm->recordApproximation(vw.first, vw.second);
+ }
}
}
-bool NonlinearExtension::modelBasedRefinement(std::vector<NlLemma>& mlems)
+bool NonlinearExtension::modelBasedRefinement()
{
++(d_stats.d_mbrRuns);
+ d_checkCounter++;
// get the assertions
std::vector<Node> assertions;
@@ -657,7 +379,7 @@ bool NonlinearExtension::modelBasedRefinement(std::vector<NlLemma>& mlems)
// get the extended terms belonging to this theory
std::vector<Node> xts;
- d_containing.getExtTheory()->getTerms(xts);
+ d_extTheory.getTerms(xts);
if (Trace.isOn("nl-ext-debug"))
{
@@ -723,16 +445,15 @@ bool NonlinearExtension::modelBasedRefinement(std::vector<NlLemma>& mlems)
// complete_status:
// 1 : we may answer SAT, -1 : we may not answer SAT, 0 : unknown
int complete_status = 1;
- // lemmas that should be sent later
- std::vector<NlLemma> wlems;
// We require a check either if an assertion is false or a shared term has
// a wrong value
if (!false_asserts.empty() || num_shared_wrong_value > 0)
{
complete_status = num_shared_wrong_value > 0 ? -1 : 0;
- checkLastCall(assertions, false_asserts, xts, mlems, wlems);
- if (!mlems.empty())
+ runStrategy(Theory::Effort::EFFORT_FULL, assertions, false_asserts, xts);
+ if (d_im.hasSentLemma() || d_im.hasPendingLemma())
{
+ d_im.clearWaitingLemmas();
return true;
}
}
@@ -747,22 +468,13 @@ bool NonlinearExtension::modelBasedRefinement(std::vector<NlLemma>& mlems)
<< std::endl;
// check the model based on simple solving of equalities and using
// error bounds on the Taylor approximation of transcendental functions.
- std::vector<NlLemma> lemmas;
- std::vector<Node> gs;
- if (checkModel(assertions, false_asserts, lemmas, gs))
+ if (checkModel(assertions))
{
complete_status = 1;
}
- for (const Node& mg : gs)
- {
- Node mgr = Rewriter::rewrite(mg);
- mgr = d_containing.getValuation().ensureLiteral(mgr);
- d_containing.getOutputChannel().requirePhase(mgr, true);
- d_builtModel = true;
- }
- filterLemmas(lemmas, mlems);
- if (!mlems.empty())
+ if (d_im.hasUsed())
{
+ d_im.clearWaitingLemmas();
return true;
}
}
@@ -771,10 +483,11 @@ bool NonlinearExtension::modelBasedRefinement(std::vector<NlLemma>& mlems)
if (complete_status != 1)
{
// flush the waiting lemmas
- if (!wlems.empty())
+ if (d_im.hasWaitingLemma())
{
- mlems.insert(mlems.end(), wlems.begin(), wlems.end());
- Trace("nl-ext") << "...added " << wlems.size() << " waiting lemmas."
+ std::size_t count = d_im.numWaitingLemmas();
+ d_im.flushWaitingLemmas();
+ Trace("nl-ext") << "...added " << count << " waiting lemmas."
<< std::endl;
return true;
}
@@ -785,7 +498,6 @@ bool NonlinearExtension::modelBasedRefinement(std::vector<NlLemma>& mlems)
complete_status = -1;
if (!shared_term_value_splits.empty())
{
- std::vector<NlLemma> stvLemmas;
for (const Node& eq : shared_term_value_splits)
{
Node req = Rewriter::rewrite(eq);
@@ -793,13 +505,13 @@ bool NonlinearExtension::modelBasedRefinement(std::vector<NlLemma>& mlems)
d_containing.getOutputChannel().requirePhase(literal, true);
Trace("nl-ext-debug") << "Split on : " << literal << std::endl;
Node split = literal.orNode(literal.negate());
- NlLemma nsplit(split, Inference::SHARED_TERM_VALUE_SPLIT);
- filterLemma(nsplit, stvLemmas);
+ NlLemma nsplit(split, InferenceId::NL_SHARED_TERM_VALUE_SPLIT);
+ d_im.addPendingArithLemma(nsplit, true);
}
- if (!stvLemmas.empty())
+ if (d_im.hasWaitingLemma())
{
- mlems.insert(mlems.end(), stvLemmas.begin(), stvLemmas.end());
- Trace("nl-ext") << "...added " << stvLemmas.size()
+ d_im.flushWaitingLemmas();
+ Trace("nl-ext") << "...added " << d_im.numPendingLemmas()
<< " shared term value split lemmas." << std::endl;
return true;
}
@@ -831,6 +543,12 @@ bool NonlinearExtension::modelBasedRefinement(std::vector<NlLemma>& mlems)
d_containing.getOutputChannel().setIncomplete();
}
}
+ else
+ {
+ // we have built a model
+ d_builtModel = true;
+ }
+ d_im.clearWaitingLemmas();
} while (needsRecheck);
// did not add lemmas
@@ -847,24 +565,115 @@ void NonlinearExtension::interceptModel(std::map<Node, Node>& arithModel)
Trace("nl-ext") << "NonlinearExtension::interceptModel begin" << std::endl;
d_model.reset(d_containing.getValuation().getModel(), arithModel);
// run a last call effort check
- d_cmiLemmas.clear();
if (!d_builtModel.get())
{
Trace("nl-ext") << "interceptModel: do model-based refinement" << std::endl;
- modelBasedRefinement(d_cmiLemmas);
+ modelBasedRefinement();
}
if (d_builtModel.get())
{
Trace("nl-ext") << "interceptModel: do model repair" << std::endl;
d_approximations.clear();
+ d_witnesses.clear();
// modify the model values
- d_model.getModelValueRepair(arithModel, d_approximations);
+ d_model.getModelValueRepair(arithModel, d_approximations, d_witnesses);
}
}
void NonlinearExtension::presolve()
{
Trace("nl-ext") << "NonlinearExtension::presolve" << std::endl;
+ d_builtModel = false;
+}
+
+void NonlinearExtension::runStrategy(Theory::Effort effort,
+ const std::vector<Node>& assertions,
+ const std::vector<Node>& false_asserts,
+ const std::vector<Node>& xts)
+{
+ ++(d_stats.d_checkRuns);
+
+ if (Trace.isOn("nl-ext"))
+ {
+ for (const auto& a : assertions)
+ {
+ Trace("nl-ext") << "Input assertion: " << a << std::endl;
+ }
+ }
+ if (!d_strategy.isStrategyInit())
+ {
+ d_strategy.initializeStrategy();
+ }
+
+ auto steps = d_strategy.getStrategy();
+ bool stop = false;
+ while (!stop && steps.hasNext())
+ {
+ InferStep step = steps.next();
+ Trace("nl-ext") << "Step " << step << std::endl;
+ switch (step)
+ {
+ case InferStep::BREAK: stop = d_im.hasPendingLemma(); break;
+ case InferStep::FLUSH_WAITING_LEMMAS: d_im.flushWaitingLemmas(); break;
+ case InferStep::CAD_FULL: d_cadSlv.checkFull(); break;
+ case InferStep::CAD_INIT: d_cadSlv.initLastCall(assertions); break;
+ case InferStep::NL_FACTORING:
+ d_factoringSlv.check(assertions, false_asserts);
+ break;
+ case InferStep::IAND_INIT:
+ d_iandSlv.initLastCall(assertions, false_asserts, xts);
+ break;
+ case InferStep::IAND_FULL: d_iandSlv.checkFullRefine(); break;
+ case InferStep::IAND_INITIAL: d_iandSlv.checkInitialRefine(); break;
+ case InferStep::ICP:
+ d_icpSlv.reset(assertions);
+ d_icpSlv.check();
+ break;
+ case InferStep::NL_INIT:
+ d_extState.init(xts);
+ d_monomialBoundsSlv.init();
+ d_monomialSlv.init(xts);
+ break;
+ case InferStep::NL_MONOMIAL_INFER_BOUNDS:
+ d_monomialBoundsSlv.checkBounds(assertions, false_asserts);
+ break;
+ case InferStep::NL_MONOMIAL_MAGNITUDE0:
+ d_monomialSlv.checkMagnitude(0);
+ break;
+ case InferStep::NL_MONOMIAL_MAGNITUDE1:
+ d_monomialSlv.checkMagnitude(1);
+ break;
+ case InferStep::NL_MONOMIAL_MAGNITUDE2:
+ d_monomialSlv.checkMagnitude(2);
+ break;
+ case InferStep::NL_MONOMIAL_SIGN: d_monomialSlv.checkSign(); break;
+ case InferStep::NL_RESOLUTION_BOUNDS:
+ d_monomialBoundsSlv.checkResBounds();
+ break;
+ case InferStep::NL_SPLIT_ZERO: d_splitZeroSlv.check(); break;
+ case InferStep::NL_TANGENT_PLANES: d_tangentPlaneSlv.check(false); break;
+ case InferStep::NL_TANGENT_PLANES_WAITING:
+ d_tangentPlaneSlv.check(true);
+ break;
+ case InferStep::TRANS_INIT:
+ d_trSlv.initLastCall(assertions, false_asserts, xts);
+ break;
+ case InferStep::TRANS_INITIAL:
+ d_trSlv.checkTranscendentalInitialRefine();
+ break;
+ case InferStep::TRANS_MONOTONIC:
+ d_trSlv.checkTranscendentalMonotonic();
+ break;
+ case InferStep::TRANS_TANGENT_PLANES:
+ d_trSlv.checkTranscendentalTangentPlanes();
+ break;
+ }
+ }
+
+ Trace("nl-ext") << " ...finished with " << d_im.numWaitingLemmas()
+ << " waiting lemmas." << std::endl;
+ Trace("nl-ext") << " ...finished with " << d_im.numPendingLemmas()
+ << " pending lemmas." << std::endl;
}
} // namespace nl
diff --git a/src/theory/arith/nl/nonlinear_extension.h b/src/theory/arith/nl/nonlinear_extension.h
index 69710265c..21b978a55 100644
--- a/src/theory/arith/nl/nonlinear_extension.h
+++ b/src/theory/arith/nl/nonlinear_extension.h
@@ -2,10 +2,10 @@
/*! \file nonlinear_extension.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Tim King, Tianyi Liang
+ ** Andrew Reynolds, Tim King, Gereon Kremer
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,20 +18,28 @@
#ifndef CVC4__THEORY__ARITH__NL__NONLINEAR_EXTENSION_H
#define CVC4__THEORY__ARITH__NL__NONLINEAR_EXTENSION_H
-#include <stdint.h>
#include <map>
#include <vector>
#include "context/cdlist.h"
#include "expr/kind.h"
#include "expr/node.h"
+#include "theory/arith/inference_manager.h"
+#include "theory/arith/nl/cad_solver.h"
+#include "theory/arith/nl/ext/factoring_check.h"
+#include "theory/arith/nl/ext/monomial_bounds_check.h"
+#include "theory/arith/nl/ext/monomial_check.h"
+#include "theory/arith/nl/ext/split_zero_check.h"
+#include "theory/arith/nl/ext/tangent_plane_check.h"
+#include "theory/arith/nl/ext_theory_callback.h"
#include "theory/arith/nl/iand_solver.h"
+#include "theory/arith/nl/icp/icp_solver.h"
#include "theory/arith/nl/nl_lemma_utils.h"
#include "theory/arith/nl/nl_model.h"
-#include "theory/arith/nl/nl_solver.h"
#include "theory/arith/nl/stats.h"
+#include "theory/arith/nl/strategy.h"
#include "theory/arith/nl/transcendental_solver.h"
-#include "theory/arith/theory_arith.h"
+#include "theory/ext_theory.h"
#include "theory/uf/equality_engine.h"
namespace CVC4 {
@@ -68,50 +76,12 @@ class NonlinearExtension
typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
public:
- NonlinearExtension(TheoryArith& containing, eq::EqualityEngine* ee);
+ NonlinearExtension(TheoryArith& containing, ArithState& state, eq::EqualityEngine* ee);
~NonlinearExtension();
- /** Get current substitution
- *
- * This function and the one below are
- * used for context-dependent
- * simplification, see Section 3.1 of
- * "Designing Theory Solvers with Extensions"
- * by Reynolds et al. FroCoS 2017.
- *
- * effort : an identifier indicating the stage where
- * we are performing context-dependent simplification,
- * vars : a set of arithmetic variables.
- *
- * This function populates subs and exp, such that for 0 <= i < vars.size():
- * ( exp[vars[i]] ) => vars[i] = subs[i]
- * where exp[vars[i]] is a set of assertions
- * that hold in the current context. We call { vars -> subs } a "derivable
- * substituion" (see Reynolds et al. FroCoS 2017).
- */
- bool getCurrentSubstitution(int effort,
- const std::vector<Node>& vars,
- std::vector<Node>& subs,
- std::map<Node, std::vector<Node>>& exp);
- /** Is the term n in reduced form?
- *
- * Used for context-dependent simplification.
- *
- * effort : an identifier indicating the stage where
- * we are performing context-dependent simplification,
- * on : the original term that we reduced to n,
- * exp : an explanation such that ( exp => on = n ).
- *
- * We return a pair ( b, exp' ) such that
- * if b is true, then:
- * n is in reduced form
- * if exp' is non-null, then ( exp' => on = n )
- * The second part of the pair is used for constructing
- * minimal explanations for context-dependent simplifications.
+ /**
+ * Does non-context dependent setup for a node connected to a theory.
*/
- std::pair<bool, Node> isExtfReduced(int effort,
- Node n,
- Node on,
- const std::vector<Node>& exp) const;
+ void preRegisterTerm(TNode n);
/** Check at effort level e.
*
* This call may result in (possibly multiple) calls to d_out->lemma(...)
@@ -147,11 +117,6 @@ class NonlinearExtension
* constraints are satisfiable, it may "repair" the values in the argument
* arithModel so that it satisfies certain nonlinear constraints. This may
* involve e.g. solving for variables in nonlinear equations.
- *
- * Notice that in the former case, the lemmas it constructs are not sent out
- * immediately. Instead, they are put in temporary vector d_cmiLemmas, which
- * are then sent out (if necessary) when a last call
- * effort check is issued to this class.
*/
void interceptModel(std::map<Node, Node>& arithModel);
/** Does this class need a call to check(...) at last call effort? */
@@ -165,6 +130,9 @@ class NonlinearExtension
*/
void presolve();
+ /** Process side effect se */
+ void processSideEffect(const NlLemma& se);
+
private:
/** Model-based refinement
*
@@ -175,38 +143,12 @@ class NonlinearExtension
* described in Reynolds et al. FroCoS 2017 that are based on ruling out
* the current candidate model.
*
- * This function returns true if a lemma was added to the vector lems.
+ * This function returns true if a lemma was added to the inference manager.
* Otherwise, it returns false. In the latter case, the model object d_model
* may have information regarding how to construct a model, in the case that
* we determined the problem is satisfiable.
*/
- bool modelBasedRefinement(std::vector<NlLemma>& mlems);
-
- /** check last call
- *
- * Check assertions for consistency in the effort LAST_CALL with a subset of
- * the assertions, false_asserts, that evaluate to false in the current model.
- *
- * xts : the list of (non-reduced) extended terms in the current context.
- *
- * This method adds lemmas to arguments lems and wlems, each of
- * which are intended to be sent out on the output channel of TheoryArith
- * under certain conditions.
- *
- * If the set lems is non-empty, then no further processing is
- * necessary. The last call effort check should terminate and these
- * lemmas should be sent.
- *
- * The "waiting" lemmas wlems contain lemmas that should be sent on the
- * output channel as a last resort. In other words, only if we are not
- * able to establish SAT via a call to checkModel(...) should wlems be
- * considered. This set typically contains tangent plane lemmas.
- */
- int checkLastCall(const std::vector<Node>& assertions,
- const std::vector<Node>& false_asserts,
- const std::vector<Node>& xts,
- std::vector<NlLemma>& lems,
- std::vector<NlLemma>& wlems);
+ bool modelBasedRefinement();
/** get assertions
*
@@ -241,20 +183,12 @@ class NonlinearExtension
*
* For details, see Section 3 of Cimatti et al CADE 2017 under the heading
* "Detecting Satisfiable Formulas".
- *
- * The arguments lemmas and gs store the lemmas and guard literals to be sent
- * out on the output channel of TheoryArith as lemmas and calls to
- * ensureLiteral respectively.
*/
- bool checkModel(const std::vector<Node>& assertions,
- const std::vector<Node>& false_asserts,
- std::vector<NlLemma>& lemmas,
- std::vector<Node>& gs);
+ bool checkModel(const std::vector<Node>& assertions);
//---------------------------end check model
-
- /** Is n entailed with polarity pol in the current context? */
- bool isEntailed(Node n, bool pol);
-
+ /** compute relevant assertions */
+ void computeRelevantAssertions(const std::vector<Node>& assertions,
+ std::vector<Node>& keep);
/**
* Potentially adds lemmas to the set out and clears lemmas. Returns
* the number of lemmas added to out. We do not add lemmas that have already
@@ -269,13 +203,21 @@ class NonlinearExtension
* Send lemmas in out on the output channel of theory of arithmetic.
*/
void sendLemmas(const std::vector<NlLemma>& out);
- /** Process side effect se */
- void processSideEffect(const NlLemma& se);
- /** cache of all lemmas sent on the output channel (user-context-dependent) */
- NodeSet d_lemmas;
- /** Same as above, for preprocessed lemmas */
- NodeSet d_lemmasPp;
+ /** run check strategy
+ *
+ * Check assertions for consistency in the effort LAST_CALL with a subset of
+ * the assertions, false_asserts, that evaluate to false in the current model.
+ *
+ * xts : the list of (non-reduced) extended terms in the current context.
+ *
+ * This method adds lemmas to d_im directly.
+ */
+ void runStrategy(Theory::Effort effort,
+ const std::vector<Node>& assertions,
+ const std::vector<Node>& false_asserts,
+ const std::vector<Node>& xts);
+
/** commonly used terms */
Node d_zero;
Node d_one;
@@ -283,46 +225,74 @@ class NonlinearExtension
Node d_true;
// The theory of arithmetic containing this extension.
TheoryArith& d_containing;
+ InferenceManager& d_im;
// pointer to used equality engine
eq::EqualityEngine* d_ee;
/** The statistics class */
NlStats d_stats;
// needs last call effort
bool d_needsLastCall;
+ /**
+ * The number of times we have the called main check method
+ * (modelBasedRefinement). This counter is used for interleaving strategies.
+ */
+ unsigned d_checkCounter;
+ /** The callback for the extended theory below */
+ NlExtTheoryCallback d_extTheoryCb;
+ /** Extended theory, responsible for context-dependent simplification. */
+ ExtTheory d_extTheory;
/** The non-linear model object
*
* This class is responsible for computing model values for arithmetic terms
* and for establishing when we are able to answer "SAT".
*/
NlModel d_model;
+
/** The transcendental extension object
*
* This is the subsolver responsible for running the procedure for
* transcendental functions.
*/
TranscendentalSolver d_trSlv;
- /** The nonlinear extension object
- *
- * This is the subsolver responsible for running the procedure for
- * constraints involving nonlinear mulitplication, Cimatti et al., TACAS 2017.
+ /**
+ * Holds common lookup data for the checks implemented in the "nl-ext"
+ * solvers (from Cimatti et al., TACAS 2017).
*/
- NlSolver d_nlSlv;
+ ExtState d_extState;
+ /** Solver for factoring lemmas. */
+ FactoringCheck d_factoringSlv;
+ /** Solver for lemmas about monomial bounds. */
+ MonomialBoundsCheck d_monomialBoundsSlv;
+ /** Solver for lemmas about monomials. */
+ MonomialCheck d_monomialSlv;
+ /** Solver for lemmas that split multiplication at zero. */
+ SplitZeroCheck d_splitZeroSlv;
+ /** Solver for tangent plane lemmas. */
+ TangentPlaneCheck d_tangentPlaneSlv;
+ /** The CAD-based solver */
+ CadSolver d_cadSlv;
+ /** The ICP-based solver */
+ icp::ICPSolver d_icpSlv;
/** The integer and solver
*
* This is the subsolver responsible for running the procedure for
* constraints involving integer and.
*/
IAndSolver d_iandSlv;
- /**
- * The lemmas we computed during collectModelInfo, to be sent out on the
- * output channel of TheoryArith.
- */
- std::vector<NlLemma> d_cmiLemmas;
+
+ /** The strategy for the nonlinear extension. */
+ Strategy d_strategy;
+
/**
* The approximations computed during collectModelInfo. For details, see
* NlModel::getModelValueRepair.
*/
std::map<Node, std::pair<Node, Node>> d_approximations;
+ /**
+ * The witnesses computed during collectModelInfo. For details, see
+ * NlModel::getModelValueRepair.
+ */
+ std::map<Node, Node> d_witnesses;
/** have we successfully built the model in this SAT context? */
context::CDO<bool> d_builtModel;
}; /* class NonlinearExtension */
diff --git a/src/theory/arith/nl/poly_conversion.cpp b/src/theory/arith/nl/poly_conversion.cpp
new file mode 100644
index 000000000..0e4e21b76
--- /dev/null
+++ b/src/theory/arith/nl/poly_conversion.cpp
@@ -0,0 +1,805 @@
+/********************* */
+/*! \file poly_conversion.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utilities for converting to and from LibPoly objects.
+ **
+ ** Utilities for converting to and from LibPoly objects.
+ **/
+
+#include "poly_conversion.h"
+
+#ifdef CVC4_POLY_IMP
+
+#include "expr/node.h"
+#include "expr/node_manager_attributes.h"
+#include "util/integer.h"
+#include "util/poly_util.h"
+#include "util/rational.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+poly::Variable VariableMapper::operator()(const CVC4::Node& n)
+{
+ auto it = mVarCVCpoly.find(n);
+ if (it == mVarCVCpoly.end())
+ {
+ std::string name;
+ if (n.isVar())
+ {
+ if (!n.getAttribute(expr::VarNameAttr(), name))
+ {
+ Trace("poly::conversion")
+ << "Variable " << n << " has no name, using ID instead."
+ << std::endl;
+ name = "v_" + std::to_string(n.getId());
+ }
+ }
+ else
+ {
+ name = "v_" + std::to_string(n.getId());
+ }
+ it = mVarCVCpoly.emplace(n, poly::Variable(name.c_str())).first;
+ mVarpolyCVC.emplace(it->second, n);
+ }
+ return it->second;
+}
+
+CVC4::Node VariableMapper::operator()(const poly::Variable& n)
+{
+ auto it = mVarpolyCVC.find(n);
+ Assert(it != mVarpolyCVC.end())
+ << "Expect variable " << n << " to be added already.";
+ return it->second;
+}
+
+CVC4::Node as_cvc_upolynomial(const poly::UPolynomial& p, const CVC4::Node& var)
+{
+ Trace("poly::conversion")
+ << "Converting " << p << " over " << var << std::endl;
+
+ std::vector<poly::Integer> coeffs = coefficients(p);
+
+ auto* nm = NodeManager::currentNM();
+
+ Node res = nm->mkConst(Rational(0));
+ Node monomial = nm->mkConst(Rational(1));
+ for (std::size_t i = 0, n = coeffs.size(); i < n; ++i)
+ {
+ if (!is_zero(coeffs[i]))
+ {
+ Node coeff = nm->mkConst(poly_utils::toRational(coeffs[i]));
+ Node term = nm->mkNode(Kind::MULT, coeff, monomial);
+ res = nm->mkNode(Kind::PLUS, res, term);
+ }
+ monomial = nm->mkNode(Kind::NONLINEAR_MULT, monomial, var);
+ }
+ Trace("poly::conversion") << "-> " << res << std::endl;
+ return res;
+}
+
+poly::UPolynomial as_poly_upolynomial_impl(const CVC4::Node& n,
+ poly::Integer& denominator,
+ const CVC4::Node& var)
+{
+ denominator = poly::Integer(1);
+ if (n.isVar())
+ {
+ Assert(n == var) << "Unexpected variable: should be " << var << " but is "
+ << n;
+ return poly::UPolynomial({0, 1});
+ }
+ switch (n.getKind())
+ {
+ case Kind::CONST_RATIONAL:
+ {
+ Rational r = n.getConst<Rational>();
+ denominator = poly_utils::toInteger(r.getDenominator());
+ return poly::UPolynomial(poly_utils::toInteger(r.getNumerator()));
+ }
+ case Kind::PLUS:
+ {
+ poly::UPolynomial res;
+ poly::Integer denom;
+ for (const auto& child : n)
+ {
+ poly::UPolynomial tmp = as_poly_upolynomial_impl(child, denom, var);
+ /** Normalize denominators
+ */
+ poly::Integer g = gcd(denom, denominator);
+ res = res * (denom / g) + tmp * (denominator / g);
+ denominator *= (denom / g);
+ }
+ return res;
+ }
+ case Kind::MULT:
+ case Kind::NONLINEAR_MULT:
+ {
+ poly::UPolynomial res(denominator);
+ poly::Integer denom;
+ for (const auto& child : n)
+ {
+ res = res * as_poly_upolynomial_impl(child, denom, var);
+ denominator *= denom;
+ }
+ return res;
+ }
+ default:
+ Warning() << "Unhandled node " << n << " with kind " << n.getKind()
+ << std::endl;
+ }
+ return poly::UPolynomial();
+}
+
+poly::UPolynomial as_poly_upolynomial(const CVC4::Node& n,
+ const CVC4::Node& var)
+{
+ poly::Integer denom;
+ return as_poly_upolynomial_impl(n, denom, var);
+}
+
+poly::Polynomial as_poly_polynomial_impl(const CVC4::Node& n,
+ poly::Integer& denominator,
+ VariableMapper& vm)
+{
+ denominator = poly::Integer(1);
+ if (n.isVar())
+ {
+ return poly::Polynomial(vm(n));
+ }
+ switch (n.getKind())
+ {
+ case Kind::CONST_RATIONAL:
+ {
+ Rational r = n.getConst<Rational>();
+ denominator = poly_utils::toInteger(r.getDenominator());
+ return poly::Polynomial(poly_utils::toInteger(r.getNumerator()));
+ }
+ case Kind::PLUS:
+ {
+ poly::Polynomial res;
+ poly::Integer denom;
+ for (const auto& child : n)
+ {
+ poly::Polynomial tmp = as_poly_polynomial_impl(child, denom, vm);
+ /** Normalize denominators
+ */
+ poly::Integer g = gcd(denom, denominator);
+ res = res * (denom / g) + tmp * (denominator / g);
+ denominator *= (denom / g);
+ }
+ return res;
+ }
+ case Kind::MULT:
+ case Kind::NONLINEAR_MULT:
+ {
+ poly::Polynomial res(denominator);
+ poly::Integer denom;
+ for (const auto& child : n)
+ {
+ res *= as_poly_polynomial_impl(child, denom, vm);
+ denominator *= denom;
+ }
+ return res;
+ }
+ default: return poly::Polynomial(vm(n));
+ }
+ return poly::Polynomial();
+}
+poly::Polynomial as_poly_polynomial(const CVC4::Node& n, VariableMapper& vm)
+{
+ poly::Integer denom;
+ return as_poly_polynomial_impl(n, denom, vm);
+}
+poly::Polynomial as_poly_polynomial(const CVC4::Node& n,
+ VariableMapper& vm,
+ poly::Rational& denominator)
+{
+ poly::Integer denom;
+ auto res = as_poly_polynomial_impl(n, denom, vm);
+ denominator = poly::Rational(denom);
+ return res;
+}
+
+namespace {
+/**
+ * Utility class that collects the monomial terms (as nodes) from the polynomial
+ * we are converting.
+ */
+struct CollectMonomialData
+{
+ CollectMonomialData(VariableMapper& v) : d_vm(v) {}
+
+ /** Mapper from poly variables to CVC4 variables */
+ VariableMapper& d_vm;
+ /** Collections of the monomial terms */
+ std::vector<Node> d_terms;
+ /** Caches the current node manager */
+ NodeManager* d_nm = NodeManager::currentNM();
+};
+/**
+ * Callback for lp_polynomial_traverse. Assumes data is actually a
+ * CollectMonomialData object and puts the polynomial into it.
+ */
+void collect_monomials(const lp_polynomial_context_t* ctx,
+ lp_monomial_t* m,
+ void* data)
+{
+ CollectMonomialData* d = static_cast<CollectMonomialData*>(data);
+ // constant
+ Node term =
+ d->d_nm->mkConst<Rational>(poly_utils::toRational(poly::Integer(&m->a)));
+ for (std::size_t i = 0; i < m->n; ++i)
+ {
+ // variable exponent pair
+ Node var = d->d_vm(m->p[i].x);
+ if (m->p[i].d > 1)
+ {
+ Node exp = d->d_nm->mkConst<Rational>(m->p[i].d);
+ term = d->d_nm->mkNode(
+ Kind::NONLINEAR_MULT, term, d->d_nm->mkNode(Kind::POW, var, exp));
+ }
+ else
+ {
+ term = d->d_nm->mkNode(Kind::NONLINEAR_MULT, term, var);
+ }
+ }
+ d->d_terms.emplace_back(term);
+}
+} // namespace
+
+CVC4::Node as_cvc_polynomial(const poly::Polynomial& p, VariableMapper& vm)
+{
+ CollectMonomialData cmd(vm);
+ // Do the actual conversion
+ lp_polynomial_traverse(p.get_internal(), collect_monomials, &cmd);
+
+ if (cmd.d_terms.empty())
+ {
+ return cmd.d_nm->mkConst<Rational>(0);
+ }
+ if (cmd.d_terms.size() == 1)
+ {
+ return cmd.d_terms.front();
+ }
+ return cmd.d_nm->mkNode(Kind::PLUS, cmd.d_terms);
+}
+
+poly::SignCondition normalize_kind(CVC4::Kind kind,
+ bool negated,
+ poly::Polynomial& lhs)
+{
+ switch (kind)
+ {
+ case Kind::EQUAL:
+ {
+ return negated ? poly::SignCondition::NE : poly::SignCondition::EQ;
+ }
+ case Kind::LT:
+ {
+ if (negated)
+ {
+ lhs = -lhs;
+ return poly::SignCondition::LE;
+ }
+ return poly::SignCondition::LT;
+ }
+ case Kind::LEQ:
+ {
+ if (negated)
+ {
+ lhs = -lhs;
+ return poly::SignCondition::LT;
+ }
+ return poly::SignCondition::LE;
+ }
+ case Kind::GT:
+ {
+ if (negated)
+ {
+ return poly::SignCondition::LE;
+ }
+ lhs = -lhs;
+ return poly::SignCondition::LT;
+ }
+ case Kind::GEQ:
+ {
+ if (negated)
+ {
+ return poly::SignCondition::LT;
+ }
+ lhs = -lhs;
+ return poly::SignCondition::LE;
+ }
+ default:
+ Assert(false) << "This function only deals with arithmetic relations.";
+ return poly::SignCondition::EQ;
+ }
+}
+
+std::pair<poly::Polynomial, poly::SignCondition> as_poly_constraint(
+ Node n, VariableMapper& vm)
+{
+ bool negated = false;
+ Node origin = n;
+ if (n.getKind() == Kind::NOT)
+ {
+ Assert(n.getNumChildren() == 1)
+ << "Expect negations to have a single child.";
+ negated = true;
+ n = *n.begin();
+ }
+ Assert((n.getKind() == Kind::EQUAL) || (n.getKind() == Kind::GT)
+ || (n.getKind() == Kind::GEQ) || (n.getKind() == Kind::LT)
+ || (n.getKind() == Kind::LEQ))
+ << "Found a constraint with unsupported relation " << n.getKind();
+
+ Assert(n.getNumChildren() == 2)
+ << "Supported relations only have two children.";
+ auto childit = n.begin();
+ poly::Integer ldenom;
+ poly::Polynomial left = as_poly_polynomial_impl(*childit++, ldenom, vm);
+ poly::Integer rdenom;
+ poly::Polynomial right = as_poly_polynomial_impl(*childit++, rdenom, vm);
+ Assert(childit == n.end()) << "Screwed up iterator handling.";
+ Assert(ldenom > poly::Integer(0) && rdenom > poly::Integer(0))
+ << "Expected denominators to be always positive.";
+
+ poly::Integer g = gcd(ldenom, rdenom);
+ poly::Polynomial lhs = left * (rdenom / g) - right * (ldenom / g);
+ poly::SignCondition sc = normalize_kind(n.getKind(), negated, lhs);
+ return {lhs, sc};
+}
+
+Node ran_to_node(const RealAlgebraicNumber& ran, const Node& ran_variable)
+{
+ return ran_to_node(ran.getValue(), ran_variable);
+}
+
+Node ran_to_node(const poly::AlgebraicNumber& an, const Node& ran_variable)
+{
+ auto* nm = NodeManager::currentNM();
+
+ const poly::DyadicInterval& di = get_isolating_interval(an);
+ if (is_point(di))
+ {
+ return nm->mkConst(poly_utils::toRational(get_point(di)));
+ }
+ Assert(di.get_internal()->a_open && di.get_internal()->b_open)
+ << "We assume an open interval here.";
+
+ Node poly = as_cvc_upolynomial(get_defining_polynomial(an), ran_variable);
+ Node lower = nm->mkConst(poly_utils::toRational(get_lower(di)));
+ Node upper = nm->mkConst(poly_utils::toRational(get_upper(di)));
+
+ // Construct witness:
+ return nm->mkNode(Kind::AND,
+ // poly(var) == 0
+ nm->mkNode(Kind::EQUAL, poly, nm->mkConst(Rational(0))),
+ // lower_bound < var
+ nm->mkNode(Kind::LT, lower, ran_variable),
+ // var < upper_bound
+ nm->mkNode(Kind::LT, ran_variable, upper));
+}
+
+Node value_to_node(const poly::Value& v, const Node& ran_variable)
+{
+ Assert(!is_minus_infinity(v)) << "Can not convert minus infinity.";
+ Assert(!is_none(v)) << "Can not convert none.";
+ Assert(!is_plus_infinity(v)) << "Can not convert plus infinity.";
+
+ if (is_algebraic_number(v))
+ {
+ return ran_to_node(as_algebraic_number(v), ran_variable);
+ }
+ auto* nm = NodeManager::currentNM();
+ if (is_dyadic_rational(v))
+ {
+ return nm->mkConst(poly_utils::toRational(as_dyadic_rational(v)));
+ }
+ if (is_integer(v))
+ {
+ return nm->mkConst(poly_utils::toRational(as_integer(v)));
+ }
+ if (is_rational(v))
+ {
+ return nm->mkConst(poly_utils::toRational(as_rational(v)));
+ }
+ Assert(false) << "All cases should be covered.";
+ return nm->mkConst(Rational(0));
+}
+
+Node lower_bound_as_node(const Node& var,
+ const poly::Value& lower,
+ bool open,
+ bool allowNonlinearLemma)
+{
+ auto* nm = NodeManager::currentNM();
+ if (!poly::is_algebraic_number(lower))
+ {
+ return nm->mkNode(open ? Kind::LEQ : Kind::LT,
+ var,
+ nm->mkConst(poly_utils::toRationalAbove(lower)));
+ }
+ if (poly::represents_rational(lower))
+ {
+ return nm->mkNode(
+ open ? Kind::LEQ : Kind::LT,
+ var,
+ nm->mkConst(poly_utils::toRationalAbove(poly::get_rational(lower))));
+ }
+ if (!allowNonlinearLemma)
+ {
+ return Node();
+ }
+
+ const poly::AlgebraicNumber& alg = as_algebraic_number(lower);
+
+ Node poly = as_cvc_upolynomial(get_defining_polynomial(alg), var);
+ Rational l = poly_utils::toRational(
+ poly::get_lower(poly::get_isolating_interval(alg)));
+ Rational u = poly_utils::toRational(
+ poly::get_upper(poly::get_isolating_interval(alg)));
+ int sl = poly::sign_at(get_defining_polynomial(alg),
+ poly::get_lower(poly::get_isolating_interval(alg)));
+ int su = poly::sign_at(get_defining_polynomial(alg),
+ poly::get_upper(poly::get_isolating_interval(alg)));
+ Assert(sl != 0 && su != 0 && sl != su);
+
+ // open: var <= l or (var < u and sgn(poly(var)) == sl)
+ // !open: var <= l or (var < u and sgn(poly(var)) == sl/0)
+ Kind relation;
+ if (open)
+ {
+ relation = (sl < 0) ? Kind::LEQ : Kind::GEQ;
+ }
+ else
+ {
+ relation = (sl < 0) ? Kind::LT : Kind::GT;
+ }
+ return nm->mkNode(
+ Kind::OR,
+ nm->mkNode(Kind::LEQ, var, nm->mkConst(l)),
+ nm->mkNode(Kind::AND,
+ nm->mkNode(Kind::LT, var, nm->mkConst(u)),
+ nm->mkNode(relation, poly, nm->mkConst(Rational(0)))));
+}
+
+Node upper_bound_as_node(const Node& var,
+ const poly::Value& upper,
+ bool open,
+ bool allowNonlinearLemma)
+{
+ auto* nm = NodeManager::currentNM();
+ if (!poly::is_algebraic_number(upper))
+ {
+ return nm->mkNode(open ? Kind::GEQ : Kind::GT,
+ var,
+ nm->mkConst(poly_utils::toRationalAbove(upper)));
+ }
+ if (poly::represents_rational(upper))
+ {
+ return nm->mkNode(
+ open ? Kind::GEQ : Kind::GT,
+ var,
+ nm->mkConst(poly_utils::toRationalAbove(poly::get_rational(upper))));
+ }
+ if (!allowNonlinearLemma)
+ {
+ return Node();
+ }
+
+ const poly::AlgebraicNumber& alg = as_algebraic_number(upper);
+
+ Node poly = as_cvc_upolynomial(get_defining_polynomial(alg), var);
+ Rational l = poly_utils::toRational(
+ poly::get_lower(poly::get_isolating_interval(alg)));
+ Rational u = poly_utils::toRational(
+ poly::get_upper(poly::get_isolating_interval(alg)));
+ int sl = poly::sign_at(get_defining_polynomial(alg),
+ poly::get_lower(poly::get_isolating_interval(alg)));
+ int su = poly::sign_at(get_defining_polynomial(alg),
+ poly::get_upper(poly::get_isolating_interval(alg)));
+ Assert(sl != 0 && su != 0 && sl != su);
+
+ // open: var >= u or (var > l and sgn(poly(var)) == su)
+ // !open: var >= u or (var > l and sgn(poly(var)) == su/0)
+ Kind relation;
+ if (open)
+ {
+ relation = (su < 0) ? Kind::LEQ : Kind::GEQ;
+ }
+ else
+ {
+ relation = (su < 0) ? Kind::LT : Kind::GT;
+ }
+ return nm->mkNode(
+ Kind::OR,
+ nm->mkNode(Kind::GEQ, var, nm->mkConst(u)),
+ nm->mkNode(Kind::AND,
+ nm->mkNode(Kind::GT, var, nm->mkConst(l)),
+ nm->mkNode(relation, poly, nm->mkConst(Rational(0)))));
+}
+
+Node excluding_interval_to_lemma(const Node& variable,
+ const poly::Interval& interval,
+ bool allowNonlinearLemma)
+{
+ auto* nm = NodeManager::currentNM();
+ const auto& lv = poly::get_lower(interval);
+ const auto& uv = poly::get_upper(interval);
+ if (bitsize(lv) > 100 || bitsize(uv) > 100) return Node();
+ bool li = poly::is_minus_infinity(lv);
+ bool ui = poly::is_plus_infinity(uv);
+ if (li && ui) return nm->mkConst(true);
+ if (poly::is_point(interval))
+ {
+ if (is_algebraic_number(lv))
+ {
+ const poly::AlgebraicNumber& alg = as_algebraic_number(lv);
+ if (poly::is_rational(alg))
+ {
+ Trace("nl-cad") << "Rational point interval: " << interval << std::endl;
+ return nm->mkNode(Kind::DISTINCT,
+ variable,
+ nm->mkConst(poly_utils::toRational(
+ poly::to_rational_approximation(alg))));
+ }
+ Trace("nl-cad") << "Algebraic point interval: " << interval << std::endl;
+ // p(x) != 0 or x <= lb or ub <= x
+ if (allowNonlinearLemma)
+ {
+ Node poly = as_cvc_upolynomial(get_defining_polynomial(alg), variable);
+ return nm->mkNode(
+ Kind::OR,
+ nm->mkNode(Kind::DISTINCT, poly, nm->mkConst(Rational(0))),
+ nm->mkNode(Kind::LT,
+ variable,
+ nm->mkConst(poly_utils::toRationalBelow(lv))),
+ nm->mkNode(Kind::GT,
+ variable,
+ nm->mkConst(poly_utils::toRationalAbove(lv))));
+ }
+ return Node();
+ }
+ else
+ {
+ Trace("nl-cad") << "Rational point interval: " << interval << std::endl;
+ return nm->mkNode(Kind::DISTINCT,
+ variable,
+ nm->mkConst(poly_utils::toRationalBelow(lv)));
+ }
+ }
+ if (li)
+ {
+ Trace("nl-cad") << "Only upper bound: " << interval << std::endl;
+ return upper_bound_as_node(
+ variable, uv, poly::get_upper_open(interval), allowNonlinearLemma);
+ }
+ if (ui)
+ {
+ Trace("nl-cad") << "Only lower bound: " << interval << std::endl;
+ return lower_bound_as_node(
+ variable, lv, poly::get_lower_open(interval), allowNonlinearLemma);
+ }
+ Trace("nl-cad") << "Proper interval: " << interval << std::endl;
+ Node lb = lower_bound_as_node(
+ variable, lv, poly::get_lower_open(interval), allowNonlinearLemma);
+ Node ub = upper_bound_as_node(
+ variable, uv, poly::get_upper_open(interval), allowNonlinearLemma);
+ if (lb.isNull() || ub.isNull()) return Node();
+ return nm->mkNode(Kind::OR, lb, ub);
+}
+
+Maybe<Rational> get_lower_bound(const Node& n)
+{
+ if (n.getNumChildren() != 2) return Maybe<Rational>();
+ if (n.getKind() == Kind::LT)
+ {
+ if (!n[0].isConst()) return Maybe<Rational>();
+ if (!n[1].isVar()) return Maybe<Rational>();
+ return n[0].getConst<Rational>();
+ }
+ else if (n.getKind() == Kind::GT)
+ {
+ if (!n[0].isVar()) return Maybe<Rational>();
+ if (!n[1].isConst()) return Maybe<Rational>();
+ return n[1].getConst<Rational>();
+ }
+ return Maybe<Rational>();
+}
+Maybe<Rational> get_upper_bound(const Node& n)
+{
+ if (n.getNumChildren() != 2) return Maybe<Rational>();
+ if (n.getKind() == Kind::LT)
+ {
+ if (!n[0].isVar()) return Maybe<Rational>();
+ if (!n[1].isConst()) return Maybe<Rational>();
+ return n[1].getConst<Rational>();
+ }
+ else if (n.getKind() == Kind::GT)
+ {
+ if (!n[0].isConst()) return Maybe<Rational>();
+ if (!n[1].isVar()) return Maybe<Rational>();
+ return n[0].getConst<Rational>();
+ }
+ return Maybe<Rational>();
+}
+
+/** Returns indices of appropriate parts of ran encoding.
+ * Returns (poly equation ; lower bound ; upper bound)
+ */
+std::tuple<Node, Rational, Rational> detect_ran_encoding(const Node& n)
+{
+ Assert(n.getKind() == Kind::AND) << "Invalid node structure.";
+ Assert(n.getNumChildren() == 3) << "Invalid node structure.";
+
+ Node poly_eq;
+ if (n[0].getKind() == Kind::EQUAL)
+ poly_eq = n[0];
+ else if (n[1].getKind() == Kind::EQUAL)
+ poly_eq = n[1];
+ else if (n[2].getKind() == Kind::EQUAL)
+ poly_eq = n[2];
+ else
+ Assert(false) << "Could not identify polynomial equation.";
+
+ Node poly;
+ Assert(poly_eq.getNumChildren() == 2) << "Invalid polynomial equation.";
+ if (poly_eq[0].isConst())
+ {
+ Assert(poly_eq[0].getConst<Rational>() == Rational(0))
+ << "Invalid polynomial equation.";
+ poly = poly_eq[1];
+ }
+ else if (poly_eq[1].isConst())
+ {
+ Assert(poly_eq[1].getConst<Rational>() == Rational(0))
+ << "Invalid polynomial equation.";
+ poly = poly_eq[0];
+ }
+ else
+ {
+ Assert(false) << "Invalid polynomial equation.";
+ }
+
+ Maybe<Rational> lower = get_lower_bound(n[0]);
+ if (!lower) lower = get_lower_bound(n[1]);
+ if (!lower) lower = get_lower_bound(n[2]);
+ Assert(lower) << "Could not identify lower bound.";
+
+ Maybe<Rational> upper = get_upper_bound(n[0]);
+ if (!upper) upper = get_upper_bound(n[1]);
+ if (!upper) upper = get_upper_bound(n[2]);
+ Assert(upper) << "Could not identify upper bound.";
+
+ return std::tuple<Node, Rational, Rational>(
+ poly, lower.value(), upper.value());
+}
+
+poly::AlgebraicNumber node_to_poly_ran(const Node& n, const Node& ran_variable)
+{
+ // Identify poly, lower and upper
+ auto encoding = detect_ran_encoding(n);
+ // Construct polynomial
+ poly::UPolynomial pol =
+ as_poly_upolynomial(std::get<0>(encoding), ran_variable);
+ // Construct algebraic number
+ return poly_utils::toPolyRanWithRefinement(
+ std::move(pol), std::get<1>(encoding), std::get<2>(encoding));
+}
+RealAlgebraicNumber node_to_ran(const Node& n, const Node& ran_variable)
+{
+ return RealAlgebraicNumber(node_to_poly_ran(n, ran_variable));
+}
+
+poly::Value node_to_value(const Node& n, const Node& ran_variable)
+{
+ if (n.isConst())
+ {
+ return poly_utils::toRational(n.getConst<Rational>());
+ }
+ return node_to_poly_ran(n, ran_variable);
+}
+
+/** Bitsize of a dyadic rational. */
+std::size_t bitsize(const poly::DyadicRational& v)
+{
+ return bit_size(numerator(v)) + bit_size(denominator(v));
+}
+/** Bitsize of an integer. */
+std::size_t bitsize(const poly::Integer& v) { return bit_size(v); }
+/** Bitsize of a rational. */
+std::size_t bitsize(const poly::Rational& v)
+{
+ return bit_size(numerator(v)) + bit_size(denominator(v));
+}
+/** Bitsize of a univariate polynomial. */
+std::size_t bitsize(const poly::UPolynomial& v)
+{
+ std::size_t sum = 0;
+ for (const auto& c : coefficients(v))
+ {
+ sum += bitsize(c);
+ }
+ return sum;
+}
+/** Bitsize of an algebraic number. */
+std::size_t bitsize(const poly::AlgebraicNumber& v)
+{
+ if (is_rational(v))
+ {
+ return bitsize(to_rational_approximation(v));
+ }
+ return bitsize(get_lower_bound(v)) + bitsize(get_upper_bound(v))
+ + bitsize(get_defining_polynomial(v));
+}
+
+std::size_t bitsize(const poly::Value& v)
+{
+ if (is_algebraic_number(v))
+ {
+ return bitsize(as_algebraic_number(v));
+ }
+ else if (is_dyadic_rational(v))
+ {
+ return bitsize(as_dyadic_rational(v));
+ }
+ else if (is_integer(v))
+ {
+ return bitsize(as_integer(v));
+ }
+ else if (is_minus_infinity(v))
+ {
+ return 1;
+ }
+ else if (is_none(v))
+ {
+ return 0;
+ }
+ else if (is_plus_infinity(v))
+ {
+ return 1;
+ }
+ else if (is_rational(v))
+ {
+ return bitsize(as_rational(v));
+ }
+ Assert(false);
+ return 0;
+}
+
+poly::IntervalAssignment getBounds(VariableMapper& vm, const BoundInference& bi)
+{
+ poly::IntervalAssignment res;
+ for (const auto& vb : bi.get())
+ {
+ poly::Variable v = vm(vb.first);
+ poly::Value l = vb.second.lower_value.isNull()
+ ? poly::Value::minus_infty()
+ : node_to_value(vb.second.lower_value, vb.first);
+ poly::Value u = vb.second.upper_value.isNull()
+ ? poly::Value::plus_infty()
+ : node_to_value(vb.second.upper_value, vb.first);
+ poly::Interval i(l, vb.second.lower_strict, u, vb.second.upper_strict);
+ res.set(v, i);
+ }
+ return res;
+}
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arith/nl/poly_conversion.h b/src/theory/arith/nl/poly_conversion.h
new file mode 100644
index 000000000..37d816179
--- /dev/null
+++ b/src/theory/arith/nl/poly_conversion.h
@@ -0,0 +1,167 @@
+/********************* */
+/*! \file poly_conversion.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utilities for converting to and from LibPoly objects.
+ **
+ ** Utilities for converting to and from LibPoly objects.
+ **/
+
+#ifndef CVC4__THEORY__ARITH__NL__POLY_CONVERSION_H
+#define CVC4__THEORY__ARITH__NL__POLY_CONVERSION_H
+
+#include "util/real_algebraic_number.h"
+
+#ifdef CVC4_POLY_IMP
+
+#include <poly/polyxx.h>
+
+#include <iostream>
+
+#include "expr/node.h"
+#include "theory/arith/bound_inference.h"
+#include "util/real_algebraic_number.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+/** Bijective mapping between CVC4 variables and poly variables. */
+struct VariableMapper
+{
+ /** A mapping from CVC4 variables to poly variables. */
+ std::map<CVC4::Node, poly::Variable> mVarCVCpoly;
+ /** A mapping from poly variables to CVC4 variables. */
+ std::map<poly::Variable, CVC4::Node> mVarpolyCVC;
+
+ /** Retrieves the according poly variable. */
+ poly::Variable operator()(const CVC4::Node& n);
+ /** Retrieves the according CVC4 variable. */
+ CVC4::Node operator()(const poly::Variable& n);
+};
+
+/** Convert a poly univariate polynomial to a CVC4::Node. */
+CVC4::Node as_cvc_upolynomial(const poly::UPolynomial& p,
+ const CVC4::Node& var);
+
+/** Convert a CVC4::Node to a poly univariate polynomial. */
+poly::UPolynomial as_poly_upolynomial(const CVC4::Node& n,
+ const CVC4::Node& var);
+
+/**
+ * Constructs a polynomial from the given node.
+ *
+ * While a Node may contain rationals, a Polynomial does not.
+ * We therefore also store the denominator of the returned polynomial and
+ * use it to construct the integer polynomial recursively.
+ * Once the polynomial has been fully constructed, we can oftentimes ignore the
+ * denominator (except for its sign, which is always positive, though).
+ * This is the case if we are solely interested in the roots of the polynomials
+ * (like in the context of CAD). If we need the actual polynomial (for example
+ * in the context of ICP) the second overload provides the denominator in the
+ * third argument.
+ */
+poly::Polynomial as_poly_polynomial(const CVC4::Node& n, VariableMapper& vm);
+poly::Polynomial as_poly_polynomial(const CVC4::Node& n,
+ VariableMapper& vm,
+ poly::Rational& denominator);
+
+/**
+ * Constructs a node from the given polynomial.
+ *
+ * This methods does the straight-forward conversion from a polynomial into Node
+ * representation, using the given variable mapper.
+ * The resulting node is not minimized in any form (it may contain spurious
+ * multiplications with one or use NONLINEAR_MULT where regular MULT may be
+ * sufficient), so it may be sensible to rewrite it afterwards.
+ */
+CVC4::Node as_cvc_polynomial(const poly::Polynomial& p, VariableMapper& vm);
+
+/**
+ * Constructs a constraints (a polynomial and a sign condition) from the given
+ * node.
+ */
+std::pair<poly::Polynomial, poly::SignCondition> as_poly_constraint(
+ Node n, VariableMapper& vm);
+
+/**
+ * Transforms a real algebraic number to a node suitable for putting it into a
+ * model. The resulting node can be either a constant (suitable for
+ * addCheckModelSubstitution) or a witness term (suitable for
+ * addCheckModelWitness).
+ */
+Node ran_to_node(const RealAlgebraicNumber& ran, const Node& ran_variable);
+
+Node ran_to_node(const poly::AlgebraicNumber& an, const Node& ran_variable);
+
+/**
+ * Transforms a poly::Value to a node.
+ * The resulting node can be either a constant or a witness term.
+ */
+Node value_to_node(const poly::Value& v, const Node& ran_variable);
+
+/**
+ * Constructs a lemma that excludes a given interval from the feasible values of
+ * a variable. Conceptually, the resulting lemma has the form
+ * (OR
+ * (<= var interval.lower)
+ * (<= interval.upper var)
+ * )
+ * This method honors the interval bound types (open or closed), but also deals
+ * with real algebraic endpoints. If allowNonlinearLemma is false, real
+ * algebraic endpoints are reflected by coarse (numeric) approximations and thus
+ * may lead to lemmas that are weaker than they could be. Also, lemma creation
+ * may fail altogether.
+ * If allowNonlinearLemma is true, it tries to construct better lemmas (based on
+ * the sign of the defining polynomial of the real algebraic number). These
+ * lemmas are nonlinear, though, and may thus be expensive to use in the
+ * subsequent solving process.
+ */
+Node excluding_interval_to_lemma(const Node& variable,
+ const poly::Interval& interval,
+ bool allowNonlinearLemma);
+
+/**
+ * Transforms a node to a poly::AlgebraicNumber.
+ * Expects a node of the following form:
+ * (AND
+ * (= (polynomial in __z) 0)
+ * (< CONST __z)
+ * (< __z CONST)
+ * )
+ */
+poly::AlgebraicNumber node_to_poly_ran(const Node& n, const Node& ran_variable);
+
+/** Transforms a node to a RealAlgebraicNumber by calling node_to_poly_ran. */
+RealAlgebraicNumber node_to_ran(const Node& n, const Node& ran_variable);
+
+/**
+ * Transforms a node to a poly::Value.
+ */
+poly::Value node_to_value(const Node& n, const Node& ran_variable);
+
+/**
+ * Give a rough estimate of the bitsize of the representation of `v`.
+ * It can be used as a rough measure of the size of complexity of a value, for
+ * example to avoid divergence or disallow huge lemmas.
+ */
+std::size_t bitsize(const poly::Value& v);
+
+poly::IntervalAssignment getBounds(VariableMapper& vm, const BoundInference& bi);
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif
+
+#endif
diff --git a/src/theory/arith/nl/stats.cpp b/src/theory/arith/nl/stats.cpp
index e189d13a8..eb5804e6b 100644
--- a/src/theory/arith/nl/stats.cpp
+++ b/src/theory/arith/nl/stats.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/nl/stats.h b/src/theory/arith/nl/stats.h
index 1a8a9419e..6e78b7dd2 100644
--- a/src/theory/arith/nl/stats.h
+++ b/src/theory/arith/nl/stats.h
@@ -2,10 +2,10 @@
/*! \file stats.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds
+ ** Andrew Reynolds, Gereon Kremer
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,7 +18,7 @@
#define CVC4__THEORY__ARITH__NL__STATS_H
#include "expr/kind.h"
-#include "theory/arith/nl/inference.h"
+#include "theory/arith/inference_id.h"
#include "util/statistics_registry.h"
namespace CVC4 {
@@ -42,7 +42,7 @@ class NlStats
/** Number of calls to NonlinearExtension::checkLastCall */
IntStat d_checkRuns;
/** Counts the number of applications of each type of inference */
- HistogramStat<Inference> d_inferences;
+ HistogramStat<InferenceId> d_inferences;
};
} // namespace nl
diff --git a/src/theory/arith/nl/strategy.cpp b/src/theory/arith/nl/strategy.cpp
new file mode 100644
index 000000000..627500d68
--- /dev/null
+++ b/src/theory/arith/nl/strategy.cpp
@@ -0,0 +1,176 @@
+/********************* */
+/*! \file strategy.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of non-linear solver
+ **/
+
+#include "theory/arith/nl/strategy.h"
+
+#include <iostream>
+
+#include "base/check.h"
+#include "options/arith_options.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+std::ostream& operator<<(std::ostream& os, InferStep step)
+{
+ switch (step)
+ {
+ case InferStep::BREAK: return os << "BREAK";
+ case InferStep::FLUSH_WAITING_LEMMAS: return os << "FLUSH_WAITING_LEMMAS";
+ case InferStep::CAD_INIT: return os << "CAD_INIT";
+ case InferStep::CAD_FULL: return os << "CAD_FULL";
+ case InferStep::NL_FACTORING: return os << "NL_FACTORING";
+ case InferStep::IAND_INIT: return os << "IAND_INIT";
+ case InferStep::IAND_FULL: return os << "IAND_FULL";
+ case InferStep::IAND_INITIAL: return os << "IAND_INITIAL";
+ case InferStep::ICP: return os << "ICP";
+ case InferStep::NL_INIT: return os << "NL_INIT";
+ case InferStep::NL_MONOMIAL_INFER_BOUNDS:
+ return os << "NL_MONOMIAL_INFER_BOUNDS";
+ case InferStep::NL_MONOMIAL_MAGNITUDE0:
+ return os << "NL_MONOMIAL_MAGNITUDE0";
+ case InferStep::NL_MONOMIAL_MAGNITUDE1:
+ return os << "NL_MONOMIAL_MAGNITUDE1";
+ case InferStep::NL_MONOMIAL_MAGNITUDE2:
+ return os << "NL_MONOMIAL_MAGNITUDE2";
+ case InferStep::NL_MONOMIAL_SIGN: return os << "NL_MONOMIAL_SIGN";
+ case InferStep::NL_RESOLUTION_BOUNDS: return os << "NL_RESOLUTION_BOUNDS";
+ case InferStep::NL_SPLIT_ZERO: return os << "NL_SPLIT_ZERO";
+ case InferStep::NL_TANGENT_PLANES: return os << "NL_TANGENT_PLANES";
+ case InferStep::NL_TANGENT_PLANES_WAITING:
+ return os << "NL_TANGENT_PLANES_WAITING";
+ case InferStep::TRANS_INIT: return os << "TRANS_INIT";
+ case InferStep::TRANS_INITIAL: return os << "TRANS_INITIAL";
+ case InferStep::TRANS_MONOTONIC: return os << "TRANS_MONOTONIC";
+ case InferStep::TRANS_TANGENT_PLANES: return os << "TRANS_TANGENT_PLANES";
+ default: Unreachable(); return os << "UNKNOWN_STEP";
+ }
+}
+
+namespace {
+/** Puts a new InferStep into a StepSequence */
+inline StepSequence& operator<<(StepSequence& steps, InferStep s)
+{
+ steps.emplace_back(s);
+ return steps;
+}
+} // namespace
+
+void Interleaving::add(const StepSequence& ss, std::size_t constant)
+{
+ d_branches.emplace_back(Branch{ss, constant});
+ d_size += constant;
+}
+void Interleaving::resetCounter() { d_counter = 0; }
+
+const StepSequence& Interleaving::get()
+{
+ Assert(!d_branches.empty())
+ << "Can not get next sequence from an empty interleaving.";
+ std::size_t cnt = d_counter;
+ // Increase the counter
+ d_counter = (d_counter + 1) % d_size;
+ for (const auto& branch : d_branches)
+ {
+ if (cnt < branch.d_interleavingConstant)
+ {
+ // This is the current branch
+ return branch.d_steps;
+ }
+ cnt -= branch.d_interleavingConstant;
+ }
+ Assert(false) << "Something went wrong.";
+ return d_branches[0].d_steps;
+}
+bool Interleaving::empty() const { return d_branches.empty(); }
+
+bool StepGenerator::hasNext() const { return d_next < d_steps.size(); }
+InferStep StepGenerator::next() { return d_steps[d_next++]; }
+
+bool Strategy::isStrategyInit() const { return !d_interleaving.empty(); }
+void Strategy::initializeStrategy()
+{
+ StepSequence one;
+ if (options::nlICP())
+ {
+ one << InferStep::ICP << InferStep::BREAK;
+ }
+ if (options::nlExt())
+ {
+ one << InferStep::NL_INIT << InferStep::TRANS_INIT << InferStep::BREAK;
+ if (options::nlExtSplitZero())
+ {
+ one << InferStep::NL_SPLIT_ZERO << InferStep::BREAK;
+ }
+ one << InferStep::TRANS_INITIAL << InferStep::BREAK;
+ }
+ one << InferStep::IAND_INIT;
+ one << InferStep::IAND_INITIAL << InferStep::BREAK;
+ if (options::nlExt())
+ {
+ one << InferStep::NL_MONOMIAL_SIGN << InferStep::BREAK;
+ one << InferStep::TRANS_MONOTONIC << InferStep::BREAK;
+ one << InferStep::NL_MONOMIAL_MAGNITUDE0 << InferStep::BREAK;
+ one << InferStep::NL_MONOMIAL_MAGNITUDE1 << InferStep::BREAK;
+ one << InferStep::NL_MONOMIAL_MAGNITUDE2 << InferStep::BREAK;
+ one << InferStep::NL_MONOMIAL_INFER_BOUNDS;
+ if (options::nlExtTangentPlanes()
+ && options::nlExtTangentPlanesInterleave())
+ {
+ one << InferStep::NL_TANGENT_PLANES;
+ }
+ one << InferStep::BREAK;
+ one << InferStep::FLUSH_WAITING_LEMMAS << InferStep::BREAK;
+ if (options::nlExtFactor())
+ {
+ one << InferStep::NL_FACTORING << InferStep::BREAK;
+ }
+ if (options::nlExtResBound())
+ {
+ one << InferStep::NL_MONOMIAL_INFER_BOUNDS << InferStep::BREAK;
+ }
+ if (options::nlExtTangentPlanes()
+ && !options::nlExtTangentPlanesInterleave())
+ {
+ one << InferStep::NL_TANGENT_PLANES_WAITING;
+ }
+ if (options::nlExtTfTangentPlanes())
+ {
+ one << InferStep::TRANS_TANGENT_PLANES;
+ }
+ one << InferStep::BREAK;
+ }
+ one << InferStep::IAND_FULL << InferStep::BREAK;
+ if (options::nlCad())
+ {
+ one << InferStep::CAD_INIT;
+ }
+ if (options::nlCad())
+ {
+ one << InferStep::CAD_FULL << InferStep::BREAK;
+ }
+
+ d_interleaving.add(one);
+}
+StepGenerator Strategy::getStrategy()
+{
+ return StepGenerator(d_interleaving.get());
+}
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/nl/strategy.h b/src/theory/arith/nl/strategy.h
new file mode 100644
index 000000000..ad96d9442
--- /dev/null
+++ b/src/theory/arith/nl/strategy.h
@@ -0,0 +1,179 @@
+/********************* */
+/*! \file strategy.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Strategies for the nonlinear extension
+ **/
+
+#ifndef CVC4__THEORY__ARITH__NL__STRATEGY_H
+#define CVC4__THEORY__ARITH__NL__STRATEGY_H
+
+#include <iosfwd>
+#include <map>
+#include <vector>
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+namespace nl {
+
+/** The possible inference steps for the nonlinear extension */
+enum class InferStep
+{
+ /** Break if any lemma is pending */
+ BREAK,
+ /** Flush waiting lemmas to be pending */
+ FLUSH_WAITING_LEMMAS,
+
+ /** Initialize the CAD solver */
+ CAD_INIT,
+ /** A full CAD check */
+ CAD_FULL,
+
+ /** Initialize the IAND solver */
+ IAND_INIT,
+ /** A full IAND check */
+ IAND_FULL,
+ /** An initial IAND check */
+ IAND_INITIAL,
+
+ /** An ICP check */
+ ICP,
+
+ /** Initialize the NL solver */
+ NL_INIT,
+ /** Nl factoring lemmas */
+ NL_FACTORING,
+ /** Nl lemmas for monomial bound inference */
+ NL_MONOMIAL_INFER_BOUNDS,
+ /** Nl lemmas for monomial magnitudes (class 0) */
+ NL_MONOMIAL_MAGNITUDE0,
+ /** Nl lemmas for monomial magnitudes (class 1) */
+ NL_MONOMIAL_MAGNITUDE1,
+ /** Nl lemmas for monomial magnitudes (class 2) */
+ NL_MONOMIAL_MAGNITUDE2,
+ /** Nl lemmas for monomial signs */
+ NL_MONOMIAL_SIGN,
+ /** Nl lemmas for resolution bounds */
+ NL_RESOLUTION_BOUNDS,
+ /** Nl splitting at zero */
+ NL_SPLIT_ZERO,
+ /** Nl tangent plane lemmas */
+ NL_TANGENT_PLANES,
+ /** Nl tangent plane lemmas as waiting lemmas */
+ NL_TANGENT_PLANES_WAITING,
+
+ /** Initialize the transcendental solver */
+ TRANS_INIT,
+ /** Initial transcendental lemmas */
+ TRANS_INITIAL,
+ /** Monotonicity lemmas from transcendental solver */
+ TRANS_MONOTONIC,
+ /** Tangent planes from transcendental solver */
+ TRANS_TANGENT_PLANES,
+};
+
+/** Streaming operator for InferStep */
+std::ostream& operator<<(std::ostream& os, InferStep step);
+
+/** A sequence of steps */
+using StepSequence = std::vector<InferStep>;
+
+/**
+ * Stores an interleaving of multiple StepSequences.
+ *
+ * Every Branch of the interleaving holds a StepSequence s_i and a constant c_i.
+ * Once initialized, the interleaving may be asked repeatedly for a
+ * StepSequence. Repeated calls cycle through the branches, but will return
+ * every branch repeatedly as specified by its constant.
+ *
+ * Let for example [(s_1, 1), (s_2, 2), (s_3, 1)], then the sequence returned by
+ * get() would be: s_1, s_2, s_2, s_3, s_1, s_2, s_2, s_3, ...
+ */
+class Interleaving
+{
+ public:
+ /** Add a new branch to this interleaving */
+ void add(const StepSequence& ss, std::size_t constant = 1);
+ /**
+ * Reset the counter to start from the first branch for the next get() call
+ */
+ void resetCounter();
+ /** Retrieve the next branch */
+ const StepSequence& get();
+ /** Check whether this interleaving is empty */
+ bool empty() const;
+
+ private:
+ /** Represents a single branch in an interleaving */
+ struct Branch
+ {
+ StepSequence d_steps;
+ std::size_t d_interleavingConstant;
+ };
+ /** The current counter of get() calls */
+ std::size_t d_counter = 0;
+ /** The overall size of interleaving (considering constants) */
+ std::size_t d_size = 0;
+ /** The branches */
+ std::vector<Branch> d_branches;
+};
+
+/**
+ * A small wrapper around a StepSequence.
+ *
+ * This class makes handling a StepSequence slightly more convenient.
+ * Also, it may help wrapping a more flexible strategy implementation in the
+ * future.
+ */
+class StepGenerator
+{
+ public:
+ StepGenerator(const StepSequence& ss) : d_steps(ss) {}
+ /** Check if there is another step */
+ bool hasNext() const;
+ /** Get the next step */
+ InferStep next();
+
+ private:
+ /** The StepSequence to process */
+ const StepSequence& d_steps;
+ /** The next step */
+ std::size_t d_next = 0;
+};
+
+/**
+ * A strategy for the nonlinear extension
+ *
+ * A strategy consists of multiple step sequences that are interleaved for every
+ * Theory::Effort. The initialization creates the strategy. Calling
+ * getStrategy() yields a StepGenerator that produces a sequence of InferSteps.
+ */
+class Strategy
+{
+ public:
+ /** Is this strategy initialized? */
+ bool isStrategyInit() const;
+ /** Initialize this strategy */
+ void initializeStrategy();
+ /** Retrieve the strategy for the given effort e */
+ StepGenerator getStrategy();
+
+ private:
+ /** The interleaving for this strategy */
+ Interleaving d_interleaving;
+};
+
+} // namespace nl
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__ARITH__NL__STRATEGY_H */
diff --git a/src/theory/arith/nl/transcendental_solver.cpp b/src/theory/arith/nl/transcendental_solver.cpp
index 321818b94..2e25f1642 100644
--- a/src/theory/arith/nl/transcendental_solver.cpp
+++ b/src/theory/arith/nl/transcendental_solver.cpp
@@ -2,10 +2,10 @@
/*! \file transcendental_solver.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Tim King, Mathias Preiner
+ ** Andrew Reynolds, Tim King, Gereon Kremer
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -31,7 +31,7 @@ namespace theory {
namespace arith {
namespace nl {
-TranscendentalSolver::TranscendentalSolver(NlModel& m) : d_model(m)
+TranscendentalSolver::TranscendentalSolver(InferenceManager& im, NlModel& m) : d_im(im), d_model(m)
{
NodeManager* nm = NodeManager::currentNM();
d_true = nm->mkConst(true);
@@ -49,8 +49,7 @@ TranscendentalSolver::~TranscendentalSolver() {}
void TranscendentalSolver::initLastCall(const std::vector<Node>& assertions,
const std::vector<Node>& false_asserts,
- const std::vector<Node>& xts,
- std::vector<NlLemma>& lems)
+ const std::vector<Node>& xts)
{
d_funcCongClass.clear();
d_funcMap.clear();
@@ -136,7 +135,7 @@ void TranscendentalSolver::initLastCall(const std::vector<Node>& assertions,
}
Node expn = exp.size() == 1 ? exp[0] : nm->mkNode(AND, exp);
Node cong_lemma = nm->mkNode(OR, expn.negate(), a.eqNode(aa));
- lems.emplace_back(cong_lemma, Inference::CONGRUENCE);
+ d_im.addPendingArithLemma(cong_lemma, InferenceId::NL_CONGRUENCE);
}
}
else
@@ -160,10 +159,10 @@ void TranscendentalSolver::initLastCall(const std::vector<Node>& assertions,
if (needPi && d_pi.isNull())
{
mkPi();
- getCurrentPiBounds(lems);
+ getCurrentPiBounds();
}
- if (!lems.empty())
+ if (d_im.hasUsed())
{
return;
}
@@ -212,9 +211,8 @@ void TranscendentalSolver::initLastCall(const std::vector<Node>& assertions,
// note we must do preprocess on this lemma
Trace("nl-ext-lemma") << "NonlinearExtension::Lemma : purify : " << lem
<< std::endl;
- NlLemma nlem(lem, Inference::T_PURIFY_ARG);
- nlem.d_preprocess = true;
- lems.emplace_back(nlem);
+ NlLemma nlem(lem, LemmaProperty::PREPROCESS, nullptr, InferenceId::NL_T_PURIFY_ARG);
+ d_im.addPendingArithLemma(nlem);
}
if (Trace.isOn("nl-ext-mv"))
@@ -363,19 +361,18 @@ void TranscendentalSolver::mkPi()
}
}
-void TranscendentalSolver::getCurrentPiBounds(std::vector<NlLemma>& lemmas)
+void TranscendentalSolver::getCurrentPiBounds()
{
NodeManager* nm = NodeManager::currentNM();
Node pi_lem = nm->mkNode(AND,
nm->mkNode(GEQ, d_pi, d_pi_bound[0]),
nm->mkNode(LEQ, d_pi, d_pi_bound[1]));
- lemmas.emplace_back(pi_lem, Inference::T_PI_BOUND);
+ d_im.addPendingArithLemma(pi_lem, InferenceId::NL_T_PI_BOUND);
}
-std::vector<NlLemma> TranscendentalSolver::checkTranscendentalInitialRefine()
+void TranscendentalSolver::checkTranscendentalInitialRefine()
{
NodeManager* nm = NodeManager::currentNM();
- std::vector<NlLemma> lemmas;
Trace("nl-ext")
<< "Get initial refinement lemmas for transcendental functions..."
<< std::endl;
@@ -454,18 +451,15 @@ std::vector<NlLemma> TranscendentalSolver::checkTranscendentalInitialRefine()
}
if (!lem.isNull())
{
- lemmas.emplace_back(lem, Inference::T_INIT_REFINE);
+ d_im.addPendingArithLemma(lem, InferenceId::NL_T_INIT_REFINE);
}
}
}
}
-
- return lemmas;
}
-std::vector<NlLemma> TranscendentalSolver::checkTranscendentalMonotonic()
+void TranscendentalSolver::checkTranscendentalMonotonic()
{
- std::vector<NlLemma> lemmas;
Trace("nl-ext") << "Get monotonicity lemmas for transcendental functions..."
<< std::endl;
@@ -630,7 +624,8 @@ std::vector<NlLemma> TranscendentalSolver::checkTranscendentalMonotonic()
}
Trace("nl-ext-tf-mono")
<< "Monotonicity lemma : " << mono_lem << std::endl;
- lemmas.emplace_back(mono_lem, Inference::T_MONOTONICITY);
+
+ d_im.addPendingArithLemma(mono_lem, InferenceId::NL_T_MONOTONICITY);
}
}
// store the previous values
@@ -642,12 +637,10 @@ std::vector<NlLemma> TranscendentalSolver::checkTranscendentalMonotonic()
}
}
}
- return lemmas;
}
-std::vector<NlLemma> TranscendentalSolver::checkTranscendentalTangentPlanes()
+void TranscendentalSolver::checkTranscendentalTangentPlanes()
{
- std::vector<NlLemma> lemmas;
Trace("nl-ext") << "Get tangent plane lemmas for transcendental functions..."
<< std::endl;
// this implements Figure 3 of "Satisfiaility Modulo Transcendental Functions
@@ -682,11 +675,13 @@ std::vector<NlLemma> TranscendentalSolver::checkTranscendentalTangentPlanes()
for (unsigned d = 1; d <= d_taylor_degree; d++)
{
Trace("nl-ext-tftp") << "- run at degree " << d << "..." << std::endl;
- unsigned prev = lemmas.size();
- if (checkTfTangentPlanesFun(tf, d, lemmas))
+ unsigned prev = d_im.numPendingLemmas() + d_im.numWaitingLemmas();
+ if (checkTfTangentPlanesFun(tf, d))
{
Trace("nl-ext-tftp")
- << "...fail, #lemmas = " << (lemmas.size() - prev) << std::endl;
+ << "...fail, #lemmas = "
+ << (d_im.numPendingLemmas() + d_im.numWaitingLemmas() - prev)
+ << std::endl;
break;
}
else
@@ -696,13 +691,10 @@ std::vector<NlLemma> TranscendentalSolver::checkTranscendentalTangentPlanes()
}
}
}
-
- return lemmas;
}
bool TranscendentalSolver::checkTfTangentPlanesFun(Node tf,
- unsigned d,
- std::vector<NlLemma>& lemmas)
+ unsigned d)
{
NodeManager* nm = NodeManager::currentNM();
Kind k = tf.getKind();
@@ -883,7 +875,7 @@ bool TranscendentalSolver::checkTfTangentPlanesFun(Node tf,
<< "*** Tangent plane lemma : " << lem << std::endl;
Assert(d_model.computeAbstractModelValue(lem) == d_false);
// Figure 3 : line 9
- lemmas.emplace_back(lem, Inference::T_TANGENT);
+ d_im.addPendingArithLemma(lem, InferenceId::NL_T_TANGENT, nullptr, true);
}
else if (is_secant)
{
@@ -1017,11 +1009,11 @@ bool TranscendentalSolver::checkTfTangentPlanesFun(Node tf,
Assert(!lemmaConj.empty());
Node lem =
lemmaConj.size() == 1 ? lemmaConj[0] : nm->mkNode(AND, lemmaConj);
- NlLemma nlem(lem, Inference::T_SECANT);
+ NlLemma nlem(lem, LemmaProperty::NONE, nullptr, InferenceId::NL_T_SECANT);
// The side effect says that if lem is added, then we should add the
// secant point c for (tf,d).
nlem.d_secantPoint.push_back(std::make_tuple(tf, d, c));
- lemmas.emplace_back(nlem);
+ d_im.addPendingArithLemma(nlem, true);
}
return true;
}
diff --git a/src/theory/arith/nl/transcendental_solver.h b/src/theory/arith/nl/transcendental_solver.h
index c80fa99e6..004221be2 100644
--- a/src/theory/arith/nl/transcendental_solver.h
+++ b/src/theory/arith/nl/transcendental_solver.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,7 +21,7 @@
#include <vector>
#include "expr/node.h"
-#include "theory/arith/nl/nl_lemma_utils.h"
+#include "theory/arith/inference_manager.h"
#include "theory/arith/nl/nl_model.h"
namespace CVC4 {
@@ -44,7 +44,7 @@ namespace nl {
class TranscendentalSolver
{
public:
- TranscendentalSolver(NlModel& m);
+ TranscendentalSolver(InferenceManager& im, NlModel& m);
~TranscendentalSolver();
/** init last call
@@ -60,8 +60,7 @@ class TranscendentalSolver
*/
void initLastCall(const std::vector<Node>& assertions,
const std::vector<Node>& false_asserts,
- const std::vector<Node>& xts,
- std::vector<NlLemma>& lems);
+ const std::vector<Node>& xts);
/** increment taylor degree */
void incrementTaylorDegree();
/** get taylor degree */
@@ -80,7 +79,7 @@ class TranscendentalSolver
//-------------------------------------------- lemma schemas
/** check transcendental initial refine
*
- * Returns a set of valid theory lemmas, based on
+ * Constructs a set of valid theory lemmas, based on
* simple facts about transcendental functions.
* This mostly follows the initial axioms described in
* Section 4 of "Satisfiability
@@ -94,11 +93,11 @@ class TranscendentalSolver
* exp( x )>0
* x<0 => exp( x )<1
*/
- std::vector<NlLemma> checkTranscendentalInitialRefine();
+ void checkTranscendentalInitialRefine();
/** check transcendental monotonic
*
- * Returns a set of valid theory lemmas, based on a
+ * Constructs a set of valid theory lemmas, based on a
* lemma scheme that ensures that applications
* of transcendental functions respect monotonicity.
*
@@ -108,11 +107,11 @@ class TranscendentalSolver
* PI/2 > x > y > 0 => sin( x ) > sin( y )
* PI > x > y > PI/2 => sin( x ) < sin( y )
*/
- std::vector<NlLemma> checkTranscendentalMonotonic();
+ void checkTranscendentalMonotonic();
/** check transcendental tangent planes
*
- * Returns a set of valid theory lemmas, based on
+ * Constructs a set of valid theory lemmas, based on
* computing an "incremental linearization" of
* transcendental functions based on the model values
* of transcendental functions and their arguments.
@@ -168,7 +167,8 @@ class TranscendentalSolver
* where c1, c2 are rationals (for brevity, omitted here)
* such that c1 ~= .277 and c2 ~= 2.032.
*/
- std::vector<NlLemma> checkTranscendentalTangentPlanes();
+ void checkTranscendentalTangentPlanes();
+ private:
/** check transcendental function refinement for tf
*
* This method is called by the above method for each "master"
@@ -186,9 +186,8 @@ class TranscendentalSolver
* It returns false if the bounds are not precise enough to add a
* secant or tangent plane lemma.
*/
- bool checkTfTangentPlanesFun(Node tf, unsigned d, std::vector<NlLemma>& lems);
+ bool checkTfTangentPlanesFun(Node tf, unsigned d);
//-------------------------------------------- end lemma schemas
- private:
/** polynomial approximation bounds
*
* This adds P_l+[x], P_l-[x], P_u+[x], P_u-[x] to pbounds, where x is
@@ -268,10 +267,12 @@ class TranscendentalSolver
Node getDerivative(Node n, Node x);
void mkPi();
- void getCurrentPiBounds(std::vector<NlLemma>& lemmas);
+ void getCurrentPiBounds();
/** Make the node -pi <= a <= pi */
static Node mkValidPhase(Node a, Node pi);
+ /** The inference manager that we push conflicts and lemmas to. */
+ InferenceManager& d_im;
/** Reference to the non-linear model object */
NlModel& d_model;
/** commonly used terms */
diff --git a/src/theory/arith/normal_form.cpp b/src/theory/arith/normal_form.cpp
index f964f1628..fc9a86f49 100644
--- a/src/theory/arith/normal_form.cpp
+++ b/src/theory/arith/normal_form.cpp
@@ -5,7 +5,7 @@
** Tim King, Andrew Reynolds, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -816,6 +816,64 @@ DeltaRational Comparison::normalizedDeltaRational() const {
}
}
+std::tuple<Polynomial, Kind, Constant> Comparison::decompose(
+ bool split_constant) const
+{
+ Kind rel = getNode().getKind();
+ if (rel == Kind::NOT)
+ {
+ switch (getNode()[0].getKind())
+ {
+ case kind::LEQ: rel = Kind::GT; break;
+ case kind::LT: rel = Kind::GEQ; break;
+ case kind::EQUAL: rel = Kind::DISTINCT; break;
+ case kind::DISTINCT: rel = Kind::EQUAL; break;
+ case kind::GEQ: rel = Kind::LT; break;
+ case kind::GT: rel = Kind::LEQ; break;
+ default:
+ Assert(false) << "Unsupported relation: " << getNode()[0].getKind();
+ }
+ }
+
+ Polynomial poly = getLeft() - getRight();
+
+ if (!split_constant)
+ {
+ return std::tuple<Polynomial, Kind, Constant>{
+ poly, rel, Constant::mkZero()};
+ }
+
+ Constant right = Constant::mkZero();
+ if (poly.containsConstant())
+ {
+ right = -poly.getHead().getConstant();
+ poly = poly + Polynomial::mkPolynomial(right);
+ }
+
+ Constant lcoeff = poly.getHead().getConstant();
+ if (!lcoeff.isOne())
+ {
+ Constant invlcoeff = lcoeff.inverse();
+ if (lcoeff.isNegative())
+ {
+ switch (rel)
+ {
+ case kind::LEQ: rel = Kind::GEQ; break;
+ case kind::LT: rel = Kind::GT; break;
+ case kind::EQUAL: break;
+ case kind::DISTINCT: break;
+ case kind::GEQ: rel = Kind::LEQ; break;
+ case kind::GT: rel = Kind::LT; break;
+ default: Assert(false) << "Unsupported relation: " << rel;
+ }
+ }
+ poly = poly * invlcoeff;
+ right = right * invlcoeff;
+ }
+
+ return std::tuple<Polynomial, Kind, Constant>{poly, rel, right};
+}
+
Comparison Comparison::parseNormalForm(TNode n) {
Debug("polynomial") << "Comparison::parseNormalForm(" << n << ")";
Comparison result(n);
diff --git a/src/theory/arith/normal_form.h b/src/theory/arith/normal_form.h
index 484bdbf44..79cae2fff 100644
--- a/src/theory/arith/normal_form.h
+++ b/src/theory/arith/normal_form.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -946,6 +946,18 @@ public:
/** Returns true if the polynomial contains a non-linear monomial.*/
bool isNonlinear() const;
+ /** Check whether this polynomial is only a single variable. */
+ bool isVariable() const
+ {
+ return singleton() && getHead().getVarList().singleton()
+ && getHead().coefficientIsOne();
+ }
+ /** Return the variable, given that isVariable() holds. */
+ Variable getVariable() const
+ {
+ Assert(isVariable());
+ return getHead().getVarList().getHead();
+ }
/**
* Selects a minimal monomial in the polynomial by the absolute value of
@@ -1377,6 +1389,19 @@ public:
Polynomial normalizedVariablePart() const;
DeltaRational normalizedDeltaRational() const;
+ /**
+ * Transforms a Comparison object into a stronger normal form:
+ * Polynomial ~Kind~ Constant
+ *
+ * From the comparison, this method resolved a negation (if present) and
+ * moves everything to the left side.
+ * If split_constant is false, the constant is always zero.
+ * If split_constant is true, the polynomial has no constant term and is
+ * normalized to have leading coefficient one.
+ */
+ std::tuple<Polynomial, Kind, Constant> decompose(
+ bool split_constant = false) const;
+
};/* class Comparison */
}/* CVC4::theory::arith namespace */
diff --git a/src/theory/arith/operator_elim.cpp b/src/theory/arith/operator_elim.cpp
index 593fbd584..4d4c4a6f5 100644
--- a/src/theory/arith/operator_elim.cpp
+++ b/src/theory/arith/operator_elim.cpp
@@ -2,10 +2,10 @@
/*! \file operator_elim.cpp
** \verbatim
** Top contributors (to current version):
- ** Tim King, Andrew Reynolds, Morgan Deters
+ ** Andrew Reynolds, Andres Noetzli, Morgan Deters
** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -27,7 +27,10 @@ namespace CVC4 {
namespace theory {
namespace arith {
-OperatorElim::OperatorElim(const LogicInfo& info) : d_info(info) {}
+OperatorElim::OperatorElim(ProofNodeManager* pnm, const LogicInfo& info)
+ : EagerProofGenerator(pnm), d_info(info)
+{
+}
void OperatorElim::checkNonLinearLogic(Node term)
{
@@ -43,7 +46,21 @@ void OperatorElim::checkNonLinearLogic(Node term)
}
}
-Node OperatorElim::eliminateOperatorsRec(Node n)
+TrustNode OperatorElim::eliminate(Node n)
+{
+ TConvProofGenerator* tg = nullptr;
+ Node nn = eliminateOperators(n, tg);
+ if (nn != n)
+ {
+ // since elimination may introduce new operators to eliminate, we must
+ // recursively eliminate result
+ Node nnr = eliminateOperatorsRec(nn, tg);
+ return TrustNode::mkTrustRewrite(n, nnr, nullptr);
+ }
+ return TrustNode::null();
+}
+
+Node OperatorElim::eliminateOperatorsRec(Node n, TConvProofGenerator* tg)
{
Trace("arith-elim") << "Begin elim: " << n << std::endl;
NodeManager* nm = NodeManager::currentNM();
@@ -91,12 +108,12 @@ Node OperatorElim::eliminateOperatorsRec(Node n)
{
ret = nm->mkNode(cur.getKind(), children);
}
- Node retElim = eliminateOperators(ret);
+ Node retElim = eliminateOperators(ret, tg);
if (retElim != ret)
{
// recursively eliminate operators in result, since some eliminations
// are defined in terms of other non-standard operators.
- ret = eliminateOperatorsRec(retElim);
+ ret = eliminateOperatorsRec(retElim, tg);
}
visited[cur] = ret;
}
@@ -106,7 +123,7 @@ Node OperatorElim::eliminateOperatorsRec(Node n)
return visited[n];
}
-Node OperatorElim::eliminateOperators(Node node)
+Node OperatorElim::eliminateOperators(Node node, TConvProofGenerator* tg)
{
NodeManager* nm = NodeManager::currentNM();
SkolemManager* sm = nm->getSkolemManager();
@@ -138,9 +155,14 @@ Node OperatorElim::eliminateOperators(Node node)
Node zero = mkRationalNode(0);
Node diff = nm->mkNode(MINUS, node[0], v);
Node lem = mkInRange(diff, zero, one);
- toIntSkolem = sm->mkSkolem(
- v, lem, "toInt", "a conversion of a Real term to its Integer part");
- toIntSkolem = SkolemManager::getWitnessForm(toIntSkolem);
+ toIntSkolem =
+ sm->mkSkolem(v,
+ lem,
+ "toInt",
+ "a conversion of a Real term to its Integer part",
+ NodeManager::SKOLEM_DEFAULT,
+ this,
+ true);
d_to_int_skolem[node[0]] = toIntSkolem;
}
else
@@ -235,9 +257,13 @@ Node OperatorElim::eliminateOperators(Node node)
nm->mkNode(
PLUS, v, nm->mkConst(Rational(-1))))))));
}
- intVar = sm->mkSkolem(
- v, lem, "linearIntDiv", "the result of an intdiv-by-k term");
- intVar = SkolemManager::getWitnessForm(intVar);
+ intVar = sm->mkSkolem(v,
+ lem,
+ "linearIntDiv",
+ "the result of an intdiv-by-k term",
+ NodeManager::SKOLEM_DEFAULT,
+ this,
+ true);
d_int_div_skolem[rw] = intVar;
}
else
@@ -276,9 +302,13 @@ Node OperatorElim::eliminateOperators(Node node)
Node lem = nm->mkNode(IMPLIES,
den.eqNode(nm->mkConst(Rational(0))).negate(),
nm->mkNode(MULT, den, v).eqNode(num));
- var = sm->mkSkolem(
- v, lem, "nonlinearDiv", "the result of a non-linear div term");
- var = SkolemManager::getWitnessForm(var);
+ var = sm->mkSkolem(v,
+ lem,
+ "nonlinearDiv",
+ "the result of a non-linear div term",
+ NodeManager::SKOLEM_DEFAULT,
+ this,
+ true);
d_div_skolem[rw] = var;
}
else
@@ -424,8 +454,11 @@ Node OperatorElim::eliminateOperators(Node node)
var,
lem,
"tfk",
- "Skolem to eliminate a non-standard transcendental function");
- ret = SkolemManager::getWitnessForm(ret);
+ "Skolem to eliminate a non-standard transcendental function",
+ NodeManager::SKOLEM_DEFAULT,
+ this,
+ true);
+ Assert(ret.getKind() == WITNESS);
d_nlin_inverse_skolem[node] = ret;
return ret;
}
@@ -438,6 +471,8 @@ Node OperatorElim::eliminateOperators(Node node)
return node;
}
+Node OperatorElim::getAxiomFor(Node n) { return Node::null(); }
+
Node OperatorElim::getArithSkolem(ArithSkolemId asi)
{
std::map<ArithSkolemId, Node>::iterator it = d_arith_skolem.find(asi);
diff --git a/src/theory/arith/operator_elim.h b/src/theory/arith/operator_elim.h
index 2cdf9bc49..c7b55caf1 100644
--- a/src/theory/arith/operator_elim.h
+++ b/src/theory/arith/operator_elim.h
@@ -2,10 +2,10 @@
/*! \file operator_elim.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds
+ ** Andrew Reynolds, Andres Noetzli, Martin Brain
** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -17,43 +17,32 @@
#include <map>
#include "expr/node.h"
+#include "expr/term_conversion_proof_generator.h"
+#include "theory/eager_proof_generator.h"
#include "theory/logic_info.h"
namespace CVC4 {
namespace theory {
namespace arith {
-class OperatorElim
+class OperatorElim : public EagerProofGenerator
{
public:
- OperatorElim(const LogicInfo& info);
+ OperatorElim(ProofNodeManager* pnm, const LogicInfo& info);
~OperatorElim() {}
+ /** Eliminate operators in this term.
+ *
+ * Eliminate operators in term n. If n has top symbol that is not a core
+ * one (including division, int division, mod, to_int, is_int, syntactic sugar
+ * transcendental functions), then we replace it by a form that eliminates
+ * that operator. This may involve the introduction of witness terms.
+ */
+ TrustNode eliminate(Node n);
/**
- * Eliminate operators in term n. If n has top symbol that is not a core
- * one (including division, int division, mod, to_int, is_int, syntactic sugar
- * transcendental functions), then we replace it by a form that eliminates
- * that operator. This may involve the introduction of witness terms.
- *
- * One exception to the above rule is that we may leave certain applications
- * like (/ 4 1) unchanged, since replacing this by 4 changes its type from
- * real to int. This is important for some subtyping issues during
- * expandDefinition. Moreover, applications like this can be eliminated
- * trivially later by rewriting.
- *
- * This method is called both during expandDefinition and during ppRewrite.
- *
- * @param n The node to eliminate operators from.
- * @return The (single step) eliminated form of n.
+ * Get axiom for term n. This returns the axiom that this class uses to
+ * eliminate the term n, which is determined by its top-most symbol.
*/
- Node eliminateOperators(Node n);
- /**
- * Recursively ensure that n has no non-standard operators. This applies
- * the above method on all subterms of n.
- *
- * @param n The node to eliminate operators from.
- * @return The eliminated form of n.
- */
- Node eliminateOperatorsRec(Node n);
+ static Node getAxiomFor(Node n);
private:
/** Logic info of the owner of this class */
@@ -95,6 +84,32 @@ class OperatorElim
* function-ness of e.g. division by zero is ignored.
*/
std::map<ArithSkolemId, Node> d_arith_skolem;
+ /**
+ * Eliminate operators in term n. If n has top symbol that is not a core
+ * one (including division, int division, mod, to_int, is_int, syntactic sugar
+ * transcendental functions), then we replace it by a form that eliminates
+ * that operator. This may involve the introduction of witness terms.
+ *
+ * One exception to the above rule is that we may leave certain applications
+ * like (/ 4 1) unchanged, since replacing this by 4 changes its type from
+ * real to int. This is important for some subtyping issues during
+ * expandDefinition. Moreover, applications like this can be eliminated
+ * trivially later by rewriting.
+ *
+ * This method is called both during expandDefinition and during ppRewrite.
+ *
+ * @param n The node to eliminate operators from.
+ * @return The (single step) eliminated form of n.
+ */
+ Node eliminateOperators(Node n, TConvProofGenerator* tg);
+ /**
+ * Recursively ensure that n has no non-standard operators. This applies
+ * the above method on all subterms of n.
+ *
+ * @param n The node to eliminate operators from.
+ * @return The eliminated form of n.
+ */
+ Node eliminateOperatorsRec(Node n, TConvProofGenerator* tg);
/** get arithmetic skolem
*
* Returns the Skolem in the above map for the given id, creating it if it
diff --git a/src/theory/arith/partial_model.cpp b/src/theory/arith/partial_model.cpp
index 9b2c38d81..bf86c7e86 100644
--- a/src/theory/arith/partial_model.cpp
+++ b/src/theory/arith/partial_model.cpp
@@ -5,7 +5,7 @@
** Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/partial_model.h b/src/theory/arith/partial_model.h
index 43c265278..1606be73b 100644
--- a/src/theory/arith/partial_model.h
+++ b/src/theory/arith/partial_model.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/proof_checker.cpp b/src/theory/arith/proof_checker.cpp
index 5b7a3d63a..a28eb02df 100644
--- a/src/theory/arith/proof_checker.cpp
+++ b/src/theory/arith/proof_checker.cpp
@@ -4,8 +4,8 @@
** Top contributors (to current version):
** Alex Ozdemir
** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -33,8 +33,9 @@ void ArithProofRuleChecker::registerTo(ProofChecker* pc)
pc->registerChecker(PfRule::ARITH_TRICHOTOMY, this);
pc->registerChecker(PfRule::INT_TIGHT_UB, this);
pc->registerChecker(PfRule::INT_TIGHT_LB, this);
- pc->registerChecker(PfRule::INT_TRUST, this);
pc->registerChecker(PfRule::ARITH_OP_ELIM_AXIOM, this);
+ // trusted rules
+ pc->registerTrustedChecker(PfRule::INT_TRUST, this, 2);
}
Node ArithProofRuleChecker::checkInternal(PfRule id,
@@ -252,6 +253,20 @@ Node ArithProofRuleChecker::checkInternal(PfRule id,
}
case PfRule::INT_TRUST:
{
+ if (Debug.isOn("arith::pf::check::trust"))
+ {
+ Debug("arith::pf::check::trust") << "Arith PfRule:" << id << std::endl;
+ Debug("arith::pf::check::trust") << " children: " << std::endl;
+ for (const auto& c : children)
+ {
+ Debug("arith::pf::check::trust") << " * " << c << std::endl;
+ }
+ Debug("arith::pf::check::trust") << " args:" << std::endl;
+ for (const auto& c : args)
+ {
+ Debug("arith::pf::check::trust") << " * " << c << std::endl;
+ }
+ }
Assert(args.size() == 1);
return args[0];
}
diff --git a/src/theory/arith/proof_checker.h b/src/theory/arith/proof_checker.h
index b8a5d0df7..720fba34a 100644
--- a/src/theory/arith/proof_checker.h
+++ b/src/theory/arith/proof_checker.h
@@ -4,8 +4,8 @@
** Top contributors (to current version):
** Alex Ozdemir
** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/proof_macros.h b/src/theory/arith/proof_macros.h
new file mode 100644
index 000000000..4760760ef
--- /dev/null
+++ b/src/theory/arith/proof_macros.h
@@ -0,0 +1,34 @@
+/********************* */
+/*! \file proof_macros.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Alex Ozdemir
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Macros which run code when the old or new proof system is enabled,
+ ** or unsat cores are enabled.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__ARITH__PROOF_MACROS_H
+#define CVC4__THEORY__ARITH__PROOF_MACROS_H
+
+#include "options/smt_options.h"
+
+#define ARITH_PROOF(x) \
+ if (CVC4::options::proofNew()) \
+ { \
+ x; \
+ }
+#define ARITH_NULLPROOF(x) \
+ (CVC4::options::proofNew()) \
+ ? x \
+ : NULL
+#define ARITH_PROOF_ON() CVC4::options::proofNew()
+
+#endif // CVC4__THEORY__ARITH__PROOF_MACROS_H
diff --git a/src/theory/arith/rewrites.cpp b/src/theory/arith/rewrites.cpp
new file mode 100644
index 000000000..870d009d2
--- /dev/null
+++ b/src/theory/arith/rewrites.cpp
@@ -0,0 +1,50 @@
+/********************* */
+/*! \file rewrites.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of inference information utility.
+ **/
+
+#include "theory/arith/rewrites.h"
+
+#include <iostream>
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+const char* toString(Rewrite r)
+{
+ switch (r)
+ {
+ case Rewrite::NONE: return "NONE";
+ case Rewrite::CONST_EVAL: return "CONST_EVAL";
+ case Rewrite::MOD_TOTAL_BY_CONST: return "MOD_TOTAL_BY_CONST";
+ case Rewrite::DIV_TOTAL_BY_CONST: return "DIV_TOTAL_BY_CONST";
+ case Rewrite::DIV_MOD_BY_ZERO: return "DIV_MOD_BY_ZERO";
+ case Rewrite::MOD_BY_ONE: return "MOD_BY_ONE";
+ case Rewrite::DIV_BY_ONE: return "DIV_BY_ONE";
+ case Rewrite::DIV_MOD_PULL_NEG_DEN: return "DIV_MOD_PULL_NEG_DEN";
+ case Rewrite::MOD_OVER_MOD: return "MOD_OVER_MOD";
+ case Rewrite::MOD_CHILD_MOD: return "MOD_CHILD_MOD";
+ case Rewrite::DIV_OVER_MOD: return "DIV_OVER_MOD";
+ default: return "?";
+ }
+}
+
+std::ostream& operator<<(std::ostream& out, Rewrite r)
+{
+ out << toString(r);
+ return out;
+}
+
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arith/rewrites.h b/src/theory/arith/rewrites.h
new file mode 100644
index 000000000..48913e8cf
--- /dev/null
+++ b/src/theory/arith/rewrites.h
@@ -0,0 +1,82 @@
+/********************* */
+/*! \file rewrites.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Type for rewrites for arithmetic.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__ARITH__REWRITES_H
+#define CVC4__THEORY__ARITH__REWRITES_H
+
+#include <iosfwd>
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+/**
+ * Types of rewrites used by arithmetic
+ */
+enum class Rewrite : uint32_t
+{
+ NONE,
+ // constant evaluation
+ CONST_EVAL,
+ // (mod x c) replaced by total (mod x c) if c != 0
+ MOD_TOTAL_BY_CONST,
+ // (div x c) replaced by total (div x c) if c != 0
+ DIV_TOTAL_BY_CONST,
+ // Total versions choose arbitrary values for 0 denominator:
+ // (div x 0) ---> 0
+ // (mod x 0) ---> 0
+ DIV_MOD_BY_ZERO,
+ // (mod x 1) --> 0
+ MOD_BY_ONE,
+ // (div x 1) --> x
+ DIV_BY_ONE,
+ // (div x (- c)) ---> (- (div x c))
+ // (mod x (- c)) ---> (mod x c)
+ DIV_MOD_PULL_NEG_DEN,
+ // (mod (mod x c) c) --> (mod x c)
+ MOD_OVER_MOD,
+ // (mod (op ... (mod x c) ...) c) ---> (mod (op ... x ...) c) where
+ // op is one of { NONLINEAR_MULT, MULT, PLUS }.
+ MOD_CHILD_MOD,
+ // (div (mod x c) c) --> 0
+ DIV_OVER_MOD
+};
+
+/**
+ * Converts an rewrite to a string. Note: This function is also used in
+ * `safe_print()`. Changing this functions name or signature will result in
+ * `safe_print()` printing "<unsupported>" instead of the proper strings for
+ * the enum values.
+ *
+ * @param r The rewrite
+ * @return The name of the rewrite
+ */
+const char* toString(Rewrite r);
+
+/**
+ * Writes an rewrite name to a stream.
+ *
+ * @param out The stream to write to
+ * @param r The rewrite to write to the stream
+ * @return The stream
+ */
+std::ostream& operator<<(std::ostream& out, Rewrite r);
+
+} // namespace arith
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__ARITH__REWRITES_H */
diff --git a/src/theory/arith/simplex.cpp b/src/theory/arith/simplex.cpp
index 50248167e..5c1b90663 100644
--- a/src/theory/arith/simplex.cpp
+++ b/src/theory/arith/simplex.cpp
@@ -5,7 +5,7 @@
** Tim King, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/simplex.h b/src/theory/arith/simplex.h
index 6a297113e..6740c8e1c 100644
--- a/src/theory/arith/simplex.h
+++ b/src/theory/arith/simplex.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner, Clark Barrett
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/simplex_update.cpp b/src/theory/arith/simplex_update.cpp
index 613a30a07..a1431a78d 100644
--- a/src/theory/arith/simplex_update.cpp
+++ b/src/theory/arith/simplex_update.cpp
@@ -5,7 +5,7 @@
** Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/simplex_update.h b/src/theory/arith/simplex_update.h
index 7668bb2f0..b6792c265 100644
--- a/src/theory/arith/simplex_update.h
+++ b/src/theory/arith/simplex_update.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/soi_simplex.cpp b/src/theory/arith/soi_simplex.cpp
index 71d5fda8b..ecac3d749 100644
--- a/src/theory/arith/soi_simplex.cpp
+++ b/src/theory/arith/soi_simplex.cpp
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/soi_simplex.h b/src/theory/arith/soi_simplex.h
index 95c19a50a..b6df9b488 100644
--- a/src/theory/arith/soi_simplex.h
+++ b/src/theory/arith/soi_simplex.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -52,8 +52,6 @@
#pragma once
-#include <stdint.h>
-
#include "theory/arith/simplex.h"
#include "util/dense_map.h"
#include "util/statistics_registry.h"
diff --git a/src/theory/arith/tableau.cpp b/src/theory/arith/tableau.cpp
index 4c119ba36..a61ce4529 100644
--- a/src/theory/arith/tableau.cpp
+++ b/src/theory/arith/tableau.cpp
@@ -5,7 +5,7 @@
** Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/tableau.h b/src/theory/arith/tableau.h
index 1affc61d4..f6b7f4704 100644
--- a/src/theory/arith/tableau.h
+++ b/src/theory/arith/tableau.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/tableau_sizes.cpp b/src/theory/arith/tableau_sizes.cpp
index f54c3dfef..e4e6c91d0 100644
--- a/src/theory/arith/tableau_sizes.cpp
+++ b/src/theory/arith/tableau_sizes.cpp
@@ -5,7 +5,7 @@
** Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arith/tableau_sizes.h b/src/theory/arith/tableau_sizes.h
index 085ff9640..76914e04a 100644
--- a/src/theory/arith/tableau_sizes.h
+++ b/src/theory/arith/tableau_sizes.h
@@ -5,7 +5,7 @@
** Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,7 +20,6 @@
#pragma once
-#include <stdint.h>
#include "theory/arith/arithvar.h"
namespace CVC4 {
diff --git a/src/theory/arith/theory_arith.cpp b/src/theory/arith/theory_arith.cpp
index eb5bf3685..b5c0d1bd0 100644
--- a/src/theory/arith/theory_arith.cpp
+++ b/src/theory/arith/theory_arith.cpp
@@ -2,10 +2,10 @@
/*! \file theory_arith.cpp
** \verbatim
** Top contributors (to current version):
- ** Tim King, Andrew Reynolds, Dejan Jovanovic
+ ** Andrew Reynolds, Tim King, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,6 +21,7 @@
#include "smt/smt_statistics_registry.h"
#include "theory/arith/arith_rewriter.h"
#include "theory/arith/infer_bounds.h"
+#include "theory/arith/nl/nonlinear_extension.h"
#include "theory/arith/theory_arith_private.h"
#include "theory/ext_theory.h"
@@ -39,21 +40,18 @@ TheoryArith::TheoryArith(context::Context* c,
ProofNodeManager* pnm)
: Theory(THEORY_ARITH, c, u, out, valuation, logicInfo, pnm),
d_internal(
- new TheoryArithPrivate(*this, c, u, out, valuation, logicInfo)),
+ new TheoryArithPrivate(*this, c, u, out, valuation, logicInfo, pnm)),
d_ppRewriteTimer("theory::arith::ppRewriteTimer"),
- d_proofRecorder(nullptr)
+ d_astate(*d_internal, c, u, valuation),
+ d_inferenceManager(*this, d_astate, pnm),
+ d_nonlinearExtension(nullptr),
+ d_arithPreproc(d_astate, d_inferenceManager, pnm, logicInfo)
{
smtStatisticsRegistry()->registerStat(&d_ppRewriteTimer);
- // if logic is non-linear
- if (logicInfo.isTheoryEnabled(THEORY_ARITH) && !logicInfo.isLinear())
- {
- setupExtTheory();
- getExtTheory()->addFunctionKind(kind::NONLINEAR_MULT);
- getExtTheory()->addFunctionKind(kind::EXPONENTIAL);
- getExtTheory()->addFunctionKind(kind::SINE);
- getExtTheory()->addFunctionKind(kind::PI);
- getExtTheory()->addFunctionKind(kind::IAND);
- }
+
+ // indicate we are using the theory state object and inference manager
+ d_theoryState = &d_astate;
+ d_inferManager = &d_inferenceManager;
}
TheoryArith::~TheoryArith(){
@@ -61,93 +59,211 @@ TheoryArith::~TheoryArith(){
delete d_internal;
}
-TheoryRewriter* TheoryArith::getTheoryRewriter()
-{
- return d_internal->getTheoryRewriter();
-}
+TheoryRewriter* TheoryArith::getTheoryRewriter() { return &d_rewriter; }
-void TheoryArith::preRegisterTerm(TNode n){
- d_internal->preRegisterTerm(n);
+bool TheoryArith::needsEqualityEngine(EeSetupInfo& esi)
+{
+ return d_internal->needsEqualityEngine(esi);
}
-
void TheoryArith::finishInit()
{
- TheoryModel* tm = d_valuation.getModel();
- Assert(tm != nullptr);
if (getLogicInfo().isTheoryEnabled(THEORY_ARITH)
&& getLogicInfo().areTranscendentalsUsed())
{
// witness is used to eliminate square root
- tm->setUnevaluatedKind(kind::WITNESS);
+ d_valuation.setUnevaluatedKind(kind::WITNESS);
// we only need to add the operators that are not syntax sugar
- tm->setUnevaluatedKind(kind::EXPONENTIAL);
- tm->setUnevaluatedKind(kind::SINE);
- tm->setUnevaluatedKind(kind::PI);
+ d_valuation.setUnevaluatedKind(kind::EXPONENTIAL);
+ d_valuation.setUnevaluatedKind(kind::SINE);
+ d_valuation.setUnevaluatedKind(kind::PI);
+ }
+ // only need to create nonlinear extension if non-linear logic
+ const LogicInfo& logicInfo = getLogicInfo();
+ if (logicInfo.isTheoryEnabled(THEORY_ARITH) && !logicInfo.isLinear())
+ {
+ d_nonlinearExtension.reset(
+ new nl::NonlinearExtension(*this, d_astate, d_equalityEngine));
}
+ // finish initialize internally
+ d_internal->finishInit();
}
-TrustNode TheoryArith::expandDefinition(Node node)
+void TheoryArith::preRegisterTerm(TNode n)
{
- Node expNode = d_internal->expandDefinition(node);
- return TrustNode::mkTrustRewrite(node, expNode, nullptr);
-}
-
-void TheoryArith::setMasterEqualityEngine(eq::EqualityEngine* eq) {
- d_internal->setMasterEqualityEngine(eq);
+ if (d_nonlinearExtension != nullptr)
+ {
+ d_nonlinearExtension->preRegisterTerm(n);
+ }
+ d_internal->preRegisterTerm(n);
}
-void TheoryArith::addSharedTerm(TNode n){
- d_internal->addSharedTerm(n);
-}
+void TheoryArith::notifySharedTerm(TNode n) { d_internal->notifySharedTerm(n); }
TrustNode TheoryArith::ppRewrite(TNode atom)
{
CodeTimer timer(d_ppRewriteTimer, /* allow_reentrant = */ true);
- Node ret = d_internal->ppRewrite(atom);
- if (ret != atom)
+ Debug("arith::preprocess") << "arith::preprocess() : " << atom << endl;
+
+ if (options::arithRewriteEq())
{
- return TrustNode::mkTrustRewrite(atom, ret, nullptr);
+ if (atom.getKind() == kind::EQUAL && atom[0].getType().isReal())
+ {
+ Node leq = NodeBuilder<2>(kind::LEQ) << atom[0] << atom[1];
+ Node geq = NodeBuilder<2>(kind::GEQ) << atom[0] << atom[1];
+ TrustNode tleq = ppRewriteTerms(leq);
+ TrustNode tgeq = ppRewriteTerms(geq);
+ if (!tleq.isNull())
+ {
+ leq = tleq.getNode();
+ }
+ if (!tgeq.isNull())
+ {
+ geq = tgeq.getNode();
+ }
+ Node rewritten = Rewriter::rewrite(leq.andNode(geq));
+ Debug("arith::preprocess")
+ << "arith::preprocess() : returning " << rewritten << endl;
+ // don't need to rewrite terms since rewritten is not a non-standard op
+ return TrustNode::mkTrustRewrite(atom, rewritten, nullptr);
+ }
}
- return TrustNode::null();
+ return ppRewriteTerms(atom);
}
-Theory::PPAssertStatus TheoryArith::ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
- return d_internal->ppAssert(in, outSubstitutions);
+TrustNode TheoryArith::ppRewriteTerms(TNode n)
+{
+ if (Theory::theoryOf(n) != THEORY_ARITH)
+ {
+ return TrustNode::null();
+ }
+ // Eliminate operators recursively. Notice we must do this here since other
+ // theories may generate lemmas that involve non-standard operators. For
+ // example, quantifier instantiation may use TO_INTEGER terms; SyGuS may
+ // introduce non-standard arithmetic terms appearing in grammars.
+ // call eliminate operators
+ return d_arithPreproc.eliminate(n);
+}
+
+Theory::PPAssertStatus TheoryArith::ppAssert(
+ TrustNode tin, TrustSubstitutionMap& outSubstitutions)
+{
+ return d_internal->ppAssert(tin, outSubstitutions);
}
void TheoryArith::ppStaticLearn(TNode n, NodeBuilder<>& learned) {
d_internal->ppStaticLearn(n, learned);
}
-void TheoryArith::check(Effort effortLevel){
- getOutputChannel().spendResource(ResourceManager::Resource::TheoryCheckStep);
- d_internal->check(effortLevel);
+bool TheoryArith::preCheck(Effort level)
+{
+ Trace("arith-check") << "TheoryArith::preCheck " << level << std::endl;
+ return d_internal->preCheck(level);
}
-bool TheoryArith::needsCheckLastEffort() {
- return d_internal->needsCheckLastEffort();
+void TheoryArith::postCheck(Effort level)
+{
+ Trace("arith-check") << "TheoryArith::postCheck " << level << std::endl;
+ // check with the non-linear solver at last call
+ if (level == Theory::EFFORT_LAST_CALL)
+ {
+ if (d_nonlinearExtension != nullptr)
+ {
+ d_nonlinearExtension->check(level);
+ }
+ return;
+ }
+ // otherwise, check with the linear solver
+ if (d_internal->postCheck(level))
+ {
+ // linear solver emitted a conflict or lemma, return
+ return;
+ }
+
+ if (Theory::fullEffort(level))
+ {
+ if (d_nonlinearExtension != nullptr)
+ {
+ d_nonlinearExtension->check(level);
+ }
+ else if (d_internal->foundNonlinear())
+ {
+ // set incomplete
+ d_inferenceManager.setIncomplete();
+ }
+ }
}
-TrustNode TheoryArith::explain(TNode n)
+bool TheoryArith::preNotifyFact(
+ TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal)
{
- Node exp = d_internal->explain(n);
- return TrustNode::mkTrustPropExp(n, exp, nullptr);
+ Trace("arith-check") << "TheoryArith::preNotifyFact: " << fact
+ << ", isPrereg=" << isPrereg
+ << ", isInternal=" << isInternal << std::endl;
+ d_internal->preNotifyFact(atom, pol, fact);
+ // We do not assert to the equality engine of arithmetic in the standard way,
+ // hence we return "true" to indicate we are finished with this fact.
+ return true;
}
-bool TheoryArith::getCurrentSubstitution( int effort, std::vector< Node >& vars, std::vector< Node >& subs, std::map< Node, std::vector< Node > >& exp ) {
- return d_internal->getCurrentSubstitution( effort, vars, subs, exp );
+bool TheoryArith::needsCheckLastEffort() {
+ if (d_nonlinearExtension != nullptr)
+ {
+ return d_nonlinearExtension->needsCheckLastEffort();
+ }
+ return false;
}
-bool TheoryArith::isExtfReduced( int effort, Node n, Node on, std::vector< Node >& exp ) {
- return d_internal->isExtfReduced( effort, n, on, exp );
-}
+TrustNode TheoryArith::explain(TNode n) { return d_internal->explain(n); }
void TheoryArith::propagate(Effort e) {
d_internal->propagate(e);
}
-bool TheoryArith::collectModelInfo(TheoryModel* m)
+
+bool TheoryArith::collectModelInfo(TheoryModel* m,
+ const std::set<Node>& termSet)
+{
+ // this overrides behavior to not assert equality engine
+ return collectModelValues(m, termSet);
+}
+
+bool TheoryArith::collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet)
{
- return d_internal->collectModelInfo(m);
+ // get the model from the linear solver
+ std::map<Node, Node> arithModel;
+ d_internal->collectModelValues(termSet, arithModel);
+ // if non-linear is enabled, intercept the model, which may repair its values
+ if (d_nonlinearExtension != nullptr)
+ {
+ // Non-linear may repair values to satisfy non-linear constraints (see
+ // documentation for NonlinearExtension::interceptModel).
+ d_nonlinearExtension->interceptModel(arithModel);
+ }
+ // We are now ready to assert the model.
+ for (const std::pair<const Node, Node>& p : arithModel)
+ {
+ // maps to constant of comparable type
+ Assert(p.first.getType().isComparableTo(p.second.getType()));
+ if (m->assertEquality(p.first, p.second, true))
+ {
+ continue;
+ }
+ // If we failed to assert an equality, it is likely due to theory
+ // combination, namely the repaired model for non-linear changed
+ // an equality status that was agreed upon by both (linear) arithmetic
+ // and another theory. In this case, we must add a lemma, or otherwise
+ // we would terminate with an invalid model. Thus, we add a splitting
+ // lemma of the form ( x = v V x != v ) where v is the model value
+ // assigned by the non-linear solver to x.
+ if (d_nonlinearExtension != nullptr)
+ {
+ Node eq = p.first.eqNode(p.second);
+ Node lem = NodeManager::currentNM()->mkNode(kind::OR, eq, eq.negate());
+ d_out->lemma(lem);
+ }
+ return false;
+ }
+ return true;
}
void TheoryArith::notifyRestart(){
@@ -156,6 +272,10 @@ void TheoryArith::notifyRestart(){
void TheoryArith::presolve(){
d_internal->presolve();
+ if (d_nonlinearExtension != nullptr)
+ {
+ d_nonlinearExtension->presolve();
+ }
}
EqualityStatus TheoryArith::getEqualityStatus(TNode a, TNode b) {
@@ -174,6 +294,10 @@ std::pair<bool, Node> TheoryArith::entailmentCheck(TNode lit)
std::pair<bool, Node> res = d_internal->entailmentCheck(lit, def, ase);
return res;
}
+eq::ProofEqEngine* TheoryArith::getProofEqEngine()
+{
+ return d_inferenceManager.getProofEqEngine();
+}
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
diff --git a/src/theory/arith/theory_arith.h b/src/theory/arith/theory_arith.h
index 30de7bbad..e6029faef 100644
--- a/src/theory/arith/theory_arith.h
+++ b/src/theory/arith/theory_arith.h
@@ -2,10 +2,10 @@
/*! \file theory_arith.h
** \verbatim
** Top contributors (to current version):
- ** Tim King, Alex Ozdemir, Morgan Deters
+ ** Andrew Reynolds, Tim King, Gereon Kremer
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -17,20 +17,24 @@
#pragma once
-#include "theory/theory.h"
#include "expr/node.h"
-#include "proof/arith_proof_recorder.h"
-#include "theory/arith/theory_arith_private_forward.h"
-
+#include "theory/arith/arith_preprocess.h"
+#include "theory/arith/arith_rewriter.h"
+#include "theory/arith/arith_state.h"
+#include "theory/arith/inference_manager.h"
+#include "theory/arith/nl/nonlinear_extension.h"
+#include "theory/arith/operator_elim.h"
+#include "theory/theory.h"
namespace CVC4 {
namespace theory {
-
namespace arith {
+class TheoryArithPrivate;
+
/**
- * Implementation of QF_LRA.
- * Based upon:
+ * Implementation of linear and non-linear integer and real arithmetic.
+ * The linear arithmetic solver is based upon:
* http://research.microsoft.com/en-us/um/people/leonardo/cav06.pdf
*/
class TheoryArith : public Theory {
@@ -41,11 +45,6 @@ class TheoryArith : public Theory {
TimerStat d_ppRewriteTimer;
- /**
- * @brief Where to store Farkas proofs of lemmas
- */
- proof::ArithProofRecorder * d_proofRecorder;
-
public:
TheoryArith(context::Context* c,
context::UserContext* u,
@@ -55,39 +54,55 @@ class TheoryArith : public Theory {
ProofNodeManager* pnm = nullptr);
virtual ~TheoryArith();
+ //--------------------------------- initialization
+ /** get the official theory rewriter of this theory */
TheoryRewriter* getTheoryRewriter() override;
+ /**
+ * Returns true if this theory needs an equality engine, which is assigned
+ * to it (d_equalityEngine) by the equality engine manager during
+ * TheoryEngine::finishInit, prior to calling finishInit for this theory.
+ * If this method returns true, it stores instructions for the notifications
+ * this Theory wishes to receive from its equality engine.
+ */
+ bool needsEqualityEngine(EeSetupInfo& esi) override;
+ /** finish initialization */
+ void finishInit() override;
+ //--------------------------------- end initialization
/**
* Does non-context dependent setup for a node connected to a theory.
*/
void preRegisterTerm(TNode n) override;
- void finishInit() override;
-
- TrustNode expandDefinition(Node node) override;
-
- void setMasterEqualityEngine(eq::EqualityEngine* eq) override;
-
- void check(Effort e) override;
+ //--------------------------------- standard check
+ /** Pre-check, called before the fact queue of the theory is processed. */
+ bool preCheck(Effort level) override;
+ /** Post-check, called after the fact queue of the theory is processed. */
+ void postCheck(Effort level) override;
+ /** Pre-notify fact, return true if processed. */
+ bool preNotifyFact(TNode atom,
+ bool pol,
+ TNode fact,
+ bool isPrereg,
+ bool isInternal) override;
+ //--------------------------------- end standard check
bool needsCheckLastEffort() override;
void propagate(Effort e) override;
TrustNode explain(TNode n) override;
- bool getCurrentSubstitution(int effort,
- std::vector<Node>& vars,
- std::vector<Node>& subs,
- std::map<Node, std::vector<Node> >& exp) override;
- bool isExtfReduced(int effort,
- Node n,
- Node on,
- std::vector<Node>& exp) override;
- bool collectModelInfo(TheoryModel* m) override;
+ bool collectModelInfo(TheoryModel* m, const std::set<Node>& termSet) override;
+ /**
+ * Collect model values in m based on the relevant terms given by termSet.
+ */
+ bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet) override;
void shutdown() override {}
void presolve() override;
void notifyRestart() override;
- PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions) override;
+ PPAssertStatus ppAssert(TrustNode tin,
+ TrustSubstitutionMap& outSubstitutions) override;
TrustNode ppRewrite(TNode atom) override;
void ppStaticLearn(TNode in, NodeBuilder<>& learned) override;
@@ -95,17 +110,44 @@ class TheoryArith : public Theory {
EqualityStatus getEqualityStatus(TNode a, TNode b) override;
- void addSharedTerm(TNode n) override;
+ void notifySharedTerm(TNode n) override;
Node getModelValue(TNode var) override;
std::pair<bool, Node> entailmentCheck(TNode lit) override;
- void setProofRecorder(proof::ArithProofRecorder* proofRecorder)
+ /** Return a reference to the arith::InferenceManager. */
+ InferenceManager& getInferenceManager()
{
- d_proofRecorder = proofRecorder;
+ return d_inferenceManager;
}
+ private:
+ /**
+ * Preprocess rewrite terms, return the trust node encapsulating the
+ * preprocessed form of n, and the proof generator that can provide the
+ * proof for the equivalence of n and this term.
+ *
+ * This calls the operator elimination utility to eliminate extended
+ * symbols.
+ */
+ TrustNode ppRewriteTerms(TNode n);
+ /** Get the proof equality engine */
+ eq::ProofEqEngine* getProofEqEngine();
+ /** The state object wrapping TheoryArithPrivate */
+ ArithState d_astate;
+ /** The arith::InferenceManager. */
+ InferenceManager d_inferenceManager;
+
+ /**
+ * The non-linear extension, responsible for all approaches for non-linear
+ * arithmetic.
+ */
+ std::unique_ptr<nl::NonlinearExtension> d_nonlinearExtension;
+ /** The preprocess utility */
+ ArithPreprocess d_arithPreproc;
+ /** The theory rewriter for this theory. */
+ ArithRewriter d_rewriter;
};/* 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 d0da29e7a..153b8e379 100644
--- a/src/theory/arith/theory_arith_private.cpp
+++ b/src/theory/arith/theory_arith_private.cpp
@@ -2,10 +2,10 @@
/*! \file theory_arith_private.cpp
** \verbatim
** Top contributors (to current version):
- ** Tim King, Andrew Reynolds, Alex Ozdemir
+ ** Tim King, Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -17,8 +17,6 @@
#include "theory/arith/theory_arith_private.h"
-#include <stdint.h>
-
#include <map>
#include <queue>
#include <vector>
@@ -34,6 +32,8 @@
#include "expr/node.h"
#include "expr/node_algorithm.h"
#include "expr/node_builder.h"
+#include "expr/proof_generator.h"
+#include "expr/proof_node_manager.h"
#include "expr/skolem_manager.h"
#include "options/arith_options.h"
#include "options/smt_options.h" // for incrementalSolving()
@@ -87,12 +87,21 @@ TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing,
context::UserContext* u,
OutputChannel& out,
Valuation valuation,
- const LogicInfo& logicInfo)
+ const LogicInfo& logicInfo,
+ ProofNodeManager* pnm)
: d_containing(containing),
- d_nlIncomplete(false),
+ d_foundNl(false),
d_rowTracking(),
- d_constraintDatabase(
- c, u, d_partialModel, d_congruenceManager, RaiseConflict(*this)),
+ d_pnm(pnm),
+ d_checker(),
+ d_pfGen(new EagerProofGenerator(d_pnm, u)),
+ d_constraintDatabase(c,
+ u,
+ d_partialModel,
+ d_congruenceManager,
+ RaiseConflict(*this),
+ d_pfGen.get(),
+ d_pnm),
d_qflraStatus(Result::SAT_UNKNOWN),
d_unknownsInARow(0),
d_hasDoneWorkSinceCut(false),
@@ -118,11 +127,14 @@ TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing,
d_tableauResetPeriod(10),
d_conflicts(c),
d_blackBoxConflict(c, Node::null()),
+ d_blackBoxConflictPf(c, std::shared_ptr<ProofNode>(nullptr)),
d_congruenceManager(c,
+ u,
d_constraintDatabase,
SetupLiteralCallBack(*this),
d_partialModel,
- RaiseEqualityEngineConflict(*this)),
+ RaiseEqualityEngineConflict(*this),
+ d_pnm),
d_cmEnabled(c, true),
d_dualSimplex(
@@ -133,7 +145,6 @@ TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing,
d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
d_attemptSolSimplex(
d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
- d_nonlinearExtension(NULL),
d_pass1SDP(NULL),
d_otherSDP(NULL),
d_lastContextIntegerAttempted(c, -1),
@@ -155,21 +166,32 @@ TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing,
d_dioSolveResources(0),
d_solveIntMaybeHelp(0u),
d_solveIntAttempts(0u),
- d_statistics(),
- d_opElim(logicInfo)
+ d_newFacts(false),
+ d_previousStatus(Result::SAT_UNKNOWN),
+ d_statistics()
{
- // only need to create if non-linear logic
- if (logicInfo.isTheoryEnabled(THEORY_ARITH) && !logicInfo.isLinear())
+ ProofChecker* pc = pnm != nullptr ? pnm->getChecker() : nullptr;
+ if (pc != nullptr)
{
- d_nonlinearExtension = new nl::NonlinearExtension(
- containing, d_congruenceManager.getEqualityEngine());
+ d_checker.registerTo(pc);
}
}
TheoryArithPrivate::~TheoryArithPrivate(){
if(d_treeLog != NULL){ delete d_treeLog; }
if(d_approxStats != NULL) { delete d_approxStats; }
- if(d_nonlinearExtension != NULL) { delete d_nonlinearExtension; }
+}
+
+bool TheoryArithPrivate::needsEqualityEngine(EeSetupInfo& esi)
+{
+ return d_congruenceManager.needsEqualityEngine(esi);
+}
+void TheoryArithPrivate::finishInit()
+{
+ eq::EqualityEngine* ee = d_containing.getEqualityEngine();
+ eq::ProofEqEngine* pfee = d_containing.getProofEqEngine();
+ Assert(ee != nullptr);
+ d_congruenceManager.finishInit(ee, pfee);
}
static bool contains(const ConstraintCPVec& v, ConstraintP con){
@@ -226,10 +248,6 @@ static void resolve(ConstraintCPVec& buf, ConstraintP c, const ConstraintCPVec&
// return safeConstructNary(nb);
}
-void TheoryArithPrivate::setMasterEqualityEngine(eq::EqualityEngine* eq) {
- d_congruenceManager.setMasterEqualityEngine(eq);
-}
-
TheoryArithPrivate::ModelException::ModelException(TNode n, const char* msg)
{
stringstream ss;
@@ -511,17 +529,36 @@ bool complexityBelow(const DenseMap<Rational>& row, uint32_t cap){
return true;
}
+bool TheoryArithPrivate::isProofEnabled() const
+{
+ return d_pnm != nullptr;
+}
+
void TheoryArithPrivate::raiseConflict(ConstraintCP a){
Assert(a->inConflict());
d_conflicts.push_back(a);
}
-void TheoryArithPrivate::raiseBlackBoxConflict(Node bb){
- if(d_blackBoxConflict.get().isNull()){
+void TheoryArithPrivate::raiseBlackBoxConflict(Node bb,
+ std::shared_ptr<ProofNode> pf)
+{
+ Debug("arith::bb") << "raiseBlackBoxConflict: " << bb << std::endl;
+ if (d_blackBoxConflict.get().isNull())
+ {
+ if (isProofEnabled())
+ {
+ Debug("arith::bb") << " with proof " << pf << std::endl;
+ d_blackBoxConflictPf.set(pf);
+ }
d_blackBoxConflict = bb;
}
}
+bool TheoryArithPrivate::anyConflict() const
+{
+ return !conflictQueueEmpty() || !d_blackBoxConflict.get().isNull();
+}
+
void TheoryArithPrivate::revertOutOfConflict(){
d_partialModel.revertAssignmentChanges();
clearUpdates();
@@ -615,7 +652,7 @@ bool TheoryArithPrivate::AssertLower(ConstraintP constraint){
ConstraintP ubc = d_partialModel.getUpperBoundConstraint(x_i);
ConstraintP negation = constraint->getNegation();
negation->impliedByUnate(ubc, true);
-
+
raiseConflict(constraint);
++(d_statistics.d_statAssertLowerConflicts);
@@ -748,7 +785,7 @@ bool TheoryArithPrivate::AssertUpper(ConstraintP constraint){
if(d_partialModel.greaterThanUpperBound(x_i, c_i) ){ // \upperbound(x_i) <= c_i
return false; //sat
}
-
+
// cmpToLb = \lowerbound(x_i).cmp(c_i)
int cmpToLB = d_partialModel.cmpToLowerBound(x_i, c_i);
if( cmpToLB < 0 ){ // \upperbound(x_i) < \lowerbound(x_i)
@@ -793,7 +830,7 @@ bool TheoryArithPrivate::AssertUpper(ConstraintP constraint){
++(d_statistics.d_statDisequalityConflicts);
raiseConflict(eq);
return true;
- }
+ }
}
}else if(cmpToLB > 0){
// l <= x <= u and l < u
@@ -1029,7 +1066,7 @@ bool TheoryArithPrivate::AssertDisequality(ConstraintP constraint){
if(!split && c_i == d_partialModel.getAssignment(x_i)){
Debug("arith::eq") << "lemma now! " << constraint << endl;
- outputLemma(constraint->split());
+ outputTrustedLemma(constraint->split());
return false;
}else if(d_partialModel.strictlyLessThanLowerBound(x_i, c_i)){
Debug("arith::eq") << "can drop as less than lb" << constraint << endl;
@@ -1045,13 +1082,12 @@ bool TheoryArithPrivate::AssertDisequality(ConstraintP constraint){
return false;
}
-void TheoryArithPrivate::addSharedTerm(TNode n){
- Debug("arith::addSharedTerm") << "addSharedTerm: " << n << endl;
+void TheoryArithPrivate::notifySharedTerm(TNode n)
+{
+ Debug("arith::notifySharedTerm") << "notifySharedTerm: " << n << endl;
if(n.isConst()){
d_partialModel.invalidateDelta();
}
-
- d_congruenceManager.addSharedTerm(n);
if(!n.isConst() && !isSetup(n)){
Polynomial poly = Polynomial::parsePolynomial(n);
Polynomial::iterator it = poly.begin();
@@ -1078,48 +1114,11 @@ Node TheoryArithPrivate::getModelValue(TNode term) {
}
}
-Node TheoryArithPrivate::ppRewriteTerms(TNode n) {
- if(Theory::theoryOf(n) != THEORY_ARITH) {
- return n;
- }
- // Eliminate operators recursively. Notice we must do this here since other
- // theories may generate lemmas that involve non-standard operators. For
- // example, quantifier instantiation may use TO_INTEGER terms; SyGuS may
- // introduce non-standard arithmetic terms appearing in grammars.
- // call eliminate operators
- Node nn = d_opElim.eliminateOperators(n);
- if (nn != n)
- {
- // since elimination may introduce new operators to eliminate, we must
- // recursively eliminate result
- return d_opElim.eliminateOperatorsRec(nn);
- }
- return n;
-}
-
-Node TheoryArithPrivate::ppRewrite(TNode atom) {
- Debug("arith::preprocess") << "arith::preprocess() : " << atom << endl;
-
- if (options::arithRewriteEq())
- {
- if (atom.getKind() == kind::EQUAL && atom[0].getType().isReal())
- {
- 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;
- // don't need to rewrite terms since rewritten is not a non-standard op
- return rewritten;
- }
- }
- return ppRewriteTerms(atom);
-}
-
-Theory::PPAssertStatus TheoryArithPrivate::ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
+Theory::PPAssertStatus TheoryArithPrivate::ppAssert(
+ TrustNode tin, TrustSubstitutionMap& outSubstitutions)
+{
TimerStat::CodeTimer codeTimer(d_statistics.d_simplifyTimer);
+ TNode in = tin.getNode();
Debug("simplify") << "TheoryArithPrivate::solve(" << in << ")" << endl;
@@ -1170,7 +1169,7 @@ Theory::PPAssertStatus TheoryArithPrivate::ppAssert(TNode in, SubstitutionMap& o
Debug("simplify") << "TheoryArithPrivate::solve(): substitution "
<< minVar << " |-> " << elim << endl;
- outSubstitutions.addSubstitution(minVar, elim);
+ outSubstitutions.addSubstitutionSolved(minVar, elim, tin);
return Theory::PP_ASSERT_STATUS_SOLVED;
}
else
@@ -1264,11 +1263,7 @@ void TheoryArithPrivate::setupVariableList(const VarList& vl){
if(getLogicInfo().isLinear()){
throw LogicException("A non-linear fact was asserted to arithmetic in a linear logic.");
}
-
- if (d_nonlinearExtension == nullptr)
- {
- d_nlIncomplete = true;
- }
+ d_foundNl = true;
++(d_statistics.d_statUserVariables);
requestArithVar(vlNode, false, false);
@@ -1276,14 +1271,12 @@ void TheoryArithPrivate::setupVariableList(const VarList& vl){
//setupInitialValue(av);
markSetup(vlNode);
- }else{
- if (d_nonlinearExtension == nullptr)
- {
- if( vlNode.getKind()==kind::EXPONENTIAL || vlNode.getKind()==kind::SINE ||
- vlNode.getKind()==kind::COSINE || vlNode.getKind()==kind::TANGENT ){
- d_nlIncomplete = true;
- }
- }
+ }
+ else if (vlNode.getKind() == kind::EXPONENTIAL
+ || vlNode.getKind() == kind::SINE || vlNode.getKind() == kind::COSINE
+ || vlNode.getKind() == kind::TANGENT)
+ {
+ d_foundNl = true;
}
/* Note:
@@ -1445,11 +1438,6 @@ void TheoryArithPrivate::setupAtom(TNode atom) {
void TheoryArithPrivate::preRegisterTerm(TNode n) {
Debug("arith::preregister") <<"begin arith::preRegisterTerm("<< n <<")"<< endl;
- if (d_nonlinearExtension != nullptr)
- {
- d_containing.getExtTheory()->registerTermRec( n );
- }
-
try {
if(isRelationOperator(n.getKind())){
if(!isSetup(n)){
@@ -1483,8 +1471,9 @@ ArithVar TheoryArithPrivate::requestArithVar(TNode x, bool aux, bool internal){
Assert(isLeaf(x) || VarList::isMember(x) || x.getKind() == PLUS || internal);
if(getLogicInfo().isLinear() && Variable::isDivMember(x)){
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.";
+ ss << "A non-linear fact (involving div/mod/divisibility) was asserted to "
+ "arithmetic in a linear logic: "
+ << x << std::endl;
throw LogicException(ss.str());
}
Assert(!d_partialModel.hasArithVar(x));
@@ -1647,9 +1636,9 @@ Node TheoryArithPrivate::callDioSolver(){
Node orig = Node::null();
if(lb->isEquality()){
- orig = lb->externalExplainByAssertions();
+ orig = Constraint::externalExplainByAssertions({lb});
}else if(ub->isEquality()){
- orig = ub->externalExplainByAssertions();
+ orig = Constraint::externalExplainByAssertions({ub});
}else {
orig = Constraint::externalExplainByAssertions(ub, lb);
}
@@ -1674,10 +1663,8 @@ Node TheoryArithPrivate::callDioSolver(){
return d_diosolver.processEquationsForConflict();
}
-ConstraintP TheoryArithPrivate::constraintFromFactQueue(){
- Assert(!done());
- TNode assertion = get();
-
+ConstraintP TheoryArithPrivate::constraintFromFactQueue(TNode assertion)
+{
Kind simpleKind = Comparison::comparisonKind(assertion);
ConstraintP constraint = d_constraintDatabase.lookup(assertion);
if(constraint == NullConstraint){
@@ -1723,9 +1710,10 @@ ConstraintP TheoryArithPrivate::constraintFromFactQueue(){
Debug("arith::constraint") << "marking as constraint as self explaining " << endl;
constraint->setAssumption(inConflict);
} else {
- Debug("arith::constraint") << "already has proof: " << constraint->externalExplainByAssertions() << endl;
+ Debug("arith::constraint")
+ << "already has proof: "
+ << Constraint::externalExplainByAssertions({constraint});
}
-
if(Debug.isOn("arith::negatedassumption") && inConflict){
ConstraintP negation = constraint->getNegation();
@@ -1893,7 +1881,7 @@ void TheoryArithPrivate::outputConflicts(){
Debug("arith::conflict") << "outputting conflicts" << std::endl;
Assert(anyConflict());
static unsigned int conflicts = 0;
-
+
if(!conflictQueueEmpty()){
Assert(!d_conflicts.empty());
for(size_t i = 0, i_end = d_conflicts.size(); i < i_end; ++i){
@@ -1906,45 +1894,32 @@ void TheoryArithPrivate::outputConflicts(){
pf.print(std::cout);
std::cout << std::endl;
}
- Node conflict = confConstraint->externalExplainConflict();
+ if (Debug.isOn("arith::pf::tree"))
+ {
+ Debug("arith::pf::tree") << "\n\nTree:\n";
+ confConstraint->printProofTree(Debug("arith::pf::tree"));
+ confConstraint->getNegation()->printProofTree(Debug("arith::pf::tree"));
+ }
+
+ TrustNode trustedConflict = confConstraint->externalExplainConflict();
+ Node conflict = trustedConflict.getNode();
++conflicts;
Debug("arith::conflict") << "d_conflicts[" << i << "] " << conflict
<< " has proof: " << hasProof << endl;
- PROOF(if (d_containing.d_proofRecorder && confConstraint->hasFarkasProof()
- && pf.d_farkasCoefficients->size()
- == conflict.getNumChildren()) {
- // The Farkas coefficients and the children of `conflict` seem to be in
- // opposite orders... There is some relevant documentation in the
- // comment for the d_farkasCoefficients field in "constraint.h"
- //
- // Anyways, we reverse the children in `conflict` here.
- NodeBuilder<> conflictInFarkasCoefficientOrder(kind::AND);
- for (size_t j = 0, nchildren = conflict.getNumChildren(); j < nchildren;
- ++j)
- {
- conflictInFarkasCoefficientOrder
- << conflict[conflict.getNumChildren() - j - 1];
- }
-
- if (Debug.isOn("arith::pf::tree")) {
- confConstraint->printProofTree(Debug("arith::pf::tree"));
- confConstraint->getNegation()->printProofTree(Debug("arith::pf::tree"));
- }
-
- Assert(conflict.getNumChildren() == pf.d_farkasCoefficients->size());
- if (confConstraint->hasSimpleFarkasProof())
- {
- d_containing.d_proofRecorder->saveFarkasCoefficients(
- conflictInFarkasCoefficientOrder, pf.d_farkasCoefficients);
- }
- })
if(Debug.isOn("arith::normalize::external")){
conflict = flattenAndSort(conflict);
Debug("arith::conflict") << "(normalized to) " << conflict << endl;
}
- outputConflict(conflict);
+ if (isProofEnabled())
+ {
+ outputTrustedConflict(trustedConflict);
+ }
+ else
+ {
+ outputConflict(conflict);
+ }
}
}
if(!d_blackBoxConflict.get().isNull()){
@@ -1957,16 +1932,35 @@ void TheoryArithPrivate::outputConflicts(){
bb = flattenAndSort(bb);
Debug("arith::conflict") << "(normalized to) " << bb << endl;
}
-
- outputConflict(bb);
+ if (isProofEnabled() && d_blackBoxConflictPf.get())
+ {
+ auto confPf = d_blackBoxConflictPf.get();
+ outputTrustedConflict(d_pfGen->mkTrustNode(bb, confPf, true));
+ }
+ else
+ {
+ outputConflict(bb);
+ }
}
}
+void TheoryArithPrivate::outputTrustedLemma(TrustNode lemma)
+{
+ Debug("arith::channel") << "Arith trusted lemma: " << lemma << std::endl;
+ (d_containing.d_out)->lemma(lemma.getNode());
+}
+
void TheoryArithPrivate::outputLemma(TNode lem) {
Debug("arith::channel") << "Arith lemma: " << lem << std::endl;
(d_containing.d_out)->lemma(lem);
}
+void TheoryArithPrivate::outputTrustedConflict(TrustNode conf)
+{
+ Debug("arith::channel") << "Arith trusted conflict: " << conf << std::endl;
+ (d_containing.d_out)->conflict(conf.getNode());
+}
+
void TheoryArithPrivate::outputConflict(TNode lit) {
Debug("arith::channel") << "Arith conflict: " << lit << std::endl;
(d_containing.d_out)->conflict(lit);
@@ -1974,6 +1968,7 @@ void TheoryArithPrivate::outputConflict(TNode lit) {
void TheoryArithPrivate::outputPropagate(TNode lit) {
Debug("arith::channel") << "Arith propagation: " << lit << std::endl;
+ // call the propagate lit method of the
(d_containing.d_out)->propagate(lit);
}
@@ -1982,20 +1977,6 @@ void TheoryArithPrivate::outputRestart() {
(d_containing.d_out)->demandRestart();
}
-// void TheoryArithPrivate::branchVector(const std::vector<ArithVar>& lemmas){
-// //output the lemmas
-// for(vector<ArithVar>::const_iterator i = lemmas.begin(); i != lemmas.end();
-// ++i){
-// ArithVar v = *i;
-// Assert(!d_cutInContext.contains(v));
-// d_cutInContext.insert(v);
-// d_cutCount = d_cutCount + 1;
-// Node lem = branchIntegerVariable(v);
-// outputLemma(lem);
-// ++(d_statistics.d_externalBranchAndBounds);
-// }
-// }
-
bool TheoryArithPrivate::attemptSolveInteger(Theory::Effort effortLevel, bool emmmittedLemmaOrSplit){
int level = getSatContext()->getLevel();
Debug("approx")
@@ -2177,7 +2158,6 @@ std::pair<ConstraintP, ArithVar> TheoryArithPrivate::replayGetConstraint(const D
return make_pair(imp, added);
}
}
-
ConstraintP newc = d_constraintDatabase.getConstraint(v, t, dr);
d_replayConstraints.push_back(newc);
@@ -2324,7 +2304,7 @@ void TheoryArithPrivate::tryBranchCut(ApproximateSimplex* approx, int nid, Branc
// ConstraintCPVec& back = conflicts.back();
// back.push_back(conflicting);
// back.push_back(negConflicting);
-
+
// // remove the floor/ceiling contraint implied by bcneg
// Constraint::assertionFringe(back);
}
@@ -2362,14 +2342,15 @@ void TheoryArithPrivate::replayAssert(ConstraintP c) {
}else{
Debug("approx::replayAssert") << "replayAssert " << c << " has explanation" << endl;
}
- Debug("approx::replayAssert") << "replayAssertion " << c << endl;
+ Debug("approx::replayAssert") << "replayAssertion " << c << endl;
if(inConflict){
raiseConflict(c);
}else{
assertionCases(c);
}
}else{
- Debug("approx::replayAssert") << "replayAssert " << c << " already asserted" << endl;
+ Debug("approx::replayAssert")
+ << "replayAssert " << c << " already asserted" << endl;
}
}
@@ -2538,7 +2519,7 @@ std::vector<ConstraintCPVec> TheoryArithPrivate::replayLogRec(ApproximateSimplex
SimplexDecisionProcedure& simplex = selectSimplex(true);
simplex.findModel(false);
- // can change d_qflraStatus
+ // can change d_qflraStatus
d_linEq.stopTrackingBoundCounts();
d_partialModel.startQueueingBoundCounts();
@@ -3088,13 +3069,13 @@ bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
<< " " << useApprox
<< " " << safeToCallApprox()
<< endl;
-
+
bool noPivotLimitPass1 = noPivotLimit && !useApprox;
d_qflraStatus = simplex.findModel(noPivotLimitPass1);
Debug("TheoryArithPrivate::solveRealRelaxation")
<< "solveRealRelaxation()" << " pass1 " << d_qflraStatus << endl;
-
+
if(d_qflraStatus == Result::SAT_UNKNOWN && useApprox && safeToCallApprox()){
// pass2: fancy-final
static const int32_t relaxationLimit = 10000;
@@ -3262,7 +3243,6 @@ bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
// if(!useFancyFinal){
// d_qflraStatus = simplex.findModel(noPivotLimit);
// }else{
-
// if(d_qflraStatus == Result::SAT_UNKNOWN){
// //Message() << "got sat unknown" << endl;
@@ -3319,47 +3299,37 @@ bool TheoryArithPrivate::hasFreshArithLiteral(Node n) const{
}
}
-void TheoryArithPrivate::check(Theory::Effort effortLevel){
+bool TheoryArithPrivate::preCheck(Theory::Effort level)
+{
Assert(d_currentPropagationList.empty());
-
- if(done() && effortLevel < Theory::EFFORT_FULL && ( d_qflraStatus == Result::SAT) ){
- return;
- }
-
- if(effortLevel == Theory::EFFORT_LAST_CALL){
- if (d_nonlinearExtension != nullptr)
- {
- d_nonlinearExtension->check(effortLevel);
- }
- return;
- }
-
- TimerStat::CodeTimer checkTimer(d_containing.d_checkTime);
- //cout << "TheoryArithPrivate::check " << effortLevel << std::endl;
- Debug("effortlevel") << "TheoryArithPrivate::check " << effortLevel << std::endl;
- Debug("arith") << "TheoryArithPrivate::check begun " << effortLevel << std::endl;
-
if(Debug.isOn("arith::consistency")){
Assert(unenqueuedVariablesAreConsistent());
}
- bool newFacts = !done();
- //If previous == SAT, then reverts on conflicts are safe
- //Otherwise, they are not and must be committed.
- Result::Sat previous = d_qflraStatus;
- if(newFacts){
+ d_newFacts = !done();
+ // If d_previousStatus == SAT, then reverts on conflicts are safe
+ // Otherwise, they are not and must be committed.
+ d_previousStatus = d_qflraStatus;
+ if (d_newFacts)
+ {
d_qflraStatus = Result::SAT_UNKNOWN;
d_hasDoneWorkSinceCut = true;
}
+ return false;
+}
- while(!done()){
- ConstraintP curr = constraintFromFactQueue();
- if(curr != NullConstraint){
- bool res CVC4_UNUSED = assertionCases(curr);
- Assert(!res || anyConflict());
- }
- if(anyConflict()){ break; }
+void TheoryArithPrivate::preNotifyFact(TNode atom, bool pol, TNode fact)
+{
+ ConstraintP curr = constraintFromFactQueue(fact);
+ if (curr != NullConstraint)
+ {
+ bool res CVC4_UNUSED = assertionCases(curr);
+ Assert(!res || anyConflict());
}
+}
+
+bool TheoryArithPrivate::postCheck(Theory::Effort effortLevel)
+{
if(!anyConflict()){
while(!d_learnedBounds.empty()){
// we may attempt some constraints twice. this is okay!
@@ -3376,20 +3346,25 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
if(anyConflict()){
d_qflraStatus = Result::UNSAT;
- if(options::revertArithModels() && previous == Result::SAT){
+ if (options::revertArithModels() && d_previousStatus == Result::SAT)
+ {
++d_statistics.d_revertsOnConflicts;
- Debug("arith::bt") << "clearing here " << " " << newFacts << " " << previous << " " << d_qflraStatus << endl;
+ Debug("arith::bt") << "clearing here "
+ << " " << d_newFacts << " " << d_previousStatus << " "
+ << d_qflraStatus << endl;
revertOutOfConflict();
d_errorSet.clear();
}else{
++d_statistics.d_commitsOnConflicts;
- Debug("arith::bt") << "committing here " << " " << newFacts << " " << previous << " " << d_qflraStatus << endl;
+ Debug("arith::bt") << "committing here "
+ << " " << d_newFacts << " " << d_previousStatus << " "
+ << d_qflraStatus << endl;
d_partialModel.commitAssignmentChanges();
revertOutOfConflict();
}
outputConflicts();
//cout << "unate conflict 1 " << effortLevel << std::endl;
- return;
+ return true;
}
@@ -3418,11 +3393,13 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
solveInteger(effortLevel);
if(anyConflict()){
++d_statistics.d_commitsOnConflicts;
- Debug("arith::bt") << "committing here " << " " << newFacts << " " << previous << " " << d_qflraStatus << endl;
+ Debug("arith::bt") << "committing here "
+ << " " << d_newFacts << " " << d_previousStatus << " "
+ << d_qflraStatus << endl;
revertOutOfConflict();
d_errorSet.clear();
outputConflicts();
- return;
+ return true;
}
}
@@ -3431,11 +3408,14 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
switch(d_qflraStatus){
case Result::SAT:
- if(newFacts){
+ if (d_newFacts)
+ {
++d_statistics.d_nontrivialSatChecks;
}
- Debug("arith::bt") << "committing sap inConflit" << " " << newFacts << " " << previous << " " << d_qflraStatus << endl;
+ Debug("arith::bt") << "committing sap inConflit"
+ << " " << d_newFacts << " " << d_previousStatus << " "
+ << d_qflraStatus << endl;
d_partialModel.commitAssignmentChanges();
d_unknownsInARow = 0;
if(Debug.isOn("arith::consistency")){
@@ -3453,7 +3433,9 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
++d_unknownsInARow;
++(d_statistics.d_unknownChecks);
Assert(!Theory::fullEffort(effortLevel));
- Debug("arith::bt") << "committing unknown" << " " << newFacts << " " << previous << " " << d_qflraStatus << endl;
+ Debug("arith::bt") << "committing unknown"
+ << " " << d_newFacts << " " << d_previousStatus << " "
+ << d_qflraStatus << endl;
d_partialModel.commitAssignmentChanges();
d_statistics.d_maxUnknownsInARow.maxAssign(d_unknownsInARow);
@@ -3470,7 +3452,9 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
++d_statistics.d_commitsOnConflicts;
- Debug("arith::bt") << "committing on conflict" << " " << newFacts << " " << previous << " " << d_qflraStatus << endl;
+ Debug("arith::bt") << "committing on conflict"
+ << " " << d_newFacts << " " << d_previousStatus << " "
+ << d_qflraStatus << endl;
d_partialModel.commitAssignmentChanges();
revertOutOfConflict();
@@ -3494,6 +3478,14 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
}
d_statistics.d_avgUnknownsInARow.addEntry(d_unknownsInARow);
+ size_t nPivots =
+ options::useFC() ? d_fcSimplex.getPivots() : d_dualSimplex.getPivots();
+ for (std::size_t i = 0; i < nPivots; ++i)
+ {
+ d_containing.d_out->spendResource(
+ ResourceManager::Resource::ArithPivotStep);
+ }
+
Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
<< "pre approx cuts" << endl;
if(!d_approxCuts.empty()){
@@ -3567,7 +3559,9 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
outputConflicts();
emmittedConflictOrSplit = true;
//cout << "unate conflict " << endl;
- Debug("arith::bt") << "committing on unate conflict" << " " << newFacts << " " << previous << " " << d_qflraStatus << endl;
+ Debug("arith::bt") << "committing on unate conflict"
+ << " " << d_newFacts << " " << d_previousStatus << " "
+ << d_qflraStatus << endl;
Debug("arith::conflict") << "unate arith conflict" << endl;
}
@@ -3651,24 +3645,10 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
}
}//if !emmittedConflictOrSplit && fullEffort(effortLevel) && !hasIntegerModel()
- if(!emmittedConflictOrSplit && effortLevel>=Theory::EFFORT_FULL){
- if (d_nonlinearExtension != nullptr)
- {
- d_nonlinearExtension->check( effortLevel );
- }
- }
-
- if(Theory::fullEffort(effortLevel) && d_nlIncomplete){
- setIncomplete();
- }
-
if(Theory::fullEffort(effortLevel)){
if(Debug.isOn("arith::consistency::final")){
entireStateIsConsistent("arith::consistency::final");
}
- // cout << "fulleffort" << getSatContext()->getLevel() << endl;
- // entireStateIsConsistent("arith::consistency::final");
- // cout << "emmittedConflictOrSplit" << emmittedConflictOrSplit << endl;
}
if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
@@ -3676,8 +3656,11 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
debugPrintModel(Debug("arith::print_model"));
}
Debug("arith") << "TheoryArithPrivate::check end" << std::endl;
+ return emmittedConflictOrSplit;
}
+bool TheoryArithPrivate::foundNonlinear() const { return d_foundNl; }
+
Node TheoryArithPrivate::branchIntegerVariable(ArithVar x) const {
const DeltaRational& d = d_partialModel.getAssignment(x);
Assert(!d.isIntegral());
@@ -3698,7 +3681,7 @@ Node TheoryArithPrivate::branchIntegerVariable(ArithVar x) const {
Integer ceil_d = d.ceiling();
Rational f = r - floor_d;
// Multiply by -1 to get abs value.
- Rational c = (r - ceil_d) * (-1);
+ Rational c = (r - ceil_d) * (-1);
Integer nearest = (c > f) ? floor_d : ceil_d;
// Prioritize trying a simple rounding of the real solution first,
@@ -3791,11 +3774,12 @@ bool TheoryArithPrivate::splitDisequalities(){
Debug("arith::lemma") << "Splitting on " << front << endl;
Debug("arith::lemma") << "LHS value = " << lhsValue << endl;
Debug("arith::lemma") << "RHS value = " << rhsValue << endl;
- Node lemma = front->split();
+ TrustNode lemma = front->split();
++(d_statistics.d_statDisequalitySplits);
- Debug("arith::lemma") << "Now " << Rewriter::rewrite(lemma) << endl;
- outputLemma(lemma);
+ Debug("arith::lemma")
+ << "Now " << Rewriter::rewrite(lemma.getNode()) << endl;
+ outputTrustedLemma(lemma);
//cout << "Now " << Rewriter::rewrite(lemma) << endl;
splitSomething = true;
}else if(d_partialModel.strictlyLessThanLowerBound(lhsVar, rhsValue)){
@@ -3855,67 +3839,32 @@ void TheoryArithPrivate::debugPrintModel(std::ostream& out) const{
}
}
-bool TheoryArithPrivate::needsCheckLastEffort() {
- if (d_nonlinearExtension != nullptr)
- {
- return d_nonlinearExtension->needsCheckLastEffort();
- }else{
- return false;
- }
-}
-
-Node TheoryArithPrivate::explain(TNode n)
+TrustNode TheoryArithPrivate::explain(TNode n)
{
Debug("arith::explain") << "explain @" << getSatContext()->getLevel() << ": " << n << endl;
ConstraintP c = d_constraintDatabase.lookup(n);
+ TrustNode exp;
if(c != NullConstraint){
Assert(!c->isAssumption());
- Node exp = c->externalExplainForPropagation();
+ exp = c->externalExplainForPropagation();
Debug("arith::explain") << "constraint explanation" << n << ":" << exp << endl;
- return exp;
}else if(d_assertionsThatDoNotMatchTheirLiterals.find(n) != d_assertionsThatDoNotMatchTheirLiterals.end()){
c = d_assertionsThatDoNotMatchTheirLiterals[n];
if(!c->isAssumption()){
- Node exp = c->externalExplainForPropagation();
+ exp = c->externalExplainForPropagation();
Debug("arith::explain") << "assertions explanation" << n << ":" << exp << endl;
- return exp;
}else{
Debug("arith::explain") << "this is a strange mismatch" << n << endl;
Assert(d_congruenceManager.canExplain(n));
- Debug("arith::explain") << "this is a strange mismatch" << n << endl;
- return d_congruenceManager.explain(n);
+ exp = d_congruenceManager.explain(n);
}
}else{
Assert(d_congruenceManager.canExplain(n));
Debug("arith::explain") << "dm explanation" << n << endl;
- return d_congruenceManager.explain(n);
- }
-}
-
-bool TheoryArithPrivate::getCurrentSubstitution( int effort, std::vector< Node >& vars, std::vector< Node >& subs, std::map< Node, std::vector< Node > >& exp ) {
- if (d_nonlinearExtension != nullptr)
- {
- return d_nonlinearExtension->getCurrentSubstitution( effort, vars, subs, exp );
- }else{
- return false;
- }
-}
-
-bool TheoryArithPrivate::isExtfReduced(int effort, Node n, Node on,
- std::vector<Node>& exp) {
- if (d_nonlinearExtension != nullptr)
- {
- std::pair<bool, Node> reduced =
- d_nonlinearExtension->isExtfReduced(effort, n, on, exp);
- if (!reduced.second.isNull()) {
- exp.clear();
- exp.push_back(reduced.second);
- }
- return reduced.first;
- } else {
- return false; // d_containing.isExtfReduced( effort, n, on );
+ exp = d_congruenceManager.explain(n);
}
+ return exp;
}
void TheoryArithPrivate::propagate(Theory::Effort e) {
@@ -3974,7 +3923,7 @@ void TheoryArithPrivate::propagate(Theory::Effort e) {
outputPropagate(toProp);
}else if(constraint->negationHasProof()){
- Node exp = d_congruenceManager.explain(toProp);
+ Node exp = d_congruenceManager.explain(toProp).getNode();
Node notNormalized = normalized.getKind() == NOT ?
normalized[0] : normalized.notNode();
Node lp = flattenAnd(exp.andNode(notNormalized));
@@ -4115,10 +4064,10 @@ Rational TheoryArithPrivate::deltaValueForTotalOrder() const{
return belowMin;
}
-bool TheoryArithPrivate::collectModelInfo(TheoryModel* m)
+void TheoryArithPrivate::collectModelValues(const std::set<Node>& termSet,
+ std::map<Node, Node>& arithModel)
{
AlwaysAssert(d_qflraStatus == Result::SAT);
- //AlwaysAssert(!d_nlIncomplete, "Arithmetic solver cannot currently produce models for input with nonlinear arithmetic constraints");
if(Debug.isOn("arith::collectModelInfo")){
debugPrintFacts();
@@ -4126,10 +4075,6 @@ bool TheoryArithPrivate::collectModelInfo(TheoryModel* m)
Debug("arith::collectModelInfo") << "collectModelInfo() begin " << endl;
- std::set<Node> termSet;
- d_containing.computeRelevantTerms(termSet);
-
-
// Delta lasts at least the duration of the function call
const Rational& delta = d_partialModel.getDelta();
std::unordered_set<TNode, TNodeHashFunction> shared = d_containing.currentlySharedTerms();
@@ -4137,8 +4082,6 @@ bool TheoryArithPrivate::collectModelInfo(TheoryModel* m)
// TODO:
// This is not very good for user push/pop....
// Revisit when implementing push/pop
- // Map of terms to values, constructed when non-linear arithmetic is active.
- std::map<Node, Node> arithModel;
for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
ArithVar v = *vi;
@@ -4153,56 +4096,20 @@ bool TheoryArithPrivate::collectModelInfo(TheoryModel* m)
Node qNode = mkRationalNode(qmodel);
Debug("arith::collectModelInfo") << "m->assertEquality(" << term << ", " << qmodel << ", true)" << endl;
- if (d_nonlinearExtension != nullptr)
- {
- // Let non-linear extension inspect the values before they are sent
- // to the theory model.
- arithModel[term] = qNode;
- }
- else
- {
- if (!m->assertEquality(term, qNode, true))
- {
- return false;
- }
- }
+ // Add to the map
+ arithModel[term] = qNode;
}else{
Debug("arith::collectModelInfo") << "Skipping m->assertEquality(" << term << ", true)" << endl;
}
}
}
- if (d_nonlinearExtension != nullptr)
- {
- // Non-linear may repair values to satisfy non-linear constraints (see
- // documentation for NonlinearExtension::interceptModel).
- d_nonlinearExtension->interceptModel(arithModel);
- // We are now ready to assert the model.
- for (std::pair<const Node, Node>& p : arithModel)
- {
- if (!m->assertEquality(p.first, p.second, true))
- {
- // If we failed to assert an equality, it is likely due to theory
- // combination, namely the repaired model for non-linear changed
- // an equality status that was agreed upon by both (linear) arithmetic
- // and another theory. In this case, we must add a lemma, or otherwise
- // we would terminate with an invalid model. Thus, we add a splitting
- // lemma of the form ( x = v V x != v ) where v is the model value
- // assigned by the non-linear solver to x.
- Node eq = p.first.eqNode(p.second);
- Node lem = NodeManager::currentNM()->mkNode(kind::OR, eq, eq.negate());
- d_containing.d_out->lemma(lem);
- return false;
- }
- }
- }
// Iterate over equivalence classes in LinearEqualityModule
// const eq::EqualityEngine& ee = d_congruenceManager.getEqualityEngine();
// m->assertEqualityEngine(&ee);
Debug("arith::collectModelInfo") << "collectModelInfo() end " << endl;
- return true;
}
bool TheoryArithPrivate::safeToReset() const {
@@ -4297,7 +4204,7 @@ void TheoryArithPrivate::presolve(){
callCount = callCount + 1;
}
- vector<Node> lemmas;
+ vector<TrustNode> lemmas;
if(!options::incrementalSolving()) {
switch(options::arithUnateLemmaMode()){
case options::ArithUnateLemmaMode::NO: break;
@@ -4315,16 +4222,11 @@ void TheoryArithPrivate::presolve(){
}
}
- vector<Node>::const_iterator i = lemmas.begin(), i_end = lemmas.end();
+ vector<TrustNode>::const_iterator i = lemmas.begin(), i_end = lemmas.end();
for(; i != i_end; ++i){
- Node lem = *i;
+ TrustNode lem = *i;
Debug("arith::oldprop") << " lemma lemma duck " <<lem << endl;
- outputLemma(lem);
- }
-
- if (d_nonlinearExtension != nullptr)
- {
- d_nonlinearExtension->presolve();
+ outputTrustedLemma(lem);
}
}
@@ -4359,7 +4261,7 @@ bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound
//We are only going to recreate the functionality for now.
//In the future this can be improved to generate a temporary constraint
//if none exists.
- //Experiment with doing this everytime or only when the new constraint
+ //Experiment with doing this every time or only when the new constraint
//implies an unknown fact.
ConstraintType t = upperBound ? UpperBound : LowerBound;
@@ -4638,7 +4540,6 @@ bool TheoryArithPrivate::tryToPropagate(RowIndex ridx, bool rowUp, ArithVar v, b
ConstraintP implied = d_constraintDatabase.getBestImpliedBound(v, t, bound);
if(implied != NullConstraint){
-
return rowImplicationCanBeApplied(ridx, rowUp, implied);
}
}
@@ -4647,23 +4548,40 @@ bool TheoryArithPrivate::tryToPropagate(RowIndex ridx, bool rowUp, ArithVar v, b
Node flattenImplication(Node imp){
NodeBuilder<> nb(kind::OR);
+ std::unordered_set<Node, NodeHashFunction> included;
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();
+ if (!included.count((*i).negate()))
+ {
+ nb << (*i).negate();
+ included.insert((*i).negate());
+ }
}
}else{
- nb << left.negate();
+ if (!included.count(left.negate()))
+ {
+ nb << left.negate();
+ included.insert(left.negate());
+ }
}
if(right.getKind() == kind::OR){
for(Node::iterator i = right.begin(), iend = right.end(); i != iend; ++i) {
- nb << *i;
+ if (!included.count(*i))
+ {
+ nb << *i;
+ included.insert(*i);
+ }
}
}else{
- nb << right;
+ if (!included.count(right))
+ {
+ nb << right;
+ included.insert(right);
+ }
}
return nb;
@@ -4686,9 +4604,8 @@ bool TheoryArithPrivate::rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, C
if( !assertedToTheTheory && canBePropagated && !hasProof ){
ConstraintCPVec explain;
-
- PROOF(d_farkasBuffer.clear());
- RationalVectorP coeffs = NULLPROOF(&d_farkasBuffer);
+ ARITH_PROOF(d_farkasBuffer.clear());
+ RationalVectorP coeffs = ARITH_NULLPROOF(&d_farkasBuffer);
// After invoking `propegateRow`:
// * coeffs[0] is for implied
@@ -4703,39 +4620,63 @@ bool TheoryArithPrivate::rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, C
}
Node implication = implied->externalImplication(explain);
Node clause = flattenImplication(implication);
- PROOF(if (d_containing.d_proofRecorder
- && coeffs != RationalVectorCPSentinel
- && coeffs->size() == clause.getNumChildren()) {
- Debug("arith::prop") << "implied : " << implied << std::endl;
- Debug("arith::prop") << "implication: " << implication << std::endl;
- Debug("arith::prop") << "coeff len: " << coeffs->size() << std::endl;
- Debug("arith::prop") << "exp : " << explain << std::endl;
- Debug("arith::prop") << "clause : " << clause << std::endl;
- Debug("arith::prop")
- << "clause len: " << clause.getNumChildren() << std::endl;
- Debug("arith::prop") << "exp len: " << explain.size() << std::endl;
- // Using the information from the above comment we assemble a conflict
- // AND in coefficient order
- NodeBuilder<> conflictInFarkasCoefficientOrder(kind::AND);
- conflictInFarkasCoefficientOrder << implication[1].negate();
- for (const Node& antecedent : implication[0])
- {
- Debug("arith::prop") << " ante: " << antecedent << std::endl;
- conflictInFarkasCoefficientOrder << antecedent;
- }
+ std::shared_ptr<ProofNode> clausePf{nullptr};
- Assert(coeffs != RationalVectorPSentinel);
- Assert(conflictInFarkasCoefficientOrder.getNumChildren()
- == coeffs->size());
- if (std::all_of(explain.begin(), explain.end(), [](ConstraintCP c) {
- return c->isAssumption() || c->hasIntTightenProof();
- }))
+ if (isProofEnabled())
+ {
+ // We can prove this lemma from Farkas...
+ std::vector<std::shared_ptr<ProofNode>> conflictPfs;
+ // Assume the negated getLiteral version of the implied constaint
+ // then rewrite it into proof normal form.
+ conflictPfs.push_back(
+ d_pnm->mkNode(PfRule::MACRO_SR_PRED_TRANSFORM,
+ {d_pnm->mkAssume(implied->getLiteral().negate())},
+ {implied->getNegation()->getProofLiteral()}));
+ // Add the explaination proofs.
+ for (const auto constraint : explain)
{
- d_containing.d_proofRecorder->saveFarkasCoefficients(
- conflictInFarkasCoefficientOrder, coeffs);
+ NodeBuilder<> nb;
+ conflictPfs.push_back(constraint->externalExplainByAssertions(nb));
}
- })
- outputLemma(clause);
+ // Collect the farkas coefficients, as nodes.
+ std::vector<Node> farkasCoefficients;
+ farkasCoefficients.reserve(coeffs->size());
+ auto nm = NodeManager::currentNM();
+ std::transform(
+ coeffs->begin(),
+ coeffs->end(),
+ std::back_inserter(farkasCoefficients),
+ [nm](const Rational& r) { return nm->mkConst<Rational>(r); });
+
+ // Prove bottom.
+ auto sumPf = d_pnm->mkNode(PfRule::ARITH_SCALE_SUM_UPPER_BOUNDS,
+ conflictPfs,
+ farkasCoefficients);
+ auto botPf = d_pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM, {sumPf}, {nm->mkConst(false)});
+
+ // Prove the conflict
+ std::vector<Node> assumptions;
+ assumptions.reserve(clause.getNumChildren());
+ std::transform(clause.begin(),
+ clause.end(),
+ std::back_inserter(assumptions),
+ [](TNode r) { return r.negate(); });
+ auto notAndNotPf = d_pnm->mkScope(botPf, assumptions);
+
+ // Convert it to a clause
+ auto orNotNotPf = d_pnm->mkNode(PfRule::NOT_AND, {notAndNotPf}, {});
+ clausePf = d_pnm->mkNode(
+ PfRule::MACRO_SR_PRED_TRANSFORM, {orNotNotPf}, {clause});
+
+ // Output it
+ TrustNode trustedClause = d_pfGen->mkTrustNode(clause, clausePf);
+ outputTrustedLemma(trustedClause);
+ }
+ else
+ {
+ outputLemma(clause);
+ }
}else{
Assert(!implied->negationHasProof());
implied->impliedByFarkas(explain, coeffs, false);
@@ -4811,19 +4752,6 @@ const BoundsInfo& TheoryArithPrivate::boundsInfo(ArithVar basic) const{
return d_rowTracking[ridx];
}
-Node TheoryArithPrivate::expandDefinition(Node node)
-{
- // call eliminate operators
- Node nn = d_opElim.eliminateOperators(node);
- if (nn != node)
- {
- // since elimination may introduce new operators to eliminate, we must
- // recursively eliminate result
- return d_opElim.eliminateOperatorsRec(nn);
- }
- return node;
-}
-
std::pair<bool, Node> TheoryArithPrivate::entailmentCheck(TNode lit, const ArithEntailmentCheckParameters& params, ArithEntailmentCheckSideEffects& out){
using namespace inferbounds;
@@ -5199,7 +5127,7 @@ void TheoryArithPrivate::entailmentCheckBoundLookup(std::pair<Node, DeltaRationa
? d_partialModel.getUpperBoundConstraint(v)
: d_partialModel.getLowerBoundConstraint(v);
if(c != NullConstraint){
- tmp.first = c->externalExplainByAssertions();
+ tmp.first = Constraint::externalExplainByAssertions({c});
tmp.second = c->getValue();
}
}
diff --git a/src/theory/arith/theory_arith_private.h b/src/theory/arith/theory_arith_private.h
index 867029e3c..31435221f 100644
--- a/src/theory/arith/theory_arith_private.h
+++ b/src/theory/arith/theory_arith_private.h
@@ -5,7 +5,7 @@
** Tim King, Andrew Reynolds, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,7 +19,6 @@
#include <map>
#include <queue>
-#include <stdint.h>
#include <vector>
#include "context/cdhashset.h"
@@ -31,10 +30,10 @@
#include "expr/metakind.h"
#include "expr/node.h"
#include "expr/node_builder.h"
+#include "expr/proof_generator.h"
#include "options/arith_options.h"
#include "smt/logic_exception.h"
#include "smt_util/boolean_simplification.h"
-#include "theory/arith/arith_rewriter.h"
#include "theory/arith/arith_static_learner.h"
#include "theory/arith/arith_utilities.h"
#include "theory/arith/arithvar.h"
@@ -49,14 +48,15 @@
#include "theory/arith/linear_equality.h"
#include "theory/arith/matrix.h"
#include "theory/arith/normal_form.h"
-#include "theory/arith/operator_elim.h"
#include "theory/arith/partial_model.h"
+#include "theory/arith/proof_checker.h"
#include "theory/arith/simplex.h"
#include "theory/arith/soi_simplex.h"
#include "theory/arith/theory_arith.h"
-#include "theory/arith/theory_arith_private_forward.h"
+#include "theory/eager_proof_generator.h"
#include "theory/rewriter.h"
#include "theory/theory_model.h"
+#include "theory/trust_node.h"
#include "theory/valuation.h"
#include "util/dense_map.h"
#include "util/integer.h"
@@ -79,10 +79,6 @@ namespace inferbounds {
}
class InferBoundsResult;
-namespace nl {
-class NonlinearExtension;
-}
-
/**
* Implementation of QF_LRA.
* Based upon:
@@ -95,12 +91,21 @@ private:
TheoryArith& d_containing;
- bool d_nlIncomplete;
- // TODO A better would be:
- //context::CDO<bool> d_nlIncomplete;
+ /**
+ * Whether we encountered non-linear arithmetic at any time during solving.
+ */
+ bool d_foundNl;
BoundInfoMap d_rowTracking;
+ // For proofs
+ /** Manages the proof nodes of this theory. */
+ ProofNodeManager* d_pnm;
+ /** Checks the proof rules of this theory. */
+ ArithProofRuleChecker d_checker;
+ /** Stores proposition(node)/proof pairs. */
+ std::unique_ptr<EagerProofGenerator> d_pfGen;
+
/**
* The constraint database associated with the theory.
* This must be declared before ArithPartialModel.
@@ -306,8 +311,12 @@ private:
/** This is only used by simplex at the moment. */
context::CDO<Node> d_blackBoxConflict;
-public:
+ /** For holding the proof of the above conflict node. */
+ context::CDO<std::shared_ptr<ProofNode>> d_blackBoxConflictPf;
+
+ bool isProofEnabled() const;
+ public:
/**
* This adds the constraint a to the queue of conflicts in d_conflicts.
* Both a and ~a must have a proof.
@@ -322,19 +331,18 @@ public:
// void raiseConflict(ConstraintCP a, ConstraintCP b, ConstraintCP c);
/** This is a conflict that is magically known to hold. */
- void raiseBlackBoxConflict(Node bb);
-
-private:
+ void raiseBlackBoxConflict(Node bb, std::shared_ptr<ProofNode> pf = nullptr);
+ /**
+ * Returns true iff a conflict has been raised. This method is public since
+ * it is needed by the ArithState class to know whether we are in conflict.
+ */
+ bool anyConflict() const;
+ private:
inline bool conflictQueueEmpty() const {
return d_conflicts.empty();
}
- /** Returns true iff a conflict has been raised. */
- inline bool anyConflict() const {
- return !conflictQueueEmpty() || !d_blackBoxConflict.get().isNull();
- }
-
/**
* Outputs the contents of d_conflicts onto d_out.
* The conditions of anyConflict() must hold.
@@ -368,9 +376,6 @@ private:
FCSimplexDecisionProcedure d_fcSimplex;
SumOfInfeasibilitiesSPD d_soiSimplex;
AttemptSolutionSDP d_attemptSolSimplex;
-
- /** non-linear algebraic approach */
- nl::NonlinearExtension* d_nonlinearExtension;
bool solveRealRelaxation(Theory::Effort effortLevel);
@@ -413,62 +418,91 @@ 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);
+ const LogicInfo& logicInfo,
+ ProofNodeManager* pnm);
~TheoryArithPrivate();
- TheoryRewriter* getTheoryRewriter() { return &d_rewriter; }
+ //--------------------------------- initialization
+ /**
+ * Returns true if we need an equality engine, see
+ * Theory::needsEqualityEngine.
+ */
+ bool needsEqualityEngine(EeSetupInfo& esi);
+ /** finish initialize */
+ void finishInit();
+ //--------------------------------- end initialization
/**
* Does non-context dependent setup for a node connected to a theory.
*/
void preRegisterTerm(TNode n);
- Node expandDefinition(Node node);
- void setMasterEqualityEngine(eq::EqualityEngine* eq);
-
- void check(Theory::Effort e);
- bool needsCheckLastEffort();
void propagate(Theory::Effort e);
- Node explain(TNode n);
- bool getCurrentSubstitution( int effort, std::vector< Node >& vars, std::vector< Node >& subs, std::map< Node, std::vector< Node > >& exp );
- bool isExtfReduced( int effort, Node n, Node on, std::vector< Node >& exp );
+ TrustNode explain(TNode n);
Rational deltaValueForTotalOrder() const;
bool collectModelInfo(TheoryModel* m);
+ /**
+ * Collect model values. This is the main method for extracting information
+ * about how to construct the model. This method relies on the caller for
+ * processing the map, which is done so that other modules (e.g. the
+ * non-linear extension) can modify arithModel before it is sent to the model.
+ *
+ * @param termSet The set of relevant terms
+ * @param arithModel Mapping from terms (of real type) to their values. The
+ * caller should assert equalities to the model for each entry in this map.
+ */
+ void collectModelValues(const std::set<Node>& termSet,
+ std::map<Node, Node>& arithModel);
void shutdown(){ }
void presolve();
void notifyRestart();
- Theory::PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions);
- Node ppRewrite(TNode atom);
+ Theory::PPAssertStatus ppAssert(TrustNode tin,
+ TrustSubstitutionMap& outSubstitutions);
void ppStaticLearn(TNode in, NodeBuilder<>& learned);
std::string identify() const { return std::string("TheoryArith"); }
EqualityStatus getEqualityStatus(TNode a, TNode b);
- void addSharedTerm(TNode n);
+ /** Called when n is notified as being a shared term with TheoryArith. */
+ void notifySharedTerm(TNode n);
Node getModelValue(TNode var);
std::pair<bool, Node> entailmentCheck(TNode lit, const ArithEntailmentCheckParameters& params, ArithEntailmentCheckSideEffects& out);
+ //--------------------------------- standard check
+ /** Pre-check, called before the fact queue of the theory is processed. */
+ bool preCheck(Theory::Effort level);
+ /** Pre-notify fact. */
+ void preNotifyFact(TNode atom, bool pol, TNode fact);
+ /**
+ * Post-check, called after the fact queue of the theory is processed. Returns
+ * true if a conflict or lemma was emitted.
+ */
+ bool postCheck(Theory::Effort level);
+ //--------------------------------- end standard check
+ /**
+ * Found non-linear? This returns true if this solver ever encountered
+ * any non-linear terms that were unhandled. Note that this class is not
+ * responsible for handling non-linear arithmetic. If the owner of this
+ * class does not handle non-linear arithmetic in another way, then
+ * setIncomplete should be called on the output channel of TheoryArith.
+ */
+ bool foundNonlinear() const;
-private:
-
+ private:
/** The constant zero. */
DeltaRational d_DELTA_ZERO;
@@ -613,8 +647,11 @@ private:
* Handles the case splitting for check() for a new assertion.
* Returns a conflict if one was found.
* Returns Node::null if no conflict was found.
+ *
+ * @param assertion The assertion that was just popped from the fact queue
+ * of TheoryArith and given to this class via preNotifyFact.
*/
- ConstraintP constraintFromFactQueue();
+ ConstraintP constraintFromFactQueue(TNode assertion);
bool assertionCases(ConstraintP c);
/**
@@ -652,11 +689,9 @@ private:
inline TheoryId theoryOf(TNode x) const { return d_containing.theoryOf(x); }
inline void debugPrintFacts() const { d_containing.debugPrintFacts(); }
inline context::Context* getSatContext() const { return d_containing.getSatContext(); }
- inline void setIncomplete() {
- (d_containing.d_out)->setIncomplete();
- d_nlIncomplete = true;
- }
+ void outputTrustedLemma(TrustNode lem);
void outputLemma(TNode lem);
+ void outputTrustedConflict(TrustNode conf);
void outputConflict(TNode lit);
void outputPropagate(TNode lit);
void outputRestart();
@@ -728,6 +763,13 @@ private:
RationalVector d_farkasBuffer;
+ //---------------- during check
+ /** Whether there were new facts during preCheck */
+ bool d_newFacts;
+ /** The previous status, computed during preCheck */
+ Result::Sat d_previousStatus;
+ //---------------- end during check
+
/** These fields are designed to be accessible to TheoryArith methods. */
class Statistics {
public:
@@ -830,11 +872,6 @@ private:
Statistics d_statistics;
-
- /** The theory rewriter for this theory. */
- ArithRewriter d_rewriter;
- /** The operator elimination utility */
- OperatorElim d_opElim;
};/* class TheoryArithPrivate */
}/* CVC4::theory::arith namespace */
diff --git a/src/theory/arith/theory_arith_type_rules.h b/src/theory/arith/theory_arith_type_rules.h
index 77efcfff7..0aa9cd4b3 100644
--- a/src/theory/arith/theory_arith_type_rules.h
+++ b/src/theory/arith/theory_arith_type_rules.h
@@ -2,10 +2,10 @@
/*! \file theory_arith_type_rules.h
** \verbatim
** Top contributors (to current version):
- ** Dejan Jovanovic, Christopher L. Conway, Tim King
+ ** Andrew Reynolds, Dejan Jovanovic, Christopher L. Conway
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -60,12 +60,13 @@ public:
}
}
}
- switch(Kind k = n.getKind()) {
+ switch (Kind k = n.getKind())
+ {
case kind::TO_REAL:
- return realType;
- case kind::TO_INTEGER:
- return integerType;
- default: {
+ case kind::CAST_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);
}
diff --git a/src/theory/arith/type_enumerator.h b/src/theory/arith/type_enumerator.h
index ff6308122..60291f44d 100644
--- a/src/theory/arith/type_enumerator.h
+++ b/src/theory/arith/type_enumerator.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arrays/array_info.cpp b/src/theory/arrays/array_info.cpp
index c2928e534..2a19f29f2 100644
--- a/src/theory/arrays/array_info.cpp
+++ b/src/theory/arrays/array_info.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Clark Barrett, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arrays/array_info.h b/src/theory/arrays/array_info.h
index d472277c7..d95e2c7cd 100644
--- a/src/theory/arrays/array_info.h
+++ b/src/theory/arrays/array_info.h
@@ -5,7 +5,7 @@
** Morgan Deters, Clark Barrett, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arrays/array_proof_reconstruction.cpp b/src/theory/arrays/array_proof_reconstruction.cpp
deleted file mode 100644
index abc4857e8..000000000
--- a/src/theory/arrays/array_proof_reconstruction.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-/********************* */
-/*! \file array_proof_reconstruction.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Guy Katz, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** [[ Add lengthier description here ]]
-
- ** \todo document this file
-
-**/
-
-#include "theory/arrays/array_proof_reconstruction.h"
-
-#include <memory>
-
-namespace CVC4 {
-namespace theory {
-namespace arrays {
-
-ArrayProofReconstruction::ArrayProofReconstruction(const eq::EqualityEngine* equalityEngine)
- : d_equalityEngine(equalityEngine) {
-}
-
-void ArrayProofReconstruction::setRowMergeTag(unsigned tag) {
- d_reasonRow = tag;
-}
-
-void ArrayProofReconstruction::setRow1MergeTag(unsigned tag) {
- d_reasonRow1 = tag;
-}
-
-void ArrayProofReconstruction::setExtMergeTag(unsigned tag) {
- d_reasonExt = tag;
-}
-
-void ArrayProofReconstruction::notify(
- unsigned reasonType, Node reason, Node a, Node b,
- std::vector<TNode>& equalities, eq::EqProof* proof) const {
- Debug("pf::array") << "ArrayProofReconstruction::notify( "
- << reason << ", " << a << ", " << b << std::endl;
-
-
- if (reasonType == d_reasonExt) {
- if (proof) {
- // Todo: here we assume that a=b is an assertion. We should probably call
- // explain() recursively, to explain this.
- std::shared_ptr<eq::EqProof> childProof = std::make_shared<eq::EqProof>();
- childProof->d_node = reason;
- proof->d_children.push_back(childProof);
- }
- }
-
- else if (reasonType == d_reasonRow) {
- // ROW rules mean that (i==k) OR ((a[i]:=t)[k] == a[k])
- // The equality here will be either (i == k) because ((a[i]:=t)[k] != a[k]),
- // or ((a[i]:=t)[k] == a[k]) because (i != k).
-
- if (proof) {
- if (a.getKind() == kind::SELECT) {
- // This is the case of ((a[i]:=t)[k] == a[k]) because (i != k).
-
- // The edge is ((a[i]:=t)[k], a[k]), or (a[k], (a[i]:=t)[k]). This flag should be
- // false in the first case and true in the second case.
- bool currentNodeIsUnchangedArray;
-
- Assert(a.getNumChildren() == 2);
- Assert(b.getNumChildren() == 2);
-
- if (a[0].getKind() == kind::VARIABLE || a[0].getKind() == kind::SKOLEM) {
- currentNodeIsUnchangedArray = true;
- } else if (b[0].getKind() == kind::VARIABLE || b[0].getKind() == kind::SKOLEM) {
- currentNodeIsUnchangedArray = false;
- } else {
- Assert(a[0].getKind() == kind::STORE);
- Assert(b[0].getKind() == kind::STORE);
-
- if (a[0][0] == b[0]) {
- currentNodeIsUnchangedArray = false;
- } else if (b[0][0] == a[0]) {
- currentNodeIsUnchangedArray = true;
- } else {
- Unreachable();
- }
- }
-
- Node indexOne = currentNodeIsUnchangedArray ? a[1] : a[0][1];
- Node indexTwo = currentNodeIsUnchangedArray ? b[0][1] : b[1];
-
- // Some assertions to ensure that the theory of arrays behaves as expected
- Assert(a[1] == b[1]);
- if (currentNodeIsUnchangedArray) {
- Assert(a[0] == b[0][0]);
- } else {
- Assert(a[0][0] == b[0]);
- }
-
- Debug("pf::ee") << "Getting explanation for ROW guard: "
- << indexOne << " != " << indexTwo << std::endl;
-
- std::shared_ptr<eq::EqProof> childProof =
- std::make_shared<eq::EqProof>();
- d_equalityEngine->explainEquality(indexOne, indexTwo, false, equalities,
- childProof.get());
-
- // It could be that the guard condition is a constant disequality. In
- // this case, we need to change it to a different format.
- bool haveNegChild = false;
- for (unsigned i = 0; i < childProof->d_children.size(); ++i) {
- if (childProof->d_children[i]->d_node.getKind() == kind::NOT)
- haveNegChild = true;
- }
-
- if ((childProof->d_children.size() != 0) &&
- (childProof->d_id == theory::eq::MERGED_THROUGH_CONSTANTS || !haveNegChild)) {
- // The proof has two children, explaining why each index is a (different) constant.
- Assert(childProof->d_children.size() == 2);
-
- Node constantOne, constantTwo;
- // Each subproof explains why one of the indices is constant.
-
- if (childProof->d_children[0]->d_id == theory::eq::MERGED_THROUGH_REFLEXIVITY) {
- constantOne = childProof->d_children[0]->d_node;
- } else {
- Assert(childProof->d_children[0]->d_node.getKind() == kind::EQUAL);
- if ((childProof->d_children[0]->d_node[0] == indexOne) ||
- (childProof->d_children[0]->d_node[0] == indexTwo)) {
- constantOne = childProof->d_children[0]->d_node[1];
- } else {
- constantOne = childProof->d_children[0]->d_node[0];
- }
- }
-
- if (childProof->d_children[1]->d_id == theory::eq::MERGED_THROUGH_REFLEXIVITY) {
- constantTwo = childProof->d_children[1]->d_node;
- } else {
- Assert(childProof->d_children[1]->d_node.getKind() == kind::EQUAL);
- if ((childProof->d_children[1]->d_node[0] == indexOne) ||
- (childProof->d_children[1]->d_node[0] == indexTwo)) {
- constantTwo = childProof->d_children[1]->d_node[1];
- } else {
- constantTwo = childProof->d_children[1]->d_node[0];
- }
- }
-
- std::shared_ptr<eq::EqProof> constantDisequalityProof =
- std::make_shared<eq::EqProof>();
- constantDisequalityProof->d_id = theory::eq::MERGED_THROUGH_CONSTANTS;
- constantDisequalityProof->d_node =
- NodeManager::currentNM()->mkNode(kind::EQUAL, constantOne, constantTwo).negate();
-
- // Middle is where we need to insert the new disequality
- std::vector<std::shared_ptr<eq::EqProof>>::iterator middle =
- childProof->d_children.begin();
- ++middle;
-
- childProof->d_children.insert(middle, constantDisequalityProof);
-
- childProof->d_id = theory::eq::MERGED_THROUGH_TRANS;
- childProof->d_node =
- NodeManager::currentNM()->mkNode(kind::EQUAL, indexOne, indexTwo).negate();
- }
-
- proof->d_children.push_back(childProof);
- } else {
- // This is the case of (i == k) because ((a[i]:=t)[k] != a[k]),
-
- Node indexOne = a;
- Node indexTwo = b;
-
- Debug("pf::ee") << "The two indices are: " << indexOne << ", " << indexTwo << std::endl
- << "The reason for the edge is: " << reason << std::endl;
-
- Assert(reason.getNumChildren() == 2);
- Debug("pf::ee") << "Getting explanation for ROW guard: " << reason[1] << std::endl;
-
- std::shared_ptr<eq::EqProof> childProof =
- std::make_shared<eq::EqProof>();
- d_equalityEngine->explainEquality(reason[1][0], reason[1][1], false,
- equalities, childProof.get());
- proof->d_children.push_back(childProof);
- }
- }
-
- }
-
- else if (reasonType == d_reasonRow1) {
- // No special handling required at this time
- }
-}
-
-}/* CVC4::theory::arrays namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
diff --git a/src/theory/arrays/array_proof_reconstruction.h b/src/theory/arrays/array_proof_reconstruction.h
deleted file mode 100644
index a73b5dd08..000000000
--- a/src/theory/arrays/array_proof_reconstruction.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/********************* */
-/*! \file array_proof_reconstruction.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Paul Meng, Mathias Preiner, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Array-specific proof construction logic to be used during the
- ** equality engine's path reconstruction
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__THEORY__ARRAYS__ARRAY_PROOF_RECONSTRUCTION_H
-#define CVC4__THEORY__ARRAYS__ARRAY_PROOF_RECONSTRUCTION_H
-
-#include "theory/uf/equality_engine.h"
-
-namespace CVC4 {
-namespace theory {
-namespace arrays {
-
-/**
- * A callback class to be invoked whenever the equality engine traverses
- * an "array-owned" edge during path reconstruction.
- */
-
-class ArrayProofReconstruction : public eq::PathReconstructionNotify {
-public:
- ArrayProofReconstruction(const eq::EqualityEngine* equalityEngine);
-
- void notify(unsigned reasonType, Node reason, Node a, Node b,
- std::vector<TNode>& equalities,
- eq::EqProof* proof) const override;
-
- void setRowMergeTag(unsigned tag);
- void setRow1MergeTag(unsigned tag);
- void setExtMergeTag(unsigned tag);
-
-private:
- /** Merge tag for ROW applications */
- unsigned d_reasonRow;
- /** Merge tag for ROW1 applications */
- unsigned d_reasonRow1;
- /** Merge tag for EXT applications */
- unsigned d_reasonExt;
-
- const eq::EqualityEngine* d_equalityEngine;
-}; /* class ArrayProofReconstruction */
-
-}/* CVC4::theory::arrays namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* CVC4__THEORY__ARRAYS__ARRAY_PROOF_RECONSTRUCTION_H */
diff --git a/src/theory/arrays/inference_manager.cpp b/src/theory/arrays/inference_manager.cpp
new file mode 100644
index 000000000..f429140be
--- /dev/null
+++ b/src/theory/arrays/inference_manager.cpp
@@ -0,0 +1,128 @@
+/********************* */
+/*! \file inference_manager.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Arrays inference manager
+ **/
+
+#include "theory/arrays/inference_manager.h"
+
+#include "options/smt_options.h"
+#include "theory/theory.h"
+#include "theory/uf/equality_engine.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace arrays {
+
+InferenceManager::InferenceManager(Theory& t,
+ TheoryState& state,
+ ProofNodeManager* pnm)
+ : TheoryInferenceManager(t, state, pnm),
+ d_lemmaPg(pnm ? new EagerProofGenerator(pnm,
+ state.getUserContext(),
+ "ArrayLemmaProofGenerator")
+ : nullptr)
+{
+}
+
+bool InferenceManager::assertInference(TNode atom,
+ bool polarity,
+ TNode reason,
+ PfRule id)
+{
+ Trace("arrays-infer") << "TheoryArrays::assertInference: "
+ << (polarity ? Node(atom) : atom.notNode()) << " by "
+ << reason << "; " << id << std::endl;
+ Assert(atom.getKind() == EQUAL);
+ // if proofs are enabled, we determine which proof rule to add, otherwise
+ // we simply assert the internal fact
+ if (isProofEnabled())
+ {
+ Node fact = polarity ? Node(atom) : atom.notNode();
+ std::vector<Node> children;
+ std::vector<Node> args;
+ // convert to proof rule application
+ convert(id, fact, reason, children, args);
+ return assertInternalFact(atom, polarity, id, children, args);
+ }
+ return assertInternalFact(atom, polarity, reason);
+}
+
+bool InferenceManager::arrayLemma(
+ Node conc, Node exp, PfRule id, LemmaProperty p, bool doCache)
+{
+ Trace("arrays-infer") << "TheoryArrays::arrayLemma: " << conc << " by " << exp
+ << "; " << id << std::endl;
+ NodeManager* nm = NodeManager::currentNM();
+ if (isProofEnabled())
+ {
+ std::vector<Node> children;
+ std::vector<Node> args;
+ // convert to proof rule application
+ convert(id, conc, exp, children, args);
+ // make the trusted lemma based on the eager proof generator and send
+ TrustNode tlem = d_lemmaPg->mkTrustNode(conc, id, children, args);
+ return trustedLemma(tlem, p, doCache);
+ }
+ // send lemma without proofs
+ Node lem = nm->mkNode(IMPLIES, exp, conc);
+ return lemma(lem, p, doCache);
+}
+
+void InferenceManager::convert(PfRule& id,
+ Node conc,
+ Node exp,
+ std::vector<Node>& children,
+ std::vector<Node>& args)
+{
+ // note that children must contain something equivalent to exp,
+ // regardless of the PfRule.
+ switch (id)
+ {
+ case PfRule::MACRO_SR_PRED_INTRO:
+ Assert(exp.isConst());
+ args.push_back(conc);
+ break;
+ case PfRule::ARRAYS_READ_OVER_WRITE:
+ if (exp.isConst())
+ {
+ // Premise can be shown by rewriting, use standard predicate intro rule.
+ // This is the case where we have 2 constant indices.
+ id = PfRule::MACRO_SR_PRED_INTRO;
+ args.push_back(conc);
+ }
+ else
+ {
+ children.push_back(exp);
+ args.push_back(conc[0]);
+ }
+ break;
+ case PfRule::ARRAYS_READ_OVER_WRITE_CONTRA: children.push_back(exp); break;
+ case PfRule::ARRAYS_READ_OVER_WRITE_1:
+ Assert(exp.isConst());
+ args.push_back(conc[0]);
+ break;
+ case PfRule::ARRAYS_EXT: children.push_back(exp); break;
+ default:
+ // unknown rule, should never happen
+ Assert(false);
+ children.push_back(exp);
+ args.push_back(conc);
+ id = PfRule::ARRAYS_TRUST;
+ break;
+ }
+}
+
+} // namespace arrays
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arrays/inference_manager.h b/src/theory/arrays/inference_manager.h
new file mode 100644
index 000000000..2073fac6a
--- /dev/null
+++ b/src/theory/arrays/inference_manager.h
@@ -0,0 +1,77 @@
+/********************* */
+/*! \file inference_manager.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Arrays inference manager
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__ARRAYS__INFERENCE_MANAGER_H
+#define CVC4__THEORY__ARRAYS__INFERENCE_MANAGER_H
+
+#include "expr/node.h"
+#include "expr/proof_rule.h"
+#include "theory/eager_proof_generator.h"
+#include "theory/theory_inference_manager.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arrays {
+
+/**
+ * The arrays inference manager.
+ */
+class InferenceManager : public TheoryInferenceManager
+{
+ public:
+ InferenceManager(Theory& t, TheoryState& state, ProofNodeManager* pnm);
+ ~InferenceManager() {}
+
+ /**
+ * Assert inference. This sends an internal fact to the equality engine
+ * immediately, possibly with proof support. The identifier id which
+ * rule to apply when proofs are enabled. The order of children
+ * and arguments to use in the proof step are determined internally in
+ * this method.
+ *
+ * @return true if the fact was successfully asserted, and false if the
+ * fact was redundant.
+ */
+ bool assertInference(TNode atom, bool polarity, TNode reason, PfRule id);
+ /**
+ * Send lemma (exp => conc) based on proof rule id with properties p. Cache
+ * the lemma if doCache is true.
+ */
+ bool arrayLemma(Node conc,
+ Node exp,
+ PfRule id,
+ LemmaProperty p = LemmaProperty::NONE,
+ bool doCache = false);
+
+ private:
+ /**
+ * Converts a conclusion, explanation and proof rule id used by the array
+ * theory to the set of arguments required for a proof rule application.
+ */
+ void convert(PfRule& id,
+ Node conc,
+ Node exp,
+ std::vector<Node>& children,
+ std::vector<Node>& args);
+ /** Eager proof generator for lemmas from the above method */
+ std::unique_ptr<EagerProofGenerator> d_lemmaPg;
+};
+
+} // namespace arrays
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arrays/kinds b/src/theory/arrays/kinds
index 659f05ae8..629064d99 100644
--- a/src/theory/arrays/kinds
+++ b/src/theory/arrays/kinds
@@ -8,7 +8,7 @@ theory THEORY_ARRAYS ::CVC4::theory::arrays::TheoryArrays "theory/arrays/theory_
typechecker "theory/arrays/theory_arrays_type_rules.h"
properties polite stable-infinite parametric
-properties check propagate presolve
+properties check presolve
rewriter ::CVC4::theory::arrays::TheoryArraysRewriter "theory/arrays/theory_arrays_rewriter.h"
diff --git a/src/theory/arrays/proof_checker.cpp b/src/theory/arrays/proof_checker.cpp
new file mode 100644
index 000000000..a3cd82678
--- /dev/null
+++ b/src/theory/arrays/proof_checker.cpp
@@ -0,0 +1,118 @@
+/********************* */
+/*! \file proof_checker.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Haniel Barbosa
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of arrays proof checker
+ **/
+
+#include "theory/arrays/proof_checker.h"
+#include "expr/skolem_manager.h"
+#include "theory/arrays/skolem_cache.h"
+#include "theory/rewriter.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arrays {
+
+void ArraysProofRuleChecker::registerTo(ProofChecker* pc)
+{
+ pc->registerChecker(PfRule::ARRAYS_READ_OVER_WRITE, this);
+ pc->registerChecker(PfRule::ARRAYS_READ_OVER_WRITE_CONTRA, this);
+ pc->registerChecker(PfRule::ARRAYS_READ_OVER_WRITE_1, this);
+ pc->registerChecker(PfRule::ARRAYS_EXT, this);
+ // trusted rules
+ pc->registerTrustedChecker(PfRule::ARRAYS_TRUST, this, 2);
+}
+
+Node ArraysProofRuleChecker::checkInternal(PfRule id,
+ const std::vector<Node>& children,
+ const std::vector<Node>& args)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ if (id == PfRule::ARRAYS_READ_OVER_WRITE)
+ {
+ Assert(children.size() == 1);
+ Assert(args.size() == 1);
+ Node ideq = children[0];
+ if (ideq.getKind() != kind::NOT || ideq[0].getKind() != kind::EQUAL)
+ {
+ return Node::null();
+ }
+ Node lhs = args[0];
+ if (lhs.getKind() != kind::SELECT || lhs[0].getKind() != kind::STORE
+ || lhs[0][1] != ideq[0][0])
+ {
+ return Node::null();
+ }
+ Node rhs = nm->mkNode(kind::SELECT, lhs[0][0], ideq[0][1]);
+ return lhs.eqNode(rhs);
+ }
+ else if (id == PfRule::ARRAYS_READ_OVER_WRITE_CONTRA)
+ {
+ Assert(children.size() == 1);
+ Assert(args.empty());
+ Node adeq = children[0];
+ if (adeq.getKind() != kind::NOT || adeq[0].getKind() != kind::EQUAL)
+ {
+ return Node::null();
+ }
+ Node lhs = adeq[0][0];
+ Node rhs = adeq[0][1];
+ if (lhs.getKind() != kind::SELECT || lhs[0].getKind() != kind::STORE
+ || rhs.getKind() != kind::SELECT || lhs[1] != rhs[1])
+ {
+ return Node::null();
+ }
+ return lhs[1].eqNode(lhs[0][1]);
+ }
+ if (id == PfRule::ARRAYS_READ_OVER_WRITE_1)
+ {
+ Assert(children.empty());
+ Assert(args.size() == 1);
+ Node lhs = args[0];
+ if (lhs.getKind() != kind::SELECT || lhs[0].getKind() != kind::STORE
+ || lhs[0][1] != lhs[1])
+ {
+ return Node::null();
+ }
+ Node rhs = lhs[0][2];
+ return lhs.eqNode(rhs);
+ }
+ if (id == PfRule::ARRAYS_EXT)
+ {
+ Assert(children.size() == 1);
+ Assert(args.empty());
+ Node adeq = children[0];
+ if (adeq.getKind() != kind::NOT || adeq[0].getKind() != kind::EQUAL
+ || !adeq[0][0].getType().isArray())
+ {
+ return Node::null();
+ }
+ Node k = SkolemCache::getExtIndexSkolem(adeq);
+ Node a = adeq[0][0];
+ Node b = adeq[0][1];
+ Node as = nm->mkNode(kind::SELECT, a, k);
+ Node bs = nm->mkNode(kind::SELECT, b, k);
+ return as.eqNode(bs).notNode();
+ }
+ if (id == PfRule::ARRAYS_TRUST)
+ {
+ // "trusted" rules
+ Assert(!args.empty());
+ Assert(args[0].getType().isBoolean());
+ return args[0];
+ }
+ // no rule
+ return Node::null();
+}
+
+} // namespace arrays
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arrays/proof_checker.h b/src/theory/arrays/proof_checker.h
new file mode 100644
index 000000000..3bf7afecb
--- /dev/null
+++ b/src/theory/arrays/proof_checker.h
@@ -0,0 +1,49 @@
+/********************* */
+/*! \file proof_checker.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Array proof checker utility
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__ARRAYS__PROOF_CHECKER_H
+#define CVC4__THEORY__ARRAYS__PROOF_CHECKER_H
+
+#include "expr/node.h"
+#include "expr/proof_checker.h"
+#include "expr/proof_node.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arrays {
+
+/** A checker for array reasoning in proofs */
+class ArraysProofRuleChecker : public ProofRuleChecker
+{
+ public:
+ ArraysProofRuleChecker() {}
+ ~ArraysProofRuleChecker() {}
+
+ /** Register all rules owned by this rule checker into pc. */
+ void registerTo(ProofChecker* pc) override;
+
+ protected:
+ /** Return the conclusion of the given proof step, or null if it is invalid */
+ Node checkInternal(PfRule id,
+ const std::vector<Node>& children,
+ const std::vector<Node>& args) override;
+};
+
+} // namespace arrays
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__ARRAYS__PROOF_CHECKER_H */
diff --git a/src/theory/arrays/skolem_cache.cpp b/src/theory/arrays/skolem_cache.cpp
new file mode 100644
index 000000000..70217a4d7
--- /dev/null
+++ b/src/theory/arrays/skolem_cache.cpp
@@ -0,0 +1,87 @@
+/********************* */
+/*! \file skolem_cache.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Arrays skolem cache
+ **/
+
+#include "theory/arrays/skolem_cache.h"
+
+#include "expr/attribute.h"
+#include "expr/skolem_manager.h"
+#include "expr/type_node.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace arrays {
+
+/**
+ * A bound variable corresponding to an index for witnessing the satisfiability
+ * of array disequalities.
+ */
+struct ExtIndexVarAttributeId
+{
+};
+typedef expr::Attribute<ExtIndexVarAttributeId, Node> ExtIndexVarAttribute;
+
+SkolemCache::SkolemCache() {}
+
+Node SkolemCache::getExtIndexSkolem(Node deq)
+{
+ Assert(deq.getKind() == NOT && deq[0].getKind() == EQUAL);
+ Node a = deq[0][0];
+ Node b = deq[0][1];
+ Assert(a.getType().isArray());
+ Assert(b.getType() == a.getType());
+
+ NodeManager* nm = NodeManager::currentNM();
+
+ // get the reference index, which notice is deterministic for a, b in the
+ // lifetime of the node manager
+ Node x = getExtIndexVar(deq);
+
+ // make the axiom for x
+ Node as = nm->mkNode(SELECT, a, x);
+ Node bs = nm->mkNode(SELECT, b, x);
+ Node deqIndex = as.eqNode(bs).notNode();
+ Node axiom = nm->mkNode(IMPLIES, deq, deqIndex);
+
+ // make the skolem that witnesses the above axiom
+ SkolemManager* sm = nm->getSkolemManager();
+ return sm->mkSkolem(
+ x,
+ axiom,
+ "array_ext_index",
+ "an extensional lemma index variable from the theory of arrays");
+}
+
+Node SkolemCache::getExtIndexVar(Node deq)
+{
+ ExtIndexVarAttribute eiva;
+ if (deq.hasAttribute(eiva))
+ {
+ return deq.getAttribute(eiva);
+ }
+ Node a = deq[0][0];
+ Node b = deq[0][1];
+ TypeNode atn = a.getType();
+ Assert(atn.isArray());
+ Assert(atn == b.getType());
+ TypeNode atnIndex = atn.getArrayIndexType();
+ Node v = NodeManager::currentNM()->mkBoundVar(atnIndex);
+ deq.setAttribute(eiva, v);
+ return v;
+}
+
+} // namespace arrays
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/arrays/skolem_cache.h b/src/theory/arrays/skolem_cache.h
new file mode 100644
index 000000000..b07e87dc6
--- /dev/null
+++ b/src/theory/arrays/skolem_cache.h
@@ -0,0 +1,57 @@
+/********************* */
+/*! \file skolem_cache.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Arrays skolem cache
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__ARRAYS__SKOLEM_CACHE_H
+#define CVC4__THEORY__ARRAYS__SKOLEM_CACHE_H
+
+#include "expr/node.h"
+
+namespace CVC4 {
+namespace theory {
+namespace arrays {
+
+/**
+ * The arrays skolem cache, which provides static methods for constructing
+ * skolems with witness forms.
+ */
+class SkolemCache
+{
+ public:
+ SkolemCache();
+ ~SkolemCache() {}
+
+ /**
+ * Get the skolem correspoding to the index that witnesses the disequality
+ * deq between arrays a and b. The witness form of this skolem is:
+ * (witness ((x T)) (=> (not (= a b)) (not (= (select a x) (select b x)))))
+ * This skolem is unique for deq, calling this method will always return the
+ * same skolem over the lifetime of deq.
+ */
+ static Node getExtIndexSkolem(Node deq);
+
+ private:
+ /**
+ * Get the bound variable x of the witness term above for disequality deq
+ * between arrays.
+ */
+ static Node getExtIndexVar(Node deq);
+};
+
+} // namespace arrays
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/arrays/static_fact_manager.cpp b/src/theory/arrays/static_fact_manager.cpp
deleted file mode 100644
index d2f4b75c9..000000000
--- a/src/theory/arrays/static_fact_manager.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/********************* */
-/*! \file static_fact_manager.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Clark Barrett, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Path-compressing, backtrackable union-find using an undo
- ** stack. Refactored from the UF union-find.
- **
- ** Path-compressing, backtrackable union-find using an undo stack
- ** rather than storing items in a CDMap<>.
- **/
-
-#include <iostream>
-
-#include "base/check.h"
-#include "expr/node.h"
-#include "theory/arrays/static_fact_manager.h"
-
-using namespace std;
-
-namespace CVC4 {
-namespace theory {
-namespace arrays {
-
-bool StaticFactManager::areEq(TNode a, TNode b) {
- return (find(a) == find(b));
-}
-
-bool StaticFactManager::areDiseq(TNode a, TNode b) {
- Node af = find(a);
- Node bf = find(b);
- Node left, right;
- unsigned i;
- for (i = 0; i < d_diseq.size(); ++i) {
- left = find(d_diseq[i][0]);
- right = find(d_diseq[i][1]);
- if ((left == af && right == bf) ||
- (left == bf && right == af)) {
- return true;
- }
- }
- return false;
-}
-
-void StaticFactManager::addDiseq(TNode eq) {
- Assert(eq.getKind() == kind::EQUAL);
- d_diseq.push_back(eq);
-}
-
-void StaticFactManager::addEq(TNode eq) {
- Assert(eq.getKind() == kind::EQUAL);
- Node a = find(eq[0]);
- Node b = find(eq[1]);
-
- if( a == b) {
- return;
- }
-
- /*
- * take care of the congruence closure part
- */
-
- // make "a" the one with shorter diseqList
- // CNodeTNodesMap::iterator deq_ia = d_disequalities.find(a);
- // CNodeTNodesMap::iterator deq_ib = d_disequalities.find(b);
-
- // if(deq_ia != d_disequalities.end()) {
- // if(deq_ib == d_disequalities.end() ||
- // (*deq_ia).second->size() > (*deq_ib).second->size()) {
- // TNode tmp = a;
- // a = b;
- // b = tmp;
- // }
- // }
- // a = find(a);
- // b = find(b);
-
-
- // b becomes the canon of a
- setCanon(a, b);
-
- // deq_ia = d_disequalities.find(a);
- // map<TNode, TNode> alreadyDiseqs;
- // if(deq_ia != d_disequalities.end()) {
- // /*
- // * Collecting the disequalities of b, no need to check for conflicts
- // * since the representative of b does not change and we check all the things
- // * in a's class when we look at the diseq list of find(a)
- // */
-
- // CNodeTNodesMap::iterator deq_ib = d_disequalities.find(b);
- // if(deq_ib != d_disequalities.end()) {
- // CTNodeListAlloc* deq = (*deq_ib).second;
- // for(CTNodeListAlloc::const_iterator j = deq->begin(); j!=deq->end();
- // j++) {
- // TNode deqn = *j;
- // TNode s = deqn[0];
- // TNode t = deqn[1];
- // TNode sp = find(s);
- // TNode tp = find(t);
- // Assert(sp == b || tp == b);
- // if(sp == b) {
- // alreadyDiseqs[tp] = deqn;
- // } else {
- // alreadyDiseqs[sp] = deqn;
- // }
- // }
- // }
-
- // /*
- // * Looking for conflicts in the a disequality list. Note
- // * that at this point a and b are already merged. Also has
- // * the side effect that it adds them to the list of b (which
- // * became the canonical representative)
- // */
-
- // CTNodeListAlloc* deqa = (*deq_ia).second;
- // for(CTNodeListAlloc::const_iterator i = deqa->begin(); i!= deqa->end();
- // i++) {
- // TNode deqn = (*i);
- // Assert(deqn.getKind() == kind::EQUAL || deqn.getKind() ==
- // kind::IFF); TNode s = deqn[0]; TNode t = deqn[1]; TNode sp = find(s);
- // TNode tp = find(t);
-
- // if(find(s) == find(t)) {
- // d_conflict = deqn;
- // return;
- // }
- // Assert( sp == b || tp == b);
-
- // // make sure not to add duplicates
-
- // if(sp == b) {
- // if(alreadyDiseqs.find(tp) == alreadyDiseqs.end()) {
- // appendToDiseqList(b, deqn);
- // alreadyDiseqs[tp] = deqn;
- // }
- // } else {
- // if(alreadyDiseqs.find(sp) == alreadyDiseqs.end()) {
- // appendToDiseqList(b, deqn);
- // alreadyDiseqs[sp] = deqn;
- // }
- // }
-
- // }
- // }
-
- // // TODO: check for equality propagations
- // // a and b are find(a) and find(b) here
- // checkPropagations(a,b);
-
- // if(a.getType().isArray()) {
- // checkRowLemmas(a,b);
- // checkRowLemmas(b,a);
- // // note the change in order, merge info adds the list of
- // // the 2nd argument to the first
- // d_infoMap.mergeInfo(b, a);
- // }
-}
-
-
-}/* CVC4::theory::arrays namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
diff --git a/src/theory/arrays/static_fact_manager.h b/src/theory/arrays/static_fact_manager.h
deleted file mode 100644
index 2df4b0fda..000000000
--- a/src/theory/arrays/static_fact_manager.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/********************* */
-/*! \file static_fact_manager.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Clark Barrett, Mathias Preiner, Morgan Deters
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Path-compressing, backtrackable union-find using an undo
- ** stack. Refactored from the UF union-find.
- **
- ** Path-compressing, backtrackable union-find using an undo stack
- ** rather than storing items in a CDMap<>.
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__THEORY__ARRAYS__STATIC_FACT_MANAGER_H
-#define CVC4__THEORY__ARRAYS__STATIC_FACT_MANAGER_H
-
-#include <utility>
-#include <vector>
-#include <unordered_map>
-
-#include "expr/node.h"
-
-namespace CVC4 {
-namespace theory {
-namespace arrays {
-
- class StaticFactManager {
- /** Our underlying map type. */
- typedef std::unordered_map<Node, Node, NodeHashFunction> MapType;
-
- /**
- * Our map of Nodes to their canonical representatives.
- * If a Node is not present in the map, it is its own
- * representative.
- */
- MapType d_map;
- std::vector<Node> d_diseq;
-
-public:
- StaticFactManager() {}
-
- /**
- * Return a Node's union-find representative, doing path compression.
- */
- inline TNode find(TNode n);
-
- /**
- * Return a Node's union-find representative, NOT doing path compression.
- * This is useful for Assert() statements, debug checking, and similar
- * things that you do NOT want to mutate the structure.
- */
- inline TNode debugFind(TNode n) const;
-
- /**
- * Set the canonical representative of n to newParent. They should BOTH
- * be their own canonical representatives on entry to this funciton.
- */
- inline void setCanon(TNode n, TNode newParent);
-
- bool areEq(TNode a, TNode b);
- bool areDiseq(TNode a, TNode b);
- void addDiseq(TNode eq);
- void addEq(TNode eq);
-
-};/* class StaticFactManager<> */
-
-inline TNode StaticFactManager::debugFind(TNode n) const {
- MapType::const_iterator i = d_map.find(n);
- if(i == d_map.end()) {
- return n;
- } else {
- return debugFind((*i).second);
- }
-}
-
-inline TNode StaticFactManager::find(TNode n) {
- Trace("arraysuf") << "arraysUF find of " << n << std::endl;
- MapType::iterator i = d_map.find(n);
- if(i == d_map.end()) {
- Trace("arraysuf") << "arraysUF it is rep" << std::endl;
- return n;
- } else {
- Trace("arraysuf") << "arraysUF not rep: par is " << (*i).second << std::endl;
- std::pair<TNode, TNode> pr = *i;
- // our iterator is invalidated by the recursive call to find(),
- // since it mutates the map
- TNode p = find(pr.second);
- if(p == pr.second) {
- return p;
- }
- pr.second = p;
- d_map.insert(pr);
- return p;
- }
-}
-
-inline void StaticFactManager::setCanon(TNode n, TNode newParent) {
- Assert(d_map.find(n) == d_map.end());
- Assert(d_map.find(newParent) == d_map.end());
- if(n != newParent) {
- d_map[n] = newParent;
- }
-}
-
-}/* CVC4::theory::arrays namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /*CVC4__THEORY__ARRAYS__STATIC_FACT_MANAGER_H */
diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp
index 37443c070..3e59aebe6 100644
--- a/src/theory/arrays/theory_arrays.cpp
+++ b/src/theory/arrays/theory_arrays.cpp
@@ -2,10 +2,10 @@
/*! \file theory_arrays.cpp
** \verbatim
** Top contributors (to current version):
- ** Clark Barrett, Morgan Deters, Guy Katz
+ ** Clark Barrett, Andrew Reynolds, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,14 +21,12 @@
#include "expr/kind.h"
#include "expr/node_algorithm.h"
+#include "expr/proof_checker.h"
#include "options/arrays_options.h"
#include "options/smt_options.h"
-#include "proof/array_proof.h"
-#include "proof/proof_manager.h"
-#include "proof/theory_proof.h"
-#include "smt/command.h"
#include "smt/logic_exception.h"
#include "smt/smt_statistics_registry.h"
+#include "theory/arrays/skolem_cache.h"
#include "theory/arrays/theory_arrays_rewriter.h"
#include "theory/rewriter.h"
#include "theory/theory_model.h"
@@ -46,7 +44,6 @@ namespace arrays {
// Use static configuration of options for now
const bool d_ccStore = false;
-const bool d_useArrTable = false;
//const bool d_eagerLemmas = false;
const bool d_preprocess = true;
const bool d_solveWrite = true;
@@ -54,7 +51,6 @@ const bool d_solveWrite2 = false;
// These are now options
//const bool d_propagateLemmas = true;
//bool d_useNonLinearOpt = true;
- //bool d_lazyRIntro1 = true;
//bool d_eagerIndexSplitting = false;
TheoryArrays::TheoryArrays(context::Context* c,
@@ -83,14 +79,13 @@ TheoryArrays::TheoryArrays(context::Context* c,
name + "theory::arrays::number of setModelVal conflicts", 0),
d_ppEqualityEngine(u, name + "theory::arrays::pp", true),
d_ppFacts(u),
- // d_ppCache(u),
+ d_state(c, u, valuation),
+ d_im(*this, d_state, pnm),
d_literalsToPropagate(c),
d_literalsToPropagateIndex(c, 0),
d_isPreRegistered(c),
d_mayEqualEqualityEngine(c, name + "theory::arrays::mayEqual", true),
d_notify(*this),
- d_equalityEngine(d_notify, c, name + "theory::arrays", true),
- d_conflict(c, false),
d_backtracker(c),
d_infoMap(c, &d_backtracker, name),
d_mergeQueue(c),
@@ -113,7 +108,6 @@ TheoryArrays::TheoryArrays(context::Context* c,
d_readTableContext(new context::Context()),
d_arrayMerges(c),
d_inCheckModel(false),
- d_proofReconstruction(&d_equalityEngine),
d_dstrat(new TheoryArraysDecisionStrategy(this)),
d_dstratInit(false)
{
@@ -135,26 +129,15 @@ TheoryArrays::TheoryArrays(context::Context* c,
d_ppEqualityEngine.addFunctionKind(kind::SELECT);
d_ppEqualityEngine.addFunctionKind(kind::STORE);
- // The kinds we are treating as function application in congruence
- d_equalityEngine.addFunctionKind(kind::SELECT);
- if (d_ccStore) {
- d_equalityEngine.addFunctionKind(kind::STORE);
- }
- if (d_useArrTable) {
- d_equalityEngine.addFunctionKind(kind::ARR_TABLE_FUN);
+ ProofChecker* pc = pnm != nullptr ? pnm->getChecker() : nullptr;
+ if (pc != nullptr)
+ {
+ d_pchecker.registerTo(pc);
}
-
- d_reasonRow = d_equalityEngine.getFreshMergeReasonType();
- d_reasonRow1 = d_equalityEngine.getFreshMergeReasonType();
- d_reasonExt = d_equalityEngine.getFreshMergeReasonType();
-
- d_proofReconstruction.setRowMergeTag(d_reasonRow);
- d_proofReconstruction.setRow1MergeTag(d_reasonRow1);
- d_proofReconstruction.setExtMergeTag(d_reasonExt);
-
- d_equalityEngine.addPathReconstructionTrigger(d_reasonRow, &d_proofReconstruction);
- d_equalityEngine.addPathReconstructionTrigger(d_reasonRow1, &d_proofReconstruction);
- d_equalityEngine.addPathReconstructionTrigger(d_reasonExt, &d_proofReconstruction);
+ // indicate we are using the default theory state object, and the arrays
+ // inference manager
+ d_theoryState = &d_state;
+ d_inferManager = &d_im;
}
TheoryArrays::~TheoryArrays() {
@@ -180,8 +163,25 @@ TheoryArrays::~TheoryArrays() {
smtStatisticsRegistry()->unregisterStat(&d_numSetModelValConflicts);
}
-void TheoryArrays::setMasterEqualityEngine(eq::EqualityEngine* eq) {
- d_equalityEngine.setMasterEqualityEngine(eq);
+TheoryRewriter* TheoryArrays::getTheoryRewriter() { return &d_rewriter; }
+
+bool TheoryArrays::needsEqualityEngine(EeSetupInfo& esi)
+{
+ esi.d_notify = &d_notify;
+ esi.d_name = d_instanceName + "theory::arrays::ee";
+ return true;
+}
+
+void TheoryArrays::finishInit()
+{
+ Assert(d_equalityEngine != nullptr);
+
+ // The kinds we are treating as function application in congruence
+ d_equalityEngine->addFunctionKind(kind::SELECT);
+ if (d_ccStore)
+ {
+ d_equalityEngine->addFunctionKind(kind::STORE);
+ }
}
/////////////////////////////////////////////////////////////////////////////
@@ -357,8 +357,10 @@ TrustNode TheoryArrays::ppRewrite(TNode term)
return TrustNode::null();
}
-
-Theory::PPAssertStatus TheoryArrays::ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
+Theory::PPAssertStatus TheoryArrays::ppAssert(
+ TrustNode tin, TrustSubstitutionMap& outSubstitutions)
+{
+ TNode in = tin.getNode();
switch(in.getKind()) {
case kind::EQUAL:
{
@@ -366,12 +368,12 @@ Theory::PPAssertStatus TheoryArrays::ppAssert(TNode in, SubstitutionMap& outSubs
d_ppEqualityEngine.assertEquality(in, true, in);
if (in[0].isVar() && isLegalElimination(in[0], in[1]))
{
- outSubstitutions.addSubstitution(in[0], in[1]);
+ outSubstitutions.addSubstitutionSolved(in[0], in[1], tin);
return PP_ASSERT_STATUS_SOLVED;
}
if (in[1].isVar() && isLegalElimination(in[1], in[0]))
{
- outSubstitutions.addSubstitution(in[1], in[0]);
+ outSubstitutions.addSubstitutionSolved(in[1], in[0], tin);
return PP_ASSERT_STATUS_SOLVED;
}
break;
@@ -397,14 +399,18 @@ Theory::PPAssertStatus TheoryArrays::ppAssert(TNode in, SubstitutionMap& outSubs
// T-PROPAGATION / REGISTRATION
/////////////////////////////////////////////////////////////////////////////
-
-bool TheoryArrays::propagate(TNode literal)
+bool TheoryArrays::propagateLit(TNode literal)
{
- Debug("arrays") << spaces(getSatContext()->getLevel()) << "TheoryArrays::propagate(" << literal << ")" << std::endl;
+ Debug("arrays") << spaces(getSatContext()->getLevel())
+ << "TheoryArrays::propagateLit(" << literal << ")"
+ << std::endl;
// If already in conflict, no more propagation
- if (d_conflict) {
- Debug("arrays") << spaces(getSatContext()->getLevel()) << "TheoryArrays::propagate(" << literal << "): already in conflict" << std::endl;
+ if (d_state.isInConflict())
+ {
+ Debug("arrays") << spaces(getSatContext()->getLevel())
+ << "TheoryArrays::propagateLit(" << literal
+ << "): already in conflict" << std::endl;
return false;
}
@@ -414,36 +420,12 @@ bool TheoryArrays::propagate(TNode literal)
}
bool ok = d_out->propagate(literal);
if (!ok) {
- d_conflict = true;
+ d_state.notifyInConflict();
}
return ok;
}/* TheoryArrays::propagate(TNode) */
-void TheoryArrays::explain(TNode literal, std::vector<TNode>& assumptions,
- eq::EqProof* proof) {
- // Do the work
- bool polarity = literal.getKind() != kind::NOT;
- TNode atom = polarity ? literal : literal[0];
- //eq::EqProof * eqp = new eq::EqProof;
- // eq::EqProof * eqp = NULL;
- if (atom.getKind() == kind::EQUAL) {
- d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions, proof);
- } else {
- d_equalityEngine.explainPredicate(atom, polarity, assumptions, proof);
- }
- if(proof){
- Debug("pf::array") << " Proof is : " << std::endl;
- proof->debug_print("pf::array");
- }
-
- Debug("pf::array") << "Array: explain( " << literal << " ):" << std::endl << "\t";
- for (unsigned i = 0; i < assumptions.size(); ++i) {
- Debug("pf::array") << assumptions[i] << " ";
- }
- Debug("pf::array") << std::endl;
-}
-
TNode TheoryArrays::weakEquivGetRep(TNode node) {
TNode pointer;
while (true) {
@@ -464,7 +446,8 @@ TNode TheoryArrays::weakEquivGetRepIndex(TNode node, TNode index) {
return node;
}
index2 = d_infoMap.getWeakEquivIndex(node);
- if (index2.isNull() || !d_equalityEngine.areEqual(index, index2)) {
+ if (index2.isNull() || !d_equalityEngine->areEqual(index, index2))
+ {
node = pointer;
}
else {
@@ -488,7 +471,8 @@ void TheoryArrays::visitAllLeaves(TNode reason, vector<TNode>& conjunctions) {
conjunctions.push_back(reason);
break;
case kind::EQUAL:
- d_equalityEngine.explainEquality(reason[0], reason[1], true, conjunctions);
+ d_equalityEngine->explainEquality(
+ reason[0], reason[1], true, conjunctions);
break;
default:
Unreachable();
@@ -506,10 +490,11 @@ void TheoryArrays::weakEquivBuildCond(TNode node, TNode index, vector<TNode>& co
index2 = d_infoMap.getWeakEquivIndex(node);
if (index2.isNull()) {
// Null index means these two nodes became equal: explain the equality.
- d_equalityEngine.explainEquality(node, pointer, true, conjunctions);
+ d_equalityEngine->explainEquality(node, pointer, true, conjunctions);
node = pointer;
}
- else if (!d_equalityEngine.areEqual(index, index2)) {
+ else if (!d_equalityEngine->areEqual(index, index2))
+ {
// If indices are not equal in current context, need to add that to the lemma.
Node reason = index.eqNode(index2).notNode();
d_permRef.push_back(reason);
@@ -551,7 +536,8 @@ void TheoryArrays::weakEquivMakeRepIndex(TNode node) {
TNode index2 = d_infoMap.getWeakEquivIndex(secondary);
Node reason;
TNode next;
- while (index2.isNull() || !d_equalityEngine.areEqual(index, index2)) {
+ while (index2.isNull() || !d_equalityEngine->areEqual(index, index2))
+ {
next = d_infoMap.getWeakEquivPointer(secondary);
d_infoMap.setWeakEquivSecondary(node, next);
reason = d_infoMap.getWeakEquivSecondaryReason(node);
@@ -585,13 +571,13 @@ void TheoryArrays::weakEquivAddSecondary(TNode index, TNode arrayFrom, TNode arr
TNode pointer, indexRep;
if (!index.isNull()) {
index_trail.push_back(index);
- marked.insert(d_equalityEngine.getRepresentative(index));
+ marked.insert(d_equalityEngine->getRepresentative(index));
}
while (arrayFrom != arrayTo) {
index = d_infoMap.getWeakEquivIndex(arrayFrom);
pointer = d_infoMap.getWeakEquivPointer(arrayFrom);
if (!index.isNull()) {
- indexRep = d_equalityEngine.getRepresentative(index);
+ indexRep = d_equalityEngine->getRepresentative(index);
if (marked.find(indexRep) == marked.end() && weakEquivGetRepIndex(arrayFrom, index) != arrayTo) {
weakEquivMakeRepIndex(arrayFrom);
d_infoMap.setWeakEquivSecondary(arrayFrom, arrayTo);
@@ -634,7 +620,7 @@ void TheoryArrays::checkWeakEquiv(bool arraysMerged) {
|| !secondary.isNull());
if (!pointer.isNull()) {
if (index.isNull()) {
- Assert(d_equalityEngine.areEqual(n, pointer));
+ Assert(d_equalityEngine->areEqual(n, pointer));
}
else {
Assert(
@@ -664,137 +650,135 @@ void TheoryArrays::checkWeakEquiv(bool arraysMerged) {
*/
void TheoryArrays::preRegisterTermInternal(TNode node)
{
- if (d_conflict) {
+ if (d_state.isInConflict())
+ {
return;
}
Debug("arrays") << spaces(getSatContext()->getLevel()) << "TheoryArrays::preRegisterTerm(" << node << ")" << std::endl;
- switch (node.getKind()) {
- case kind::EQUAL:
+ Kind nk = node.getKind();
+ if (nk == kind::EQUAL)
+ {
// Add the trigger for equality
// NOTE: note that if the equality is true or false already, it might not be added
- d_equalityEngine.addTriggerEquality(node);
- break;
- case kind::SELECT: {
+ d_equalityEngine->addTriggerPredicate(node);
+ return;
+ }
+ else if (d_equalityEngine->hasTerm(node))
+ {
// Invariant: array terms should be preregistered before being added to the equality engine
- if (d_equalityEngine.hasTerm(node)) {
- Assert(d_isPreRegistered.find(node) != d_isPreRegistered.end());
- return;
- }
- // Reads
- TNode store = d_equalityEngine.getRepresentative(node[0]);
-
- // The may equal needs the store
- d_mayEqualEqualityEngine.addTerm(store);
-
- if (node.getType().isArray())
+ Assert(nk != kind::SELECT
+ || d_isPreRegistered.find(node) != d_isPreRegistered.end());
+ return;
+ }
+ // add to equality engine and the may equality engine
+ TypeNode nodeType = node.getType();
+ if (nodeType.isArray())
+ {
+ // index type should not be an array, otherwise we throw a logic exception
+ if (nodeType.getArrayIndexType().isArray())
{
- d_mayEqualEqualityEngine.addTerm(node);
- d_equalityEngine.addTriggerTerm(node, THEORY_ARRAYS);
+ std::stringstream ss;
+ ss << "Arrays cannot be indexed by array types, offending array type is "
+ << nodeType;
+ throw LogicException(ss.str());
}
- else
+ d_mayEqualEqualityEngine.addTerm(node);
+ }
+ d_equalityEngine->addTerm(node);
+
+ switch (node.getKind())
+ {
+ case kind::SELECT:
{
- d_equalityEngine.addTerm(node);
- }
- Assert((d_isPreRegistered.insert(node), true));
-
- if (options::arraysLazyRIntro1() && !options::arraysWeakEquivalence()) {
- // Apply RIntro1 rule to any stores equal to store if not done already
- const CTNodeList* stores = d_infoMap.getStores(store);
- CTNodeList::const_iterator it = stores->begin();
- if (it != stores->end()) {
- NodeManager* nm = NodeManager::currentNM();
- TNode s = *it;
- if (!d_infoMap.rIntro1Applied(s)) {
- d_infoMap.setRIntro1Applied(s);
- Assert(s.getKind() == kind::STORE);
- Node ni = nm->mkNode(kind::SELECT, s, s[1]);
- if (ni != node) {
- preRegisterTermInternal(ni);
- }
- d_equalityEngine.assertEquality(ni.eqNode(s[2]), true, d_true, d_reasonRow1);
- Assert(++it == stores->end());
- }
- }
- }
+ // Reads
+ TNode store = d_equalityEngine->getRepresentative(node[0]);
- Assert(d_equalityEngine.getRepresentative(store) == store);
- d_infoMap.addIndex(store, node[1]);
+ // The may equal needs the store
+ d_mayEqualEqualityEngine.addTerm(store);
- // Synchronize d_constReadsContext with SAT context
- Assert(d_constReadsContext->getLevel() <= getSatContext()->getLevel());
- while (d_constReadsContext->getLevel() < getSatContext()->getLevel()) {
- d_constReadsContext->push();
- }
+ Assert((d_isPreRegistered.insert(node), true));
+
+ Assert(d_equalityEngine->getRepresentative(store) == store);
+ d_infoMap.addIndex(store, node[1]);
- // Record read in sharing data structure
- TNode index = d_equalityEngine.getRepresentative(node[1]);
- if (!options::arraysWeakEquivalence() && index.isConst()) {
- CTNodeList* temp;
- CNodeNListMap::iterator it = d_constReads.find(index);
- if (it == d_constReads.end()) {
- temp = new(true) CTNodeList(d_constReadsContext);
- d_constReads[index] = temp;
+ // Synchronize d_constReadsContext with SAT context
+ Assert(d_constReadsContext->getLevel() <= getSatContext()->getLevel());
+ while (d_constReadsContext->getLevel() < getSatContext()->getLevel())
+ {
+ d_constReadsContext->push();
}
- else {
- temp = (*it).second;
+
+ // Record read in sharing data structure
+ TNode index = d_equalityEngine->getRepresentative(node[1]);
+ if (!options::arraysWeakEquivalence() && index.isConst())
+ {
+ CTNodeList* temp;
+ CNodeNListMap::iterator it = d_constReads.find(index);
+ if (it == d_constReads.end())
+ {
+ temp = new (true) CTNodeList(d_constReadsContext);
+ d_constReads[index] = temp;
+ }
+ else
+ {
+ temp = (*it).second;
+ }
+ temp->push_back(node);
+ d_constReadsList.push_back(node);
+ }
+ else
+ {
+ d_reads.push_back(node);
}
- temp->push_back(node);
- d_constReadsList.push_back(node);
- }
- else {
- d_reads.push_back(node);
- }
- checkRowForIndex(node[1], store);
- break;
- }
- case kind::STORE: {
- if (d_equalityEngine.hasTerm(node)) {
+ checkRowForIndex(node[1], store);
break;
}
- d_equalityEngine.addTriggerTerm(node, THEORY_ARRAYS);
-
- TNode a = d_equalityEngine.getRepresentative(node[0]);
+ case kind::STORE:
+ {
+ TNode a = d_equalityEngine->getRepresentative(node[0]);
- if (node.isConst()) {
- // Can't use d_mayEqualEqualityEngine to merge node with a because they are both constants,
- // so just set the default value manually for node.
- Assert(a == node[0]);
- d_mayEqualEqualityEngine.addTerm(node);
- Assert(d_mayEqualEqualityEngine.getRepresentative(node) == node);
- Assert(d_mayEqualEqualityEngine.getRepresentative(a) == a);
- DefValMap::iterator it = d_defValues.find(a);
- Assert(it != d_defValues.end());
- d_defValues[node] = (*it).second;
- }
- else {
- d_mayEqualEqualityEngine.assertEquality(node.eqNode(a), true, d_true);
- Assert(d_mayEqualEqualityEngine.consistent());
- }
+ if (node.isConst())
+ {
+ // Can't use d_mayEqualEqualityEngine to merge node with a because they
+ // are both constants, so just set the default value manually for node.
+ Assert(a == node[0]);
+ d_mayEqualEqualityEngine.addTerm(node);
+ Assert(d_mayEqualEqualityEngine.getRepresentative(node) == node);
+ Assert(d_mayEqualEqualityEngine.getRepresentative(a) == a);
+ DefValMap::iterator it = d_defValues.find(a);
+ Assert(it != d_defValues.end());
+ d_defValues[node] = (*it).second;
+ }
+ else
+ {
+ d_mayEqualEqualityEngine.assertEquality(node.eqNode(a), true, d_true);
+ Assert(d_mayEqualEqualityEngine.consistent());
+ }
- if (!options::arraysLazyRIntro1() || options::arraysWeakEquivalence()) {
TNode i = node[1];
TNode v = node[2];
NodeManager* nm = NodeManager::currentNM();
Node ni = nm->mkNode(kind::SELECT, node, i);
- if (!d_equalityEngine.hasTerm(ni)) {
+ if (!d_equalityEngine->hasTerm(ni))
+ {
preRegisterTermInternal(ni);
}
-
// Apply RIntro1 Rule
- d_equalityEngine.assertEquality(ni.eqNode(v), true, d_true, d_reasonRow1);
- }
+ d_im.assertInference(
+ ni.eqNode(v), true, d_true, PfRule::ARRAYS_READ_OVER_WRITE_1);
- d_infoMap.addStore(node, node);
- d_infoMap.addInStore(a, node);
- d_infoMap.setModelRep(node, node);
+ d_infoMap.addStore(node, node);
+ d_infoMap.addInStore(a, node);
+ d_infoMap.setModelRep(node, node);
- //Add-Store for Weak Equivalence
- if (options::arraysWeakEquivalence()) {
- Assert(weakEquivGetRep(node[0]) == weakEquivGetRep(a));
- Assert(weakEquivGetRep(node) == node);
- d_infoMap.setWeakEquivPointer(node, node[0]);
- d_infoMap.setWeakEquivIndex(node, node[1]);
+ // Add-Store for Weak Equivalence
+ if (options::arraysWeakEquivalence())
+ {
+ Assert(weakEquivGetRep(node[0]) == weakEquivGetRep(a));
+ Assert(weakEquivGetRep(node) == node);
+ d_infoMap.setWeakEquivPointer(node, node[0]);
+ d_infoMap.setWeakEquivIndex(node, node[1]);
#ifdef CVC4_ASSERTIONS
checkWeakEquiv(false);
#endif
@@ -804,42 +788,26 @@ void TheoryArrays::preRegisterTermInternal(TNode node)
break;
}
case kind::STORE_ALL: {
- if (d_equalityEngine.hasTerm(node)) {
- break;
- }
ArrayStoreAll storeAll = node.getConst<ArrayStoreAll>();
Node defaultValue = storeAll.getValue();
if (!defaultValue.isConst()) {
throw LogicException("Array theory solver does not yet support non-constant default values for arrays");
}
d_infoMap.setConstArr(node, node);
- d_mayEqualEqualityEngine.addTerm(node);
Assert(d_mayEqualEqualityEngine.getRepresentative(node) == node);
- d_equalityEngine.addTriggerTerm(node, THEORY_ARRAYS);
d_defValues[node] = defaultValue;
break;
}
default:
- // Variables etc
- if (node.getType().isArray()) {
- // The may equal needs the node
- d_mayEqualEqualityEngine.addTerm(node);
- d_equalityEngine.addTriggerTerm(node, THEORY_ARRAYS);
- Assert(d_equalityEngine.getSize(node) == 1);
- }
- else {
- d_equalityEngine.addTerm(node);
- }
-
+ // Variables etc, already processed above
break;
}
// Invariant: preregistered terms are exactly the terms in the equality engine
// Disabled, see comment above for kind::EQUAL
- // Assert(d_equalityEngine.hasTerm(node) ||
- // !d_equalityEngine.consistent());
+ // Assert(d_equalityEngine->hasTerm(node) ||
+ // !d_equalityEngine->consistent());
}
-
void TheoryArrays::preRegisterTerm(TNode node)
{
preRegisterTermInternal(node);
@@ -847,39 +815,45 @@ void TheoryArrays::preRegisterTerm(TNode node)
// Note: do this here instead of in preRegisterTermInternal to prevent internal select
// terms from being propagated out (as this results in an assertion failure).
if (node.getKind() == kind::SELECT && node.getType().isBoolean()) {
- d_equalityEngine.addTriggerPredicate(node);
+ d_equalityEngine->addTriggerPredicate(node);
}
}
-
-void TheoryArrays::propagate(Effort e)
-{
- // direct propagation now
-}
-
-TrustNode TheoryArrays::explain(TNode literal)
+void TheoryArrays::explain(TNode literal, Node& explanation)
{
- Node explanation = explain(literal, NULL);
- return TrustNode::mkTrustPropExp(literal, explanation, nullptr);
-}
-
-Node TheoryArrays::explain(TNode literal, eq::EqProof* proof) {
++d_numExplain;
Debug("arrays") << spaces(getSatContext()->getLevel())
<< "TheoryArrays::explain(" << literal << ")" << std::endl;
std::vector<TNode> assumptions;
- explain(literal, assumptions, proof);
- return mkAnd(assumptions);
+ // Do the work
+ bool polarity = literal.getKind() != kind::NOT;
+ TNode atom = polarity ? literal : literal[0];
+ if (atom.getKind() == kind::EQUAL)
+ {
+ d_equalityEngine->explainEquality(
+ atom[0], atom[1], polarity, assumptions, nullptr);
+ }
+ else
+ {
+ d_equalityEngine->explainPredicate(atom, polarity, assumptions, nullptr);
+ }
+ explanation = mkAnd(assumptions);
+}
+
+TrustNode TheoryArrays::explain(TNode literal)
+{
+ return d_im.explainLit(literal);
}
/////////////////////////////////////////////////////////////////////////////
// SHARING
/////////////////////////////////////////////////////////////////////////////
-
-void TheoryArrays::addSharedTerm(TNode t) {
- Debug("arrays::sharing") << spaces(getSatContext()->getLevel()) << "TheoryArrays::addSharedTerm(" << t << ")" << std::endl;
- d_equalityEngine.addTriggerTerm(t, THEORY_ARRAYS);
+void TheoryArrays::notifySharedTerm(TNode t)
+{
+ Debug("arrays::sharing") << spaces(getSatContext()->getLevel())
+ << "TheoryArrays::notifySharedTerm(" << t << ")"
+ << std::endl;
if (t.getType().isArray()) {
d_sharedArrays.insert(t);
}
@@ -891,37 +865,25 @@ void TheoryArrays::addSharedTerm(TNode t) {
}
}
-
-EqualityStatus TheoryArrays::getEqualityStatus(TNode a, TNode b) {
- Assert(d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b));
- if (d_equalityEngine.areEqual(a, b)) {
- // The terms are implied to be equal
- return EQUALITY_TRUE;
- }
- else if (d_equalityEngine.areDisequal(a, b, false)) {
- // The terms are implied to be dis-equal
- return EQUALITY_FALSE;
- }
- return EQUALITY_UNKNOWN;//FALSE_IN_MODEL;
-}
-
-
void TheoryArrays::checkPair(TNode r1, TNode r2)
{
Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): checking reads " << r1 << " and " << r2 << std::endl;
TNode x = r1[1];
TNode y = r2[1];
- Assert(d_equalityEngine.isTriggerTerm(x, THEORY_ARRAYS));
+ Assert(d_equalityEngine->isTriggerTerm(x, THEORY_ARRAYS));
- if (d_equalityEngine.hasTerm(x) && d_equalityEngine.hasTerm(y) &&
- (d_equalityEngine.areEqual(x,y) || d_equalityEngine.areDisequal(x,y,false))) {
+ if (d_equalityEngine->hasTerm(x) && d_equalityEngine->hasTerm(y)
+ && (d_equalityEngine->areEqual(x, y)
+ || d_equalityEngine->areDisequal(x, y, false)))
+ {
Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): equality known, skipping" << std::endl;
return;
}
// If the terms are already known to be equal, we are also in good shape
- if (d_equalityEngine.areEqual(r1, r2)) {
+ if (d_equalityEngine->areEqual(r1, r2))
+ {
Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): equal, skipping" << std::endl;
return;
}
@@ -930,8 +892,9 @@ void TheoryArrays::checkPair(TNode r1, TNode r2)
// If arrays are known to be disequal, or cannot become equal, we can continue
Assert(d_mayEqualEqualityEngine.hasTerm(r1[0])
&& d_mayEqualEqualityEngine.hasTerm(r2[0]));
- if (r1[0].getType() != r2[0].getType() ||
- d_equalityEngine.areDisequal(r1[0], r2[0], false)) {
+ if (r1[0].getType() != r2[0].getType()
+ || d_equalityEngine->areDisequal(r1[0], r2[0], false))
+ {
Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): arrays can't be equal, skipping" << std::endl;
return;
}
@@ -940,14 +903,17 @@ void TheoryArrays::checkPair(TNode r1, TNode r2)
}
}
- if (!d_equalityEngine.isTriggerTerm(y, THEORY_ARRAYS)) {
+ if (!d_equalityEngine->isTriggerTerm(y, THEORY_ARRAYS))
+ {
Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): not connected to shared terms, skipping" << std::endl;
return;
}
// Get representative trigger terms
- TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_ARRAYS);
- TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_ARRAYS);
+ TNode x_shared =
+ d_equalityEngine->getTriggerTermRepresentative(x, THEORY_ARRAYS);
+ TNode y_shared =
+ d_equalityEngine->getTriggerTermRepresentative(y, THEORY_ARRAYS);
EqualityStatus eqStatusDomain = d_valuation.getEqualityStatus(x_shared, y_shared);
switch (eqStatusDomain) {
case EQUALITY_TRUE_AND_PROPAGATED:
@@ -1016,14 +982,16 @@ void TheoryArrays::computeCareGraph()
TNode r1 = d_reads[i];
Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): checking read " << r1 << std::endl;
- Assert(d_equalityEngine.hasTerm(r1));
+ Assert(d_equalityEngine->hasTerm(r1));
TNode x = r1[1];
- if (!d_equalityEngine.isTriggerTerm(x, THEORY_ARRAYS)) {
+ if (!d_equalityEngine->isTriggerTerm(x, THEORY_ARRAYS))
+ {
Debug("arrays::sharing") << "TheoryArrays::computeCareGraph(): not connected to shared terms, skipping" << std::endl;
continue;
}
- Node x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_ARRAYS);
+ Node x_shared =
+ d_equalityEngine->getTriggerTermRepresentative(x, THEORY_ARRAYS);
// Get the model value of index and find all reads that read from that same model value: these are the pairs we have to check
// Also, insert this read in the list at the proper index
@@ -1051,12 +1019,12 @@ void TheoryArrays::computeCareGraph()
// We don't know the model value for x. Just do brute force examination of all pairs of reads
for (unsigned j = 0; j < size; ++j) {
TNode r2 = d_reads[j];
- Assert(d_equalityEngine.hasTerm(r2));
+ Assert(d_equalityEngine->hasTerm(r2));
checkPair(r1,r2);
}
for (unsigned j = 0; j < d_constReadsList.size(); ++j) {
TNode r2 = d_constReadsList[j];
- Assert(d_equalityEngine.hasTerm(r2));
+ Assert(d_equalityEngine->hasTerm(r2));
checkPair(r1,r2);
}
}
@@ -1070,110 +1038,36 @@ void TheoryArrays::computeCareGraph()
// MODEL GENERATION
/////////////////////////////////////////////////////////////////////////////
-bool TheoryArrays::collectModelInfo(TheoryModel* m)
+bool TheoryArrays::collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet)
{
- set<Node> termSet;
-
- // Compute terms appearing in assertions and shared terms
- computeRelevantTerms(termSet);
-
- // Compute arrays that we need to produce representatives for and also make sure RIntro1 reads are included in the relevant set of reads
+ // termSet contains terms appearing in assertions and shared terms, and also
+ // includes additional reads due to the RIntro1 and RIntro2 rules.
NodeManager* nm = NodeManager::currentNM();
+ // Compute arrays that we need to produce representatives for
std::vector<Node> arrays;
- bool computeRep, isArray;
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(&d_equalityEngine);
+
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(d_equalityEngine);
for (; !eqcs_i.isFinished(); ++eqcs_i) {
Node eqc = (*eqcs_i);
- isArray = eqc.getType().isArray();
- if (!isArray) {
+ if (!eqc.getType().isArray())
+ {
+ // not an array, skip
continue;
}
- computeRep = false;
- eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, &d_equalityEngine);
+ eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, d_equalityEngine);
for (; !eqc_i.isFinished(); ++eqc_i) {
Node n = *eqc_i;
// If this EC is an array type and it contains something other than STORE nodes, we have to compute a representative explicitly
- if (isArray && termSet.find(n) != termSet.end()) {
- if (n.getKind() == kind::STORE) {
- // Make sure RIntro1 reads are included
- Node r = nm->mkNode(kind::SELECT, n, n[1]);
- Trace("arrays::collectModelInfo") << "TheoryArrays::collectModelInfo, adding RIntro1 read: " << r << endl;
- termSet.insert(r);
- }
- else if (!computeRep) {
+ if (termSet.find(n) != termSet.end())
+ {
+ if (n.getKind() != kind::STORE)
+ {
arrays.push_back(n);
- computeRep = true;
- }
- }
- }
- }
-
- // Now do a fixed-point iteration to get all reads that need to be included because of RIntro2 rule
- bool changed;
- do {
- changed = false;
- eqcs_i = eq::EqClassesIterator(&d_equalityEngine);
- for (; !eqcs_i.isFinished(); ++eqcs_i) {
- Node eqc = (*eqcs_i);
- eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, &d_equalityEngine);
- for (; !eqc_i.isFinished(); ++eqc_i) {
- Node n = *eqc_i;
- if (n.getKind() == kind::SELECT && termSet.find(n) != termSet.end()) {
-
- // Find all terms equivalent to n[0] and get corresponding read terms
- Node array_eqc = d_equalityEngine.getRepresentative(n[0]);
- eq::EqClassIterator array_eqc_i = eq::EqClassIterator(array_eqc, &d_equalityEngine);
- for (; !array_eqc_i.isFinished(); ++array_eqc_i) {
- Node arr = *array_eqc_i;
- if (arr.getKind() == kind::STORE &&
- termSet.find(arr) != termSet.end() &&
- !d_equalityEngine.areEqual(arr[1],n[1])) {
- Node r = nm->mkNode(kind::SELECT, arr, n[1]);
- if (termSet.find(r) == termSet.end() && d_equalityEngine.hasTerm(r)) {
- Trace("arrays::collectModelInfo") << "TheoryArrays::collectModelInfo, adding RIntro2(a) read: " << r << endl;
- termSet.insert(r);
- changed = true;
- }
- r = nm->mkNode(kind::SELECT, arr[0], n[1]);
- if (termSet.find(r) == termSet.end() && d_equalityEngine.hasTerm(r)) {
- Trace("arrays::collectModelInfo") << "TheoryArrays::collectModelInfo, adding RIntro2(b) read: " << r << endl;
- termSet.insert(r);
- changed = true;
- }
- }
- }
-
- // Find all stores in which n[0] appears and get corresponding read terms
- const CTNodeList* instores = d_infoMap.getInStores(array_eqc);
- size_t it = 0;
- for(; it < instores->size(); ++it) {
- TNode instore = (*instores)[it];
- Assert(instore.getKind() == kind::STORE);
- if (termSet.find(instore) != termSet.end() &&
- !d_equalityEngine.areEqual(instore[1],n[1])) {
- Node r = nm->mkNode(kind::SELECT, instore, n[1]);
- if (termSet.find(r) == termSet.end() && d_equalityEngine.hasTerm(r)) {
- Trace("arrays::collectModelInfo") << "TheoryArrays::collectModelInfo, adding RIntro2(c) read: " << r << endl;
- termSet.insert(r);
- changed = true;
- }
- r = nm->mkNode(kind::SELECT, instore[0], n[1]);
- if (termSet.find(r) == termSet.end() && d_equalityEngine.hasTerm(r)) {
- Trace("arrays::collectModelInfo") << "TheoryArrays::collectModelInfo, adding RIntro2(d) read: " << r << endl;
- termSet.insert(r);
- changed = true;
- }
- }
- }
+ break;
}
}
}
- } while (changed);
-
- // Send the equality engine information to the model
- if (!m->assertEqualityEngine(&d_equalityEngine, &termSet))
- {
- return false;
}
// Build a list of all the relevant reads, indexed by the store representative
@@ -1183,7 +1077,7 @@ bool TheoryArrays::collectModelInfo(TheoryModel* m)
Node n = *set_it;
// If this term is a select, record that the EC rep of its store parameter is being read from using this term
if (n.getKind() == kind::SELECT) {
- selects[d_equalityEngine.getRepresentative(n[0])].push_back(n);
+ selects[d_equalityEngine->getRepresentative(n[0])].push_back(n);
}
}
@@ -1194,7 +1088,7 @@ bool TheoryArrays::collectModelInfo(TheoryModel* m)
// Compute all default values already in use
//if (fullModel) {
for (size_t i=0; i<arrays.size(); ++i) {
- TNode nrep = d_equalityEngine.getRepresentative(arrays[i]);
+ TNode nrep = d_equalityEngine->getRepresentative(arrays[i]);
d_mayEqualEqualityEngine.addTerm(nrep); // add the term in case it isn't there already
TNode mayRep = d_mayEqualEqualityEngine.getRepresentative(nrep);
it = d_defValues.find(mayRep);
@@ -1205,12 +1099,14 @@ bool TheoryArrays::collectModelInfo(TheoryModel* m)
//}
// Loop through all array equivalence classes that need a representative computed
- for (size_t i=0; i<arrays.size(); ++i) {
- TNode n = arrays[i];
- TNode nrep = d_equalityEngine.getRepresentative(n);
+ for (size_t i = 0; i < arrays.size(); ++i)
+ {
+ TNode n = arrays[i];
+ TNode nrep = d_equalityEngine->getRepresentative(n);
- //if (fullModel) {
- // Compute default value for this array - there is one default value for every mayEqual equivalence class
+ // if (fullModel) {
+ // Compute default value for this array - there is one default value for
+ // every mayEqual equivalence class
TNode mayRep = d_mayEqualEqualityEngine.getRepresentative(nrep);
it = d_defValues.find(mayRep);
// If this mayEqual EC doesn't have a default value associated, get the next available default value for the associated array element type
@@ -1285,169 +1181,35 @@ void TheoryArrays::presolve()
// MAIN SOLVER
/////////////////////////////////////////////////////////////////////////////
-
-Node TheoryArrays::getSkolem(TNode ref, const string& name, const TypeNode& type, const string& comment, bool makeEqual)
+Node TheoryArrays::getSkolem(TNode ref)
{
+ // the call to SkolemCache::getExtIndexSkolem should be deterministic, but use
+ // cache anyways for now
Node skolem;
std::unordered_map<Node, Node, NodeHashFunction>::iterator it = d_skolemCache.find(ref);
if (it == d_skolemCache.end()) {
- NodeManager* nm = NodeManager::currentNM();
- skolem = nm->mkSkolem(name, type, comment);
+ Assert(ref.getKind() == kind::NOT && ref[0].getKind() == kind::EQUAL);
+ // make the skolem using the skolem cache utility
+ skolem = SkolemCache::getExtIndexSkolem(ref);
d_skolemCache[ref] = skolem;
}
else {
skolem = (*it).second;
- if (d_equalityEngine.hasTerm(ref) &&
- d_equalityEngine.hasTerm(skolem) &&
- d_equalityEngine.areEqual(ref, skolem)) {
- makeEqual = false;
- }
}
Debug("pf::array") << "Pregistering a Skolem" << std::endl;
preRegisterTermInternal(skolem);
Debug("pf::array") << "Pregistering a Skolem DONE" << std::endl;
- if (makeEqual) {
- Node d = skolem.eqNode(ref);
- Debug("arrays-model-based") << "Asserting skolem equality " << d << endl;
- d_equalityEngine.assertEquality(d, true, d_true);
- Assert(!d_conflict);
- d_skolemAssertions.push_back(d);
- d_skolemIndex = d_skolemIndex + 1;
- }
-
Debug("pf::array") << "getSkolem DONE" << std::endl;
return skolem;
}
-
-void TheoryArrays::check(Effort e) {
- if (done() && !fullEffort(e)) {
- return;
- }
-
- getOutputChannel().spendResource(ResourceManager::Resource::TheoryCheckStep);
-
- TimerStat::CodeTimer checkTimer(d_checkTime);
-
- while (!done() && !d_conflict)
+void TheoryArrays::postCheck(Effort level)
+{
+ if ((options::arraysEagerLemmas() || fullEffort(level))
+ && !d_state.isInConflict() && options::arraysWeakEquivalence())
{
- // Get all the assertions
- Assertion assertion = get();
- TNode fact = assertion.d_assertion;
-
- Debug("arrays") << spaces(getSatContext()->getLevel()) << "TheoryArrays::check(): processing " << fact << std::endl;
-
- bool polarity = fact.getKind() != kind::NOT;
- TNode atom = polarity ? fact : fact[0];
-
- if (!assertion.d_isPreregistered)
- {
- if (atom.getKind() == kind::EQUAL) {
- if (!d_equalityEngine.hasTerm(atom[0])) {
- Assert(atom[0].isConst());
- d_equalityEngine.addTerm(atom[0]);
- }
- if (!d_equalityEngine.hasTerm(atom[1])) {
- Assert(atom[1].isConst());
- d_equalityEngine.addTerm(atom[1]);
- }
- }
- }
-
- // Do the work
- switch (fact.getKind()) {
- case kind::EQUAL:
- d_equalityEngine.assertEquality(fact, true, fact);
- break;
- case kind::SELECT:
- d_equalityEngine.assertPredicate(fact, true, fact);
- break;
- case kind::NOT:
- if (fact[0].getKind() == kind::SELECT) {
- d_equalityEngine.assertPredicate(fact[0], false, fact);
- } else if (!d_equalityEngine.areDisequal(fact[0][0], fact[0][1], false)) {
- // Assert the dis-equality
- d_equalityEngine.assertEquality(fact[0], false, fact);
-
- // Apply ArrDiseq Rule if diseq is between arrays
- if(fact[0][0].getType().isArray() && !d_conflict) {
- if (d_conflict) { Debug("pf::array") << "Entering the skolemization branch" << std::endl; }
-
- NodeManager* nm = NodeManager::currentNM();
- TypeNode indexType = fact[0][0].getType()[0];
-
- TNode k;
- // k is the skolem for this disequality.
- if (!d_proofsEnabled) {
- Debug("pf::array") << "Check: kind::NOT: array theory making a skolem" << std::endl;
-
- // If not in replay mode, generate a fresh skolem variable
- k = getSkolem(fact,
- "array_ext_index",
- indexType,
- "an extensional lemma index variable from the theory of arrays",
- false);
-
- // Register this skolem for the proof replay phase
- PROOF(ProofManager::getSkolemizationManager()->registerSkolem(fact, k));
- } else {
- if (!ProofManager::getSkolemizationManager()->hasSkolem(fact)) {
- // In the solution pass we didn't need this skolem. Therefore, we don't need it
- // in this reply pass, either.
- break;
- }
-
- // Reuse the same skolem as in the solution pass
- k = ProofManager::getSkolemizationManager()->getSkolem(fact);
- Debug("pf::array") << "Skolem = " << k << std::endl;
- }
-
- Node ak = nm->mkNode(kind::SELECT, fact[0][0], k);
- Node bk = nm->mkNode(kind::SELECT, fact[0][1], k);
- Node eq = ak.eqNode(bk);
- Node lemma = fact[0].orNode(eq.notNode());
-
- // In solve mode we don't care if ak and bk are registered. If they aren't, they'll be registered
- // when we output the lemma. However, in replay need the lemma to be propagated, and so we
- // preregister manually.
- if (d_proofsEnabled) {
- if (!d_equalityEngine.hasTerm(ak)) { preRegisterTermInternal(ak); }
- if (!d_equalityEngine.hasTerm(bk)) { preRegisterTermInternal(bk); }
- }
-
- if (options::arraysPropagate() > 0 && d_equalityEngine.hasTerm(ak) && d_equalityEngine.hasTerm(bk)) {
- // Propagate witness disequality - might produce a conflict
- d_permRef.push_back(lemma);
- Debug("pf::array") << "Asserting to the equality engine:" << std::endl
- << "\teq = " << eq << std::endl
- << "\treason = " << fact << std::endl;
-
- d_equalityEngine.assertEquality(eq, false, fact, d_reasonExt);
- ++d_numProp;
- }
-
- if (!d_proofsEnabled) {
- // If this is the solution pass, generate the lemma. Otherwise, don't generate it -
- // as this is the lemma that we're reproving...
- Trace("arrays-lem")<<"Arrays::addExtLemma " << lemma <<"\n";
- d_out->lemma(lemma);
- ++d_numExt;
- }
- } else {
- Debug("pf::array") << "Check: kind::NOT: array theory NOT making a skolem" << std::endl;
- d_modelConstraints.push_back(fact);
- }
- }
- break;
- default:
- Unreachable();
- break;
- }
- }
-
- if ((options::arraysEagerLemmas() || fullEffort(e)) && !d_conflict && options::arraysWeakEquivalence()) {
// Replay all array merges to update weak equivalence data structures
context::CDList<Node>::iterator it = d_arrayMerges.begin(), iend = d_arrayMerges.end();
TNode a, b, eq;
@@ -1482,7 +1244,7 @@ void TheoryArrays::check(Effort e) {
// Find the bucket for this read.
mayRep = d_mayEqualEqualityEngine.getRepresentative(r[0]);
- iRep = d_equalityEngine.getRepresentative(r[1]);
+ iRep = d_equalityEngine->getRepresentative(r[1]);
std::pair<TNode, TNode> key(mayRep, iRep);
ReadBucketMap::iterator rbm_it = d_readBucketTable.find(key);
if (rbm_it == d_readBucketTable.end())
@@ -1501,28 +1263,30 @@ void TheoryArrays::check(Effort e) {
const TNode& r2 = *ctnl_it;
Assert(r2.getKind() == kind::SELECT);
Assert(mayRep == d_mayEqualEqualityEngine.getRepresentative(r2[0]));
- Assert(iRep == d_equalityEngine.getRepresentative(r2[1]));
- if (d_equalityEngine.areEqual(r, r2)) {
+ Assert(iRep == d_equalityEngine->getRepresentative(r2[1]));
+ if (d_equalityEngine->areEqual(r, r2))
+ {
continue;
}
if (weakEquivGetRepIndex(r[0], r[1]) == weakEquivGetRepIndex(r2[0], r[1])) {
// add lemma: r[1] = r2[1] /\ cond(r[0],r2[0]) => r = r2
vector<TNode> conjunctions;
- Assert(d_equalityEngine.areEqual(r, Rewriter::rewrite(r)));
- Assert(d_equalityEngine.areEqual(r2, Rewriter::rewrite(r2)));
+ Assert(d_equalityEngine->areEqual(r, Rewriter::rewrite(r)));
+ Assert(d_equalityEngine->areEqual(r2, Rewriter::rewrite(r2)));
Node lemma = Rewriter::rewrite(r).eqNode(Rewriter::rewrite(r2)).negate();
d_permRef.push_back(lemma);
conjunctions.push_back(lemma);
if (r[1] != r2[1]) {
- d_equalityEngine.explainEquality(r[1], r2[1], true, conjunctions);
+ d_equalityEngine->explainEquality(r[1], r2[1], true, conjunctions);
}
// TODO: get smaller lemmas by eliminating shared parts of path
weakEquivBuildCond(r[0], r[1], conjunctions);
weakEquivBuildCond(r2[0], r[1], conjunctions);
lemma = mkAnd(conjunctions, true);
// LSH FIXME: which kind of arrays lemma is this
- Trace("arrays-lem") << "Arrays::addExtLemma " << lemma <<"\n";
- d_out->lemma(lemma, RULE_INVALID, false, false, true);
+ Trace("arrays-lem")
+ << "Arrays::addExtLemma (weak-eq) " << lemma << "\n";
+ d_out->lemma(lemma, LemmaProperty::SEND_ATOMS);
d_readTableContext->pop();
Trace("arrays") << spaces(getSatContext()->getLevel()) << "Arrays::check(): done" << endl;
return;
@@ -1533,10 +1297,13 @@ void TheoryArrays::check(Effort e) {
d_readTableContext->pop();
}
- if(!options::arraysEagerLemmas() && fullEffort(e) && !d_conflict && !options::arraysWeakEquivalence()) {
+ if (!options::arraysEagerLemmas() && fullEffort(level)
+ && !d_state.isInConflict() && !options::arraysWeakEquivalence())
+ {
// generate the lemmas on the worklist
Trace("arrays-lem")<< "Arrays::discharging lemmas. Number of queued lemmas: " << d_RowQueue.size() << "\n";
- while (d_RowQueue.size() > 0 && !d_conflict) {
+ while (d_RowQueue.size() > 0 && !d_state.isInConflict())
+ {
if (dischargeLemmas()) {
break;
}
@@ -1546,13 +1313,87 @@ void TheoryArrays::check(Effort e) {
Trace("arrays") << spaces(getSatContext()->getLevel()) << "Arrays::check(): done" << endl;
}
+bool TheoryArrays::preNotifyFact(
+ TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal)
+{
+ if (!isInternal && !isPrereg)
+ {
+ if (atom.getKind() == kind::EQUAL)
+ {
+ if (!d_equalityEngine->hasTerm(atom[0]))
+ {
+ Assert(atom[0].isConst());
+ d_equalityEngine->addTerm(atom[0]);
+ }
+ if (!d_equalityEngine->hasTerm(atom[1]))
+ {
+ Assert(atom[1].isConst());
+ d_equalityEngine->addTerm(atom[1]);
+ }
+ }
+ }
+ return false;
+}
+
+void TheoryArrays::notifyFact(TNode atom, bool pol, TNode fact, bool isInternal)
+{
+ // if a disequality
+ if (atom.getKind() == kind::EQUAL && !pol && !isInternal)
+ {
+ // Notice that this should be an external assertion, since we do not
+ // internally infer disequalities.
+ // Apply ArrDiseq Rule if diseq is between arrays
+ if (fact[0][0].getType().isArray() && !d_state.isInConflict())
+ {
+ NodeManager* nm = NodeManager::currentNM();
+
+ TNode k;
+ // k is the skolem for this disequality.
+ Debug("pf::array") << "Check: kind::NOT: array theory making a skolem"
+ << std::endl;
+
+ // If not in replay mode, generate a fresh skolem variable
+ k = getSkolem(fact);
+
+ Node ak = nm->mkNode(kind::SELECT, fact[0][0], k);
+ Node bk = nm->mkNode(kind::SELECT, fact[0][1], k);
+ Node eq = ak.eqNode(bk);
+ Node lemma = fact[0].orNode(eq.notNode());
+
+ if (options::arraysPropagate() > 0 && d_equalityEngine->hasTerm(ak)
+ && d_equalityEngine->hasTerm(bk))
+ {
+ // Propagate witness disequality - might produce a conflict
+ Debug("pf::array") << "Asserting to the equality engine:" << std::endl
+ << "\teq = " << eq << std::endl
+ << "\treason = " << fact << std::endl;
+ d_im.assertInference(eq, false, fact, PfRule::ARRAYS_EXT);
+ ++d_numProp;
+ }
+
+ // If this is the solution pass, generate the lemma. Otherwise, don't
+ // generate it - as this is the lemma that we're reproving...
+ Trace("arrays-lem") << "Arrays::addExtLemma " << lemma << "\n";
+ d_im.arrayLemma(eq.notNode(), fact, PfRule::ARRAYS_EXT);
+ ++d_numExt;
+ }
+ else
+ {
+ Debug("pf::array") << "Check: kind::NOT: array theory NOT making a skolem"
+ << std::endl;
+ d_modelConstraints.push_back(fact);
+ }
+ }
+}
Node TheoryArrays::mkAnd(std::vector<TNode>& conjunctions, bool invert, unsigned startIndex)
{
- Assert(conjunctions.size() > 0);
+ if (conjunctions.empty())
+ {
+ return invert ? d_false : d_true;
+ }
std::set<TNode> all;
- std::set<TNode> explained;
unsigned i = startIndex;
TNode t;
@@ -1569,23 +1410,6 @@ Node TheoryArrays::mkAnd(std::vector<TNode>& conjunctions, bool invert, unsigned
all.insert(*child_it);
}
}
- else if (t.getKind() == kind::OR) {
- // Expand explanation resulting from propagating a ROW or EXT lemma
- if ((explained.find(t) == explained.end())) {
- if (t[1].getKind() == kind::EQUAL) {
- // ROW lemma
- d_equalityEngine.explainEquality(t[1][0], t[1][1], false, conjunctions);
- explained.insert(t);
- } else {
- // EXT lemma
- Assert(t[1].getKind() == kind::NOT
- && t[1][0].getKind() == kind::EQUAL);
- Assert(t[0].getKind() == kind::EQUAL);
- all.insert(t[0].notNode());
- explained.insert(t);
- }
- }
- }
else {
all.insert(t);
}
@@ -1662,82 +1486,6 @@ void TheoryArrays::setNonLinear(TNode a)
}
-/*****
- * When two array equivalence classes are merged, we may need to apply RIntro1 to a store in one of the EC's
- * Here, we check the stores in a to see if any need RIntro1 applied
- * We apply RIntro1 whenever:
- * (a) a store becomes equal to another store
- * (b) a store becomes equal to any term t such that read(t,i) exists
- * (c) a store becomes equal to the root array of the store (i.e. store(store(...store(a,i,v)...)) = a)
- */
-void TheoryArrays::checkRIntro1(TNode a, TNode b)
-{
- const CTNodeList* astores = d_infoMap.getStores(a);
- // Apply RIntro1 if applicable
- CTNodeList::const_iterator it = astores->begin();
-
- if (it == astores->end()) {
- // No stores in this equivalence class - return
- return;
- }
-
- ++it;
- if (it != astores->end()) {
- // More than one store: should have already been applied
- Assert(d_infoMap.rIntro1Applied(*it));
- Assert(d_infoMap.rIntro1Applied(*(--it)));
- return;
- }
-
- // Exactly one store - see if we need to apply RIntro1
- --it;
- TNode s = *it;
- Assert(s.getKind() == kind::STORE);
- if (d_infoMap.rIntro1Applied(s)) {
- // RIntro1 already applied to s
- return;
- }
-
- // Should be no reads from this EC
- Assert(d_infoMap.getIndices(a)->begin() == d_infoMap.getIndices(a)->end());
-
- bool apply = false;
- if (d_infoMap.getStores(b)->size() > 0) {
- // Case (a): two stores become equal
- apply = true;
- }
- else {
- const CTNodeList* i_b = d_infoMap.getIndices(b);
- if (i_b->begin() != i_b->end()) {
- // Case (b): there are reads from b
- apply = true;
- }
- else {
- // Get root array of s
- TNode e1 = s[0];
- while (e1.getKind() == kind::STORE) {
- e1 = e1[0];
- }
- Assert(d_equalityEngine.hasTerm(e1));
- Assert(d_equalityEngine.hasTerm(b));
- if (d_equalityEngine.areEqual(e1, b)) {
- apply = true;
- }
- }
- }
-
- if (apply) {
- NodeManager* nm = NodeManager::currentNM();
- d_infoMap.setRIntro1Applied(s);
- Node ni = nm->mkNode(kind::SELECT, s, s[1]);
- preRegisterTermInternal(ni);
- d_equalityEngine.assertEquality(ni.eqNode(s[2]), true, d_true, d_reasonRow1);
- }
-}
-
-
-
-
void TheoryArrays::mergeArrays(TNode a, TNode b)
{
// Note: a is the new representative
@@ -1756,15 +1504,10 @@ void TheoryArrays::mergeArrays(TNode a, TNode b)
// Normally, a is its own representative, but it's possible for a to have
// been merged with another array after it got queued up by the equality engine,
// so we take its representative to be safe.
- a = d_equalityEngine.getRepresentative(a);
- Assert(d_equalityEngine.getRepresentative(b) == a);
+ a = d_equalityEngine->getRepresentative(a);
+ Assert(d_equalityEngine->getRepresentative(b) == a);
Trace("arrays-merge") << spaces(getSatContext()->getLevel()) << "Arrays::merge: (" << a << ", " << b << ")\n";
- if (options::arraysLazyRIntro1() && !options::arraysWeakEquivalence()) {
- checkRIntro1(a, b);
- checkRIntro1(b, a);
- }
-
if (options::arraysOptimizeLinear() && !options::arraysWeakEquivalence()) {
bool aNL = d_infoMap.isNonLinear(a);
bool bNL = d_infoMap.isNonLinear(b);
@@ -1846,7 +1589,8 @@ void TheoryArrays::mergeArrays(TNode a, TNode b)
}
// If no more to do, break
- if (d_conflict || d_mergeQueue.empty()) {
+ if (d_state.isInConflict() || d_mergeQueue.empty())
+ {
break;
}
@@ -1872,7 +1616,7 @@ void TheoryArrays::checkStore(TNode a) {
TNode b = a[0];
TNode i = a[1];
- TNode brep = d_equalityEngine.getRepresentative(b);
+ TNode brep = d_equalityEngine->getRepresentative(b);
if (!options::arraysOptimizeLinear() || d_infoMap.isNonLinear(brep)) {
const CTNodeList* js = d_infoMap.getIndices(brep);
@@ -1899,17 +1643,19 @@ void TheoryArrays::checkRowForIndex(TNode i, TNode a)
d_infoMap.getInfo(a)->print();
}
Assert(a.getType().isArray());
- Assert(d_equalityEngine.getRepresentative(a) == a);
+ Assert(d_equalityEngine->getRepresentative(a) == a);
TNode constArr = d_infoMap.getConstArr(a);
if (!constArr.isNull()) {
ArrayStoreAll storeAll = constArr.getConst<ArrayStoreAll>();
Node defValue = storeAll.getValue();
Node selConst = NodeManager::currentNM()->mkNode(kind::SELECT, constArr, i);
- if (!d_equalityEngine.hasTerm(selConst)) {
+ if (!d_equalityEngine->hasTerm(selConst))
+ {
preRegisterTermInternal(selConst);
}
- d_equalityEngine.assertEquality(selConst.eqNode(defValue), true, d_true);
+ d_im.assertInference(
+ selConst.eqNode(defValue), true, d_true, PfRule::ARRAYS_TRUST);
}
const CTNodeList* stores = d_infoMap.getStores(a);
@@ -1961,7 +1707,8 @@ void TheoryArrays::checkRowLemmas(TNode a, TNode b)
for( ; it < i_a->size(); ++it) {
TNode i = (*i_a)[it];
Node selConst = NodeManager::currentNM()->mkNode(kind::SELECT, constArr, i);
- if (!d_equalityEngine.hasTerm(selConst)) {
+ if (!d_equalityEngine->hasTerm(selConst))
+ {
preRegisterTermInternal(selConst);
}
}
@@ -2014,8 +1761,8 @@ void TheoryArrays::propagate(RowLemmaType lem)
std::tie(a, b, i, j) = lem;
Assert(a.getType().isArray() && b.getType().isArray());
- if (d_equalityEngine.areEqual(a,b) ||
- d_equalityEngine.areEqual(i,j)) {
+ if (d_equalityEngine->areEqual(a, b) || d_equalityEngine->areEqual(i, j))
+ {
return;
}
@@ -2024,18 +1771,19 @@ void TheoryArrays::propagate(RowLemmaType lem)
Node bj = nm->mkNode(kind::SELECT, b, j);
// Try to avoid introducing new read terms: track whether these already exist
- bool ajExists = d_equalityEngine.hasTerm(aj);
- bool bjExists = d_equalityEngine.hasTerm(bj);
+ bool ajExists = d_equalityEngine->hasTerm(aj);
+ bool bjExists = d_equalityEngine->hasTerm(bj);
bool bothExist = ajExists && bjExists;
// If propagating, check propagations
int prop = options::arraysPropagate();
if (prop > 0) {
- if (d_equalityEngine.areDisequal(i,j,true) && (bothExist || prop > 1)) {
+ if (d_equalityEngine->areDisequal(i, j, true) && (bothExist || prop > 1))
+ {
Trace("arrays-lem") << spaces(getSatContext()->getLevel()) <<"Arrays::queueRowLemma: propagating aj = bj ("<<aj<<", "<<bj<<")\n";
Node aj_eq_bj = aj.eqNode(bj);
- Node i_eq_j = i.eqNode(j);
- Node reason = nm->mkNode(kind::OR, aj_eq_bj, i_eq_j);
+ Node reason =
+ (i.isConst() && j.isConst()) ? d_true : i.eqNode(j).notNode();
d_permRef.push_back(reason);
if (!ajExists) {
preRegisterTermInternal(aj);
@@ -2043,17 +1791,19 @@ void TheoryArrays::propagate(RowLemmaType lem)
if (!bjExists) {
preRegisterTermInternal(bj);
}
- d_equalityEngine.assertEquality(aj_eq_bj, true, reason, d_reasonRow);
+ d_im.assertInference(
+ aj_eq_bj, true, reason, PfRule::ARRAYS_READ_OVER_WRITE);
++d_numProp;
return;
}
- if (bothExist && d_equalityEngine.areDisequal(aj,bj,true)) {
+ if (bothExist && d_equalityEngine->areDisequal(aj, bj, true))
+ {
Trace("arrays-lem") << spaces(getSatContext()->getLevel()) <<"Arrays::queueRowLemma: propagating i = j ("<<i<<", "<<j<<")\n";
- Node aj_eq_bj = aj.eqNode(bj);
- Node i_eq_j = i.eqNode(j);
- Node reason = nm->mkNode(kind::OR, i_eq_j, aj_eq_bj);
- d_permRef.push_back(reason);
- d_equalityEngine.assertEquality(i_eq_j, true, reason, d_reasonRow);
+ Node reason =
+ (aj.isConst() && bj.isConst()) ? d_true : aj.eqNode(bj).notNode();
+ Node j_eq_i = j.eqNode(i);
+ d_im.assertInference(
+ j_eq_i, true, reason, PfRule::ARRAYS_READ_OVER_WRITE_CONTRA);
++d_numProp;
return;
}
@@ -2064,15 +1814,16 @@ void TheoryArrays::queueRowLemma(RowLemmaType lem)
{
Debug("pf::array") << "Array solver: queue row lemma called" << std::endl;
- if (d_conflict || d_RowAlreadyAdded.contains(lem)) {
+ if (d_state.isInConflict() || d_RowAlreadyAdded.contains(lem))
+ {
return;
}
TNode a, b, i, j;
std::tie(a, b, i, j) = lem;
Assert(a.getType().isArray() && b.getType().isArray());
- if (d_equalityEngine.areEqual(a,b) ||
- d_equalityEngine.areEqual(i,j)) {
+ if (d_equalityEngine->areEqual(a, b) || d_equalityEngine->areEqual(i, j))
+ {
return;
}
@@ -2081,8 +1832,8 @@ void TheoryArrays::queueRowLemma(RowLemmaType lem)
Node bj = nm->mkNode(kind::SELECT, b, j);
// Try to avoid introducing new read terms: track whether these already exist
- bool ajExists = d_equalityEngine.hasTerm(aj);
- bool bjExists = d_equalityEngine.hasTerm(bj);
+ bool ajExists = d_equalityEngine->hasTerm(aj);
+ bool bjExists = d_equalityEngine->hasTerm(bj);
bool bothExist = ajExists && bjExists;
// If propagating, check propagations
@@ -2091,50 +1842,47 @@ void TheoryArrays::queueRowLemma(RowLemmaType lem)
propagate(lem);
}
- // If equivalent lemma already exists, don't enqueue this one
- if (d_useArrTable) {
- Node tableEntry = NodeManager::currentNM()->mkNode(kind::ARR_TABLE_FUN, a, b, i, j);
- if (d_equalityEngine.getSize(tableEntry) != 1) {
- return;
- }
- }
-
// Prefer equality between indexes so as not to introduce new read terms
- if (options::arraysEagerIndexSplitting() && !bothExist && !d_equalityEngine.areDisequal(i,j, false)) {
+ if (options::arraysEagerIndexSplitting() && !bothExist
+ && !d_equalityEngine->areDisequal(i, j, false))
+ {
Node i_eq_j;
- if (!d_proofsEnabled) {
- i_eq_j = d_valuation.ensureLiteral(i.eqNode(j)); // TODO: think about this
- } else {
- i_eq_j = i.eqNode(j);
- }
-
+ i_eq_j = d_valuation.ensureLiteral(i.eqNode(j)); // TODO: think about this
+#if 0
+ i_eq_j = i.eqNode(j);
+#endif
getOutputChannel().requirePhase(i_eq_j, true);
d_decisionRequests.push(i_eq_j);
}
// TODO: maybe add triggers here
- if ((options::arraysEagerLemmas() || bothExist) && !d_proofsEnabled) {
+ if (options::arraysEagerLemmas() || bothExist)
+ {
// Make sure that any terms introduced by rewriting are appropriately stored in the equality database
Node aj2 = Rewriter::rewrite(aj);
if (aj != aj2) {
if (!ajExists) {
preRegisterTermInternal(aj);
}
- if (!d_equalityEngine.hasTerm(aj2)) {
+ if (!d_equalityEngine->hasTerm(aj2))
+ {
preRegisterTermInternal(aj2);
}
- d_equalityEngine.assertEquality(aj.eqNode(aj2), true, d_true);
+ d_im.assertInference(
+ aj.eqNode(aj2), true, d_true, PfRule::MACRO_SR_PRED_INTRO);
}
Node bj2 = Rewriter::rewrite(bj);
if (bj != bj2) {
if (!bjExists) {
preRegisterTermInternal(bj);
}
- if (!d_equalityEngine.hasTerm(bj2)) {
+ if (!d_equalityEngine->hasTerm(bj2))
+ {
preRegisterTermInternal(bj2);
}
- d_equalityEngine.assertEquality(bj.eqNode(bj2), true, d_true);
+ d_im.assertInference(
+ bj.eqNode(bj2), true, d_true, PfRule::MACRO_SR_PRED_INTRO);
}
if (aj2 == bj2) {
return;
@@ -2144,28 +1892,32 @@ void TheoryArrays::queueRowLemma(RowLemmaType lem)
Node eq1 = aj2.eqNode(bj2);
Node eq1_r = Rewriter::rewrite(eq1);
if (eq1_r == d_true) {
- if (!d_equalityEngine.hasTerm(aj2)) {
+ if (!d_equalityEngine->hasTerm(aj2))
+ {
preRegisterTermInternal(aj2);
}
- if (!d_equalityEngine.hasTerm(bj2)) {
+ if (!d_equalityEngine->hasTerm(bj2))
+ {
preRegisterTermInternal(bj2);
}
- d_equalityEngine.assertEquality(eq1, true, d_true);
+ d_im.assertInference(eq1, true, d_true, PfRule::MACRO_SR_PRED_INTRO);
return;
}
Node eq2 = i.eqNode(j);
Node eq2_r = Rewriter::rewrite(eq2);
if (eq2_r == d_true) {
- d_equalityEngine.assertEquality(eq2, true, d_true);
+ d_im.assertInference(eq2, true, d_true, PfRule::MACRO_SR_PRED_INTRO);
return;
}
Node lemma = nm->mkNode(kind::OR, eq2_r, eq1_r);
- Trace("arrays-lem")<<"Arrays::addRowLemma adding "<<lemma<<"\n";
+ Trace("arrays-lem") << "Arrays::addRowLemma (1) adding " << lemma << "\n";
d_RowAlreadyAdded.insert(lem);
- d_out->lemma(lemma);
+ // use non-rewritten nodes
+ d_im.arrayLemma(
+ aj.eqNode(bj), eq2.notNode(), PfRule::ARRAYS_READ_OVER_WRITE);
++d_numRow;
}
else {
@@ -2202,21 +1954,24 @@ bool TheoryArrays::dischargeLemmas()
NodeManager* nm = NodeManager::currentNM();
Node aj = nm->mkNode(kind::SELECT, a, j);
Node bj = nm->mkNode(kind::SELECT, b, j);
- bool ajExists = d_equalityEngine.hasTerm(aj);
- bool bjExists = d_equalityEngine.hasTerm(bj);
+ bool ajExists = d_equalityEngine->hasTerm(aj);
+ bool bjExists = d_equalityEngine->hasTerm(bj);
// Check for redundant lemma
// TODO: more checks possible (i.e. check d_RowAlreadyAdded in context)
- if (!d_equalityEngine.hasTerm(i) || !d_equalityEngine.hasTerm(j) || d_equalityEngine.areEqual(i,j) ||
- !d_equalityEngine.hasTerm(a) || !d_equalityEngine.hasTerm(b) || d_equalityEngine.areEqual(a,b) ||
- (ajExists && bjExists && d_equalityEngine.areEqual(aj,bj))) {
+ if (!d_equalityEngine->hasTerm(i) || !d_equalityEngine->hasTerm(j)
+ || d_equalityEngine->areEqual(i, j) || !d_equalityEngine->hasTerm(a)
+ || !d_equalityEngine->hasTerm(b) || d_equalityEngine->areEqual(a, b)
+ || (ajExists && bjExists && d_equalityEngine->areEqual(aj, bj)))
+ {
continue;
}
int prop = options::arraysPropagate();
if (prop > 0) {
propagate(l);
- if (d_conflict) {
+ if (d_state.isInConflict())
+ {
return true;
}
}
@@ -2227,21 +1982,24 @@ bool TheoryArrays::dischargeLemmas()
if (!ajExists) {
preRegisterTermInternal(aj);
}
- if (!d_equalityEngine.hasTerm(aj2)) {
+ if (!d_equalityEngine->hasTerm(aj2))
+ {
preRegisterTermInternal(aj2);
}
- d_equalityEngine.assertEquality(aj.eqNode(aj2), true, d_true);
+ d_im.assertInference(
+ aj.eqNode(aj2), true, d_true, PfRule::MACRO_SR_PRED_INTRO);
}
Node bj2 = Rewriter::rewrite(bj);
if (bj != bj2) {
if (!bjExists) {
preRegisterTermInternal(bj);
}
- if (!d_equalityEngine.hasTerm(bj2)) {
+ if (!d_equalityEngine->hasTerm(bj2))
+ {
preRegisterTermInternal(bj2);
}
- d_equalityEngine.assertEquality(bj.eqNode(bj2), true, d_true);
-
+ d_im.assertInference(
+ bj.eqNode(bj2), true, d_true, PfRule::MACRO_SR_PRED_INTRO);
}
if (aj2 == bj2) {
continue;
@@ -2251,28 +2009,32 @@ bool TheoryArrays::dischargeLemmas()
Node eq1 = aj2.eqNode(bj2);
Node eq1_r = Rewriter::rewrite(eq1);
if (eq1_r == d_true) {
- if (!d_equalityEngine.hasTerm(aj2)) {
+ if (!d_equalityEngine->hasTerm(aj2))
+ {
preRegisterTermInternal(aj2);
}
- if (!d_equalityEngine.hasTerm(bj2)) {
+ if (!d_equalityEngine->hasTerm(bj2))
+ {
preRegisterTermInternal(bj2);
}
- d_equalityEngine.assertEquality(eq1, true, d_true);
+ d_im.assertInference(eq1, true, d_true, PfRule::MACRO_SR_PRED_INTRO);
continue;
}
Node eq2 = i.eqNode(j);
Node eq2_r = Rewriter::rewrite(eq2);
if (eq2_r == d_true) {
- d_equalityEngine.assertEquality(eq2, true, d_true);
+ d_im.assertInference(eq2, true, d_true, PfRule::MACRO_SR_PRED_INTRO);
continue;
}
Node lem = nm->mkNode(kind::OR, eq2_r, eq1_r);
- Trace("arrays-lem")<<"Arrays::addRowLemma adding "<<lem<<"\n";
+ Trace("arrays-lem") << "Arrays::addRowLemma (2) adding " << lem << "\n";
d_RowAlreadyAdded.insert(l);
- d_out->lemma(lem);
+ // use non-rewritten nodes, theory preprocessing will rewrite
+ d_im.arrayLemma(
+ aj.eqNode(bj), eq2.notNode(), PfRule::ARRAYS_READ_OVER_WRITE);
++d_numRow;
lemmasAdded = true;
if (options::arraysReduceSharing()) {
@@ -2284,26 +2046,13 @@ bool TheoryArrays::dischargeLemmas()
void TheoryArrays::conflict(TNode a, TNode b) {
Debug("pf::array") << "TheoryArrays::Conflict called" << std::endl;
- std::shared_ptr<eq::EqProof> proof = d_proofsEnabled ?
- std::make_shared<eq::EqProof>() : nullptr;
-
- d_conflictNode = explain(a.eqNode(b), proof.get());
-
- if (!d_inCheckModel) {
- std::unique_ptr<ProofArray> proof_array;
-
- if (d_proofsEnabled) {
- proof->debug_print("pf::array");
- proof_array.reset(new ProofArray(proof,
- /*row=*/d_reasonRow,
- /*row1=*/d_reasonRow1,
- /*ext=*/d_reasonExt));
- }
-
- d_out->conflict(d_conflictNode, std::move(proof_array));
+ if (d_inCheckModel)
+ {
+ // if in check model, don't send the conflict
+ d_state.notifyInConflict();
+ return;
}
-
- d_conflict = true;
+ d_im.conflictEqConstantMerge(a, b);
}
TheoryArrays::TheoryArraysDecisionStrategy::TheoryArraysDecisionStrategy(
@@ -2377,6 +2126,131 @@ TrustNode TheoryArrays::expandDefinition(Node node)
return TrustNode::null();
}
+void TheoryArrays::computeRelevantTerms(std::set<Node>& termSet)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ // make sure RIntro1 reads are included in the relevant set of reads
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(d_equalityEngine);
+ for (; !eqcs_i.isFinished(); ++eqcs_i)
+ {
+ Node eqc = (*eqcs_i);
+ if (!eqc.getType().isArray())
+ {
+ // not an array, skip
+ continue;
+ }
+ eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, d_equalityEngine);
+ for (; !eqc_i.isFinished(); ++eqc_i)
+ {
+ Node n = *eqc_i;
+ if (termSet.find(n) != termSet.end())
+ {
+ if (n.getKind() == kind::STORE)
+ {
+ // Make sure RIntro1 reads are included
+ Node r = nm->mkNode(kind::SELECT, n, n[1]);
+ Trace("arrays::collectModelInfo")
+ << "TheoryArrays::collectModelInfo, adding RIntro1 read: " << r
+ << endl;
+ termSet.insert(r);
+ }
+ }
+ }
+ }
+
+ // Now do a fixed-point iteration to get all reads that need to be included
+ // because of RIntro2 rule
+ bool changed;
+ do
+ {
+ changed = false;
+ eqcs_i = eq::EqClassesIterator(d_equalityEngine);
+ for (; !eqcs_i.isFinished(); ++eqcs_i)
+ {
+ Node eqc = (*eqcs_i);
+ eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, d_equalityEngine);
+ for (; !eqc_i.isFinished(); ++eqc_i)
+ {
+ Node n = *eqc_i;
+ if (n.getKind() == kind::SELECT && termSet.find(n) != termSet.end())
+ {
+ // Find all terms equivalent to n[0] and get corresponding read terms
+ Node array_eqc = d_equalityEngine->getRepresentative(n[0]);
+ eq::EqClassIterator array_eqc_i =
+ eq::EqClassIterator(array_eqc, d_equalityEngine);
+ for (; !array_eqc_i.isFinished(); ++array_eqc_i)
+ {
+ Node arr = *array_eqc_i;
+ if (arr.getKind() == kind::STORE
+ && termSet.find(arr) != termSet.end()
+ && !d_equalityEngine->areEqual(arr[1], n[1]))
+ {
+ Node r = nm->mkNode(kind::SELECT, arr, n[1]);
+ if (termSet.find(r) == termSet.end()
+ && d_equalityEngine->hasTerm(r))
+ {
+ Trace("arrays::collectModelInfo")
+ << "TheoryArrays::collectModelInfo, adding RIntro2(a) "
+ "read: "
+ << r << endl;
+ termSet.insert(r);
+ changed = true;
+ }
+ r = nm->mkNode(kind::SELECT, arr[0], n[1]);
+ if (termSet.find(r) == termSet.end()
+ && d_equalityEngine->hasTerm(r))
+ {
+ Trace("arrays::collectModelInfo")
+ << "TheoryArrays::collectModelInfo, adding RIntro2(b) "
+ "read: "
+ << r << endl;
+ termSet.insert(r);
+ changed = true;
+ }
+ }
+ }
+
+ // Find all stores in which n[0] appears and get corresponding read
+ // terms
+ const CTNodeList* instores = d_infoMap.getInStores(array_eqc);
+ size_t it = 0;
+ for (; it < instores->size(); ++it)
+ {
+ TNode instore = (*instores)[it];
+ Assert(instore.getKind() == kind::STORE);
+ if (termSet.find(instore) != termSet.end()
+ && !d_equalityEngine->areEqual(instore[1], n[1]))
+ {
+ Node r = nm->mkNode(kind::SELECT, instore, n[1]);
+ if (termSet.find(r) == termSet.end()
+ && d_equalityEngine->hasTerm(r))
+ {
+ Trace("arrays::collectModelInfo")
+ << "TheoryArrays::collectModelInfo, adding RIntro2(c) "
+ "read: "
+ << r << endl;
+ termSet.insert(r);
+ changed = true;
+ }
+ r = nm->mkNode(kind::SELECT, instore[0], n[1]);
+ if (termSet.find(r) == termSet.end()
+ && d_equalityEngine->hasTerm(r))
+ {
+ Trace("arrays::collectModelInfo")
+ << "TheoryArrays::collectModelInfo, adding RIntro2(d) "
+ "read: "
+ << r << endl;
+ termSet.insert(r);
+ changed = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ } while (changed);
+}
+
}/* CVC4::theory::arrays namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/arrays/theory_arrays.h b/src/theory/arrays/theory_arrays.h
index a4416ab8c..5236324bc 100644
--- a/src/theory/arrays/theory_arrays.h
+++ b/src/theory/arrays/theory_arrays.h
@@ -2,10 +2,10 @@
/*! \file theory_arrays.h
** \verbatim
** Top contributors (to current version):
- ** Morgan Deters, Clark Barrett, Andrew Reynolds
+ ** Morgan Deters, Andrew Reynolds, Clark Barrett
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -26,10 +26,12 @@
#include "context/cdhashset.h"
#include "context/cdqueue.h"
#include "theory/arrays/array_info.h"
-#include "theory/arrays/array_proof_reconstruction.h"
+#include "theory/arrays/inference_manager.h"
+#include "theory/arrays/proof_checker.h"
#include "theory/arrays/theory_arrays_rewriter.h"
#include "theory/theory.h"
#include "theory/uf/equality_engine.h"
+#include "theory/uf/proof_equality_engine.h"
#include "util/statistics_registry.h"
namespace CVC4 {
@@ -129,15 +131,6 @@ class TheoryArrays : public Theory {
/** conflicts in setModelVal */
IntStat d_numSetModelValConflicts;
- // Merge reason types
-
- /** Merge tag for ROW applications */
- unsigned d_reasonRow;
- /** Merge tag for ROW1 applications */
- unsigned d_reasonRow1;
- /** Merge tag for EXT applications */
- unsigned d_reasonExt;
-
public:
TheoryArrays(context::Context* c,
context::UserContext* u,
@@ -148,9 +141,18 @@ class TheoryArrays : public Theory {
std::string name = "");
~TheoryArrays();
- TheoryRewriter* getTheoryRewriter() override { return &d_rewriter; }
-
- void setMasterEqualityEngine(eq::EqualityEngine* eq) override;
+ //--------------------------------- initialization
+ /** get the official theory rewriter of this theory */
+ TheoryRewriter* getTheoryRewriter() override;
+ /**
+ * Returns true if we need an equality engine. If so, we initialize the
+ * information regarding how it should be setup. For details, see the
+ * documentation in Theory::needsEqualityEngine.
+ */
+ bool needsEqualityEngine(EeSetupInfo& esi) override;
+ /** finish initialization */
+ void finishInit() override;
+ //--------------------------------- end initialization
std::string identify() const override { return std::string("TheoryArrays"); }
@@ -185,9 +187,14 @@ class TheoryArrays : public Theory {
/** The theory rewriter for this theory. */
TheoryArraysRewriter d_rewriter;
+ /** A (default) theory state object */
+ TheoryState d_state;
+ /** The arrays inference manager */
+ InferenceManager d_im;
public:
- PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions) override;
+ PPAssertStatus ppAssert(TrustNode tin,
+ TrustSubstitutionMap& outSubstitutions) override;
TrustNode ppRewrite(TNode atom) override;
/////////////////////////////////////////////////////////////////////////////
@@ -202,11 +209,10 @@ class TheoryArrays : public Theory {
context::CDO<unsigned> d_literalsToPropagateIndex;
/** Should be called to propagate the literal. */
- bool propagate(TNode literal);
+ bool propagateLit(TNode literal);
- /** Explain why this literal is true by adding assumptions */
- void explain(TNode literal, std::vector<TNode>& assumptions,
- eq::EqProof* proof);
+ /** Explain why this literal is true by building an explanation */
+ void explain(TNode literal, Node& exp);
/** For debugging only- checks invariants about when things are preregistered*/
context::CDHashSet<Node, NodeHashFunction > d_isPreRegistered;
@@ -216,8 +222,6 @@ class TheoryArrays : public Theory {
public:
void preRegisterTerm(TNode n) override;
- void propagate(Effort e) override;
- Node explain(TNode n, eq::EqProof* proof);
TrustNode explain(TNode n) override;
/////////////////////////////////////////////////////////////////////////////
@@ -241,8 +245,7 @@ class TheoryArrays : public Theory {
void checkPair(TNode r1, TNode r2);
public:
- void addSharedTerm(TNode t) override;
- EqualityStatus getEqualityStatus(TNode a, TNode b) override;
+ void notifySharedTerm(TNode t) override;
void computeCareGraph() override;
bool isShared(TNode t)
{
@@ -254,7 +257,9 @@ class TheoryArrays : public Theory {
/////////////////////////////////////////////////////////////////////////////
public:
- bool collectModelInfo(TheoryModel* m) override;
+ /** Collect model values in m based on the relevant terms given by termSet */
+ bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet) override;
/////////////////////////////////////////////////////////////////////////////
// NOTIFICATIONS
@@ -268,8 +273,18 @@ class TheoryArrays : public Theory {
// MAIN SOLVER
/////////////////////////////////////////////////////////////////////////////
- public:
- void check(Effort e) override;
+ //--------------------------------- standard check
+ /** Post-check, called after the fact queue of the theory is processed. */
+ void postCheck(Effort level) override;
+ /** Pre-notify fact, return true if processed. */
+ bool preNotifyFact(TNode atom,
+ bool pol,
+ TNode fact,
+ bool isPrereg,
+ bool isInternal) override;
+ /** Notify fact */
+ void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal) override;
+ //--------------------------------- end standard check
private:
TNode weakEquivGetRep(TNode node);
@@ -287,26 +302,17 @@ class TheoryArrays : public Theory {
public:
NotifyClass(TheoryArrays& arrays): d_arrays(arrays) {}
- bool eqNotifyTriggerEquality(TNode equality, bool value) override
- {
- Debug("arrays::propagate") << spaces(d_arrays.getSatContext()->getLevel()) << "NotifyClass::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false") << ")" << std::endl;
- // Just forward to arrays
- if (value) {
- return d_arrays.propagate(equality);
- } else {
- return d_arrays.propagate(equality.notNode());
- }
- }
-
bool eqNotifyTriggerPredicate(TNode predicate, bool value) override
{
- Debug("arrays::propagate") << spaces(d_arrays.getSatContext()->getLevel()) << "NotifyClass::eqNotifyTriggerEquality(" << predicate << ", " << (value ? "true" : "false") << ")" << std::endl;
+ Debug("arrays::propagate")
+ << spaces(d_arrays.getSatContext()->getLevel())
+ << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", "
+ << (value ? "true" : "false") << ")" << std::endl;
// Just forward to arrays
if (value) {
- return d_arrays.propagate(predicate);
- } else {
- return d_arrays.propagate(predicate.notNode());
+ return d_arrays.propagateLit(predicate);
}
+ return d_arrays.propagateLit(predicate.notNode());
}
bool eqNotifyTriggerTermEquality(TheoryId tag,
@@ -316,22 +322,10 @@ class TheoryArrays : public Theory {
{
Debug("arrays::propagate") << spaces(d_arrays.getSatContext()->getLevel()) << "NotifyClass::eqNotifyTriggerTermEquality(" << t1 << ", " << t2 << ", " << (value ? "true" : "false") << ")" << std::endl;
if (value) {
- if (t1.getType().isArray()) {
- if (!d_arrays.isShared(t1) || !d_arrays.isShared(t2)) {
- return true;
- }
- }
// Propagate equality between shared terms
- return d_arrays.propagate(t1.eqNode(t2));
- } else {
- if (t1.getType().isArray()) {
- if (!d_arrays.isShared(t1) || !d_arrays.isShared(t2)) {
- return true;
- }
- }
- return d_arrays.propagate(t1.eqNode(t2).notNode());
+ return d_arrays.propagateLit(t1.eqNode(t2));
}
- return true;
+ return d_arrays.propagateLit(t1.eqNode(t2).notNode());
}
void eqNotifyConstantTermMerge(TNode t1, TNode t2) override
@@ -341,8 +335,7 @@ class TheoryArrays : public Theory {
}
void eqNotifyNewClass(TNode t) override {}
- void eqNotifyPreMerge(TNode t1, TNode t2) override {}
- void eqNotifyPostMerge(TNode t1, TNode t2) override
+ void eqNotifyMerge(TNode t1, TNode t2) override
{
if (t1.getType().isArray()) {
d_arrays.mergeArrays(t1, t2);
@@ -354,11 +347,8 @@ class TheoryArrays : public Theory {
/** The notify class for d_equalityEngine */
NotifyClass d_notify;
- /** Equaltity engine */
- eq::EqualityEngine d_equalityEngine;
-
- /** Are we in conflict? */
- context::CDO<bool> d_conflict;
+ /** The proof checker */
+ ArraysProofRuleChecker d_pchecker;
/** Conflict when merging constants */
void conflict(TNode a, TNode b);
@@ -443,10 +433,9 @@ class TheoryArrays : public Theory {
context::CDList<Node> d_arrayMerges;
std::vector<CTNodeList*> d_readBucketAllocations;
- Node getSkolem(TNode ref, const std::string& name, const TypeNode& type, const std::string& comment, bool makeEqual = true);
+ Node getSkolem(TNode ref);
Node mkAnd(std::vector<TNode>& conjunctions, bool invert = false, unsigned startIndex = 0);
void setNonLinear(TNode a);
- void checkRIntro1(TNode a, TNode b);
Node removeRepLoops(TNode a, TNode rep);
Node expandStores(TNode s, std::vector<TNode>& assumptions, bool checkLoop = false, TNode a = TNode(), TNode b = TNode());
void mergeArrays(TNode a, TNode b);
@@ -461,9 +450,6 @@ class TheoryArrays : public Theory {
bool d_inCheckModel;
int d_topLevel;
- /** An equality-engine callback for proof reconstruction */
- ArrayProofReconstruction d_proofReconstruction;
-
/**
* The decision strategy for the theory of arrays, which calls the
* getNextDecisionEngineRequest function below.
@@ -494,10 +480,11 @@ class TheoryArrays : public Theory {
* for the comparison between the indexes that appears in the lemma.
*/
Node getNextDecisionRequest();
-
- public:
- eq::EqualityEngine* getEqualityEngine() override { return &d_equalityEngine; }
-
+ /**
+ * Compute relevant terms. This includes select nodes for the
+ * RIntro1 and RIntro2 rules.
+ */
+ void computeRelevantTerms(std::set<Node>& termSet) override;
};/* class TheoryArrays */
}/* CVC4::theory::arrays namespace */
diff --git a/src/theory/arrays/theory_arrays_rewriter.cpp b/src/theory/arrays/theory_arrays_rewriter.cpp
index 86e5d8c08..170db6a67 100644
--- a/src/theory/arrays/theory_arrays_rewriter.cpp
+++ b/src/theory/arrays/theory_arrays_rewriter.cpp
@@ -5,7 +5,7 @@
** Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arrays/theory_arrays_rewriter.h b/src/theory/arrays/theory_arrays_rewriter.h
index e8f03c1d0..885711c14 100644
--- a/src/theory/arrays/theory_arrays_rewriter.h
+++ b/src/theory/arrays/theory_arrays_rewriter.h
@@ -2,10 +2,10 @@
/*! \file theory_arrays_rewriter.h
** \verbatim
** Top contributors (to current version):
- ** Clark Barrett, Morgan Deters, Andrew Reynolds
+ ** Clark Barrett, Morgan Deters, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arrays/theory_arrays_type_rules.h b/src/theory/arrays/theory_arrays_type_rules.h
index 56c51d9bf..332e1f2c7 100644
--- a/src/theory/arrays/theory_arrays_type_rules.h
+++ b/src/theory/arrays/theory_arrays_type_rules.h
@@ -2,10 +2,10 @@
/*! \file theory_arrays_type_rules.h
** \verbatim
** Top contributors (to current version):
- ** Morgan Deters, Clark Barrett, Christopher L. Conway
+ ** Morgan Deters, Clark Barrett, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arrays/type_enumerator.h b/src/theory/arrays/type_enumerator.h
index 5894501b2..80ce6b0b8 100644
--- a/src/theory/arrays/type_enumerator.h
+++ b/src/theory/arrays/type_enumerator.h
@@ -5,7 +5,7 @@
** Clark Barrett, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arrays/union_find.cpp b/src/theory/arrays/union_find.cpp
index fe249c50b..8c744936e 100644
--- a/src/theory/arrays/union_find.cpp
+++ b/src/theory/arrays/union_find.cpp
@@ -5,7 +5,7 @@
** Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/arrays/union_find.h b/src/theory/arrays/union_find.h
index f8a7677aa..04c9586d4 100644
--- a/src/theory/arrays/union_find.h
+++ b/src/theory/arrays/union_find.h
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/assertion.cpp b/src/theory/assertion.cpp
index e561052c6..22a6689bb 100644
--- a/src/theory/assertion.cpp
+++ b/src/theory/assertion.cpp
@@ -5,7 +5,7 @@
** Tim King, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/assertion.h b/src/theory/assertion.h
index 14dc7d920..1445ffd7b 100644
--- a/src/theory/assertion.h
+++ b/src/theory/assertion.h
@@ -5,7 +5,7 @@
** Tim King, Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/atom_requests.cpp b/src/theory/atom_requests.cpp
index fb1c8d83f..227074246 100644
--- a/src/theory/atom_requests.cpp
+++ b/src/theory/atom_requests.cpp
@@ -5,7 +5,7 @@
** Dejan Jovanovic, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/atom_requests.h b/src/theory/atom_requests.h
index 29dd4f1a3..255e87a5e 100644
--- a/src/theory/atom_requests.h
+++ b/src/theory/atom_requests.h
@@ -5,7 +5,7 @@
** Dejan Jovanovic, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/bags/bags_rewriter.cpp b/src/theory/bags/bags_rewriter.cpp
new file mode 100644
index 000000000..9479d2cc2
--- /dev/null
+++ b/src/theory/bags/bags_rewriter.cpp
@@ -0,0 +1,508 @@
+/********************* */
+/*! \file bags_rewriter.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Bags theory rewriter.
+ **/
+
+#include "theory/bags/bags_rewriter.h"
+
+#include "theory/bags/normal_form.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+BagsRewriteResponse::BagsRewriteResponse()
+ : d_node(Node::null()), d_rewrite(Rewrite::NONE)
+{
+}
+
+BagsRewriteResponse::BagsRewriteResponse(Node n, Rewrite rewrite)
+ : d_node(n), d_rewrite(rewrite)
+{
+}
+
+BagsRewriteResponse::BagsRewriteResponse(const BagsRewriteResponse& r)
+ : d_node(r.d_node), d_rewrite(r.d_rewrite)
+{
+}
+
+BagsRewriter::BagsRewriter(HistogramStat<Rewrite>* statistics)
+ : d_statistics(statistics)
+{
+ d_nm = NodeManager::currentNM();
+}
+
+RewriteResponse BagsRewriter::postRewrite(TNode n)
+{
+ BagsRewriteResponse response;
+ if (n.isConst())
+ {
+ // no need to rewrite n if it is already in a normal form
+ response = BagsRewriteResponse(n, Rewrite::NONE);
+ }
+ else if(n.getKind() == EQUAL)
+ {
+ response = postRewriteEqual(n);
+ }
+ else if (NormalForm::areChildrenConstants(n))
+ {
+ Node value = NormalForm::evaluate(n);
+ response = BagsRewriteResponse(value, Rewrite::CONSTANT_EVALUATION);
+ }
+ else
+ {
+ Kind k = n.getKind();
+ switch (k)
+ {
+ case MK_BAG: response = rewriteMakeBag(n); break;
+ case BAG_COUNT: response = rewriteBagCount(n); break;
+ case DUPLICATE_REMOVAL: response = rewriteDuplicateRemoval(n); break;
+ case UNION_MAX: response = rewriteUnionMax(n); break;
+ case UNION_DISJOINT: response = rewriteUnionDisjoint(n); break;
+ case INTERSECTION_MIN: response = rewriteIntersectionMin(n); break;
+ case DIFFERENCE_SUBTRACT: response = rewriteDifferenceSubtract(n); break;
+ case DIFFERENCE_REMOVE: response = rewriteDifferenceRemove(n); break;
+ case BAG_CHOOSE: response = rewriteChoose(n); break;
+ case BAG_CARD: response = rewriteCard(n); break;
+ case BAG_IS_SINGLETON: response = rewriteIsSingleton(n); break;
+ case BAG_FROM_SET: response = rewriteFromSet(n); break;
+ case BAG_TO_SET: response = rewriteToSet(n); break;
+ default: response = BagsRewriteResponse(n, Rewrite::NONE); break;
+ }
+ }
+
+ Trace("bags-rewrite") << "postRewrite " << n << " to " << response.d_node
+ << " by " << response.d_rewrite << "." << std::endl;
+
+ if (d_statistics != nullptr)
+ {
+ (*d_statistics) << response.d_rewrite;
+ }
+ if (response.d_node != n)
+ {
+ return RewriteResponse(RewriteStatus::REWRITE_AGAIN_FULL, response.d_node);
+ }
+ return RewriteResponse(RewriteStatus::REWRITE_DONE, n);
+}
+
+RewriteResponse BagsRewriter::preRewrite(TNode n)
+{
+ BagsRewriteResponse response;
+ Kind k = n.getKind();
+ switch (k)
+ {
+ case EQUAL: response = preRewriteEqual(n); break;
+ case SUBBAG: response = rewriteSubBag(n); break;
+ default: response = BagsRewriteResponse(n, Rewrite::NONE);
+ }
+
+ Trace("bags-rewrite") << "preRewrite " << n << " to " << response.d_node
+ << " by " << response.d_rewrite << "." << std::endl;
+
+ if (d_statistics != nullptr)
+ {
+ (*d_statistics) << response.d_rewrite;
+ }
+ if (response.d_node != n)
+ {
+ return RewriteResponse(RewriteStatus::REWRITE_AGAIN_FULL, response.d_node);
+ }
+ return RewriteResponse(RewriteStatus::REWRITE_DONE, n);
+}
+
+BagsRewriteResponse BagsRewriter::preRewriteEqual(const TNode& n) const
+{
+ Assert(n.getKind() == EQUAL);
+ if (n[0] == n[1])
+ {
+ // (= A A) = true where A is a bag
+ return BagsRewriteResponse(d_nm->mkConst(true), Rewrite::IDENTICAL_NODES);
+ }
+ return BagsRewriteResponse(n, Rewrite::NONE);
+}
+
+BagsRewriteResponse BagsRewriter::rewriteSubBag(const TNode& n) const
+{
+ Assert(n.getKind() == SUBBAG);
+
+ // (bag.is_included A B) = ((difference_subtract A B) == emptybag)
+ Node emptybag = d_nm->mkConst(EmptyBag(n[0].getType()));
+ Node subtract = d_nm->mkNode(DIFFERENCE_SUBTRACT, n[0], n[1]);
+ Node equal = subtract.eqNode(emptybag);
+ return BagsRewriteResponse(equal, Rewrite::SUB_BAG);
+}
+
+BagsRewriteResponse BagsRewriter::rewriteMakeBag(const TNode& n) const
+{
+ Assert(n.getKind() == MK_BAG);
+ // return emptybag for negative or zero multiplicity
+ if (n[1].isConst() && n[1].getConst<Rational>().sgn() != 1)
+ {
+ // (mkBag x c) = emptybag where c <= 0
+ Node emptybag = d_nm->mkConst(EmptyBag(n.getType()));
+ return BagsRewriteResponse(emptybag, Rewrite::MK_BAG_COUNT_NEGATIVE);
+ }
+ return BagsRewriteResponse(n, Rewrite::NONE);
+}
+
+BagsRewriteResponse BagsRewriter::rewriteBagCount(const TNode& n) const
+{
+ Assert(n.getKind() == BAG_COUNT);
+ if (n[1].isConst() && n[1].getKind() == EMPTYBAG)
+ {
+ // (bag.count x emptybag) = 0
+ return BagsRewriteResponse(d_nm->mkConst(Rational(0)),
+ Rewrite::COUNT_EMPTY);
+ }
+ if (n[1].getKind() == MK_BAG && n[0] == n[1][0])
+ {
+ // (bag.count x (mkBag x c) = c where c > 0 is a constant
+ return BagsRewriteResponse(n[1][1], Rewrite::COUNT_MK_BAG);
+ }
+ return BagsRewriteResponse(n, Rewrite::NONE);
+}
+
+BagsRewriteResponse BagsRewriter::rewriteDuplicateRemoval(const TNode& n) const
+{
+ Assert(n.getKind() == DUPLICATE_REMOVAL);
+ if (n[0].getKind() == MK_BAG && n[0][1].isConst()
+ && n[0][1].getConst<Rational>().sgn() == 1)
+ {
+ // (duplicate_removal (mkBag x n)) = (mkBag x 1)
+ // where n is a positive constant
+ Node one = NodeManager::currentNM()->mkConst(Rational(1));
+ Node bag = d_nm->mkBag(n[0][0].getType(), n[0][0], one);
+ return BagsRewriteResponse(bag, Rewrite::DUPLICATE_REMOVAL_MK_BAG);
+ }
+ return BagsRewriteResponse(n, Rewrite::NONE);
+}
+
+BagsRewriteResponse BagsRewriter::rewriteUnionMax(const TNode& n) const
+{
+ Assert(n.getKind() == UNION_MAX);
+ if (n[1].getKind() == EMPTYBAG || n[0] == n[1])
+ {
+ // (union_max A A) = A
+ // (union_max A emptybag) = A
+ return BagsRewriteResponse(n[0], Rewrite::UNION_MAX_SAME_OR_EMPTY);
+ }
+ if (n[0].getKind() == EMPTYBAG)
+ {
+ // (union_max emptybag A) = A
+ return BagsRewriteResponse(n[1], Rewrite::UNION_MAX_EMPTY);
+ }
+
+ if ((n[1].getKind() == UNION_MAX || n[1].getKind() == UNION_DISJOINT)
+ && (n[0] == n[1][0] || n[0] == n[1][1]))
+ {
+ // (union_max A (union_max A B)) = (union_max A B)
+ // (union_max A (union_max B A)) = (union_max B A)
+ // (union_max A (union_disjoint A B)) = (union_disjoint A B)
+ // (union_max A (union_disjoint B A)) = (union_disjoint B A)
+ return BagsRewriteResponse(n[1], Rewrite::UNION_MAX_UNION_LEFT);
+ }
+
+ if ((n[0].getKind() == UNION_MAX || n[0].getKind() == UNION_DISJOINT)
+ && (n[0][0] == n[1] || n[0][1] == n[1]))
+ {
+ // (union_max (union_max A B) A)) = (union_max A B)
+ // (union_max (union_max B A) A)) = (union_max B A)
+ // (union_max (union_disjoint A B) A)) = (union_disjoint A B)
+ // (union_max (union_disjoint B A) A)) = (union_disjoint B A)
+ return BagsRewriteResponse(n[0], Rewrite::UNION_MAX_UNION_RIGHT);
+ }
+ return BagsRewriteResponse(n, Rewrite::NONE);
+}
+
+BagsRewriteResponse BagsRewriter::rewriteUnionDisjoint(const TNode& n) const
+{
+ Assert(n.getKind() == UNION_DISJOINT);
+ if (n[1].getKind() == EMPTYBAG)
+ {
+ // (union_disjoint A emptybag) = A
+ return BagsRewriteResponse(n[0], Rewrite::UNION_DISJOINT_EMPTY_RIGHT);
+ }
+ if (n[0].getKind() == EMPTYBAG)
+ {
+ // (union_disjoint emptybag A) = A
+ return BagsRewriteResponse(n[1], Rewrite::UNION_DISJOINT_EMPTY_LEFT);
+ }
+ if ((n[0].getKind() == UNION_MAX && n[1].getKind() == INTERSECTION_MIN)
+ || (n[1].getKind() == UNION_MAX && n[0].getKind() == INTERSECTION_MIN))
+
+ {
+ // (union_disjoint (union_max A B) (intersection_min A B)) =
+ // (union_disjoint A B) // sum(a,b) = max(a,b) + min(a,b)
+ // check if the operands of union_max and intersection_min are the same
+ std::set<Node> left(n[0].begin(), n[0].end());
+ std::set<Node> right(n[0].begin(), n[0].end());
+ if (left == right)
+ {
+ Node rewritten = d_nm->mkNode(UNION_DISJOINT, n[0][0], n[0][1]);
+ return BagsRewriteResponse(rewritten, Rewrite::UNION_DISJOINT_MAX_MIN);
+ }
+ }
+ return BagsRewriteResponse(n, Rewrite::NONE);
+}
+
+BagsRewriteResponse BagsRewriter::rewriteIntersectionMin(const TNode& n) const
+{
+ Assert(n.getKind() == INTERSECTION_MIN);
+ if (n[0].getKind() == EMPTYBAG)
+ {
+ // (intersection_min emptybag A) = emptybag
+ return BagsRewriteResponse(n[0], Rewrite::INTERSECTION_EMPTY_LEFT);
+ }
+ if (n[1].getKind() == EMPTYBAG)
+ {
+ // (intersection_min A emptybag) = emptybag
+ return BagsRewriteResponse(n[1], Rewrite::INTERSECTION_EMPTY_RIGHT);
+ }
+ if (n[0] == n[1])
+ {
+ // (intersection_min A A) = A
+ return BagsRewriteResponse(n[0], Rewrite::INTERSECTION_SAME);
+ }
+ if (n[1].getKind() == UNION_DISJOINT || n[1].getKind() == UNION_MAX)
+ {
+ if (n[0] == n[1][0] || n[0] == n[1][1])
+ {
+ // (intersection_min A (union_disjoint A B)) = A
+ // (intersection_min A (union_disjoint B A)) = A
+ // (intersection_min A (union_max A B)) = A
+ // (intersection_min A (union_max B A)) = A
+ return BagsRewriteResponse(n[0], Rewrite::INTERSECTION_SHARED_LEFT);
+ }
+ }
+
+ if (n[0].getKind() == UNION_DISJOINT || n[0].getKind() == UNION_MAX)
+ {
+ if (n[1] == n[0][0] || n[1] == n[0][1])
+ {
+ // (intersection_min (union_disjoint A B) A) = A
+ // (intersection_min (union_disjoint B A) A) = A
+ // (intersection_min (union_max A B) A) = A
+ // (intersection_min (union_max B A) A) = A
+ return BagsRewriteResponse(n[1], Rewrite::INTERSECTION_SHARED_RIGHT);
+ }
+ }
+
+ return BagsRewriteResponse(n, Rewrite::NONE);
+}
+
+BagsRewriteResponse BagsRewriter::rewriteDifferenceSubtract(
+ const TNode& n) const
+{
+ Assert(n.getKind() == DIFFERENCE_SUBTRACT);
+ if (n[0].getKind() == EMPTYBAG || n[1].getKind() == EMPTYBAG)
+ {
+ // (difference_subtract A emptybag) = A
+ // (difference_subtract emptybag A) = emptybag
+ return BagsRewriteResponse(n[0], Rewrite::SUBTRACT_RETURN_LEFT);
+ }
+ if (n[0] == n[1])
+ {
+ // (difference_subtract A A) = emptybag
+ Node emptyBag = d_nm->mkConst(EmptyBag(n.getType()));
+ return BagsRewriteResponse(emptyBag, Rewrite::SUBTRACT_SAME);
+ }
+
+ if (n[0].getKind() == UNION_DISJOINT)
+ {
+ if (n[1] == n[0][0])
+ {
+ // (difference_subtract (union_disjoint A B) A) = B
+ return BagsRewriteResponse(n[0][1],
+ Rewrite::SUBTRACT_DISJOINT_SHARED_LEFT);
+ }
+ if (n[1] == n[0][1])
+ {
+ // (difference_subtract (union_disjoint B A) A) = B
+ return BagsRewriteResponse(n[0][0],
+ Rewrite::SUBTRACT_DISJOINT_SHARED_RIGHT);
+ }
+ }
+
+ if (n[1].getKind() == UNION_DISJOINT || n[1].getKind() == UNION_MAX)
+ {
+ if (n[0] == n[1][0] || n[0] == n[1][1])
+ {
+ // (difference_subtract A (union_disjoint A B)) = emptybag
+ // (difference_subtract A (union_disjoint B A)) = emptybag
+ // (difference_subtract A (union_max A B)) = emptybag
+ // (difference_subtract A (union_max B A)) = emptybag
+ Node emptyBag = d_nm->mkConst(EmptyBag(n.getType()));
+ return BagsRewriteResponse(emptyBag, Rewrite::SUBTRACT_FROM_UNION);
+ }
+ }
+
+ if (n[0].getKind() == INTERSECTION_MIN)
+ {
+ if (n[1] == n[0][0] || n[1] == n[0][1])
+ {
+ // (difference_subtract (intersection_min A B) A) = emptybag
+ // (difference_subtract (intersection_min B A) A) = emptybag
+ Node emptyBag = d_nm->mkConst(EmptyBag(n.getType()));
+ return BagsRewriteResponse(emptyBag, Rewrite::SUBTRACT_MIN);
+ }
+ }
+
+ return BagsRewriteResponse(n, Rewrite::NONE);
+}
+
+BagsRewriteResponse BagsRewriter::rewriteDifferenceRemove(const TNode& n) const
+{
+ Assert(n.getKind() == DIFFERENCE_REMOVE);
+
+ if (n[0].getKind() == EMPTYBAG || n[1].getKind() == EMPTYBAG)
+ {
+ // (difference_remove A emptybag) = A
+ // (difference_remove emptybag B) = emptybag
+ return BagsRewriteResponse(n[0], Rewrite::REMOVE_RETURN_LEFT);
+ }
+
+ if (n[0] == n[1])
+ {
+ // (difference_remove A A) = emptybag
+ Node emptyBag = d_nm->mkConst(EmptyBag(n.getType()));
+ return BagsRewriteResponse(emptyBag, Rewrite::REMOVE_SAME);
+ }
+
+ if (n[1].getKind() == UNION_DISJOINT || n[1].getKind() == UNION_MAX)
+ {
+ if (n[0] == n[1][0] || n[0] == n[1][1])
+ {
+ // (difference_remove A (union_disjoint A B)) = emptybag
+ // (difference_remove A (union_disjoint B A)) = emptybag
+ // (difference_remove A (union_max A B)) = emptybag
+ // (difference_remove A (union_max B A)) = emptybag
+ Node emptyBag = d_nm->mkConst(EmptyBag(n.getType()));
+ return BagsRewriteResponse(emptyBag, Rewrite::REMOVE_FROM_UNION);
+ }
+ }
+
+ if (n[0].getKind() == INTERSECTION_MIN)
+ {
+ if (n[1] == n[0][0] || n[1] == n[0][1])
+ {
+ // (difference_remove (intersection_min A B) A) = emptybag
+ // (difference_remove (intersection_min B A) A) = emptybag
+ Node emptyBag = d_nm->mkConst(EmptyBag(n.getType()));
+ return BagsRewriteResponse(emptyBag, Rewrite::REMOVE_MIN);
+ }
+ }
+
+ return BagsRewriteResponse(n, Rewrite::NONE);
+}
+
+BagsRewriteResponse BagsRewriter::rewriteChoose(const TNode& n) const
+{
+ Assert(n.getKind() == BAG_CHOOSE);
+ if (n[0].getKind() == MK_BAG && n[0][1].isConst())
+ {
+ // (bag.choose (mkBag x c)) = x where c is a constant > 0
+ return BagsRewriteResponse(n[0][0], Rewrite::CHOOSE_MK_BAG);
+ }
+ return BagsRewriteResponse(n, Rewrite::NONE);
+}
+
+BagsRewriteResponse BagsRewriter::rewriteCard(const TNode& n) const
+{
+ Assert(n.getKind() == BAG_CARD);
+ if (n[0].getKind() == MK_BAG && n[0][1].isConst())
+ {
+ // (bag.card (mkBag x c)) = c where c is a constant > 0
+ return BagsRewriteResponse(n[0][1], Rewrite::CARD_MK_BAG);
+ }
+
+ if (n[0].getKind() == UNION_DISJOINT)
+ {
+ // (bag.card (union-disjoint A B)) = (+ (bag.card A) (bag.card B))
+ Node A = d_nm->mkNode(BAG_CARD, n[0][0]);
+ Node B = d_nm->mkNode(BAG_CARD, n[0][1]);
+ Node plus = d_nm->mkNode(PLUS, A, B);
+ return BagsRewriteResponse(plus, Rewrite::CARD_DISJOINT);
+ }
+
+ return BagsRewriteResponse(n, Rewrite::NONE);
+}
+
+BagsRewriteResponse BagsRewriter::rewriteIsSingleton(const TNode& n) const
+{
+ Assert(n.getKind() == BAG_IS_SINGLETON);
+ if (n[0].getKind() == MK_BAG)
+ {
+ // (bag.is_singleton (mkBag x c)) = (c == 1)
+ Node one = d_nm->mkConst(Rational(1));
+ Node equal = n[0][1].eqNode(one);
+ return BagsRewriteResponse(equal, Rewrite::IS_SINGLETON_MK_BAG);
+ }
+ return BagsRewriteResponse(n, Rewrite::NONE);
+}
+
+BagsRewriteResponse BagsRewriter::rewriteFromSet(const TNode& n) const
+{
+ Assert(n.getKind() == BAG_FROM_SET);
+ if (n[0].getKind() == SINGLETON)
+ {
+ // (bag.from_set (singleton (singleton_op Int) x)) = (mkBag x 1)
+ Node one = d_nm->mkConst(Rational(1));
+ TypeNode type = n[0].getType().getSetElementType();
+ Node bag = d_nm->mkBag(type, n[0][0], one);
+ return BagsRewriteResponse(bag, Rewrite::FROM_SINGLETON);
+ }
+ return BagsRewriteResponse(n, Rewrite::NONE);
+}
+
+BagsRewriteResponse BagsRewriter::rewriteToSet(const TNode& n) const
+{
+ Assert(n.getKind() == BAG_TO_SET);
+ if (n[0].getKind() == MK_BAG && n[0][1].isConst()
+ && n[0][1].getConst<Rational>().sgn() == 1)
+ {
+ // (bag.to_set (mkBag x n)) = (singleton (singleton_op T) x)
+ // where n is a positive constant and T is the type of the bag's elements
+ Node set = d_nm->mkSingleton(n[0][0].getType(), n[0][0]);
+ return BagsRewriteResponse(set, Rewrite::TO_SINGLETON);
+ }
+ return BagsRewriteResponse(n, Rewrite::NONE);
+}
+
+BagsRewriteResponse BagsRewriter::postRewriteEqual(const TNode& n) const
+{
+ Assert(n.getKind() == kind::EQUAL);
+ if (n[0] == n[1])
+ {
+ Node ret = NodeManager::currentNM()->mkConst(true);
+ return BagsRewriteResponse(ret, Rewrite::EQ_REFL);
+ }
+
+ if (n[0].isConst() && n[1].isConst())
+ {
+ Node ret = NodeManager::currentNM()->mkConst(false);
+ return BagsRewriteResponse(ret, Rewrite::EQ_CONST_FALSE);
+ }
+
+ // standard ordering
+ if (n[0] > n[1])
+ {
+ Node ret = NodeManager::currentNM()->mkNode(kind::EQUAL, n[1], n[0]);
+ return BagsRewriteResponse(ret, Rewrite::EQ_SYM);
+ }
+ return BagsRewriteResponse(n, Rewrite::NONE);
+}
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/bags/bags_rewriter.h b/src/theory/bags/bags_rewriter.h
new file mode 100644
index 000000000..a9b3b90bb
--- /dev/null
+++ b/src/theory/bags/bags_rewriter.h
@@ -0,0 +1,224 @@
+/********************* */
+/*! \file bags_rewriter.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Bags theory rewriter.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__BAGS__THEORY_BAGS_REWRITER_H
+#define CVC4__THEORY__BAGS__THEORY_BAGS_REWRITER_H
+
+#include "theory/bags/rewrites.h"
+#include "theory/rewriter.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+/** a class represents the result of rewriting bag nodes */
+struct BagsRewriteResponse
+{
+ BagsRewriteResponse();
+ BagsRewriteResponse(Node n, Rewrite rewrite);
+ BagsRewriteResponse(const BagsRewriteResponse& r);
+ /** the rewritten node */
+ Node d_node;
+ /** type of rewrite used by bags */
+ Rewrite d_rewrite;
+
+}; /* struct BagsRewriteResponse */
+
+class BagsRewriter : public TheoryRewriter
+{
+ public:
+ BagsRewriter(HistogramStat<Rewrite>* statistics = nullptr);
+
+ /**
+ * postRewrite nodes with kinds: MK_BAG, BAG_COUNT, UNION_MAX, UNION_DISJOINT,
+ * INTERSECTION_MIN, DIFFERENCE_SUBTRACT, DIFFERENCE_REMOVE, BAG_CHOOSE,
+ * BAG_CARD, BAG_IS_SINGLETON.
+ * See the rewrite rules for these kinds below.
+ */
+ RewriteResponse postRewrite(TNode n) override;
+ /**
+ * preRewrite nodes with kinds: EQUAL, SUBBAG.
+ * See the rewrite rules for these kinds below.
+ */
+ RewriteResponse preRewrite(TNode n) override;
+
+ private:
+ /**
+ * rewrites for n include:
+ * - (= A A) = true where A is a bag
+ */
+ BagsRewriteResponse preRewriteEqual(const TNode& n) const;
+
+ /**
+ * rewrites for n include:
+ * - (bag.is_included A B) = ((difference_subtract A B) == emptybag)
+ */
+ BagsRewriteResponse rewriteSubBag(const TNode& n) const;
+
+ /**
+ * rewrites for n include:
+ * - (mkBag x 0) = (emptybag T) where T is the type of x
+ * - (mkBag x (-c)) = (emptybag T) where T is the type of x, and c > 0 is a
+ * constant
+ * - otherwise = n
+ */
+ BagsRewriteResponse rewriteMakeBag(const TNode& n) const;
+
+ /**
+ * rewrites for n include:
+ * - (bag.count x emptybag) = 0
+ * - (bag.count x (mkBag x c) = c where c > 0 is a constant
+ * - otherwise = n
+ */
+ BagsRewriteResponse rewriteBagCount(const TNode& n) const;
+
+ /**
+ * rewrites for n include:
+ * - (duplicate_removal (mkBag x n)) = (mkBag x 1)
+ * where n is a positive constant
+ */
+ BagsRewriteResponse rewriteDuplicateRemoval(const TNode& n) const;
+
+ /**
+ * rewrites for n include:
+ * - (union_max A emptybag) = A
+ * - (union_max emptybag A) = A
+ * - (union_max A A) = A
+ * - (union_max A (union_max A B)) = (union_max A B)
+ * - (union_max A (union_max B A)) = (union_max B A)
+ * - (union_max (union_max A B) A) = (union_max A B)
+ * - (union_max (union_max B A) A) = (union_max B A)
+ * - (union_max A (union_disjoint A B)) = (union_disjoint A B)
+ * - (union_max A (union_disjoint B A)) = (union_disjoint B A)
+ * - (union_max (union_disjoint A B) A) = (union_disjoint A B)
+ * - (union_max (union_disjoint B A) A) = (union_disjoint B A)
+ * - otherwise = n
+ */
+ BagsRewriteResponse rewriteUnionMax(const TNode& n) const;
+
+ /**
+ * rewrites for n include:
+ * - (union_disjoint A emptybag) = A
+ * - (union_disjoint emptybag A) = A
+ * - (union_disjoint (union_max A B) (intersection_min A B)) =
+ * (union_disjoint A B) // sum(a,b) = max(a,b) + min(a,b)
+ * - other permutations of the above like swapping A and B, or swapping
+ * intersection_min and union_max
+ * - otherwise = n
+ */
+ BagsRewriteResponse rewriteUnionDisjoint(const TNode& n) const;
+
+ /**
+ * rewrites for n include:
+ * - (intersection_min A emptybag) = emptybag
+ * - (intersection_min emptybag A) = emptybag
+ * - (intersection_min A A) = A
+ * - (intersection_min A (union_disjoint A B)) = A
+ * - (intersection_min A (union_disjoint B A)) = A
+ * - (intersection_min (union_disjoint A B) A) = A
+ * - (intersection_min (union_disjoint B A) A) = A
+ * - (intersection_min A (union_max A B)) = A
+ * - (intersection_min A (union_max B A)) = A
+ * - (intersection_min (union_max A B) A) = A
+ * - (intersection_min (union_max B A) A) = A
+ * - otherwise = n
+ */
+ BagsRewriteResponse rewriteIntersectionMin(const TNode& n) const;
+
+ /**
+ * rewrites for n include:
+ * - (difference_subtract A emptybag) = A
+ * - (difference_subtract emptybag A) = emptybag
+ * - (difference_subtract A A) = emptybag
+ * - (difference_subtract (union_disjoint A B) A) = B
+ * - (difference_subtract (union_disjoint B A) A) = B
+ * - (difference_subtract A (union_disjoint A B)) = emptybag
+ * - (difference_subtract A (union_disjoint B A)) = emptybag
+ * - (difference_subtract A (union_max A B)) = emptybag
+ * - (difference_subtract A (union_max B A)) = emptybag
+ * - (difference_subtract (intersection_min A B) A) = emptybag
+ * - (difference_subtract (intersection_min B A) A) = emptybag
+ * - otherwise = n
+ */
+ BagsRewriteResponse rewriteDifferenceSubtract(const TNode& n) const;
+
+ /**
+ * rewrites for n include:
+ * - (difference_remove A emptybag) = A
+ * - (difference_remove emptybag A) = emptybag
+ * - (difference_remove A A) = emptybag
+ * - (difference_remove A (union_disjoint A B)) = emptybag
+ * - (difference_remove A (union_disjoint B A)) = emptybag
+ * - (difference_remove A (union_max A B)) = emptybag
+ * - (difference_remove A (union_max B A)) = emptybag
+ * - (difference_remove (intersection_min A B) A) = emptybag
+ * - (difference_remove (intersection_min B A) A) = emptybag
+ * - otherwise = n
+ */
+ BagsRewriteResponse rewriteDifferenceRemove(const TNode& n) const;
+ /**
+ * rewrites for n include:
+ * - (bag.choose (mkBag x c)) = x where c is a constant > 0
+ * - otherwise = n
+ */
+ BagsRewriteResponse rewriteChoose(const TNode& n) const;
+ /**
+ * rewrites for n include:
+ * - (bag.card (mkBag x c)) = c where c is a constant > 0
+ * - (bag.card (union-disjoint A B)) = (+ (bag.card A) (bag.card B))
+ * - otherwise = n
+ */
+ BagsRewriteResponse rewriteCard(const TNode& n) const;
+
+ /**
+ * rewrites for n include:
+ * - (bag.is_singleton (mkBag x c)) = (c == 1)
+ */
+ BagsRewriteResponse rewriteIsSingleton(const TNode& n) const;
+
+ /**
+ * rewrites for n include:
+ * - (bag.from_set (singleton (singleton_op Int) x)) = (mkBag x 1)
+ */
+ BagsRewriteResponse rewriteFromSet(const TNode& n) const;
+
+ /**
+ * rewrites for n include:
+ * - (bag.to_set (mkBag x n)) = (singleton (singleton_op T) x)
+ * where n is a positive constant and T is the type of the bag's elements
+ */
+ BagsRewriteResponse rewriteToSet(const TNode& n) const;
+
+ /**
+ * rewrites for n include:
+ * - (= A A) = true
+ * - (= A B) = false if A and B are different bag constants
+ * - (= B A) = (= A B) if A < B and at least one of A or B is not a constant
+ */
+ BagsRewriteResponse postRewriteEqual(const TNode& n) const;
+
+ private:
+ /** Reference to the rewriter statistics. */
+ NodeManager* d_nm;
+ /** Reference to the rewriter statistics. */
+ HistogramStat<Rewrite>* d_statistics;
+}; /* class TheoryBagsRewriter */
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__BAGS__THEORY_BAGS_REWRITER_H */
diff --git a/src/theory/bags/bags_statistics.cpp b/src/theory/bags/bags_statistics.cpp
new file mode 100644
index 000000000..ea3d3046e
--- /dev/null
+++ b/src/theory/bags/bags_statistics.cpp
@@ -0,0 +1,35 @@
+/********************* */
+/*! \file bags_statistics.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Statistics for the theory of bags
+ **/
+
+#include "theory/bags/bags_statistics.h"
+
+#include "smt/smt_statistics_registry.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+BagsStatistics::BagsStatistics() : d_rewrites("theory::bags::rewrites")
+{
+ smtStatisticsRegistry()->registerStat(&d_rewrites);
+}
+
+BagsStatistics::~BagsStatistics()
+{
+ smtStatisticsRegistry()->unregisterStat(&d_rewrites);
+}
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/bags/bags_statistics.h b/src/theory/bags/bags_statistics.h
new file mode 100644
index 000000000..457e3a32e
--- /dev/null
+++ b/src/theory/bags/bags_statistics.h
@@ -0,0 +1,45 @@
+/********************* */
+/*! \file bags_statistics.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Statistics for the theory of bags
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__BAGS_STATISTICS_H
+#define CVC4__THEORY__BAGS_STATISTICS_H
+
+#include "expr/kind.h"
+#include "theory/bags/rewrites.h"
+#include "util/statistics_registry.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+/**
+ * Statistics for the theory of bags.
+ */
+class BagsStatistics
+{
+ public:
+ BagsStatistics();
+ ~BagsStatistics();
+
+ /** Counts the number of applications of each type of rewrite rule */
+ HistogramStat<Rewrite> d_rewrites;
+};
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__BAGS_STATISTICS_H */
diff --git a/src/theory/bags/inference_manager.cpp b/src/theory/bags/inference_manager.cpp
new file mode 100644
index 000000000..4d18ad926
--- /dev/null
+++ b/src/theory/bags/inference_manager.cpp
@@ -0,0 +1,35 @@
+/********************* */
+/*! \file inference_manager.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of the inference manager for the theory of bags
+ **/
+
+#include "theory/bags/inference_manager.h"
+
+using namespace std;
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+InferenceManager::InferenceManager(Theory& t,
+ SolverState& s,
+ ProofNodeManager* pnm)
+ : InferenceManagerBuffered(t, s, pnm), d_state(s)
+{
+ d_true = NodeManager::currentNM()->mkConst(true);
+ d_false = NodeManager::currentNM()->mkConst(false);
+}
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/bags/inference_manager.h b/src/theory/bags/inference_manager.h
new file mode 100644
index 000000000..4b4edbaef
--- /dev/null
+++ b/src/theory/bags/inference_manager.h
@@ -0,0 +1,57 @@
+/********************* */
+/*! \file inference_manager.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The inference manager for the theory of bags.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__BAGS__INFERENCE_MANAGER_H
+#define CVC4__THEORY__BAGS__INFERENCE_MANAGER_H
+
+#include "theory/bags/solver_state.h"
+#include "theory/inference_manager_buffered.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+/** Inference manager
+ *
+ * This class manages inferences produced by the theory of bags. It manages
+ * whether inferences are processed as external lemmas on the output channel
+ * of theory of bags or internally as literals asserted to the equality engine
+ * of theory of bags. The latter literals are referred to as "facts".
+ */
+class InferenceManager : public InferenceManagerBuffered
+{
+ typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
+
+ public:
+ InferenceManager(Theory& t, SolverState& s, ProofNodeManager* pnm);
+
+ private:
+ /** constants */
+ Node d_true;
+ Node d_false;
+ /**
+ * Reference to the state object for the theory of bags. We store the
+ * (derived) state here, since it has additional methods required in this
+ * class.
+ */
+ SolverState& d_state;
+};
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__BAGS__INFERENCE_MANAGER_H */
diff --git a/src/theory/bags/kinds b/src/theory/bags/kinds
new file mode 100644
index 000000000..f84b811e7
--- /dev/null
+++ b/src/theory/bags/kinds
@@ -0,0 +1,93 @@
+# kinds -*- sh -*-
+#
+# For documentation on this file format, please refer to
+# src/theory/builtin/kinds.
+#
+
+theory THEORY_BAGS \
+ ::CVC4::theory::bags::TheoryBags \
+ "theory/bags/theory_bags.h"
+typechecker "theory/bags/theory_bags_type_rules.h"
+rewriter ::CVC4::theory::bags::BagsRewriter \
+ "theory/bags/bags_rewriter.h"
+
+properties parametric
+properties check propagate presolve
+
+# constants
+constant EMPTYBAG \
+ ::CVC4::EmptyBag \
+ ::CVC4::EmptyBagHashFunction \
+ "expr/emptybag.h" \
+ "the empty bag constant; payload is an instance of the CVC4::EmptyBag class"
+
+# the type
+operator BAG_TYPE 1 "bag type, takes as parameter the type of the elements"
+cardinality BAG_TYPE \
+ "::CVC4::theory::bags::BagsProperties::computeCardinality(%TYPE%)" \
+ "theory/bags/theory_bags_type_rules.h"
+well-founded BAG_TYPE \
+ "::CVC4::theory::bags::BagsProperties::isWellFounded(%TYPE%)" \
+ "::CVC4::theory::bags::BagsProperties::mkGroundTerm(%TYPE%)" \
+ "theory/bags/theory_bags_type_rules.h"
+enumerator BAG_TYPE \
+ "::CVC4::theory::bags::BagEnumerator" \
+ "theory/bags/theory_bags_type_enumerator.h"
+
+# operators
+operator UNION_MAX 2 "union for bags (max)"
+operator UNION_DISJOINT 2 "disjoint union for bags (sum)"
+operator INTERSECTION_MIN 2 "bag intersection (min)"
+
+# {("a", 2), ("b", 3)} \ {("a", 1)} = {("a", 1), ("b", 3)}
+operator DIFFERENCE_SUBTRACT 2 "bag difference1 (subtracts multiplicities)"
+
+# {("a", 2), ("b", 3)} \\ {("a", 1)} = {("b", 3)}
+operator DIFFERENCE_REMOVE 2 "bag difference remove (removes shared elements)"
+
+operator SUBBAG 2 "inclusion predicate for bags (less than or equal multiplicities)"
+operator BAG_COUNT 2 "multiplicity of an element in a bag"
+operator DUPLICATE_REMOVAL 1 "eliminate duplicates in a bag (also known as the delta operator,or the squash operator)"
+
+constant MK_BAG_OP \
+ ::CVC4::MakeBagOp \
+ ::CVC4::MakeBagOpHashFunction \
+ "theory/bags/make_bag_op.h" \
+ "operator for MK_BAG; payload is an instance of the CVC4::MakeBagOp class"
+parameterized MK_BAG MK_BAG_OP 2 \
+"constructs a bag from one element along with its multiplicity"
+
+# The operator bag-is-singleton returns whether the given bag is a singleton
+operator BAG_IS_SINGLETON 1 "return whether the given bag is a singleton"
+
+operator BAG_CARD 1 "bag cardinality operator"
+operator BAG_FROM_SET 1 "converts a set to a bag"
+operator BAG_TO_SET 1 "converts a bag to a set"
+
+# The operator choose returns an element from a given bag.
+# If bag A = {("a", 1)}, then the term (choose A) is equivalent to the term a.
+# If the bag is empty, then (choose A) is an arbitrary value.
+# If the bag has cardinality > 1, then (choose A) will deterministically return an element in A.
+operator BAG_CHOOSE 1 "return an element in the bag given as a parameter"
+
+typerule UNION_MAX ::CVC4::theory::bags::BinaryOperatorTypeRule
+typerule UNION_DISJOINT ::CVC4::theory::bags::BinaryOperatorTypeRule
+typerule INTERSECTION_MIN ::CVC4::theory::bags::BinaryOperatorTypeRule
+typerule DIFFERENCE_SUBTRACT ::CVC4::theory::bags::BinaryOperatorTypeRule
+typerule DIFFERENCE_REMOVE ::CVC4::theory::bags::BinaryOperatorTypeRule
+typerule SUBBAG ::CVC4::theory::bags::SubBagTypeRule
+typerule BAG_COUNT ::CVC4::theory::bags::CountTypeRule
+typerule DUPLICATE_REMOVAL ::CVC4::theory::bags::DuplicateRemovalTypeRule
+typerule MK_BAG_OP "SimpleTypeRule<RBuiltinOperator>"
+typerule MK_BAG ::CVC4::theory::bags::MkBagTypeRule
+typerule EMPTYBAG ::CVC4::theory::bags::EmptyBagTypeRule
+typerule BAG_CARD ::CVC4::theory::bags::CardTypeRule
+typerule BAG_CHOOSE ::CVC4::theory::bags::ChooseTypeRule
+typerule BAG_IS_SINGLETON ::CVC4::theory::bags::IsSingletonTypeRule
+typerule BAG_FROM_SET ::CVC4::theory::bags::FromSetTypeRule
+typerule BAG_TO_SET ::CVC4::theory::bags::ToSetTypeRule
+
+construle UNION_DISJOINT ::CVC4::theory::bags::BinaryOperatorTypeRule
+construle MK_BAG ::CVC4::theory::bags::MkBagTypeRule
+
+endtheory \ No newline at end of file
diff --git a/src/theory/bags/make_bag_op.cpp b/src/theory/bags/make_bag_op.cpp
new file mode 100644
index 000000000..b60822783
--- /dev/null
+++ b/src/theory/bags/make_bag_op.cpp
@@ -0,0 +1,49 @@
+/********************* */
+/*! \file bag_op.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief a class for MK_BAG operator
+ **/
+
+#include "make_bag_op.h"
+
+#include <iostream>
+
+#include "expr/type_node.h"
+
+namespace CVC4 {
+
+std::ostream& operator<<(std::ostream& out, const MakeBagOp& op)
+{
+ return out << "(mkBag_op " << op.getType() << ')';
+}
+
+size_t MakeBagOpHashFunction::operator()(const MakeBagOp& op) const
+{
+ return TypeNodeHashFunction()(op.getType());
+}
+
+MakeBagOp::MakeBagOp(const TypeNode& elementType)
+ : d_type(new TypeNode(elementType))
+{
+}
+
+MakeBagOp::MakeBagOp(const MakeBagOp& op) : d_type(new TypeNode(op.getType()))
+{
+}
+
+const TypeNode& MakeBagOp::getType() const { return *d_type; }
+
+bool MakeBagOp::operator==(const MakeBagOp& op) const
+{
+ return getType() == op.getType();
+}
+
+} // namespace CVC4
diff --git a/src/theory/bags/make_bag_op.h b/src/theory/bags/make_bag_op.h
new file mode 100644
index 000000000..b47930879
--- /dev/null
+++ b/src/theory/bags/make_bag_op.h
@@ -0,0 +1,63 @@
+/********************* */
+/*! \file mk_bag_op.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief a class for MK_BAG operator
+ **/
+
+#include "cvc4_public.h"
+
+#ifndef CVC4__MAKE_BAG_OP_H
+#define CVC4__MAKE_BAG_OP_H
+
+#include <memory>
+
+namespace CVC4 {
+
+class TypeNode;
+
+/**
+ * The class is an operator for kind MK_BAG used to construct bags.
+ * It specifies the type of the element especially when it is a constant.
+ * e.g. the type of rational 1 is Int, however
+ * (mkBag (mkBag_op Real) 1) is of type (Bag Real), not (Bag Int).
+ * Note that the type passed to the constructor is the element's type, not the
+ * bag type.
+ */
+class MakeBagOp
+{
+ public:
+ MakeBagOp(const TypeNode& elementType);
+ MakeBagOp(const MakeBagOp& op);
+
+ /** return the type of the current object */
+ const TypeNode& getType() const;
+
+ bool operator==(const MakeBagOp& op) const;
+
+ private:
+ MakeBagOp();
+ /** a pointer to the type of the bag element */
+ std::unique_ptr<TypeNode> d_type;
+}; /* class MakeBagOp */
+
+std::ostream& operator<<(std::ostream& out, const MakeBagOp& op);
+
+/**
+ * Hash function for the MakeBagOpHashFunction objects.
+ */
+struct CVC4_PUBLIC MakeBagOpHashFunction
+{
+ size_t operator()(const MakeBagOp& op) const;
+}; /* struct MakeBagOpHashFunction */
+
+} // namespace CVC4
+
+#endif /* CVC4__MAKE_BAG_OP_H */
diff --git a/src/theory/bags/normal_form.cpp b/src/theory/bags/normal_form.cpp
new file mode 100644
index 000000000..081ed77aa
--- /dev/null
+++ b/src/theory/bags/normal_form.cpp
@@ -0,0 +1,656 @@
+/************************* */
+/*! \file normal_form.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **/
+
+#include "normal_form.h"
+
+#include "theory/sets/normal_form.h"
+#include "theory/type_enumerator.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+bool NormalForm::isConstant(TNode n)
+{
+ if (n.getKind() == EMPTYBAG)
+ {
+ // empty bags are already normalized
+ return true;
+ }
+ if (n.getKind() == MK_BAG)
+ {
+ // see the implementation in MkBagTypeRule::computeIsConst
+ return n.isConst();
+ }
+ if (n.getKind() == UNION_DISJOINT)
+ {
+ if (!(n[0].getKind() == kind::MK_BAG && n[0].isConst()))
+ {
+ // the first child is not a constant
+ return false;
+ }
+ // store the previous element to check the ordering of elements
+ Node previousElement = n[0][0];
+ Node current = n[1];
+ while (current.getKind() == UNION_DISJOINT)
+ {
+ if (!(current[0].getKind() == kind::MK_BAG && current[0].isConst()))
+ {
+ // the current element is not a constant
+ return false;
+ }
+ if (previousElement >= current[0][0])
+ {
+ // the ordering is violated
+ return false;
+ }
+ previousElement = current[0][0];
+ current = current[1];
+ }
+ // check last element
+ if (!(current.getKind() == kind::MK_BAG && current.isConst()))
+ {
+ // the last element is not a constant
+ return false;
+ }
+ if (previousElement >= current[0])
+ {
+ // the ordering is violated
+ return false;
+ }
+ return true;
+ }
+
+ // only nodes with kinds EMPTY_BAG, MK_BAG, and UNION_DISJOINT can be
+ // constants
+ return false;
+}
+
+bool NormalForm::areChildrenConstants(TNode n)
+{
+ return std::all_of(n.begin(), n.end(), [](Node c) { return c.isConst(); });
+}
+
+Node NormalForm::evaluate(TNode n)
+{
+ Assert(areChildrenConstants(n));
+ if (n.isConst())
+ {
+ // a constant node is already in a normal form
+ return n;
+ }
+ switch (n.getKind())
+ {
+ case MK_BAG: return evaluateMakeBag(n);
+ case BAG_COUNT: return evaluateBagCount(n);
+ case DUPLICATE_REMOVAL: return evaluateDuplicateRemoval(n);
+ case UNION_DISJOINT: return evaluateUnionDisjoint(n);
+ case UNION_MAX: return evaluateUnionMax(n);
+ case INTERSECTION_MIN: return evaluateIntersectionMin(n);
+ case DIFFERENCE_SUBTRACT: return evaluateDifferenceSubtract(n);
+ case DIFFERENCE_REMOVE: return evaluateDifferenceRemove(n);
+ case BAG_CHOOSE: return evaluateChoose(n);
+ case BAG_CARD: return evaluateCard(n);
+ case BAG_IS_SINGLETON: return evaluateIsSingleton(n);
+ case BAG_FROM_SET: return evaluateFromSet(n);
+ case BAG_TO_SET: return evaluateToSet(n);
+ default: break;
+ }
+ Unhandled() << "Unexpected bag kind '" << n.getKind() << "' in node " << n
+ << std::endl;
+}
+
+template <typename T1, typename T2, typename T3, typename T4, typename T5>
+Node NormalForm::evaluateBinaryOperation(const TNode& n,
+ T1&& equal,
+ T2&& less,
+ T3&& greaterOrEqual,
+ T4&& remainderOfA,
+ T5&& remainderOfB)
+{
+ std::map<Node, Rational> elementsA = getBagElements(n[0]);
+ std::map<Node, Rational> elementsB = getBagElements(n[1]);
+ std::map<Node, Rational> elements;
+
+ std::map<Node, Rational>::const_iterator itA = elementsA.begin();
+ std::map<Node, Rational>::const_iterator itB = elementsB.begin();
+
+ Trace("bags-evaluate") << "[NormalForm::evaluateBinaryOperation "
+ << n.getKind() << "] " << std::endl
+ << "elements A: " << elementsA << std::endl
+ << "elements B: " << elementsB << std::endl;
+
+ while (itA != elementsA.end() && itB != elementsB.end())
+ {
+ if (itA->first == itB->first)
+ {
+ equal(elements, itA, itB);
+ itA++;
+ itB++;
+ }
+ else if (itA->first < itB->first)
+ {
+ less(elements, itA, itB);
+ itA++;
+ }
+ else
+ {
+ greaterOrEqual(elements, itA, itB);
+ itB++;
+ }
+ }
+
+ // handle the remaining elements from A
+ remainderOfA(elements, elementsA, itA);
+ // handle the remaining elements from B
+ remainderOfA(elements, elementsB, itB);
+
+ Trace("bags-evaluate") << "elements: " << elements << std::endl;
+ Node bag = constructBagFromElements(n.getType(), elements);
+ Trace("bags-evaluate") << "bag: " << bag << std::endl;
+ return bag;
+}
+
+std::map<Node, Rational> NormalForm::getBagElements(TNode n)
+{
+ Assert(n.isConst()) << "node " << n << " is not in a normal form"
+ << std::endl;
+ std::map<Node, Rational> elements;
+ if (n.getKind() == EMPTYBAG)
+ {
+ return elements;
+ }
+ while (n.getKind() == kind::UNION_DISJOINT)
+ {
+ Assert(n[0].getKind() == kind::MK_BAG);
+ Node element = n[0][0];
+ Rational count = n[0][1].getConst<Rational>();
+ elements[element] = count;
+ n = n[1];
+ }
+ Assert(n.getKind() == kind::MK_BAG);
+ Node lastElement = n[0];
+ Rational lastCount = n[1].getConst<Rational>();
+ elements[lastElement] = lastCount;
+ return elements;
+}
+
+Node NormalForm::constructBagFromElements(
+ TypeNode t, const std::map<Node, Rational>& elements)
+{
+ Assert(t.isBag());
+ NodeManager* nm = NodeManager::currentNM();
+ if (elements.empty())
+ {
+ return nm->mkConst(EmptyBag(t));
+ }
+ TypeNode elementType = t.getBagElementType();
+ std::map<Node, Rational>::const_reverse_iterator it = elements.rbegin();
+ Node bag =
+ nm->mkBag(elementType, it->first, nm->mkConst<Rational>(it->second));
+ while (++it != elements.rend())
+ {
+ Node n =
+ nm->mkBag(elementType, it->first, nm->mkConst<Rational>(it->second));
+ bag = nm->mkNode(UNION_DISJOINT, n, bag);
+ }
+ return bag;
+}
+
+Node NormalForm::evaluateMakeBag(TNode n)
+{
+ // the case where n is const should be handled earlier.
+ // here we handle the case where the multiplicity is zero or negative
+ Assert(n.getKind() == MK_BAG && !n.isConst()
+ && n[1].getConst<Rational>().sgn() < 1);
+ Node emptybag = NodeManager::currentNM()->mkConst(EmptyBag(n.getType()));
+ return emptybag;
+}
+
+Node NormalForm::evaluateBagCount(TNode n)
+{
+ Assert(n.getKind() == BAG_COUNT);
+ // Examples
+ // --------
+ // - (bag.count "x" (emptybag String)) = 0
+ // - (bag.count "x" (mkBag "y" 5)) = 0
+ // - (bag.count "x" (mkBag "x" 4)) = 4
+ // - (bag.count "x" (union_disjoint (mkBag "x" 4) (mkBag "y" 5)) = 4
+ // - (bag.count "x" (union_disjoint (mkBag "y" 5) (mkBag "z" 5)) = 0
+
+ std::map<Node, Rational> elements = getBagElements(n[1]);
+ std::map<Node, Rational>::iterator it = elements.find(n[0]);
+
+ NodeManager* nm = NodeManager::currentNM();
+ if (it != elements.end())
+ {
+ Node count = nm->mkConst(it->second);
+ return count;
+ }
+ return nm->mkConst(Rational(0));
+}
+
+Node NormalForm::evaluateDuplicateRemoval(TNode n)
+{
+ Assert(n.getKind() == DUPLICATE_REMOVAL);
+
+ // Examples
+ // --------
+ // - (duplicate_removal (emptybag String)) = (emptybag String)
+ // - (duplicate_removal (mkBag "x" 4)) = (emptybag "x" 1)
+ // - (duplicate_removal (disjoint_union (mkBag "x" 3) (mkBag "y" 5)) =
+ // (disjoint_union (mkBag "x" 1) (mkBag "y" 1)
+
+ std::map<Node, Rational> oldElements = getBagElements(n[0]);
+ // copy elements from the old bag
+ std::map<Node, Rational> newElements(oldElements);
+ Rational one = Rational(1);
+ std::map<Node, Rational>::iterator it;
+ for (it = newElements.begin(); it != newElements.end(); it++)
+ {
+ it->second = one;
+ }
+ Node bag = constructBagFromElements(n[0].getType(), newElements);
+ return bag;
+}
+
+Node NormalForm::evaluateUnionDisjoint(TNode n)
+{
+ Assert(n.getKind() == UNION_DISJOINT);
+ // Example
+ // -------
+ // input: (union_disjoint A B)
+ // where A = (union_disjoint (MK_BAG "x" 4) (MK_BAG "z" 2)))
+ // B = (union_disjoint (MK_BAG "x" 3) (MK_BAG "y" 1)))
+ // output:
+ // (union_disjoint A B)
+ // where A = (MK_BAG "x" 7)
+ // B = (union_disjoint (MK_BAG "y" 1) (MK_BAG "z" 2)))
+
+ auto equal = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>::const_iterator& itA,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // compute the sum of the multiplicities
+ elements[itA->first] = itA->second + itB->second;
+ };
+
+ auto less = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>::const_iterator& itA,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // add the element to the result
+ elements[itA->first] = itA->second;
+ };
+
+ auto greaterOrEqual = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>::const_iterator& itA,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // add the element to the result
+ elements[itB->first] = itB->second;
+ };
+
+ auto remainderOfA = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>& elementsA,
+ std::map<Node, Rational>::const_iterator& itA) {
+ // append the remainder of A
+ while (itA != elementsA.end())
+ {
+ elements[itA->first] = itA->second;
+ itA++;
+ }
+ };
+
+ auto remainderOfB = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>& elementsB,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // append the remainder of B
+ while (itB != elementsB.end())
+ {
+ elements[itB->first] = itB->second;
+ itB++;
+ }
+ };
+
+ return evaluateBinaryOperation(
+ n, equal, less, greaterOrEqual, remainderOfA, remainderOfB);
+}
+
+Node NormalForm::evaluateUnionMax(TNode n)
+{
+ Assert(n.getKind() == UNION_MAX);
+ // Example
+ // -------
+ // input: (union_max A B)
+ // where A = (union_disjoint (MK_BAG "x" 4) (MK_BAG "z" 2)))
+ // B = (union_disjoint (MK_BAG "x" 3) (MK_BAG "y" 1)))
+ // output:
+ // (union_disjoint A B)
+ // where A = (MK_BAG "x" 4)
+ // B = (union_disjoint (MK_BAG "y" 1) (MK_BAG "z" 2)))
+
+ auto equal = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>::const_iterator& itA,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // compute the maximum multiplicity
+ elements[itA->first] = std::max(itA->second, itB->second);
+ };
+
+ auto less = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>::const_iterator& itA,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // add to the result
+ elements[itA->first] = itA->second;
+ };
+
+ auto greaterOrEqual = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>::const_iterator& itA,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // add to the result
+ elements[itB->first] = itB->second;
+ };
+
+ auto remainderOfA = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>& elementsA,
+ std::map<Node, Rational>::const_iterator& itA) {
+ // append the remainder of A
+ while (itA != elementsA.end())
+ {
+ elements[itA->first] = itA->second;
+ itA++;
+ }
+ };
+
+ auto remainderOfB = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>& elementsB,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // append the remainder of B
+ while (itB != elementsB.end())
+ {
+ elements[itB->first] = itB->second;
+ itB++;
+ }
+ };
+
+ return evaluateBinaryOperation(
+ n, equal, less, greaterOrEqual, remainderOfA, remainderOfB);
+}
+
+Node NormalForm::evaluateIntersectionMin(TNode n)
+{
+ Assert(n.getKind() == INTERSECTION_MIN);
+ // Example
+ // -------
+ // input: (intersectionMin A B)
+ // where A = (union_disjoint (MK_BAG "x" 4) (MK_BAG "z" 2)))
+ // B = (union_disjoint (MK_BAG "x" 3) (MK_BAG "y" 1)))
+ // output:
+ // (MK_BAG "x" 3)
+
+ auto equal = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>::const_iterator& itA,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // compute the minimum multiplicity
+ elements[itA->first] = std::min(itA->second, itB->second);
+ };
+
+ auto less = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>::const_iterator& itA,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // do nothing
+ };
+
+ auto greaterOrEqual = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>::const_iterator& itA,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // do nothing
+ };
+
+ auto remainderOfA = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>& elementsA,
+ std::map<Node, Rational>::const_iterator& itA) {
+ // do nothing
+ };
+
+ auto remainderOfB = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>& elementsB,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // do nothing
+ };
+
+ return evaluateBinaryOperation(
+ n, equal, less, greaterOrEqual, remainderOfA, remainderOfB);
+}
+
+Node NormalForm::evaluateDifferenceSubtract(TNode n)
+{
+ Assert(n.getKind() == DIFFERENCE_SUBTRACT);
+ // Example
+ // -------
+ // input: (difference_subtract A B)
+ // where A = (union_disjoint (MK_BAG "x" 4) (MK_BAG "z" 2)))
+ // B = (union_disjoint (MK_BAG "x" 3) (MK_BAG "y" 1)))
+ // output:
+ // (union_disjoint (MK_BAG "x" 1) (MK_BAG "z" 2))
+
+ auto equal = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>::const_iterator& itA,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // subtract the multiplicities
+ elements[itA->first] = itA->second - itB->second;
+ };
+
+ auto less = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>::const_iterator& itA,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // itA->first is not in B, so we add it to the difference subtract
+ elements[itA->first] = itA->second;
+ };
+
+ auto greaterOrEqual = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>::const_iterator& itA,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // itB->first is not in A, so we just skip it
+ };
+
+ auto remainderOfA = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>& elementsA,
+ std::map<Node, Rational>::const_iterator& itA) {
+ // append the remainder of A
+ while (itA != elementsA.end())
+ {
+ elements[itA->first] = itA->second;
+ itA++;
+ }
+ };
+
+ auto remainderOfB = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>& elementsB,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // do nothing
+ };
+
+ return evaluateBinaryOperation(
+ n, equal, less, greaterOrEqual, remainderOfA, remainderOfB);
+}
+
+Node NormalForm::evaluateDifferenceRemove(TNode n)
+{
+ Assert(n.getKind() == DIFFERENCE_REMOVE);
+ // Example
+ // -------
+ // input: (difference_subtract A B)
+ // where A = (union_disjoint (MK_BAG "x" 4) (MK_BAG "z" 2)))
+ // B = (union_disjoint (MK_BAG "x" 3) (MK_BAG "y" 1)))
+ // output:
+ // (MK_BAG "z" 2)
+
+ auto equal = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>::const_iterator& itA,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // skip the shared element by doing nothing
+ };
+
+ auto less = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>::const_iterator& itA,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // itA->first is not in B, so we add it to the difference remove
+ elements[itA->first] = itA->second;
+ };
+
+ auto greaterOrEqual = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>::const_iterator& itA,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // itB->first is not in A, so we just skip it
+ };
+
+ auto remainderOfA = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>& elementsA,
+ std::map<Node, Rational>::const_iterator& itA) {
+ // append the remainder of A
+ while (itA != elementsA.end())
+ {
+ elements[itA->first] = itA->second;
+ itA++;
+ }
+ };
+
+ auto remainderOfB = [](std::map<Node, Rational>& elements,
+ std::map<Node, Rational>& elementsB,
+ std::map<Node, Rational>::const_iterator& itB) {
+ // do nothing
+ };
+
+ return evaluateBinaryOperation(
+ n, equal, less, greaterOrEqual, remainderOfA, remainderOfB);
+}
+
+Node NormalForm::evaluateChoose(TNode n)
+{
+ Assert(n.getKind() == BAG_CHOOSE);
+ // Examples
+ // --------
+ // - (choose (emptyBag String)) = "" // the empty string which is the first
+ // element returned by the type enumerator
+ // - (choose (MK_BAG "x" 4)) = "x"
+ // - (choose (union_disjoint (MK_BAG "x" 4) (MK_BAG "y" 1))) = "x"
+ // deterministically return the first element
+
+ if (n[0].getKind() == EMPTYBAG)
+ {
+ TypeNode elementType = n[0].getType().getBagElementType();
+ TypeEnumerator typeEnumerator(elementType);
+ // get the first value from the typeEnumerator
+ Node element = *typeEnumerator;
+ return element;
+ }
+
+ if (n[0].getKind() == MK_BAG)
+ {
+ return n[0][0];
+ }
+ Assert(n[0].getKind() == UNION_DISJOINT);
+ // return the first element
+ // e.g. (choose (union_disjoint (MK_BAG "x" 4) (MK_BAG "y" 1)))
+ return n[0][0][0];
+}
+
+Node NormalForm::evaluateCard(TNode n)
+{
+ Assert(n.getKind() == BAG_CARD);
+ // Examples
+ // --------
+ // - (card (emptyBag String)) = 0
+ // - (choose (MK_BAG "x" 4)) = 4
+ // - (choose (union_disjoint (MK_BAG "x" 4) (MK_BAG "y" 1))) = 5
+
+ std::map<Node, Rational> elements = getBagElements(n[0]);
+ Rational sum(0);
+ for (std::pair<Node, Rational> element : elements)
+ {
+ sum += element.second;
+ }
+
+ NodeManager* nm = NodeManager::currentNM();
+ Node sumNode = nm->mkConst(sum);
+ return sumNode;
+}
+
+Node NormalForm::evaluateIsSingleton(TNode n)
+{
+ Assert(n.getKind() == BAG_IS_SINGLETON);
+ // Examples
+ // --------
+ // - (bag.is_singleton (emptyBag String)) = false
+ // - (bag.is_singleton (MK_BAG "x" 1)) = true
+ // - (bag.is_singleton (MK_BAG "x" 4)) = false
+ // - (bag.is_singleton (union_disjoint (MK_BAG "x" 1) (MK_BAG "y" 1))) = false
+
+ if (n[0].getKind() == MK_BAG && n[0][1].getConst<Rational>().isOne())
+ {
+ return NodeManager::currentNM()->mkConst(true);
+ }
+ return NodeManager::currentNM()->mkConst(false);
+}
+
+Node NormalForm::evaluateFromSet(TNode n)
+{
+ Assert(n.getKind() == BAG_FROM_SET);
+
+ // Examples
+ // --------
+ // - (bag.from_set (emptyset String)) = (emptybag String)
+ // - (bag.from_set (singleton "x")) = (mkBag "x" 1)
+ // - (bag.from_set (union (singleton "x") (singleton "y"))) =
+ // (disjoint_union (mkBag "x" 1) (mkBag "y" 1))
+
+ NodeManager* nm = NodeManager::currentNM();
+ std::set<Node> setElements =
+ sets::NormalForm::getElementsFromNormalConstant(n[0]);
+ Rational one = Rational(1);
+ std::map<Node, Rational> bagElements;
+ for (const Node& element : setElements)
+ {
+ bagElements[element] = one;
+ }
+ TypeNode bagType = nm->mkBagType(n[0].getType().getSetElementType());
+ Node bag = constructBagFromElements(bagType, bagElements);
+ return bag;
+}
+
+Node NormalForm::evaluateToSet(TNode n)
+{
+ Assert(n.getKind() == BAG_TO_SET);
+
+ // Examples
+ // --------
+ // - (bag.to_set (emptybag String)) = (emptyset String)
+ // - (bag.to_set (mkBag "x" 4)) = (singleton "x")
+ // - (bag.to_set (disjoint_union (mkBag "x" 3) (mkBag "y" 5)) =
+ // (union (singleton "x") (singleton "y")))
+
+ NodeManager* nm = NodeManager::currentNM();
+ std::map<Node, Rational> bagElements = getBagElements(n[0]);
+ std::set<Node> setElements;
+ std::map<Node, Rational>::const_reverse_iterator it;
+ for (it = bagElements.rbegin(); it != bagElements.rend(); it++)
+ {
+ setElements.insert(it->first);
+ }
+ TypeNode setType = nm->mkSetType(n[0].getType().getBagElementType());
+ Node set = sets::NormalForm::elementsToSet(setElements, setType);
+ return set;
+}
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4 \ No newline at end of file
diff --git a/src/theory/bags/normal_form.h b/src/theory/bags/normal_form.h
new file mode 100644
index 000000000..5a7936fa3
--- /dev/null
+++ b/src/theory/bags/normal_form.h
@@ -0,0 +1,187 @@
+/********************* */
+/*! \file normal_form.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Normal form for bag constants.
+ **/
+
+#include <expr/node.h>
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__BAGS__NORMAL_FORM_H
+#define CVC4__THEORY__BAGS__NORMAL_FORM_H
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+class NormalForm
+{
+ public:
+ /**
+ * Returns true if n is considered a to be a (canonical) constant bag value.
+ * A canonical bag value is one whose AST is:
+ * (union_disjoint (mkBag e1 c1) ...
+ * (union_disjoint (mkBag e_{n-1} c_{n-1}) (mkBag e_n c_n))))
+ * where c1 ... cn are positive integers, e1 ... en are constants, and the
+ * node identifier of these constants are such that: e1 < ... < en.
+ * Also handles the corner cases of empty bag and bag constructed by mkBag
+ */
+ static bool isConstant(TNode n);
+ /**
+ * check whether all children of the given node are constants
+ */
+ static bool areChildrenConstants(TNode n);
+ /**
+ * evaluate the node n to a constant value.
+ * As a precondition, children of n should be constants.
+ */
+ static Node evaluate(TNode n);
+
+ /**
+ * get the elements along with their multiplicities in a given bag
+ * @param n a constant node whose type is a bag
+ * @return a map whose keys are constant elements and values are
+ * multiplicities
+ */
+ static std::map<Node, Rational> getBagElements(TNode n);
+
+ /**
+ * construct a constant bag from constant elements
+ * @param t the type of the returned bag
+ * @param elements a map whose keys are constant elements and values are
+ * multiplicities
+ * @return a constant bag that contains
+ */
+ static Node constructBagFromElements(
+ TypeNode t, const std::map<Node, Rational>& elements);
+
+ private:
+ /**
+ * a high order helper function that return a constant bag that is the result
+ * of (op A B) where op is a binary operator and A, B are constant bags.
+ * The result is computed from the elements of A (elementsA with iterator itA)
+ * and elements of B (elementsB with iterator itB).
+ * The arguments below specify how these iterators are used to generate the
+ * elements of the result (elements).
+ * @param n a node whose kind is a binary operator (union_disjoint, union_max,
+ * intersection_min, difference_subtract, difference_remove) and whose
+ * children are constant bags.
+ * @param equal a lambda expression that receives (elements, itA, itB) and
+ * specify the action that needs to be taken when the elements of itA, itB are
+ * equal.
+ * @param less a lambda expression that receives (elements, itA, itB) and
+ * specify the action that needs to be taken when the element itA is less than
+ * the element of itB.
+ * @param greaterOrEqual less a lambda expression that receives (elements,
+ * itA, itB) and specify the action that needs to be taken when the element
+ * itA is greater than or equal than the element of itB.
+ * @param remainderOfA a lambda expression that receives (elements, elementsA,
+ * itA) and specify the action that needs to be taken to the remaining
+ * elements of A when all elements of B are visited.
+ * @param remainderOfB a lambda expression that receives (elements, elementsB,
+ * itB) and specify the action that needs to be taken to the remaining
+ * elements of B when all elements of A are visited.
+ * @return a constant bag that the result of (op n[0] n[1])
+ */
+ template <typename T1, typename T2, typename T3, typename T4, typename T5>
+ static Node evaluateBinaryOperation(const TNode& n,
+ T1&& equal,
+ T2&& less,
+ T3&& greaterOrEqual,
+ T4&& remainderOfA,
+ T5&& remainderOfB);
+ /**
+ * evaluate n as follows:
+ * - (mkBag a 0) = (emptybag T) where T is the type of the original bag
+ * - (mkBag a (-c)) = (emptybag T) where T is the type the original bag,
+ * and c > 0 is a constant
+ */
+ static Node evaluateMakeBag(TNode n);
+
+ /**
+ * returns the multiplicity in a constant bag
+ * @param n has the form (bag.count x A) where x, A are constants
+ * @return the multiplicity of element x in bag A.
+ */
+ static Node evaluateBagCount(TNode n);
+
+ /**
+ * @param n has the form (duplicate_removal A) where A is a constant bag
+ * @return a constant bag constructed from the elements in A where each
+ * element has multiplicity one
+ */
+ static Node evaluateDuplicateRemoval(TNode n);
+
+ /**
+ * evaluates union disjoint node such that the returned node is a canonical
+ * bag that has the form
+ * (union_disjoint (mkBag e1 c1) ...
+ * (union_disjoint * (mkBag e_{n-1} c_{n-1}) (mkBag e_n c_n)))) where
+ * c1... cn are positive integers, e1 ... en are constants, and the node
+ * identifier of these constants are such that: e1 < ... < en.
+ * @param n has the form (union_disjoint A B) where A, B are constant bags
+ * @return the union disjoint of A and B
+ */
+ static Node evaluateUnionDisjoint(TNode n);
+ /**
+ * @param n has the form (union_max A B) where A, B are constant bags
+ * @return the union max of A and B
+ */
+ static Node evaluateUnionMax(TNode n);
+ /**
+ * @param n has the form (intersection_min A B) where A, B are constant bags
+ * @return the intersection min of A and B
+ */
+ static Node evaluateIntersectionMin(TNode n);
+ /**
+ * @param n has the form (difference_subtract A B) where A, B are constant
+ * bags
+ * @return the difference subtract of A and B
+ */
+ static Node evaluateDifferenceSubtract(TNode n);
+ /**
+ * @param n has the form (difference_remove A B) where A, B are constant bags
+ * @return the difference remove of A and B
+ */
+ static Node evaluateDifferenceRemove(TNode n);
+ /**
+ * @param n has the form (bag.choose A) where A is a constant bag
+ * @return the first element of A if A is not empty. Otherwise, it returns the
+ * first element returned by the type enumerator for the elements
+ */
+ static Node evaluateChoose(TNode n);
+ /**
+ * @param n has the form (bag.card A) where A is a constant bag
+ * @return the number of elements in bag A
+ */
+ static Node evaluateCard(TNode n);
+ /**
+ * @param n has the form (bag.is_singleton A) where A is a constant bag
+ * @return whether the bag A has cardinality one.
+ */
+ static Node evaluateIsSingleton(TNode n);
+ /**
+ * @param n has the form (bag.from_set A) where A is a constant set
+ * @return a constant bag that contains exactly the elements in A.
+ */
+ static Node evaluateFromSet(TNode n);
+ /**
+ * @param n has the form (bag.to_set A) where A is a constant bag
+ * @return a constant set constructed from the elements in A.
+ */
+ static Node evaluateToSet(TNode n);
+};
+} // namespace bags
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__BAGS__NORMAL_FORM_H */
diff --git a/src/theory/bags/rewrites.cpp b/src/theory/bags/rewrites.cpp
new file mode 100644
index 000000000..85d0820af
--- /dev/null
+++ b/src/theory/bags/rewrites.cpp
@@ -0,0 +1,82 @@
+/********************* */
+/*! \file rewrites.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of inference information utility.
+ **/
+
+#include "theory/bags/rewrites.h"
+
+#include <iostream>
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+const char* toString(Rewrite r)
+{
+ switch (r)
+ {
+ case Rewrite::NONE: return "NONE";
+ case Rewrite::CARD_DISJOINT: return "CARD_DISJOINT";
+ case Rewrite::CARD_MK_BAG: return "CARD_MK_BAG";
+ case Rewrite::CHOOSE_MK_BAG: return "CHOOSE_MK_BAG";
+ case Rewrite::CONSTANT_EVALUATION: return "CONSTANT_EVALUATION";
+ case Rewrite::COUNT_EMPTY: return "COUNT_EMPTY";
+ case Rewrite::COUNT_MK_BAG: return "COUNT_MK_BAG";
+ case Rewrite::DUPLICATE_REMOVAL_MK_BAG: return "DUPLICATE_REMOVAL_MK_BAG";
+ case Rewrite::EQ_CONST_FALSE: return "EQ_CONST_FALSE";
+ case Rewrite::EQ_REFL: return "EQ_REFL";
+ case Rewrite::EQ_SYM: return "EQ_SYM";
+ case Rewrite::FROM_SINGLETON: return "FROM_SINGLETON";
+ case Rewrite::IDENTICAL_NODES: return "IDENTICAL_NODES";
+ case Rewrite::INTERSECTION_EMPTY_LEFT: return "INTERSECTION_EMPTY_LEFT";
+ case Rewrite::INTERSECTION_EMPTY_RIGHT: return "INTERSECTION_EMPTY_RIGHT";
+ case Rewrite::INTERSECTION_SAME: return "INTERSECTION_SAME";
+ case Rewrite::INTERSECTION_SHARED_LEFT: return "INTERSECTION_SHARED_LEFT";
+ case Rewrite::INTERSECTION_SHARED_RIGHT: return "INTERSECTION_SHARED_RIGHT";
+ case Rewrite::IS_SINGLETON_MK_BAG: return "IS_SINGLETON_MK_BAG";
+ case Rewrite::MK_BAG_COUNT_NEGATIVE: return "MK_BAG_COUNT_NEGATIVE";
+ case Rewrite::REMOVE_FROM_UNION: return "REMOVE_FROM_UNION";
+ case Rewrite::REMOVE_MIN: return "REMOVE_MIN";
+ case Rewrite::REMOVE_RETURN_LEFT: return "REMOVE_RETURN_LEFT";
+ case Rewrite::REMOVE_SAME: return "REMOVE_SAME";
+ case Rewrite::SUB_BAG: return "SUB_BAG";
+ case Rewrite::SUBTRACT_DISJOINT_SHARED_LEFT:
+ return "SUBTRACT_DISJOINT_SHARED_LEFT";
+ case Rewrite::SUBTRACT_DISJOINT_SHARED_RIGHT:
+ return "SUBTRACT_DISJOINT_SHARED_RIGHT";
+ case Rewrite::SUBTRACT_FROM_UNION: return "SUBTRACT_FROM_UNION";
+ case Rewrite::SUBTRACT_MIN: return "SUBTRACT_MIN";
+ case Rewrite::SUBTRACT_RETURN_LEFT: return "SUBTRACT_RETURN_LEFT";
+ case Rewrite::SUBTRACT_SAME: return "SUBTRACT_SAME";
+ case Rewrite::UNION_DISJOINT_EMPTY_LEFT: return "UNION_DISJOINT_EMPTY_LEFT";
+ case Rewrite::TO_SINGLETON: return "TO_SINGLETON";
+ case Rewrite::UNION_DISJOINT_EMPTY_RIGHT:
+ return "UNION_DISJOINT_EMPTY_RIGHT";
+ case Rewrite::UNION_DISJOINT_MAX_MIN: return "UNION_DISJOINT_MAX_MIN";
+ case Rewrite::UNION_MAX_EMPTY: return "UNION_MAX_EMPTY";
+ case Rewrite::UNION_MAX_SAME_OR_EMPTY: return "UNION_MAX_SAME_OR_EMPTY";
+ case Rewrite::UNION_MAX_UNION_LEFT: return "UNION_MAX_UNION_LEFT";
+ case Rewrite::UNION_MAX_UNION_RIGHT: return "UNION_MAX_UNION_RIGHT";
+
+ default: return "?";
+ }
+}
+
+std::ostream& operator<<(std::ostream& out, Rewrite r)
+{
+ out << toString(r);
+ return out;
+}
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/bags/rewrites.h b/src/theory/bags/rewrites.h
new file mode 100644
index 000000000..5574aa080
--- /dev/null
+++ b/src/theory/bags/rewrites.h
@@ -0,0 +1,97 @@
+/********************* */
+/*! \file rewrites.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Type for rewrites for bags.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__BAGS__REWRITES_H
+#define CVC4__THEORY__BAGS__REWRITES_H
+
+#include <iosfwd>
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+/** Types of rewrites used by bags
+ *
+ * This rewrites are documented where they are used in the rewriter.
+ */
+enum class Rewrite : uint32_t
+{
+ NONE, // no rewrite happened
+ CARD_DISJOINT,
+ CARD_MK_BAG,
+ CHOOSE_MK_BAG,
+ CONSTANT_EVALUATION,
+ COUNT_EMPTY,
+ COUNT_MK_BAG,
+ DUPLICATE_REMOVAL_MK_BAG,
+ EQ_CONST_FALSE,
+ EQ_REFL,
+ EQ_SYM,
+ FROM_SINGLETON,
+ IDENTICAL_NODES,
+ INTERSECTION_EMPTY_LEFT,
+ INTERSECTION_EMPTY_RIGHT,
+ INTERSECTION_SAME,
+ INTERSECTION_SHARED_LEFT,
+ INTERSECTION_SHARED_RIGHT,
+ IS_SINGLETON_MK_BAG,
+ MK_BAG_COUNT_NEGATIVE,
+ REMOVE_FROM_UNION,
+ REMOVE_MIN,
+ REMOVE_RETURN_LEFT,
+ REMOVE_SAME,
+ SUB_BAG,
+ SUBTRACT_DISJOINT_SHARED_LEFT,
+ SUBTRACT_DISJOINT_SHARED_RIGHT,
+ SUBTRACT_FROM_UNION,
+ SUBTRACT_MIN,
+ SUBTRACT_RETURN_LEFT,
+ SUBTRACT_SAME,
+ TO_SINGLETON,
+ UNION_DISJOINT_EMPTY_LEFT,
+ UNION_DISJOINT_EMPTY_RIGHT,
+ UNION_DISJOINT_MAX_MIN,
+ UNION_MAX_EMPTY,
+ UNION_MAX_SAME_OR_EMPTY,
+ UNION_MAX_UNION_LEFT,
+ UNION_MAX_UNION_RIGHT
+};
+
+/**
+ * Converts an rewrite to a string. Note: This function is also used in
+ * `safe_print()`. Changing this functions name or signature will result in
+ * `safe_print()` printing "<unsupported>" instead of the proper strings for
+ * the enum values.
+ *
+ * @param r The rewrite
+ * @return The name of the rewrite
+ */
+const char* toString(Rewrite r);
+
+/**
+ * Writes an rewrite name to a stream.
+ *
+ * @param out The stream to write to
+ * @param r The rewrite to write to the stream
+ * @return The stream
+ */
+std::ostream& operator<<(std::ostream& out, Rewrite r);
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__BAGS__REWRITES_H */
diff --git a/src/theory/bags/solver_state.cpp b/src/theory/bags/solver_state.cpp
new file mode 100644
index 000000000..77204ae76
--- /dev/null
+++ b/src/theory/bags/solver_state.cpp
@@ -0,0 +1,35 @@
+/********************* */
+/*! \file solver_state.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of bags state object
+ **/
+
+#include "theory/bags/solver_state.h"
+
+using namespace std;
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+SolverState::SolverState(context::Context* c,
+ context::UserContext* u,
+ Valuation val)
+ : TheoryState(c, u, val)
+{
+ d_true = NodeManager::currentNM()->mkConst(true);
+ d_false = NodeManager::currentNM()->mkConst(false);
+}
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/bags/solver_state.h b/src/theory/bags/solver_state.h
new file mode 100644
index 000000000..f5b67cb78
--- /dev/null
+++ b/src/theory/bags/solver_state.h
@@ -0,0 +1,44 @@
+/********************* */
+/*! \file solver_state.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Bags state object
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__BAGS__THEORY_SOLVER_STATE_H
+#define CVC4__THEORY__BAGS__THEORY_SOLVER_STATE_H
+
+#include <map>
+#include <vector>
+
+#include "theory/theory_state.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+class SolverState : public TheoryState
+{
+ public:
+ SolverState(context::Context* c, context::UserContext* u, Valuation val);
+
+ private:
+ /** constants */
+ Node d_true;
+ Node d_false;
+}; /* class SolverState */
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__BAGS__THEORY_SOLVER_STATE_H */
diff --git a/src/theory/bags/term_registry.cpp b/src/theory/bags/term_registry.cpp
new file mode 100644
index 000000000..60beef29f
--- /dev/null
+++ b/src/theory/bags/term_registry.cpp
@@ -0,0 +1,45 @@
+/********************* */
+/*! \file term_registry.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of bags term registry object
+ **/
+
+#include "theory/bags/term_registry.h"
+
+using namespace std;
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+TermRegistry::TermRegistry(SolverState& state, InferenceManager& im)
+ : d_im(im),
+ d_proxy(state.getUserContext()),
+ d_proxy_to_term(state.getUserContext())
+{
+}
+
+Node TermRegistry::getEmptyBag(TypeNode tn)
+{
+ std::map<TypeNode, Node>::iterator it = d_emptybag.find(tn);
+ if (it != d_emptybag.end())
+ {
+ return it->second;
+ }
+ Node n = NodeManager::currentNM()->mkConst(EmptySet(tn));
+ d_emptybag[tn] = n;
+ return n;
+}
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/bags/term_registry.h b/src/theory/bags/term_registry.h
new file mode 100644
index 000000000..d284126ee
--- /dev/null
+++ b/src/theory/bags/term_registry.h
@@ -0,0 +1,63 @@
+/********************* */
+/*! \file term_registry.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Bags state object
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__BAGS__TERM_REGISTRY_H
+#define CVC4__THEORY__BAGS__TERM_REGISTRY_H
+
+#include <map>
+#include <vector>
+
+#include "context/cdhashmap.h"
+#include "theory/bags/inference_manager.h"
+#include "theory/bags/solver_state.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+/**
+ * Term registry, the purpose of this class is to maintain a database of
+ * commonly used terms, and mappings from bags to their "proxy variables".
+ */
+class TermRegistry
+{
+ typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeMap;
+
+ public:
+ TermRegistry(SolverState& state, InferenceManager& im);
+
+ /**
+ * Returns the existing empty bag for type tn
+ * or creates a new one and returns it.
+ **/
+ Node getEmptyBag(TypeNode tn);
+
+ private:
+ /** The inference manager */
+ InferenceManager& d_im;
+ /** Map from bag terms to their proxy variables */
+ NodeMap d_proxy;
+ /** Backwards map of above */
+ NodeMap d_proxy_to_term;
+ /** Map from types to empty bag of that type */
+ std::map<TypeNode, Node> d_emptybag;
+}; /* class Term */
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__BAGS__TERM_REGISTRY_H */
diff --git a/src/theory/bags/theory_bags.cpp b/src/theory/bags/theory_bags.cpp
new file mode 100644
index 000000000..9f62ea1c6
--- /dev/null
+++ b/src/theory/bags/theory_bags.cpp
@@ -0,0 +1,143 @@
+/********************* */
+/*! \file theory_bags.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Bags theory.
+ **/
+
+#include "theory/bags/theory_bags.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+TheoryBags::TheoryBags(context::Context* c,
+ context::UserContext* u,
+ OutputChannel& out,
+ Valuation valuation,
+ const LogicInfo& logicInfo,
+ ProofNodeManager* pnm)
+ : Theory(THEORY_BAGS, c, u, out, valuation, logicInfo, pnm),
+ d_state(c, u, valuation),
+ d_im(*this, d_state, pnm),
+ d_notify(*this, d_im),
+ d_statistics(),
+ d_rewriter(&d_statistics.d_rewrites)
+{
+ // use the official theory state and inference manager objects
+ d_theoryState = &d_state;
+ d_inferManager = &d_im;
+}
+
+TheoryBags::~TheoryBags() {}
+
+TheoryRewriter* TheoryBags::getTheoryRewriter() { return &d_rewriter; }
+
+bool TheoryBags::needsEqualityEngine(EeSetupInfo& esi)
+{
+ esi.d_notify = &d_notify;
+ esi.d_name = "theory::bags::ee";
+ return true;
+}
+
+void TheoryBags::finishInit()
+{
+ Assert(d_equalityEngine != nullptr);
+
+ // choice is used to eliminate witness
+ d_valuation.setUnevaluatedKind(WITNESS);
+
+ // functions we are doing congruence over
+ d_equalityEngine->addFunctionKind(UNION_MAX);
+ d_equalityEngine->addFunctionKind(UNION_DISJOINT);
+ d_equalityEngine->addFunctionKind(INTERSECTION_MIN);
+ d_equalityEngine->addFunctionKind(DIFFERENCE_SUBTRACT);
+ d_equalityEngine->addFunctionKind(DIFFERENCE_REMOVE);
+ d_equalityEngine->addFunctionKind(BAG_COUNT);
+ d_equalityEngine->addFunctionKind(DUPLICATE_REMOVAL);
+ d_equalityEngine->addFunctionKind(MK_BAG);
+ d_equalityEngine->addFunctionKind(BAG_CARD);
+ d_equalityEngine->addFunctionKind(BAG_FROM_SET);
+ d_equalityEngine->addFunctionKind(BAG_TO_SET);
+}
+
+void TheoryBags::postCheck(Effort level) {}
+
+void TheoryBags::notifyFact(TNode atom,
+ bool polarity,
+ TNode fact,
+ bool isInternal)
+{
+}
+
+bool TheoryBags::collectModelValues(TheoryModel* m,
+ const std::set<Node>& termBag)
+{
+ return true;
+}
+
+TrustNode TheoryBags::explain(TNode node) { return d_im.explainLit(node); }
+
+Node TheoryBags::getModelValue(TNode node) { return Node::null(); }
+
+void TheoryBags::preRegisterTerm(TNode node) {}
+
+TrustNode TheoryBags::expandDefinition(Node n)
+{
+ // TODO(projects#224): add choose and is_singleton here
+ return TrustNode::null();
+}
+
+void TheoryBags::presolve() {}
+
+/**************************** eq::NotifyClass *****************************/
+
+void TheoryBags::eqNotifyNewClass(TNode t)
+{
+ Assert(false) << "Not implemented yet" << std::endl;
+}
+
+void TheoryBags::eqNotifyMerge(TNode t1, TNode t2)
+{
+ Assert(false) << "Not implemented yet" << std::endl;
+}
+
+void TheoryBags::eqNotifyDisequal(TNode t1, TNode t2, TNode reason)
+{
+ Assert(false) << "Not implemented yet" << std::endl;
+}
+
+void TheoryBags::NotifyClass::eqNotifyNewClass(TNode t)
+{
+ Debug("bags-eq") << "[bags-eq] eqNotifyNewClass:"
+ << " t = " << t << std::endl;
+ d_theory.eqNotifyNewClass(t);
+}
+
+void TheoryBags::NotifyClass::eqNotifyMerge(TNode t1, TNode t2)
+{
+ Debug("bags-eq") << "[bags-eq] eqNotifyMerge:"
+ << " t1 = " << t1 << " t2 = " << t2 << std::endl;
+ d_theory.eqNotifyMerge(t1, t2);
+}
+
+void TheoryBags::NotifyClass::eqNotifyDisequal(TNode t1, TNode t2, TNode reason)
+{
+ Debug("bags-eq") << "[bags-eq] eqNotifyDisequal:"
+ << " t1 = " << t1 << " t2 = " << t2 << " reason = " << reason
+ << std::endl;
+ d_theory.eqNotifyDisequal(t1, t2, reason);
+}
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/bags/theory_bags.h b/src/theory/bags/theory_bags.h
new file mode 100644
index 000000000..08bc5f33a
--- /dev/null
+++ b/src/theory/bags/theory_bags.h
@@ -0,0 +1,113 @@
+/********************* */
+/*! \file theory_bags.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Bags theory.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__BAGS__THEORY_BAGS_H
+#define CVC4__THEORY__BAGS__THEORY_BAGS_H
+
+#include <memory>
+
+#include "theory/bags/bags_rewriter.h"
+#include "theory/bags/bags_statistics.h"
+#include "theory/bags/inference_manager.h"
+#include "theory/bags/solver_state.h"
+#include "theory/theory.h"
+#include "theory/theory_eq_notify.h"
+#include "theory/uf/equality_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+class TheoryBags : public Theory
+{
+ public:
+ /** Constructs a new instance of TheoryBags w.r.t. the provided contexts. */
+ TheoryBags(context::Context* c,
+ context::UserContext* u,
+ OutputChannel& out,
+ Valuation valuation,
+ const LogicInfo& logicInfo,
+ ProofNodeManager* pnm);
+ ~TheoryBags() override;
+
+ //--------------------------------- initialization
+ /** get the official theory rewriter of this theory */
+ TheoryRewriter* getTheoryRewriter() override;
+ /**
+ * Returns true if we need an equality engine. If so, we initialize the
+ * information regarding how it should be setup. For details, see the
+ * documentation in Theory::needsEqualityEngine.
+ */
+ bool needsEqualityEngine(EeSetupInfo& esi) override;
+ /** finish initialization */
+ void finishInit() override;
+ //--------------------------------- end initialization
+
+ //--------------------------------- standard check
+ /** Post-check, called after the fact queue of the theory is processed. */
+ void postCheck(Effort level) override;
+ /** Notify fact */
+ void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal) override;
+ //--------------------------------- end standard check
+ /** Collect model values in m based on the relevant terms given by termSet */
+ bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet) override;
+ TrustNode explain(TNode) override;
+ Node getModelValue(TNode) override;
+ std::string identify() const override { return "THEORY_BAGS"; }
+ void preRegisterTerm(TNode node) override;
+ TrustNode expandDefinition(Node n) override;
+ void presolve() override;
+
+ private:
+ /** Functions to handle callbacks from equality engine */
+ class NotifyClass : public TheoryEqNotifyClass
+ {
+ public:
+ NotifyClass(TheoryBags& theory, TheoryInferenceManager& inferenceManager)
+
+ : TheoryEqNotifyClass(inferenceManager), d_theory(theory)
+ {
+ }
+ void eqNotifyNewClass(TNode t) override;
+ void eqNotifyMerge(TNode t1, TNode t2) override;
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override;
+
+ private:
+ TheoryBags& d_theory;
+ };
+
+ /** The state of the bags solver at full effort */
+ SolverState d_state;
+ /** The inference manager */
+ InferenceManager d_im;
+ /** Instance of the above class */
+ NotifyClass d_notify;
+ /** Statistics for the theory of bags. */
+ BagsStatistics d_statistics;
+ /** The theory rewriter for this theory. */
+ BagsRewriter d_rewriter;
+
+ void eqNotifyNewClass(TNode t);
+ void eqNotifyMerge(TNode t1, TNode t2);
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
+}; /* class TheoryBags */
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__BAGS__THEORY_BAGS_H */
diff --git a/src/theory/bags/theory_bags_type_enumerator.cpp b/src/theory/bags/theory_bags_type_enumerator.cpp
new file mode 100644
index 000000000..727407937
--- /dev/null
+++ b/src/theory/bags/theory_bags_type_enumerator.cpp
@@ -0,0 +1,86 @@
+/********************* */
+/*! \file theory_bags_type_enumerator.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief bag enumerator implementation
+ **/
+
+#include "theory/bags/theory_bags_type_enumerator.h"
+
+#include "expr/emptybag.h"
+#include "theory/rewriter.h"
+#include "theory_bags_type_enumerator.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+BagEnumerator::BagEnumerator(TypeNode type, TypeEnumeratorProperties* tep)
+ : TypeEnumeratorBase<BagEnumerator>(type),
+ d_nodeManager(NodeManager::currentNM()),
+ d_elementTypeEnumerator(type.getBagElementType(), tep)
+{
+ d_currentBag = d_nodeManager->mkConst(EmptyBag(type));
+ d_element = *d_elementTypeEnumerator;
+}
+
+BagEnumerator::BagEnumerator(const BagEnumerator& enumerator)
+ : TypeEnumeratorBase<BagEnumerator>(enumerator.getType()),
+ d_nodeManager(enumerator.d_nodeManager),
+ d_elementTypeEnumerator(enumerator.d_elementTypeEnumerator),
+ d_currentBag(enumerator.d_currentBag),
+ d_element(enumerator.d_element)
+{
+}
+
+BagEnumerator::~BagEnumerator() {}
+
+Node BagEnumerator::operator*()
+{
+ Trace("bag-type-enum") << "BagEnumerator::operator* d_currentBag = "
+ << d_currentBag << std::endl;
+
+ return d_currentBag;
+}
+
+BagEnumerator& BagEnumerator::operator++()
+{
+ // increase the multiplicity by one
+ Node one = d_nodeManager->mkConst(Rational(1));
+ TypeNode elementType = d_elementTypeEnumerator.getType();
+ Node singleton = d_nodeManager->mkBag(elementType, d_element, one);
+ if (d_currentBag.getKind() == kind::EMPTYBAG)
+ {
+ d_currentBag = singleton;
+ }
+ else
+ {
+ d_currentBag =
+ d_nodeManager->mkNode(kind::UNION_DISJOINT, singleton, d_currentBag);
+ }
+
+ d_currentBag = Rewriter::rewrite(d_currentBag);
+
+ Assert(d_currentBag.isConst());
+
+ Trace("bag-type-enum") << "BagEnumerator::operator++ d_currentBag = "
+ << d_currentBag << std::endl;
+ return *this;
+}
+
+bool BagEnumerator::isFinished()
+{
+ // bags sequence is infinite and it never ends
+ return false;
+}
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4 \ No newline at end of file
diff --git a/src/theory/bags/theory_bags_type_enumerator.h b/src/theory/bags/theory_bags_type_enumerator.h
new file mode 100644
index 000000000..a1ba896c1
--- /dev/null
+++ b/src/theory/bags/theory_bags_type_enumerator.h
@@ -0,0 +1,91 @@
+/********************* */
+/*! \file theory_bags_type_enumerator.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief type enumerator for bags
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__BAGS__TYPE_ENUMERATOR_H
+#define CVC4__THEORY__BAGS__TYPE_ENUMERATOR_H
+
+#include "expr/type_node.h"
+#include "theory/type_enumerator.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+class BagEnumerator : public TypeEnumeratorBase<BagEnumerator>
+{
+ public:
+ BagEnumerator(TypeNode type, TypeEnumeratorProperties* tep = nullptr);
+ BagEnumerator(const BagEnumerator& enumerator);
+ ~BagEnumerator();
+
+ Node operator*() override;
+
+ /**
+ * This operator iterates over the infinite bags constructed from the element
+ * type . Ideally iterating over bags of {1, 2, 3, ...} will return the
+ * following infinite sequence of bags, where n in the pair (m, n) means the
+ * multiplicity of the element m in the bag
+ * {}, sum = 0, #elements = 0, cardinality = 0
+ *
+ * {(1,1)}, sum = 2, #elements = 1, cardinality = 1
+ *
+ * {(2,1)}, sum = 3, #elements = 2, cardinality = 1
+ * {(1,2)}, sum = 3, #elements = 2, cardinality = 2
+ *
+ * {(3, 1)}, sum = 4, #elements = 3, cardinality = 1
+ * {(2, 2)}, sum = 4, #elements = 3, cardinality = 2
+ * {(1, 3)}, sum = 4, #elements = 3, cardinality = 3
+ *
+ * {(4, 1)}, sum = 5, #elements = 4, cardinality = 1
+ * {(3, 2)}, sum = 5, #elements = 4, cardinality = 2
+ * {(1, 1),(2, 1)}, sum = 5, #elements = 4, cardinality = 2
+ * {(2, 3)}, sum = 5, #elements = 4, cardinality = 3
+ * {(1, 4)}, sum = 5, #elements = 4, cardinality = 4
+ *
+ * {(5, 1)}, sum = 6, #elements = 5, cardinality = 1
+ * {(4, 2)}, sum = 6, #elements = 5, cardinality = 2
+ * {(1, 1), (3,1)}, sum = 6, #elements = 5, cardinality = 2
+ * {(3, 3)}, sum = 6, #elements = 5, cardinality = 3
+ * {(1, 1), (2,2)}, sum = 6, #elements = 5, cardinality = 3
+ * {(1, 2), (2,1)}, sum = 6, #elements = 5, cardinality = 3
+ * {(2, 4)}, sum = 6, #elements = 5, cardinality = 4
+ * {(1, 5)}, sum = 6, #elements = 5, cardinality = 5
+ *
+ * This seems too expensive to implement.
+ * For now we are implementing an obvious solution
+ * {(1,1)}, {(1,2)}, {(1,3)}, ... which works for both finite and infinite
+ * types
+ */
+ BagEnumerator& operator++() override;
+
+ bool isFinished() override;
+
+ private:
+ /** a pointer to the node manager */
+ NodeManager* d_nodeManager;
+ /** an enumerator for the set of pairs of element type x integer type */
+ TypeEnumerator d_elementTypeEnumerator;
+ /** the current set returned by the set enumerator */
+ Node d_currentBag;
+ /** the first value returned by the element type enumerator*/
+ Node d_element;
+}; /* class BagEnumerator */
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__BAGS__TYPE_ENUMERATOR_H */ \ No newline at end of file
diff --git a/src/theory/bags/theory_bags_type_rules.h b/src/theory/bags/theory_bags_type_rules.h
new file mode 100644
index 000000000..cece40c9e
--- /dev/null
+++ b/src/theory/bags/theory_bags_type_rules.h
@@ -0,0 +1,314 @@
+/********************* */
+/*! \file theory_bags_type_rules.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Bags theory type rules.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__BAGS__THEORY_BAGS_TYPE_RULES_H
+#define CVC4__THEORY__BAGS__THEORY_BAGS_TYPE_RULES_H
+
+#include "theory/bags/normal_form.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bags {
+
+struct BinaryOperatorTypeRule
+{
+ static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ {
+ Assert(n.getKind() == kind::UNION_MAX || n.getKind() == kind::UNION_DISJOINT
+ || n.getKind() == kind::INTERSECTION_MIN
+ || n.getKind() == kind::DIFFERENCE_SUBTRACT
+ || n.getKind() == kind::DIFFERENCE_REMOVE);
+ TypeNode bagType = n[0].getType(check);
+ if (check)
+ {
+ if (!bagType.isBag())
+ {
+ throw TypeCheckingExceptionPrivate(
+ n, "operator expects a bag, first argument is not");
+ }
+ TypeNode secondBagType = n[1].getType(check);
+ if (secondBagType != bagType)
+ {
+ std::stringstream ss;
+ ss << "Operator " << n.getKind()
+ << " expects two bags of the same type. Found types '" << bagType
+ << "' and '" << secondBagType << "'.";
+ throw TypeCheckingExceptionPrivate(n, ss.str());
+ }
+ }
+ return bagType;
+ }
+
+ static bool computeIsConst(NodeManager* nodeManager, TNode n)
+ {
+ // only UNION_DISJOINT has a const rule in kinds.
+ // Other binary operators do not have const rules in kinds
+ Assert(n.getKind() == kind::UNION_DISJOINT);
+ return NormalForm::isConstant(n);
+ }
+}; /* struct BinaryOperatorTypeRule */
+
+struct SubBagTypeRule
+{
+ static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ {
+ Assert(n.getKind() == kind::SUBBAG);
+ TypeNode bagType = n[0].getType(check);
+ if (check)
+ {
+ if (!bagType.isBag())
+ {
+ throw TypeCheckingExceptionPrivate(n, "SUBBAG operating on non-bag");
+ }
+ TypeNode secondBagType = n[1].getType(check);
+ if (secondBagType != bagType)
+ {
+ if (!bagType.isComparableTo(secondBagType))
+ {
+ throw TypeCheckingExceptionPrivate(
+ n, "SUBBAG operating on bags of different types");
+ }
+ }
+ }
+ return nodeManager->booleanType();
+ }
+}; /* struct SubBagTypeRule */
+
+struct CountTypeRule
+{
+ static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ {
+ Assert(n.getKind() == kind::BAG_COUNT);
+ TypeNode bagType = n[1].getType(check);
+ if (check)
+ {
+ if (!bagType.isBag())
+ {
+ throw TypeCheckingExceptionPrivate(
+ n, "checking for membership in a non-bag");
+ }
+ TypeNode elementType = n[0].getType(check);
+ // e.g. (count 1 (mkBag (mkBag_op Real) 1.0 3))) is 3 whereas
+ // (count 1.0 (mkBag (mkBag_op Int) 1 3))) throws a typing error
+ if (!elementType.isSubtypeOf(bagType.getBagElementType()))
+ {
+ std::stringstream ss;
+ ss << "member operating on bags of different types:\n"
+ << "child type: " << elementType << "\n"
+ << "not subtype: " << bagType.getBagElementType() << "\n"
+ << "in term : " << n;
+ throw TypeCheckingExceptionPrivate(n, ss.str());
+ }
+ }
+ return nodeManager->integerType();
+ }
+}; /* struct CountTypeRule */
+
+struct DuplicateRemovalTypeRule
+{
+ static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ {
+ Assert(n.getKind() == kind::DUPLICATE_REMOVAL);
+ TypeNode bagType = n[0].getType(check);
+ if (check)
+ {
+ if (!bagType.isBag())
+ {
+ std::stringstream ss;
+ ss << "Applying DUPLICATE_REMOVAL on a non-bag argument in term " << n;
+ throw TypeCheckingExceptionPrivate(n, ss.str());
+ }
+ }
+ return bagType;
+ }
+}; /* struct DuplicateRemovalTypeRule */
+
+struct MkBagTypeRule
+{
+ static TypeNode computeType(NodeManager* nm, TNode n, bool check)
+ {
+ Assert(n.getKind() == kind::MK_BAG && n.hasOperator()
+ && n.getOperator().getKind() == kind::MK_BAG_OP);
+ MakeBagOp op = n.getOperator().getConst<MakeBagOp>();
+ TypeNode expectedElementType = op.getType();
+ if (check)
+ {
+ if (n.getNumChildren() != 2)
+ {
+ std::stringstream ss;
+ ss << "operands in term " << n << " are " << n.getNumChildren()
+ << ", but MK_BAG expects 2 operands.";
+ throw TypeCheckingExceptionPrivate(n, ss.str());
+ }
+ TypeNode type1 = n[1].getType(check);
+ if (!type1.isInteger())
+ {
+ std::stringstream ss;
+ ss << "MK_BAG expects an integer for " << n[1] << ". Found" << type1;
+ throw TypeCheckingExceptionPrivate(n, ss.str());
+ }
+
+ TypeNode actualElementType = n[0].getType(check);
+ // the type of the element should be a subtype of the type of the operator
+ // e.g. (mkBag (mkBag_op Real) 1 1) where 1 is an Int
+ if (!actualElementType.isSubtypeOf(expectedElementType))
+ {
+ std::stringstream ss;
+ ss << "The type '" << actualElementType
+ << "' of the element is not a subtype of '" << expectedElementType
+ << "' in term : " << n;
+ throw TypeCheckingExceptionPrivate(n, ss.str());
+ }
+ }
+
+ return nm->mkBagType(expectedElementType);
+ }
+
+ static bool computeIsConst(NodeManager* nodeManager, TNode n)
+ {
+ Assert(n.getKind() == kind::MK_BAG);
+ // for a bag to be a constant, both the element and its multiplicity should
+ // be constants, and the multiplicity should be > 0.
+ return n[0].isConst() && n[1].isConst()
+ && n[1].getConst<Rational>().sgn() == 1;
+ }
+}; /* struct MkBagTypeRule */
+
+struct IsSingletonTypeRule
+{
+ static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ {
+ Assert(n.getKind() == kind::BAG_IS_SINGLETON);
+ TypeNode bagType = n[0].getType(check);
+ if (check)
+ {
+ if (!bagType.isBag())
+ {
+ throw TypeCheckingExceptionPrivate(
+ n, "BAG_IS_SINGLETON operator expects a bag, a non-bag is found");
+ }
+ }
+ return nodeManager->booleanType();
+ }
+}; /* struct IsMkBagTypeRule */
+
+struct EmptyBagTypeRule
+{
+ static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ {
+ Assert(n.getKind() == kind::EMPTYBAG);
+ EmptyBag emptyBag = n.getConst<EmptyBag>();
+ return emptyBag.getType();
+ }
+}; /* struct EmptyBagTypeRule */
+
+struct CardTypeRule
+{
+ static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ {
+ Assert(n.getKind() == kind::BAG_CARD);
+ TypeNode bagType = n[0].getType(check);
+ if (check)
+ {
+ if (!bagType.isBag())
+ {
+ throw TypeCheckingExceptionPrivate(
+ n, "cardinality operates on a bag, non-bag object found");
+ }
+ }
+ return nodeManager->integerType();
+ }
+}; /* struct CardTypeRule */
+
+struct ChooseTypeRule
+{
+ static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ {
+ Assert(n.getKind() == kind::BAG_CHOOSE);
+ TypeNode bagType = n[0].getType(check);
+ if (check)
+ {
+ if (!bagType.isBag())
+ {
+ throw TypeCheckingExceptionPrivate(
+ n, "CHOOSE operator expects a bag, a non-bag is found");
+ }
+ }
+ return bagType.getBagElementType();
+ }
+}; /* struct ChooseTypeRule */
+
+struct FromSetTypeRule
+{
+ static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ {
+ Assert(n.getKind() == kind::BAG_FROM_SET);
+ TypeNode setType = n[0].getType(check);
+ if (check)
+ {
+ if (!setType.isSet())
+ {
+ throw TypeCheckingExceptionPrivate(
+ n, "bag.from_set operator expects a set, a non-set is found");
+ }
+ }
+ TypeNode elementType = setType.getSetElementType();
+ TypeNode bagType = nodeManager->mkBagType(elementType);
+ return bagType;
+ }
+}; /* struct FromSetTypeRule */
+
+struct ToSetTypeRule
+{
+ static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ {
+ Assert(n.getKind() == kind::BAG_TO_SET);
+ TypeNode bagType = n[0].getType(check);
+ if (check)
+ {
+ if (!bagType.isBag())
+ {
+ throw TypeCheckingExceptionPrivate(
+ n, "bag.to_set operator expects a bag, a non-bag is found");
+ }
+ }
+ TypeNode elementType = bagType.getBagElementType();
+ TypeNode setType = nodeManager->mkSetType(elementType);
+ return setType;
+ }
+}; /* struct ToSetTypeRule */
+
+struct BagsProperties
+{
+ static Cardinality computeCardinality(TypeNode type)
+ {
+ return Cardinality::INTEGERS;
+ }
+
+ static bool isWellFounded(TypeNode type) { return type[0].isWellFounded(); }
+
+ static Node mkGroundTerm(TypeNode type)
+ {
+ Assert(type.isBag());
+ return NodeManager::currentNM()->mkConst(EmptyBag(type));
+ }
+}; /* struct BagsProperties */
+
+} // namespace bags
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__BAGS__THEORY_BAGS_TYPE_RULES_H */
diff --git a/src/theory/booleans/circuit_propagator.cpp b/src/theory/booleans/circuit_propagator.cpp
index 32901e7ed..270c0b9a9 100644
--- a/src/theory/booleans/circuit_propagator.cpp
+++ b/src/theory/booleans/circuit_propagator.cpp
@@ -5,7 +5,7 @@
** Dejan Jovanovic, Morgan Deters, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,11 +16,12 @@
#include "theory/booleans/circuit_propagator.h"
+#include <algorithm>
#include <stack>
#include <vector>
-#include <algorithm>
#include "expr/node_algorithm.h"
+#include "theory/booleans/proof_circuit_propagator.h"
#include "util/utility.h"
using namespace std;
@@ -29,29 +30,167 @@ namespace CVC4 {
namespace theory {
namespace booleans {
+CircuitPropagator::CircuitPropagator(bool enableForward, bool enableBackward)
+ : d_context(),
+ d_propagationQueue(),
+ d_propagationQueueClearer(&d_context, d_propagationQueue),
+ d_conflict(&d_context, TrustNode()),
+ d_learnedLiterals(),
+ d_learnedLiteralClearer(&d_context, d_learnedLiterals),
+ d_backEdges(),
+ d_backEdgesClearer(&d_context, d_backEdges),
+ d_seen(&d_context),
+ d_state(&d_context),
+ d_forwardPropagation(enableForward),
+ d_backwardPropagation(enableBackward),
+ d_needsFinish(false),
+ d_pnm(nullptr),
+ d_epg(nullptr),
+ d_proofInternal(nullptr),
+ d_proofExternal(nullptr)
+{
+}
+
+void CircuitPropagator::finish()
+{
+ Trace("circuit-prop") << "FINISH" << std::endl;
+ d_context.pop();
+}
+
void CircuitPropagator::assertTrue(TNode assertion)
{
- if (assertion.getKind() == kind::AND) {
- for (unsigned i = 0; i < assertion.getNumChildren(); ++ i) {
- assertTrue(assertion[i]);
+ Trace("circuit-prop") << "TRUE: " << assertion << std::endl;
+ if (assertion.getKind() == kind::CONST_BOOLEAN && !assertion.getConst<bool>())
+ {
+ makeConflict(assertion);
+ }
+ else if (assertion.getKind() == kind::AND)
+ {
+ ProofCircuitPropagatorBackward prover{d_pnm, assertion, true};
+ if (isProofEnabled())
+ {
+ addProof(assertion, prover.assume(assertion));
+ }
+ for (auto it = assertion.begin(); it != assertion.end(); ++it)
+ {
+ addProof(*it, prover.andTrue(it));
+ assertTrue(*it);
}
- } else {
+ }
+ else
+ {
// Analyze the assertion for back-edges and all that
computeBackEdges(assertion);
// Assign the given assertion to true
- assignAndEnqueue(assertion, true);
+ if (isProofEnabled())
+ {
+ assignAndEnqueue(assertion, true, d_pnm->mkAssume(assertion));
+ }
+ else
+ {
+ assignAndEnqueue(assertion, true, nullptr);
+ }
}
}
-void CircuitPropagator::computeBackEdges(TNode node) {
+void CircuitPropagator::assignAndEnqueue(TNode n,
+ bool value,
+ std::shared_ptr<ProofNode> proof)
+{
+ Trace("circuit-prop") << "CircuitPropagator::assign(" << n << ", "
+ << (value ? "true" : "false") << ")" << std::endl;
+
+ if (n.getKind() == kind::CONST_BOOLEAN)
+ {
+ // Assigning a constant to the opposite value is dumb
+ if (value != n.getConst<bool>())
+ {
+ makeConflict(n);
+ return;
+ }
+ }
- Debug("circuit-prop") << "CircuitPropagator::computeBackEdges(" << node << ")" << endl;
+ if (isProofEnabled())
+ {
+ if (proof == nullptr)
+ {
+ Warning() << "CircuitPropagator: Proof is missing for " << n << std::endl;
+ Assert(false);
+ }
+ else
+ {
+ Assert(!proof->getResult().isNull());
+ Node expected = value ? Node(n) : n.negate();
+ if (proof->getResult() != expected)
+ {
+ Warning() << "CircuitPropagator: Incorrect proof: " << expected
+ << " vs. " << proof->getResult() << std::endl
+ << *proof << std::endl;
+ }
+ addProof(expected, std::move(proof));
+ }
+ }
+
+ // Get the current assignment
+ AssignmentStatus state = d_state[n];
+
+ if (state != UNASSIGNED)
+ {
+ // If the node is already assigned we might have a conflict
+ if (value != (state == ASSIGNED_TO_TRUE))
+ {
+ makeConflict(n);
+ }
+ }
+ else
+ {
+ // If unassigned, mark it as assigned
+ d_state[n] = value ? ASSIGNED_TO_TRUE : ASSIGNED_TO_FALSE;
+ // Add for further propagation
+ d_propagationQueue.push_back(n);
+ }
+}
+
+void CircuitPropagator::makeConflict(Node n)
+{
+ auto bfalse = NodeManager::currentNM()->mkConst(false);
+ ProofGenerator* g = nullptr;
+ if (isProofEnabled())
+ {
+ if (d_epg->hasProofFor(bfalse))
+ {
+ return;
+ }
+ ProofCircuitPropagator pcp(d_pnm);
+ if (n == bfalse)
+ {
+ d_epg->setProofFor(bfalse, pcp.assume(bfalse));
+ }
+ else
+ {
+ d_epg->setProofFor(bfalse,
+ pcp.conflict(pcp.assume(n), pcp.assume(n.negate())));
+ }
+ g = d_proofInternal.get();
+ Trace("circuit-prop") << "Added conflict " << *d_epg->getProofFor(bfalse)
+ << std::endl;
+ Trace("circuit-prop") << "\texpanded " << *g->getProofFor(bfalse)
+ << std::endl;
+ }
+ d_conflict = TrustNode::mkTrustLemma(bfalse, g);
+}
+
+void CircuitPropagator::computeBackEdges(TNode node)
+{
+ Debug("circuit-prop") << "CircuitPropagator::computeBackEdges(" << node << ")"
+ << endl;
// Vector of nodes to visit
vector<TNode> toVisit;
// Start with the top node
- if (d_seen.find(node) == d_seen.end()) {
+ if (d_seen.find(node) == d_seen.end())
+ {
toVisit.push_back(node);
d_seen.insert(node);
}
@@ -60,20 +199,28 @@ void CircuitPropagator::computeBackEdges(TNode node) {
d_backEdges[node];
// Go through the visit list
- for (unsigned i = 0; i < toVisit.size(); ++ i) {
+ for (unsigned i = 0; i < toVisit.size(); ++i)
+ {
// Node we need to visit
TNode current = toVisit[i];
- Debug("circuit-prop") << "CircuitPropagator::computeBackEdges(): processing " << current << endl;
+ Debug("circuit-prop")
+ << "CircuitPropagator::computeBackEdges(): processing " << current
+ << endl;
Assert(d_seen.find(current) != d_seen.end());
// If this not an atom visit all the children and compute the back edges
- if (Theory::theoryOf(current) == THEORY_BOOL) {
- for (unsigned child = 0, child_end = current.getNumChildren(); child < child_end; ++ child) {
+ if (Theory::theoryOf(current) == THEORY_BOOL)
+ {
+ for (unsigned child = 0, child_end = current.getNumChildren();
+ child < child_end;
+ ++child)
+ {
TNode childNode = current[child];
// Add the back edge
d_backEdges[childNode].push_back(current);
// Add to the queue if not seen yet
- if (d_seen.find(childNode) == d_seen.end()) {
+ if (d_seen.find(childNode) == d_seen.end())
+ {
toVisit.push_back(childNode);
d_seen.insert(childNode);
}
@@ -82,124 +229,204 @@ void CircuitPropagator::computeBackEdges(TNode node) {
}
}
-void CircuitPropagator::propagateBackward(TNode parent, bool parentAssignment) {
-
- Debug("circuit-prop") << "CircuitPropagator::propagateBackward(" << parent << ", " << parentAssignment << ")" << endl;
+void CircuitPropagator::propagateBackward(TNode parent, bool parentAssignment)
+{
+ Debug("circuit-prop") << "CircuitPropagator::propagateBackward(" << parent
+ << ", " << parentAssignment << ")" << endl;
+ ProofCircuitPropagatorBackward prover{d_pnm, parent, parentAssignment};
// backward rules
- switch(parent.getKind()) {
- case kind::AND:
- if (parentAssignment) {
- // AND = TRUE: forall children c, assign(c = TRUE)
- for(TNode::iterator i = parent.begin(), i_end = parent.end(); i != i_end; ++i) {
- assignAndEnqueue(*i, true);
+ switch (parent.getKind())
+ {
+ case kind::AND:
+ if (parentAssignment)
+ {
+ // AND = TRUE: forall children c, assign(c = TRUE)
+ for (TNode::iterator i = parent.begin(), i_end = parent.end();
+ i != i_end;
+ ++i)
+ {
+ assignAndEnqueue(*i, true, prover.andTrue(i));
+ }
}
- } else {
- // AND = FALSE: if all children BUT ONE == TRUE, assign(c = FALSE)
- TNode::iterator holdout = find_if_unique(parent.begin(), parent.end(), not1(IsAssignedTo(*this, true)));
- if (holdout != parent.end()) {
- assignAndEnqueue(*holdout, false);
+ else
+ {
+ // AND = FALSE: if all children BUT ONE == TRUE, assign(c = FALSE)
+ TNode::iterator holdout = find_if_unique(
+ parent.begin(), parent.end(), not1(IsAssignedTo(*this, true)));
+ if (holdout != parent.end())
+ {
+ assignAndEnqueue(*holdout, false, prover.andFalse(parent, holdout));
+ }
}
- }
- break;
- case kind::OR:
- if (parentAssignment) {
- // OR = TRUE: if all children BUT ONE == FALSE, assign(c = TRUE)
- TNode::iterator holdout = find_if_unique(parent.begin(), parent.end(), not1(IsAssignedTo(*this, false)));
- if (holdout != parent.end()) {
- assignAndEnqueue(*holdout, true);
+ break;
+ case kind::OR:
+ if (parentAssignment)
+ {
+ // OR = TRUE: if all children BUT ONE == FALSE, assign(c = TRUE)
+ TNode::iterator holdout = find_if_unique(
+ parent.begin(), parent.end(), not1(IsAssignedTo(*this, false)));
+ if (holdout != parent.end())
+ {
+ assignAndEnqueue(*holdout, true, prover.orTrue(parent, holdout));
+ }
}
- } else {
- // OR = FALSE: forall children c, assign(c = FALSE)
- for(TNode::iterator i = parent.begin(), i_end = parent.end(); i != i_end; ++i) {
- assignAndEnqueue(*i, false);
+ else
+ {
+ // OR = FALSE: forall children c, assign(c = FALSE)
+ for (TNode::iterator i = parent.begin(), i_end = parent.end();
+ i != i_end;
+ ++i)
+ {
+ assignAndEnqueue(*i, false, prover.orFalse(i));
+ }
}
- }
- break;
- case kind::NOT:
- // NOT = b: assign(c = !b)
- assignAndEnqueue(parent[0], !parentAssignment);
- break;
- case kind::ITE:
- if (isAssignedTo(parent[0], true)) {
- // ITE c x y = v: if c is assigned and TRUE, assign(x = v)
- assignAndEnqueue(parent[1], parentAssignment);
- } else if (isAssignedTo(parent[0], false)) {
- // ITE c x y = v: if c is assigned and FALSE, assign(y = v)
- assignAndEnqueue(parent[2], parentAssignment);
- } else if (isAssigned(parent[1]) && isAssigned(parent[2])) {
- if (getAssignment(parent[1]) == parentAssignment && getAssignment(parent[2]) != parentAssignment) {
- // ITE c x y = v: if c is unassigned, x and y are assigned, x==v and y!=v, assign(c = TRUE)
- assignAndEnqueue(parent[0], true);
- } else if (getAssignment(parent[1]) != parentAssignment && getAssignment(parent[2]) == parentAssignment) {
- // ITE c x y = v: if c is unassigned, x and y are assigned, x!=v and y==v, assign(c = FALSE)
- assignAndEnqueue(parent[0], false);
+ break;
+ case kind::NOT:
+ // NOT = b: assign(c = !b)
+ assignAndEnqueue(
+ parent[0], !parentAssignment, prover.Not(!parentAssignment, parent));
+ break;
+ case kind::ITE:
+ if (isAssignedTo(parent[0], true))
+ {
+ // ITE c x y = v: if c is assigned and TRUE, assign(x = v)
+ assignAndEnqueue(parent[1], parentAssignment, prover.iteC(true));
}
- }
- break;
- case kind::EQUAL:
- Assert(parent[0].getType().isBoolean());
- if (parentAssignment) {
- // IFF x y = TRUE: if x [resp y] is assigned, assign(y = x.assignment [resp x = y.assignment])
- if (isAssigned(parent[0])) {
- assignAndEnqueue(parent[1], getAssignment(parent[0]));
- } else if (isAssigned(parent[1])) {
- assignAndEnqueue(parent[0], getAssignment(parent[1]));
+ else if (isAssignedTo(parent[0], false))
+ {
+ // ITE c x y = v: if c is assigned and FALSE, assign(y = v)
+ assignAndEnqueue(parent[2], parentAssignment, prover.iteC(false));
}
- } else {
- // IFF x y = FALSE: if x [resp y] is assigned, assign(y = !x.assignment [resp x = !y.assignment])
- if (isAssigned(parent[0])) {
- assignAndEnqueue(parent[1], !getAssignment(parent[0]));
- } else if (isAssigned(parent[1])) {
- assignAndEnqueue(parent[0], !getAssignment(parent[1]));
+ else if (isAssigned(parent[1]) && isAssigned(parent[2]))
+ {
+ if (getAssignment(parent[1]) == parentAssignment
+ && getAssignment(parent[2]) != parentAssignment)
+ {
+ // ITE c x y = v: if c is unassigned, x and y are assigned, x==v and
+ // y!=v, assign(c = TRUE)
+ assignAndEnqueue(parent[0], true, prover.iteIsCase(1));
+ }
+ else if (getAssignment(parent[1]) != parentAssignment
+ && getAssignment(parent[2]) == parentAssignment)
+ {
+ // ITE c x y = v: if c is unassigned, x and y are assigned, x!=v and
+ // y==v, assign(c = FALSE)
+ assignAndEnqueue(parent[0], false, prover.iteIsCase(0));
+ }
}
- }
- break;
- case kind::IMPLIES:
- if (parentAssignment) {
- if (isAssignedTo(parent[0], true)) {
- // IMPLIES x y = TRUE, and x == TRUE: assign(y = TRUE)
- assignAndEnqueue(parent[1], true);
+ break;
+ case kind::EQUAL:
+ Assert(parent[0].getType().isBoolean());
+ if (parentAssignment)
+ {
+ // IFF x y = TRUE: if x [resp y] is assigned, assign(y = x.assignment
+ // [resp x = y.assignment])
+ if (isAssigned(parent[0]))
+ {
+ assignAndEnqueue(parent[1],
+ getAssignment(parent[0]),
+ prover.eqYFromX(getAssignment(parent[0]), parent));
+ }
+ else if (isAssigned(parent[1]))
+ {
+ assignAndEnqueue(parent[0],
+ getAssignment(parent[1]),
+ prover.eqXFromY(getAssignment(parent[1]), parent));
+ }
}
- if (isAssignedTo(parent[1], false)) {
- // IMPLIES x y = TRUE, and y == FALSE: assign(x = FALSE)
- assignAndEnqueue(parent[0], false);
+ else
+ {
+ // IFF x y = FALSE: if x [resp y] is assigned, assign(y = !x.assignment
+ // [resp x = !y.assignment])
+ if (isAssigned(parent[0]))
+ {
+ assignAndEnqueue(parent[1],
+ !getAssignment(parent[0]),
+ prover.neqYFromX(getAssignment(parent[0]), parent));
+ }
+ else if (isAssigned(parent[1]))
+ {
+ assignAndEnqueue(parent[0],
+ !getAssignment(parent[1]),
+ prover.neqXFromY(getAssignment(parent[1]), parent));
+ }
}
- } else {
- // IMPLIES x y = FALSE: assign(x = TRUE) and assign(y = FALSE)
- assignAndEnqueue(parent[0], true);
- assignAndEnqueue(parent[1], false);
- }
- break;
- case kind::XOR:
- if (parentAssignment) {
- if (isAssigned(parent[0])) {
- // XOR x y = TRUE, and x assigned, assign(y = !assignment(x))
- assignAndEnqueue(parent[1], !getAssignment(parent[0]));
- } else if (isAssigned(parent[1])) {
- // XOR x y = TRUE, and y assigned, assign(x = !assignment(y))
- assignAndEnqueue(parent[0], !getAssignment(parent[1]));
+ break;
+ case kind::IMPLIES:
+ if (parentAssignment)
+ {
+ if (isAssignedTo(parent[0], true))
+ {
+ // IMPLIES x y = TRUE, and x == TRUE: assign(y = TRUE)
+ assignAndEnqueue(parent[1], true, prover.impliesYFromX(parent));
+ }
+ if (isAssignedTo(parent[1], false))
+ {
+ // IMPLIES x y = TRUE, and y == FALSE: assign(x = FALSE)
+ assignAndEnqueue(parent[0], false, prover.impliesXFromY(parent));
+ }
}
- } else {
- if (isAssigned(parent[0])) {
- // XOR x y = FALSE, and x assigned, assign(y = assignment(x))
- assignAndEnqueue(parent[1], getAssignment(parent[0]));
- } else if (isAssigned(parent[1])) {
- // XOR x y = FALSE, and y assigned, assign(x = assignment(y))
- assignAndEnqueue(parent[0], getAssignment(parent[1]));
+ else
+ {
+ // IMPLIES x y = FALSE: assign(x = TRUE) and assign(y = FALSE)
+ assignAndEnqueue(parent[0], true, prover.impliesNegX());
+ assignAndEnqueue(parent[1], false, prover.impliesNegY());
}
- }
- break;
- default:
- Unhandled();
+ break;
+ case kind::XOR:
+ if (parentAssignment)
+ {
+ if (isAssigned(parent[0]))
+ {
+ // XOR x y = TRUE, and x assigned, assign(y = !assignment(x))
+ assignAndEnqueue(
+ parent[1],
+ !getAssignment(parent[0]),
+ prover.xorYFromX(
+ !parentAssignment, getAssignment(parent[0]), parent));
+ }
+ else if (isAssigned(parent[1]))
+ {
+ // XOR x y = TRUE, and y assigned, assign(x = !assignment(y))
+ assignAndEnqueue(
+ parent[0],
+ !getAssignment(parent[1]),
+ prover.xorXFromY(
+ !parentAssignment, getAssignment(parent[1]), parent));
+ }
+ }
+ else
+ {
+ if (isAssigned(parent[0]))
+ {
+ // XOR x y = FALSE, and x assigned, assign(y = assignment(x))
+ assignAndEnqueue(
+ parent[1],
+ getAssignment(parent[0]),
+ prover.xorYFromX(
+ !parentAssignment, getAssignment(parent[0]), parent));
+ }
+ else if (isAssigned(parent[1]))
+ {
+ // XOR x y = FALSE, and y assigned, assign(x = assignment(y))
+ assignAndEnqueue(
+ parent[0],
+ getAssignment(parent[1]),
+ prover.xorXFromY(
+ !parentAssignment, getAssignment(parent[1]), parent));
+ }
+ }
+ break;
+ default: Unhandled();
}
}
-
-void CircuitPropagator::propagateForward(TNode child, bool childAssignment) {
-
+void CircuitPropagator::propagateForward(TNode child, bool childAssignment)
+{
// The assignment we have
- Debug("circuit-prop") << "CircuitPropagator::propagateForward(" << child << ", " << childAssignment << ")" << endl;
+ Debug("circuit-prop") << "CircuitPropagator::propagateForward(" << child
+ << ", " << childAssignment << ")" << endl;
// Get the back any nodes where this is child
const vector<Node>& parents = d_backEdges.find(child)->second;
@@ -207,165 +434,265 @@ void CircuitPropagator::propagateForward(TNode child, bool childAssignment) {
// Go through the parents and see if there is anything to propagate
vector<Node>::const_iterator parent_it = parents.begin();
vector<Node>::const_iterator parent_it_end = parents.end();
- for(; parent_it != parent_it_end && !d_conflict; ++ parent_it) {
+ for (; parent_it != parent_it_end && d_conflict.get().isNull(); ++parent_it)
+ {
// The current parent of the child
TNode parent = *parent_it;
+ Debug("circuit-prop") << "Parent: " << parent << endl;
Assert(expr::hasSubterm(parent, child));
+ ProofCircuitPropagatorForward prover{d_pnm, child, childAssignment, parent};
+
// Forward rules
- switch(parent.getKind()) {
- case kind::AND:
- if (childAssignment) {
- TNode::iterator holdout;
- holdout = find_if (parent.begin(), parent.end(), not1(IsAssignedTo(*this, true)));
- if (holdout == parent.end()) { // all children are assigned TRUE
- // AND ...(x=TRUE)...: if all children now assigned to TRUE, assign(AND = TRUE)
- assignAndEnqueue(parent, true);
- } else if (isAssignedTo(parent, false)) {// the AND is FALSE
- // is the holdout unique ?
- TNode::iterator other = find_if (holdout + 1, parent.end(), not1(IsAssignedTo(*this, true)));
- if (other == parent.end()) { // the holdout is unique
- // AND ...(x=TRUE)...: if all children BUT ONE now assigned to TRUE, and AND == FALSE, assign(last_holdout = FALSE)
- assignAndEnqueue(*holdout, false);
+ switch (parent.getKind())
+ {
+ case kind::AND:
+ if (childAssignment)
+ {
+ TNode::iterator holdout;
+ holdout = find_if(
+ parent.begin(), parent.end(), not1(IsAssignedTo(*this, true)));
+ if (holdout == parent.end())
+ { // all children are assigned TRUE
+ // AND ...(x=TRUE)...: if all children now assigned to TRUE,
+ // assign(AND = TRUE)
+ assignAndEnqueue(parent, true, prover.andAllTrue());
+ }
+ else if (isAssignedTo(parent, false))
+ { // the AND is FALSE
+ // is the holdout unique ?
+ TNode::iterator other = find_if(
+ holdout + 1, parent.end(), not1(IsAssignedTo(*this, true)));
+ if (other == parent.end())
+ { // the holdout is unique
+ // AND ...(x=TRUE)...: if all children BUT ONE now assigned to
+ // TRUE, and AND == FALSE, assign(last_holdout = FALSE)
+ assignAndEnqueue(
+ *holdout, false, prover.andFalse(parent, holdout));
+ }
}
}
- } else {
- // AND ...(x=FALSE)...: assign(AND = FALSE)
- assignAndEnqueue(parent, false);
- }
- break;
- case kind::OR:
- if (childAssignment) {
- // OR ...(x=TRUE)...: assign(OR = TRUE)
- assignAndEnqueue(parent, true);
- } else {
- TNode::iterator holdout;
- holdout = find_if (parent.begin(), parent.end(), not1(IsAssignedTo(*this, false)));
- if (holdout == parent.end()) { // all children are assigned FALSE
- // OR ...(x=FALSE)...: if all children now assigned to FALSE, assign(OR = FALSE)
- assignAndEnqueue(parent, false);
- } else if (isAssignedTo(parent, true)) {// the OR is TRUE
- // is the holdout unique ?
- TNode::iterator other = find_if (holdout + 1, parent.end(), not1(IsAssignedTo(*this, false)));
- if (other == parent.end()) { // the holdout is unique
- // OR ...(x=FALSE)...: if all children BUT ONE now assigned to FALSE, and OR == TRUE, assign(last_holdout = TRUE)
- assignAndEnqueue(*holdout, true);
+ else
+ {
+ // AND ...(x=FALSE)...: assign(AND = FALSE)
+ assignAndEnqueue(parent, false, prover.andOneFalse());
+ }
+ break;
+ case kind::OR:
+ if (childAssignment)
+ {
+ // OR ...(x=TRUE)...: assign(OR = TRUE)
+ assignAndEnqueue(parent, true, prover.orOneTrue());
+ }
+ else
+ {
+ TNode::iterator holdout;
+ holdout = find_if(
+ parent.begin(), parent.end(), not1(IsAssignedTo(*this, false)));
+ if (holdout == parent.end())
+ { // all children are assigned FALSE
+ // OR ...(x=FALSE)...: if all children now assigned to FALSE,
+ // assign(OR = FALSE)
+ assignAndEnqueue(parent, false, prover.orFalse());
+ }
+ else if (isAssignedTo(parent, true))
+ { // the OR is TRUE
+ // is the holdout unique ?
+ TNode::iterator other = find_if(
+ holdout + 1, parent.end(), not1(IsAssignedTo(*this, false)));
+ if (other == parent.end())
+ { // the holdout is unique
+ // OR ...(x=FALSE)...: if all children BUT ONE now assigned to
+ // FALSE, and OR == TRUE, assign(last_holdout = TRUE)
+ assignAndEnqueue(*holdout, true, prover.orTrue(parent, holdout));
+ }
}
}
- }
- break;
-
- case kind::NOT:
- // NOT (x=b): assign(NOT = !b)
- assignAndEnqueue(parent, !childAssignment);
- break;
-
- case kind::ITE:
- if (child == parent[0]) {
- if (childAssignment) {
- if (isAssigned(parent[1])) {
- // ITE (c=TRUE) x y: if x is assigned, assign(ITE = x.assignment)
- assignAndEnqueue(parent, getAssignment(parent[1]));
+ break;
+
+ case kind::NOT:
+ // NOT (x=b): assign(NOT = !b)
+ assignAndEnqueue(
+ parent, !childAssignment, prover.Not(childAssignment, parent));
+ break;
+
+ case kind::ITE:
+ if (child == parent[0])
+ {
+ if (childAssignment)
+ {
+ if (isAssigned(parent[1]))
+ {
+ // ITE (c=TRUE) x y: if x is assigned, assign(ITE = x.assignment)
+ assignAndEnqueue(parent,
+ getAssignment(parent[1]),
+ prover.iteEvalThen(getAssignment(parent[1])));
+ }
}
- } else {
- if (isAssigned(parent[2])) {
- // ITE (c=FALSE) x y: if y is assigned, assign(ITE = y.assignment)
- assignAndEnqueue(parent, getAssignment(parent[2]));
+ else
+ {
+ if (isAssigned(parent[2]))
+ {
+ // ITE (c=FALSE) x y: if y is assigned, assign(ITE = y.assignment)
+ assignAndEnqueue(parent,
+ getAssignment(parent[2]),
+ prover.iteEvalElse(getAssignment(parent[2])));
+ }
}
}
- }
- if (child == parent[1]) {
- if (isAssignedTo(parent[0], true)) {
- // ITE c (x=v) y: if c is assigned and TRUE, assign(ITE = v)
- assignAndEnqueue(parent, childAssignment);
+ if (child == parent[1])
+ {
+ if (isAssignedTo(parent[0], true))
+ {
+ // ITE c (x=v) y: if c is assigned and TRUE, assign(ITE = v)
+ assignAndEnqueue(
+ parent, childAssignment, prover.iteEvalThen(childAssignment));
+ }
}
- }
- if (child == parent[2]) {
- Assert(child == parent[2]);
- if (isAssignedTo(parent[0], false)) {
- // ITE c x (y=v): if c is assigned and FALSE, assign(ITE = v)
- assignAndEnqueue(parent, childAssignment);
+ if (child == parent[2])
+ {
+ Assert(child == parent[2]);
+ if (isAssignedTo(parent[0], false))
+ {
+ // ITE c x (y=v): if c is assigned and FALSE, assign(ITE = v)
+ assignAndEnqueue(
+ parent, childAssignment, prover.iteEvalElse(childAssignment));
+ }
}
- }
- break;
- case kind::EQUAL:
- Assert(parent[0].getType().isBoolean());
- if (isAssigned(parent[0]) && isAssigned(parent[1])) {
- // IFF x y: if x or y is assigned, assign(IFF = (x.assignment <=> y.assignment))
- assignAndEnqueue(parent, getAssignment(parent[0]) == getAssignment(parent[1]));
- } else {
- if (isAssigned(parent)) {
- if (child == parent[0]) {
- if (getAssignment(parent)) {
- // IFF (x = b) y: if IFF is assigned to TRUE, assign(y = b)
- assignAndEnqueue(parent[1], childAssignment);
- } else {
- // IFF (x = b) y: if IFF is assigned to FALSE, assign(y = !b)
- assignAndEnqueue(parent[1], !childAssignment);
+ break;
+ case kind::EQUAL:
+ Assert(parent[0].getType().isBoolean());
+ if (isAssigned(parent[0]) && isAssigned(parent[1]))
+ {
+ // IFF x y: if x and y is assigned, assign(IFF = (x.assignment <=>
+ // y.assignment))
+ assignAndEnqueue(parent,
+ getAssignment(parent[0]) == getAssignment(parent[1]),
+ prover.eqEval(getAssignment(parent[0]),
+ getAssignment(parent[1])));
+ }
+ else
+ {
+ if (isAssigned(parent))
+ {
+ if (child == parent[0])
+ {
+ if (getAssignment(parent))
+ {
+ // IFF (x = b) y: if IFF is assigned to TRUE, assign(y = b)
+ assignAndEnqueue(parent[1],
+ childAssignment,
+ prover.eqYFromX(childAssignment, parent));
+ }
+ else
+ {
+ // IFF (x = b) y: if IFF is assigned to FALSE, assign(y = !b)
+ assignAndEnqueue(parent[1],
+ !childAssignment,
+ prover.neqYFromX(childAssignment, parent));
+ }
}
- } else {
- Assert(child == parent[1]);
- if (getAssignment(parent)) {
- // IFF x y = b: if IFF is assigned to TRUE, assign(x = b)
- assignAndEnqueue(parent[0], childAssignment);
- } else {
- // IFF x y = b y: if IFF is assigned to TRUE, assign(x = !b)
- assignAndEnqueue(parent[0], !childAssignment);
+ else
+ {
+ Assert(child == parent[1]);
+ if (getAssignment(parent))
+ {
+ // IFF x y = b: if IFF is assigned to TRUE, assign(x = b)
+ assignAndEnqueue(parent[0],
+ childAssignment,
+ prover.eqXFromY(childAssignment, parent));
+ }
+ else
+ {
+ // IFF x y = b y: if IFF is assigned to FALSE, assign(x = !b)
+ assignAndEnqueue(parent[0],
+ !childAssignment,
+ prover.neqXFromY(childAssignment, parent));
+ }
}
}
}
- }
- break;
- case kind::IMPLIES:
- if (isAssigned(parent[0]) && isAssigned(parent[1])) {
- // IMPLIES (x=v1) (y=v2): assign(IMPLIES = (!v1 || v2))
- assignAndEnqueue(parent, !getAssignment(parent[0]) || getAssignment(parent[1]));
- } else {
- if (child == parent[0] && childAssignment && isAssignedTo(parent, true)) {
- // IMPLIES (x=TRUE) y [with IMPLIES == TRUE]: assign(y = TRUE)
- assignAndEnqueue(parent[1], true);
- }
- if (child == parent[1] && !childAssignment && isAssignedTo(parent, true)) {
- // IMPLIES x (y=FALSE) [with IMPLIES == TRUE]: assign(x = FALSE)
- assignAndEnqueue(parent[0], false);
- }
- // Note that IMPLIES == FALSE doesn't need any cases here
- // because if that assignment has been done, we've already
- // propagated all the children (in back-propagation).
- }
- break;
- case kind::XOR:
- if (isAssigned(parent)) {
- if (child == parent[0]) {
- // XOR (x=v) y [with XOR assigned], assign(y = (v ^ XOR)
- assignAndEnqueue(parent[1], childAssignment != getAssignment(parent));
- } else {
- Assert(child == parent[1]);
- // XOR x (y=v) [with XOR assigned], assign(x = (v ^ XOR))
- assignAndEnqueue(parent[0], childAssignment != getAssignment(parent));
+ break;
+ case kind::IMPLIES:
+ if (isAssigned(parent[0]) && isAssigned(parent[1]))
+ {
+ // IMPLIES (x=v1) (y=v2): assign(IMPLIES = (!v1 || v2))
+ assignAndEnqueue(
+ parent,
+ !getAssignment(parent[0]) || getAssignment(parent[1]),
+ prover.impliesEval(getAssignment(parent[0]),
+ getAssignment(parent[1])));
}
- }
- if (isAssigned(parent[0]) && isAssigned(parent[1])) {
- assignAndEnqueue(parent, getAssignment(parent[0]) != getAssignment(parent[1]));
- }
- break;
- default:
- Unhandled();
+ else
+ {
+ if (child == parent[0] && childAssignment
+ && isAssignedTo(parent, true))
+ {
+ // IMPLIES (x=TRUE) y [with IMPLIES == TRUE]: assign(y = TRUE)
+ assignAndEnqueue(parent[1], true, prover.impliesYFromX(parent));
+ }
+ if (child == parent[1] && !childAssignment
+ && isAssignedTo(parent, true))
+ {
+ // IMPLIES x (y=FALSE) [with IMPLIES == TRUE]: assign(x = FALSE)
+ assignAndEnqueue(parent[0], false, prover.impliesXFromY(parent));
+ }
+ // Note that IMPLIES == FALSE doesn't need any cases here
+ // because if that assignment has been done, we've already
+ // propagated all the children (in back-propagation).
+ }
+ break;
+ case kind::XOR:
+ if (isAssigned(parent))
+ {
+ if (child == parent[0])
+ {
+ // XOR (x=v) y [with XOR assigned], assign(y = (v ^ XOR)
+ assignAndEnqueue(
+ parent[1],
+ childAssignment != getAssignment(parent),
+ prover.xorYFromX(
+ !getAssignment(parent), childAssignment, parent));
+ }
+ else
+ {
+ Assert(child == parent[1]);
+ // XOR x (y=v) [with XOR assigned], assign(x = (v ^ XOR))
+ assignAndEnqueue(
+ parent[0],
+ childAssignment != getAssignment(parent),
+ prover.xorXFromY(
+ !getAssignment(parent), childAssignment, parent));
+ }
+ }
+ if (isAssigned(parent[0]) && isAssigned(parent[1]))
+ {
+ assignAndEnqueue(parent,
+ getAssignment(parent[0]) != getAssignment(parent[1]),
+ prover.xorEval(getAssignment(parent[0]),
+ getAssignment(parent[1])));
+ }
+ break;
+ default: Unhandled();
}
}
}
-bool CircuitPropagator::propagate() {
-
+TrustNode CircuitPropagator::propagate()
+{
Debug("circuit-prop") << "CircuitPropagator::propagate()" << std::endl;
- for(unsigned i = 0; i < d_propagationQueue.size() && !d_conflict; ++ i) {
-
+ for (unsigned i = 0;
+ i < d_propagationQueue.size() && d_conflict.get().isNull();
+ ++i)
+ {
// The current node we are propagating
TNode current = d_propagationQueue[i];
- Debug("circuit-prop") << "CircuitPropagator::propagate(): processing " << current << std::endl;
+ Debug("circuit-prop") << "CircuitPropagator::propagate(): processing "
+ << current << std::endl;
bool assignment = getAssignment(current);
- Debug("circuit-prop") << "CircuitPropagator::propagate(): assigned to " << (assignment ? "true" : "false") << std::endl;
+ Debug("circuit-prop") << "CircuitPropagator::propagate(): assigned to "
+ << (assignment ? "true" : "false") << std::endl;
// Is this an atom
bool atom = Theory::theoryOf(current) != THEORY_BOOL || current.isVar()
@@ -373,17 +700,52 @@ bool CircuitPropagator::propagate() {
&& (current[0].isVar() && current[1].isVar()));
// If an atom, add to the list for simplification
- if (atom) {
- Debug("circuit-prop") << "CircuitPropagator::propagate(): adding to learned: " << (assignment ? (Node)current : current.notNode()) << std::endl;
- d_learnedLiterals.push_back(assignment ? (Node)current : current.notNode());
+ if (atom)
+ {
+ Debug("circuit-prop")
+ << "CircuitPropagator::propagate(): adding to learned: "
+ << (assignment ? (Node)current : current.notNode()) << std::endl;
+ Node lit = assignment ? Node(current) : current.notNode();
+
+ if (isProofEnabled())
+ {
+ if (d_epg->hasProofFor(lit))
+ {
+ // if we have a parent proof generator that provides proofs of the
+ // inputs to this class, we must use the lazy proof chain
+ ProofGenerator* pg = d_proofInternal.get();
+ if (d_proofExternal != nullptr)
+ {
+ d_proofExternal->addLazyStep(lit, pg);
+ pg = d_proofExternal.get();
+ }
+ TrustNode tlit = TrustNode::mkTrustLemma(lit, pg);
+ d_learnedLiterals.push_back(tlit);
+ }
+ else
+ {
+ Warning() << "CircuitPropagator: Proof is missing for " << lit
+ << std::endl;
+ TrustNode tlit = TrustNode::mkTrustLemma(lit, nullptr);
+ d_learnedLiterals.push_back(tlit);
+ }
+ }
+ else
+ {
+ TrustNode tlit = TrustNode::mkTrustLemma(lit, nullptr);
+ d_learnedLiterals.push_back(tlit);
+ }
+ Trace("circuit-prop") << "Added proof for " << lit << std::endl;
}
// Propagate this value to the children (if not an atom or a constant)
- if (d_backwardPropagation && !atom && !current.isConst()) {
+ if (d_backwardPropagation && !atom && !current.isConst())
+ {
propagateBackward(current, assignment);
}
// Propagate this value to the parents
- if (d_forwardPropagation) {
+ if (d_forwardPropagation)
+ {
propagateForward(current, assignment);
}
}
@@ -392,6 +754,48 @@ bool CircuitPropagator::propagate() {
return d_conflict;
}
-}/* CVC4::theory::booleans namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
+void CircuitPropagator::setProof(ProofNodeManager* pnm,
+ context::Context* ctx,
+ ProofGenerator* defParent)
+{
+ d_pnm = pnm;
+ d_epg.reset(new EagerProofGenerator(pnm, ctx));
+ d_proofInternal.reset(
+ new LazyCDProofChain(pnm, true, ctx, d_epg.get(), true));
+ if (defParent != nullptr)
+ {
+ // If we provide a parent proof generator (defParent), we want the ASSUME
+ // leafs of proofs provided by this class to call the getProofFor method on
+ // the parent. To do this, we use a LazyCDProofChain.
+ d_proofExternal.reset(
+ new LazyCDProofChain(pnm, true, ctx, defParent, false));
+ }
+}
+
+bool CircuitPropagator::isProofEnabled() const
+{
+ return d_proofInternal != nullptr;
+}
+
+void CircuitPropagator::addProof(TNode f, std::shared_ptr<ProofNode> pf)
+{
+ if (isProofEnabled())
+ {
+ if (!d_epg->hasProofFor(f))
+ {
+ Trace("circuit-prop") << "Adding proof for " << f << std::endl
+ << "\t" << *pf << std::endl;
+ d_epg->setProofFor(f, std::move(pf));
+ }
+ else
+ {
+ auto prf = d_epg->getProofFor(f);
+ Trace("circuit-prop") << "Ignoring proof, we already have" << std::endl
+ << "\t" << *prf << std::endl;
+ }
+ }
+}
+
+} // namespace booleans
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/booleans/circuit_propagator.h b/src/theory/booleans/circuit_propagator.h
index f0a0b3c3f..4c7c2d124 100644
--- a/src/theory/booleans/circuit_propagator.h
+++ b/src/theory/booleans/circuit_propagator.h
@@ -5,7 +5,7 @@
** Aina Niemetz, Morgan Deters, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,6 +20,7 @@
#define CVC4__THEORY__BOOLEANS__CIRCUIT_PROPAGATOR_H
#include <functional>
+#include <memory>
#include <unordered_map>
#include <vector>
@@ -27,8 +28,13 @@
#include "context/cdhashset.h"
#include "context/cdo.h"
#include "context/context.h"
+#include "expr/lazy_proof_chain.h"
#include "expr/node.h"
+#include "expr/proof_generator.h"
+#include "expr/proof_node.h"
+#include "theory/eager_proof_generator.h"
#include "theory/theory.h"
+#include "theory/trust_node.h"
#include "util/hash.h"
namespace CVC4 {
@@ -63,22 +69,7 @@ class CircuitPropagator
/**
* Construct a new CircuitPropagator.
*/
- CircuitPropagator(bool enableForward = true, bool enableBackward = true)
- : d_context(),
- d_propagationQueue(),
- d_propagationQueueClearer(&d_context, d_propagationQueue),
- d_conflict(&d_context, false),
- d_learnedLiterals(),
- d_learnedLiteralClearer(&d_context, d_learnedLiterals),
- d_backEdges(),
- d_backEdgesClearer(&d_context, d_backEdges),
- d_seen(&d_context),
- d_state(&d_context),
- d_forwardPropagation(enableForward),
- d_backwardPropagation(enableBackward),
- d_needsFinish(false)
- {
- }
+ CircuitPropagator(bool enableForward = true, bool enableBackward = true);
/** Get Node assignment in circuit. Assert-fails if Node is unassigned. */
bool getAssignment(TNode n) const
@@ -95,9 +86,10 @@ class CircuitPropagator
bool getNeedsFinish() { return d_needsFinish; }
- std::vector<Node>& getLearnedLiterals() { return d_learnedLiterals; }
+ std::vector<TrustNode>& getLearnedLiterals() { return d_learnedLiterals; }
- void finish() { d_context.pop(); }
+ /** Finish the computation and pop the internal context */
+ void finish();
/** Assert for propagation */
void assertTrue(TNode assertion);
@@ -107,9 +99,10 @@ class CircuitPropagator
* discovered by the propagator are put in the substitutions vector used in
* construction.
*
- * @return true iff conflict found
+ * @return a trust node encapsulating the proof for a conflict as a lemma that
+ * proves false, or the null trust node otherwise
*/
- bool propagate() CVC4_WARN_UNUSED_RESULT;
+ TrustNode propagate() CVC4_WARN_UNUSED_RESULT;
/**
* Get the back edges of this circuit.
@@ -142,6 +135,15 @@ class CircuitPropagator
if (!value && ((*i).second == ASSIGNED_TO_FALSE)) return true;
return false;
}
+ /**
+ * Set proof node manager, context and parent proof generator.
+ *
+ * If parent is non-null, then it is responsible for the proofs provided
+ * to this class.
+ */
+ void setProof(ProofNodeManager* pnm,
+ context::Context* ctx,
+ ProofGenerator* defParent);
private:
/** A context-notify object that clears out stale data. */
@@ -206,40 +208,15 @@ class CircuitPropagator
* Assign Node in circuit with the value and add it to the queue; note
* conflicts.
*/
- void assignAndEnqueue(TNode n, bool value)
- {
- Trace("circuit-prop") << "CircuitPropagator::assign(" << n << ", "
- << (value ? "true" : "false") << ")" << std::endl;
-
- if (n.getKind() == kind::CONST_BOOLEAN)
- {
- // Assigning a constant to the opposite value is dumb
- if (value != n.getConst<bool>())
- {
- d_conflict = true;
- return;
- }
- }
-
- // Get the current assignment
- AssignmentStatus state = d_state[n];
+ void assignAndEnqueue(TNode n,
+ bool value,
+ std::shared_ptr<ProofNode> proof = nullptr);
- if (state != UNASSIGNED)
- {
- // If the node is already assigned we might have a conflict
- if (value != (state == ASSIGNED_TO_TRUE))
- {
- d_conflict = true;
- }
- }
- else
- {
- // If unassigned, mark it as assigned
- d_state[n] = value ? ASSIGNED_TO_TRUE : ASSIGNED_TO_FALSE;
- // Add for further propagation
- d_propagationQueue.push_back(n);
- }
- }
+ /**
+ * Store a conflict for the case that we have derived both n and n.negate()
+ * to be true.
+ */
+ void makeConflict(Node n);
/**
* Compute the map from nodes to the nodes that use it.
@@ -258,6 +235,9 @@ class CircuitPropagator
*/
void propagateBackward(TNode parent, bool assignment);
+ /** Are proofs enabled? */
+ bool isProofEnabled() const;
+
context::Context d_context;
/** The propagation queue */
@@ -269,18 +249,18 @@ class CircuitPropagator
* but this keeps us safe in case there's still some rubbish around
* on the queue.
*/
- DataClearer<std::vector<TNode> > d_propagationQueueClearer;
+ DataClearer<std::vector<TNode>> d_propagationQueueClearer;
/** Are we in conflict? */
- context::CDO<bool> d_conflict;
+ context::CDO<TrustNode> d_conflict;
/** Map of substitutions */
- std::vector<Node> d_learnedLiterals;
+ std::vector<TrustNode> d_learnedLiterals;
/**
* Similar data clearer for learned literals.
*/
- DataClearer<std::vector<Node>> d_learnedLiteralClearer;
+ DataClearer<std::vector<TrustNode>> d_learnedLiteralClearer;
/**
* Back edges from nodes to where they are used.
@@ -307,6 +287,17 @@ class CircuitPropagator
/* Does the current state require a call to finish()? */
bool d_needsFinish;
+ /** Adds a new proof for f, or drops it if we already have a proof */
+ void addProof(TNode f, std::shared_ptr<ProofNode> pf);
+
+ /** A pointer to the proof manager */
+ ProofNodeManager* d_pnm;
+ /** Eager proof generator that actually stores the proofs */
+ std::unique_ptr<EagerProofGenerator> d_epg;
+ /** Connects the proofs to subproofs internally */
+ std::unique_ptr<LazyCDProofChain> d_proofInternal;
+ /** Connects the proofs to assumptions externally */
+ std::unique_ptr<LazyCDProofChain> d_proofExternal;
}; /* class CircuitPropagator */
} // namespace booleans
diff --git a/src/theory/booleans/proof_checker.cpp b/src/theory/booleans/proof_checker.cpp
index 6a8244ce0..3eb523ab5 100644
--- a/src/theory/booleans/proof_checker.cpp
+++ b/src/theory/booleans/proof_checker.cpp
@@ -2,10 +2,10 @@
/*! \file proof_checker.cpp
** \verbatim
** Top contributors (to current version):
- ** Haniel Barbosa
+ ** Haniel Barbosa, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -13,6 +13,8 @@
**/
#include "theory/booleans/proof_checker.h"
+#include "expr/skolem_manager.h"
+#include "theory/rewriter.h"
namespace CVC4 {
namespace theory {
@@ -21,7 +23,14 @@ namespace booleans {
void BoolProofRuleChecker::registerTo(ProofChecker* pc)
{
pc->registerChecker(PfRule::SPLIT, this);
+ pc->registerChecker(PfRule::RESOLUTION, this);
+ pc->registerChecker(PfRule::CHAIN_RESOLUTION, this);
+ pc->registerChecker(PfRule::FACTORING, this);
+ pc->registerChecker(PfRule::REORDERING, this);
pc->registerChecker(PfRule::EQ_RESOLVE, this);
+ pc->registerChecker(PfRule::MODUS_PONENS, this);
+ pc->registerChecker(PfRule::NOT_NOT_ELIM, this);
+ pc->registerChecker(PfRule::CONTRA, this);
pc->registerChecker(PfRule::AND_ELIM, this);
pc->registerChecker(PfRule::AND_INTRO, this);
pc->registerChecker(PfRule::NOT_OR_ELIM, this);
@@ -68,6 +77,170 @@ Node BoolProofRuleChecker::checkInternal(PfRule id,
const std::vector<Node>& children,
const std::vector<Node>& args)
{
+ if (id == PfRule::RESOLUTION)
+ {
+ Assert(children.size() == 2);
+ Assert(args.size() == 2);
+ NodeManager* nm = NodeManager::currentNM();
+ std::vector<Node> disjuncts;
+ Node pivots[2];
+ if (args[0] == nm->mkConst(true))
+ {
+ pivots[0] = args[1];
+ pivots[1] = args[1].notNode();
+ }
+ else
+ {
+ Assert(args[0] == nm->mkConst(false));
+ pivots[0] = args[1].notNode();
+ pivots[1] = args[1];
+ }
+ for (unsigned i = 0; i < 2; ++i)
+ {
+ // determine whether the clause is unit for effects of resolution, which
+ // is the case if it's not an OR node or it is an OR node but it is equal
+ // to the pivot
+ std::vector<Node> lits;
+ if (children[i].getKind() == kind::OR && pivots[i] != children[i])
+ {
+ lits.insert(lits.end(), children[i].begin(), children[i].end());
+ }
+ else
+ {
+ lits.push_back(children[i]);
+ }
+ for (unsigned j = 0, size = lits.size(); j < size; ++j)
+ {
+ if (pivots[i] != lits[j])
+ {
+ disjuncts.push_back(lits[j]);
+ }
+ else
+ {
+ // just eliminate first occurrence
+ pivots[i] = Node::null();
+ }
+ }
+ }
+ return disjuncts.empty()
+ ? nm->mkConst(false)
+ : disjuncts.size() == 1 ? disjuncts[0]
+ : nm->mkNode(kind::OR, disjuncts);
+ }
+ if (id == PfRule::FACTORING)
+ {
+ Assert(children.size() == 1);
+ Assert(args.empty());
+ if (children[0].getKind() != kind::OR)
+ {
+ return Node::null();
+ }
+ // remove duplicates while keeping the order of children
+ std::unordered_set<TNode, TNodeHashFunction> clauseSet;
+ std::vector<Node> disjuncts;
+ unsigned size = children[0].getNumChildren();
+ for (unsigned i = 0; i < size; ++i)
+ {
+ if (clauseSet.count(children[0][i]))
+ {
+ continue;
+ }
+ disjuncts.push_back(children[0][i]);
+ clauseSet.insert(children[0][i]);
+ }
+ if (disjuncts.size() == size)
+ {
+ return Node::null();
+ }
+ NodeManager* nm = NodeManager::currentNM();
+ return disjuncts.empty()
+ ? nm->mkConst<bool>(false)
+ : disjuncts.size() == 1 ? disjuncts[0]
+ : nm->mkNode(kind::OR, disjuncts);
+ }
+ if (id == PfRule::REORDERING)
+ {
+ Assert(children.size() == 1);
+ Assert(args.size() == 1);
+ std::unordered_set<Node, NodeHashFunction> clauseSet1, clauseSet2;
+ if (children[0].getKind() == kind::OR)
+ {
+ clauseSet1.insert(children[0].begin(), children[0].end());
+ }
+ else
+ {
+ clauseSet1.insert(children[0]);
+ }
+ if (args[0].getKind() == kind::OR)
+ {
+ clauseSet2.insert(args[0].begin(), args[0].end());
+ }
+ else
+ {
+ clauseSet2.insert(args[0]);
+ }
+ if (clauseSet1 != clauseSet2)
+ {
+ Trace("bool-pfcheck") << id << ": clause set1: " << clauseSet1 << "\n"
+ << id << ": clause set2: " << clauseSet2 << "\n";
+ return Node::null();
+ }
+ return args[0];
+ }
+ if (id == PfRule::CHAIN_RESOLUTION)
+ {
+ Assert(children.size() > 1);
+ Assert(args.size() == children.size() - 1);
+ Trace("bool-pfcheck") << "chain_res:\n" << push;
+ std::vector<Node> clauseNodes;
+ for (unsigned i = 0, childrenSize = children.size(); i < childrenSize; ++i)
+ {
+ std::unordered_set<Node, NodeHashFunction> elim;
+ // literals to be removed from "first" clause
+ if (i < childrenSize - 1)
+ {
+ elim.insert(args.begin() + i, args.end());
+ }
+ // literal to be removed from "second" clause. They will be negated
+ if (i > 0)
+ {
+ elim.insert(args[i - 1].negate());
+ }
+ Trace("bool-pfcheck") << i << ": elimination set: " << elim << "\n";
+ // only add to conclusion nodes that are not in elimination set. First get
+ // the nodes.
+ //
+ // Since unit clauses can also be OR nodes, we rely on the invariant that
+ // non-unit clauses will not occur themselves in their elimination sets.
+ // If they do then they must be unit.
+ std::vector<Node> lits;
+ if (children[i].getKind() == kind::OR && elim.count(children[i]) == 0)
+ {
+ lits.insert(lits.end(), children[i].begin(), children[i].end());
+ }
+ else
+ {
+ lits.push_back(children[i]);
+ }
+ Trace("bool-pfcheck") << i << ": clause lits: " << lits << "\n";
+ std::vector<Node> added;
+ for (unsigned j = 0, size = lits.size(); j < size; ++j)
+ {
+ if (elim.count(lits[j]) == 0)
+ {
+ clauseNodes.push_back(lits[j]);
+ added.push_back(lits[j]);
+ }
+ }
+ Trace("bool-pfcheck") << i << ": added lits: " << added << "\n\n";
+ }
+ Trace("bool-pfcheck") << "clause: " << clauseNodes << "\n" << pop;
+ NodeManager* nm = NodeManager::currentNM();
+ return clauseNodes.empty()
+ ? nm->mkConst<bool>(false)
+ : clauseNodes.size() == 1 ? clauseNodes[0]
+ : nm->mkNode(kind::OR, clauseNodes);
+ }
if (id == PfRule::SPLIT)
{
Assert(children.empty());
@@ -75,6 +248,15 @@ Node BoolProofRuleChecker::checkInternal(PfRule id,
return NodeManager::currentNM()->mkNode(
kind::OR, args[0], args[0].notNode());
}
+ if (id == PfRule::CONTRA)
+ {
+ Assert(children.size() == 2);
+ if (children[1].getKind() == Kind::NOT && children[0] == children[1][0])
+ {
+ return NodeManager::currentNM()->mkConst(false);
+ }
+ return Node::null();
+ }
if (id == PfRule::EQ_RESOLVE)
{
Assert(children.size() == 2);
@@ -85,6 +267,26 @@ Node BoolProofRuleChecker::checkInternal(PfRule id,
}
return children[1][1];
}
+ if (id == PfRule::MODUS_PONENS)
+ {
+ Assert(children.size() == 2);
+ Assert(args.empty());
+ if (children[1].getKind() != kind::IMPLIES || children[0] != children[1][0])
+ {
+ return Node::null();
+ }
+ return children[1][1];
+ }
+ if (id == PfRule::NOT_NOT_ELIM)
+ {
+ Assert(children.size() == 1);
+ Assert(args.empty());
+ if (children[0].getKind() != kind::NOT || children[0][0].getKind() != kind::NOT)
+ {
+ return Node::null();
+ }
+ return children[0][0][0];
+ }
// natural deduction rules
if (id == PfRule::AND_ELIM)
{
diff --git a/src/theory/booleans/proof_checker.h b/src/theory/booleans/proof_checker.h
index 8258130fb..88585755a 100644
--- a/src/theory/booleans/proof_checker.h
+++ b/src/theory/booleans/proof_checker.h
@@ -5,7 +5,7 @@
** Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/booleans/proof_circuit_propagator.cpp b/src/theory/booleans/proof_circuit_propagator.cpp
new file mode 100644
index 000000000..bc4e0c8ae
--- /dev/null
+++ b/src/theory/booleans/proof_circuit_propagator.cpp
@@ -0,0 +1,587 @@
+/********************* */
+/*! \file proof_circuit_propagator.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Proofs for the non-clausal circuit propagator.
+ **
+ ** Proofs for the non-clausal circuit propagator.
+ **/
+
+#include "theory/booleans/proof_circuit_propagator.h"
+
+#include "expr/proof_node_manager.h"
+
+namespace CVC4 {
+namespace theory {
+namespace booleans {
+
+namespace {
+
+/** Shorthand to create a Node from a constant number */
+template <typename T>
+Node mkRat(T val)
+{
+ return NodeManager::currentNM()->mkConst<Rational>(val);
+}
+
+/**
+ * Collect all children from parent except for one particular child (the
+ * "holdout"). The holdout is given as iterator, and should be an iterator into
+ * the [parent.begin(),parent.end()] range.
+ */
+inline std::vector<Node> collectButHoldout(TNode parent,
+ TNode::iterator holdout)
+{
+ std::vector<Node> lits;
+ for (TNode::iterator i = parent.begin(), i_end = parent.end(); i != i_end;
+ ++i)
+ {
+ if (i != holdout)
+ {
+ lits.emplace_back(*i);
+ }
+ }
+ return lits;
+}
+
+} // namespace
+
+ProofCircuitPropagator::ProofCircuitPropagator(ProofNodeManager* pnm)
+ : d_pnm(pnm)
+{
+}
+
+bool ProofCircuitPropagator::disabled() const { return d_pnm == nullptr; }
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::assume(Node n)
+{
+ return d_pnm->mkAssume(n);
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::conflict(
+ const std::shared_ptr<ProofNode>& a, const std::shared_ptr<ProofNode>& b)
+{
+ if (a->getResult().notNode() == b->getResult())
+ {
+ return mkProof(PfRule::CONTRA, {a, b});
+ }
+ Assert(a->getResult() == b->getResult().notNode());
+ return mkProof(PfRule::CONTRA, {b, a});
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::andFalse(
+ Node parent, TNode::iterator holdout)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ return mkNot(
+ mkCResolution(mkProof(PfRule::NOT_AND, {assume(parent.notNode())}),
+ collectButHoldout(parent, holdout),
+ false));
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::orTrue(
+ Node parent, TNode::iterator holdout)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ return mkCResolution(
+ assume(parent), collectButHoldout(parent, holdout), true);
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::Not(bool negate, Node parent)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ return mkNot(assume(negate ? Node(parent[0]) : parent));
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::impliesXFromY(Node parent)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ return mkNot(mkResolution(
+ mkProof(PfRule::IMPLIES_ELIM, {assume(parent)}), parent[1], true));
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::impliesYFromX(Node parent)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ return mkResolution(
+ mkProof(PfRule::IMPLIES_ELIM, {assume(parent)}), parent[0], false);
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::eqXFromY(bool y, Node parent)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ if (y)
+ {
+ return mkProof(
+ PfRule::EQ_RESOLVE,
+ {assume(parent[1]), mkProof(PfRule::SYMM, {assume(parent)})});
+ }
+ return mkNot(mkResolution(
+ mkProof(PfRule::EQUIV_ELIM1, {assume(parent)}), parent[1], true));
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::eqYFromX(bool x, Node parent)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ if (x)
+ {
+ return mkProof(PfRule::EQ_RESOLVE, {assume(parent[0]), assume(parent)});
+ }
+ return mkNot(mkResolution(
+ mkProof(PfRule::EQUIV_ELIM2, {assume(parent)}), parent[0], true));
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::neqXFromY(bool y,
+ Node parent)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ return mkResolution(
+ mkProof(y ? PfRule::NOT_EQUIV_ELIM2 : PfRule::NOT_EQUIV_ELIM1,
+ {assume(parent.notNode())}),
+ parent[1],
+ !y);
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::neqYFromX(bool x,
+ Node parent)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ return mkResolution(
+ mkProof(x ? PfRule::NOT_EQUIV_ELIM2 : PfRule::NOT_EQUIV_ELIM1,
+ {assume(parent.notNode())}),
+ parent[0],
+ !x);
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::xorXFromY(bool negated,
+ bool y,
+ Node parent)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ if (y)
+ {
+ return mkNot(mkResolution(
+ mkProof(negated ? PfRule::NOT_XOR_ELIM1 : PfRule::XOR_ELIM2,
+ {assume(negated ? parent.notNode() : Node(parent))}),
+ parent[1],
+ false));
+ }
+ return mkResolution(
+ mkProof(negated ? PfRule::NOT_XOR_ELIM2 : PfRule::XOR_ELIM1,
+ {assume(negated ? parent.notNode() : Node(parent))}),
+ parent[1],
+ true);
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::xorYFromX(bool negated,
+ bool x,
+ Node parent)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ if (x)
+ {
+ return mkResolution(
+ mkProof(negated ? PfRule::NOT_XOR_ELIM2 : PfRule::XOR_ELIM2,
+ {assume(negated ? parent.notNode() : Node(parent))}),
+ parent[0],
+ false);
+ }
+ return mkNot(
+ mkResolution(mkProof(negated ? PfRule::NOT_XOR_ELIM1 : PfRule::XOR_ELIM1,
+ {assume(negated ? parent.notNode() : Node(parent))}),
+ parent[0],
+ true));
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::mkProof(
+ PfRule rule,
+ const std::vector<std::shared_ptr<ProofNode>>& children,
+ const std::vector<Node>& args)
+{
+ if (Trace.isOn("circuit-prop"))
+ {
+ std::stringstream ss;
+ ss << "Constructing (" << rule;
+ for (const auto& c : children)
+ {
+ ss << " " << *c;
+ }
+ if (!args.empty())
+ {
+ ss << " :args";
+ for (const auto& a : args)
+ {
+ ss << " " << a;
+ }
+ }
+ ss << ")";
+ Trace("circuit-prop") << ss.str() << std::endl;
+ }
+ return d_pnm->mkNode(rule, children, args);
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::mkCResolution(
+ const std::shared_ptr<ProofNode>& clause,
+ const std::vector<Node>& lits,
+ const std::vector<bool>& polarity)
+{
+ auto* nm = NodeManager::currentNM();
+ std::vector<std::shared_ptr<ProofNode>> children = {clause};
+ std::vector<Node> args;
+ Assert(lits.size() == polarity.size());
+ for (std::size_t i = 0, n = lits.size(); i < n; ++i)
+ {
+ bool pol = polarity[i];
+ Node lit = lits[i];
+ if (polarity[i])
+ {
+ if (lit.getKind() == Kind::NOT)
+ {
+ lit = lit[0];
+ pol = !pol;
+ children.emplace_back(assume(lit));
+ }
+ else
+ {
+ children.emplace_back(assume(lit.notNode()));
+ }
+ }
+ else
+ {
+ children.emplace_back(assume(lit));
+ }
+ args.emplace_back(nm->mkConst(pol));
+ args.emplace_back(lit);
+ }
+ return mkProof(PfRule::CHAIN_RESOLUTION, children, args);
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::mkCResolution(
+ const std::shared_ptr<ProofNode>& clause,
+ const std::vector<Node>& lits,
+ bool polarity)
+{
+ return mkCResolution(clause, lits, std::vector<bool>(lits.size(), polarity));
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::mkResolution(
+ const std::shared_ptr<ProofNode>& clause, const Node& lit, bool polarity)
+{
+ auto* nm = NodeManager::currentNM();
+ if (polarity)
+ {
+ if (lit.getKind() == Kind::NOT)
+ {
+ return mkProof(PfRule::RESOLUTION,
+ {clause, assume(lit[0])},
+ {nm->mkConst(false), lit[0]});
+ }
+ return mkProof(PfRule::RESOLUTION,
+ {clause, assume(lit.notNode())},
+ {nm->mkConst(true), lit});
+ }
+ return mkProof(
+ PfRule::RESOLUTION, {clause, assume(lit)}, {nm->mkConst(false), lit});
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagator::mkNot(
+ const std::shared_ptr<ProofNode>& n)
+{
+ Node m = n->getResult();
+ if (m.getKind() == Kind::NOT && m[0].getKind() == Kind::NOT)
+ {
+ return mkProof(PfRule::NOT_NOT_ELIM, {n});
+ }
+ return n;
+}
+
+ProofCircuitPropagatorBackward::ProofCircuitPropagatorBackward(
+ ProofNodeManager* pnm, TNode parent, bool parentAssignment)
+ : ProofCircuitPropagator(pnm),
+ d_parent(parent),
+ d_parentAssignment(parentAssignment)
+{
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagatorBackward::andTrue(
+ TNode::iterator i)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ return mkProof(
+ PfRule::AND_ELIM, {assume(d_parent)}, {mkRat(i - d_parent.begin())});
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagatorBackward::orFalse(
+ TNode::iterator i)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ return mkNot(mkProof(PfRule::NOT_OR_ELIM,
+ {assume(d_parent.notNode())},
+ {mkRat(i - d_parent.begin())}));
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagatorBackward::iteC(bool c)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ if (d_parentAssignment)
+ {
+ return mkResolution(
+ mkProof(c ? PfRule::ITE_ELIM1 : PfRule::ITE_ELIM2, {assume(d_parent)}),
+ d_parent[0],
+ !c);
+ }
+ return mkResolution(mkProof(c ? PfRule::NOT_ITE_ELIM1 : PfRule::NOT_ITE_ELIM2,
+ {assume(d_parent.notNode())}),
+ d_parent[0],
+ !c);
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagatorBackward::iteIsCase(unsigned c)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ if (d_parentAssignment)
+ {
+ return mkResolution(
+ mkProof(PfRule::ITE_ELIM2, {assume(d_parent)}), d_parent[c + 1], false);
+ }
+ return mkResolution(
+ mkProof(PfRule::NOT_ITE_ELIM2, {assume(d_parent.notNode())}),
+ d_parent[c + 1],
+ false);
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagatorBackward::impliesNegX()
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ return mkNot(
+ mkProof(PfRule::NOT_IMPLIES_ELIM1, {assume(d_parent.notNode())}));
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagatorBackward::impliesNegY()
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ return mkNot(
+ mkProof(PfRule::NOT_IMPLIES_ELIM2, {assume(d_parent.notNode())}));
+}
+
+ProofCircuitPropagatorForward::ProofCircuitPropagatorForward(
+ ProofNodeManager* pnm, Node child, bool childAssignment, Node parent)
+ : ProofCircuitPropagator{pnm},
+ d_child(child),
+ d_childAssignment(childAssignment),
+ d_parent(parent)
+{
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagatorForward::andAllTrue()
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ std::vector<std::shared_ptr<ProofNode>> children;
+ for (const auto& child : d_parent)
+ {
+ children.emplace_back(assume(child));
+ }
+ return mkProof(PfRule::AND_INTRO, children);
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagatorForward::andOneFalse()
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ auto it = std::find(d_parent.begin(), d_parent.end(), d_child);
+ return mkResolution(
+ mkProof(
+ PfRule::CNF_AND_POS, {}, {d_parent, mkRat(it - d_parent.begin())}),
+ d_child,
+ true);
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagatorForward::orOneTrue()
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ auto it = std::find(d_parent.begin(), d_parent.end(), d_child);
+ return mkNot(mkResolution(
+ mkProof(PfRule::CNF_OR_NEG, {}, {d_parent, mkRat(it - d_parent.begin())}),
+ d_child,
+ false));
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagatorForward::orFalse()
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ std::vector<Node> children(d_parent.begin(), d_parent.end());
+ return mkCResolution(
+ mkProof(PfRule::CNF_OR_POS, {}, {d_parent}), children, true);
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagatorForward::iteEvalThen(bool x)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ return mkCResolution(
+ mkProof(x ? PfRule::CNF_ITE_NEG1 : PfRule::CNF_ITE_POS1, {}, {d_parent}),
+ {d_parent[0], d_parent[1]},
+ {false, !x});
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagatorForward::iteEvalElse(bool y)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ return mkCResolution(
+ mkProof(y ? PfRule::CNF_ITE_NEG2 : PfRule::CNF_ITE_POS2, {}, {d_parent}),
+ {d_parent[0], d_parent[2]},
+ {true, !y});
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagatorForward::eqEval(bool x, bool y)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ if (x == y)
+ {
+ return mkCResolution(
+ mkProof(x ? PfRule::CNF_EQUIV_NEG2 : PfRule::CNF_EQUIV_NEG1,
+ {},
+ {d_parent}),
+ {d_parent[0], d_parent[1]},
+ {!x, !y});
+ }
+ return mkCResolution(
+ mkProof(
+ x ? PfRule::CNF_EQUIV_POS1 : PfRule::CNF_EQUIV_POS2, {}, {d_parent}),
+ {d_parent[0], d_parent[1]},
+ {!x, !y});
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagatorForward::impliesEval(
+ bool premise, bool conclusion)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ if (!premise)
+ {
+ return mkResolution(
+ mkProof(PfRule::CNF_IMPLIES_NEG1, {}, {d_parent}), d_parent[0], true);
+ }
+ if (conclusion)
+ {
+ return mkResolution(
+ mkProof(PfRule::CNF_IMPLIES_NEG2, {}, {d_parent}), d_parent[1], false);
+ }
+ return mkCResolution(mkProof(PfRule::CNF_IMPLIES_POS, {}, {d_parent}),
+ {d_parent[0], d_parent[1]},
+ {false, true});
+}
+
+std::shared_ptr<ProofNode> ProofCircuitPropagatorForward::xorEval(bool x,
+ bool y)
+{
+ if (disabled())
+ {
+ return nullptr;
+ }
+ if (x && y)
+ {
+ return mkCResolution(mkProof(PfRule::CNF_XOR_POS2, {}, {d_parent}),
+ {d_parent[0], d_parent[1]},
+ {false, false});
+ }
+ else if (x && !y)
+ {
+ return mkCResolution(mkProof(PfRule::CNF_XOR_NEG1, {}, {d_parent}),
+ {d_parent[0], d_parent[1]},
+ {false, true});
+ }
+ else if (!x && y)
+ {
+ return mkCResolution(mkProof(PfRule::CNF_XOR_NEG2, {}, {d_parent}),
+ {d_parent[0], d_parent[1]},
+ {true, false});
+ }
+ Assert(!x && !y);
+ return mkCResolution(mkProof(PfRule::CNF_XOR_POS1, {}, {d_parent}),
+ {d_parent[0], d_parent[1]},
+ {true, true});
+}
+
+} // namespace booleans
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/booleans/proof_circuit_propagator.h b/src/theory/booleans/proof_circuit_propagator.h
new file mode 100644
index 000000000..cc0aaad36
--- /dev/null
+++ b/src/theory/booleans/proof_circuit_propagator.h
@@ -0,0 +1,213 @@
+/********************* */
+/*! \file proof_circuit_propagator.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Proofs for the non-clausal circuit propagator.
+ **
+ ** Proofs for the non-clausal circuit propagator.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__BOOLEANS__PROOF_CIRCUIT_PROPAGATOR_H
+#define CVC4__THEORY__BOOLEANS__PROOF_CIRCUIT_PROPAGATOR_H
+
+#include <memory>
+
+#include "expr/node.h"
+#include "expr/proof_node.h"
+
+namespace CVC4 {
+namespace theory {
+namespace booleans {
+
+/**
+ * Base class for for CircuitPropagatorProofs.
+ * This class collects common functionality for proofs of backward and forward
+ * propagation.
+ */
+class ProofCircuitPropagator
+{
+ public:
+ ProofCircuitPropagator(ProofNodeManager* pnm);
+
+ /** Assuming the given node */
+ std::shared_ptr<ProofNode> assume(Node n);
+ /** Apply CONTRA rule. Takes care of switching a and b if necessary */
+ std::shared_ptr<ProofNode> conflict(const std::shared_ptr<ProofNode>& a,
+ const std::shared_ptr<ProofNode>& b);
+
+ /** (and true ... holdout true ...) --> holdout */
+ std::shared_ptr<ProofNode> andFalse(Node parent, TNode::iterator holdout);
+
+ /** (or false ... holdout false ...) -> holdout */
+ std::shared_ptr<ProofNode> orTrue(Node parent, TNode::iterator holdout);
+
+ /** (not x) is true --> x is false (and vice versa) */
+ std::shared_ptr<ProofNode> Not(bool negate, Node parent);
+
+ /** (=> X false) --> (not X) */
+ std::shared_ptr<ProofNode> impliesXFromY(Node parent);
+ /** (=> true Y) --> Y */
+ std::shared_ptr<ProofNode> impliesYFromX(Node parent);
+
+ /** Derive X from (= X Y) */
+ std::shared_ptr<ProofNode> eqXFromY(bool y, Node parent);
+ /** Derive Y from (= X Y) */
+ std::shared_ptr<ProofNode> eqYFromX(bool x, Node parent);
+ /** Derive X from (not (= X Y)) */
+ std::shared_ptr<ProofNode> neqXFromY(bool y, Node parent);
+ /** Derive Y from (not (= X Y)) */
+ std::shared_ptr<ProofNode> neqYFromX(bool x, Node parent);
+
+ /**
+ * Uses (xor X Y) to derive the value of X.
+ * (xor X false) --> X
+ * (xor X true) --> (not X)
+ * (not (xor X false)) --> (not X)
+ * (not (xor X true)) --> X
+ */
+ std::shared_ptr<ProofNode> xorXFromY(bool negated, bool y, Node parent);
+ /**
+ * Uses (xor X Y) to derive the value of Y.
+ * (xor false Y) --> Y
+ * (xor true Y) --> (not Y)
+ * (not (xor false Y)) --> (not Y)
+ * (not (xor true Y)) --> Y
+ */
+ std::shared_ptr<ProofNode> xorYFromX(bool negated, bool x, Node parent);
+
+ protected:
+ /** Shorthand to check whether proof generation is disabled */
+ bool disabled() const;
+
+ /** Construct proof using the given rule, children and args */
+ std::shared_ptr<ProofNode> mkProof(
+ PfRule rule,
+ const std::vector<std::shared_ptr<ProofNode>>& children,
+ const std::vector<Node>& args = {});
+ /**
+ * Apply CHAIN_RESOLUTION rule.
+ * Constructs the args from the given literals and polarities (called ids in
+ * the proof rule). Automatically adds the clauses to resolve with as
+ * assumptions, depending on their polarity.
+ */
+ std::shared_ptr<ProofNode> mkCResolution(
+ const std::shared_ptr<ProofNode>& clause,
+ const std::vector<Node>& lits,
+ const std::vector<bool>& polarity);
+ /** Shorthand for mkCResolution(clause, lits, {polarity, ...}) */
+ std::shared_ptr<ProofNode> mkCResolution(
+ const std::shared_ptr<ProofNode>& clause,
+ const std::vector<Node>& lits,
+ bool polarity);
+ /** Apply RESOLUTION rule */
+ std::shared_ptr<ProofNode> mkResolution(
+ const std::shared_ptr<ProofNode>& clause, const Node& lit, bool polarity);
+ /** Apply NOT_NOT_ELIM rule if n.getResult() is a nested negation */
+ std::shared_ptr<ProofNode> mkNot(const std::shared_ptr<ProofNode>& n);
+
+ /** The proof node manager */
+ ProofNodeManager* d_pnm;
+};
+
+/**
+ * Proof generator for backward propagation
+ * A backward propagation is triggered by the assignment of the parent node.
+ */
+class ProofCircuitPropagatorBackward : public ProofCircuitPropagator
+{
+ public:
+ ProofCircuitPropagatorBackward(ProofNodeManager* pnm,
+ TNode parent,
+ bool parentAssignment);
+
+ /** and true --> child is true */
+ std::shared_ptr<ProofNode> andTrue(TNode::iterator i);
+
+ /** or false --> child is false */
+ std::shared_ptr<ProofNode> orFalse(TNode::iterator i);
+
+ /**
+ * Propagate on ite with evaluate condition
+ * (ite true t e) --> t
+ * (not (ite true t e)) --> (not t)
+ * (ite false t e) --> e
+ * (not (ite false t e)) --> (not e)
+ */
+ std::shared_ptr<ProofNode> iteC(bool c);
+ /**
+ * For (ite c t e), we can derive the value for c
+ * c = 1: c = true
+ * c = 0: c = false
+ */
+ std::shared_ptr<ProofNode> iteIsCase(unsigned c);
+
+ /** (not (=> X Y)) --> X */
+ std::shared_ptr<ProofNode> impliesNegX();
+ /** (not (=> X Y)) --> (not Y) */
+ std::shared_ptr<ProofNode> impliesNegY();
+
+ private:
+ /** The parent node */
+ TNode d_parent;
+ /** The assignment of d_parent */
+ bool d_parentAssignment;
+};
+
+/**
+ * Proof generator for forward propagation
+ * A forward propagation is triggered by the assignment of a child node.
+ */
+class ProofCircuitPropagatorForward : public ProofCircuitPropagator
+{
+ public:
+ ProofCircuitPropagatorForward(ProofNodeManager* pnm,
+ Node child,
+ bool childAssignment,
+ Node parent);
+
+ /** All children are true --> and is true */
+ std::shared_ptr<ProofNode> andAllTrue();
+ /** One child is false --> and is false */
+ std::shared_ptr<ProofNode> andOneFalse();
+
+ /** One child is true --> or is true */
+ std::shared_ptr<ProofNode> orOneTrue();
+ /** or false --> all children are false */
+ std::shared_ptr<ProofNode> orFalse();
+
+ /** Evaluate (ite true X _) from X */
+ std::shared_ptr<ProofNode> iteEvalThen(bool x);
+ /** Evaluate (ite false _ Y) from Y */
+ std::shared_ptr<ProofNode> iteEvalElse(bool y);
+
+ /** Evaluate (= X Y) from X,Y */
+ std::shared_ptr<ProofNode> eqEval(bool x, bool y);
+
+ /** Evaluate (=> X Y) from X,Y */
+ std::shared_ptr<ProofNode> impliesEval(bool premise, bool conclusion);
+ /** Evaluate (xor X Y) from X,Y */
+ std::shared_ptr<ProofNode> xorEval(bool x, bool y);
+
+ private:
+ /** The current child that triggered the propagations */
+ Node d_child;
+ /** The assignment of d_child */
+ bool d_childAssignment;
+ /** The parent node used for propagation */
+ Node d_parent;
+};
+
+} // namespace booleans
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/booleans/theory_bool.cpp b/src/theory/booleans/theory_bool.cpp
index 022249808..c08012b61 100644
--- a/src/theory/booleans/theory_bool.cpp
+++ b/src/theory/booleans/theory_bool.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Dejan Jovanovic, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -50,8 +50,10 @@ TheoryBool::TheoryBool(context::Context* c,
}
}
-Theory::PPAssertStatus TheoryBool::ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
-
+Theory::PPAssertStatus TheoryBool::ppAssert(
+ TrustNode tin, TrustSubstitutionMap& outSubstitutions)
+{
+ TNode in = tin.getNode();
if (in.getKind() == kind::CONST_BOOLEAN && !in.getConst<bool>()) {
// If we get a false literal, we're in conflict
return PP_ASSERT_STATUS_CONFLICT;
@@ -61,18 +63,20 @@ Theory::PPAssertStatus TheoryBool::ppAssert(TNode in, SubstitutionMap& outSubsti
if (in.getKind() == kind::NOT) {
if (in[0].isVar())
{
- outSubstitutions.addSubstitution(in[0], NodeManager::currentNM()->mkConst<bool>(false));
+ outSubstitutions.addSubstitutionSolved(
+ in[0], NodeManager::currentNM()->mkConst<bool>(false), tin);
return PP_ASSERT_STATUS_SOLVED;
}
} else {
if (in.isVar())
{
- outSubstitutions.addSubstitution(in, NodeManager::currentNM()->mkConst<bool>(true));
+ outSubstitutions.addSubstitutionSolved(
+ in, NodeManager::currentNM()->mkConst<bool>(true), tin);
return PP_ASSERT_STATUS_SOLVED;
}
}
- return Theory::ppAssert(in, outSubstitutions);
+ return Theory::ppAssert(tin, outSubstitutions);
}
}/* CVC4::theory::booleans namespace */
diff --git a/src/theory/booleans/theory_bool.h b/src/theory/booleans/theory_bool.h
index 2f882e257..0a8ca2766 100644
--- a/src/theory/booleans/theory_bool.h
+++ b/src/theory/booleans/theory_bool.h
@@ -2,10 +2,10 @@
/*! \file theory_bool.h
** \verbatim
** Top contributors (to current version):
- ** Andres Noetzli, Mathias Preiner, Morgan Deters
+ ** Andrew Reynolds, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -39,7 +39,8 @@ class TheoryBool : public Theory {
TheoryRewriter* getTheoryRewriter() override { return &d_rewriter; }
- PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions) override;
+ PPAssertStatus ppAssert(TrustNode tin,
+ TrustSubstitutionMap& outSubstitutions) override;
std::string identify() const override { return std::string("TheoryBool"); }
diff --git a/src/theory/booleans/theory_bool_rewriter.cpp b/src/theory/booleans/theory_bool_rewriter.cpp
index ca2ac13ea..73cf25ea4 100644
--- a/src/theory/booleans/theory_bool_rewriter.cpp
+++ b/src/theory/booleans/theory_bool_rewriter.cpp
@@ -2,10 +2,10 @@
/*! \file theory_bool_rewriter.cpp
** \verbatim
** Top contributors (to current version):
- ** Tim King, Dejan Jovanovic, Kshitij Bansal
+ ** Tim King, Dejan Jovanovic, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/booleans/theory_bool_rewriter.h b/src/theory/booleans/theory_bool_rewriter.h
index 04de76ac3..322d3a96a 100644
--- a/src/theory/booleans/theory_bool_rewriter.h
+++ b/src/theory/booleans/theory_bool_rewriter.h
@@ -5,7 +5,7 @@
** Andres Noetzli, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/booleans/theory_bool_type_rules.h b/src/theory/booleans/theory_bool_type_rules.h
index 25701d394..81ae108c4 100644
--- a/src/theory/booleans/theory_bool_type_rules.h
+++ b/src/theory/booleans/theory_bool_type_rules.h
@@ -5,7 +5,7 @@
** Dejan Jovanovic, Morgan Deters, Christopher L. Conway
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/booleans/type_enumerator.h b/src/theory/booleans/type_enumerator.h
index 4966afa7d..8750a744b 100644
--- a/src/theory/booleans/type_enumerator.h
+++ b/src/theory/booleans/type_enumerator.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/builtin/proof_checker.cpp b/src/theory/builtin/proof_checker.cpp
index 59f405337..4e2e78bae 100644
--- a/src/theory/builtin/proof_checker.cpp
+++ b/src/theory/builtin/proof_checker.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -15,6 +15,8 @@
#include "theory/builtin/proof_checker.h"
#include "expr/skolem_manager.h"
+#include "smt/term_formula_removal.h"
+#include "theory/evaluator.h"
#include "theory/rewriter.h"
#include "theory/theory.h"
@@ -28,7 +30,12 @@ const char* toString(MethodId id)
switch (id)
{
case MethodId::RW_REWRITE: return "RW_REWRITE";
+ case MethodId::RW_EXT_REWRITE: return "RW_EXT_REWRITE";
+ case MethodId::RW_REWRITE_EQ_EXT: return "RW_REWRITE_EQ_EXT";
+ case MethodId::RW_EVALUATE: return "RW_EVALUATE";
case MethodId::RW_IDENTITY: return "RW_IDENTITY";
+ case MethodId::RW_REWRITE_THEORY_PRE: return "RW_REWRITE_THEORY_PRE";
+ case MethodId::RW_REWRITE_THEORY_POST: return "RW_REWRITE_THEORY_POST";
case MethodId::SB_DEFAULT: return "SB_DEFAULT";
case MethodId::SB_LITERAL: return "SB_LITERAL";
case MethodId::SB_FORMULA: return "SB_FORMULA";
@@ -55,24 +62,25 @@ void BuiltinProofRuleChecker::registerTo(ProofChecker* pc)
pc->registerChecker(PfRule::SCOPE, this);
pc->registerChecker(PfRule::SUBS, this);
pc->registerChecker(PfRule::REWRITE, this);
+ pc->registerChecker(PfRule::EVALUATE, this);
pc->registerChecker(PfRule::MACRO_SR_EQ_INTRO, this);
pc->registerChecker(PfRule::MACRO_SR_PRED_INTRO, this);
pc->registerChecker(PfRule::MACRO_SR_PRED_ELIM, this);
pc->registerChecker(PfRule::MACRO_SR_PRED_TRANSFORM, this);
pc->registerChecker(PfRule::THEORY_REWRITE, this);
- pc->registerChecker(PfRule::PREPROCESS, this);
+ pc->registerChecker(PfRule::REMOVE_TERM_FORMULA_AXIOM, this);
+ // trusted rules
+ pc->registerTrustedChecker(PfRule::THEORY_LEMMA, this, 1);
+ pc->registerTrustedChecker(PfRule::PREPROCESS, this, 3);
+ pc->registerTrustedChecker(PfRule::PREPROCESS_LEMMA, this, 3);
+ pc->registerTrustedChecker(PfRule::THEORY_PREPROCESS, this, 3);
+ pc->registerTrustedChecker(PfRule::THEORY_PREPROCESS_LEMMA, this, 3);
+ pc->registerTrustedChecker(PfRule::WITNESS_AXIOM, this, 3);
+ pc->registerTrustedChecker(PfRule::TRUST_REWRITE, this, 1);
+ pc->registerTrustedChecker(PfRule::TRUST_SUBS, this, 1);
+ pc->registerTrustedChecker(PfRule::TRUST_SUBS_MAP, this, 3);
}
-Node BuiltinProofRuleChecker::applyTheoryRewrite(Node n, bool preRewrite)
-{
- TheoryId tid = Theory::theoryOf(n);
- Rewriter* rewriter = Rewriter::getInstance();
- Node nkr = preRewrite ? rewriter->preRewrite(tid, n).d_node
- : rewriter->postRewrite(tid, n).d_node;
- return nkr;
-}
-
-
Node BuiltinProofRuleChecker::applySubstitutionRewrite(
Node n, const std::vector<Node>& exp, MethodId ids, MethodId idr)
{
@@ -88,7 +96,20 @@ Node BuiltinProofRuleChecker::applyRewrite(Node n, MethodId idr)
{
return Rewriter::rewrite(n);
}
- else if (idr == MethodId::RW_IDENTITY)
+ if (idr == MethodId::RW_EXT_REWRITE)
+ {
+ return d_ext_rewriter.extendedRewrite(n);
+ }
+ if (idr == MethodId::RW_REWRITE_EQ_EXT)
+ {
+ return Rewriter::rewriteEqualityExt(n);
+ }
+ if (idr == MethodId::RW_EVALUATE)
+ {
+ Evaluator eval;
+ return eval.eval(n, {}, {}, false);
+ }
+ if (idr == MethodId::RW_IDENTITY)
{
// does nothing
return n;
@@ -99,10 +120,10 @@ Node BuiltinProofRuleChecker::applyRewrite(Node n, MethodId idr)
return n;
}
-bool BuiltinProofRuleChecker::getSubstitution(Node exp,
- TNode& var,
- TNode& subs,
- MethodId ids)
+bool BuiltinProofRuleChecker::getSubstitutionForLit(Node exp,
+ TNode& var,
+ TNode& subs,
+ MethodId ids)
{
if (ids == MethodId::SB_DEFAULT)
{
@@ -134,17 +155,57 @@ bool BuiltinProofRuleChecker::getSubstitution(Node exp,
return true;
}
+bool BuiltinProofRuleChecker::getSubstitutionFor(Node exp,
+ std::vector<TNode>& vars,
+ std::vector<TNode>& subs,
+ std::vector<TNode>& from,
+ MethodId ids)
+{
+ TNode v;
+ TNode s;
+ if (exp.getKind() == AND && ids == MethodId::SB_DEFAULT)
+ {
+ for (const Node& ec : exp)
+ {
+ // non-recursive, do not use nested AND
+ if (!getSubstitutionForLit(ec, v, s, ids))
+ {
+ return false;
+ }
+ vars.push_back(v);
+ subs.push_back(s);
+ from.push_back(ec);
+ }
+ return true;
+ }
+ bool ret = getSubstitutionForLit(exp, v, s, ids);
+ vars.push_back(v);
+ subs.push_back(s);
+ from.push_back(exp);
+ return ret;
+}
+
Node BuiltinProofRuleChecker::applySubstitution(Node n, Node exp, MethodId ids)
{
- TNode var, subs;
- if (!getSubstitution(exp, var, subs, ids))
+ std::vector<TNode> vars;
+ std::vector<TNode> subs;
+ std::vector<TNode> from;
+ if (!getSubstitutionFor(exp, vars, subs, from, ids))
{
return Node::null();
}
- Trace("builtin-pfcheck-debug")
- << "applySubstitution (" << ids << "): " << var << " -> " << subs
- << " (from " << exp << ")" << std::endl;
- return n.substitute(var, subs);
+ Node ns = n;
+ // apply substitution one at a time, in reverse order
+ for (size_t i = 0, nvars = vars.size(); i < nvars; i++)
+ {
+ TNode v = vars[nvars - 1 - i];
+ TNode s = subs[nvars - 1 - i];
+ Trace("builtin-pfcheck-debug")
+ << "applySubstitution (" << ids << "): " << v << " -> " << s
+ << " (from " << exp << ")" << std::endl;
+ ns = ns.substitute(v, s);
+ }
+ return ns;
}
Node BuiltinProofRuleChecker::applySubstitution(Node n,
@@ -183,6 +244,7 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id,
const std::vector<Node>& children,
const std::vector<Node>& args)
{
+ NodeManager * nm = NodeManager::currentNM();
// compute what was proven
if (id == PfRule::ASSUME)
{
@@ -199,13 +261,13 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id,
// no antecedant
return children[0];
}
- Node ant = mkAnd(args);
+ Node ant = nm->mkAnd(args);
// if the conclusion is false, its the negated antencedant only
if (children[0].isConst() && !children[0].getConst<bool>())
{
return ant.notNode();
}
- return NodeManager::currentNM()->mkNode(IMPLIES, ant, children[0]);
+ return nm->mkNode(IMPLIES, ant, children[0]);
}
else if (id == PfRule::SUBS)
{
@@ -221,7 +283,11 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id,
{
exp.push_back(children[i]);
}
- Node res = applySubstitution(args[0], exp);
+ Node res = applySubstitution(args[0], exp, ids);
+ if (res.isNull())
+ {
+ return Node::null();
+ }
return args[0].eqNode(res);
}
else if (id == PfRule::REWRITE)
@@ -234,6 +300,21 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id,
return Node::null();
}
Node res = applyRewrite(args[0], idr);
+ if (res.isNull())
+ {
+ return Node::null();
+ }
+ return args[0].eqNode(res);
+ }
+ else if (id == PfRule::EVALUATE)
+ {
+ Assert(children.empty());
+ Assert(args.size() == 1);
+ Node res = applyRewrite(args[0], MethodId::RW_EVALUATE);
+ if (res.isNull())
+ {
+ return Node::null();
+ }
return args[0].eqNode(res);
}
else if (id == PfRule::MACRO_SR_EQ_INTRO)
@@ -244,7 +325,11 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id,
{
return Node::null();
}
- Node res = applySubstitutionRewrite(args[0], children, idr);
+ Node res = applySubstitutionRewrite(args[0], children, ids, idr);
+ if (res.isNull())
+ {
+ return Node::null();
+ }
return args[0].eqNode(res);
}
else if (id == PfRule::MACRO_SR_PRED_INTRO)
@@ -321,10 +406,22 @@ Node BuiltinProofRuleChecker::checkInternal(PfRule id,
}
return args[0];
}
- else if (id == PfRule::PREPROCESS)
+ else if (id == PfRule::REMOVE_TERM_FORMULA_AXIOM)
{
Assert(children.empty());
Assert(args.size() == 1);
+ return RemoveTermFormulas::getAxiomFor(args[0]);
+ }
+ else if (id == PfRule::PREPROCESS || id == PfRule::THEORY_PREPROCESS
+ || id == PfRule::WITNESS_AXIOM || id == PfRule::THEORY_LEMMA
+ || id == PfRule::PREPROCESS_LEMMA || id == PfRule::THEORY_REWRITE
+ || id == PfRule::TRUST_REWRITE || id == PfRule::TRUST_SUBS
+ || id == PfRule::TRUST_SUBS_MAP)
+ {
+ // "trusted" rules
+ Assert(children.empty());
+ Assert(!args.empty());
+ Assert(args[0].getType().isBoolean());
return args[0];
}
// no rule
@@ -374,6 +471,23 @@ void BuiltinProofRuleChecker::addMethodIds(std::vector<Node>& args,
}
}
+bool BuiltinProofRuleChecker::getTheoryId(TNode n, TheoryId& tid)
+{
+ uint32_t i;
+ if (!getUInt32(n, i))
+ {
+ return false;
+ }
+ tid = static_cast<TheoryId>(i);
+ return true;
+}
+
+Node BuiltinProofRuleChecker::mkTheoryIdNode(TheoryId tid)
+{
+ return NodeManager::currentNM()->mkConst(
+ Rational(static_cast<uint32_t>(tid)));
+}
+
} // namespace builtin
} // namespace theory
} // namespace CVC4
diff --git a/src/theory/builtin/proof_checker.h b/src/theory/builtin/proof_checker.h
index 7e46587b7..fc26beaa1 100644
--- a/src/theory/builtin/proof_checker.h
+++ b/src/theory/builtin/proof_checker.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,11 +20,12 @@
#include "expr/node.h"
#include "expr/proof_checker.h"
#include "expr/proof_node.h"
+#include "theory/quantifiers/extended_rewrite.h"
namespace CVC4 {
namespace theory {
-/**
+/**
* Identifiers for rewriters and substitutions, which we abstractly
* classify as "methods". Methods have a unique identifier in the internal
* proof calculus implemented by the checker below.
@@ -41,8 +42,20 @@ enum class MethodId : uint32_t
//---------------------------- Rewriters
// Rewriter::rewrite(n)
RW_REWRITE,
+ // d_ext_rew.extendedRewrite(n);
+ RW_EXT_REWRITE,
+ // Rewriter::rewriteExtEquality(n)
+ RW_REWRITE_EQ_EXT,
+ // Evaluator::evaluate(n)
+ RW_EVALUATE,
// identity
RW_IDENTITY,
+ // theory preRewrite, note this is only intended to be used as an argument
+ // to THEORY_REWRITE in the final proof. It is not implemented in
+ // applyRewrite below, see documentation in proof_rule.h for THEORY_REWRITE.
+ RW_REWRITE_THEORY_PRE,
+ // same as above, for theory postRewrite
+ RW_REWRITE_THEORY_POST,
//---------------------------- Substitutions
// (= x y) is interpreted as x -> y, using Node::substitute
SB_DEFAULT,
@@ -75,26 +88,29 @@ class BuiltinProofRuleChecker : public ProofRuleChecker
* specifying a call to Rewriter::rewrite.
* @return The rewritten form of n.
*/
- static Node applyRewrite(Node n, MethodId idr = MethodId::RW_REWRITE);
+ Node applyRewrite(Node n, MethodId idr = MethodId::RW_REWRITE);
/**
- * Apply small-step rewrite on n in skolem form (either pre- or
- * post-rewrite). This encapsulates the exact behavior of a THEORY_REWRITE
- * step in a proof.
- *
- * @param n The node to rewrite
- * @param preRewrite If true, performs a pre-rewrite or a post-rewrite
- * otherwise
- * @return The rewritten form of n
+ * Get substitution for literal exp. Updates vars/subs to the substitution
+ * specified by exp for the substitution method ids.
*/
- static Node applyTheoryRewrite(Node n, bool preRewrite);
+ static bool getSubstitutionForLit(Node exp,
+ TNode& var,
+ TNode& subs,
+ MethodId ids = MethodId::SB_DEFAULT);
/**
- * Get substitution. Updates vars/subs to the substitution specified by
- * exp (e.g. as an equality) for the substitution method ids.
+ * Get substitution for formula exp. Adds to vars/subs to the substitution
+ * specified by exp for the substitution method ids, which may be multiple
+ * substitutions if exp is of kind AND and ids is SB_DEFAULT (note the other
+ * substitution types always interpret applications of AND as a formula).
+ * The vector "from" are the literals from exp that each substitution in
+ * vars/subs are based on. For example, if exp is (and (= x t) (= y s)), then
+ * vars = { x, y }, subs = { t, s }, from = { (= x y), (= y s) }.
*/
- static bool getSubstitution(Node exp,
- TNode& var,
- TNode& subs,
- MethodId ids = MethodId::SB_DEFAULT);
+ static bool getSubstitutionFor(Node exp,
+ std::vector<TNode>& vars,
+ std::vector<TNode>& subs,
+ std::vector<TNode>& from,
+ MethodId ids = MethodId::SB_DEFAULT);
/**
* Apply substitution on n in skolem form. This encapsulates the exact
@@ -123,10 +139,10 @@ class BuiltinProofRuleChecker : public ProofRuleChecker
* @param idr The method identifier of the rewriter.
* @return The substituted, rewritten form of n.
*/
- static Node applySubstitutionRewrite(Node n,
- const std::vector<Node>& exp,
- MethodId ids = MethodId::SB_DEFAULT,
- MethodId idr = MethodId::RW_REWRITE);
+ Node applySubstitutionRewrite(Node n,
+ const std::vector<Node>& exp,
+ MethodId ids = MethodId::SB_DEFAULT,
+ MethodId idr = MethodId::RW_REWRITE);
/** get a method identifier from a node, return false if we fail */
static bool getMethodId(TNode n, MethodId& i);
/**
@@ -144,6 +160,11 @@ class BuiltinProofRuleChecker : public ProofRuleChecker
*/
static void addMethodIds(std::vector<Node>& args, MethodId ids, MethodId idr);
+ /** get a TheoryId from a node, return false if we fail */
+ static bool getTheoryId(TNode n, TheoryId& tid);
+ /** Make a TheoryId into a node */
+ static Node mkTheoryIdNode(TheoryId tid);
+
/** Register all rules owned by this rule checker into pc. */
void registerTo(ProofChecker* pc) override;
protected:
@@ -151,6 +172,9 @@ class BuiltinProofRuleChecker : public ProofRuleChecker
Node checkInternal(PfRule id,
const std::vector<Node>& children,
const std::vector<Node>& args) override;
+
+ /** extended rewriter object */
+ quantifiers::ExtendedRewriter d_ext_rewriter;
};
} // namespace builtin
diff --git a/src/theory/builtin/theory_builtin.cpp b/src/theory/builtin/theory_builtin.cpp
index f6ce4414e..2cb3b45cd 100644
--- a/src/theory/builtin/theory_builtin.cpp
+++ b/src/theory/builtin/theory_builtin.cpp
@@ -2,10 +2,10 @@
/*! \file theory_builtin.cpp
** \verbatim
** Top contributors (to current version):
- ** Mudathir Mohamed, Andrew Reynolds, Morgan Deters
+ ** Andrew Reynolds, Mudathir Mohamed, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/builtin/theory_builtin.h b/src/theory/builtin/theory_builtin.h
index beca0b76a..9b5c22ee4 100644
--- a/src/theory/builtin/theory_builtin.h
+++ b/src/theory/builtin/theory_builtin.h
@@ -2,10 +2,10 @@
/*! \file theory_builtin.h
** \verbatim
** Top contributors (to current version):
- ** Mudathir Mohamed, Andres Noetzli, Mathias Preiner
+ ** Mudathir Mohamed, Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/builtin/theory_builtin_rewriter.cpp b/src/theory/builtin/theory_builtin_rewriter.cpp
index 456b0cbca..99e2bfd74 100644
--- a/src/theory/builtin/theory_builtin_rewriter.cpp
+++ b/src/theory/builtin/theory_builtin_rewriter.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -92,43 +92,26 @@ RewriteResponse TheoryBuiltinRewriter::postRewrite(TNode node) {
}
return RewriteResponse(REWRITE_DONE, node);
}
- else if (node.getKind() == kind::WITNESS)
+ // otherwise, do the default call
+ return doRewrite(node);
+}
+
+RewriteResponse TheoryBuiltinRewriter::doRewrite(TNode node)
+{
+ switch (node.getKind())
{
- if (node[1].getKind() == kind::EQUAL)
- {
- for (unsigned i = 0; i < 2; i++)
- {
- // (witness ((x T)) (= x t)) ---> t
- if (node[1][i] == node[0][0])
- {
- Trace("builtin-rewrite") << "Witness rewrite: " << node << " --> "
- << node[1][1 - i] << std::endl;
- // also must be a legal elimination: the other side of the equality
- // cannot contain the variable, and it must be a subtype of the
- // variable
- if (!expr::hasSubterm(node[1][1 - i], node[0][0]) &&
- node[1][i].getType().isSubtypeOf(node[0][0].getType()))
- {
- return RewriteResponse(REWRITE_DONE, node[1][1 - i]);
- }
- }
- }
- }
- else if (node[1] == node[0][0])
+ case kind::WITNESS:
{
- // (witness ((x Bool)) x) ---> true
- return RewriteResponse(REWRITE_DONE,
- NodeManager::currentNM()->mkConst(true));
+ // it is important to run this rewriting at prerewrite and postrewrite,
+ // since e.g. arithmetic rewrites equalities in ways that may make an
+ // equality not in solved form syntactically, e.g. (= x (+ 1 a)) rewrites
+ // to (= a (- x 1)), where x no longer is in solved form.
+ Node rnode = rewriteWitness(node);
+ return RewriteResponse(REWRITE_DONE, rnode);
}
- else if (node[1].getKind() == kind::NOT && node[1][0] == node[0][0])
- {
- // (witness ((x Bool)) (not x)) ---> false
- return RewriteResponse(REWRITE_DONE,
- NodeManager::currentNM()->mkConst(false));
- }
- return RewriteResponse(REWRITE_DONE, node);
- }else{
- return doRewrite(node);
+ case kind::DISTINCT:
+ return RewriteResponse(REWRITE_DONE, blastDistinct(node));
+ default: return RewriteResponse(REWRITE_DONE, node);
}
}
@@ -468,6 +451,42 @@ Node TheoryBuiltinRewriter::getArrayRepresentationForLambdaRec(TNode n,
}
}
+Node TheoryBuiltinRewriter::rewriteWitness(TNode node)
+{
+ Assert(node.getKind() == kind::WITNESS);
+ if (node[1].getKind() == kind::EQUAL)
+ {
+ for (size_t i = 0; i < 2; i++)
+ {
+ // (witness ((x T)) (= x t)) ---> t
+ if (node[1][i] == node[0][0])
+ {
+ Trace("builtin-rewrite") << "Witness rewrite: " << node << " --> "
+ << node[1][1 - i] << std::endl;
+ // also must be a legal elimination: the other side of the equality
+ // cannot contain the variable, and it must be a subtype of the
+ // variable
+ if (!expr::hasSubterm(node[1][1 - i], node[0][0])
+ && node[1][i].getType().isSubtypeOf(node[0][0].getType()))
+ {
+ return node[1][1 - i];
+ }
+ }
+ }
+ }
+ else if (node[1] == node[0][0])
+ {
+ // (witness ((x Bool)) x) ---> true
+ return NodeManager::currentNM()->mkConst(true);
+ }
+ else if (node[1].getKind() == kind::NOT && node[1][0] == node[0][0])
+ {
+ // (witness ((x Bool)) (not x)) ---> false
+ return NodeManager::currentNM()->mkConst(false);
+ }
+ return node;
+}
+
Node TheoryBuiltinRewriter::getArrayRepresentationForLambda(TNode n)
{
Assert(n.getKind() == kind::LAMBDA);
diff --git a/src/theory/builtin/theory_builtin_rewriter.h b/src/theory/builtin/theory_builtin_rewriter.h
index 930a316a2..5fe4b159d 100644
--- a/src/theory/builtin/theory_builtin_rewriter.h
+++ b/src/theory/builtin/theory_builtin_rewriter.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -33,16 +33,6 @@ class TheoryBuiltinRewriter : public TheoryRewriter
public:
- static inline RewriteResponse doRewrite(TNode node)
- {
- switch (node.getKind())
- {
- case kind::DISTINCT:
- return RewriteResponse(REWRITE_DONE, blastDistinct(node));
- default: return RewriteResponse(REWRITE_DONE, node);
- }
- }
-
RewriteResponse postRewrite(TNode node) override;
RewriteResponse preRewrite(TNode node) override { return doRewrite(node); }
@@ -56,6 +46,15 @@ class TheoryBuiltinRewriter : public TheoryRewriter
static Node getArrayRepresentationForLambdaRec(TNode n, TypeNode retType);
public:
+ /**
+ * The default rewriter for rewrites that occur at both pre and post rewrite.
+ */
+ static RewriteResponse doRewrite(TNode node);
+ /**
+ * Main entry point for rewriting terms of the form (witness ((x T)) (P x)).
+ * Returns the rewritten form of node.
+ */
+ static Node rewriteWitness(TNode node);
/** Get function type for array type
*
* This returns the function type of terms returned by the function
diff --git a/src/theory/builtin/theory_builtin_type_rules.cpp b/src/theory/builtin/theory_builtin_type_rules.cpp
new file mode 100644
index 000000000..59c1ecd65
--- /dev/null
+++ b/src/theory/builtin/theory_builtin_type_rules.cpp
@@ -0,0 +1,50 @@
+/********************* */
+/*! \file theory_builtin_type_rules.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Type rules for the builtin theory
+ **
+ ** Type rules for the builtin theory.
+ **/
+
+#include "theory/builtin/theory_builtin_type_rules.h"
+
+#include "expr/attribute.h"
+
+namespace CVC4 {
+namespace theory {
+namespace builtin {
+
+/**
+ * Attribute for caching the ground term for each type. Maps TypeNode to the
+ * skolem to return for mkGroundTerm.
+ */
+struct GroundTermAttributeId
+{
+};
+typedef expr::Attribute<GroundTermAttributeId, Node> GroundTermAttribute;
+
+Node SortProperties::mkGroundTerm(TypeNode type)
+{
+ Assert(type.getKind() == kind::SORT_TYPE);
+ GroundTermAttribute gta;
+ if (type.hasAttribute(gta))
+ {
+ return type.getAttribute(gta);
+ }
+ Node k = NodeManager::currentNM()->mkSkolem(
+ "groundTerm", type, "a ground term created for type " + type.toString());
+ type.setAttribute(gta, k);
+ return k;
+}
+
+} // namespace builtin
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/builtin/theory_builtin_type_rules.h b/src/theory/builtin/theory_builtin_type_rules.h
index 29ac4f2d1..1b251f8e0 100644
--- a/src/theory/builtin/theory_builtin_type_rules.h
+++ b/src/theory/builtin/theory_builtin_type_rules.h
@@ -5,7 +5,7 @@
** Morgan Deters, Andrew Reynolds, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -199,10 +199,7 @@ class SortProperties {
inline static bool isWellFounded(TypeNode type) {
return true;
}
- inline static Node mkGroundTerm(TypeNode type) {
- Assert(type.getKind() == kind::SORT_TYPE);
- return NodeManager::currentNM()->mkSkolem("groundTerm", type, "a ground term created for type " + type.toString());
- }
+ static Node mkGroundTerm(TypeNode type);
};/* class SortProperties */
class FunctionProperties {
diff --git a/src/theory/builtin/type_enumerator.cpp b/src/theory/builtin/type_enumerator.cpp
index f971a6242..99ab0ed79 100644
--- a/src/theory/builtin/type_enumerator.cpp
+++ b/src/theory/builtin/type_enumerator.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/builtin/type_enumerator.h b/src/theory/builtin/type_enumerator.h
index 18dcf4521..f08f9be9d 100644
--- a/src/theory/builtin/type_enumerator.h
+++ b/src/theory/builtin/type_enumerator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/bv/abstraction.cpp b/src/theory/bv/abstraction.cpp
index a9ec7aa53..9eb0f10fa 100644
--- a/src/theory/bv/abstraction.cpp
+++ b/src/theory/bv/abstraction.cpp
@@ -5,7 +5,7 @@
** Liana Hadarean, Aina Niemetz, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -15,12 +15,14 @@
#include "theory/bv/abstraction.h"
#include "options/bv_options.h"
+#include "printer/printer.h"
#include "smt/dump.h"
+#include "smt/smt_engine.h"
+#include "smt/smt_engine_scope.h"
#include "smt/smt_statistics_registry.h"
#include "theory/bv/theory_bv_utils.h"
#include "theory/rewriter.h"
-
using namespace CVC4;
using namespace CVC4::theory;
using namespace CVC4::theory::bv;
@@ -691,15 +693,6 @@ Node AbstractionModule::substituteArguments(TNode signature, TNode apply, unsign
}
Node AbstractionModule::simplifyConflict(TNode conflict) {
- if (Dump.isOn("bv-abstraction")) {
- NodeNodeMap seen;
- Node c = reverseAbstraction(conflict, seen);
- Dump("bv-abstraction") << PushCommand();
- Dump("bv-abstraction") << AssertCommand(c.toExpr());
- Dump("bv-abstraction") << CheckSatCommand();
- Dump("bv-abstraction") << PopCommand();
- }
-
Debug("bv-abstraction-dbg") << "AbstractionModule::simplifyConflict " << conflict << "\n";
if (conflict.getKind() != kind::AND)
return conflict;
@@ -742,16 +735,6 @@ Node AbstractionModule::simplifyConflict(TNode conflict) {
Debug("bv-abstraction") << "AbstractionModule::simplifyConflict conflict " << conflict <<"\n";
Debug("bv-abstraction") << " => " << new_conflict <<"\n";
- if (Dump.isOn("bv-abstraction")) {
-
- NodeNodeMap seen;
- Node nc = reverseAbstraction(new_conflict, seen);
- Dump("bv-abstraction") << PushCommand();
- Dump("bv-abstraction") << AssertCommand(nc.toExpr());
- Dump("bv-abstraction") << CheckSatCommand();
- Dump("bv-abstraction") << PopCommand();
- }
-
return new_conflict;
}
@@ -836,15 +819,6 @@ void AbstractionModule::generalizeConflict(TNode conflict, std::vector<Node>& le
lemmas.push_back(lemma);
Debug("bv-abstraction-gen") << "adding lemma " << lemma << "\n";
storeLemma(lemma);
-
- if (Dump.isOn("bv-abstraction")) {
- NodeNodeMap seen;
- Node l = reverseAbstraction(lemma, seen);
- Dump("bv-abstraction") << PushCommand();
- Dump("bv-abstraction") << AssertCommand(l.toExpr());
- Dump("bv-abstraction") << CheckSatCommand();
- Dump("bv-abstraction") << PopCommand();
- }
}
}
}
diff --git a/src/theory/bv/abstraction.h b/src/theory/bv/abstraction.h
index 77fe1e363..8f6c6cdf8 100644
--- a/src/theory/bv/abstraction.h
+++ b/src/theory/bv/abstraction.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/bv/bitblast/aig_bitblaster.cpp b/src/theory/bv/bitblast/aig_bitblaster.cpp
index 331db9378..ca1ca4c74 100644
--- a/src/theory/bv/bitblast/aig_bitblaster.cpp
+++ b/src/theory/bv/bitblast/aig_bitblaster.cpp
@@ -5,7 +5,7 @@
** Liana Hadarean, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,12 +14,12 @@
** AIG bitblaster.
**/
-#include "cvc4_private.h"
-
#include "theory/bv/bitblast/aig_bitblaster.h"
#include "base/check.h"
+#include "cvc4_private.h"
#include "options/bv_options.h"
+#include "prop/cnf_stream.h"
#include "prop/sat_solver_factory.h"
#include "smt/smt_statistics_registry.h"
@@ -28,7 +28,6 @@
extern "C" {
#include "base/abc/abc.h"
#include "base/main/main.h"
-#include "prop/cnf_stream.h"
#include "sat/cnf/cnf.h"
extern Aig_Man_t* Abc_NtkToDar(Abc_Ntk_t* pNtk, int fExors, int fRegisters);
diff --git a/src/theory/bv/bitblast/aig_bitblaster.h b/src/theory/bv/bitblast/aig_bitblaster.h
index 1e1b5bab4..ce733cabc 100644
--- a/src/theory/bv/bitblast/aig_bitblaster.h
+++ b/src/theory/bv/bitblast/aig_bitblaster.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Mathias Preiner, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -89,12 +89,6 @@ class AigBitblaster : public TBitblaster<Abc_Obj_t*>
prop::SatSolver* getSatSolver() override { return d_satSolver.get(); }
- void setProofLog(proof::BitVectorProof* bvp) override
- {
- // Proofs are currently not supported with ABC
- Unimplemented();
- }
-
class Statistics
{
public:
diff --git a/src/theory/bv/bitblast/bitblast_strategies_template.h b/src/theory/bv/bitblast/bitblast_strategies_template.h
index 7f1fe4eeb..a4e1757e2 100644
--- a/src/theory/bv/bitblast/bitblast_strategies_template.h
+++ b/src/theory/bv/bitblast/bitblast_strategies_template.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Aina Niemetz, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/bv/bitblast/bitblast_utils.h b/src/theory/bv/bitblast/bitblast_utils.h
index 13ae129be..de98dc8bb 100644
--- a/src/theory/bv/bitblast/bitblast_utils.h
+++ b/src/theory/bv/bitblast/bitblast_utils.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Dejan Jovanovic, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/bv/bitblast/bitblaster.h b/src/theory/bv/bitblast/bitblaster.h
index defc66b74..fd99621d4 100644
--- a/src/theory/bv/bitblast/bitblaster.h
+++ b/src/theory/bv/bitblast/bitblaster.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Mathias Preiner, Alex Ozdemir
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -24,8 +24,8 @@
#include <vector>
#include "expr/node.h"
-#include "proof/bitvector_proof.h"
#include "prop/bv_sat_solver_notify.h"
+#include "prop/sat_solver.h"
#include "prop/sat_solver_types.h"
#include "smt/smt_engine_scope.h"
#include "theory/bv/bitblast/bitblast_strategies_template.h"
@@ -64,7 +64,6 @@ class TBitblaster
// sat solver used for bitblasting and associated CnfStream
std::unique_ptr<context::Context> d_nullContext;
std::unique_ptr<prop::CnfStream> d_cnfStream;
- proof::BitVectorProof* d_bvp;
void initAtomBBStrategies();
void initTermBBStrategies();
@@ -91,7 +90,6 @@ class TBitblaster
bool hasBBTerm(TNode node) const;
void getBBTerm(TNode node, Bits& bits) const;
virtual void storeBBTerm(TNode term, const Bits& bits);
- virtual void setProofLog(proof::BitVectorProof* bvp);
/**
* Return a constant representing the value of a in the model.
@@ -186,8 +184,7 @@ TBitblaster<T>::TBitblaster()
: d_termCache(),
d_modelCache(),
d_nullContext(new context::Context()),
- d_cnfStream(),
- d_bvp(nullptr)
+ d_cnfStream()
{
initAtomBBStrategies();
initTermBBStrategies();
@@ -218,20 +215,6 @@ void TBitblaster<T>::invalidateModelCache()
}
template <class T>
-void TBitblaster<T>::setProofLog(proof::BitVectorProof* bvp)
-{
- if (THEORY_PROOF_ON())
- {
- d_bvp = bvp;
- prop::SatSolver* satSolver = getSatSolver();
- bvp->attachToSatSolver(*satSolver);
- prop::SatVariable t = satSolver->trueVar();
- prop::SatVariable f = satSolver->falseVar();
- bvp->initCnfProof(d_cnfStream.get(), d_nullContext.get(), t, f);
- }
-}
-
-template <class T>
Node TBitblaster<T>::getTermModel(TNode node, bool fullModel)
{
if (d_modelCache.find(node) != d_modelCache.end()) return d_modelCache[node];
diff --git a/src/theory/bv/bitblast/eager_bitblaster.cpp b/src/theory/bv/bitblast/eager_bitblaster.cpp
index 4acd1d2f8..046ad4b1b 100644
--- a/src/theory/bv/bitblast/eager_bitblaster.cpp
+++ b/src/theory/bv/bitblast/eager_bitblaster.cpp
@@ -2,10 +2,10 @@
/*! \file eager_bitblaster.cpp
** \verbatim
** Top contributors (to current version):
- ** Liana Hadarean, Mathias Preiner, Tim King
+ ** Liana Hadarean, Mathias Preiner, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,14 +14,15 @@
** Bitblaster for the eager bv solver.
**/
-#include "cvc4_private.h"
-
#include "theory/bv/bitblast/eager_bitblaster.h"
+#include "cvc4_private.h"
#include "options/bv_options.h"
#include "prop/cnf_stream.h"
#include "prop/sat_solver_factory.h"
+#include "smt/smt_engine.h"
#include "smt/smt_statistics_registry.h"
+#include "theory/bv/bv_solver_lazy.h"
#include "theory/bv/theory_bv.h"
#include "theory/theory_model.h"
@@ -29,7 +30,7 @@ namespace CVC4 {
namespace theory {
namespace bv {
-EagerBitblaster::EagerBitblaster(TheoryBV* theory_bv, context::Context* c)
+EagerBitblaster::EagerBitblaster(BVSolverLazy* theory_bv, context::Context* c)
: TBitblaster<Node>(),
d_context(c),
d_satSolver(),
@@ -68,12 +69,13 @@ EagerBitblaster::EagerBitblaster(TheoryBV* theory_bv, context::Context* c)
}
d_satSolver.reset(solver);
ResourceManager* rm = smt::currentResourceManager();
- d_cnfStream.reset(new prop::TseitinCnfStream(d_satSolver.get(),
- d_bitblastingRegistrar.get(),
- d_nullContext.get(),
- rm,
- options::proof(),
- "EagerBitblaster"));
+ d_cnfStream.reset(new prop::CnfStream(d_satSolver.get(),
+ d_bitblastingRegistrar.get(),
+ d_nullContext.get(),
+ nullptr,
+ rm,
+ false,
+ "EagerBitblaster"));
}
EagerBitblaster::~EagerBitblaster() {}
@@ -87,8 +89,7 @@ void EagerBitblaster::bbFormula(TNode node)
}
else
{
- d_cnfStream->convertAndAssert(
- node, false, false, RULE_INVALID, TNode::null());
+ d_cnfStream->convertAndAssert(node, false, false);
}
}
@@ -116,10 +117,7 @@ void EagerBitblaster::bbAtom(TNode node)
? d_atomBBStrategies[normalized.getKind()](normalized, this)
: normalized;
- if (!options::proof())
- {
- atom_bb = Rewriter::rewrite(atom_bb);
- }
+ atom_bb = Rewriter::rewrite(atom_bb);
// asserting that the atom is true iff the definition holds
Node atom_definition =
@@ -127,21 +125,14 @@ void EagerBitblaster::bbAtom(TNode node)
AlwaysAssert(options::bitblastMode() == options::BitblastMode::EAGER);
storeBBAtom(node, atom_bb);
- d_cnfStream->convertAndAssert(
- atom_definition, false, false, RULE_INVALID, TNode::null());
+ d_cnfStream->convertAndAssert(atom_definition, false, false);
}
void EagerBitblaster::storeBBAtom(TNode atom, Node atom_bb) {
- if (d_bvp) {
- d_bvp->registerAtomBB(atom.toExpr(), atom_bb.toExpr());
- }
d_bbAtoms.insert(atom);
}
void EagerBitblaster::storeBBTerm(TNode node, const Bits& bits) {
- if (d_bvp) {
- d_bvp->registerTermBB(node.toExpr());
- }
d_termCache.insert(std::make_pair(node, bits));
}
diff --git a/src/theory/bv/bitblast/eager_bitblaster.h b/src/theory/bv/bitblast/eager_bitblaster.h
index a8b7ccbe5..38a9f775b 100644
--- a/src/theory/bv/bitblast/eager_bitblaster.h
+++ b/src/theory/bv/bitblast/eager_bitblaster.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Liana Hadarean, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -23,8 +23,6 @@
#include "theory/bv/bitblast/bitblaster.h"
-#include "proof/bitvector_proof.h"
-#include "proof/resolution_bitvector_proof.h"
#include "prop/cnf_stream.h"
#include "prop/sat_solver.h"
@@ -33,12 +31,12 @@ namespace theory {
namespace bv {
class BitblastingRegistrar;
-class TheoryBV;
+class BVSolverLazy;
class EagerBitblaster : public TBitblaster<Node>
{
public:
- EagerBitblaster(TheoryBV* theory_bv, context::Context* context);
+ EagerBitblaster(BVSolverLazy* theory_bv, context::Context* context);
~EagerBitblaster();
void addAtom(TNode atom);
@@ -63,7 +61,7 @@ class EagerBitblaster : public TBitblaster<Node>
std::unique_ptr<prop::SatSolver> d_satSolver;
std::unique_ptr<BitblastingRegistrar> d_bitblastingRegistrar;
- TheoryBV* d_bv;
+ BVSolverLazy* d_bv;
TNodeSet d_bbAtoms;
TNodeSet d_variables;
diff --git a/src/theory/bv/bitblast/lazy_bitblaster.cpp b/src/theory/bv/bitblast/lazy_bitblaster.cpp
index c3a305952..95d78c69b 100644
--- a/src/theory/bv/bitblast/lazy_bitblaster.cpp
+++ b/src/theory/bv/bitblast/lazy_bitblaster.cpp
@@ -5,7 +5,7 @@
** Liana Hadarean, Aina Niemetz, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,17 +14,17 @@
** Bitblaster for the lazy bv solver.
**/
-#include "cvc4_private.h"
-
#include "theory/bv/bitblast/lazy_bitblaster.h"
+#include "cvc4_private.h"
#include "options/bv_options.h"
-#include "proof/proof_manager.h"
#include "prop/cnf_stream.h"
#include "prop/sat_solver.h"
#include "prop/sat_solver_factory.h"
+#include "smt/smt_engine.h"
#include "smt/smt_statistics_registry.h"
#include "theory/bv/abstraction.h"
+#include "theory/bv/bv_solver_lazy.h"
#include "theory/bv/theory_bv.h"
#include "theory/bv/theory_bv_utils.h"
#include "theory/rewriter.h"
@@ -59,7 +59,7 @@ uint64_t numNodes(TNode node, utils::NodeSet& seen)
}
TLazyBitblaster::TLazyBitblaster(context::Context* c,
- bv::TheoryBV* bv,
+ bv::BVSolverLazy* bv,
const std::string name,
bool emptyNotify)
: TBitblaster<Node>(),
@@ -80,12 +80,13 @@ TLazyBitblaster::TLazyBitblaster(context::Context* c,
prop::SatSolverFactory::createMinisat(c, smtStatisticsRegistry(), name));
ResourceManager* rm = smt::currentResourceManager();
- d_cnfStream.reset(new prop::TseitinCnfStream(d_satSolver.get(),
- d_nullRegistrar.get(),
- d_nullContext.get(),
- rm,
- options::proof(),
- "LazyBitblaster"));
+ d_cnfStream.reset(new prop::CnfStream(d_satSolver.get(),
+ d_nullRegistrar.get(),
+ d_nullContext.get(),
+ nullptr,
+ rm,
+ false,
+ "LazyBitblaster"));
d_satSolverNotify.reset(
d_emptyNotify
@@ -161,8 +162,7 @@ void TLazyBitblaster::bbAtom(TNode node)
Assert(!atom_bb.isNull());
Node atom_definition = nm->mkNode(kind::EQUAL, node, atom_bb);
storeBBAtom(node, atom_bb);
- d_cnfStream->convertAndAssert(
- atom_definition, false, false, RULE_INVALID, TNode::null());
+ d_cnfStream->convertAndAssert(atom_definition, false, false);
return;
}
@@ -173,28 +173,19 @@ void TLazyBitblaster::bbAtom(TNode node)
? d_atomBBStrategies[normalized.getKind()](normalized, this)
: normalized;
- if (!options::proof())
- {
- atom_bb = Rewriter::rewrite(atom_bb);
- }
+ atom_bb = Rewriter::rewrite(atom_bb);
// asserting that the atom is true iff the definition holds
Node atom_definition = nm->mkNode(kind::EQUAL, node, atom_bb);
storeBBAtom(node, atom_bb);
- d_cnfStream->convertAndAssert(
- atom_definition, false, false, RULE_INVALID, TNode::null());
+ d_cnfStream->convertAndAssert(atom_definition, false, false);
}
void TLazyBitblaster::storeBBAtom(TNode atom, Node atom_bb) {
- // No need to store the definition for the lazy bit-blaster (unless proofs are enabled).
- if( d_bvp != NULL ){
- d_bvp->registerAtomBB(atom.toExpr(), atom_bb.toExpr());
- }
d_bbAtoms.insert(atom);
}
void TLazyBitblaster::storeBBTerm(TNode node, const Bits& bits) {
- if( d_bvp ){ d_bvp->registerTermBB(node.toExpr()); }
d_termCache.insert(std::make_pair(node, bits));
}
@@ -303,8 +294,12 @@ bool TLazyBitblaster::assertToSat(TNode lit, bool propagate) {
markerLit = ~markerLit;
}
- Debug("bitvector-bb") << "TheoryBV::TLazyBitblaster::assertToSat asserting node: " << atom <<"\n";
- Debug("bitvector-bb") << "TheoryBV::TLazyBitblaster::assertToSat with literal: " << markerLit << "\n";
+ Debug("bitvector-bb")
+ << "BVSolverLazy::TLazyBitblaster::assertToSat asserting node: " << atom
+ << "\n";
+ Debug("bitvector-bb")
+ << "BVSolverLazy::TLazyBitblaster::assertToSat with literal: "
+ << markerLit << "\n";
prop::SatValue ret = d_satSolver->assertAssumption(markerLit, propagate);
@@ -421,9 +416,9 @@ void TLazyBitblaster::MinisatNotify::notify(prop::SatClause& clause) {
lemmab << d_cnf->getNode(clause[i]);
}
Node lemma = lemmab;
- d_bv->d_out->lemma(lemma);
+ d_bv->d_inferManager.lemma(lemma);
} else {
- d_bv->d_out->lemma(d_cnf->getNode(clause[0]));
+ d_bv->d_inferManager.lemma(d_cnf->getNode(clause[0]));
}
}
@@ -434,7 +429,7 @@ void TLazyBitblaster::MinisatNotify::spendResource(ResourceManager::Resource r)
void TLazyBitblaster::MinisatNotify::safePoint(ResourceManager::Resource r)
{
- d_bv->d_out->safePoint(r);
+ d_bv->d_inferManager.safePoint(r);
}
EqualityStatus TLazyBitblaster::getEqualityStatus(TNode a, TNode b)
@@ -537,11 +532,9 @@ Node TLazyBitblaster::getModelFromSatSolver(TNode a, bool fullModel) {
return utils::mkConst(bits.size(), value);
}
-bool TLazyBitblaster::collectModelInfo(TheoryModel* m, bool fullModel)
+bool TLazyBitblaster::collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet)
{
- std::set<Node> termSet;
- d_bv->computeRelevantTerms(termSet);
-
for (std::set<Node>::const_iterator it = termSet.begin(); it != termSet.end(); ++it) {
TNode var = *it;
// not actually a leaf of the bit-vector theory
@@ -555,9 +548,9 @@ bool TLazyBitblaster::collectModelInfo(TheoryModel* m, bool fullModel)
Node const_value = getModelFromSatSolver(var, true);
Assert(const_value.isNull() || const_value.isConst());
if(const_value != Node()) {
- Debug("bitvector-model") << "TLazyBitblaster::collectModelInfo (assert (= "
- << var << " "
- << const_value << "))\n";
+ Debug("bitvector-model")
+ << "TLazyBitblaster::collectModelValues (assert (= " << var << " "
+ << const_value << "))\n";
if (!m->assertEquality(var, const_value, true))
{
return false;
@@ -582,8 +575,11 @@ void TLazyBitblaster::clearSolver() {
d_satSolver.reset(
prop::SatSolverFactory::createMinisat(d_ctx, smtStatisticsRegistry()));
ResourceManager* rm = smt::currentResourceManager();
- d_cnfStream.reset(new prop::TseitinCnfStream(
- d_satSolver.get(), d_nullRegistrar.get(), d_nullContext.get(), rm));
+ d_cnfStream.reset(new prop::CnfStream(d_satSolver.get(),
+ d_nullRegistrar.get(),
+ d_nullContext.get(),
+ nullptr,
+ rm));
d_satSolverNotify.reset(
d_emptyNotify
? (prop::BVSatSolverNotify*)new MinisatEmptyNotify()
diff --git a/src/theory/bv/bitblast/lazy_bitblaster.h b/src/theory/bv/bitblast/lazy_bitblaster.h
index a355d42c4..a15eb084e 100644
--- a/src/theory/bv/bitblast/lazy_bitblaster.h
+++ b/src/theory/bv/bitblast/lazy_bitblaster.h
@@ -2,10 +2,10 @@
/*! \file lazy_bitblaster.h
** \verbatim
** Top contributors (to current version):
- ** Liana Hadarean, Mathias Preiner, Clark Barrett
+ ** Mathias Preiner, Liana Hadarean, Clark Barrett
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,7 +19,6 @@
#ifndef CVC4__THEORY__BV__BITBLAST__LAZY_BITBLASTER_H
#define CVC4__THEORY__BV__BITBLAST__LAZY_BITBLASTER_H
-#include "proof/resolution_bitvector_proof.h"
#include "theory/bv/bitblast/bitblaster.h"
#include "context/cdhashmap.h"
@@ -33,7 +32,7 @@ namespace CVC4 {
namespace theory {
namespace bv {
-class TheoryBV;
+class BVSolverLazy;
class TLazyBitblaster : public TBitblaster<Node>
{
@@ -46,7 +45,7 @@ class TLazyBitblaster : public TBitblaster<Node>
bool hasBBAtom(TNode atom) const override;
TLazyBitblaster(context::Context* c,
- TheoryBV* bv,
+ BVSolverLazy* bv,
const std::string name = "",
bool emptyNotify = false);
~TLazyBitblaster();
@@ -73,10 +72,10 @@ class TLazyBitblaster : public TBitblaster<Node>
* 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
+ * @param termSet the set of relevant terms
*/
- bool collectModelInfo(TheoryModel* m, bool fullModel);
+ bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet);
typedef TNodeSet::const_iterator vars_iterator;
vars_iterator beginVars() { return d_variables.begin(); }
@@ -109,11 +108,11 @@ class TLazyBitblaster : public TBitblaster<Node>
class MinisatNotify : public prop::BVSatSolverNotify
{
prop::CnfStream* d_cnf;
- TheoryBV* d_bv;
+ BVSolverLazy* d_bv;
TLazyBitblaster* d_lazyBB;
public:
- MinisatNotify(prop::CnfStream* cnf, TheoryBV* bv, TLazyBitblaster* lbv)
+ MinisatNotify(prop::CnfStream* cnf, BVSolverLazy* bv, TLazyBitblaster* lbv)
: d_cnf(cnf), d_bv(bv), d_lazyBB(lbv)
{
}
@@ -124,7 +123,7 @@ class TLazyBitblaster : public TBitblaster<Node>
void safePoint(ResourceManager::Resource r) override;
};
- TheoryBV* d_bv;
+ BVSolverLazy* d_bv;
context::Context* d_ctx;
std::unique_ptr<prop::NullRegistrar> d_nullRegistrar;
diff --git a/src/theory/bv/bv_eager_solver.cpp b/src/theory/bv/bv_eager_solver.cpp
index 36aa72da3..44dc9555f 100644
--- a/src/theory/bv/bv_eager_solver.cpp
+++ b/src/theory/bv/bv_eager_solver.cpp
@@ -5,7 +5,7 @@
** Mathias Preiner, Liana Hadarean, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -26,15 +26,14 @@ namespace CVC4 {
namespace theory {
namespace bv {
-EagerBitblastSolver::EagerBitblastSolver(context::Context* c, TheoryBV* bv)
+EagerBitblastSolver::EagerBitblastSolver(context::Context* c, BVSolverLazy* bv)
: d_assertionSet(c),
d_assumptionSet(c),
d_context(c),
d_bitblaster(),
d_aigBitblaster(),
d_useAig(options::bitvectorAig()),
- d_bv(bv),
- d_bvp(nullptr)
+ d_bv(bv)
{
}
@@ -55,10 +54,6 @@ void EagerBitblastSolver::initialize() {
#endif
} else {
d_bitblaster.reset(new EagerBitblaster(d_bv, d_context));
- THEORY_PROOF(if (d_bvp) {
- d_bitblaster->setProofLog(d_bvp);
- d_bvp->setBitblaster(d_bitblaster.get());
- });
}
}
@@ -127,11 +122,6 @@ bool EagerBitblastSolver::collectModelInfo(TheoryModel* m, bool fullModel)
return d_bitblaster->collectModelInfo(m, fullModel);
}
-void EagerBitblastSolver::setProofLog(proof::BitVectorProof* bvp)
-{
- d_bvp = bvp;
-}
-
} // namespace bv
} // namespace theory
} // namespace CVC4
diff --git a/src/theory/bv/bv_eager_solver.h b/src/theory/bv/bv_eager_solver.h
index 6182832e9..2cb2df595 100644
--- a/src/theory/bv/bv_eager_solver.h
+++ b/src/theory/bv/bv_eager_solver.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -23,8 +23,7 @@
#include <vector>
#include "expr/node.h"
-#include "proof/resolution_bitvector_proof.h"
-#include "theory/bv/theory_bv.h"
+#include "theory/bv/bv_solver_lazy.h"
#include "theory/theory_model.h"
namespace CVC4 {
@@ -39,7 +38,7 @@ class AigBitblaster;
*/
class EagerBitblastSolver {
public:
- EagerBitblastSolver(context::Context* c, theory::bv::TheoryBV* bv);
+ EagerBitblastSolver(context::Context* c, theory::bv::BVSolverLazy* bv);
~EagerBitblastSolver();
bool checkSat();
void assertFormula(TNode formula);
@@ -48,7 +47,6 @@ class EagerBitblastSolver {
bool isInitialized();
void initialize();
bool collectModelInfo(theory::TheoryModel* m, bool fullModel);
- void setProofLog(proof::BitVectorProof* bvp);
private:
context::CDHashSet<Node, NodeHashFunction> d_assertionSet;
@@ -60,8 +58,7 @@ class EagerBitblastSolver {
std::unique_ptr<AigBitblaster> d_aigBitblaster;
bool d_useAig;
- TheoryBV* d_bv;
- proof::BitVectorProof* d_bvp;
+ BVSolverLazy* d_bv;
}; // class EagerBitblastSolver
} // namespace bv
diff --git a/src/theory/bv/bv_inequality_graph.cpp b/src/theory/bv/bv_inequality_graph.cpp
index 05d6806f8..adc349247 100644
--- a/src/theory/bv/bv_inequality_graph.cpp
+++ b/src/theory/bv/bv_inequality_graph.cpp
@@ -5,7 +5,7 @@
** Liana Hadarean, Aina Niemetz, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/bv/bv_inequality_graph.h b/src/theory/bv/bv_inequality_graph.h
index 77984d217..38e4b3aa6 100644
--- a/src/theory/bv/bv_inequality_graph.h
+++ b/src/theory/bv/bv_inequality_graph.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/bv/bv_quick_check.cpp b/src/theory/bv/bv_quick_check.cpp
index ed445eb33..4b5c800b3 100644
--- a/src/theory/bv/bv_quick_check.cpp
+++ b/src/theory/bv/bv_quick_check.cpp
@@ -2,10 +2,10 @@
/*! \file bv_quick_check.cpp
** \verbatim
** Top contributors (to current version):
- ** Liana Hadarean, Tim King, Morgan Deters
+ ** Liana Hadarean, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,6 +18,7 @@
#include "smt/smt_statistics_registry.h"
#include "theory/bv/bitblast/lazy_bitblaster.h"
+#include "theory/bv/bv_solver_lazy.h"
#include "theory/bv/theory_bv_utils.h"
using namespace CVC4::prop;
@@ -26,11 +27,12 @@ namespace CVC4 {
namespace theory {
namespace bv {
-BVQuickCheck::BVQuickCheck(const std::string& name, theory::bv::TheoryBV* bv)
- : d_ctx()
- , d_bitblaster(new TLazyBitblaster(&d_ctx, bv, name, true))
- , d_conflict()
- , d_inConflict(&d_ctx, false)
+BVQuickCheck::BVQuickCheck(const std::string& name,
+ theory::bv::BVSolverLazy* bv)
+ : d_ctx(),
+ d_bitblaster(new TLazyBitblaster(&d_ctx, bv, name, true)),
+ d_conflict(),
+ d_inConflict(&d_ctx, false)
{}
@@ -138,9 +140,10 @@ void BVQuickCheck::popToZero() {
}
}
-bool BVQuickCheck::collectModelInfo(theory::TheoryModel* model, bool fullModel)
+bool BVQuickCheck::collectModelValues(theory::TheoryModel* model,
+ const std::set<Node>& termSet)
{
- return d_bitblaster->collectModelInfo(model, fullModel);
+ return d_bitblaster->collectModelValues(model, termSet);
}
BVQuickCheck::~BVQuickCheck() {
diff --git a/src/theory/bv/bv_quick_check.h b/src/theory/bv/bv_quick_check.h
index 03a62e41b..c37c3bb14 100644
--- a/src/theory/bv/bv_quick_check.h
+++ b/src/theory/bv/bv_quick_check.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,8 +19,8 @@
#ifndef CVC4__BV_QUICK_CHECK_H
#define CVC4__BV_QUICK_CHECK_H
-#include <vector>
#include <unordered_set>
+#include <vector>
#include "context/cdo.h"
#include "expr/node.h"
@@ -36,43 +36,44 @@ class TheoryModel;
namespace bv {
class TLazyBitblaster;
-class TheoryBV;
+class BVSolverLazy;
-class BVQuickCheck {
+class BVQuickCheck
+{
context::Context d_ctx;
std::unique_ptr<TLazyBitblaster> d_bitblaster;
Node d_conflict;
context::CDO<bool> d_inConflict;
void setConflict();
-public:
- BVQuickCheck(const std::string& name, theory::bv::TheoryBV* bv);
+ public:
+ BVQuickCheck(const std::string& name, theory::bv::BVSolverLazy* bv);
~BVQuickCheck();
bool inConflict();
Node getConflict() { return d_conflict; }
- /**
+ /**
* Checks the satisfiability for a given set of assumptions.
- *
+ *
* @param assumptions literals assumed true
* @param budget max number of conflicts
- *
- * @return
+ *
+ * @return
*/
prop::SatValue checkSat(std::vector<Node>& assumptions, unsigned long budget);
- /**
+ /**
* Checks the satisfiability of given assertions.
- *
+ *
* @param budget max number of conflicts
- *
- * @return
+ *
+ * @return
*/
prop::SatValue checkSat(unsigned long budget);
-
- /**
+
+ /**
* Convert to CNF and assert the given literal.
- *
+ *
* @param assumption bv literal
- *
+ *
* @return false if a conflict has been found via bcp.
*/
bool addAssertion(TNode assumption);
@@ -80,36 +81,38 @@ public:
void push();
void pop();
void popToZero();
- /**
+ /**
* Deletes the SAT solver and CNF stream, but maintains the
- * bit-blasting term cache.
- *
+ * bit-blasting term cache.
+ *
*/
- void clearSolver();
+ void clearSolver();
- /**
+ /**
* Computes the size of the circuit required to bit-blast
- * atom, by not recounting the nodes in seen.
- *
- * @param node
- * @param seen
- *
- * @return
+ * atom, by not recounting the nodes in seen.
+ *
+ * @param node
+ * @param seen
+ *
+ * @return
*/
uint64_t computeAtomWeight(TNode atom, NodeSet& seen);
- bool collectModelInfo(theory::TheoryModel* model, bool fullModel);
-
- typedef std::unordered_set<TNode, TNodeHashFunction>::const_iterator vars_iterator;
- vars_iterator beginVars();
- vars_iterator endVars();
+ bool collectModelValues(theory::TheoryModel* model,
+ const std::set<Node>& termSet);
- Node getVarValue(TNode var, bool fullModel);
+ typedef std::unordered_set<TNode, TNodeHashFunction>::const_iterator
+ vars_iterator;
+ vars_iterator beginVars();
+ vars_iterator endVars();
+ Node getVarValue(TNode var, bool fullModel);
};
-
-class QuickXPlain {
- struct Statistics {
+class QuickXPlain
+{
+ struct Statistics
+ {
TimerStat d_xplainTime;
IntStat d_numSolved;
IntStat d_numUnknown;
@@ -124,52 +127,59 @@ class QuickXPlain {
unsigned long d_budget;
// crazy heuristic variables
- unsigned d_numCalled; // number of times called
- double d_minRatioSum; // sum of minimization ratio for computing average min ratio
- unsigned d_numConflicts; // number of conflicts (including when minimization not applied)
+ unsigned d_numCalled; // number of times called
+ double d_minRatioSum; // sum of minimization ratio for computing average min
+ // ratio
+ unsigned d_numConflicts; // number of conflicts (including when minimization
+ // not applied)
// unsigned d_period; // after how many conflicts to try minimizing again
// double d_thresh; // if minimization ratio is less, increase period
- // double d_hardThresh; // decrease period if minimization ratio is greater than this
-
-
+ // double d_hardThresh; // decrease period if minimization ratio is greater
+ // than this
+
Statistics d_statistics;
- /**
+ /**
* Uses solve with assumptions unsat core feature to
* further minimize a conflict. The minimized conflict
* will be between low and the returned value in conflict.
- *
- * @param low
- * @param high
- * @param conflict
- *
- * @return
+ *
+ * @param low
+ * @param high
+ * @param conflict
+ *
+ * @return
*/
- unsigned selectUnsatCore(unsigned low, unsigned high,
+ unsigned selectUnsatCore(unsigned low,
+ unsigned high,
std::vector<TNode>& conflict);
- /**
+ /**
* Internal conflict minimization, attempts to minimize
* literals in conflict between low and high and adds the
- * result in new_conflict.
- *
- * @param low
- * @param high
- * @param conflict
- * @param new_conflict
+ * result in new_conflict.
+ *
+ * @param low
+ * @param high
+ * @param conflict
+ * @param new_conflict
*/
- void minimizeConflictInternal(unsigned low, unsigned high,
+ void minimizeConflictInternal(unsigned low,
+ unsigned high,
std::vector<TNode>& conflict,
std::vector<TNode>& new_conflict);
bool useHeuristic();
-public:
- QuickXPlain(const std::string& name, BVQuickCheck* solver, unsigned long budged = 10000);
+
+ public:
+ QuickXPlain(const std::string& name,
+ BVQuickCheck* solver,
+ unsigned long budged = 10000);
~QuickXPlain();
- Node minimizeConflict(TNode conflict);
+ Node minimizeConflict(TNode conflict);
};
-} /* bv namespace */
-} /* theory namespace */
-} /* CVC4 namespace */
+} // namespace bv
+} // namespace theory
+} // namespace CVC4
#endif /* CVC4__BV_QUICK_CHECK_H */
diff --git a/src/theory/bv/bv_solver.h b/src/theory/bv/bv_solver.h
new file mode 100644
index 000000000..f4b5a9d11
--- /dev/null
+++ b/src/theory/bv/bv_solver.h
@@ -0,0 +1,122 @@
+/********************* */
+/*! \file bv_solver.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mathias Preiner, Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Bit-vector solver interface.
+ **
+ ** Describes the interface for the internal bit-vector solver of TheoryBV.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__BV__BV_SOLVER_H
+#define CVC4__THEORY__BV__BV_SOLVER_H
+
+#include "theory/theory.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bv {
+
+class BVSolver
+{
+ public:
+ BVSolver(TheoryState& state, TheoryInferenceManager& inferMgr)
+ : d_state(state), d_inferManager(inferMgr){};
+
+ virtual ~BVSolver(){};
+
+ /**
+ * Returns true if we need an equality engine. If so, we initialize the
+ * information regarding how it should be setup. For details, see the
+ * documentation in Theory::needsEqualityEngine.
+ */
+ virtual bool needsEqualityEngine(EeSetupInfo& esi) { return false; }
+
+ virtual void finishInit(){};
+
+ virtual void preRegisterTerm(TNode n) = 0;
+
+ /**
+ * Forwarded from TheoryBV::preCheck().
+ */
+ virtual bool preCheck(Theory::Effort level = Theory::Effort::EFFORT_FULL)
+ {
+ return false;
+ }
+ /**
+ * Forwarded from TheoryBV::postCheck().
+ */
+ virtual void postCheck(Theory::Effort level = Theory::Effort::EFFORT_FULL){};
+ /**
+ * Forwarded from TheoryBV:preNotifyFact().
+ */
+ virtual bool preNotifyFact(
+ TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal)
+ {
+ return false;
+ }
+ /**
+ * Forwarded from TheoryBV::notifyFact().
+ */
+ virtual void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal) {}
+
+ virtual bool needsCheckLastEffort() { return false; }
+
+ virtual void propagate(Theory::Effort e){};
+
+ virtual TrustNode explain(TNode n)
+ {
+ Unimplemented() << "BVSolver propagated a node but doesn't implement the "
+ "BVSolver::explain() interface!";
+ return TrustNode::null();
+ }
+
+ /** Collect model values in m based on the relevant terms given by termSet */
+ virtual bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet) = 0;
+
+ virtual std::string identify() const = 0;
+
+ virtual Theory::PPAssertStatus ppAssert(
+ TrustNode in, TrustSubstitutionMap& outSubstitutions) = 0;
+
+ virtual TrustNode ppRewrite(TNode t) { return TrustNode::null(); };
+
+ virtual void ppStaticLearn(TNode in, NodeBuilder<>& learned){};
+
+ virtual void presolve(){};
+
+ virtual void notifySharedTerm(TNode t) {}
+
+ virtual EqualityStatus getEqualityStatus(TNode a, TNode b)
+ {
+ return EqualityStatus::EQUALITY_UNKNOWN;
+ }
+
+ /** Called by abstraction preprocessing pass. */
+ virtual bool applyAbstraction(const std::vector<Node>& assertions,
+ std::vector<Node>& new_assertions)
+ {
+ new_assertions.insert(
+ new_assertions.end(), assertions.begin(), assertions.end());
+ return false;
+ };
+
+ protected:
+ TheoryState& d_state;
+ TheoryInferenceManager& d_inferManager;
+};
+
+} // namespace bv
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__BV__BV_SOLVER_H */
diff --git a/src/theory/bv/bv_solver_lazy.cpp b/src/theory/bv/bv_solver_lazy.cpp
new file mode 100644
index 000000000..a19af44ac
--- /dev/null
+++ b/src/theory/bv/bv_solver_lazy.cpp
@@ -0,0 +1,830 @@
+/********************* */
+/*! \file bv_solver_lazy.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mathias Preiner, Liana Hadarean, Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** [[ Add lengthier description here ]]
+ ** \todo document this file
+ **/
+
+#include "theory/bv/bv_solver_lazy.h"
+
+#include "expr/node_algorithm.h"
+#include "options/bv_options.h"
+#include "options/smt_options.h"
+#include "smt/smt_statistics_registry.h"
+#include "theory/bv/abstraction.h"
+#include "theory/bv/bv_eager_solver.h"
+#include "theory/bv/bv_subtheory_algebraic.h"
+#include "theory/bv/bv_subtheory_bitblast.h"
+#include "theory/bv/bv_subtheory_core.h"
+#include "theory/bv/bv_subtheory_inequality.h"
+#include "theory/bv/theory_bv_rewrite_rules_normalization.h"
+#include "theory/bv/theory_bv_rewrite_rules_simplification.h"
+#include "theory/bv/theory_bv_rewriter.h"
+#include "theory/bv/theory_bv_utils.h"
+#include "theory/theory_model.h"
+
+using namespace CVC4::theory::bv::utils;
+
+namespace CVC4 {
+namespace theory {
+namespace bv {
+
+BVSolverLazy::BVSolverLazy(TheoryBV& bv,
+ context::Context* c,
+ context::UserContext* u,
+ ProofNodeManager* pnm,
+ std::string name)
+ : BVSolver(bv.d_state, bv.d_inferMgr),
+ d_bv(bv),
+ d_context(c),
+ d_alreadyPropagatedSet(c),
+ d_sharedTermsSet(c),
+ d_subtheories(),
+ d_subtheoryMap(),
+ d_statistics(),
+ d_staticLearnCache(),
+ d_lemmasAdded(c, false),
+ d_conflict(c, false),
+ d_invalidateModelCache(c, true),
+ d_literalsToPropagate(c),
+ d_literalsToPropagateIndex(c, 0),
+ d_propagatedBy(c),
+ d_eagerSolver(),
+ d_abstractionModule(new AbstractionModule(getStatsPrefix(THEORY_BV))),
+ d_calledPreregister(false)
+{
+ if (options::bitblastMode() == options::BitblastMode::EAGER)
+ {
+ d_eagerSolver.reset(new EagerBitblastSolver(c, this));
+ return;
+ }
+
+ if (options::bitvectorEqualitySolver())
+ {
+ d_subtheories.emplace_back(new CoreSolver(c, this));
+ d_subtheoryMap[SUB_CORE] = d_subtheories.back().get();
+ }
+
+ if (options::bitvectorInequalitySolver())
+ {
+ d_subtheories.emplace_back(new InequalitySolver(c, u, this));
+ d_subtheoryMap[SUB_INEQUALITY] = d_subtheories.back().get();
+ }
+
+ if (options::bitvectorAlgebraicSolver())
+ {
+ d_subtheories.emplace_back(new AlgebraicSolver(c, this));
+ d_subtheoryMap[SUB_ALGEBRAIC] = d_subtheories.back().get();
+ }
+
+ BitblastSolver* bb_solver = new BitblastSolver(c, this);
+ if (options::bvAbstraction())
+ {
+ bb_solver->setAbstraction(d_abstractionModule.get());
+ }
+ d_subtheories.emplace_back(bb_solver);
+ d_subtheoryMap[SUB_BITBLAST] = bb_solver;
+}
+
+BVSolverLazy::~BVSolverLazy() {}
+
+bool BVSolverLazy::needsEqualityEngine(EeSetupInfo& esi)
+{
+ CoreSolver* core = (CoreSolver*)d_subtheoryMap[SUB_CORE];
+ if (core)
+ {
+ return core->needsEqualityEngine(esi);
+ }
+ // otherwise we don't use an equality engine
+ return false;
+}
+
+void BVSolverLazy::finishInit()
+{
+ CoreSolver* core = (CoreSolver*)d_subtheoryMap[SUB_CORE];
+ if (core)
+ {
+ // must finish initialization in the core solver
+ core->finishInit();
+ }
+}
+
+void BVSolverLazy::spendResource(ResourceManager::Resource r)
+{
+ d_inferManager.spendResource(r);
+}
+
+BVSolverLazy::Statistics::Statistics()
+ : d_avgConflictSize("theory::bv::lazy::AvgBVConflictSize"),
+ d_solveSubstitutions("theory::bv::lazy::NumSolveSubstitutions", 0),
+ d_solveTimer("theory::bv::lazy::solveTimer"),
+ d_numCallsToCheckFullEffort("theory::bv::lazy::NumFullCheckCalls", 0),
+ d_numCallsToCheckStandardEffort("theory::bv::lazy::NumStandardCheckCalls",
+ 0),
+ d_weightComputationTimer("theory::bv::lazy::weightComputationTimer"),
+ d_numMultSlice("theory::bv::lazy::NumMultSliceApplied", 0)
+{
+ smtStatisticsRegistry()->registerStat(&d_avgConflictSize);
+ smtStatisticsRegistry()->registerStat(&d_solveSubstitutions);
+ smtStatisticsRegistry()->registerStat(&d_solveTimer);
+ smtStatisticsRegistry()->registerStat(&d_numCallsToCheckFullEffort);
+ smtStatisticsRegistry()->registerStat(&d_numCallsToCheckStandardEffort);
+ smtStatisticsRegistry()->registerStat(&d_weightComputationTimer);
+ smtStatisticsRegistry()->registerStat(&d_numMultSlice);
+}
+
+BVSolverLazy::Statistics::~Statistics()
+{
+ smtStatisticsRegistry()->unregisterStat(&d_avgConflictSize);
+ smtStatisticsRegistry()->unregisterStat(&d_solveSubstitutions);
+ smtStatisticsRegistry()->unregisterStat(&d_solveTimer);
+ smtStatisticsRegistry()->unregisterStat(&d_numCallsToCheckFullEffort);
+ smtStatisticsRegistry()->unregisterStat(&d_numCallsToCheckStandardEffort);
+ smtStatisticsRegistry()->unregisterStat(&d_weightComputationTimer);
+ smtStatisticsRegistry()->unregisterStat(&d_numMultSlice);
+}
+
+void BVSolverLazy::preRegisterTerm(TNode node)
+{
+ d_calledPreregister = true;
+ Debug("bitvector-preregister")
+ << "BVSolverLazy::preRegister(" << node << ")" << std::endl;
+
+ if (options::bitblastMode() == options::BitblastMode::EAGER)
+ {
+ // the aig bit-blaster option is set heuristically
+ // if bv abstraction is used
+ if (!d_eagerSolver->isInitialized())
+ {
+ d_eagerSolver->initialize();
+ }
+
+ if (node.getKind() == kind::BITVECTOR_EAGER_ATOM)
+ {
+ Node formula = node[0];
+ d_eagerSolver->assertFormula(formula);
+ }
+ return;
+ }
+
+ for (unsigned i = 0; i < d_subtheories.size(); ++i)
+ {
+ d_subtheories[i]->preRegister(node);
+ }
+
+ // AJR : equality solver currently registers all terms to ExtTheory, if we
+ // want a lazy reduction without the bv equality solver, need to call this
+ // d_bv.d_extTheory->registerTermRec( node );
+}
+
+void BVSolverLazy::sendConflict()
+{
+ Assert(d_conflict);
+ if (d_conflictNode.isNull())
+ {
+ return;
+ }
+ else
+ {
+ Debug("bitvector") << indent() << "BVSolverLazy::check(): conflict "
+ << d_conflictNode << std::endl;
+ d_inferManager.conflict(d_conflictNode);
+ d_statistics.d_avgConflictSize.addEntry(d_conflictNode.getNumChildren());
+ d_conflictNode = Node::null();
+ }
+}
+
+void BVSolverLazy::checkForLemma(TNode fact)
+{
+ if (fact.getKind() == kind::EQUAL)
+ {
+ NodeManager* nm = NodeManager::currentNM();
+ if (fact[0].getKind() == kind::BITVECTOR_UREM_TOTAL)
+ {
+ TNode urem = fact[0];
+ TNode result = fact[1];
+ TNode divisor = urem[1];
+ Node result_ult_div = nm->mkNode(kind::BITVECTOR_ULT, result, divisor);
+ Node divisor_eq_0 =
+ nm->mkNode(kind::EQUAL, divisor, mkZero(getSize(divisor)));
+ Node split = nm->mkNode(
+ kind::OR, divisor_eq_0, nm->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];
+ Node result_ult_div = nm->mkNode(kind::BITVECTOR_ULT, result, divisor);
+ Node divisor_eq_0 =
+ nm->mkNode(kind::EQUAL, divisor, mkZero(getSize(divisor)));
+ Node split = nm->mkNode(
+ kind::OR, divisor_eq_0, nm->mkNode(kind::NOT, fact), result_ult_div);
+ lemma(split);
+ }
+ }
+}
+
+bool BVSolverLazy::preCheck(Theory::Effort e)
+{
+ check(e);
+ return true;
+}
+
+void BVSolverLazy::check(Theory::Effort e)
+{
+ if (done() && e < Theory::EFFORT_FULL)
+ {
+ return;
+ }
+
+ // last call : do reductions on extended bitvector functions
+ if (e == Theory::EFFORT_LAST_CALL)
+ {
+ CoreSolver* core = (CoreSolver*)d_subtheoryMap[SUB_CORE];
+ if (core)
+ {
+ // check extended functions at last call effort
+ core->checkExtf(e);
+ }
+ return;
+ }
+
+ Debug("bitvector") << "BVSolverLazy::check(" << e << ")" << std::endl;
+ TimerStat::CodeTimer codeTimer(d_statistics.d_solveTimer);
+ // we may be getting new assertions so the model cache may not be sound
+ d_invalidateModelCache.set(true);
+ // if we are using the eager solver
+ if (options::bitblastMode() == options::BitblastMode::EAGER)
+ {
+ // this can only happen on an empty benchmark
+ if (!d_eagerSolver->isInitialized())
+ {
+ d_eagerSolver->initialize();
+ }
+ if (!Theory::fullEffort(e)) return;
+
+ std::vector<TNode> assertions;
+ while (!done())
+ {
+ TNode fact = get().d_assertion;
+ Assert(fact.getKind() == kind::BITVECTOR_EAGER_ATOM);
+ assertions.push_back(fact);
+ d_eagerSolver->assertFormula(fact[0]);
+ }
+
+ bool ok = d_eagerSolver->checkSat();
+ if (!ok)
+ {
+ if (assertions.size() == 1)
+ {
+ d_inferManager.conflict(assertions[0]);
+ return;
+ }
+ Node conflict = utils::mkAnd(assertions);
+ d_inferManager.conflict(conflict);
+ return;
+ }
+ return;
+ }
+
+ if (Theory::fullEffort(e))
+ {
+ ++(d_statistics.d_numCallsToCheckFullEffort);
+ }
+ else
+ {
+ ++(d_statistics.d_numCallsToCheckStandardEffort);
+ }
+ // if we are already in conflict just return the conflict
+ if (inConflict())
+ {
+ sendConflict();
+ return;
+ }
+
+ while (!done())
+ {
+ TNode fact = get().d_assertion;
+
+ checkForLemma(fact);
+
+ for (unsigned i = 0; i < d_subtheories.size(); ++i)
+ {
+ d_subtheories[i]->assertFact(fact);
+ }
+ }
+
+ bool ok = true;
+ bool complete = false;
+ for (unsigned i = 0; i < d_subtheories.size(); ++i)
+ {
+ Assert(!inConflict());
+ ok = d_subtheories[i]->check(e);
+ complete = d_subtheories[i]->isComplete();
+
+ if (!ok)
+ {
+ // if we are in a conflict no need to check with other theories
+ Assert(inConflict());
+ sendConflict();
+ return;
+ }
+ if (complete)
+ {
+ // if the last subtheory was complete we stop
+ break;
+ }
+ }
+
+ // check extended functions
+ if (Theory::fullEffort(e))
+ {
+ CoreSolver* core = (CoreSolver*)d_subtheoryMap[SUB_CORE];
+ if (core)
+ {
+ // check extended functions at full effort
+ core->checkExtf(e);
+ }
+ }
+}
+
+bool BVSolverLazy::needsCheckLastEffort()
+{
+ CoreSolver* core = (CoreSolver*)d_subtheoryMap[SUB_CORE];
+ if (core)
+ {
+ return core->needsCheckLastEffort();
+ }
+ return false;
+}
+
+bool BVSolverLazy::collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet)
+{
+ Assert(!inConflict());
+ if (options::bitblastMode() == options::BitblastMode::EAGER)
+ {
+ if (!d_eagerSolver->collectModelInfo(m, true))
+ {
+ return false;
+ }
+ }
+ for (unsigned i = 0; i < d_subtheories.size(); ++i)
+ {
+ if (d_subtheories[i]->isComplete())
+ {
+ return d_subtheories[i]->collectModelValues(m, termSet);
+ }
+ }
+ return true;
+}
+
+Node BVSolverLazy::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);
+ }
+ }
+ Unreachable();
+}
+
+void BVSolverLazy::propagate(Theory::Effort e)
+{
+ Debug("bitvector") << indent() << "BVSolverLazy::propagate()" << std::endl;
+ if (options::bitblastMode() == options::BitblastMode::EAGER)
+ {
+ return;
+ }
+
+ if (inConflict())
+ {
+ return;
+ }
+
+ // go through stored propagations
+ 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
+ if (d_state.isSatLiteral(literal))
+ {
+ Debug("bitvector::propagate")
+ << "BVSolverLazy:: propagating " << literal << "\n";
+ ok = d_inferManager.propagateLit(literal);
+ }
+ }
+
+ if (!ok)
+ {
+ Debug("bitvector::propagate")
+ << indent() << "BVSolverLazy::propagate(): conflict from theory engine"
+ << std::endl;
+ setConflict();
+ }
+}
+
+Theory::PPAssertStatus BVSolverLazy::ppAssert(
+ TrustNode tin, TrustSubstitutionMap& outSubstitutions)
+{
+ TNode in = tin.getNode();
+ switch (in.getKind())
+ {
+ case kind::EQUAL:
+ {
+ if (in[0].isVar() && d_bv.isLegalElimination(in[0], in[1]))
+ {
+ ++(d_statistics.d_solveSubstitutions);
+ outSubstitutions.addSubstitutionSolved(in[0], in[1], tin);
+ return Theory::PP_ASSERT_STATUS_SOLVED;
+ }
+ if (in[1].isVar() && d_bv.isLegalElimination(in[1], in[0]))
+ {
+ ++(d_statistics.d_solveSubstitutions);
+ outSubstitutions.addSubstitutionSolved(in[1], in[0], tin);
+ return Theory::PP_ASSERT_STATUS_SOLVED;
+ }
+ Node node = Rewriter::rewrite(in);
+ if ((node[0].getKind() == kind::BITVECTOR_EXTRACT && node[1].isConst())
+ || (node[1].getKind() == kind::BITVECTOR_EXTRACT
+ && node[0].isConst()))
+ {
+ Node extract = node[0].isConst() ? node[1] : node[0];
+ if (extract[0].isVar())
+ {
+ Node c = node[0].isConst() ? node[0] : node[1];
+
+ unsigned high = utils::getExtractHigh(extract);
+ unsigned low = utils::getExtractLow(extract);
+ unsigned var_bitwidth = utils::getSize(extract[0]);
+ std::vector<Node> children;
+
+ if (low == 0)
+ {
+ Assert(high != var_bitwidth - 1);
+ unsigned skolem_size = var_bitwidth - high - 1;
+ Node skolem = utils::mkVar(skolem_size);
+ children.push_back(skolem);
+ children.push_back(c);
+ }
+ else if (high == var_bitwidth - 1)
+ {
+ unsigned skolem_size = low;
+ Node skolem = utils::mkVar(skolem_size);
+ children.push_back(c);
+ children.push_back(skolem);
+ }
+ else
+ {
+ unsigned skolem1_size = low;
+ unsigned skolem2_size = var_bitwidth - high - 1;
+ Node skolem1 = utils::mkVar(skolem1_size);
+ Node skolem2 = utils::mkVar(skolem2_size);
+ children.push_back(skolem2);
+ children.push_back(c);
+ children.push_back(skolem1);
+ }
+ Node concat = utils::mkConcat(children);
+ Assert(utils::getSize(concat) == utils::getSize(extract[0]));
+ if (d_bv.isLegalElimination(extract[0], concat))
+ {
+ outSubstitutions.addSubstitutionSolved(extract[0], concat, tin);
+ return Theory::PP_ASSERT_STATUS_SOLVED;
+ }
+ }
+ }
+ }
+ break;
+ case kind::BITVECTOR_ULT:
+ case kind::BITVECTOR_SLT:
+ case kind::BITVECTOR_ULE:
+ case kind::BITVECTOR_SLE:
+
+ default:
+ // TODO other predicates
+ break;
+ }
+ return Theory::PP_ASSERT_STATUS_UNSOLVED;
+}
+
+TrustNode BVSolverLazy::ppRewrite(TNode t)
+{
+ Debug("bv-pp-rewrite") << "BVSolverLazy::ppRewrite " << t << "\n";
+ Node res = t;
+ if (options::bitwiseEq() && RewriteRule<BitwiseEq>::applies(t))
+ {
+ Node result = RewriteRule<BitwiseEq>::run<false>(t);
+ res = Rewriter::rewrite(result);
+ }
+ else if (RewriteRule<UltPlusOne>::applies(t))
+ {
+ Node result = RewriteRule<UltPlusOne>::run<false>(t);
+ res = Rewriter::rewrite(result);
+ }
+ else if (res.getKind() == kind::EQUAL
+ && ((res[0].getKind() == kind::BITVECTOR_PLUS
+ && RewriteRule<ConcatToMult>::applies(res[1]))
+ || (res[1].getKind() == kind::BITVECTOR_PLUS
+ && RewriteRule<ConcatToMult>::applies(res[0]))))
+ {
+ Node mult = RewriteRule<ConcatToMult>::applies(res[0])
+ ? RewriteRule<ConcatToMult>::run<false>(res[0])
+ : RewriteRule<ConcatToMult>::run<true>(res[1]);
+ Node factor = mult[0];
+ Node sum = RewriteRule<ConcatToMult>::applies(res[0]) ? res[1] : res[0];
+ Node new_eq = NodeManager::currentNM()->mkNode(kind::EQUAL, sum, mult);
+ Node rewr_eq = RewriteRule<SolveEq>::run<true>(new_eq);
+ if (rewr_eq[0].isVar() || rewr_eq[1].isVar())
+ {
+ res = Rewriter::rewrite(rewr_eq);
+ }
+ else
+ {
+ res = t;
+ }
+ }
+ else if (RewriteRule<SignExtendEqConst>::applies(t))
+ {
+ res = RewriteRule<SignExtendEqConst>::run<false>(t);
+ }
+ else if (RewriteRule<ZeroExtendEqConst>::applies(t))
+ {
+ res = RewriteRule<ZeroExtendEqConst>::run<false>(t);
+ }
+ else if (RewriteRule<NormalizeEqPlusNeg>::applies(t))
+ {
+ res = RewriteRule<NormalizeEqPlusNeg>::run<false>(t);
+ }
+
+ // if(t.getKind() == kind::EQUAL &&
+ // ((t[0].getKind() == kind::BITVECTOR_MULT && t[1].getKind() ==
+ // kind::BITVECTOR_PLUS) ||
+ // (t[1].getKind() == kind::BITVECTOR_MULT && t[0].getKind() ==
+ // kind::BITVECTOR_PLUS))) {
+ // // if we have an equality between a multiplication and addition
+ // // try to express multiplication in terms of addition
+ // Node mult = t[0].getKind() == kind::BITVECTOR_MULT? t[0] : t[1];
+ // Node add = t[0].getKind() == kind::BITVECTOR_PLUS? t[0] : t[1];
+ // if (RewriteRule<MultSlice>::applies(mult)) {
+ // Node new_mult = RewriteRule<MultSlice>::run<false>(mult);
+ // Node new_eq =
+ // Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::EQUAL,
+ // new_mult, add));
+
+ // // the simplification can cause the formula to blow up
+ // // only apply if formula reduced
+ // if (d_subtheoryMap.find(SUB_BITBLAST) != d_subtheoryMap.end()) {
+ // BitblastSolver* bv = (BitblastSolver*)d_subtheoryMap[SUB_BITBLAST];
+ // uint64_t old_size = bv->computeAtomWeight(t);
+ // Assert (old_size);
+ // uint64_t new_size = bv->computeAtomWeight(new_eq);
+ // double ratio = ((double)new_size)/old_size;
+ // if (ratio <= 0.4) {
+ // ++(d_statistics.d_numMultSlice);
+ // return new_eq;
+ // }
+ // }
+
+ // if (new_eq.getKind() == kind::CONST_BOOLEAN) {
+ // ++(d_statistics.d_numMultSlice);
+ // return new_eq;
+ // }
+ // }
+ // }
+
+ if (options::bvAbstraction() && t.getType().isBoolean())
+ {
+ d_abstractionModule->addInputAtom(res);
+ }
+ Debug("bv-pp-rewrite") << "to " << res << "\n";
+ if (res != t)
+ {
+ return TrustNode::mkTrustRewrite(t, res, nullptr);
+ }
+ return TrustNode::null();
+}
+
+void BVSolverLazy::presolve()
+{
+ Debug("bitvector") << "BVSolverLazy::presolve" << std::endl;
+}
+
+static int prop_count = 0;
+
+bool BVSolverLazy::storePropagation(TNode literal, SubTheory subtheory)
+{
+ Debug("bitvector::propagate") << indent() << d_context->getLevel() << " "
+ << "BVSolverLazy::storePropagation(" << literal
+ << ", " << subtheory << ")" << std::endl;
+ prop_count++;
+
+ // If already in conflict, no more propagation
+ if (d_conflict)
+ {
+ Debug("bitvector::propagate")
+ << indent() << "BVSolverLazy::storePropagation(" << literal << ", "
+ << subtheory << "): already in conflict" << std::endl;
+ return false;
+ }
+
+ // If propagated already, just skip
+ PropagatedMap::const_iterator find = d_propagatedBy.find(literal);
+ if (find != d_propagatedBy.end())
+ {
+ return true;
+ }
+ else
+ {
+ bool polarity = literal.getKind() != kind::NOT;
+ Node negatedLiteral = polarity ? literal.notNode() : (Node)literal[0];
+ find = d_propagatedBy.find(negatedLiteral);
+ if (find != d_propagatedBy.end() && (*find).second != subtheory)
+ {
+ // Safe to ignore this one, subtheory should produce a conflict
+ return true;
+ }
+
+ d_propagatedBy[literal] = subtheory;
+ }
+
+ // Propagate differs depending on the subtheory
+ // * bitblaster needs to be left alone until it's done, otherwise it doesn't
+ // know how to explain
+ // * equality engine can propagate eagerly
+ // TODO(2348): Determine if ok should be set by propagate. If not, remove ok.
+ constexpr bool ok = true;
+ if (subtheory == SUB_CORE)
+ {
+ d_inferManager.propagateLit(literal);
+ if (!ok)
+ {
+ setConflict();
+ }
+ }
+ else
+ {
+ d_literalsToPropagate.push_back(literal);
+ }
+ return ok;
+
+} /* BVSolverLazy::propagate(TNode) */
+
+void BVSolverLazy::explain(TNode literal, std::vector<TNode>& assumptions)
+{
+ Assert(wasPropagatedBySubtheory(literal));
+ SubTheory sub = getPropagatingSubtheory(literal);
+ d_subtheoryMap[sub]->explain(literal, assumptions);
+}
+
+TrustNode BVSolverLazy::explain(TNode node)
+{
+ Debug("bitvector::explain")
+ << "BVSolverLazy::explain(" << node << ")" << std::endl;
+ std::vector<TNode> assumptions;
+
+ // Ask for the explanation
+ explain(node, assumptions);
+ // this means that it is something true at level 0
+ Node explanation;
+ if (assumptions.size() == 0)
+ {
+ explanation = utils::mkTrue();
+ }
+ else
+ {
+ // return the explanation
+ explanation = utils::mkAnd(assumptions);
+ }
+ Debug("bitvector::explain") << "BVSolverLazy::explain(" << node << ") => "
+ << explanation << std::endl;
+ Debug("bitvector::explain") << "BVSolverLazy::explain done. \n";
+ return TrustNode::mkTrustPropExp(node, explanation, nullptr);
+}
+
+void BVSolverLazy::notifySharedTerm(TNode t)
+{
+ Debug("bitvector::sharing")
+ << indent() << "BVSolverLazy::notifySharedTerm(" << t << ")" << std::endl;
+ d_sharedTermsSet.insert(t);
+}
+
+EqualityStatus BVSolverLazy::getEqualityStatus(TNode a, TNode b)
+{
+ if (options::bitblastMode() == options::BitblastMode::EAGER)
+ return EQUALITY_UNKNOWN;
+ Assert(options::bitblastMode() == options::BitblastMode::LAZY);
+ for (unsigned i = 0; i < d_subtheories.size(); ++i)
+ {
+ EqualityStatus status = d_subtheories[i]->getEqualityStatus(a, b);
+ if (status != EQUALITY_UNKNOWN)
+ {
+ return status;
+ }
+ }
+ return EQUALITY_UNKNOWN;
+ ;
+}
+
+void BVSolverLazy::ppStaticLearn(TNode in, NodeBuilder<>& learned)
+{
+ if (d_staticLearnCache.find(in) != d_staticLearnCache.end())
+ {
+ return;
+ }
+ d_staticLearnCache.insert(in);
+
+ if (in.getKind() == kind::EQUAL)
+ {
+ if ((in[0].getKind() == kind::BITVECTOR_PLUS
+ && in[1].getKind() == kind::BITVECTOR_SHL)
+ || (in[1].getKind() == kind::BITVECTOR_PLUS
+ && in[0].getKind() == kind::BITVECTOR_SHL))
+ {
+ TNode p = in[0].getKind() == kind::BITVECTOR_PLUS ? in[0] : in[1];
+ TNode s = in[0].getKind() == kind::BITVECTOR_PLUS ? in[1] : in[0];
+
+ if (p.getNumChildren() == 2 && p[0].getKind() == kind::BITVECTOR_SHL
+ && p[1].getKind() == kind::BITVECTOR_SHL)
+ {
+ unsigned size = utils::getSize(s);
+ Node one = utils::mkConst(size, 1u);
+ if (s[0] == one && p[0][0] == one && p[1][0] == one)
+ {
+ Node zero = utils::mkConst(size, 0u);
+ TNode b = p[0];
+ TNode c = p[1];
+ // (s : 1 << S) = (b : 1 << B) + (c : 1 << C)
+ Node b_eq_0 = b.eqNode(zero);
+ Node c_eq_0 = c.eqNode(zero);
+ Node b_eq_c = b.eqNode(c);
+
+ Node dis = NodeManager::currentNM()->mkNode(
+ kind::OR, b_eq_0, c_eq_0, b_eq_c);
+ Node imp = in.impNode(dis);
+ learned << imp;
+ }
+ }
+ }
+ }
+ else if (in.getKind() == kind::AND)
+ {
+ for (size_t i = 0, N = in.getNumChildren(); i < N; ++i)
+ {
+ ppStaticLearn(in[i], learned);
+ }
+ }
+}
+
+bool BVSolverLazy::applyAbstraction(const std::vector<Node>& assertions,
+ std::vector<Node>& new_assertions)
+{
+ bool changed =
+ d_abstractionModule->applyAbstraction(assertions, new_assertions);
+ if (changed && options::bitblastMode() == options::BitblastMode::EAGER
+ && options::bitvectorAig())
+ {
+ // disable AIG mode
+ AlwaysAssert(!d_eagerSolver->isInitialized());
+ d_eagerSolver->turnOffAig();
+ d_eagerSolver->initialize();
+ }
+ return changed;
+}
+
+void BVSolverLazy::setConflict(Node conflict)
+{
+ if (options::bvAbstraction())
+ {
+ NodeManager* const nm = NodeManager::currentNM();
+ Node new_conflict = d_abstractionModule->simplifyConflict(conflict);
+
+ std::vector<Node> lemmas;
+ lemmas.push_back(new_conflict);
+ d_abstractionModule->generalizeConflict(new_conflict, lemmas);
+ for (unsigned i = 0; i < lemmas.size(); ++i)
+ {
+ lemma(nm->mkNode(kind::NOT, lemmas[i]));
+ }
+ }
+ d_conflict = true;
+ d_conflictNode = conflict;
+}
+
+} // namespace bv
+} // namespace theory
+} /* namespace CVC4 */
diff --git a/src/theory/bv/bv_solver_lazy.h b/src/theory/bv/bv_solver_lazy.h
new file mode 100644
index 000000000..6885dbba4
--- /dev/null
+++ b/src/theory/bv/bv_solver_lazy.h
@@ -0,0 +1,234 @@
+/********************* */
+/*! \file bv_solver_lazy.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mathias Preiner, Liana Hadarean, Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Lazy bit-vector solver.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__BV__BV_SOLVER_LAZY_H
+#define CVC4__THEORY__BV__BV_SOLVER_LAZY_H
+
+#include <unordered_map>
+#include <unordered_set>
+
+#include "context/cdhashset.h"
+#include "context/cdlist.h"
+#include "context/context.h"
+#include "theory/bv/bv_solver.h"
+#include "theory/bv/bv_subtheory.h"
+#include "theory/bv/theory_bv.h"
+#include "util/hash.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bv {
+
+class CoreSolver;
+class InequalitySolver;
+class AlgebraicSolver;
+class BitblastSolver;
+class EagerBitblastSolver;
+class AbstractionModule;
+
+class BVSolverLazy : public BVSolver
+{
+ /** Back reference to TheoryBV */
+ TheoryBV& d_bv;
+
+ /** The context we are using */
+ context::Context* d_context;
+
+ /** Context dependent set of atoms we already propagated */
+ context::CDHashSet<Node, NodeHashFunction> d_alreadyPropagatedSet;
+ context::CDHashSet<Node, NodeHashFunction> d_sharedTermsSet;
+
+ std::vector<std::unique_ptr<SubtheorySolver>> d_subtheories;
+ std::unordered_map<SubTheory, SubtheorySolver*, std::hash<int>>
+ d_subtheoryMap;
+
+ public:
+ BVSolverLazy(TheoryBV& bv,
+ context::Context* c,
+ context::UserContext* u,
+ ProofNodeManager* pnm = nullptr,
+ std::string name = "");
+
+ ~BVSolverLazy();
+
+ //--------------------------------- initialization
+
+ /**
+ * Returns true if we need an equality engine. If so, we initialize the
+ * information regarding how it should be setup. For details, see the
+ * documentation in Theory::needsEqualityEngine.
+ */
+ bool needsEqualityEngine(EeSetupInfo& esi) override;
+
+ /** finish initialization */
+ void finishInit() override;
+ //--------------------------------- end initialization
+
+ void preRegisterTerm(TNode n) override;
+
+ bool preCheck(Theory::Effort e) override;
+
+ bool needsCheckLastEffort() override;
+
+ void propagate(Theory::Effort e) override;
+
+ TrustNode explain(TNode n) override;
+
+ bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet) override;
+
+ std::string identify() const override { return std::string("BVSolverLazy"); }
+
+ Theory::PPAssertStatus ppAssert(
+ TrustNode tin, TrustSubstitutionMap& outSubstitutions) override;
+
+ TrustNode ppRewrite(TNode t) override;
+
+ void ppStaticLearn(TNode in, NodeBuilder<>& learned) override;
+
+ void presolve() override;
+
+ bool applyAbstraction(const std::vector<Node>& assertions,
+ std::vector<Node>& new_assertions) override;
+
+ bool isLeaf(TNode node) { return d_bv.isLeaf(node); }
+
+ private:
+ class Statistics
+ {
+ public:
+ AverageStat d_avgConflictSize;
+ IntStat d_solveSubstitutions;
+ TimerStat d_solveTimer;
+ IntStat d_numCallsToCheckFullEffort;
+ IntStat d_numCallsToCheckStandardEffort;
+ TimerStat d_weightComputationTimer;
+ IntStat d_numMultSlice;
+ Statistics();
+ ~Statistics();
+ };
+
+ Statistics d_statistics;
+
+ void check(Theory::Effort e);
+ void spendResource(ResourceManager::Resource r);
+
+ typedef std::unordered_set<TNode, TNodeHashFunction> TNodeSet;
+ typedef std::unordered_set<Node, NodeHashFunction> NodeSet;
+ NodeSet d_staticLearnCache;
+
+ typedef std::unordered_map<Node, Node, NodeHashFunction> NodeToNode;
+
+ context::CDO<bool> d_lemmasAdded;
+
+ // Are we in conflict?
+ context::CDO<bool> d_conflict;
+
+ // Invalidate the model cache if check was called
+ context::CDO<bool> d_invalidateModelCache;
+
+ /** The conflict node */
+ Node d_conflictNode;
+
+ /** Literals to propagate */
+ context::CDList<Node> d_literalsToPropagate;
+
+ /** Index of the next literal to propagate */
+ context::CDO<unsigned> d_literalsToPropagateIndex;
+
+ /**
+ * Keeps a map from nodes to the subtheory that propagated it so that we can
+ * explain it properly.
+ */
+ typedef context::CDHashMap<Node, SubTheory, NodeHashFunction> PropagatedMap;
+ PropagatedMap d_propagatedBy;
+
+ std::unique_ptr<EagerBitblastSolver> d_eagerSolver;
+ std::unique_ptr<AbstractionModule> d_abstractionModule;
+ bool d_calledPreregister;
+
+ bool wasPropagatedBySubtheory(TNode literal) const
+ {
+ return d_propagatedBy.find(literal) != d_propagatedBy.end();
+ }
+
+ SubTheory getPropagatingSubtheory(TNode literal) const
+ {
+ Assert(wasPropagatedBySubtheory(literal));
+ PropagatedMap::const_iterator find = d_propagatedBy.find(literal);
+ return (*find).second;
+ }
+
+ /** Should be called to propagate the literal. */
+ bool storePropagation(TNode literal, SubTheory subtheory);
+
+ /**
+ * Explains why this literal (propagated by subtheory) is true by adding
+ * assumptions.
+ */
+ void explain(TNode literal, std::vector<TNode>& assumptions);
+
+ void notifySharedTerm(TNode t) override;
+
+ bool isSharedTerm(TNode t) { return d_sharedTermsSet.contains(t); }
+
+ EqualityStatus getEqualityStatus(TNode a, TNode b) override;
+
+ Node getModelValue(TNode var);
+
+ inline std::string indent()
+ {
+ std::string indentStr(d_context->getLevel(), ' ');
+ return indentStr;
+ }
+
+ void setConflict(Node conflict = Node::null());
+
+ bool inConflict() { return d_conflict; }
+
+ void sendConflict();
+
+ void lemma(TNode node)
+ {
+ d_inferManager.lemma(node);
+ d_lemmasAdded = true;
+ }
+
+ void checkForLemma(TNode node);
+
+ size_t numAssertions() { return d_bv.numAssertions(); }
+
+ theory::Assertion get() { return d_bv.get(); }
+
+ bool done() { return d_bv.done(); }
+
+ friend class LazyBitblaster;
+ friend class TLazyBitblaster;
+ friend class EagerBitblaster;
+ friend class BitblastSolver;
+ friend class EqualitySolver;
+ friend class CoreSolver;
+ friend class InequalitySolver;
+ friend class AlgebraicSolver;
+ friend class EagerBitblastSolver;
+}; /* class BVSolverLazy */
+
+} // namespace bv
+} // namespace theory
+
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__BV__BV_SOLVER_LAZY_H */
diff --git a/src/theory/bv/bv_solver_simple.cpp b/src/theory/bv/bv_solver_simple.cpp
new file mode 100644
index 000000000..e03feedfc
--- /dev/null
+++ b/src/theory/bv/bv_solver_simple.cpp
@@ -0,0 +1,296 @@
+/********************* */
+/*! \file bv_solver_simple.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mathias Preiner
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Simple bit-blast solver
+ **
+ ** Simple bit-blast solver that sends bitblast lemmas directly to MiniSat.
+ **/
+
+#include "theory/bv/bv_solver_simple.h"
+
+#include "theory/bv/bitblast/lazy_bitblaster.h"
+#include "theory/bv/theory_bv.h"
+#include "theory/bv/theory_bv_utils.h"
+#include "theory/theory_model.h"
+
+namespace CVC4 {
+namespace theory {
+namespace bv {
+
+/**
+ * Implementation of a simple Node-based bit-blaster.
+ *
+ * Implements the bare minimum to bit-blast bit-vector atoms/terms.
+ */
+class BBSimple : public TBitblaster<Node>
+{
+ using Bits = std::vector<Node>;
+
+ public:
+ BBSimple(TheoryState& state);
+ ~BBSimple() = default;
+
+ /** Bit-blast term 'node' and return bit-blasted 'bits'. */
+ void bbTerm(TNode node, Bits& bits) override;
+ /** Bit-blast atom 'node'. */
+ void bbAtom(TNode node) override;
+ /** Get bit-blasted atom, returns 'atom' itself since it's Boolean. */
+ Node getBBAtom(TNode atom) const override;
+ /** Store Boolean node representing the bit-blasted atom. */
+ void storeBBAtom(TNode atom, Node atom_bb) override;
+ /** Store bits of bit-blasted term. */
+ void storeBBTerm(TNode node, const Bits& bits) override;
+ /** Check if atom was already bit-blasted. */
+ bool hasBBAtom(TNode atom) const override;
+ /** Get bit-blasted node stored for atom. */
+ Node getStoredBBAtom(TNode node);
+ /** Create 'bits' for variable 'var'. */
+ void makeVariable(TNode var, Bits& bits) override;
+
+ /** Collect model values for all relevant terms given in 'relevantTerms'. */
+ bool collectModelValues(TheoryModel* m, const std::set<Node>& relevantTerms);
+
+ prop::SatSolver* getSatSolver() override { Unreachable(); }
+
+ private:
+ /** Query SAT solver for assignment of node 'a'. */
+ Node getModelFromSatSolver(TNode a, bool fullModel) override;
+
+ /** Caches variables for which we already created bits. */
+ TNodeSet d_variables;
+ /** Stores bit-blasted atoms. */
+ std::unordered_map<Node, Node, NodeHashFunction> d_bbAtoms;
+ /** Theory state. */
+ TheoryState& d_state;
+};
+
+BBSimple::BBSimple(TheoryState& s) : TBitblaster<Node>(), d_state(s) {}
+
+void BBSimple::bbAtom(TNode node)
+{
+ node = node.getKind() == kind::NOT ? node[0] : node;
+
+ if (hasBBAtom(node))
+ {
+ return;
+ }
+
+ Node normalized = Rewriter::rewrite(node);
+ Node atom_bb =
+ normalized.getKind() != kind::CONST_BOOLEAN
+ && normalized.getKind() != kind::BITVECTOR_BITOF
+ ? d_atomBBStrategies[normalized.getKind()](normalized, this)
+ : normalized;
+
+ storeBBAtom(node, atom_bb);
+}
+
+void BBSimple::storeBBAtom(TNode atom, Node atom_bb)
+{
+ d_bbAtoms.emplace(atom, atom_bb);
+}
+
+void BBSimple::storeBBTerm(TNode node, const Bits& bits)
+{
+ d_termCache.emplace(node, bits);
+}
+
+bool BBSimple::hasBBAtom(TNode atom) const
+{
+ return d_bbAtoms.find(atom) != d_bbAtoms.end();
+}
+
+void BBSimple::makeVariable(TNode var, Bits& bits)
+{
+ Assert(bits.size() == 0);
+ for (unsigned i = 0; i < utils::getSize(var); ++i)
+ {
+ bits.push_back(utils::mkBitOf(var, i));
+ }
+ d_variables.insert(var);
+}
+
+Node BBSimple::getBBAtom(TNode node) const { return node; }
+
+void BBSimple::bbTerm(TNode node, Bits& bits)
+{
+ Assert(node.getType().isBitVector());
+ if (hasBBTerm(node))
+ {
+ getBBTerm(node, bits);
+ return;
+ }
+ d_termBBStrategies[node.getKind()](node, bits, this);
+ Assert(bits.size() == utils::getSize(node));
+ storeBBTerm(node, bits);
+}
+
+Node BBSimple::getStoredBBAtom(TNode node)
+{
+ bool negated = false;
+ if (node.getKind() == kind::NOT)
+ {
+ node = node[0];
+ negated = true;
+ }
+
+ Assert(hasBBAtom(node));
+ Node atom_bb = d_bbAtoms.at(node);
+ return negated ? atom_bb.negate() : atom_bb;
+}
+
+Node BBSimple::getModelFromSatSolver(TNode a, bool fullModel)
+{
+ if (!hasBBTerm(a))
+ {
+ return utils::mkConst(utils::getSize(a), 0u);
+ }
+
+ bool assignment;
+ Bits bits;
+ getBBTerm(a, bits);
+ Integer value(0);
+ Integer one(1), zero(0);
+ for (int i = bits.size() - 1; i >= 0; --i)
+ {
+ Integer bit;
+ if (d_state.hasSatValue(bits[i], assignment))
+ {
+ bit = assignment ? one : zero;
+ }
+ else
+ {
+ bit = zero;
+ }
+ value = value * 2 + bit;
+ }
+ return utils::mkConst(bits.size(), value);
+}
+
+bool BBSimple::collectModelValues(TheoryModel* m,
+ const std::set<Node>& relevantTerms)
+{
+ for (const auto& var : relevantTerms)
+ {
+ if (d_variables.find(var) == d_variables.end()) continue;
+
+ Node const_value = getModelFromSatSolver(var, true);
+ Assert(const_value.isNull() || const_value.isConst());
+ if (!const_value.isNull())
+ {
+ if (!m->assertEquality(var, const_value, true))
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/* -------------------------------------------------------------------------- */
+
+namespace {
+
+bool isBVAtom(TNode n)
+{
+ return (n.getKind() == kind::EQUAL && n[0].getType().isBitVector())
+ || n.getKind() == kind::BITVECTOR_ULT
+ || n.getKind() == kind::BITVECTOR_ULE
+ || n.getKind() == kind::BITVECTOR_SLT
+ || n.getKind() == kind::BITVECTOR_SLE;
+}
+
+/* Traverse Boolean nodes and collect BV atoms. */
+void collectBVAtoms(TNode n, std::unordered_set<Node, NodeHashFunction>& atoms)
+{
+ std::vector<TNode> visit;
+ std::unordered_set<TNode, TNodeHashFunction> visited;
+
+ visit.push_back(n);
+
+ do
+ {
+ TNode cur = visit.back();
+ visit.pop_back();
+
+ if (visited.find(cur) != visited.end() || !cur.getType().isBoolean())
+ continue;
+
+ visited.insert(cur);
+ if (isBVAtom(cur))
+ {
+ atoms.insert(cur);
+ continue;
+ }
+
+ visit.insert(visit.end(), cur.begin(), cur.end());
+ } while (!visit.empty());
+}
+
+} // namespace
+
+BVSolverSimple::BVSolverSimple(TheoryState& s, TheoryInferenceManager& inferMgr)
+ : BVSolver(s, inferMgr), d_bitblaster(new BBSimple(s))
+{
+}
+
+void BVSolverSimple::addBBLemma(TNode fact)
+{
+ if (!d_bitblaster->hasBBAtom(fact))
+ {
+ d_bitblaster->bbAtom(fact);
+ }
+ NodeManager* nm = NodeManager::currentNM();
+ Node atom_bb = Rewriter::rewrite(d_bitblaster->getStoredBBAtom(fact));
+ Node lemma = nm->mkNode(kind::EQUAL, fact, atom_bb);
+ d_inferManager.lemma(lemma);
+}
+
+bool BVSolverSimple::preNotifyFact(
+ TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal)
+{
+ if (fact.getKind() == kind::NOT)
+ {
+ fact = fact[0];
+ }
+
+ if (isBVAtom(fact))
+ {
+ addBBLemma(fact);
+ }
+ else if (fact.getKind() == kind::BITVECTOR_EAGER_ATOM)
+ {
+ TNode n = fact[0];
+
+ NodeManager* nm = NodeManager::currentNM();
+ Node lemma = nm->mkNode(kind::EQUAL, fact, n);
+ d_inferManager.lemma(lemma);
+
+ std::unordered_set<Node, NodeHashFunction> bv_atoms;
+ collectBVAtoms(n, bv_atoms);
+ for (const Node& nn : bv_atoms)
+ {
+ addBBLemma(nn);
+ }
+ }
+
+ return true;
+}
+
+bool BVSolverSimple::collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet)
+{
+ return d_bitblaster->collectModelValues(m, termSet);
+}
+
+} // namespace bv
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/bv/bv_solver_simple.h b/src/theory/bv/bv_solver_simple.h
new file mode 100644
index 000000000..59239a52c
--- /dev/null
+++ b/src/theory/bv/bv_solver_simple.h
@@ -0,0 +1,80 @@
+/********************* */
+/*! \file bv_solver_simple.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mathias Preiner
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Simple bit-blast solver
+ **
+ ** Simple bit-blast solver that sends bit-blast lemmas directly to MiniSat.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__BV__BV_SOLVER_SIMPLE_H
+#define CVC4__THEORY__BV__BV_SOLVER_SIMPLE_H
+
+#include <unordered_map>
+
+#include "theory/bv/bv_solver.h"
+
+namespace CVC4 {
+
+namespace theory {
+namespace bv {
+
+class BBSimple;
+
+/**
+ * Simple bit-blasting solver that sends bit-blasting lemmas directly to the
+ * internal MiniSat. It is also ablo to handle atoms of kind
+ * BITVECTOR_EAGER_ATOM.
+ *
+ * Sends lemmas atom <=> bb(atom) to MiniSat on preNotifyFact().
+ */
+class BVSolverSimple : public BVSolver
+{
+ public:
+ BVSolverSimple(TheoryState& state, TheoryInferenceManager& inferMgr);
+ ~BVSolverSimple() = default;
+
+ void preRegisterTerm(TNode n) override {}
+
+ bool preNotifyFact(TNode atom,
+ bool pol,
+ TNode fact,
+ bool isPrereg,
+ bool isInternal) override;
+
+ std::string identify() const override { return "BVSolverSimple"; };
+
+ Theory::PPAssertStatus ppAssert(
+ TrustNode in, TrustSubstitutionMap& outSubstitutions) override
+ {
+ return Theory::PPAssertStatus::PP_ASSERT_STATUS_UNSOLVED;
+ }
+
+ bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet) override;
+
+ private:
+ /**
+ * Sends a bit-blasting lemma fact <=> d_bitblaster.bbAtom(fact) to the
+ * inference manager.
+ */
+ void addBBLemma(TNode fact);
+
+ /** Bit-blaster used to bit-blast atoms/terms. */
+ std::unique_ptr<BBSimple> d_bitblaster;
+};
+
+} // namespace bv
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/bv/bv_subtheory.h b/src/theory/bv/bv_subtheory.h
index 725b61f95..5e5720a5c 100644
--- a/src/theory/bv/bv_subtheory.h
+++ b/src/theory/bv/bv_subtheory.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Tim King, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,10 +25,6 @@
namespace CVC4 {
-namespace proof {
-class BitVectorProof;
-}
-
namespace theory {
class TheoryModel;
@@ -59,7 +55,7 @@ inline std::ostream& operator<<(std::ostream& out, SubTheory subtheory) {
}
// forward declaration
-class TheoryBV;
+class BVSolverLazy;
using AssertionQueue = context::CDQueue<Node>;
@@ -69,22 +65,20 @@ using AssertionQueue = context::CDQueue<Node>;
*/
class SubtheorySolver {
public:
- SubtheorySolver(context::Context* c, TheoryBV* bv)
- : d_context(c),
- d_bv(bv),
- d_bvp(nullptr),
- d_assertionQueue(c),
- d_assertionIndex(c, 0) {}
+ SubtheorySolver(context::Context* c, BVSolverLazy* bv)
+ : d_context(c), d_bv(bv), d_assertionQueue(c), d_assertionIndex(c, 0)
+ {
+ }
virtual ~SubtheorySolver() {}
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 bool collectModelInfo(TheoryModel* m, bool fullModel) = 0;
+ virtual bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet) = 0;
virtual Node getModelValue(TNode var) = 0;
virtual bool isComplete() = 0;
virtual EqualityStatus getEqualityStatus(TNode a, TNode b) = 0;
- virtual void addSharedTerm(TNode node) {}
bool done() { return d_assertionQueue.size() == d_assertionIndex; }
TNode get() {
Assert(!done());
@@ -93,7 +87,7 @@ class SubtheorySolver {
return res;
}
virtual void assertFact(TNode fact) { d_assertionQueue.push_back(fact); }
- virtual void setProofLog(proof::BitVectorProof* bvp) {}
+
AssertionQueue::const_iterator assertionsBegin() {
return d_assertionQueue.begin();
}
@@ -106,9 +100,7 @@ class SubtheorySolver {
context::Context* d_context;
/** The bit-vector theory */
- TheoryBV* d_bv;
- /** proof log */
- proof::ResolutionBitVectorProof* d_bvp;
+ BVSolverLazy* d_bv;
AssertionQueue d_assertionQueue;
context::CDO<uint32_t> d_assertionIndex;
}; /* class SubtheorySolver */
diff --git a/src/theory/bv/bv_subtheory_algebraic.cpp b/src/theory/bv/bv_subtheory_algebraic.cpp
index e5a416a1b..50a509517 100644
--- a/src/theory/bv/bv_subtheory_algebraic.cpp
+++ b/src/theory/bv/bv_subtheory_algebraic.cpp
@@ -2,10 +2,10 @@
/*! \file bv_subtheory_algebraic.cpp
** \verbatim
** Top contributors (to current version):
- ** Liana Hadarean, Aina Niemetz, Tim King
+ ** Liana Hadarean, Aina Niemetz, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,10 +19,14 @@
#include "expr/node_algorithm.h"
#include "options/bv_options.h"
+#include "printer/printer.h"
+#include "smt/dump.h"
+#include "smt/smt_engine.h"
+#include "smt/smt_engine_scope.h"
#include "smt/smt_statistics_registry.h"
#include "smt_util/boolean_simplification.h"
#include "theory/bv/bv_quick_check.h"
-#include "theory/bv/theory_bv.h"
+#include "theory/bv/bv_solver_lazy.h"
#include "theory/bv/theory_bv_utils.h"
#include "theory/theory_model.h"
@@ -227,7 +231,7 @@ void SubstitutionEx::storeCache(TNode from, TNode to, Node reason) {
d_cache[from] = SubstitutionElement(to, reason);
}
-AlgebraicSolver::AlgebraicSolver(context::Context* c, TheoryBV* bv)
+AlgebraicSolver::AlgebraicSolver(context::Context* c, BVSolverLazy* bv)
: SubtheorySolver(c, bv),
d_modelMap(),
d_quickSolver(new BVQuickCheck("theory::bv::algebraic", bv)),
@@ -271,7 +275,6 @@ bool AlgebraicSolver::check(Theory::Effort e)
uint64_t original_bb_cost = 0;
- NodeManager* nm = NodeManager::currentNM();
NodeSet seen_assertions;
// Processing assertions from scratch
for (AssertionQueue::const_iterator it = assertionsBegin(); it != assertionsEnd(); ++it) {
@@ -321,16 +324,6 @@ bool AlgebraicSolver::check(Theory::Effort e)
TNode fact = worklist[r].node;
unsigned id = worklist[r].id;
- if (Dump.isOn("bv-algebraic")) {
- Node expl = d_explanations[id];
- Node query = utils::mkNot(nm->mkNode(kind::IMPLIES, expl, fact));
- Dump("bv-algebraic") << EchoCommand("ThoeryBV::AlgebraicSolver::substitution explanation");
- Dump("bv-algebraic") << PushCommand();
- Dump("bv-algebraic") << AssertCommand(query.toExpr());
- Dump("bv-algebraic") << CheckSatCommand();
- Dump("bv-algebraic") << PopCommand();
- }
-
if (fact.isConst() &&
fact.getConst<bool>() == true) {
continue;
@@ -344,15 +337,6 @@ bool AlgebraicSolver::check(Theory::Effort e)
d_isComplete.set(true);
Debug("bv-subtheory-algebraic") << " UNSAT: assertion simplfies to false with conflict: "<< conflict << "\n";
- if (Dump.isOn("bv-algebraic")) {
- Dump("bv-algebraic") << EchoCommand("TheoryBV::AlgebraicSolver::conflict");
- Dump("bv-algebraic") << PushCommand();
- Dump("bv-algebraic") << AssertCommand(conflict.toExpr());
- Dump("bv-algebraic") << CheckSatCommand();
- Dump("bv-algebraic") << PopCommand();
- }
-
-
++(d_statistics.d_numSimplifiesToFalse);
++(d_numSolved);
return false;
@@ -471,7 +455,8 @@ bool AlgebraicSolver::quickCheck(std::vector<Node>& facts) {
return false;
}
-void AlgebraicSolver::setConflict(TNode conflict) {
+void AlgebraicSolver::setConflict(TNode conflict)
+{
Node final_conflict = conflict;
if (options::bitvectorQuickXplain() &&
conflict.getKind() == kind::AND &&
@@ -534,17 +519,6 @@ bool AlgebraicSolver::solve(TNode fact, TNode reason, SubstitutionEx& subst) {
Node new_right = nm->mkNode(kind::BITVECTOR_XOR, right, inverse);
bool changed = subst.addSubstitution(var, new_right, reason);
- if (Dump.isOn("bv-algebraic")) {
- Node query = utils::mkNot(nm->mkNode(
- kind::EQUAL, fact, nm->mkNode(kind::EQUAL, var, new_right)));
- Dump("bv-algebraic") << EchoCommand("ThoeryBV::AlgebraicSolver::substitution explanation");
- Dump("bv-algebraic") << PushCommand();
- Dump("bv-algebraic") << AssertCommand(query.toExpr());
- Dump("bv-algebraic") << CheckSatCommand();
- Dump("bv-algebraic") << PopCommand();
- }
-
-
return changed;
}
@@ -710,12 +684,11 @@ EqualityStatus AlgebraicSolver::getEqualityStatus(TNode a, TNode b) {
return EQUALITY_UNKNOWN;
}
-bool AlgebraicSolver::collectModelInfo(TheoryModel* model, bool fullModel)
+bool AlgebraicSolver::collectModelValues(TheoryModel* model,
+ const std::set<Node>& termSet)
{
- Debug("bitvector-model") << "AlgebraicSolver::collectModelInfo\n";
+ Debug("bitvector-model") << "AlgebraicSolver::collectModelValues\n";
AlwaysAssert(!d_quickSolver->inConflict());
- set<Node> termSet;
- d_bv->computeRelevantTerms(termSet);
// collect relevant terms that the bv theory abstracts to variables
// (variables and parametric terms such as select apply_uf)
@@ -746,7 +719,7 @@ bool AlgebraicSolver::collectModelInfo(TheoryModel* model, bool fullModel)
for (NodeSet::const_iterator it = leaf_vars.begin(); it != leaf_vars.end(); ++it) {
TNode var = *it;
Node value = d_quickSolver->getVarValue(var, true);
- Assert(!value.isNull() || !fullModel);
+ Assert(!value.isNull());
// may be a shared term that did not appear in the current assertions
// AJR: need to check whether already in map for cases where collectModelInfo is called multiple times in the same context
diff --git a/src/theory/bv/bv_subtheory_algebraic.h b/src/theory/bv/bv_subtheory_algebraic.h
index d9a9bce6f..69cf5186d 100644
--- a/src/theory/bv/bv_subtheory_algebraic.h
+++ b/src/theory/bv/bv_subtheory_algebraic.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -31,64 +31,60 @@ namespace bv {
class AlgebraicSolver;
-
Node mergeExplanations(TNode expl1, TNode expl2);
Node mergeExplanations(const std::vector<Node>& expls);
-
/**
* Non-context dependent substitution with explanations.
- *
+ *
*/
-class SubstitutionEx {
- struct SubstitutionElement {
+class SubstitutionEx
+{
+ struct SubstitutionElement
+ {
Node to;
Node reason;
- SubstitutionElement()
- : to()
- , reason()
- {}
-
- SubstitutionElement(TNode t, TNode r)
- : to(t)
- , reason(r)
- {}
+ SubstitutionElement() : to(), reason() {}
+
+ SubstitutionElement(TNode t, TNode r) : to(t), reason(r) {}
};
- struct SubstitutionStackElement {
+ struct SubstitutionStackElement
+ {
TNode node;
bool childrenAdded;
SubstitutionStackElement(TNode n, bool ca = false)
- : node(n)
- , childrenAdded(ca)
- {}
+ : node(n), childrenAdded(ca)
+ {
+ }
};
- typedef std::unordered_map<Node, SubstitutionElement, NodeHashFunction> Substitutions;
- typedef std::unordered_map<Node, SubstitutionElement, NodeHashFunction> SubstitutionsCache;
+ typedef std::unordered_map<Node, SubstitutionElement, NodeHashFunction>
+ Substitutions;
+ typedef std::unordered_map<Node, SubstitutionElement, NodeHashFunction>
+ SubstitutionsCache;
Substitutions d_substitutions;
SubstitutionsCache d_cache;
bool d_cacheInvalid;
- theory::SubstitutionMap* d_modelMap;
+ theory::SubstitutionMap* d_modelMap;
-
Node getReason(TNode node) const;
bool hasCache(TNode node) const;
Node getCache(TNode node) const;
void storeCache(TNode from, TNode to, Node rason);
Node internalApply(TNode node);
-public:
+ public:
SubstitutionEx(theory::SubstitutionMap* modelMap);
- /**
- * Returnst true if the substitution map did not contain from.
- *
- * @param from
- * @param to
- * @param reason
- *
- * @return
+ /**
+ * Returnst true if the substitution map did not contain from.
+ *
+ * @param from
+ * @param to
+ * @param reason
+ *
+ * @return
*/
bool addSubstitution(TNode from, TNode to, TNode reason);
Node apply(TNode node);
@@ -97,37 +93,39 @@ public:
/**
* In-processing worklist element, id keeps track of
- * original assertion.
- *
+ * original assertion.
+ *
*/
-struct WorklistElement {
+struct WorklistElement
+{
Node node;
unsigned id;
WorklistElement(Node n, unsigned i) : node(n), id(i) {}
WorklistElement() : node(), id(-1) {}
-};
-
+};
typedef std::unordered_map<Node, Node, NodeHashFunction> NodeNodeMap;
typedef std::unordered_map<Node, unsigned, NodeHashFunction> NodeIdMap;
typedef std::unordered_set<TNode, TNodeHashFunction> TNodeSet;
-
-class ExtractSkolemizer {
- struct Extract {
+class ExtractSkolemizer
+{
+ struct Extract
+ {
unsigned high;
unsigned low;
Extract(unsigned h, unsigned l) : high(h), low(l) {}
};
-
- struct ExtractList {
+
+ struct ExtractList
+ {
Base base;
std::vector<Extract> extracts;
ExtractList(unsigned bitwidth) : base(bitwidth), extracts() {}
ExtractList() : base(1), extracts() {}
- void addExtract(Extract& e);
+ void addExtract(Extract& e);
};
- typedef std::unordered_map<Node, ExtractList, NodeHashFunction> VarExtractMap;
+ typedef std::unordered_map<Node, ExtractList, NodeHashFunction> VarExtractMap;
context::Context d_emptyContext;
VarExtractMap d_varToExtract;
theory::SubstitutionMap* d_modelMap;
@@ -141,12 +139,13 @@ class ExtractSkolemizer {
Node unSkolemize(TNode);
Node mkSkolem(Node node);
-public:
- ExtractSkolemizer(theory::SubstitutionMap* modelMap);
+
+ public:
+ ExtractSkolemizer(theory::SubstitutionMap* modelMap);
void skolemize(std::vector<WorklistElement>&);
void unSkolemize(std::vector<WorklistElement>&);
~ExtractSkolemizer();
-};
+};
class BVQuickCheck;
class QuickXPlain;
@@ -154,9 +153,10 @@ class QuickXPlain;
/**
* AlgebraicSolver
*/
-class AlgebraicSolver : public SubtheorySolver {
-
- struct Statistics {
+class AlgebraicSolver : public SubtheorySolver
+{
+ struct Statistics
+ {
IntStat d_numCallstoCheck;
IntStat d_numSimplifiesToTrue;
IntStat d_numSimplifiesToFalse;
@@ -171,13 +171,17 @@ class AlgebraicSolver : public SubtheorySolver {
std::unique_ptr<SubstitutionMap> d_modelMap;
std::unique_ptr<BVQuickCheck> d_quickSolver;
- context::CDO<bool> d_isComplete;
- context::CDO<bool> d_isDifficult; /**< flag to indicate whether the current assertions contain expensive BV operators */
-
+ context::CDO<bool> d_isComplete;
+ context::CDO<bool>
+ d_isDifficult; /**< flag to indicate whether the current assertions
+ contain expensive BV operators */
+
unsigned long d_budget;
- std::vector<Node> d_explanations; /**< explanations for assertions indexed by assertion id */
- TNodeSet d_inputAssertions; /**< assertions in current context (for debugging purposes only) */
- NodeIdMap d_ids; /**< map from assertions to ids */
+ std::vector<Node> d_explanations; /**< explanations for assertions indexed by
+ assertion id */
+ TNodeSet d_inputAssertions; /**< assertions in current context (for debugging
+ purposes only) */
+ NodeIdMap d_ids; /**< map from assertions to ids */
uint64_t d_numSolved;
uint64_t d_numCalls;
@@ -191,37 +195,38 @@ class AlgebraicSolver : public SubtheorySolver {
bool checkExplanation(TNode expl);
void storeExplanation(TNode expl);
void storeExplanation(unsigned id, TNode expl);
- /**
+ /**
* Apply substitutions and rewriting to the worklist assertions to a fixpoint.
- * Subsitutions learned store in subst.
+ * Subsitutions learned store in subst.
*
- * @param worklist
- * @param subst
+ * @param worklist
+ * @param subst
*/
- void processAssertions(std::vector<WorklistElement>& worklist, SubstitutionEx& subst);
- /**
+ void processAssertions(std::vector<WorklistElement>& worklist,
+ SubstitutionEx& subst);
+ /**
* Attempt to solve the equation in fact, and if successful
- * add a substitution to subst.
- *
+ * add a substitution to subst.
+ *
* @param fact equation we are trying to solve
* @param reason the reason in terms of original assertions
* @param subst substitution map
- *
+ *
* @return true if added a substitution to subst
*/
bool solve(TNode fact, TNode reason, SubstitutionEx& subst);
- /**
+ /**
* Run a SAT solver on the given facts with the given budget.
- * Sets the isComplete flag and conflict accordingly.
- *
- * @param facts
- *
- * @return true if no conflict was detected.
+ * Sets the isComplete flag and conflict accordingly.
+ *
+ * @param facts
+ *
+ * @return true if no conflict was detected.
*/
bool quickCheck(std::vector<Node>& facts);
-public:
- AlgebraicSolver(context::Context* c, TheoryBV* bv);
+ public:
+ AlgebraicSolver(context::Context* c, BVSolverLazy* bv);
~AlgebraicSolver();
void preRegister(TNode node) override {}
@@ -231,7 +236,8 @@ public:
Unreachable() << "AlgebraicSolver does not propagate.\n";
}
EqualityStatus getEqualityStatus(TNode a, TNode b) override;
- bool collectModelInfo(TheoryModel* m, bool fullModel) override;
+ bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet) override;
Node getModelValue(TNode node) override;
bool isComplete() override;
void assertFact(TNode fact) override;
diff --git a/src/theory/bv/bv_subtheory_bitblast.cpp b/src/theory/bv/bv_subtheory_bitblast.cpp
index 8f87bc4b8..7de5e0fe6 100644
--- a/src/theory/bv/bv_subtheory_bitblast.cpp
+++ b/src/theory/bv/bv_subtheory_bitblast.cpp
@@ -5,7 +5,7 @@
** Liana Hadarean, Aina Niemetz, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -15,15 +15,15 @@
**/
#include "theory/bv/bv_subtheory_bitblast.h"
+
#include "decision/decision_attributes.h"
#include "options/bv_options.h"
#include "options/decision_options.h"
-#include "proof/proof_manager.h"
#include "smt/smt_statistics_registry.h"
#include "theory/bv/abstraction.h"
#include "theory/bv/bitblast/lazy_bitblaster.h"
#include "theory/bv/bv_quick_check.h"
-#include "theory/bv/theory_bv.h"
+#include "theory/bv/bv_solver_lazy.h"
#include "theory/bv/theory_bv_utils.h"
using namespace std;
@@ -33,7 +33,7 @@ namespace CVC4 {
namespace theory {
namespace bv {
-BitblastSolver::BitblastSolver(context::Context* c, TheoryBV* bv)
+BitblastSolver::BitblastSolver(context::Context* c, BVSolverLazy* bv)
: SubtheorySolver(c, bv),
d_bitblaster(new TLazyBitblaster(c, bv, "theory::bv::lazy")),
d_bitblastQueue(c),
@@ -248,9 +248,10 @@ EqualityStatus BitblastSolver::getEqualityStatus(TNode a, TNode b) {
return d_bitblaster->getEqualityStatus(a, b);
}
-bool BitblastSolver::collectModelInfo(TheoryModel* m, bool fullModel)
+bool BitblastSolver::collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet)
{
- return d_bitblaster->collectModelInfo(m, fullModel);
+ return d_bitblaster->collectModelValues(m, termSet);
}
Node BitblastSolver::getModelValue(TNode node)
@@ -263,9 +264,8 @@ Node BitblastSolver::getModelValue(TNode node)
return val;
}
-
-
-void BitblastSolver::setConflict(TNode conflict) {
+void BitblastSolver::setConflict(TNode conflict)
+{
Node final_conflict = conflict;
if (options::bitvectorQuickXplain() &&
conflict.getKind() == kind::AND) {
@@ -276,12 +276,6 @@ void BitblastSolver::setConflict(TNode conflict) {
d_bv->setConflict(final_conflict);
}
-void BitblastSolver::setProofLog(proof::BitVectorProof* bvp)
-{
- d_bitblaster->setProofLog( bvp );
- bvp->setBitblaster(d_bitblaster.get());
-}
-
}/* namespace CVC4::theory::bv */
}/* namespace CVC4::theory */
}/* namespace CVC4 */
diff --git a/src/theory/bv/bv_subtheory_bitblast.h b/src/theory/bv/bv_subtheory_bitblast.h
index a2b099609..4832cce30 100644
--- a/src/theory/bv/bv_subtheory_bitblast.h
+++ b/src/theory/bv/bv_subtheory_bitblast.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Mathias Preiner, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -24,10 +24,6 @@
namespace CVC4 {
-namespace proof {
-class ResolutionBitVectorProof;
-}
-
namespace theory {
namespace bv {
@@ -39,8 +35,10 @@ class QuickXPlain;
/**
* BitblastSolver
*/
-class BitblastSolver : public SubtheorySolver {
- struct Statistics {
+class BitblastSolver : public SubtheorySolver
+{
+ struct Statistics
+ {
IntStat d_numCallstoCheck;
IntStat d_numBBLemmas;
Statistics();
@@ -59,29 +57,30 @@ class BitblastSolver : public SubtheorySolver {
/** Queue for bit-blasting lemma atoms only in full check if we are sat */
context::CDQueue<TNode> d_lemmaAtomsQueue;
- bool d_useSatPropagation;
+ bool d_useSatPropagation;
AbstractionModule* d_abstractionModule;
std::unique_ptr<BVQuickCheck> d_quickCheck;
std::unique_ptr<QuickXPlain> d_quickXplain;
// Node getModelValueRec(TNode node);
void setConflict(TNode conflict);
-public:
- BitblastSolver(context::Context* c, TheoryBV* bv);
+
+ public:
+ BitblastSolver(context::Context* c, BVSolverLazy* bv);
~BitblastSolver();
void preRegister(TNode node) override;
bool check(Theory::Effort e) override;
void explain(TNode literal, std::vector<TNode>& assumptions) override;
EqualityStatus getEqualityStatus(TNode a, TNode b) override;
- bool collectModelInfo(TheoryModel* m, bool fullModel) override;
+ bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet) override;
Node getModelValue(TNode node) override;
bool isComplete() override { return true; }
void bitblastQueue();
void setAbstraction(AbstractionModule* module);
uint64_t computeAtomWeight(TNode atom);
- void setProofLog(proof::BitVectorProof* bvp) override;
};
-} /* namespace CVC4::theory::bv */
-} /* namespace CVC4::theory */
+} // namespace bv
+} // namespace theory
} /* namespace CVC4 */
diff --git a/src/theory/bv/bv_subtheory_core.cpp b/src/theory/bv/bv_subtheory_core.cpp
index 668d7b87e..e29553063 100644
--- a/src/theory/bv/bv_subtheory_core.cpp
+++ b/src/theory/bv/bv_subtheory_core.cpp
@@ -2,10 +2,10 @@
/*! \file bv_subtheory_core.cpp
** \verbatim
** Top contributors (to current version):
- ** Liana Hadarean, Aina Niemetz, Andrew Reynolds
+ ** Andrew Reynolds, Liana Hadarean, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,8 +19,7 @@
#include "options/bv_options.h"
#include "options/smt_options.h"
#include "smt/smt_statistics_registry.h"
-#include "theory/bv/slicer.h"
-#include "theory/bv/theory_bv.h"
+#include "theory/bv/bv_solver_lazy.h"
#include "theory/bv/theory_bv_utils.h"
#include "theory/ext_theory.h"
#include "theory/theory_model.h"
@@ -32,75 +31,146 @@ using namespace CVC4::theory;
using namespace CVC4::theory::bv;
using namespace CVC4::theory::bv::utils;
-CoreSolver::CoreSolver(context::Context* c, TheoryBV* bv)
- : SubtheorySolver(c, bv),
- d_notify(*this),
- d_equalityEngine(d_notify, c, "theory::bv::ee", true),
- d_slicer(new Slicer()),
- d_isComplete(c, true),
- d_lemmaThreshold(16),
- d_useSlicer(false),
- d_preregisterCalled(false),
- d_checkCalled(false),
- d_reasons(c)
+bool CoreSolverExtTheoryCallback::getCurrentSubstitution(
+ int effort,
+ const std::vector<Node>& vars,
+ std::vector<Node>& subs,
+ std::map<Node, std::vector<Node> >& exp)
{
- // 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);
- d_equalityEngine.addFunctionKind(kind::BITVECTOR_TO_NAT);
- d_equalityEngine.addFunctionKind(kind::INT_TO_BITVECTOR);
+ if (d_equalityEngine == nullptr)
+ {
+ return false;
+ }
+ // get the constant equivalence classes
+ bool retVal = false;
+ for (const Node& n : vars)
+ {
+ if (d_equalityEngine->hasTerm(n))
+ {
+ Node nr = d_equalityEngine->getRepresentative(n);
+ if (nr.isConst())
+ {
+ subs.push_back(nr);
+ exp[n].push_back(n.eqNode(nr));
+ retVal = true;
+ }
+ else
+ {
+ subs.push_back(n);
+ }
+ }
+ else
+ {
+ subs.push_back(n);
+ }
+ }
+ // return true if the substitution is non-trivial
+ return retVal;
+}
+
+bool CoreSolverExtTheoryCallback::getReduction(int effort,
+ Node n,
+ Node& nr,
+ bool& satDep)
+{
+ Trace("bv-ext") << "TheoryBV::checkExt : non-reduced : " << n << std::endl;
+ if (n.getKind() == kind::BITVECTOR_TO_NAT)
+ {
+ nr = utils::eliminateBv2Nat(n);
+ satDep = false;
+ return true;
+ }
+ else if (n.getKind() == kind::INT_TO_BITVECTOR)
+ {
+ nr = utils::eliminateInt2Bv(n);
+ satDep = false;
+ return true;
+ }
+ return false;
+}
+
+CoreSolver::CoreSolver(context::Context* c, BVSolverLazy* bv)
+ : SubtheorySolver(c, bv),
+ d_notify(*this),
+ d_isComplete(c, true),
+ d_lemmaThreshold(16),
+ d_preregisterCalled(false),
+ d_checkCalled(false),
+ d_bv(bv),
+ d_extTheoryCb(),
+ d_extTheory(new ExtTheory(d_extTheoryCb,
+ bv->d_bv.getSatContext(),
+ bv->d_bv.getUserContext(),
+ bv->d_bv.getOutputChannel())),
+ d_reasons(c),
+ d_needsLastCallCheck(false),
+ d_extf_range_infer(bv->d_bv.getUserContext()),
+ d_extf_collapse_infer(bv->d_bv.getUserContext())
+{
+ d_extTheory->addFunctionKind(kind::BITVECTOR_TO_NAT);
+ d_extTheory->addFunctionKind(kind::INT_TO_BITVECTOR);
}
CoreSolver::~CoreSolver() {}
-void CoreSolver::setMasterEqualityEngine(eq::EqualityEngine* eq) {
- d_equalityEngine.setMasterEqualityEngine(eq);
+bool CoreSolver::needsEqualityEngine(EeSetupInfo& esi)
+{
+ esi.d_notify = &d_notify;
+ esi.d_name = "theory::bv::ee";
+ return true;
}
-void CoreSolver::enableSlicer() {
- AlwaysAssert(!d_preregisterCalled);
- d_useSlicer = true;
- d_statistics.d_slicerEnabled.setData(true);
+void CoreSolver::finishInit()
+{
+ // use the parent's equality engine, which may be the one we allocated above
+ d_equalityEngine = d_bv->d_bv.getEqualityEngine();
+
+ // 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);
+ d_equalityEngine->addFunctionKind(kind::BITVECTOR_TO_NAT);
+ d_equalityEngine->addFunctionKind(kind::INT_TO_BITVECTOR);
}
void CoreSolver::preRegister(TNode node) {
d_preregisterCalled = true;
if (node.getKind() == kind::EQUAL) {
- d_equalityEngine.addTriggerEquality(node);
- if (d_useSlicer) {
- d_slicer->processEquality(node);
- AlwaysAssert(!d_checkCalled);
- }
+ d_equalityEngine->addTriggerPredicate(node);
} else {
- d_equalityEngine.addTerm(node);
+ d_equalityEngine->addTerm(node);
+ // Register with the extended theory, for context-dependent simplification.
+ // Notice we do this for registered terms but not internally generated
+ // equivalence classes. The two should roughly cooincide. Since ExtTheory is
+ // being used as a heuristic, it is good enough to be registered here.
+ d_extTheory->registerTerm(node);
}
}
@@ -109,69 +179,17 @@ void CoreSolver::explain(TNode literal, std::vector<TNode>& assumptions) {
bool polarity = literal.getKind() != kind::NOT;
TNode atom = polarity ? literal : literal[0];
if (atom.getKind() == kind::EQUAL) {
- d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions);
+ d_equalityEngine->explainEquality(atom[0], atom[1], polarity, assumptions);
} else {
- d_equalityEngine.explainPredicate(atom, polarity, assumptions);
- }
-}
-
-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;
-}
-
-bool CoreSolver::decomposeFact(TNode fact) {
- 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 a = eq[0];
- TNode b = eq[1];
- Node new_a = getBaseDecomposition(a);
- Node new_b = getBaseDecomposition(b);
-
- Assert(utils::getSize(new_a) == utils::getSize(new_b)
- && 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;
- ok = assertFactToEqualityEngine(b_eq_new_b, utils::mkTrue());
- 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());
- 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);
- if (!ok) return false;
- }
- }
+ d_equalityEngine->explainPredicate(atom, polarity, assumptions);
}
- return true;
}
bool CoreSolver::check(Theory::Effort e) {
Trace("bitvector::core") << "CoreSolver::check \n";
- d_bv->spendResource(ResourceManager::Resource::TheoryCheckStep);
+ d_bv->d_inferManager.spendResource(
+ ResourceManager::Resource::TheoryCheckStep);
d_checkCalled = true;
Assert(!d_bv->inConflict());
@@ -179,10 +197,6 @@ bool CoreSolver::check(Theory::Effort e) {
bool ok = true;
std::vector<Node> core_eqs;
TNodeBoolMap seen;
- // slicer does not deal with cardinality constraints yet
- if (d_useSlicer) {
- d_isComplete = false;
- }
while (! done()) {
TNode fact = get();
if (d_isComplete && !isCompleteForTerm(fact, seen)) {
@@ -191,11 +205,7 @@ bool CoreSolver::check(Theory::Effort e) {
// only reason about equalities
if (fact.getKind() == kind::EQUAL || (fact.getKind() == kind::NOT && fact[0].getKind() == kind::EQUAL)) {
- if (d_useSlicer) {
- ok = decomposeFact(fact);
- } else {
- ok = assertFactToEqualityEngine(fact, fact);
- }
+ ok = assertFactToEqualityEngine(fact, fact);
} else {
ok = assertFactToEqualityEngine(fact, fact);
}
@@ -218,14 +228,14 @@ void CoreSolver::buildModel()
TNodeSet constants;
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)
{
// must check if it's just the constant
- eq::EqClassIterator it(repr, &d_equalityEngine);
+ eq::EqClassIterator it(repr, d_equalityEngine);
if (!(++it).isFinished() || true)
{
constants.insert(repr);
@@ -237,7 +247,7 @@ void CoreSolver::buildModel()
// build repr to value map
- eqcs_i = eq::EqClassesIterator(&d_equalityEngine);
+ eqcs_i = eq::EqClassesIterator(d_equalityEngine);
while (!eqcs_i.isFinished())
{
TNode repr = *eqcs_i;
@@ -337,7 +347,10 @@ void CoreSolver::buildModel()
bool CoreSolver::assertFactToEqualityEngine(TNode fact, TNode reason) {
// Notify the equality engine
- if (!d_bv->inConflict() && (!d_bv->wasPropagatedBySubtheory(fact) || d_bv->getPropagatingSubtheory(fact) != SUB_CORE)) {
+ 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;
@@ -345,42 +358,34 @@ bool CoreSolver::assertFactToEqualityEngine(TNode fact, TNode reason) {
if (predicate.getKind() == kind::EQUAL) {
if (negated) {
// dis-equality
- d_equalityEngine.assertEquality(predicate, false, reason);
+ d_equalityEngine->assertEquality(predicate, false, reason);
} else {
// equality
- d_equalityEngine.assertEquality(predicate, true, reason);
+ d_equalityEngine->assertEquality(predicate, true, reason);
}
} else {
// Adding predicate if the congruence over it is turned on
- if (d_equalityEngine.isFunctionKind(predicate.getKind())) {
- d_equalityEngine.assertPredicate(predicate, !negated, reason);
+ if (d_equalityEngine->isFunctionKind(predicate.getKind()))
+ {
+ d_equalityEngine->assertPredicate(predicate, !negated, reason);
}
}
}
// checking for a conflict
- if (d_bv->inConflict()) {
+ if (d_bv->inConflict())
+ {
return false;
}
return true;
}
-bool CoreSolver::NotifyClass::eqNotifyTriggerEquality(TNode equality, bool value) {
- Debug("bitvector::core") << "NotifyClass::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false" )<< ")" << std::endl;
- if (value) {
- return d_solver.storePropagation(equality);
- } else {
- return d_solver.storePropagation(equality.notNode());
- }
-}
-
bool CoreSolver::NotifyClass::eqNotifyTriggerPredicate(TNode predicate, bool value) {
Debug("bitvector::core") << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", " << (value ? "true" : "false" ) << ")" << std::endl;
if (value) {
return d_solver.storePropagation(predicate);
- } else {
- return d_solver.storePropagation(predicate.notNode());
}
+ return d_solver.storePropagation(predicate.notNode());
}
bool CoreSolver::NotifyClass::eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) {
@@ -396,58 +401,38 @@ void CoreSolver::NotifyClass::eqNotifyConstantTermMerge(TNode t1, TNode t2) {
d_solver.conflict(t1, t2);
}
-void CoreSolver::NotifyClass::eqNotifyNewClass(TNode t) {
- d_solver.eqNotifyNewClass( t );
-}
-
bool CoreSolver::storePropagation(TNode literal) {
return d_bv->storePropagation(literal, SUB_CORE);
}
void CoreSolver::conflict(TNode a, TNode b) {
std::vector<TNode> assumptions;
- d_equalityEngine.explainEquality(a, b, true, assumptions);
+ d_equalityEngine->explainEquality(a, b, true, assumptions);
Node conflict = flattenAnd(assumptions);
d_bv->setConflict(conflict);
}
-void CoreSolver::eqNotifyNewClass(TNode t) {
- Assert(d_bv->getExtTheory() != NULL);
- d_bv->getExtTheory()->registerTerm( t );
-}
-
bool CoreSolver::isCompleteForTerm(TNode term, TNodeBoolMap& seen) {
- if (d_useSlicer)
- return utils::isCoreTerm(term, seen);
-
return utils::isEqualityTerm(term, seen);
}
-bool CoreSolver::collectModelInfo(TheoryModel* m, bool fullModel)
+bool CoreSolver::collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet)
{
- if (d_useSlicer) {
- Unreachable();
- }
if (Debug.isOn("bitvector-model")) {
context::CDQueue<Node>::const_iterator it = d_assertionQueue.begin();
for (; it!= d_assertionQueue.end(); ++it) {
- Debug("bitvector-model") << "CoreSolver::collectModelInfo (assert "
- << *it << ")\n";
+ Debug("bitvector-model")
+ << "CoreSolver::collectModelValues (assert " << *it << ")\n";
}
}
- set<Node> termSet;
- d_bv->computeRelevantTerms(termSet);
- if (!m->assertEqualityEngine(&d_equalityEngine, &termSet))
- {
- return false;
- }
if (isComplete()) {
- Debug("bitvector-model") << "CoreSolver::collectModelInfo complete.";
+ Debug("bitvector-model") << "CoreSolver::collectModelValues complete.";
for (ModelValue::const_iterator it = d_modelValues.begin(); it != d_modelValues.end(); ++it) {
Node a = it->first;
Node b = it->second;
- Debug("bitvector-model") << "CoreSolver::collectModelInfo modelValues "
- << a << " => " << b <<")\n";
+ Debug("bitvector-model") << "CoreSolver::collectModelValues modelValues "
+ << a << " => " << b << ")\n";
if (!m->assertEquality(a, b, true))
{
return false;
@@ -460,7 +445,7 @@ bool CoreSolver::collectModelInfo(TheoryModel* m, bool fullModel)
Node CoreSolver::getModelValue(TNode var) {
Debug("bitvector-model") << "CoreSolver::getModelValue (" << var <<")";
Assert(isComplete());
- TNode repr = d_equalityEngine.getRepresentative(var);
+ TNode repr = d_equalityEngine->getRepresentative(var);
Node result = Node();
if (repr.getKind() == kind::CONST_BITVECTOR) {
result = repr;
@@ -475,14 +460,173 @@ Node CoreSolver::getModelValue(TNode var) {
return result;
}
+EqualityStatus CoreSolver::getEqualityStatus(TNode a, TNode 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;
+}
+
+bool CoreSolver::hasTerm(TNode node) const
+{
+ return d_equalityEngine->hasTerm(node);
+}
+void CoreSolver::addTermToEqualityEngine(TNode node)
+{
+ d_equalityEngine->addTerm(node);
+}
+
CoreSolver::Statistics::Statistics()
: d_numCallstoCheck("theory::bv::CoreSolver::NumCallsToCheck", 0)
- , d_slicerEnabled("theory::bv::CoreSolver::SlicerEnabled", false)
{
smtStatisticsRegistry()->registerStat(&d_numCallstoCheck);
- smtStatisticsRegistry()->registerStat(&d_slicerEnabled);
}
CoreSolver::Statistics::~Statistics() {
smtStatisticsRegistry()->unregisterStat(&d_numCallstoCheck);
- smtStatisticsRegistry()->unregisterStat(&d_slicerEnabled);
+}
+
+void CoreSolver::checkExtf(Theory::Effort e)
+{
+ if (e == Theory::EFFORT_LAST_CALL)
+ {
+ std::vector<Node> nred = d_extTheory->getActive();
+ doExtfReductions(nred);
+ }
+ Assert(e == Theory::EFFORT_FULL);
+ // do inferences (adds external lemmas) TODO: this can be improved to add
+ // internal inferences
+ std::vector<Node> nred;
+ if (d_extTheory->doInferences(0, nred))
+ {
+ return;
+ }
+ d_needsLastCallCheck = false;
+ if (!nred.empty())
+ {
+ // other inferences involving bv2nat, int2bv
+ if (options::bvAlgExtf())
+ {
+ if (doExtfInferences(nred))
+ {
+ return;
+ }
+ }
+ if (!options::bvLazyReduceExtf())
+ {
+ if (doExtfReductions(nred))
+ {
+ return;
+ }
+ }
+ else
+ {
+ d_needsLastCallCheck = true;
+ }
+ }
+}
+
+bool CoreSolver::needsCheckLastEffort() const { return d_needsLastCallCheck; }
+
+bool CoreSolver::doExtfInferences(std::vector<Node>& terms)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ bool sentLemma = false;
+ eq::EqualityEngine* ee = d_equalityEngine;
+ std::map<Node, Node> op_map;
+ for (unsigned j = 0; j < terms.size(); j++)
+ {
+ TNode n = terms[j];
+ Assert(n.getKind() == kind::BITVECTOR_TO_NAT
+ || n.getKind() == kind::INT_TO_BITVECTOR);
+ if (n.getKind() == kind::BITVECTOR_TO_NAT)
+ {
+ // range lemmas
+ if (d_extf_range_infer.find(n) == d_extf_range_infer.end())
+ {
+ d_extf_range_infer.insert(n);
+ unsigned bvs = n[0].getType().getBitVectorSize();
+ Node min = nm->mkConst(Rational(0));
+ Node max = nm->mkConst(Rational(Integer(1).multiplyByPow2(bvs)));
+ Node lem = nm->mkNode(kind::AND,
+ nm->mkNode(kind::GEQ, n, min),
+ nm->mkNode(kind::LT, n, max));
+ Trace("bv-extf-lemma")
+ << "BV extf lemma (range) : " << lem << std::endl;
+ d_bv->d_inferManager.lemma(lem);
+ sentLemma = true;
+ }
+ }
+ Node r = (ee && ee->hasTerm(n[0])) ? ee->getRepresentative(n[0]) : n[0];
+ op_map[r] = n;
+ }
+ for (unsigned j = 0; j < terms.size(); j++)
+ {
+ TNode n = terms[j];
+ Node r = (ee && ee->hasTerm(n[0])) ? ee->getRepresentative(n) : n;
+ std::map<Node, Node>::iterator it = op_map.find(r);
+ if (it != op_map.end())
+ {
+ Node parent = it->second;
+ // Node cterm = parent[0]==n ? parent : nm->mkNode( parent.getOperator(),
+ // n );
+ Node cterm = parent[0].eqNode(n);
+ Trace("bv-extf-lemma-debug")
+ << "BV extf collapse based on : " << cterm << std::endl;
+ if (d_extf_collapse_infer.find(cterm) == d_extf_collapse_infer.end())
+ {
+ d_extf_collapse_infer.insert(cterm);
+
+ Node t = n[0];
+ if (t.getType() == parent.getType())
+ {
+ if (n.getKind() == kind::INT_TO_BITVECTOR)
+ {
+ Assert(t.getType().isInteger());
+ // congruent modulo 2^( bv width )
+ unsigned bvs = n.getType().getBitVectorSize();
+ Node coeff = nm->mkConst(Rational(Integer(1).multiplyByPow2(bvs)));
+ Node k = nm->mkSkolem(
+ "int_bv_cong", t.getType(), "for int2bv/bv2nat congruence");
+ t = nm->mkNode(kind::PLUS, t, nm->mkNode(kind::MULT, coeff, k));
+ }
+ Node lem = parent.eqNode(t);
+
+ if (parent[0] != n)
+ {
+ Assert(ee->areEqual(parent[0], n));
+ lem = nm->mkNode(kind::IMPLIES, parent[0].eqNode(n), lem);
+ }
+ // this handles inferences of the form, e.g.:
+ // ((_ int2bv w) (bv2nat x)) == x (if x is bit-width w)
+ // (bv2nat ((_ int2bv w) x)) == x + k*2^w for some k
+ Trace("bv-extf-lemma")
+ << "BV extf lemma (collapse) : " << lem << std::endl;
+ d_bv->d_inferManager.lemma(lem);
+ sentLemma = true;
+ }
+ }
+ Trace("bv-extf-lemma-debug")
+ << "BV extf f collapse based on : " << cterm << std::endl;
+ }
+ }
+ return sentLemma;
+}
+
+bool CoreSolver::doExtfReductions(std::vector<Node>& terms)
+{
+ std::vector<Node> nredr;
+ if (d_extTheory->doReductions(0, terms, nredr))
+ {
+ return true;
+ }
+ Assert(nredr.empty());
+ return false;
}
diff --git a/src/theory/bv/bv_subtheory_core.h b/src/theory/bv/bv_subtheory_core.h
index a9ca57fb4..3cd2686f8 100644
--- a/src/theory/bv/bv_subtheory_core.h
+++ b/src/theory/bv/bv_subtheory_core.h
@@ -2,10 +2,10 @@
/*! \file bv_subtheory_core.h
** \verbatim
** Top contributors (to current version):
- ** Liana Hadarean, Mathias Preiner, Tim King
+ ** Andrew Reynolds, Liana Hadarean, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -24,13 +24,30 @@
#include "context/cdhashmap.h"
#include "context/cdhashset.h"
#include "theory/bv/bv_subtheory.h"
+#include "theory/ext_theory.h"
namespace CVC4 {
namespace theory {
namespace bv {
-class Slicer;
class Base;
+
+/** An extended theory callback used by the core solver */
+class CoreSolverExtTheoryCallback : public ExtTheoryCallback
+{
+ public:
+ CoreSolverExtTheoryCallback() : d_equalityEngine(nullptr) {}
+ /** Get current substitution based on the underlying equality engine. */
+ bool getCurrentSubstitution(int effort,
+ const std::vector<Node>& vars,
+ std::vector<Node>& subs,
+ std::map<Node, std::vector<Node> >& exp) override;
+ /** Get reduction. */
+ bool getReduction(int effort, Node n, Node& nr, bool& satDep) override;
+ /** The underlying equality engine */
+ eq::EqualityEngine* d_equalityEngine;
+};
+
/**
* Bitvector equality solver
*/
@@ -42,7 +59,6 @@ class CoreSolver : public SubtheorySolver {
struct Statistics {
IntStat d_numCallstoCheck;
- BackedStat<bool> d_slicerEnabled;
Statistics();
~Statistics();
};
@@ -53,16 +69,14 @@ class CoreSolver : public SubtheorySolver {
public:
NotifyClass(CoreSolver& solver): d_solver(solver) {}
- bool eqNotifyTriggerEquality(TNode equality, bool value) override;
bool eqNotifyTriggerPredicate(TNode predicate, bool value) override;
bool eqNotifyTriggerTermEquality(TheoryId tag,
TNode t1,
TNode t2,
bool value) override;
void eqNotifyConstantTermMerge(TNode t1, TNode t2) override;
- void eqNotifyNewClass(TNode t) override;
- void eqNotifyPreMerge(TNode t1, TNode t2) override {}
- void eqNotifyPostMerge(TNode t1, TNode t2) override {}
+ void eqNotifyNewClass(TNode t) override {}
+ void eqNotifyMerge(TNode t1, TNode t2) override {}
void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override {}
};
@@ -70,69 +84,85 @@ 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);
- /** new equivalence class */
- void eqNotifyNewClass(TNode t);
-
- std::unique_ptr<Slicer> d_slicer;
context::CDO<bool> d_isComplete;
unsigned d_lemmaThreshold;
-
- /** Used to ensure that the core slicer is used properly*/
- bool d_useSlicer;
+
bool d_preregisterCalled;
bool d_checkCalled;
-
+
+ /** Pointer to the parent theory solver that owns this */
+ BVSolverLazy* d_bv;
+ /** Pointer to the equality engine of the parent */
+ eq::EqualityEngine* d_equalityEngine;
+ /** The extended theory callback */
+ CoreSolverExtTheoryCallback d_extTheoryCb;
+ /** Extended theory module, for context-dependent simplification. */
+ std::unique_ptr<ExtTheory> d_extTheory;
+
/** To make sure we keep the explanations */
context::CDHashSet<Node, NodeHashFunction> d_reasons;
ModelValue d_modelValues;
void buildModel();
bool assertFactToEqualityEngine(TNode fact, TNode reason);
- bool decomposeFact(TNode fact);
- Node getBaseDecomposition(TNode a);
bool isCompleteForTerm(TNode term, TNodeBoolMap& seen);
Statistics d_statistics;
-public:
- CoreSolver(context::Context* c, TheoryBV* bv);
+
+ /** Whether we need a last call effort check */
+ bool d_needsLastCallCheck;
+ /** For extended functions */
+ context::CDHashSet<Node, NodeHashFunction> d_extf_range_infer;
+ context::CDHashSet<Node, NodeHashFunction> d_extf_collapse_infer;
+
+ /** do extended function inferences
+ *
+ * This method adds lemmas on the output channel of TheoryBV based on
+ * reasoning about extended functions, such as bv2nat and int2bv. Examples
+ * of lemmas added by this method include:
+ * 0 <= ((_ int2bv w) x) < 2^w
+ * ((_ int2bv w) (bv2nat x)) = x
+ * (bv2nat ((_ int2bv w) x)) == x + k*2^w
+ * The purpose of these lemmas is to recognize easy conflicts before fully
+ * reducing extended functions based on their full semantics.
+ */
+ bool doExtfInferences(std::vector<Node>& terms);
+ /** do extended function reductions
+ *
+ * This method adds lemmas on the output channel of TheoryBV based on
+ * reducing all extended function applications that are preregistered to
+ * this theory and have not already been reduced by context-dependent
+ * simplification (see theory/ext_theory.h). Examples of lemmas added by
+ * this method include:
+ * (bv2nat x) = (ite ((_ extract w w-1) x) 2^{w-1} 0) + ... +
+ * (ite ((_ extract 1 0) x) 1 0)
+ */
+ bool doExtfReductions(std::vector<Node>& terms);
+
+ public:
+ CoreSolver(context::Context* c, BVSolverLazy* bv);
~CoreSolver();
+ bool needsEqualityEngine(EeSetupInfo& esi);
+ void finishInit();
bool isComplete() override { return d_isComplete; }
- void setMasterEqualityEngine(eq::EqualityEngine* eq);
void preRegister(TNode node) override;
bool check(Theory::Effort e) override;
void explain(TNode literal, std::vector<TNode>& assumptions) override;
- bool collectModelInfo(TheoryModel* m, bool fullModel) override;
+ bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet) override;
Node getModelValue(TNode var) override;
- void addSharedTerm(TNode t) override
- {
- d_equalityEngine.addTriggerTerm(t, THEORY_BV);
- }
- EqualityStatus getEqualityStatus(TNode a, TNode b) override
- {
- 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;
- }
- bool hasTerm(TNode node) const { return d_equalityEngine.hasTerm(node); }
- void addTermToEqualityEngine(TNode node) { d_equalityEngine.addTerm(node); }
- void enableSlicer();
- eq::EqualityEngine * getEqualityEngine() { return &d_equalityEngine; }
+ EqualityStatus getEqualityStatus(TNode a, TNode b) override;
+ bool hasTerm(TNode node) const;
+ void addTermToEqualityEngine(TNode node);
+ /** check extended functions at the given effort */
+ void checkExtf(Theory::Effort e);
+ bool needsCheckLastEffort() const;
};
-
}
}
}
diff --git a/src/theory/bv/bv_subtheory_inequality.cpp b/src/theory/bv/bv_subtheory_inequality.cpp
index 1ff23c460..0c25d4212 100644
--- a/src/theory/bv/bv_subtheory_inequality.cpp
+++ b/src/theory/bv/bv_subtheory_inequality.cpp
@@ -5,7 +5,7 @@
** Liana Hadarean, Aina Niemetz, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,7 +18,7 @@
#include "options/smt_options.h"
#include "smt/smt_statistics_registry.h"
-#include "theory/bv/theory_bv.h"
+#include "theory/bv/bv_solver_lazy.h"
#include "theory/bv/theory_bv_utils.h"
#include "theory/theory_model.h"
@@ -189,9 +189,10 @@ void InequalitySolver::explain(TNode literal, std::vector<TNode>& assumptions) {
}
void InequalitySolver::propagate(Theory::Effort e) { Assert(false); }
-bool InequalitySolver::collectModelInfo(TheoryModel* m, bool fullModel)
+bool InequalitySolver::collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet)
{
- Debug("bitvector-model") << "InequalitySolver::collectModelInfo \n";
+ Debug("bitvector-model") << "InequalitySolver::collectModelValues \n";
std::vector<Node> model;
d_inequalityGraph.getAllValuesInModel(model);
for (unsigned i = 0; i < model.size(); ++i) {
diff --git a/src/theory/bv/bv_subtheory_inequality.h b/src/theory/bv/bv_subtheory_inequality.h
index abfb0d3cf..7ecfe5bd1 100644
--- a/src/theory/bv/bv_subtheory_inequality.h
+++ b/src/theory/bv/bv_subtheory_inequality.h
@@ -2,10 +2,10 @@
/*! \file bv_subtheory_inequality.h
** \verbatim
** Top contributors (to current version):
- ** Liana Hadarean, Mathias Preiner, Morgan Deters
+ ** Mathias Preiner, Liana Hadarean, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -31,12 +31,17 @@ namespace theory {
namespace bv {
/** Cache for InequalitySolver::isInequalityOnly() */
-struct IneqOnlyAttributeId {};
+struct IneqOnlyAttributeId
+{
+};
typedef expr::Attribute<IneqOnlyAttributeId, bool> IneqOnlyAttribute;
/** Whether the above has been computed yet or not for an expr */
-struct IneqOnlyComputedAttributeId {};
-typedef expr::Attribute<IneqOnlyComputedAttributeId, bool> IneqOnlyComputedAttribute;
+struct IneqOnlyComputedAttributeId
+{
+};
+typedef expr::Attribute<IneqOnlyComputedAttributeId, bool>
+ IneqOnlyComputedAttribute;
class InequalitySolver : public SubtheorySolver
{
@@ -57,30 +62,33 @@ class InequalitySolver : public SubtheorySolver
bool isInequalityOnly(TNode node);
bool addInequality(TNode a, TNode b, bool strict, TNode fact);
Statistics d_statistics;
-public:
- InequalitySolver(context::Context* c, context::Context* u, TheoryBV* bv)
- : SubtheorySolver(c, bv),
- d_assertionSet(c),
- d_inequalityGraph(c, u),
- d_explanations(c),
- d_isComplete(c, true),
- d_ineqTerms(),
- d_statistics()
- {}
+
+ public:
+ InequalitySolver(context::Context* c, context::Context* u, BVSolverLazy* bv)
+ : SubtheorySolver(c, bv),
+ d_assertionSet(c),
+ d_inequalityGraph(c, u),
+ d_explanations(c),
+ d_isComplete(c, true),
+ d_ineqTerms(),
+ d_statistics()
+ {
+ }
bool check(Theory::Effort e) override;
void propagate(Theory::Effort e) override;
void explain(TNode literal, std::vector<TNode>& assumptions) override;
bool isComplete() override { return d_isComplete; }
- bool collectModelInfo(TheoryModel* m, bool fullModel) override;
+ bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet) override;
Node getModelValue(TNode var) override;
EqualityStatus getEqualityStatus(TNode a, TNode b) override;
void assertFact(TNode fact) override;
void preRegister(TNode node) override;
};
-}
-}
-}
+} // namespace bv
+} // namespace theory
+} // namespace CVC4
#endif /* CVC4__THEORY__BV__BV_SUBTHEORY__INEQUALITY_H */
diff --git a/src/theory/bv/slicer.cpp b/src/theory/bv/slicer.cpp
index 4524ddb8c..1e2c55c15 100644
--- a/src/theory/bv/slicer.cpp
+++ b/src/theory/bv/slicer.cpp
@@ -2,10 +2,10 @@
/*! \file slicer.cpp
** \verbatim
** Top contributors (to current version):
- ** Liana Hadarean, Aina Niemetz, Mathias Preiner
+ ** Liana Hadarean, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -15,41 +15,15 @@
**/
#include "theory/bv/slicer.h"
-#include "options/bv_options.h"
-#include "smt/smt_statistics_registry.h"
#include "theory/bv/theory_bv_utils.h"
#include "theory/rewriter.h"
using namespace std;
-
namespace CVC4 {
namespace theory {
namespace bv {
-const TermId UndefinedId = -1;
-
-namespace {
-
-void intersect(const std::vector<TermId>& v1,
- const std::vector<TermId>& v2,
- std::vector<TermId>& intersection)
-{
- for (const TermId id1 : v1)
- {
- for (const TermId id2 : v2)
- {
- if (id2 == id1)
- {
- intersection.push_back(id1);
- break;
- }
- }
- }
-}
-
-} // namespace
-
/**
* Base
*
@@ -72,13 +46,6 @@ void Base::sliceAt(Index index)
d_repr[vector_index] = d_repr[vector_index] | bit_mask;
}
-void Base::sliceWith(const Base& other) {
- Assert(d_size == other.d_size);
- for (unsigned i = 0; i < d_repr.size(); ++i) {
- d_repr[i] = d_repr[i] | other.d_repr[i];
- }
-}
-
bool Base::isCutPoint (Index index) const
{
// there is an implicit cut point at the end and begining of the bv
@@ -93,22 +60,6 @@ bool Base::isCutPoint (Index index) const
return (bit_mask & d_repr[vector_index]) != 0;
}
-void Base::diffCutPoints(const Base& other, Base& res) const {
- Assert(d_size == other.d_size && res.d_size == d_size);
- for (unsigned i = 0; i < d_repr.size(); ++i) {
- Assert(res.d_repr[i] == 0);
- res.d_repr[i] = d_repr[i] ^ other.d_repr[i];
- }
-}
-
-bool Base::isEmpty() const {
- for (unsigned i = 0; i< d_repr.size(); ++i) {
- if (d_repr[i] != 0)
- return false;
- }
- return true;
-}
-
std::string Base::debugPrint() const {
std::ostringstream os;
os << "[";
@@ -127,543 +78,6 @@ std::string Base::debugPrint() const {
return os.str();
}
-/**
- * ExtractTerm
- *
- */
-
-std::string ExtractTerm::debugPrint() const {
- ostringstream os;
- os << "id" << id << "[" << high << ":" << low <<"] ";
- return os.str();
-}
-
-/**
- * NormalForm
- *
- */
-
-std::pair<TermId, Index> NormalForm::getTerm(Index index, const UnionFind& uf) const {
- Assert(index < base.getBitwidth());
- Index count = 0;
- for (unsigned i = 0; i < decomp.size(); ++i) {
- Index size = uf.getBitwidth(decomp[i]);
- if ( count + size > index && index >= count) {
- return pair<TermId, Index>(decomp[i], count);
- }
- count += size;
- }
- Unreachable();
-}
-
-
-
-std::string NormalForm::debugPrint(const UnionFind& uf) const {
- ostringstream os;
- os << "NF " << base.debugPrint() << endl;
- os << "(";
- for (int i = decomp.size() - 1; i>= 0; --i) {
- os << decomp[i] << "[" << uf.getBitwidth(decomp[i]) <<"]";
- os << (i != 0? ", " : "");
- }
- os << ") \n";
- return os.str();
-}
-/**
- * UnionFind::Node
- *
- */
-
-std::string UnionFind::Node::debugPrint() const {
- ostringstream os;
- os << "Repr " << d_repr << " ["<< d_bitwidth << "] ";
- os << "( " << d_ch1 <<", " << d_ch0 << ")" << endl;
- return os.str();
-}
-
-
-/**
- * UnionFind
- *
- */
-TermId UnionFind::addTerm(Index bitwidth) {
- Node node(bitwidth);
- d_nodes.push_back(node);
- ++(d_statistics.d_numNodes);
-
- TermId id = d_nodes.size() - 1;
- d_representatives.insert(id);
- ++(d_statistics.d_numRepresentatives);
-
- Debug("bv-slicer-uf") << "UnionFind::addTerm " << id << " size " << bitwidth << endl;
- return id;
-}
-/**
- * At this point we assume the slicings of the two terms are properly aligned.
- *
- * @param t1
- * @param t2
- */
-void UnionFind::unionTerms(const ExtractTerm& t1, const ExtractTerm& t2) {
- Debug("bv-slicer") << "UnionFind::unionTerms " << t1.debugPrint() << " and \n"
- << " " << t2.debugPrint() << endl;
- Assert(t1.getBitwidth() == t2.getBitwidth());
-
- NormalForm nf1(t1.getBitwidth());
- NormalForm nf2(t2.getBitwidth());
-
- getNormalForm(t1, nf1);
- getNormalForm(t2, nf2);
-
- Assert(nf1.decomp.size() == nf2.decomp.size());
- Assert(nf1.base == nf2.base);
-
- for (unsigned i = 0; i < nf1.decomp.size(); ++i) {
- merge (nf1.decomp[i], nf2.decomp[i]);
- }
-}
-
-/**
- * Merge the two terms in the union find. Both t1 and t2
- * should be root terms.
- *
- * @param t1
- * @param t2
- */
-void UnionFind::merge(TermId t1, TermId t2) {
- Debug("bv-slicer-uf") << "UnionFind::merge (" << t1 <<", " << t2 << ")" << endl;
- ++(d_statistics.d_numMerges);
- t1 = find(t1);
- t2 = find(t2);
-
- if (t1 == t2)
- return;
-
- Assert(!hasChildren(t1) && !hasChildren(t2));
- setRepr(t1, t2);
- d_representatives.erase(t1);
- d_statistics.d_numRepresentatives += -1;
-}
-
-TermId UnionFind::find(TermId id) {
- TermId repr = getRepr(id);
- if (repr != UndefinedId) {
- TermId find_id = find(repr);
- setRepr(id, find_id);
- return find_id;
- }
- return id;
-}
-/**
- * Splits the representative of the term between i-1 and i
- *
- * @param id the id of the term
- * @param i the index we are splitting at
- *
- * @return
- */
-void UnionFind::split(TermId id, Index i) {
- Debug("bv-slicer-uf") << "UnionFind::split " << id << " at " << i << endl;
- id = find(id);
- Debug("bv-slicer-uf") << " node: " << d_nodes[id].debugPrint() << endl;
-
- if (i == 0 || i == getBitwidth(id)) {
- // nothing to do
- return;
- }
- Assert(i < getBitwidth(id));
- if (!hasChildren(id)) {
- // first time we split this term
- TermId bottom_id = addTerm(i);
- TermId top_id = addTerm(getBitwidth(id) - i);
- setChildren(id, top_id, bottom_id);
-
- } else {
- Index cut = getCutPoint(id);
- if (i < cut )
- split(getChild(id, 0), i);
- else
- split(getChild(id, 1), i - cut);
- }
- ++(d_statistics.d_numSplits);
-}
-
-void UnionFind::getNormalForm(const ExtractTerm& term, NormalForm& nf) {
- nf.clear();
- getDecomposition(term, nf.decomp);
- // update nf base
- Index count = 0;
- for (unsigned i = 0; i < nf.decomp.size(); ++i) {
- count += getBitwidth(nf.decomp[i]);
- nf.base.sliceAt(count);
- }
- Debug("bv-slicer-uf") << "UnionFind::getNormalFrom term: " << term.debugPrint() << endl;
- Debug("bv-slicer-uf") << " nf: " << nf.debugPrint(*this) << endl;
-}
-
-void UnionFind::getDecomposition(const ExtractTerm& term, Decomposition& decomp) {
- // making sure the term is aligned
- TermId id = find(term.id);
-
- Assert(term.high < getBitwidth(id));
- // because we split the node, this must be the whole extract
- if (!hasChildren(id)) {
- Assert(term.high == getBitwidth(id) - 1 && term.low == 0);
- decomp.push_back(id);
- return;
- }
-
- Index cut = getCutPoint(id);
-
- if (term.low < cut && term.high < cut) {
- // the extract falls entirely on the low child
- ExtractTerm child_ex(getChild(id, 0), term.high, term.low);
- getDecomposition(child_ex, decomp);
- }
- else if (term.low >= cut && term.high >= cut){
- // the extract falls entirely on the high child
- ExtractTerm child_ex(getChild(id, 1), term.high - cut, term.low - cut);
- getDecomposition(child_ex, decomp);
- }
- else {
- // the extract is split over the two children
- ExtractTerm low_child(getChild(id, 0), cut - 1, term.low);
- getDecomposition(low_child, decomp);
- ExtractTerm high_child(getChild(id, 1), term.high - cut, 0);
- getDecomposition(high_child, decomp);
- }
-}
-
-/* Compute the greatest common divisor of two indices. */
-static Index gcd(Index a, Index b)
-{
- while (b != 0)
- {
- Index t = b;
- b = a % t;
- a = t;
- }
- return a;
-}
-
-/**
- * May cause reslicings of the decompositions. Must not assume the decompositons
- * are the current normal form.
- *
- * @param d1
- * @param d2
- * @param common
- */
-void UnionFind::handleCommonSlice(const Decomposition& decomp1, const Decomposition& decomp2, TermId common) {
- Debug("bv-slicer") << "UnionFind::handleCommonSlice common = " << common << endl;
- Index common_size = getBitwidth(common);
- // find starting points of common slice
- Index start1 = 0;
- for (unsigned j = 0; j < decomp1.size(); ++j) {
- if (decomp1[j] == common)
- break;
- start1 += getBitwidth(decomp1[j]);
- }
-
- Index start2 = 0;
- for (unsigned j = 0; j < decomp2.size(); ++j) {
- if (decomp2[j] == common)
- break;
- start2 += getBitwidth(decomp2[j]);
- }
- if (start1 > start2) {
- Index temp = start1;
- start1 = start2;
- start2 = temp;
- }
-
- if (start2 - start1 < common_size) {
- Index overlap = start1 + common_size - start2;
- Assert(overlap > 0);
- Index diff = common_size - overlap;
- Assert(diff >= 0);
- Index granularity = gcd(diff, overlap);
- // split the common part
- for (unsigned i = 0; i < common_size; i+= granularity) {
- split(common, i);
- }
- }
-
-}
-
-void UnionFind::alignSlicings(const ExtractTerm& term1, const ExtractTerm& term2) {
- Debug("bv-slicer") << "UnionFind::alignSlicings " << term1.debugPrint() << endl;
- Debug("bv-slicer") << " " << term2.debugPrint() << endl;
- NormalForm nf1(term1.getBitwidth());
- NormalForm nf2(term2.getBitwidth());
-
- getNormalForm(term1, nf1);
- getNormalForm(term2, nf2);
-
- Assert(nf1.base.getBitwidth() == nf2.base.getBitwidth());
-
- // first check if the two have any common slices
- std::vector<TermId> intersection;
- intersect(nf1.decomp, nf2.decomp, intersection);
- for (TermId id : intersection)
- {
- /* handleCommonSlice() may change the normal form */
- handleCommonSlice(nf1.decomp, nf2.decomp, id);
- }
- // propagate cuts to a fixpoint
- bool changed;
- Base cuts(term1.getBitwidth());
- do {
- changed = false;
- // we need to update the normal form which may have changed
- getNormalForm(term1, nf1);
- getNormalForm(term2, nf2);
-
- // align the cuts points of the two slicings
- // FIXME: this can be done more efficiently
- cuts.sliceWith(nf1.base);
- cuts.sliceWith(nf2.base);
-
- for (unsigned i = 0; i < cuts.getBitwidth(); ++i) {
- if (cuts.isCutPoint(i)) {
- if (!nf1.base.isCutPoint(i)) {
- pair<TermId, Index> pair1 = nf1.getTerm(i, *this);
- split(pair1.first, i - pair1.second);
- changed = true;
- }
- if (!nf2.base.isCutPoint(i)) {
- pair<TermId, Index> pair2 = nf2.getTerm(i, *this);
- split(pair2.first, i - pair2.second);
- changed = true;
- }
- }
- }
- } while (changed);
-}
-/**
- * Given an extract term a[i:j] makes sure a is sliced
- * at indices i and j.
- *
- * @param term
- */
-void UnionFind::ensureSlicing(const ExtractTerm& term) {
- //Debug("bv-slicer") << "Slicer::ensureSlicing " << term.debugPrint() << endl;
- TermId id = find(term.id);
- split(id, term.high + 1);
- split(id, term.low);
-}
-
-/**
- * Slicer
- *
- */
-
-ExtractTerm Slicer::registerTerm(TNode node) {
- Index low = 0, high = utils::getSize(node) - 1;
- TNode n = node;
- if (node.getKind() == kind::BITVECTOR_EXTRACT) {
- n = node[0];
- high = utils::getExtractHigh(node);
- low = utils::getExtractLow(node);
- }
- if (d_nodeToId.find(n) == d_nodeToId.end()) {
- TermId id = d_unionFind.addTerm(utils::getSize(n));
- d_nodeToId[n] = id;
- d_idToNode[id] = n;
- }
- TermId id = d_nodeToId[n];
- ExtractTerm res(id, high, low);
- Debug("bv-slicer") << "Slicer::registerTerm " << node << " => " << res.debugPrint() << endl;
- return res;
-}
-
-void Slicer::processEquality(TNode eq) {
- Debug("bv-slicer") << "Slicer::processEquality: " << eq << endl;
-
- Assert(eq.getKind() == kind::EQUAL);
- TNode a = eq[0];
- TNode b = eq[1];
- ExtractTerm a_ex= registerTerm(a);
- ExtractTerm b_ex= registerTerm(b);
-
- d_unionFind.ensureSlicing(a_ex);
- d_unionFind.ensureSlicing(b_ex);
-
- d_unionFind.alignSlicings(a_ex, b_ex);
- d_unionFind.unionTerms(a_ex, b_ex);
- Debug("bv-slicer") << "Base of " << a_ex.id <<" " << d_unionFind.debugPrint(a_ex.id) << endl;
- Debug("bv-slicer") << "Base of " << b_ex.id <<" " << d_unionFind.debugPrint(b_ex.id) << endl;
- Debug("bv-slicer") << "Slicer::processEquality done. " << endl;
-}
-
-void Slicer::getBaseDecomposition(TNode node, std::vector<Node>& decomp) {
- Debug("bv-slicer") << "Slicer::getBaseDecomposition " << node << endl;
-
- Index high = utils::getSize(node) - 1;
- Index low = 0;
- TNode top = node;
- if (node.getKind() == kind::BITVECTOR_EXTRACT) {
- high = utils::getExtractHigh(node);
- low = utils::getExtractLow(node);
- top = node[0];
- }
- AlwaysAssert(d_nodeToId.find(top) != d_nodeToId.end());
- TermId id = d_nodeToId[top];
- NormalForm nf(high-low+1);
- d_unionFind.getNormalForm(ExtractTerm(id, high, low), nf);
-
- // construct actual extract nodes
- unsigned size = utils::getSize(node);
- Index current_low = size;
- Index current_high = size;
- for (int i = nf.decomp.size() - 1; i >= 0; --i) {
- Index current_size = d_unionFind.getBitwidth(nf.decomp[i]);
- current_low -= current_size;
- Node current = Rewriter::rewrite(utils::mkExtract(node, current_high - 1, current_low));
- current_high = current_low;
- decomp.push_back(current);
- }
-
- Debug("bv-slicer") << "as [";
- for (unsigned i = 0; i < decomp.size(); ++i) {
- Debug("bv-slicer") << decomp[i] <<" ";
- }
- Debug("bv-slicer") << "]" << endl;
-
-}
-
-bool Slicer::isCoreTerm(TNode node) {
- if (d_coreTermCache.find(node) == d_coreTermCache.end()) {
- Kind kind = node.getKind();
- bool not_core;
- if (options::bitvectorEqualitySlicer() != options::BvSlicerMode::OFF)
- {
- not_core =
- (kind != kind::BITVECTOR_EXTRACT && kind != kind::BITVECTOR_CONCAT);
- }
- else
- {
- not_core = true;
- }
- if (not_core &&
- kind != kind::EQUAL &&
- kind != kind::NOT &&
- kind != kind::STORE &&
- kind != kind::SELECT &&
- node.getMetaKind() != kind::metakind::VARIABLE &&
- kind != kind::CONST_BITVECTOR) {
- d_coreTermCache[node] = false;
- return false;
- } else {
- // we need to recursively check whether the term is a root term or not
- bool isCore = true;
- for (unsigned i = 0; i < node.getNumChildren(); ++i) {
- isCore = isCore && isCoreTerm(node[i]);
- }
- d_coreTermCache[node] = isCore;
- return isCore;
- }
- }
- return d_coreTermCache[node];
-}
-unsigned Slicer::d_numAddedEqualities = 0;
-
-void Slicer::splitEqualities(TNode node, std::vector<Node>& equalities)
-{
- Assert(node.getKind() == kind::EQUAL);
- NodeManager* nm = NodeManager::currentNM();
- TNode t1 = node[0];
- TNode t2 = node[1];
-
- uint32_t width = utils::getSize(t1);
-
- Base base1(width);
- if (t1.getKind() == kind::BITVECTOR_CONCAT)
- {
- int size = 0;
- // no need to count the last child since the end cut point is implicit
- for (int i = t1.getNumChildren() - 1; i >= 1; --i)
- {
- size = size + utils::getSize(t1[i]);
- base1.sliceAt(size);
- }
- }
-
- Base base2(width);
- if (t2.getKind() == kind::BITVECTOR_CONCAT)
- {
- unsigned size = 0;
- for (int i = t2.getNumChildren() - 1; i >= 1; --i)
- {
- size = size + utils::getSize(t2[i]);
- base2.sliceAt(size);
- }
- }
-
- base1.sliceWith(base2);
- if (!base1.isEmpty())
- {
- // we split the equalities according to the base
- int last = 0;
- for (unsigned i = 1; i <= utils::getSize(t1); ++i)
- {
- if (base1.isCutPoint(i))
- {
- Node extract1 = utils::mkExtract(t1, i - 1, last);
- Node extract2 = utils::mkExtract(t2, i - 1, last);
- last = i;
- Assert(utils::getSize(extract1) == utils::getSize(extract2));
- equalities.push_back(nm->mkNode(kind::EQUAL, extract1, extract2));
- }
- }
- }
- else
- {
- // just return same equality
- equalities.push_back(node);
- }
- d_numAddedEqualities += equalities.size() - 1;
-}
-
-std::string UnionFind::debugPrint(TermId id) {
- ostringstream os;
- if (hasChildren(id)) {
- TermId id1 = find(getChild(id, 1));
- TermId id0 = find(getChild(id, 0));
- os << debugPrint(id1);
- os << debugPrint(id0);
- } else {
- if (getRepr(id) == UndefinedId) {
- os <<"id"<< id <<"[" << getBitwidth(id) <<"] ";
- } else {
- os << debugPrint(find(id));
- }
- }
- return os.str();
-}
-
-UnionFind::Statistics::Statistics():
- d_numNodes("theory::bv::slicer::NumNodes", 0),
- d_numRepresentatives("theory::bv::slicer::NumRepresentatives", 0),
- d_numSplits("theory::bv::slicer::NumSplits", 0),
- d_numMerges("theory::bv::slicer::NumMerges", 0),
- d_avgFindDepth("theory::bv::slicer::AverageFindDepth"),
- d_numAddedEqualities("theory::bv::slicer::NumEqualitiesAdded", Slicer::d_numAddedEqualities)
-{
- smtStatisticsRegistry()->registerStat(&d_numRepresentatives);
- smtStatisticsRegistry()->registerStat(&d_numSplits);
- smtStatisticsRegistry()->registerStat(&d_numMerges);
- smtStatisticsRegistry()->registerStat(&d_avgFindDepth);
- smtStatisticsRegistry()->registerStat(&d_numAddedEqualities);
-}
-
-UnionFind::Statistics::~Statistics() {
- smtStatisticsRegistry()->unregisterStat(&d_numRepresentatives);
- smtStatisticsRegistry()->unregisterStat(&d_numSplits);
- smtStatisticsRegistry()->unregisterStat(&d_numMerges);
- smtStatisticsRegistry()->unregisterStat(&d_avgFindDepth);
- smtStatisticsRegistry()->unregisterStat(&d_numAddedEqualities);
-}
} // namespace bv
} // namespace theory
diff --git a/src/theory/bv/slicer.h b/src/theory/bv/slicer.h
index 794df633f..290b58386 100644
--- a/src/theory/bv/slicer.h
+++ b/src/theory/bv/slicer.h
@@ -2,10 +2,10 @@
/*! \file slicer.h
** \verbatim
** Top contributors (to current version):
- ** Liana Hadarean, Mathias Preiner, Tim King
+ ** Liana Hadarean, Mathias Preiner, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,33 +16,17 @@
#include "cvc4_private.h"
-#include <math.h>
-
-#include <vector>
-#include <list>
-#include <unordered_map>
-
-#include "expr/node.h"
-#include "theory/bv/theory_bv_utils.h"
-#include "util/bitvector.h"
-#include "util/index.h"
-#include "util/statistics_registry.h"
-
#ifndef CVC4__THEORY__BV__SLICER_BV_H
#define CVC4__THEORY__BV__SLICER_BV_H
+#include <string>
+#include <vector>
+#include "util/index.h"
namespace CVC4 {
-
namespace theory {
namespace bv {
-
-
-typedef Index TermId;
-extern const TermId UndefinedId;
-
-
/**
* Base
*
@@ -53,20 +37,10 @@ class Base {
public:
Base(Index size);
void sliceAt(Index index);
- void sliceWith(const Base& other);
bool isCutPoint(Index index) const;
- void diffCutPoints(const Base& other, Base& res) const;
- bool isEmpty() const;
std::string debugPrint() const;
- Index getBitwidth() const { return d_size; }
- void clear() {
- for (unsigned i = 0; i < d_repr.size(); ++i) {
- d_repr[i] = 0;
- }
- }
bool operator==(const Base& other) const {
- if (other.getBitwidth() != getBitwidth())
- return false;
+ if (other.d_size != d_size) return false;
for (unsigned i = 0; i < d_repr.size(); ++i) {
if (d_repr[i] != other.d_repr[i])
return false;
@@ -75,179 +49,6 @@ public:
}
};
-/**
- * UnionFind
- *
- */
-typedef std::unordered_set<TermId> TermSet;
-typedef std::vector<TermId> Decomposition;
-
-struct ExtractTerm {
- TermId id;
- Index high;
- Index low;
- ExtractTerm(TermId i, Index h, Index l)
- : id (i),
- high(h),
- low(l)
- {
- Assert(h >= l && id != UndefinedId);
- }
- Index getBitwidth() const { return high - low + 1; }
- std::string debugPrint() const;
-};
-
-class UnionFind;
-
-struct NormalForm {
- Base base;
- Decomposition decomp;
-
- NormalForm(Index bitwidth)
- : base(bitwidth),
- decomp()
- {}
- /**
- * Returns the term in the decomposition on which the index i
- * falls in
- * @param i
- *
- * @return
- */
- std::pair<TermId, Index> getTerm(Index i, const UnionFind& uf) const;
- std::string debugPrint(const UnionFind& uf) const;
- void clear() { base.clear(); decomp.clear(); }
-};
-
-
-class UnionFind {
- class Node {
- Index d_bitwidth;
- TermId d_ch1, d_ch0;
- TermId d_repr;
- public:
- Node(Index b)
- : d_bitwidth(b),
- d_ch1(UndefinedId),
- d_ch0(UndefinedId),
- d_repr(UndefinedId)
- {}
-
- TermId getRepr() const { return d_repr; }
- Index getBitwidth() const { return d_bitwidth; }
- bool hasChildren() const { return d_ch1 != UndefinedId && d_ch0 != UndefinedId; }
-
- TermId getChild(Index i) const {
- Assert(i < 2);
- return i == 0? d_ch0 : d_ch1;
- }
- void setRepr(TermId id) {
- Assert(!hasChildren());
- d_repr = id;
- }
- void setChildren(TermId ch1, TermId ch0) {
- Assert(d_repr == UndefinedId && !hasChildren());
- d_ch1 = ch1;
- d_ch0 = ch0;
- }
- std::string debugPrint() const;
- };
-
- /// map from TermId to the nodes that represent them
- std::vector<Node> d_nodes;
- /// a term is in this set if it is its own representative
- TermSet d_representatives;
-
- void getDecomposition(const ExtractTerm& term, Decomposition& decomp);
- void handleCommonSlice(const Decomposition& d1, const Decomposition& d2, TermId common);
- /// getter methods for the internal nodes
- TermId getRepr(TermId id) const {
- Assert(id < d_nodes.size());
- return d_nodes[id].getRepr();
- }
- TermId getChild(TermId id, Index i) const {
- Assert(id < d_nodes.size());
- return d_nodes[id].getChild(i);
- }
- Index getCutPoint(TermId id) const {
- return getBitwidth(getChild(id, 0));
- }
- bool hasChildren(TermId id) const {
- Assert(id < d_nodes.size());
- return d_nodes[id].hasChildren();
- }
- /// setter methods for the internal nodes
- void setRepr(TermId id, TermId new_repr) {
- Assert(id < d_nodes.size());
- d_nodes[id].setRepr(new_repr);
- }
- void setChildren(TermId id, TermId ch1, TermId ch0) {
- Assert(id < d_nodes.size()
- && getBitwidth(id) == getBitwidth(ch1) + getBitwidth(ch0));
- d_nodes[id].setChildren(ch1, ch0);
- }
-
- class Statistics {
- public:
- IntStat d_numNodes;
- IntStat d_numRepresentatives;
- IntStat d_numSplits;
- IntStat d_numMerges;
- AverageStat d_avgFindDepth;
- ReferenceStat<unsigned> d_numAddedEqualities;
- //IntStat d_numAddedEqualities;
- Statistics();
- ~Statistics();
- };
-
- Statistics d_statistics
-;
-
-public:
- UnionFind()
- : d_nodes(),
- d_representatives()
- {}
-
- TermId addTerm(Index bitwidth);
- void unionTerms(const ExtractTerm& t1, const ExtractTerm& t2);
- void merge(TermId t1, TermId t2);
- TermId find(TermId t1);
- void split(TermId term, Index i);
-
- void getNormalForm(const ExtractTerm& term, NormalForm& nf);
- void alignSlicings(const ExtractTerm& term1, const ExtractTerm& term2);
- void ensureSlicing(const ExtractTerm& term);
- Index getBitwidth(TermId id) const {
- Assert(id < d_nodes.size());
- return d_nodes[id].getBitwidth();
- }
- std::string debugPrint(TermId id);
- friend class Slicer;
-};
-
-class Slicer {
- std::unordered_map<TermId, TNode> d_idToNode;
- std::unordered_map<TNode, TermId, TNodeHashFunction> d_nodeToId;
- std::unordered_map<TNode, bool, TNodeHashFunction> d_coreTermCache;
- UnionFind d_unionFind;
- ExtractTerm registerTerm(TNode node);
-public:
- Slicer()
- : d_idToNode(),
- d_nodeToId(),
- d_coreTermCache(),
- d_unionFind()
- {}
-
- void getBaseDecomposition(TNode node, std::vector<Node>& decomp);
- void processEquality(TNode eq);
- bool isCoreTerm (TNode node);
- static void splitEqualities(TNode node, std::vector<Node>& equalities);
- static unsigned d_numAddedEqualities;
-};
-
-
}/* CVC4::theory::bv namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp
index c8e585d88..d43fa3927 100644
--- a/src/theory/bv/theory_bv.cpp
+++ b/src/theory/bv/theory_bv.cpp
@@ -2,10 +2,10 @@
/*! \file theory_bv.cpp
** \verbatim
** Top contributors (to current version):
- ** Liana Hadarean, Andrew Reynolds, Aina Niemetz
+ ** Mathias Preiner, Andrew Reynolds, Martin Brain
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -15,30 +15,10 @@
#include "theory/bv/theory_bv.h"
-#include "expr/node_algorithm.h"
#include "options/bv_options.h"
-#include "options/smt_options.h"
-#include "proof/proof_manager.h"
-#include "proof/theory_proof.h"
-#include "smt/smt_statistics_registry.h"
-#include "theory/bv/abstraction.h"
-#include "theory/bv/bv_eager_solver.h"
-#include "theory/bv/bv_subtheory_algebraic.h"
-#include "theory/bv/bv_subtheory_bitblast.h"
-#include "theory/bv/bv_subtheory_core.h"
-#include "theory/bv/bv_subtheory_inequality.h"
-#include "theory/bv/slicer.h"
-#include "theory/bv/theory_bv_rewrite_rules_normalization.h"
-#include "theory/bv/theory_bv_rewrite_rules_simplification.h"
-#include "theory/bv/theory_bv_rewriter.h"
+#include "theory/bv/bv_solver_lazy.h"
+#include "theory/bv/bv_solver_simple.h"
#include "theory/bv/theory_bv_utils.h"
-#include "theory/ext_theory.h"
-#include "theory/theory_model.h"
-#include "theory/valuation.h"
-
-using namespace CVC4::context;
-using namespace CVC4::theory::bv::utils;
-using namespace std;
namespace CVC4 {
namespace theory {
@@ -52,184 +32,128 @@ TheoryBV::TheoryBV(context::Context* c,
ProofNodeManager* pnm,
std::string name)
: Theory(THEORY_BV, c, u, out, valuation, logicInfo, pnm, name),
- d_context(c),
- d_alreadyPropagatedSet(c),
- d_sharedTermsSet(c),
- d_subtheories(),
- d_subtheoryMap(),
- d_statistics(),
- d_staticLearnCache(),
- d_BVDivByZero(),
- d_BVRemByZero(),
- d_lemmasAdded(c, false),
- d_conflict(c, false),
- d_invalidateModelCache(c, true),
- d_literalsToPropagate(c),
- d_literalsToPropagateIndex(c, 0),
- d_propagatedBy(c),
- d_eagerSolver(),
- d_abstractionModule(new AbstractionModule(getStatsPrefix(THEORY_BV))),
- d_isCoreTheory(false),
- d_calledPreregister(false),
- d_needsLastCallCheck(false),
- d_extf_range_infer(u),
- d_extf_collapse_infer(u)
+ d_internal(nullptr),
+ d_ufDivByZero(),
+ d_ufRemByZero(),
+ d_rewriter(),
+ d_state(c, u, valuation),
+ d_inferMgr(*this, d_state, nullptr)
{
- setupExtTheory();
- getExtTheory()->addFunctionKind(kind::BITVECTOR_TO_NAT);
- getExtTheory()->addFunctionKind(kind::INT_TO_BITVECTOR);
- if (options::bitblastMode() == options::BitblastMode::EAGER)
- {
- d_eagerSolver.reset(new EagerBitblastSolver(c, this));
- return;
- }
-
- if (options::bitvectorEqualitySolver() && !options::proof())
- {
- d_subtheories.emplace_back(new CoreSolver(c, this));
- d_subtheoryMap[SUB_CORE] = d_subtheories.back().get();
- }
-
- if (options::bitvectorInequalitySolver() && !options::proof())
+ switch (options::bvSolver())
{
- d_subtheories.emplace_back(new InequalitySolver(c, u, this));
- d_subtheoryMap[SUB_INEQUALITY] = d_subtheories.back().get();
- }
-
- if (options::bitvectorAlgebraicSolver() && !options::proof())
- {
- d_subtheories.emplace_back(new AlgebraicSolver(c, this));
- d_subtheoryMap[SUB_ALGEBRAIC] = d_subtheories.back().get();
- }
+ case options::BVSolver::LAZY:
+ d_internal.reset(new BVSolverLazy(*this, c, u, pnm, name));
+ break;
- BitblastSolver* bb_solver = new BitblastSolver(c, this);
- if (options::bvAbstraction())
- {
- bb_solver->setAbstraction(d_abstractionModule.get());
+ default:
+ AlwaysAssert(options::bvSolver() == options::BVSolver::SIMPLE);
+ d_internal.reset(new BVSolverSimple(d_state, d_inferMgr));
}
- d_subtheories.emplace_back(bb_solver);
- d_subtheoryMap[SUB_BITBLAST] = bb_solver;
+ d_theoryState = &d_state;
+ d_inferManager = &d_inferMgr;
}
TheoryBV::~TheoryBV() {}
-void TheoryBV::setMasterEqualityEngine(eq::EqualityEngine* eq) {
- if (options::bitblastMode() == options::BitblastMode::EAGER)
- {
- return;
- }
- if (options::bitvectorEqualitySolver()) {
- dynamic_cast<CoreSolver*>(d_subtheoryMap[SUB_CORE])->setMasterEqualityEngine(eq);
- }
-}
+TheoryRewriter* TheoryBV::getTheoryRewriter() { return &d_rewriter; }
-void TheoryBV::spendResource(ResourceManager::Resource r)
+bool TheoryBV::needsEqualityEngine(EeSetupInfo& esi)
{
- getOutputChannel().spendResource(r);
+ return d_internal->needsEqualityEngine(esi);
}
-TheoryBV::Statistics::Statistics():
- d_avgConflictSize("theory::bv::AvgBVConflictSize"),
- d_solveSubstitutions("theory::bv::NumSolveSubstitutions", 0),
- d_solveTimer("theory::bv::solveTimer"),
- d_numCallsToCheckFullEffort("theory::bv::NumFullCheckCalls", 0),
- d_numCallsToCheckStandardEffort("theory::bv::NumStandardCheckCalls", 0),
- d_weightComputationTimer("theory::bv::weightComputationTimer"),
- d_numMultSlice("theory::bv::NumMultSliceApplied", 0)
+void TheoryBV::finishInit()
{
- smtStatisticsRegistry()->registerStat(&d_avgConflictSize);
- smtStatisticsRegistry()->registerStat(&d_solveSubstitutions);
- smtStatisticsRegistry()->registerStat(&d_solveTimer);
- smtStatisticsRegistry()->registerStat(&d_numCallsToCheckFullEffort);
- smtStatisticsRegistry()->registerStat(&d_numCallsToCheckStandardEffort);
- smtStatisticsRegistry()->registerStat(&d_weightComputationTimer);
- smtStatisticsRegistry()->registerStat(&d_numMultSlice);
-}
-
-TheoryBV::Statistics::~Statistics() {
- smtStatisticsRegistry()->unregisterStat(&d_avgConflictSize);
- smtStatisticsRegistry()->unregisterStat(&d_solveSubstitutions);
- smtStatisticsRegistry()->unregisterStat(&d_solveTimer);
- smtStatisticsRegistry()->unregisterStat(&d_numCallsToCheckFullEffort);
- smtStatisticsRegistry()->unregisterStat(&d_numCallsToCheckStandardEffort);
- smtStatisticsRegistry()->unregisterStat(&d_weightComputationTimer);
- smtStatisticsRegistry()->unregisterStat(&d_numMultSlice);
+ // these kinds are semi-evaluated in getModelValue (applications of this
+ // kind are treated as variables)
+ getValuation().setSemiEvaluatedKind(kind::BITVECTOR_ACKERMANNIZE_UDIV);
+ getValuation().setSemiEvaluatedKind(kind::BITVECTOR_ACKERMANNIZE_UREM);
+ d_internal->finishInit();
}
-Node TheoryBV::getBVDivByZero(Kind k, unsigned width) {
+Node TheoryBV::getUFDivByZero(Kind k, unsigned width)
+{
NodeManager* nm = NodeManager::currentNM();
- if (k == kind::BITVECTOR_UDIV) {
- if (d_BVDivByZero.find(width) == d_BVDivByZero.end()) {
+ if (k == kind::BITVECTOR_UDIV)
+ {
+ if (d_ufDivByZero.find(width) == d_ufDivByZero.end())
+ {
// lazily create the function symbols
- ostringstream os;
+ std::ostringstream os;
os << "BVUDivByZero_" << width;
- Node divByZero = nm->mkSkolem(os.str(),
- nm->mkFunctionType(nm->mkBitVectorType(width), nm->mkBitVectorType(width)),
- "partial bvudiv", NodeManager::SKOLEM_EXACT_NAME);
- d_BVDivByZero[width] = divByZero;
+ Node divByZero =
+ nm->mkSkolem(os.str(),
+ nm->mkFunctionType(nm->mkBitVectorType(width),
+ nm->mkBitVectorType(width)),
+ "partial bvudiv",
+ NodeManager::SKOLEM_EXACT_NAME);
+ d_ufDivByZero[width] = divByZero;
}
- return d_BVDivByZero[width];
+ return d_ufDivByZero[width];
}
- else if (k == kind::BITVECTOR_UREM) {
- if (d_BVRemByZero.find(width) == d_BVRemByZero.end()) {
- ostringstream os;
+ else if (k == kind::BITVECTOR_UREM)
+ {
+ if (d_ufRemByZero.find(width) == d_ufRemByZero.end())
+ {
+ std::ostringstream os;
os << "BVURemByZero_" << width;
- Node divByZero = nm->mkSkolem(os.str(),
- nm->mkFunctionType(nm->mkBitVectorType(width), nm->mkBitVectorType(width)),
- "partial bvurem", NodeManager::SKOLEM_EXACT_NAME);
- d_BVRemByZero[width] = divByZero;
+ Node divByZero =
+ nm->mkSkolem(os.str(),
+ nm->mkFunctionType(nm->mkBitVectorType(width),
+ nm->mkBitVectorType(width)),
+ "partial bvurem",
+ NodeManager::SKOLEM_EXACT_NAME);
+ d_ufRemByZero[width] = divByZero;
}
- return d_BVRemByZero[width];
+ return d_ufRemByZero[width];
}
Unreachable();
}
-void TheoryBV::finishInit()
-{
- // these kinds are semi-evaluated in getModelValue (applications of this
- // kind are treated as variables)
- TheoryModel* tm = d_valuation.getModel();
- Assert(tm != nullptr);
- tm->setSemiEvaluatedKind(kind::BITVECTOR_ACKERMANNIZE_UDIV);
- tm->setSemiEvaluatedKind(kind::BITVECTOR_ACKERMANNIZE_UREM);
-}
-
TrustNode TheoryBV::expandDefinition(Node node)
{
- Debug("bitvector-expandDefinition") << "TheoryBV::expandDefinition(" << node << ")" << std::endl;
+ Debug("bitvector-expandDefinition")
+ << "TheoryBV::expandDefinition(" << node << ")" << std::endl;
Node ret;
- switch (node.getKind()) {
- case kind::BITVECTOR_SDIV:
- case kind::BITVECTOR_SREM:
- case kind::BITVECTOR_SMOD:
- ret = TheoryBVRewriter::eliminateBVSDiv(node);
- break;
+ switch (node.getKind())
+ {
+ case kind::BITVECTOR_SDIV:
+ case kind::BITVECTOR_SREM:
+ case kind::BITVECTOR_SMOD:
+ ret = TheoryBVRewriter::eliminateBVSDiv(node);
+ break;
- case kind::BITVECTOR_UDIV:
- case kind::BITVECTOR_UREM: {
- NodeManager* nm = NodeManager::currentNM();
- unsigned width = node.getType().getBitVectorSize();
+ case kind::BITVECTOR_UDIV:
+ case kind::BITVECTOR_UREM:
+ {
+ NodeManager* nm = NodeManager::currentNM();
+ unsigned width = node.getType().getBitVectorSize();
- if (options::bitvectorDivByZeroConst()) {
- Kind kind = node.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_UDIV_TOTAL : kind::BITVECTOR_UREM_TOTAL;
- ret = nm->mkNode(kind, node[0], node[1]);
- break;
- }
+ if (options::bitvectorDivByZeroConst())
+ {
+ Kind kind = node.getKind() == kind::BITVECTOR_UDIV
+ ? kind::BITVECTOR_UDIV_TOTAL
+ : kind::BITVECTOR_UREM_TOTAL;
+ ret = nm->mkNode(kind, node[0], node[1]);
+ break;
+ }
- TNode num = node[0], den = node[1];
- Node den_eq_0 = nm->mkNode(kind::EQUAL, den, utils::mkZero(width));
- Node divTotalNumDen = nm->mkNode(node.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_UDIV_TOTAL :
- kind::BITVECTOR_UREM_TOTAL, num, den);
- Node divByZero = getBVDivByZero(node.getKind(), width);
- Node divByZeroNum = nm->mkNode(kind::APPLY_UF, divByZero, num);
- ret = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
- }
+ TNode num = node[0], den = node[1];
+ Node den_eq_0 = nm->mkNode(kind::EQUAL, den, utils::mkZero(width));
+ Node divTotalNumDen = nm->mkNode(node.getKind() == kind::BITVECTOR_UDIV
+ ? kind::BITVECTOR_UDIV_TOTAL
+ : kind::BITVECTOR_UREM_TOTAL,
+ num,
+ den);
+ Node divByZero = getUFDivByZero(node.getKind(), width);
+ Node divByZeroNum = nm->mkNode(kind::APPLY_UF, divByZero, num);
+ ret = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
+ }
break;
- default:
- break;
+ default: break;
}
if (!ret.isNull() && node != ret)
{
@@ -238,772 +162,66 @@ TrustNode TheoryBV::expandDefinition(Node node)
return TrustNode::null();
}
-void TheoryBV::preRegisterTerm(TNode node) {
- d_calledPreregister = true;
- Debug("bitvector-preregister") << "TheoryBV::preRegister(" << node << ")" << std::endl;
-
- if (options::bitblastMode() == options::BitblastMode::EAGER)
- {
- // the aig bit-blaster option is set heuristically
- // if bv abstraction is used
- if (!d_eagerSolver->isInitialized())
- {
- d_eagerSolver->initialize();
- }
-
- if (node.getKind() == kind::BITVECTOR_EAGER_ATOM)
- {
- Node formula = node[0];
- d_eagerSolver->assertFormula(formula);
- }
- return;
- }
-
- for (unsigned i = 0; i < d_subtheories.size(); ++i) {
- d_subtheories[i]->preRegister(node);
- }
-
- // AJR : equality solver currently registers all terms to ExtTheory, if we want a lazy reduction without the bv equality solver, need to call this
- //getExtTheory()->registerTermRec( node );
-}
-
-void TheoryBV::sendConflict() {
- Assert(d_conflict);
- if (d_conflictNode.isNull()) {
- return;
- } else {
- Debug("bitvector") << indent() << "TheoryBV::check(): conflict " << d_conflictNode << std::endl;
- d_out->conflict(d_conflictNode);
- d_statistics.d_avgConflictSize.addEntry(d_conflictNode.getNumChildren());
- d_conflictNode = Node::null();
- }
-}
-
-void TheoryBV::checkForLemma(TNode fact)
-{
- if (fact.getKind() == kind::EQUAL)
- {
- NodeManager* nm = NodeManager::currentNM();
- if (fact[0].getKind() == kind::BITVECTOR_UREM_TOTAL)
- {
- TNode urem = fact[0];
- TNode result = fact[1];
- TNode divisor = urem[1];
- Node result_ult_div = nm->mkNode(kind::BITVECTOR_ULT, result, divisor);
- Node divisor_eq_0 =
- nm->mkNode(kind::EQUAL, divisor, mkZero(getSize(divisor)));
- Node split = nm->mkNode(
- kind::OR, divisor_eq_0, nm->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];
- Node result_ult_div = nm->mkNode(kind::BITVECTOR_ULT, result, divisor);
- Node divisor_eq_0 =
- nm->mkNode(kind::EQUAL, divisor, mkZero(getSize(divisor)));
- Node split = nm->mkNode(
- kind::OR, divisor_eq_0, nm->mkNode(kind::NOT, fact), result_ult_div);
- lemma(split);
- }
- }
-}
-
-void TheoryBV::check(Effort e)
+void TheoryBV::preRegisterTerm(TNode node)
{
- if (done() && e<Theory::EFFORT_FULL) {
- return;
- }
-
- //last call : do reductions on extended bitvector functions
- if (e == Theory::EFFORT_LAST_CALL) {
- std::vector<Node> nred = getExtTheory()->getActive();
- doExtfReductions(nred);
- return;
- }
-
- TimerStat::CodeTimer checkTimer(d_checkTime);
- Debug("bitvector") << "TheoryBV::check(" << e << ")" << std::endl;
- TimerStat::CodeTimer codeTimer(d_statistics.d_solveTimer);
- // we may be getting new assertions so the model cache may not be sound
- d_invalidateModelCache.set(true);
- // if we are using the eager solver
- if (options::bitblastMode() == options::BitblastMode::EAGER)
- {
- // this can only happen on an empty benchmark
- if (!d_eagerSolver->isInitialized()) {
- d_eagerSolver->initialize();
- }
- if (!Theory::fullEffort(e))
- return;
-
- std::vector<TNode> assertions;
- while (!done()) {
- TNode fact = get().d_assertion;
- Assert(fact.getKind() == kind::BITVECTOR_EAGER_ATOM);
- assertions.push_back(fact);
- d_eagerSolver->assertFormula(fact[0]);
- }
-
- bool ok = d_eagerSolver->checkSat();
- if (!ok) {
- if (assertions.size() == 1) {
- d_out->conflict(assertions[0]);
- return;
- }
- Node conflict = utils::mkAnd(assertions);
- d_out->conflict(conflict);
- return;
- }
- return;
- }
-
- if (Theory::fullEffort(e)) {
- ++(d_statistics.d_numCallsToCheckFullEffort);
- } else {
- ++(d_statistics.d_numCallsToCheckStandardEffort);
- }
- // if we are already in conflict just return the conflict
- if (inConflict()) {
- sendConflict();
- return;
- }
-
- while (!done()) {
- TNode fact = get().d_assertion;
-
- checkForLemma(fact);
-
- for (unsigned i = 0; i < d_subtheories.size(); ++i) {
- d_subtheories[i]->assertFact(fact);
- }
- }
-
- bool ok = true;
- bool complete = false;
- for (unsigned i = 0; i < d_subtheories.size(); ++i) {
- Assert(!inConflict());
- ok = d_subtheories[i]->check(e);
- complete = d_subtheories[i]->isComplete();
-
- if (!ok) {
- // if we are in a conflict no need to check with other theories
- Assert(inConflict());
- sendConflict();
- return;
- }
- if (complete) {
- // if the last subtheory was complete we stop
- break;
- }
- }
-
- //check extended functions
- if (Theory::fullEffort(e)) {
- //do inferences (adds external lemmas) TODO: this can be improved to add internal inferences
- std::vector< Node > nred;
- if( getExtTheory()->doInferences( 0, nred ) ){
- return;
- }
- d_needsLastCallCheck = false;
- if( !nred.empty() ){
- //other inferences involving bv2nat, int2bv
- if( options::bvAlgExtf() ){
- if( doExtfInferences( nred ) ){
- return;
- }
- }
- if( !options::bvLazyReduceExtf() ){
- if( doExtfReductions( nred ) ){
- return;
- }
- }else{
- d_needsLastCallCheck = true;
- }
- }
- }
+ d_internal->preRegisterTerm(node);
}
-bool TheoryBV::doExtfInferences(std::vector<Node>& terms)
-{
- NodeManager* nm = NodeManager::currentNM();
- bool sentLemma = false;
- eq::EqualityEngine* ee = getEqualityEngine();
- std::map<Node, Node> op_map;
- for (unsigned j = 0; j < terms.size(); j++)
- {
- TNode n = terms[j];
- Assert(n.getKind() == kind::BITVECTOR_TO_NAT
- || n.getKind() == kind::INT_TO_BITVECTOR);
- if (n.getKind() == kind::BITVECTOR_TO_NAT)
- {
- // range lemmas
- if (d_extf_range_infer.find(n) == d_extf_range_infer.end())
- {
- d_extf_range_infer.insert(n);
- unsigned bvs = n[0].getType().getBitVectorSize();
- Node min = nm->mkConst(Rational(0));
- Node max = nm->mkConst(Rational(Integer(1).multiplyByPow2(bvs)));
- Node lem = nm->mkNode(kind::AND,
- nm->mkNode(kind::GEQ, n, min),
- nm->mkNode(kind::LT, n, max));
- Trace("bv-extf-lemma")
- << "BV extf lemma (range) : " << lem << std::endl;
- d_out->lemma(lem);
- sentLemma = true;
- }
- }
- Node r = (ee && ee->hasTerm(n[0])) ? ee->getRepresentative(n[0]) : n[0];
- op_map[r] = n;
- }
- for (unsigned j = 0; j < terms.size(); j++)
- {
- TNode n = terms[j];
- Node r = (ee && ee->hasTerm(n[0])) ? ee->getRepresentative(n) : n;
- std::map<Node, Node>::iterator it = op_map.find(r);
- if (it != op_map.end())
- {
- Node parent = it->second;
- // Node cterm = parent[0]==n ? parent : nm->mkNode( parent.getOperator(),
- // n );
- Node cterm = parent[0].eqNode(n);
- Trace("bv-extf-lemma-debug")
- << "BV extf collapse based on : " << cterm << std::endl;
- if (d_extf_collapse_infer.find(cterm) == d_extf_collapse_infer.end())
- {
- d_extf_collapse_infer.insert(cterm);
-
- Node t = n[0];
- if (t.getType() == parent.getType())
- {
- if (n.getKind() == kind::INT_TO_BITVECTOR)
- {
- Assert(t.getType().isInteger());
- // congruent modulo 2^( bv width )
- unsigned bvs = n.getType().getBitVectorSize();
- Node coeff = nm->mkConst(Rational(Integer(1).multiplyByPow2(bvs)));
- Node k = nm->mkSkolem(
- "int_bv_cong", t.getType(), "for int2bv/bv2nat congruence");
- t = nm->mkNode(kind::PLUS, t, nm->mkNode(kind::MULT, coeff, k));
- }
- Node lem = parent.eqNode(t);
-
- if (parent[0] != n)
- {
- Assert(ee->areEqual(parent[0], n));
- lem = nm->mkNode(kind::IMPLIES, parent[0].eqNode(n), lem);
- }
- // this handles inferences of the form, e.g.:
- // ((_ int2bv w) (bv2nat x)) == x (if x is bit-width w)
- // (bv2nat ((_ int2bv w) x)) == x + k*2^w for some k
- Trace("bv-extf-lemma")
- << "BV extf lemma (collapse) : " << lem << std::endl;
- d_out->lemma(lem);
- sentLemma = true;
- }
- }
- Trace("bv-extf-lemma-debug")
- << "BV extf f collapse based on : " << cterm << std::endl;
- }
- }
- return sentLemma;
-}
+bool TheoryBV::preCheck(Effort e) { return d_internal->preCheck(e); }
-bool TheoryBV::doExtfReductions( std::vector< Node >& terms ) {
- std::vector< Node > nredr;
- if( getExtTheory()->doReductions( 0, terms, nredr ) ){
- return true;
- }
- Assert(nredr.empty());
- return false;
-}
+void TheoryBV::postCheck(Effort e) { d_internal->postCheck(e); }
-bool TheoryBV::needsCheckLastEffort() {
- return d_needsLastCallCheck;
-}
-bool TheoryBV::collectModelInfo(TheoryModel* m)
+bool TheoryBV::preNotifyFact(
+ TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal)
{
- Assert(!inConflict());
- if (options::bitblastMode() == options::BitblastMode::EAGER)
- {
- if (!d_eagerSolver->collectModelInfo(m, true))
- {
- return false;
- }
- }
- for (unsigned i = 0; i < d_subtheories.size(); ++i) {
- if (d_subtheories[i]->isComplete()) {
- return d_subtheories[i]->collectModelInfo(m, true);
- }
- }
- return true;
-}
-
-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);
- }
- }
- Unreachable();
-}
-
-void TheoryBV::propagate(Effort e) {
- Debug("bitvector") << indent() << "TheoryBV::propagate()" << std::endl;
- if (options::bitblastMode() == options::BitblastMode::EAGER)
- {
- return;
- }
-
- if (inConflict()) {
- return;
- }
-
- // go through stored propagations
- 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
- if (d_valuation.isSatLiteral(literal)) {
- Debug("bitvector::propagate") << "TheoryBV:: propagating " << literal <<"\n";
- ok = d_out->propagate(literal);
- }
- }
-
- if (!ok) {
- Debug("bitvector::propagate") << indent() << "TheoryBV::propagate(): conflict from theory engine" << std::endl;
- setConflict();
- }
-}
-
-
-eq::EqualityEngine * TheoryBV::getEqualityEngine() {
- CoreSolver* core = (CoreSolver*)d_subtheoryMap[SUB_CORE];
- if( core ){
- return core->getEqualityEngine();
- }else{
- return NULL;
- }
+ return d_internal->preNotifyFact(atom, pol, fact, isPrereg, isInternal);
}
-bool TheoryBV::getCurrentSubstitution( int effort, std::vector< Node >& vars, std::vector< Node >& subs, std::map< Node, std::vector< Node > >& exp ) {
- eq::EqualityEngine * ee = getEqualityEngine();
- if( ee ){
- //get the constant equivalence classes
- bool retVal = false;
- for( unsigned i=0; i<vars.size(); i++ ){
- Node n = vars[i];
- if( ee->hasTerm( n ) ){
- Node nr = ee->getRepresentative( n );
- if( nr.isConst() ){
- subs.push_back( nr );
- exp[n].push_back( n.eqNode( nr ) );
- retVal = true;
- }else{
- subs.push_back( n );
- }
- }else{
- subs.push_back( n );
- }
- }
- //return true if the substitution is non-trivial
- return retVal;
- }
- return false;
-}
-
-int TheoryBV::getReduction(int effort, Node n, Node& nr)
+void TheoryBV::notifyFact(TNode atom, bool pol, TNode fact, bool isInternal)
{
- Trace("bv-ext") << "TheoryBV::checkExt : non-reduced : " << n << std::endl;
- if (n.getKind() == kind::BITVECTOR_TO_NAT)
- {
- nr = utils::eliminateBv2Nat(n);
- return -1;
- }
- else if (n.getKind() == kind::INT_TO_BITVECTOR)
- {
- nr = utils::eliminateInt2Bv(n);
- return -1;
- }
- return 0;
+ d_internal->notifyFact(atom, pol, fact, isInternal);
}
-Theory::PPAssertStatus TheoryBV::ppAssert(TNode in,
- SubstitutionMap& outSubstitutions)
+bool TheoryBV::needsCheckLastEffort()
{
- switch (in.getKind())
- {
- case kind::EQUAL:
- {
- if (in[0].isVar() && isLegalElimination(in[0], in[1]))
- {
- ++(d_statistics.d_solveSubstitutions);
- outSubstitutions.addSubstitution(in[0], in[1]);
- return PP_ASSERT_STATUS_SOLVED;
- }
- if (in[1].isVar() && isLegalElimination(in[1], in[0]))
- {
- ++(d_statistics.d_solveSubstitutions);
- outSubstitutions.addSubstitution(in[1], in[0]);
- return PP_ASSERT_STATUS_SOLVED;
- }
- Node node = Rewriter::rewrite(in);
- if ((node[0].getKind() == kind::BITVECTOR_EXTRACT && node[1].isConst())
- || (node[1].getKind() == kind::BITVECTOR_EXTRACT
- && node[0].isConst()))
- {
- Node extract = node[0].isConst() ? node[1] : node[0];
- if (extract[0].isVar())
- {
- Node c = node[0].isConst() ? node[0] : node[1];
-
- unsigned high = utils::getExtractHigh(extract);
- unsigned low = utils::getExtractLow(extract);
- unsigned var_bitwidth = utils::getSize(extract[0]);
- std::vector<Node> children;
-
- if (low == 0)
- {
- Assert(high != var_bitwidth - 1);
- unsigned skolem_size = var_bitwidth - high - 1;
- Node skolem = utils::mkVar(skolem_size);
- children.push_back(skolem);
- children.push_back(c);
- }
- else if (high == var_bitwidth - 1)
- {
- unsigned skolem_size = low;
- Node skolem = utils::mkVar(skolem_size);
- children.push_back(c);
- children.push_back(skolem);
- }
- else
- {
- unsigned skolem1_size = low;
- unsigned skolem2_size = var_bitwidth - high - 1;
- Node skolem1 = utils::mkVar(skolem1_size);
- Node skolem2 = utils::mkVar(skolem2_size);
- children.push_back(skolem2);
- children.push_back(c);
- children.push_back(skolem1);
- }
- Node concat = utils::mkConcat(children);
- Assert(utils::getSize(concat) == utils::getSize(extract[0]));
- if (isLegalElimination(extract[0], concat))
- {
- outSubstitutions.addSubstitution(extract[0], concat);
- return PP_ASSERT_STATUS_SOLVED;
- }
- }
- }
- }
- break;
- case kind::BITVECTOR_ULT:
- case kind::BITVECTOR_SLT:
- case kind::BITVECTOR_ULE:
- case kind::BITVECTOR_SLE:
-
- default:
- // TODO other predicates
- break;
- }
- return PP_ASSERT_STATUS_UNSOLVED;
+ return d_internal->needsCheckLastEffort();
}
-TrustNode TheoryBV::ppRewrite(TNode t)
+bool TheoryBV::collectModelValues(TheoryModel* m, const std::set<Node>& termSet)
{
- Debug("bv-pp-rewrite") << "TheoryBV::ppRewrite " << t << "\n";
- Node res = t;
- if (options::bitwiseEq() && RewriteRule<BitwiseEq>::applies(t)) {
- Node result = RewriteRule<BitwiseEq>::run<false>(t);
- res = Rewriter::rewrite(result);
- } else if (d_isCoreTheory && t.getKind() == kind::EQUAL) {
- std::vector<Node> equalities;
- Slicer::splitEqualities(t, equalities);
- res = utils::mkAnd(equalities);
- } else if (RewriteRule<UltPlusOne>::applies(t)) {
- Node result = RewriteRule<UltPlusOne>::run<false>(t);
- res = Rewriter::rewrite(result);
- } else if( res.getKind() == kind::EQUAL &&
- ((res[0].getKind() == kind::BITVECTOR_PLUS &&
- RewriteRule<ConcatToMult>::applies(res[1])) ||
- (res[1].getKind() == kind::BITVECTOR_PLUS &&
- RewriteRule<ConcatToMult>::applies(res[0])))) {
- Node mult = RewriteRule<ConcatToMult>::applies(res[0])?
- RewriteRule<ConcatToMult>::run<false>(res[0]) :
- RewriteRule<ConcatToMult>::run<true>(res[1]);
- Node factor = mult[0];
- Node sum = RewriteRule<ConcatToMult>::applies(res[0])? res[1] : res[0];
- Node new_eq = NodeManager::currentNM()->mkNode(kind::EQUAL, sum, mult);
- Node rewr_eq = RewriteRule<SolveEq>::run<true>(new_eq);
- if (rewr_eq[0].isVar() || rewr_eq[1].isVar()){
- res = Rewriter::rewrite(rewr_eq);
- } else {
- res = t;
- }
- } else if (RewriteRule<SignExtendEqConst>::applies(t)) {
- res = RewriteRule<SignExtendEqConst>::run<false>(t);
- } else if (RewriteRule<ZeroExtendEqConst>::applies(t)) {
- res = RewriteRule<ZeroExtendEqConst>::run<false>(t);
- }
- else if (RewriteRule<NormalizeEqPlusNeg>::applies(t))
- {
- res = RewriteRule<NormalizeEqPlusNeg>::run<false>(t);
- }
-
- // if(t.getKind() == kind::EQUAL &&
- // ((t[0].getKind() == kind::BITVECTOR_MULT && t[1].getKind() ==
- // kind::BITVECTOR_PLUS) ||
- // (t[1].getKind() == kind::BITVECTOR_MULT && t[0].getKind() ==
- // kind::BITVECTOR_PLUS))) {
- // // if we have an equality between a multiplication and addition
- // // try to express multiplication in terms of addition
- // Node mult = t[0].getKind() == kind::BITVECTOR_MULT? t[0] : t[1];
- // Node add = t[0].getKind() == kind::BITVECTOR_PLUS? t[0] : t[1];
- // if (RewriteRule<MultSlice>::applies(mult)) {
- // Node new_mult = RewriteRule<MultSlice>::run<false>(mult);
- // Node new_eq =
- // Rewriter::rewrite(NodeManager::currentNM()->mkNode(kind::EQUAL,
- // new_mult, add));
-
- // // the simplification can cause the formula to blow up
- // // only apply if formula reduced
- // if (d_subtheoryMap.find(SUB_BITBLAST) != d_subtheoryMap.end()) {
- // BitblastSolver* bv = (BitblastSolver*)d_subtheoryMap[SUB_BITBLAST];
- // uint64_t old_size = bv->computeAtomWeight(t);
- // Assert (old_size);
- // uint64_t new_size = bv->computeAtomWeight(new_eq);
- // double ratio = ((double)new_size)/old_size;
- // if (ratio <= 0.4) {
- // ++(d_statistics.d_numMultSlice);
- // return new_eq;
- // }
- // }
-
- // if (new_eq.getKind() == kind::CONST_BOOLEAN) {
- // ++(d_statistics.d_numMultSlice);
- // return new_eq;
- // }
- // }
- // }
-
- if (options::bvAbstraction() && t.getType().isBoolean()) {
- d_abstractionModule->addInputAtom(res);
- }
- Debug("bv-pp-rewrite") << "to " << res << "\n";
- if (res != t)
- {
- return TrustNode::mkTrustRewrite(t, res, nullptr);
- }
- return TrustNode::null();
-}
-
-void TheoryBV::presolve() {
- Debug("bitvector") << "TheoryBV::presolve" << endl;
+ return d_internal->collectModelValues(m, termSet);
}
-static int prop_count = 0;
-
-bool TheoryBV::storePropagation(TNode literal, SubTheory subtheory)
-{
- Debug("bitvector::propagate") << indent() << getSatContext()->getLevel() << " " << "TheoryBV::storePropagation(" << literal << ", " << subtheory << ")" << std::endl;
- prop_count++;
-
- // If already in conflict, no more propagation
- if (d_conflict) {
- Debug("bitvector::propagate") << indent() << "TheoryBV::storePropagation(" << literal << ", " << subtheory << "): already in conflict" << std::endl;
- return false;
- }
-
- // If propagated already, just skip
- PropagatedMap::const_iterator find = d_propagatedBy.find(literal);
- if (find != d_propagatedBy.end()) {
- return true;
- } else {
- bool polarity = literal.getKind() != kind::NOT;
- Node negatedLiteral = polarity ? literal.notNode() : (Node) literal[0];
- find = d_propagatedBy.find(negatedLiteral);
- if (find != d_propagatedBy.end() && (*find).second != subtheory) {
- // Safe to ignore this one, subtheory should produce a conflict
- return true;
- }
-
- d_propagatedBy[literal] = subtheory;
- }
-
- // Propagate differs depending on the subtheory
- // * bitblaster needs to be left alone until it's done, otherwise it doesn't
- // know how to explain
- // * equality engine can propagate eagerly
- // TODO(2348): Determine if ok should be set by propagate. If not, remove ok.
- constexpr bool ok = true;
- if (subtheory == SUB_CORE) {
- d_out->propagate(literal);
- if (!ok) {
- setConflict();
- }
- } else {
- d_literalsToPropagate.push_back(literal);
- }
- return ok;
-
-}/* TheoryBV::propagate(TNode) */
-
-
-void TheoryBV::explain(TNode literal, std::vector<TNode>& assumptions) {
- Assert(wasPropagatedBySubtheory(literal));
- SubTheory sub = getPropagatingSubtheory(literal);
- d_subtheoryMap[sub]->explain(literal, assumptions);
-}
+void TheoryBV::propagate(Effort e) { return d_internal->propagate(e); }
-TrustNode TheoryBV::explain(TNode node)
+Theory::PPAssertStatus TheoryBV::ppAssert(
+ TrustNode tin, TrustSubstitutionMap& outSubstitutions)
{
- Debug("bitvector::explain") << "TheoryBV::explain(" << node << ")" << std::endl;
- std::vector<TNode> assumptions;
-
- // Ask for the explanation
- explain(node, assumptions);
- // this means that it is something true at level 0
- Node explanation;
- if (assumptions.size() == 0) {
- explanation = utils::mkTrue();
- }
- else
- {
- // return the explanation
- explanation = utils::mkAnd(assumptions);
- }
- Debug("bitvector::explain") << "TheoryBV::explain(" << node << ") => " << explanation << std::endl;
- Debug("bitvector::explain") << "TheoryBV::explain done. \n";
- return TrustNode::mkTrustPropExp(node, explanation, nullptr);
+ return d_internal->ppAssert(tin, outSubstitutions);
}
+TrustNode TheoryBV::ppRewrite(TNode t) { return d_internal->ppRewrite(t); }
-void TheoryBV::addSharedTerm(TNode t) {
- Debug("bitvector::sharing") << indent() << "TheoryBV::addSharedTerm(" << t << ")" << std::endl;
- d_sharedTermsSet.insert(t);
- if (options::bitvectorEqualitySolver()) {
- for (unsigned i = 0; i < d_subtheories.size(); ++i) {
- d_subtheories[i]->addSharedTerm(t);
- }
- }
-}
+void TheoryBV::presolve() { d_internal->presolve(); }
+TrustNode TheoryBV::explain(TNode node) { return d_internal->explain(node); }
-EqualityStatus TheoryBV::getEqualityStatus(TNode a, TNode b)
+void TheoryBV::notifySharedTerm(TNode t)
{
- if (options::bitblastMode() == options::BitblastMode::EAGER)
- return EQUALITY_UNKNOWN;
- Assert(options::bitblastMode() == options::BitblastMode::LAZY);
- for (unsigned i = 0; i < d_subtheories.size(); ++i) {
- EqualityStatus status = d_subtheories[i]->getEqualityStatus(a, b);
- if (status != EQUALITY_UNKNOWN) {
- return status;
- }
- }
- return EQUALITY_UNKNOWN; ;
-}
-
-
-void TheoryBV::enableCoreTheorySlicer() {
- Assert(!d_calledPreregister);
- d_isCoreTheory = true;
- if (d_subtheoryMap.find(SUB_CORE) != d_subtheoryMap.end()) {
- CoreSolver* core = (CoreSolver*)d_subtheoryMap[SUB_CORE];
- core->enableSlicer();
- }
-}
-
-
-void TheoryBV::ppStaticLearn(TNode in, NodeBuilder<>& learned) {
- if(d_staticLearnCache.find(in) != d_staticLearnCache.end()){
- return;
- }
- d_staticLearnCache.insert(in);
-
- if (in.getKind() == kind::EQUAL) {
- if((in[0].getKind() == kind::BITVECTOR_PLUS && in[1].getKind() == kind::BITVECTOR_SHL) ||
- (in[1].getKind() == kind::BITVECTOR_PLUS && in[0].getKind() == kind::BITVECTOR_SHL)) {
- TNode p = in[0].getKind() == kind::BITVECTOR_PLUS ? in[0] : in[1];
- TNode s = in[0].getKind() == kind::BITVECTOR_PLUS ? in[1] : in[0];
-
- if(p.getNumChildren() == 2
- && p[0].getKind() == kind::BITVECTOR_SHL
- && p[1].getKind() == kind::BITVECTOR_SHL ){
- unsigned size = utils::getSize(s);
- Node one = utils::mkConst(size, 1u);
- if(s[0] == one && p[0][0] == one && p[1][0] == one){
- Node zero = utils::mkConst(size, 0u);
- TNode b = p[0];
- TNode c = p[1];
- // (s : 1 << S) = (b : 1 << B) + (c : 1 << C)
- Node b_eq_0 = b.eqNode(zero);
- Node c_eq_0 = c.eqNode(zero);
- Node b_eq_c = b.eqNode(c);
-
- Node dis = NodeManager::currentNM()->mkNode(
- kind::OR, b_eq_0, c_eq_0, b_eq_c);
- Node imp = in.impNode(dis);
- learned << imp;
- }
- }
- }
- }else if(in.getKind() == kind::AND){
- for(size_t i = 0, N = in.getNumChildren(); i < N; ++i){
- ppStaticLearn(in[i], learned);
- }
- }
+ d_internal->notifySharedTerm(t);
}
-bool TheoryBV::applyAbstraction(const std::vector<Node>& assertions, std::vector<Node>& new_assertions) {
- bool changed = d_abstractionModule->applyAbstraction(assertions, new_assertions);
- if (changed && options::bitblastMode() == options::BitblastMode::EAGER
- && options::bitvectorAig())
- {
- // disable AIG mode
- AlwaysAssert(!d_eagerSolver->isInitialized());
- d_eagerSolver->turnOffAig();
- d_eagerSolver->initialize();
- }
- return changed;
-}
-
-void TheoryBV::setProofLog(proof::BitVectorProof* bvp)
+void TheoryBV::ppStaticLearn(TNode in, NodeBuilder<>& learned)
{
- if (options::bitblastMode() == options::BitblastMode::EAGER)
- {
- d_eagerSolver->setProofLog(bvp);
- }
- else
- {
- for( unsigned i=0; i< d_subtheories.size(); i++ ){
- d_subtheories[i]->setProofLog( bvp );
- }
- }
+ d_internal->ppStaticLearn(in, learned);
}
-void TheoryBV::setConflict(Node conflict)
+bool TheoryBV::applyAbstraction(const std::vector<Node>& assertions,
+ std::vector<Node>& new_assertions)
{
- if (options::bvAbstraction())
- {
- NodeManager* const nm = NodeManager::currentNM();
- Node new_conflict = d_abstractionModule->simplifyConflict(conflict);
-
- std::vector<Node> lemmas;
- lemmas.push_back(new_conflict);
- d_abstractionModule->generalizeConflict(new_conflict, lemmas);
- for (unsigned i = 0; i < lemmas.size(); ++i)
- {
- lemma(nm->mkNode(kind::NOT, lemmas[i]));
- }
- }
- d_conflict = true;
- d_conflictNode = conflict;
+ return d_internal->applyAbstraction(assertions, new_assertions);
}
-} /* namespace CVC4::theory::bv */
-} /* namespace CVC4::theory */
-} /* namespace CVC4 */
+} // namespace bv
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/bv/theory_bv.h b/src/theory/bv/theory_bv.h
index c98de0f18..fa228131c 100644
--- a/src/theory/bv/theory_bv.h
+++ b/src/theory/bv/theory_bv.h
@@ -2,10 +2,10 @@
/*! \file theory_bv.h
** \verbatim
** Top contributors (to current version):
- ** Liana Hadarean, Andrew Reynolds, Tim King
+ ** Andrew Reynolds, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,50 +20,21 @@
#define CVC4__THEORY__BV__THEORY_BV_H
#include <unordered_map>
-#include <unordered_set>
-#include "context/cdhashset.h"
-#include "context/cdlist.h"
-#include "context/context.h"
-#include "theory/bv/bv_subtheory.h"
#include "theory/bv/theory_bv_rewriter.h"
-#include "theory/bv/theory_bv_utils.h"
#include "theory/theory.h"
-#include "util/hash.h"
-#include "util/statistics_registry.h"
-
-// Forward declarations, needed because the BV theory and the BV Proof classes
-// are cyclically dependent
-namespace CVC4 {
-namespace proof {
-class BitVectorProof;
-}
-} // namespace CVC4
namespace CVC4 {
namespace theory {
namespace bv {
-class CoreSolver;
-class InequalitySolver;
-class AlgebraicSolver;
-class BitblastSolver;
-
-class EagerBitblastSolver;
-
-class AbstractionModule;
-
-class TheoryBV : public Theory {
+class BVSolver;
- /** The context we are using */
- context::Context* d_context;
-
- /** Context dependent set of atoms we already propagated */
- context::CDHashSet<Node, NodeHashFunction> d_alreadyPropagatedSet;
- context::CDHashSet<Node, NodeHashFunction> d_sharedTermsSet;
-
- std::vector<std::unique_ptr<SubtheorySolver>> d_subtheories;
- std::unordered_map<SubTheory, SubtheorySolver*, std::hash<int> > d_subtheoryMap;
+class TheoryBV : public Theory
+{
+ /* BVSolverLazy accesses methods from theory in a way that is deprecated and
+ * will be removed in the future. For now we allow direct access. */
+ friend class BVSolverLazy;
public:
TheoryBV(context::Context* c,
@@ -76,9 +47,15 @@ class TheoryBV : public Theory {
~TheoryBV();
- TheoryRewriter* getTheoryRewriter() override { return &d_rewriter; }
+ /** get the official theory rewriter of this theory */
+ TheoryRewriter* getTheoryRewriter() override;
- void setMasterEqualityEngine(eq::EqualityEngine* eq) override;
+ /**
+ * Returns true if we need an equality engine. If so, we initialize the
+ * information regarding how it should be setup. For details, see the
+ * documentation in Theory::needsEqualityEngine.
+ */
+ bool needsEqualityEngine(EeSetupInfo& esi) override;
void finishInit() override;
@@ -86,7 +63,17 @@ class TheoryBV : public Theory {
void preRegisterTerm(TNode n) override;
- void check(Effort e) override;
+ bool preCheck(Effort e) override;
+
+ void postCheck(Effort e) override;
+
+ bool preNotifyFact(TNode atom,
+ bool pol,
+ TNode fact,
+ bool isPrereg,
+ bool isInternal) override;
+
+ void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal) override;
bool needsCheckLastEffort() override;
@@ -94,21 +81,14 @@ class TheoryBV : public Theory {
TrustNode explain(TNode n) override;
- bool collectModelInfo(TheoryModel* m) override;
+ /** Collect model values in m based on the relevant terms given by termSet */
+ bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet) override;
std::string identify() const override { return std::string("TheoryBV"); }
- /** equality engine */
- eq::EqualityEngine* getEqualityEngine() override;
- bool getCurrentSubstitution(int effort,
- std::vector<Node>& vars,
- std::vector<Node>& subs,
- std::map<Node, std::vector<Node>>& exp) override;
- int getReduction(int effort, Node n, Node& nr) override;
-
- PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions) override;
-
- void enableCoreTheorySlicer();
+ PPAssertStatus ppAssert(TrustNode in,
+ TrustSubstitutionMap& outSubstitutions) override;
TrustNode ppRewrite(TNode t) override;
@@ -116,171 +96,44 @@ class TheoryBV : public Theory {
void presolve() override;
+ /** Called by abstraction preprocessing pass. */
bool applyAbstraction(const std::vector<Node>& assertions,
std::vector<Node>& new_assertions);
- void setProofLog(proof::BitVectorProof* bvp);
-
private:
- class Statistics
- {
- public:
- AverageStat d_avgConflictSize;
- IntStat d_solveSubstitutions;
- TimerStat d_solveTimer;
- IntStat d_numCallsToCheckFullEffort;
- IntStat d_numCallsToCheckStandardEffort;
- TimerStat d_weightComputationTimer;
- IntStat d_numMultSlice;
- Statistics();
- ~Statistics();
- };
-
- Statistics d_statistics;
-
- void spendResource(ResourceManager::Resource r);
+ void notifySharedTerm(TNode t) override;
/**
- * Return the uninterpreted function symbol corresponding to division-by-zero
- * for this particular bit-width
+ * Return the UF symbol corresponding to division-by-zero for this particular
+ * bit-width.
* @param k should be UREM or UDIV
- * @param width
- *
- * @return
+ * @param width bit-width
*/
- Node getBVDivByZero(Kind k, unsigned width);
+ Node getUFDivByZero(Kind k, unsigned width);
- typedef std::unordered_set<TNode, TNodeHashFunction> TNodeSet;
- typedef std::unordered_set<Node, NodeHashFunction> NodeSet;
- NodeSet d_staticLearnCache;
+ /** Internal BV solver. */
+ std::unique_ptr<BVSolver> d_internal;
/**
* Maps from bit-vector width to division-by-zero uninterpreted
* function symbols.
*/
- std::unordered_map<unsigned, Node> d_BVDivByZero;
- std::unordered_map<unsigned, Node> d_BVRemByZero;
-
- typedef std::unordered_map<Node, Node, NodeHashFunction> NodeToNode;
-
- context::CDO<bool> d_lemmasAdded;
-
- // Are we in conflict?
- context::CDO<bool> d_conflict;
-
- // Invalidate the model cache if check was called
- context::CDO<bool> d_invalidateModelCache;
-
- /** The conflict node */
- Node d_conflictNode;
-
- /** Literals to propagate */
- context::CDList<Node> d_literalsToPropagate;
-
- /** Index of the next literal to propagate */
- context::CDO<unsigned> d_literalsToPropagateIndex;
+ std::unordered_map<unsigned, Node> d_ufDivByZero;
+ std::unordered_map<unsigned, Node> d_ufRemByZero;
- /**
- * Keeps a map from nodes to the subtheory that propagated it so that we can explain it
- * properly.
- */
- typedef context::CDHashMap<Node, SubTheory, NodeHashFunction> PropagatedMap;
- PropagatedMap d_propagatedBy;
-
- std::unique_ptr<EagerBitblastSolver> d_eagerSolver;
- std::unique_ptr<AbstractionModule> d_abstractionModule;
- bool d_isCoreTheory;
- bool d_calledPreregister;
-
- //for extended functions
- bool d_needsLastCallCheck;
- context::CDHashSet<Node, NodeHashFunction> d_extf_range_infer;
- context::CDHashSet<Node, NodeHashFunction> d_extf_collapse_infer;
- /** do extended function inferences
- *
- * This method adds lemmas on the output channel of TheoryBV based on
- * reasoning about extended functions, such as bv2nat and int2bv. Examples
- * of lemmas added by this method include:
- * 0 <= ((_ int2bv w) x) < 2^w
- * ((_ int2bv w) (bv2nat x)) = x
- * (bv2nat ((_ int2bv w) x)) == x + k*2^w
- * The purpose of these lemmas is to recognize easy conflicts before fully
- * reducing extended functions based on their full semantics.
- */
- bool doExtfInferences( std::vector< Node >& terms );
- /** do extended function reductions
- *
- * This method adds lemmas on the output channel of TheoryBV based on
- * reducing all extended function applications that are preregistered to
- * this theory and have not already been reduced by context-dependent
- * simplification (see theory/ext_theory.h). Examples of lemmas added by
- * this method include:
- * (bv2nat x) = (ite ((_ extract w w-1) x) 2^{w-1} 0) + ... +
- * (ite ((_ extract 1 0) x) 1 0)
- */
- bool doExtfReductions( std::vector< Node >& terms );
-
- bool wasPropagatedBySubtheory(TNode literal) const {
- return d_propagatedBy.find(literal) != d_propagatedBy.end();
- }
-
- SubTheory getPropagatingSubtheory(TNode literal) const {
- Assert(wasPropagatedBySubtheory(literal));
- PropagatedMap::const_iterator find = d_propagatedBy.find(literal);
- return (*find).second;
- }
-
- /** Should be called to propagate the literal. */
- bool storePropagation(TNode literal, SubTheory subtheory);
-
- /**
- * Explains why this literal (propagated by subtheory) is true by adding assumptions.
- */
- void explain(TNode literal, std::vector<TNode>& assumptions);
-
- void addSharedTerm(TNode t) override;
-
- bool isSharedTerm(TNode t) { return d_sharedTermsSet.contains(t); }
-
- EqualityStatus getEqualityStatus(TNode a, TNode b) override;
-
- Node getModelValue(TNode var) override;
-
- inline std::string indent()
- {
- std::string indentStr(getSatContext()->getLevel(), ' ');
- return indentStr;
- }
-
- void setConflict(Node conflict = Node::null());
-
- bool inConflict() {
- return d_conflict;
- }
-
- void sendConflict();
+ /** The theory rewriter for this theory. */
+ TheoryBVRewriter d_rewriter;
- void lemma(TNode node) { d_out->lemma(node, RULE_CONFLICT); d_lemmasAdded = true; }
+ /** A (default) theory state object */
+ TheoryState d_state;
- void checkForLemma(TNode node);
+ /** A (default) theory inference manager. */
+ TheoryInferenceManager d_inferMgr;
- /** The theory rewriter for this theory. */
- TheoryBVRewriter d_rewriter;
+}; /* class TheoryBV */
- friend class LazyBitblaster;
- friend class TLazyBitblaster;
- friend class EagerBitblaster;
- friend class BitblastSolver;
- friend class EqualitySolver;
- friend class CoreSolver;
- friend class InequalitySolver;
- friend class AlgebraicSolver;
- friend class EagerBitblastSolver;
-};/* class TheoryBV */
-
-}/* CVC4::theory::bv namespace */
-}/* CVC4::theory namespace */
-
-}/* CVC4 namespace */
+} // namespace bv
+} // namespace theory
+} // namespace CVC4
#endif /* CVC4__THEORY__BV__THEORY_BV_H */
diff --git a/src/theory/bv/theory_bv_rewrite_rules.h b/src/theory/bv/theory_bv_rewrite_rules.h
index 6e7fb37d0..8f97bf3a6 100644
--- a/src/theory/bv/theory_bv_rewrite_rules.h
+++ b/src/theory/bv/theory_bv_rewrite_rules.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Dejan Jovanovic, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -22,7 +22,10 @@
#include <sstream>
#include "context/context.h"
-#include "smt/command.h"
+#include "printer/printer.h"
+#include "smt/dump.h"
+#include "smt/smt_engine.h"
+#include "smt/smt_engine_scope.h"
#include "theory/bv/theory_bv_utils.h"
#include "theory/theory.h"
#include "util/statistics_registry.h"
@@ -66,9 +69,12 @@ enum RewriteRuleId
NorEliminate,
XnorEliminate,
SdivEliminate,
+ SdivEliminateFewerBitwiseOps,
UdivEliminate,
SmodEliminate,
+ SmodEliminateFewerBitwiseOps,
SremEliminate,
+ SremEliminateFewerBitwiseOps,
ZeroExtendEliminate,
SignExtendEliminate,
BVToNatEliminate,
@@ -120,6 +126,9 @@ enum RewriteRuleId
AndZero,
AndOne,
AndOrXorConcatPullUp,
+ NegEliminate,
+ OrEliminate,
+ XorEliminate,
OrZero,
OrOne,
XorDuplicate,
@@ -150,6 +159,7 @@ enum RewriteRuleId
UremOne,
UremSelf,
ShiftZero,
+ UgtUrem,
UltOne,
SltZero,
@@ -193,6 +203,7 @@ enum RewriteRuleId
ConcatToMult,
IsPowerOfTwo,
MultSltMult,
+ BitOfConst,
};
inline std::ostream& operator << (std::ostream& out, RewriteRuleId ruleId) {
@@ -202,6 +213,9 @@ inline std::ostream& operator << (std::ostream& out, RewriteRuleId ruleId) {
case ConcatExtractMerge: out << "ConcatExtractMerge"; return out;
case ConcatConstantMerge: out << "ConcatConstantMerge"; return out;
case AndOrXorConcatPullUp:out << "AndOrXorConcatPullUp";return out;
+ case NegEliminate: out << "NegEliminate"; return out;
+ case OrEliminate: out << "OrEliminate"; return out;
+ case XorEliminate: out << "XorEliminate"; return out;
case ExtractExtract: out << "ExtractExtract"; return out;
case ExtractWhole: out << "ExtractWhole"; return out;
case ExtractConcat: out << "ExtractConcat"; return out;
@@ -223,8 +237,17 @@ inline std::ostream& operator << (std::ostream& out, RewriteRuleId ruleId) {
case NandEliminate: out << "NandEliminate"; return out;
case NorEliminate : out << "NorEliminate"; return out;
case SdivEliminate : out << "SdivEliminate"; return out;
+ case SdivEliminateFewerBitwiseOps:
+ out << "SdivEliminateFewerBitwiseOps";
+ return out;
case SremEliminate : out << "SremEliminate"; return out;
+ case SremEliminateFewerBitwiseOps:
+ out << "SremEliminateFewerBitwiseOps";
+ return out;
case SmodEliminate : out << "SmodEliminate"; return out;
+ case SmodEliminateFewerBitwiseOps:
+ out << "SmodEliminateFewerBitwiseOps";
+ return out;
case ZeroExtendEliminate :out << "ZeroExtendEliminate"; return out;
case EvalEquals : out << "EvalEquals"; return out;
case EvalConcat : out << "EvalConcat"; return out;
@@ -306,6 +329,7 @@ inline std::ostream& operator << (std::ostream& out, RewriteRuleId ruleId) {
case UremOne : out << "UremOne"; return out;
case UremSelf : out << "UremSelf"; return out;
case ShiftZero : out << "ShiftZero"; return out;
+ case UgtUrem: out << "UgtUrem"; return out;
case SubEliminate : out << "SubEliminate"; return out;
case CompEliminate : out << "CompEliminate"; return out;
case XnorEliminate : out << "XnorEliminate"; return out;
@@ -344,6 +368,7 @@ inline std::ostream& operator << (std::ostream& out, RewriteRuleId ruleId) {
case IsPowerOfTwo: out << "IsPowerOfTwo"; return out;
case MultSltMult: out << "MultSltMult"; return out;
case NormalizeEqPlusNeg: out << "NormalizeEqPlusNeg"; return out;
+ case BitOfConst: out << "BitOfConst"; return out;
default:
Unreachable();
}
@@ -429,9 +454,13 @@ public:
Node condition = node.eqNode(result).notNode();
- Dump("bv-rewrites")
- << CommentCommand(os.str())
- << CheckSatCommand(condition.toExpr());
+ const Printer& printer =
+ smt::currentSmtEngine()->getOutputManager().getPrinter();
+ std::ostream& out =
+ smt::currentSmtEngine()->getOutputManager().getDumpOut();
+
+ printer.toStreamCmdComment(out, os.str());
+ printer.toStreamCmdCheckSat(out, condition);
}
}
Debug("theory::bv::rewrite") << "RewriteRule<" << rule << ">(" << node << ") => " << result << std::endl;
@@ -585,6 +614,13 @@ struct AllRewriteRules {
RewriteRule<BvIteMergeThenElse> rule137;
RewriteRule<BvIteMergeElseElse> rule138;
RewriteRule<AndOrXorConcatPullUp> rule139;
+ RewriteRule<NegEliminate> rule140;
+ RewriteRule<OrEliminate> rule141;
+ RewriteRule<XorEliminate> rule142;
+ RewriteRule<SdivEliminate> rule143;
+ RewriteRule<SremEliminate> rule144;
+ RewriteRule<SmodEliminate> rule145;
+ RewriteRule<UgtUrem> rule146;
};
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 f007bbc16..dfcc4f052 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_constant_evaluation.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_constant_evaluation.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Clark Barrett, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/bv/theory_bv_rewrite_rules_core.h b/src/theory/bv/theory_bv_rewrite_rules_core.h
index 53c8546a3..d57d2a20a 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_core.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_core.h
@@ -5,7 +5,7 @@
** Dejan Jovanovic, Liana Hadarean, Clark Barrett
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/bv/theory_bv_rewrite_rules_normalization.h b/src/theory/bv/theory_bv_rewrite_rules_normalization.h
index 6055ce86e..90e073e1e 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_normalization.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_normalization.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Aina Niemetz, Clark Barrett
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
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 3ff3a88b3..1e48be1da 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_operator_elimination.h
@@ -2,10 +2,10 @@
/*! \file theory_bv_rewrite_rules_operator_elimination.h
** \verbatim
** Top contributors (to current version):
- ** Liana Hadarean, Aina Niemetz, Yoni Zohar
+ ** Yoni Zohar, Liana Hadarean, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -27,6 +27,86 @@ namespace CVC4 {
namespace theory {
namespace bv {
+/*
+ * This rewrite is not meant to be used by the BV rewriter.
+ * It is specifically designed for the bv-to-int preprocessing pass.
+ * Based on Hacker's Delight section 2-2 equation a:
+ * -x = ~x+1
+ */
+template <>
+inline bool RewriteRule<NegEliminate>::applies(TNode node)
+{
+ return (node.getKind() == kind::BITVECTOR_NEG);
+}
+
+template <>
+inline Node RewriteRule<NegEliminate>::apply(TNode node)
+{
+ Debug("bv-rewrite") << "RewriteRule<NegEliminate>(" << node << ")"
+ << std::endl;
+ NodeManager* nm = NodeManager::currentNM();
+ TNode a = node[0];
+ unsigned size = utils::getSize(a);
+ Node one = utils::mkOne(size);
+ Node nota = nm->mkNode(kind::BITVECTOR_NOT, a);
+ Node bvadd =
+ nm->mkNode(kind::BITVECTOR_PLUS, nota, one);
+ return bvadd;
+}
+
+/*
+ * This rewrite is not meant to be used by the BV rewriter.
+ * It is specifically designed for the bv-to-int preprocessing pass.
+ * Based on Hacker's Delight section 2-2 equation h:
+ * x+y = x|y + x&y
+ */
+template <>
+inline bool RewriteRule<OrEliminate>::applies(TNode node)
+{
+ return (node.getKind() == kind::BITVECTOR_OR);
+}
+
+template <>
+inline Node RewriteRule<OrEliminate>::apply(TNode node)
+{
+ Debug("bv-rewrite") << "RewriteRule<OrEliminate>(" << node << ")"
+ << std::endl;
+ NodeManager* nm = NodeManager::currentNM();
+ TNode a = node[0];
+ TNode b = node[1];
+ Node bvadd = nm->mkNode(kind::BITVECTOR_PLUS, a, b);
+ Node bvand = nm->mkNode(kind::BITVECTOR_AND, a, b);
+ Node result =
+ nm->mkNode(kind::BITVECTOR_SUB, bvadd, bvand);
+ return result;
+}
+
+/*
+ * This rewrite is not meant to be used by the BV rewriter.
+ * It is specifically designed for the bv-to-int preprocessing pass.
+ * Based on Hacker's Delight section 2-2 equation n:
+ * x xor y = x|y - x&y
+ */
+template <>
+inline bool RewriteRule<XorEliminate>::applies(TNode node)
+{
+ return (node.getKind() == kind::BITVECTOR_XOR);
+}
+
+template <>
+inline Node RewriteRule<XorEliminate>::apply(TNode node)
+{
+ Debug("bv-rewrite") << "RewriteRule<XorEliminate>(" << node << ")"
+ << std::endl;
+ NodeManager* nm = NodeManager::currentNM();
+ TNode a = node[0];
+ TNode b = node[1];
+ Node bvor = nm->mkNode(kind::BITVECTOR_OR, a, b);
+ Node bvand = nm->mkNode(kind::BITVECTOR_AND, a, b);
+ Node result = nm->mkNode(kind::BITVECTOR_SUB, bvor, bvand);
+ return result;
+}
+
template <>
inline bool RewriteRule<UgtEliminate>::applies(TNode node)
{
@@ -397,6 +477,47 @@ inline Node RewriteRule<SdivEliminate>::apply(TNode node)
return result;
}
+/*
+ * This rewrite is not meant to be used by the BV rewriter
+ * It is specifically designed for the bv-to-int preprocessing pass.
+ * Similar to ordinary sdiv elimination.
+ * The sign-check is done with bvult instead of bit-extraction.
+ */
+template <>
+inline bool RewriteRule<SdivEliminateFewerBitwiseOps>::applies(TNode node)
+{
+ return (node.getKind() == kind::BITVECTOR_SDIV);
+}
+
+template <>
+inline Node RewriteRule<SdivEliminateFewerBitwiseOps>::apply(TNode node)
+{
+ Debug("bv-rewrite") << "RewriteRule<SdivEliminateFewerBitwiseOps>(" << node
+ << ")" << std::endl;
+
+ NodeManager* nm = NodeManager::currentNM();
+ TNode a = node[0];
+ TNode b = node[1];
+ unsigned size = utils::getSize(a);
+ Node a_lt_0 = nm->mkNode(kind::BITVECTOR_UGE, a, utils::mkMinSigned(size));
+ Node b_lt_0 = nm->mkNode(kind::BITVECTOR_UGE, b, utils::mkMinSigned(size));
+ Node abs_a =
+ nm->mkNode(kind::ITE, a_lt_0, nm->mkNode(kind::BITVECTOR_NEG, a), a);
+ Node abs_b =
+ nm->mkNode(kind::ITE, b_lt_0, nm->mkNode(kind::BITVECTOR_NEG, b), b);
+
+ Node a_udiv_b =
+ nm->mkNode(options::bitvectorDivByZeroConst() ? kind::BITVECTOR_UDIV_TOTAL
+ : kind::BITVECTOR_UDIV,
+ abs_a,
+ abs_b);
+ Node neg_result = nm->mkNode(kind::BITVECTOR_NEG, a_udiv_b);
+
+ Node result = nm->mkNode(kind::ITE, a_lt_0.xorNode(b_lt_0), neg_result, a_udiv_b);
+
+ return result;
+}
+
template <>
inline bool RewriteRule<SremEliminate>::applies(TNode node)
{
@@ -435,6 +556,45 @@ inline Node RewriteRule<SremEliminate>::apply(TNode node)
return result;
}
+/*
+ * This rewrite is not meant to be used by the BV rewriter
+ * It is specifically designed for the bv-to-int preprocessing pass.
+ * Similar to ordinary srem elimination.
+ * The sign-check is done with bvult instead of bit-extraction.
+ */
+template <>
+inline bool RewriteRule<SremEliminateFewerBitwiseOps>::applies(TNode node)
+{
+ return (node.getKind() == kind::BITVECTOR_SREM);
+}
+
+template <>
+inline Node RewriteRule<SremEliminateFewerBitwiseOps>::apply(TNode node)
+{
+ Debug("bv-rewrite") << "RewriteRule<SremEliminateFewerBitwiseOps>(" << node
+ << ")" << std::endl;
+ NodeManager* nm = NodeManager::currentNM();
+ TNode a = node[0];
+ TNode b = node[1];
+ unsigned size = utils::getSize(a);
+ Node a_lt_0 = nm->mkNode(kind::BITVECTOR_UGE, a, utils::mkMinSigned(size));
+ Node b_lt_0 = nm->mkNode(kind::BITVECTOR_UGE, b, utils::mkMinSigned(size));
+ Node abs_a =
+ nm->mkNode(kind::ITE, a_lt_0, nm->mkNode(kind::BITVECTOR_NEG, a), a);
+ Node abs_b =
+ nm->mkNode(kind::ITE, b_lt_0, nm->mkNode(kind::BITVECTOR_NEG, b), b);
+ Node a_urem_b =
+ nm->mkNode(options::bitvectorDivByZeroConst() ? kind::BITVECTOR_UREM_TOTAL
+ : kind::BITVECTOR_UREM,
+ abs_a,
+ abs_b);
+ Node neg_result = nm->mkNode(kind::BITVECTOR_NEG, a_urem_b);
+
+ Node result = nm->mkNode(kind::ITE, a_lt_0, neg_result, a_urem_b);
+
+ return result;
+}
+
template <>
inline bool RewriteRule<SmodEliminate>::applies(TNode node)
{
@@ -497,6 +657,73 @@ inline Node RewriteRule<SmodEliminate>::apply(TNode node)
return result;
}
+/*
+ * This rewrite is not meant to be used by the BV rewriter
+ * It is specifically designed for the bv-to-int preprocessing pass.
+ * Similar to ordinary smod elimination.
+ * The sign-check is done with bvult instead of bit-extraction.
+ */
+template <>
+inline bool RewriteRule<SmodEliminateFewerBitwiseOps>::applies(TNode node)
+{
+ return (node.getKind() == kind::BITVECTOR_SMOD);
+}
+
+template <>
+inline Node RewriteRule<SmodEliminateFewerBitwiseOps>::apply(TNode node)
+{
+ Debug("bv-rewrite") << "RewriteRule<SmodEliminate>(" << node << ")"
+ << std::endl;
+ NodeManager* nm = NodeManager::currentNM();
+ TNode s = node[0];
+ TNode t = node[1];
+ unsigned size = utils::getSize(s);
+
+ /*
+ * (bvsmod s t) abbreviates
+ * (let ((?msb_s ((_ extract |m-1| |m-1|) s))
+ * (?msb_t ((_ extract |m-1| |m-1|) t)))
+ * (let ((abs_s (ite (= ?msb_s #b0) s (bvneg s)))
+ * (abs_t (ite (= ?msb_t #b0) t (bvneg t))))
+ * (let ((u (bvurem abs_s abs_t)))
+ * (ite (= u (_ bv0 m))
+ * u
+ * (ite (and (= ?msb_s #b0) (= ?msb_t #b0))
+ * u
+ * (ite (and (= ?msb_s #b1) (= ?msb_t #b0))
+ * (bvadd (bvneg u) t)
+ * (ite (and (= ?msb_s #b0) (= ?msb_t #b1))
+ * (bvadd u t)
+ * (bvneg u))))))))
+ */
+
+ Node s_lt_0 = nm->mkNode(kind::BITVECTOR_UGE, s, utils::mkMinSigned(size));
+ Node t_lt_0 = nm->mkNode(kind::BITVECTOR_UGE, t, utils::mkMinSigned(size));
+ Node abs_s =
+ nm->mkNode(kind::ITE, s_lt_0, nm->mkNode(kind::BITVECTOR_NEG, s), s);
+ Node abs_t =
+ nm->mkNode(kind::ITE, t_lt_0, nm->mkNode(kind::BITVECTOR_NEG, t), t);
+
+ Node u = nm->mkNode(kind::BITVECTOR_UREM, abs_s, abs_t);
+ Node neg_u = nm->mkNode(kind::BITVECTOR_NEG, u);
+
+ Node cond0 = u.eqNode(utils::mkConst(size, 0));
+ Node cond1 =
+ nm->mkNode(kind::NOT, s_lt_0).andNode(nm->mkNode(kind::NOT, t_lt_0));
+ Node cond2 = s_lt_0.andNode(nm->mkNode(kind::NOT, t_lt_0));
+ Node cond3 = nm->mkNode(kind::NOT, s_lt_0).andNode(t_lt_0);
+
+ Node result = cond0.iteNode(
+ u,
+ cond1.iteNode(
+ u,
+ cond2.iteNode(
+ nm->mkNode(kind::BITVECTOR_PLUS, neg_u, t),
+ cond3.iteNode(nm->mkNode(kind::BITVECTOR_PLUS, u, t), neg_u))));
+
+ return result;
+}
+
template <>
inline bool RewriteRule<ZeroExtendEliminate>::applies(TNode node)
{
diff --git a/src/theory/bv/theory_bv_rewrite_rules_simplification.h b/src/theory/bv/theory_bv_rewrite_rules_simplification.h
index c35f33f53..20dac35cd 100644
--- a/src/theory/bv/theory_bv_rewrite_rules_simplification.h
+++ b/src/theory/bv/theory_bv_rewrite_rules_simplification.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Aina Niemetz, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,6 +19,7 @@
#pragma once
+#include "options/bv_options.h"
#include "theory/bv/theory_bv_rewrite_rules.h"
#include "theory/bv/theory_bv_utils.h"
#include "theory/rewriter.h"
@@ -27,6 +28,23 @@ namespace CVC4 {
namespace theory {
namespace bv {
+/* -------------------------------------------------------------------------- */
+
+/**
+ * BitOfConst
+ */
+template <>
+inline bool RewriteRule<BitOfConst>::applies(TNode node)
+{
+ return node.getKind() == kind::BITVECTOR_BITOF && node[0].isConst();
+}
+
+template <>
+inline Node RewriteRule<BitOfConst>::apply(TNode node)
+{
+ size_t pos = node.getOperator().getConst<BitVectorBitOf>().d_bitIndex;
+ return utils::getBit(node[0], pos) ? utils::mkTrue() : utils::mkFalse();
+}
/* -------------------------------------------------------------------------- */
@@ -1558,6 +1576,41 @@ Node RewriteRule<ShiftZero>::apply(TNode node) {
/* -------------------------------------------------------------------------- */
/**
+ * UgtUrem
+ *
+ * (bvugt (bvurem T x) x)
+ * ==> (ite (= x 0_k) (bvugt T x) false)
+ * ==> (and (=> (= x 0_k) (bvugt T x)) (=> (not (= x 0_k)) false))
+ * ==> (and (=> (= x 0_k) (bvugt T x)) (= x 0_k))
+ * ==> (and (bvugt T x) (= x 0_k))
+ * ==> (and (bvugt T 0_k) (= x 0_k))
+ */
+
+template <>
+inline bool RewriteRule<UgtUrem>::applies(TNode node)
+{
+ return (options::bitvectorDivByZeroConst()
+ && node.getKind() == kind::BITVECTOR_UGT
+ && node[0].getKind() == kind::BITVECTOR_UREM_TOTAL
+ && node[0][1] == node[1]);
+}
+
+template <>
+inline Node RewriteRule<UgtUrem>::apply(TNode node)
+{
+ Debug("bv-rewrite") << "RewriteRule<UgtUrem>(" << node << ")" << std::endl;
+ const Node& T = node[0][0];
+ const Node& x = node[1];
+ Node zero = utils::mkConst(utils::getSize(x), 0);
+ NodeManager* nm = NodeManager::currentNM();
+ return nm->mkNode(kind::AND,
+ nm->mkNode(kind::EQUAL, x, zero),
+ nm->mkNode(kind::BITVECTOR_UGT, T, zero));
+}
+
+/* -------------------------------------------------------------------------- */
+
+/**
* BBPlusNeg
*
* -a1 - a2 - ... - an + ak + .. ==> - (a1 + a2 + ... + an) + ak
@@ -1840,7 +1893,7 @@ inline bool RewriteRule<SignExtendUltConst>::applies(TNode node)
unsigned size_c = utils::getSize(c);
unsigned msb_x_pos = utils::getSize(x) - 1;
// (1 << (n - 1)))
- BitVector bv_msb_x = BitVector(size_c).setBit(msb_x_pos);
+ BitVector bv_msb_x = BitVector(size_c).setBit(msb_x_pos, true);
// (~0 << (n - 1))
BitVector bv_upper_bits =
(~BitVector(size_c)).leftShift(BitVector(size_c, msb_x_pos));
@@ -1876,7 +1929,7 @@ inline Node RewriteRule<SignExtendUltConst>::apply(TNode node)
unsigned msb_x_pos = utils::getSize(x) - 1;
Node c_lo = utils::mkConst(bv_c.extract(msb_x_pos, 0));
// (1 << (n - 1)))
- BitVector bv_msb_x = BitVector(size_c).setBit(msb_x_pos);
+ BitVector bv_msb_x = BitVector(size_c).setBit(msb_x_pos, true);
// (~0 << (n - 1))
BitVector bv_upper_bits =
(~BitVector(size_c)).leftShift(BitVector(size_c, msb_x_pos));
diff --git a/src/theory/bv/theory_bv_rewriter.cpp b/src/theory/bv/theory_bv_rewriter.cpp
index 0b1b58f9a..4f84facca 100644
--- a/src/theory/bv/theory_bv_rewriter.cpp
+++ b/src/theory/bv/theory_bv_rewriter.cpp
@@ -5,7 +5,7 @@
** Liana Hadarean, Aina Niemetz, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -53,6 +53,12 @@ RewriteResponse TheoryBVRewriter::postRewrite(TNode node) {
return res;
}
+RewriteResponse TheoryBVRewriter::RewriteBitOf(TNode node, bool prerewrite)
+{
+ Node resultNode = LinearRewriteStrategy<RewriteRule<BitOfConst>>::apply(node);
+ return RewriteResponse(REWRITE_DONE, resultNode);
+}
+
RewriteResponse TheoryBVRewriter::RewriteUlt(TNode node, bool prerewrite) {
// reduce common subexpressions on both sides
Node resultNode = LinearRewriteStrategy
@@ -121,9 +127,9 @@ RewriteResponse TheoryBVRewriter::RewriteSle(TNode node, bool prerewrite){
}
RewriteResponse TheoryBVRewriter::RewriteUgt(TNode node, bool prerewrite){
- Node resultNode = LinearRewriteStrategy
- < RewriteRule<UgtEliminate>
- >::apply(node);
+ Node resultNode =
+ LinearRewriteStrategy<RewriteRule<UgtUrem>,
+ RewriteRule<UgtEliminate>>::apply(node);
return RewriteResponse(REWRITE_AGAIN, resultNode);
}
@@ -683,6 +689,7 @@ void TheoryBVRewriter::initializeRewrites() {
}
d_rewriteTable [ kind::EQUAL ] = RewriteEqual;
+ d_rewriteTable[kind::BITVECTOR_BITOF] = RewriteBitOf;
d_rewriteTable [ kind::BITVECTOR_ULT ] = RewriteUlt;
d_rewriteTable [ kind::BITVECTOR_SLT ] = RewriteSlt;
d_rewriteTable [ kind::BITVECTOR_ULE ] = RewriteUle;
diff --git a/src/theory/bv/theory_bv_rewriter.h b/src/theory/bv/theory_bv_rewriter.h
index 74e8b4f79..7e2110b14 100644
--- a/src/theory/bv/theory_bv_rewriter.h
+++ b/src/theory/bv/theory_bv_rewriter.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Andres Noetzli, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -50,8 +50,9 @@ class TheoryBVRewriter : public TheoryRewriter
private:
static RewriteResponse IdentityRewrite(TNode node, bool prerewrite = false);
- static RewriteResponse UndefinedRewrite(TNode node, bool prerewrite = false);
-
+ static RewriteResponse UndefinedRewrite(TNode node, bool prerewrite = false);
+
+ static RewriteResponse RewriteBitOf(TNode node, bool prerewrite = false);
static RewriteResponse RewriteEqual(TNode node, bool prerewrite = false);
static RewriteResponse RewriteUlt(TNode node, bool prerewrite = false);
static RewriteResponse RewriteUltBv(TNode node, bool prerewrite = false);
diff --git a/src/theory/bv/theory_bv_type_rules.h b/src/theory/bv/theory_bv_type_rules.h
index ea3e30d9e..b250fa153 100644
--- a/src/theory/bv/theory_bv_type_rules.h
+++ b/src/theory/bv/theory_bv_type_rules.h
@@ -5,7 +5,7 @@
** Aina Niemetz, Andrew Reynolds, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/bv/theory_bv_utils.cpp b/src/theory/bv/theory_bv_utils.cpp
index b7b3ebf57..21d3004df 100644
--- a/src/theory/bv/theory_bv_utils.cpp
+++ b/src/theory/bv/theory_bv_utils.cpp
@@ -5,7 +5,7 @@
** Aina Niemetz, Andrew Reynolds, Liana Hadarean
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/bv/theory_bv_utils.h b/src/theory/bv/theory_bv_utils.h
index 1ac0b39dc..4f42217aa 100644
--- a/src/theory/bv/theory_bv_utils.h
+++ b/src/theory/bv/theory_bv_utils.h
@@ -5,7 +5,7 @@
** Aina Niemetz, Andrew Reynolds, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/bv/type_enumerator.h b/src/theory/bv/type_enumerator.h
index 6a388cc0e..9a1142fe9 100644
--- a/src/theory/bv/type_enumerator.h
+++ b/src/theory/bv/type_enumerator.h
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/care_graph.h b/src/theory/care_graph.h
index 121d605dc..40553f01b 100644
--- a/src/theory/care_graph.h
+++ b/src/theory/care_graph.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Dejan Jovanovic, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/combination_care_graph.cpp b/src/theory/combination_care_graph.cpp
new file mode 100644
index 000000000..45a709d19
--- /dev/null
+++ b/src/theory/combination_care_graph.cpp
@@ -0,0 +1,100 @@
+/********************* */
+/*! \file combination_care_graph.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Dejan Jovanovic
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Management of a care graph based approach for theory combination.
+ **/
+
+#include "theory/combination_care_graph.h"
+
+#include "expr/node_visitor.h"
+#include "theory/care_graph.h"
+#include "theory/theory_engine.h"
+
+namespace CVC4 {
+namespace theory {
+
+CombinationCareGraph::CombinationCareGraph(
+ TheoryEngine& te,
+ const std::vector<Theory*>& paraTheories,
+ ProofNodeManager* pnm)
+ : CombinationEngine(te, paraTheories, pnm)
+{
+}
+
+CombinationCareGraph::~CombinationCareGraph() {}
+
+void CombinationCareGraph::combineTheories()
+{
+ Trace("combineTheories") << "TheoryEngine::combineTheories()" << std::endl;
+
+ // Care graph we'll be building
+ CareGraph careGraph;
+
+ // get the care graph from the parametric theories
+ for (Theory* t : d_paraTheories)
+ {
+ t->getCareGraph(&careGraph);
+ }
+
+ Trace("combineTheories")
+ << "TheoryEngine::combineTheories(): care graph size = "
+ << careGraph.size() << std::endl;
+
+ // Now add splitters for the ones we are interested in
+ prop::PropEngine* propEngine = d_te.getPropEngine();
+ for (const CarePair& carePair : careGraph)
+ {
+ Debug("combineTheories")
+ << "TheoryEngine::combineTheories(): checking " << carePair.d_a << " = "
+ << carePair.d_b << " from " << carePair.d_theory << std::endl;
+
+ // The equality in question (order for no repetition)
+ Node equality = carePair.d_a.eqNode(carePair.d_b);
+
+ // We need to split on it
+ Debug("combineTheories")
+ << "TheoryEngine::combineTheories(): requesting a split " << std::endl;
+
+ TrustNode tsplit;
+ if (isProofEnabled())
+ {
+ // make proof of splitting lemma
+ tsplit = d_cmbsPg->mkTrustNodeSplit(equality);
+ }
+ else
+ {
+ Node split = equality.orNode(equality.notNode());
+ tsplit = TrustNode::mkTrustLemma(split, nullptr);
+ }
+ sendLemma(tsplit, carePair.d_theory);
+
+ // Could check the equality status here:
+ // EqualityStatus es = getEqualityStatus(carePair.d_a, carePair.d_b);
+ // and only require true phase below if:
+ // es == EQUALITY_TRUE || es == EQUALITY_TRUE_IN_MODEL
+ // and require false phase below if:
+ // es == EQUALITY_FALSE_IN_MODEL
+ // This is supposed to force preference to follow what the theory models
+ // already have but it doesn't seem to make a big difference - need to
+ // explore more -Clark
+ Node e = d_te.ensureLiteral(equality);
+ propEngine->requirePhase(e, true);
+ }
+}
+
+bool CombinationCareGraph::buildModel()
+{
+ // building the model happens as a separate step
+ return d_mmanager->buildModel();
+}
+
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/combination_care_graph.h b/src/theory/combination_care_graph.h
new file mode 100644
index 000000000..98d55ba63
--- /dev/null
+++ b/src/theory/combination_care_graph.h
@@ -0,0 +1,52 @@
+/********************* */
+/*! \file combination_care_graph.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Management of a care graph based approach for theory combination.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__COMBINATION_CARE_GRAPH__H
+#define CVC4__THEORY__COMBINATION_CARE_GRAPH__H
+
+#include <vector>
+
+#include "theory/combination_engine.h"
+
+namespace CVC4 {
+
+class TheoryEngine;
+
+namespace theory {
+
+/**
+ * Manager for doing theory combination using care graphs. This is typically
+ * done via a distributed equality engine architecture.
+ */
+class CombinationCareGraph : public CombinationEngine
+{
+ public:
+ CombinationCareGraph(TheoryEngine& te,
+ const std::vector<Theory*>& paraTheories,
+ ProofNodeManager* pnm);
+ ~CombinationCareGraph();
+
+ bool buildModel() override;
+ /**
+ * Combine theories using a care graph.
+ */
+ void combineTheories() override;
+};
+
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__COMBINATION_DISTRIBUTED__H */
diff --git a/src/theory/combination_engine.cpp b/src/theory/combination_engine.cpp
new file mode 100644
index 000000000..5e242659f
--- /dev/null
+++ b/src/theory/combination_engine.cpp
@@ -0,0 +1,127 @@
+/********************* */
+/*! \file combination_engine.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Management of a care graph based approach for theory combination.
+ **/
+
+#include "theory/combination_engine.h"
+
+#include "expr/node_visitor.h"
+#include "theory/care_graph.h"
+#include "theory/ee_manager_distributed.h"
+#include "theory/model_manager_distributed.h"
+#include "theory/shared_solver_distributed.h"
+#include "theory/theory_engine.h"
+
+namespace CVC4 {
+namespace theory {
+
+CombinationEngine::CombinationEngine(TheoryEngine& te,
+ const std::vector<Theory*>& paraTheories,
+ ProofNodeManager* pnm)
+ : d_te(te),
+ d_pnm(pnm),
+ d_logicInfo(te.getLogicInfo()),
+ d_paraTheories(paraTheories),
+ d_eemanager(nullptr),
+ d_mmanager(nullptr),
+ d_sharedSolver(nullptr),
+ d_cmbsPg(pnm ? new EagerProofGenerator(pnm, te.getUserContext())
+ : nullptr)
+{
+}
+
+CombinationEngine::~CombinationEngine() {}
+
+void CombinationEngine::finishInit()
+{
+ // create the equality engine, model manager, and shared solver
+ if (options::eeMode() == options::EqEngineMode::DISTRIBUTED)
+ {
+ // use the distributed shared solver
+ d_sharedSolver.reset(new SharedSolverDistributed(d_te, d_pnm));
+ // make the distributed equality engine manager
+ d_eemanager.reset(
+ new EqEngineManagerDistributed(d_te, *d_sharedSolver.get()));
+ // make the distributed model manager
+ d_mmanager.reset(new ModelManagerDistributed(d_te, *d_eemanager.get()));
+ }
+ else
+ {
+ Unhandled() << "CombinationEngine::finishInit: equality engine mode "
+ << options::eeMode() << " not supported";
+ }
+
+ Assert(d_eemanager != nullptr);
+
+ // initialize equality engines in all theories, including quantifiers engine
+ // and the (provided) shared solver
+ d_eemanager->initializeTheories();
+
+ Assert(d_mmanager != nullptr);
+ // initialize the model manager, based on the notify object of this class
+ eq::EqualityEngineNotify* meen = getModelEqualityEngineNotify();
+ d_mmanager->finishInit(meen);
+}
+
+const EeTheoryInfo* CombinationEngine::getEeTheoryInfo(TheoryId tid) const
+{
+ return d_eemanager->getEeTheoryInfo(tid);
+}
+
+eq::EqualityEngine* CombinationEngine::getCoreEqualityEngine()
+{
+ return d_eemanager->getCoreEqualityEngine();
+}
+
+void CombinationEngine::resetModel() { d_mmanager->resetModel(); }
+
+void CombinationEngine::postProcessModel(bool incomplete)
+{
+ // should have a consistent core equality engine
+ eq::EqualityEngine* mee = d_eemanager->getCoreEqualityEngine();
+ if (mee != nullptr)
+ {
+ AlwaysAssert(mee->consistent());
+ }
+ // postprocess with the model
+ d_mmanager->postProcessModel(incomplete);
+}
+
+theory::TheoryModel* CombinationEngine::getModel()
+{
+ return d_mmanager->getModel();
+}
+
+SharedSolver* CombinationEngine::getSharedSolver()
+{
+ return d_sharedSolver.get();
+}
+bool CombinationEngine::isProofEnabled() const { return d_cmbsPg != nullptr; }
+
+eq::EqualityEngineNotify* CombinationEngine::getModelEqualityEngineNotify()
+{
+ // by default, no notifications from model's equality engine
+ return nullptr;
+}
+
+void CombinationEngine::sendLemma(TrustNode trn, TheoryId atomsTo)
+{
+ d_te.lemma(trn, LemmaProperty::NONE, atomsTo);
+}
+
+void CombinationEngine::resetRound()
+{
+ // compute the relevant terms?
+}
+
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/combination_engine.h b/src/theory/combination_engine.h
new file mode 100644
index 000000000..4413da603
--- /dev/null
+++ b/src/theory/combination_engine.h
@@ -0,0 +1,145 @@
+/********************* */
+/*! \file combination_engine.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Abstract interface for theory combination.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__COMBINATION_ENGINE__H
+#define CVC4__THEORY__COMBINATION_ENGINE__H
+
+#include <vector>
+#include <memory>
+
+#include "theory/eager_proof_generator.h"
+#include "theory/ee_manager.h"
+#include "theory/model_manager.h"
+#include "theory/shared_solver.h"
+
+namespace CVC4 {
+
+class TheoryEngine;
+
+namespace theory {
+
+/**
+ * Manager for doing theory combination. This class is responsible for:
+ * (1) Initializing the various components of theory combination (equality
+ * engine manager, model manager, shared solver) based on the equality engine
+ * mode, and
+ * (2) Implementing the main combination method (combineTheories).
+ */
+class CombinationEngine
+{
+ public:
+ CombinationEngine(TheoryEngine& te,
+ const std::vector<Theory*>& paraTheories,
+ ProofNodeManager* pnm);
+ virtual ~CombinationEngine();
+
+ /** Finish initialization */
+ void finishInit();
+
+ //-------------------------- equality engine
+ /** Get equality engine theory information for theory with identifier tid. */
+ const EeTheoryInfo* getEeTheoryInfo(TheoryId tid) const;
+ /**
+ * Get the "core" equality engine. This is the equality engine that
+ * quantifiers should use.
+ */
+ eq::EqualityEngine* getCoreEqualityEngine();
+ //-------------------------- end equality engine
+ //-------------------------- model
+ /**
+ * Reset the model maintained by this class. This resets all local information
+ * that is unique to each check.
+ */
+ void resetModel();
+ /**
+ * Build the model maintained by this class.
+ *
+ * @return true if model building was successful.
+ */
+ virtual bool buildModel() = 0;
+ /**
+ * Post process the model maintained by this class. This is called after
+ * a successful call to buildModel. This does any theory-specific
+ * postprocessing of the model.
+ *
+ * @param incomplete Whether we are answering "unknown" instead of "sat".
+ */
+ void postProcessModel(bool incomplete);
+ /**
+ * Get the model object maintained by this class.
+ */
+ TheoryModel* getModel();
+ //-------------------------- end model
+ /**
+ * Get the shared solver, which is the active component of theory combination
+ * that TheoryEngine interacts with prior to calling combineTheories.
+ */
+ SharedSolver* getSharedSolver();
+ /**
+ * Called at the beginning of full effort
+ */
+ virtual void resetRound();
+ /**
+ * Combine theories, called after FULL effort passes with no lemmas
+ * and before LAST_CALL effort is run. This adds necessary lemmas for
+ * theory combination (e.g. splitting lemmas) to the parent TheoryEngine.
+ */
+ virtual void combineTheories() = 0;
+
+ protected:
+ /** Is proof enabled? */
+ bool isProofEnabled() const;
+ /**
+ * Get model equality engine notify. Return the notification object for
+ * who listens to the model's equality engine (if any).
+ */
+ virtual eq::EqualityEngineNotify* getModelEqualityEngineNotify();
+ /** Send lemma to the theory engine, atomsTo is the theory to send atoms to */
+ void sendLemma(TrustNode trn, TheoryId atomsTo);
+ /** Reference to the theory engine */
+ TheoryEngine& d_te;
+ /** The proof node manager */
+ ProofNodeManager* d_pnm;
+ /** Logic info of theory engine (cached) */
+ const LogicInfo& d_logicInfo;
+ /** List of parametric theories of theory engine */
+ const std::vector<Theory*> d_paraTheories;
+ /**
+ * The equality engine manager we are using. This class is responsible for
+ * configuring equality engines for each theory.
+ */
+ std::unique_ptr<EqEngineManager> d_eemanager;
+ /**
+ * The model manager we are using. This class is responsible for building the
+ * model.
+ */
+ std::unique_ptr<ModelManager> d_mmanager;
+ /**
+ * The shared solver. This class is responsible for performing combination
+ * tasks (e.g. preregistration) during solving.
+ */
+ std::unique_ptr<SharedSolver> d_sharedSolver;
+ /**
+ * An eager proof generator, if proofs are enabled. This proof generator is
+ * responsible for proofs of splitting lemmas generated in combineTheories.
+ */
+ std::unique_ptr<EagerProofGenerator> d_cmbsPg;
+};
+
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__COMBINATION_DISTRIBUTED__H */
diff --git a/src/theory/datatypes/datatypes_rewriter.cpp b/src/theory/datatypes/datatypes_rewriter.cpp
index 450a0fd37..747ed89b7 100644
--- a/src/theory/datatypes/datatypes_rewriter.cpp
+++ b/src/theory/datatypes/datatypes_rewriter.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -280,7 +280,7 @@ RewriteResponse DatatypesRewriter::preRewrite(TNode in)
const DTypeConstructor& dtc = utils::datatypeOf(op)[utils::indexOf(op)];
// create ascribed constructor type
Node tc = NodeManager::currentNM()->mkConst(
- AscriptionType(dtc.getSpecializedConstructorType(tn).toType()));
+ AscriptionType(dtc.getSpecializedConstructorType(tn)));
Node op_new = NodeManager::currentNM()->mkNode(
kind::APPLY_TYPE_ASCRIPTION, tc, op);
// make new node
@@ -390,41 +390,21 @@ RewriteResponse DatatypesRewriter::rewriteSelector(TNode in)
}
else if (k == kind::APPLY_SELECTOR_TOTAL)
{
- Node gt;
- bool useTe = true;
- // if( !tn.isSort() ){
- // useTe = false;
- //}
- if (tn.isDatatype())
+ // evaluates to the first ground value of type tn.
+ Node gt = tn.mkGroundValue();
+ Assert(!gt.isNull());
+ if (tn.isDatatype() && !tn.isInstantiatedDatatype())
{
- const DType& dta = tn.getDType();
- useTe = !dta.isCodatatype();
- }
- if (useTe)
- {
- TypeEnumerator te(tn);
- gt = *te;
- }
- else
- {
- gt = tn.mkGroundTerm();
- }
- if (!gt.isNull())
- {
- // Assert( gtt.isDatatype() || gtt.isParametricDatatype() );
- if (tn.isDatatype() && !tn.isInstantiatedDatatype())
- {
- gt = NodeManager::currentNM()->mkNode(
- kind::APPLY_TYPE_ASCRIPTION,
- NodeManager::currentNM()->mkConst(AscriptionType(tn.toType())),
- gt);
- }
- Trace("datatypes-rewrite") << "DatatypesRewriter::postRewrite: "
- << "Rewrite trivial selector " << in
- << " to distinguished ground term " << gt
- << std::endl;
- return RewriteResponse(REWRITE_DONE, gt);
+ gt = NodeManager::currentNM()->mkNode(
+ kind::APPLY_TYPE_ASCRIPTION,
+ NodeManager::currentNM()->mkConst(AscriptionType(tn)),
+ gt);
}
+ Trace("datatypes-rewrite")
+ << "DatatypesRewriter::postRewrite: "
+ << "Rewrite trivial selector " << in
+ << " to distinguished ground term " << gt << std::endl;
+ return RewriteResponse(REWRITE_DONE, gt);
}
}
return RewriteResponse(REWRITE_DONE, in);
diff --git a/src/theory/datatypes/datatypes_rewriter.h b/src/theory/datatypes/datatypes_rewriter.h
index 7f39a68ab..fe8859755 100644
--- a/src/theory/datatypes/datatypes_rewriter.h
+++ b/src/theory/datatypes/datatypes_rewriter.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/datatypes/infer_proof_cons.cpp b/src/theory/datatypes/infer_proof_cons.cpp
new file mode 100644
index 000000000..443218bf4
--- /dev/null
+++ b/src/theory/datatypes/infer_proof_cons.cpp
@@ -0,0 +1,275 @@
+/********************* */
+/*! \file infer_proof_cons.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of inference to proof conversion for datatypes
+ **/
+
+#include "theory/datatypes/infer_proof_cons.h"
+
+#include "theory/datatypes/theory_datatypes_utils.h"
+#include "theory/rewriter.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace datatypes {
+
+InferProofCons::InferProofCons(context::Context* c, ProofNodeManager* pnm)
+ : d_pnm(pnm), d_lazyFactMap(c == nullptr ? &d_context : c)
+{
+ Assert(d_pnm != nullptr);
+}
+
+void InferProofCons::notifyFact(const std::shared_ptr<DatatypesInference>& di)
+{
+ TNode fact = di->d_conc;
+ if (d_lazyFactMap.find(fact) != d_lazyFactMap.end())
+ {
+ return;
+ }
+ Node symFact = CDProof::getSymmFact(fact);
+ if (!symFact.isNull() && d_lazyFactMap.find(symFact) != d_lazyFactMap.end())
+ {
+ return;
+ }
+ d_lazyFactMap.insert(fact, di);
+}
+
+void InferProofCons::convert(InferId infer, TNode conc, TNode exp, CDProof* cdp)
+{
+ Trace("dt-ipc") << "convert: " << infer << ": " << conc << " by " << exp
+ << std::endl;
+ // split into vector
+ std::vector<Node> expv;
+ if (!exp.isNull() && !exp.isConst())
+ {
+ if (exp.getKind() == AND)
+ {
+ for (const Node& ec : exp)
+ {
+ expv.push_back(ec);
+ }
+ }
+ else
+ {
+ expv.push_back(exp);
+ }
+ }
+ NodeManager* nm = NodeManager::currentNM();
+ bool success = false;
+ switch (infer)
+ {
+ case InferId::UNIF:
+ {
+ Assert(expv.size() == 1);
+ Assert(exp.getKind() == EQUAL && exp[0].getKind() == APPLY_CONSTRUCTOR
+ && exp[1].getKind() == APPLY_CONSTRUCTOR
+ && exp[0].getOperator() == exp[1].getOperator());
+ Node narg;
+ // we may be asked for a proof of (not P) coming from (= P false) or
+ // (= false P), or similarly P from (= P true) or (= true P).
+ bool concPol = conc.getKind() != NOT;
+ Node concAtom = concPol ? conc : conc[0];
+ Node unifConc = conc;
+ for (size_t i = 0, nchild = exp[0].getNumChildren(); i < nchild; i++)
+ {
+ bool argSuccess = false;
+ if (conc.getKind() == EQUAL)
+ {
+ argSuccess = (exp[0][i] == conc[0] && exp[1][i] == conc[1]);
+ }
+ else
+ {
+ for (size_t j = 0; j < 2; j++)
+ {
+ if (exp[j][i] == concAtom && exp[1 - j][i].isConst()
+ && exp[1 - j][i].getConst<bool>() == concPol)
+ {
+ argSuccess = true;
+ unifConc = exp[0][i].eqNode(exp[1][i]);
+ break;
+ }
+ }
+ }
+ if (argSuccess)
+ {
+ narg = nm->mkConst(Rational(i));
+ break;
+ }
+ }
+ if (!narg.isNull())
+ {
+ if (conc.getKind() == EQUAL)
+ {
+ // normal case where we conclude an equality
+ cdp->addStep(conc, PfRule::DT_UNIF, {exp}, {narg});
+ }
+ else
+ {
+ // must use true or false elim to prove the final
+ cdp->addStep(unifConc, PfRule::DT_UNIF, {exp}, {narg});
+ // may use symmetry
+ Node eq = concAtom.eqNode(nm->mkConst(concPol));
+ cdp->addStep(
+ conc, concPol ? PfRule::TRUE_ELIM : PfRule::FALSE_ELIM, {eq}, {});
+ }
+ success = true;
+ }
+ }
+ break;
+ case InferId::INST:
+ {
+ if (expv.size() == 1)
+ {
+ Assert(conc.getKind() == EQUAL);
+ int n = utils::isTester(exp);
+ if (n >= 0)
+ {
+ Node t = exp[0];
+ Node nn = nm->mkConst(Rational(n));
+ Node eq = exp.eqNode(conc);
+ cdp->addStep(eq, PfRule::DT_INST, {}, {t, nn});
+ cdp->addStep(conc, PfRule::EQ_RESOLVE, {exp, eq}, {});
+ success = true;
+ }
+ }
+ }
+ break;
+ case InferId::SPLIT:
+ {
+ Assert(expv.empty());
+ Node t = conc.getKind() == OR ? conc[0][0] : conc[0];
+ cdp->addStep(conc, PfRule::DT_SPLIT, {}, {t});
+ success = true;
+ }
+ break;
+ case InferId::COLLAPSE_SEL:
+ {
+ Assert(exp.getKind() == EQUAL);
+ Node concEq = conc;
+ // might be a Boolean conclusion
+ if (conc.getKind() != EQUAL)
+ {
+ bool concPol = conc.getKind() != NOT;
+ Node concAtom = concPol ? conc : conc[0];
+ concEq = concAtom.eqNode(nm->mkConst(concPol));
+ }
+ Assert(concEq.getKind() == EQUAL
+ && concEq[0].getKind() == APPLY_SELECTOR_TOTAL);
+ Assert(exp[0].getType().isDatatype());
+ Node sop = concEq[0].getOperator();
+ Node sl = nm->mkNode(APPLY_SELECTOR_TOTAL, sop, exp[0]);
+ Node sr = nm->mkNode(APPLY_SELECTOR_TOTAL, sop, exp[1]);
+ // exp[0] = exp[1]
+ // --------------------- CONG ----------------- DT_COLLAPSE
+ // s(exp[0]) = s(exp[1]) s(exp[1]) = r
+ // --------------------------------------------------- TRANS
+ // s(exp[0]) = r
+ Node asn = ProofRuleChecker::mkKindNode(APPLY_SELECTOR_TOTAL);
+ Node seq = sl.eqNode(sr);
+ cdp->addStep(seq, PfRule::CONG, {exp}, {asn, sop});
+ Node sceq = sr.eqNode(concEq[1]);
+ cdp->addStep(sceq, PfRule::DT_COLLAPSE, {}, {sr});
+ cdp->addStep(sl.eqNode(concEq[1]), PfRule::TRANS, {seq, sceq}, {});
+ if (conc.getKind() != EQUAL)
+ {
+ PfRule eid =
+ conc.getKind() == NOT ? PfRule::FALSE_ELIM : PfRule::TRUE_ELIM;
+ cdp->addStep(conc, eid, {concEq}, {});
+ }
+ success = true;
+ }
+ break;
+ case InferId::CLASH_CONFLICT:
+ {
+ cdp->addStep(conc, PfRule::MACRO_SR_PRED_ELIM, {exp}, {});
+ success = true;
+ }
+ break;
+ case InferId::TESTER_CONFLICT:
+ {
+ // rewrites to false under substitution
+ Node fn = nm->mkConst(false);
+ cdp->addStep(fn, PfRule::MACRO_SR_PRED_ELIM, expv, {});
+ success = true;
+ }
+ break;
+ case InferId::TESTER_MERGE_CONFLICT:
+ {
+ Assert(expv.size() == 3);
+ Node tester1 = expv[0];
+ Node tester1c =
+ nm->mkNode(APPLY_TESTER, expv[1].getOperator(), expv[0][0]);
+ cdp->addStep(tester1c,
+ PfRule::MACRO_SR_PRED_TRANSFORM,
+ {expv[1], expv[2]},
+ {tester1c});
+ Node fn = nm->mkConst(false);
+ cdp->addStep(fn, PfRule::DT_CLASH, {tester1, tester1c}, {});
+ success = true;
+ }
+ break;
+ // inferences currently not supported
+ case InferId::LABEL_EXH:
+ case InferId::BISIMILAR:
+ case InferId::CYCLE:
+ default:
+ Trace("dt-ipc") << "...no conversion for inference " << infer
+ << std::endl;
+ break;
+ }
+
+ if (!success)
+ {
+ // failed to reconstruct, add trust
+ Trace("dt-ipc") << "...failed " << infer << std::endl;
+ cdp->addStep(conc, PfRule::DT_TRUST, expv, {conc});
+ }
+ else
+ {
+ Trace("dt-ipc") << "...success" << std::endl;
+ }
+}
+
+std::shared_ptr<ProofNode> InferProofCons::getProofFor(Node fact)
+{
+ Trace("dt-ipc") << "dt-ipc: Ask proof for " << fact << std::endl;
+ // temporary proof
+ CDProof pf(d_pnm);
+ // get the inference
+ NodeDatatypesInferenceMap::iterator it = d_lazyFactMap.find(fact);
+ if (it == d_lazyFactMap.end())
+ {
+ Node factSym = CDProof::getSymmFact(fact);
+ if (!factSym.isNull())
+ {
+ // Use the symmetric fact. There is no need to explictly make a
+ // SYMM proof, as this is handled by CDProof::getProofFor below.
+ it = d_lazyFactMap.find(factSym);
+ }
+ }
+ AlwaysAssert(it != d_lazyFactMap.end());
+ // now go back and convert it to proof steps and add to proof
+ std::shared_ptr<DatatypesInference> di = (*it).second;
+ // run the conversion
+ convert(di->getInferId(), di->d_conc, di->d_exp, &pf);
+ return pf.getProofFor(fact);
+}
+
+std::string InferProofCons::identify() const
+{
+ return "datatypes::InferProofCons";
+}
+
+} // namespace datatypes
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/datatypes/infer_proof_cons.h b/src/theory/datatypes/infer_proof_cons.h
new file mode 100644
index 000000000..34e042237
--- /dev/null
+++ b/src/theory/datatypes/infer_proof_cons.h
@@ -0,0 +1,99 @@
+/********************* */
+/*! \file infer_proof_cons.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Inference to proof conversion for datatypes
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__DATATYPES__INFER_PROOF_CONS_H
+#define CVC4__THEORY__DATATYPES__INFER_PROOF_CONS_H
+
+#include <vector>
+
+#include "expr/node.h"
+#include "expr/proof_generator.h"
+#include "theory/datatypes/inference.h"
+#include "theory/theory_proof_step_buffer.h"
+
+namespace CVC4 {
+namespace theory {
+namespace datatypes {
+
+/**
+ * Converts between the datatype-specific (untrustworthy) DatatypesInference
+ * class and information about how to construct a trustworthy proof step
+ * (PfRule, children, args). It acts as a (lazy) proof generator where the
+ * former is registered via notifyFact and the latter is asked for in
+ * getProofFor, typically by the proof equality engine.
+ *
+ * The main (private) method of this class is convert below, which is
+ * called when we need to construct a proof node from an InferInfo.
+ */
+class InferProofCons : public ProofGenerator
+{
+ typedef context::
+ CDHashMap<Node, std::shared_ptr<DatatypesInference>, NodeHashFunction>
+ NodeDatatypesInferenceMap;
+
+ public:
+ InferProofCons(context::Context* c, ProofNodeManager* pnm);
+ ~InferProofCons() {}
+ /**
+ * This is called to notify that di is an inference that may need a proof
+ * in the future.
+ *
+ * In detail, this class should be prepared to respond to a call to:
+ * getProofFor(di.d_conc)
+ * in the remainder of the SAT context. This method copies di and stores it
+ * in the context-dependent map d_lazyFactMap below.
+ *
+ * This is used for lazy proof construction, where proofs are constructed
+ * only for facts that are explained.
+ */
+ void notifyFact(const std::shared_ptr<DatatypesInference>& di);
+
+ /**
+ * This returns the proof for fact. This is required for using this class as
+ * a lazy proof generator.
+ *
+ * It should be the case that a call was made to notifyFact(di) where
+ * di.d_conc is fact in this SAT context.
+ */
+ std::shared_ptr<ProofNode> getProofFor(Node fact) override;
+ /** Identify this generator (for debugging, etc..) */
+ virtual std::string identify() const override;
+
+ private:
+ /** convert
+ *
+ * This method is called when the theory of strings makes an inference
+ * described by an InferInfo, whose fields are given by the first four
+ * arguments of this method.
+ *
+ * This method converts this call to instructions on what the proof rule
+ * step(s) are for concluding the conclusion of the inference. This
+ * information is stored in cdp.
+ */
+ void convert(InferId infer, TNode conc, TNode exp, CDProof* cdp);
+ /** A dummy context used by this class if none is provided */
+ context::Context d_context;
+ /** the proof node manager */
+ ProofNodeManager* d_pnm;
+ /** The lazy fact map */
+ NodeDatatypesInferenceMap d_lazyFactMap;
+};
+
+} // namespace datatypes
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__DATATYPES__INFER_PROOF_CONS_H */
diff --git a/src/theory/datatypes/inference.cpp b/src/theory/datatypes/inference.cpp
new file mode 100644
index 000000000..806dfd418
--- /dev/null
+++ b/src/theory/datatypes/inference.cpp
@@ -0,0 +1,105 @@
+/********************* */
+/*! \file inference.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Datatypes inference
+ **/
+
+#include "theory/datatypes/inference.h"
+
+#include "expr/dtype.h"
+#include "options/datatypes_options.h"
+#include "theory/datatypes/inference_manager.h"
+#include "theory/theory.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace datatypes {
+
+const char* toString(InferId i)
+{
+ switch (i)
+ {
+ case InferId::NONE: return "NONE";
+ case InferId::UNIF: return "UNIF";
+ case InferId::INST: return "INST";
+ case InferId::SPLIT: return "SPLIT";
+ case InferId::LABEL_EXH: return "LABEL_EXH";
+ case InferId::COLLAPSE_SEL: return "COLLAPSE_SEL";
+ case InferId::CLASH_CONFLICT: return "CLASH_CONFLICT";
+ case InferId::TESTER_CONFLICT: return "TESTER_CONFLICT";
+ case InferId::TESTER_MERGE_CONFLICT: return "TESTER_MERGE_CONFLICT";
+ case InferId::BISIMILAR: return "BISIMILAR";
+ case InferId::CYCLE: return "CYCLE";
+ default: return "?";
+ }
+}
+
+std::ostream& operator<<(std::ostream& out, InferId i)
+{
+ out << toString(i);
+ return out;
+}
+
+DatatypesInference::DatatypesInference(InferenceManager* im,
+ Node conc,
+ Node exp,
+ InferId i)
+ : SimpleTheoryInternalFact(conc, exp, nullptr), d_im(im), d_id(i)
+{
+ // false is not a valid explanation
+ Assert(d_exp.isNull() || !d_exp.isConst() || d_exp.getConst<bool>());
+}
+
+bool DatatypesInference::mustCommunicateFact(Node n, Node exp)
+{
+ Trace("dt-lemma-debug") << "Compute for " << exp << " => " << n << std::endl;
+ // Force lemmas if option is set
+ if (options::dtInferAsLemmas())
+ {
+ Trace("dt-lemma-debug")
+ << "Communicate " << n << " due to option" << std::endl;
+ return true;
+ }
+ // Note that equalities due to instantiate are forced as lemmas if
+ // necessary as they are created. This ensures that terms are shared with
+ // external theories when necessary. We send the lemma here only if the
+ // conclusion has kind LEQ (for datatypes size) or OR. Notice that
+ // all equalities are kept internal, apart from those forced as lemmas
+ // via instantiate.
+ else if (n.getKind() == LEQ || n.getKind() == OR)
+ {
+ Trace("dt-lemma-debug")
+ << "Communicate " << n << " due to kind" << std::endl;
+ return true;
+ }
+ Trace("dt-lemma-debug") << "Do not communicate " << n << std::endl;
+ return false;
+}
+
+bool DatatypesInference::process(TheoryInferenceManager* im, bool asLemma)
+{
+ // Check to see if we have to communicate it to the rest of the system.
+ // The flag asLemma is true when the inference was marked that it must be
+ // sent as a lemma in addPendingInference below.
+ if (asLemma || mustCommunicateFact(d_conc, d_exp))
+ {
+ return d_im->processDtLemma(d_conc, d_exp, d_id);
+ }
+ return d_im->processDtFact(d_conc, d_exp, d_id);
+}
+
+InferId DatatypesInference::getInferId() const { return d_id; }
+
+} // namespace datatypes
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/datatypes/inference.h b/src/theory/datatypes/inference.h
new file mode 100644
index 000000000..1cf135a7b
--- /dev/null
+++ b/src/theory/datatypes/inference.h
@@ -0,0 +1,123 @@
+/********************* */
+/*! \file inference.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Datatypes inference
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__DATATYPES__INFERENCE_H
+#define CVC4__THEORY__DATATYPES__INFERENCE_H
+
+#include "context/cdhashmap.h"
+#include "expr/node.h"
+#include "theory/inference_manager_buffered.h"
+
+namespace CVC4 {
+namespace theory {
+namespace datatypes {
+
+enum class InferId : uint32_t
+{
+ NONE,
+ // (= (C t1 ... tn) (C s1 .. sn)) => (= ti si)
+ UNIF,
+ // ((_ is Ci) t) => (= t (Ci (sel_1 t) ... (sel_n t)))
+ INST,
+ // (or ((_ is C1) t) V ... V ((_ is Cn) t))
+ SPLIT,
+ // (not ((_ is C1) t)) ^ ... [j] ... ^ (not ((_ is Cn) t)) => ((_ is Cj) t)
+ LABEL_EXH,
+ // (= t (Ci t1 ... tn)) => (= (sel_j t) rewrite((sel_j (Ci t1 ... tn))))
+ COLLAPSE_SEL,
+ // (= (Ci t1...tn) (Cj t1...tn)) => false
+ CLASH_CONFLICT,
+ // ((_ is Ci) t) ^ (= t (Cj t1 ... tn)) => false
+ TESTER_CONFLICT,
+ // ((_ is Ci) t) ^ ((_ is Cj) s) ^ (= t s) => false
+ TESTER_MERGE_CONFLICT,
+ // bisimilarity for codatatypes
+ BISIMILAR,
+ // cycle conflict for datatypes
+ CYCLE,
+};
+
+/**
+ * Converts an inference to a string. Note: This function is also used in
+ * `safe_print()`. Changing this functions name or signature will result in
+ * `safe_print()` printing "<unsupported>" instead of the proper strings for
+ * the enum values.
+ *
+ * @param i The inference
+ * @return The name of the inference
+ */
+const char* toString(InferId i);
+
+/**
+ * Writes an inference name to a stream.
+ *
+ * @param out The stream to write to
+ * @param i The inference to write to the stream
+ * @return The stream
+ */
+std::ostream& operator<<(std::ostream& out, InferId i);
+
+class InferenceManager;
+
+/**
+ * A custom inference class. The main feature of this class is that it
+ * dynamically decides whether to process itself as a fact or as a lemma,
+ * based on the mustCommunicateFact method below.
+ */
+class DatatypesInference : public SimpleTheoryInternalFact
+{
+ public:
+ DatatypesInference(InferenceManager* im,
+ Node conc,
+ Node exp,
+ InferId i = InferId::NONE);
+ /**
+ * Must communicate fact method.
+ * The datatypes decision procedure makes "internal" inferences :
+ * (1) Unification : C( t1...tn ) = C( s1...sn ) => ti = si
+ * (2) Label : ~is_C1(t) ... ~is_C{i-1}(t) ~is_C{i+1}(t) ... ~is_Cn(t) =>
+ * is_Ci( t )
+ * (3) Instantiate : is_C( t ) => t = C( sel_1( t ) ... sel_n( t ) )
+ * (4) collapse selector : S( C( t1...tn ) ) = t'
+ * (5) collapse term size : size( C( t1...tn ) ) = 1 + size( t1 ) + ... +
+ * size( tn )
+ * (6) non-negative size : 0 <= size(t)
+ * This method returns true if the fact must be sent out as a lemma. If it
+ * returns false, then we assert the fact internally. We return true for (6)
+ * and OR conclusions. We also return true if the option dtInferAsLemmas is
+ * set to true.
+ */
+ static bool mustCommunicateFact(Node n, Node exp);
+ /**
+ * Process this fact, possibly as a fact or as a lemma, depending on the
+ * above method.
+ */
+ bool process(TheoryInferenceManager* im, bool asLemma) override;
+ /** Get the inference identifier */
+ InferId getInferId() const;
+
+ private:
+ /** Pointer to the inference manager */
+ InferenceManager* d_im;
+ /** The inference */
+ InferId d_id;
+};
+
+} // namespace datatypes
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/datatypes/inference_manager.cpp b/src/theory/datatypes/inference_manager.cpp
new file mode 100644
index 000000000..f391cacd9
--- /dev/null
+++ b/src/theory/datatypes/inference_manager.cpp
@@ -0,0 +1,219 @@
+/********************* */
+/*! \file inference_manager.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Datatypes inference manager
+ **/
+
+#include "theory/datatypes/inference_manager.h"
+
+#include "expr/dtype.h"
+#include "options/datatypes_options.h"
+#include "smt/smt_statistics_registry.h"
+#include "theory/theory.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace datatypes {
+
+InferenceManager::InferenceManager(Theory& t,
+ TheoryState& state,
+ ProofNodeManager* pnm)
+ : InferenceManagerBuffered(t, state, pnm),
+ d_inferenceLemmas("theory::datatypes::inferenceLemmas"),
+ d_inferenceFacts("theory::datatypes::inferenceFacts"),
+ d_inferenceConflicts("theory::datatypes::inferenceConflicts"),
+ d_pnm(pnm),
+ d_ipc(pnm == nullptr ? nullptr
+ : new InferProofCons(state.getSatContext(), pnm)),
+ d_lemPg(pnm == nullptr
+ ? nullptr
+ : new EagerProofGenerator(
+ pnm, state.getUserContext(), "datatypes::lemPg"))
+{
+ d_false = NodeManager::currentNM()->mkConst(false);
+ smtStatisticsRegistry()->registerStat(&d_inferenceLemmas);
+ smtStatisticsRegistry()->registerStat(&d_inferenceFacts);
+ smtStatisticsRegistry()->registerStat(&d_inferenceConflicts);
+}
+
+InferenceManager::~InferenceManager()
+{
+ smtStatisticsRegistry()->unregisterStat(&d_inferenceLemmas);
+ smtStatisticsRegistry()->unregisterStat(&d_inferenceFacts);
+ smtStatisticsRegistry()->unregisterStat(&d_inferenceConflicts);
+}
+
+void InferenceManager::addPendingInference(Node conc,
+ Node exp,
+ bool forceLemma,
+ InferId i)
+{
+ if (forceLemma)
+ {
+ d_pendingLem.emplace_back(new DatatypesInference(this, conc, exp, i));
+ }
+ else
+ {
+ d_pendingFact.emplace_back(new DatatypesInference(this, conc, exp, i));
+ }
+}
+
+void InferenceManager::process()
+{
+ // process pending lemmas, used infrequently, only for definitional lemmas
+ doPendingLemmas();
+ // now process the pending facts
+ doPendingFacts();
+}
+
+void InferenceManager::sendDtLemma(Node lem,
+ InferId id,
+ LemmaProperty p,
+ bool doCache)
+{
+ if (isProofEnabled())
+ {
+ processDtLemma(lem, Node::null(), id);
+ return;
+ }
+ // otherwise send as a normal lemma
+ if (lemma(lem, p, doCache))
+ {
+ d_inferenceLemmas << id;
+ }
+}
+
+void InferenceManager::sendDtConflict(const std::vector<Node>& conf, InferId id)
+{
+ if (isProofEnabled())
+ {
+ Node exp = NodeManager::currentNM()->mkAnd(conf);
+ prepareDtInference(d_false, exp, id, d_ipc.get());
+ }
+ conflictExp(conf, d_ipc.get());
+ d_inferenceConflicts << id;
+}
+
+bool InferenceManager::sendLemmas(const std::vector<Node>& lemmas)
+{
+ bool ret = false;
+ for (const Node& lem : lemmas)
+ {
+ if (lemma(lem))
+ {
+ ret = true;
+ }
+ }
+ return ret;
+}
+
+bool InferenceManager::isProofEnabled() const { return d_ipc != nullptr; }
+
+bool InferenceManager::processDtLemma(
+ Node conc, Node exp, InferId id, LemmaProperty p, bool doCache)
+{
+ // set up a proof constructor
+ std::shared_ptr<InferProofCons> ipcl;
+ if (isProofEnabled())
+ {
+ ipcl = std::make_shared<InferProofCons>(nullptr, d_pnm);
+ }
+ conc = prepareDtInference(conc, exp, id, ipcl.get());
+ // send it as a lemma
+ Node lem;
+ if (!exp.isNull() && !exp.isConst())
+ {
+ lem = NodeManager::currentNM()->mkNode(kind::IMPLIES, exp, conc);
+ }
+ else
+ {
+ lem = conc;
+ }
+ if (isProofEnabled())
+ {
+ // store its proof
+ std::shared_ptr<ProofNode> pbody = ipcl->getProofFor(conc);
+ std::shared_ptr<ProofNode> pn = pbody;
+ if (!exp.isNull() && !exp.isConst())
+ {
+ std::vector<Node> expv;
+ expv.push_back(exp);
+ pn = d_pnm->mkScope(pbody, expv);
+ }
+ d_lemPg->setProofFor(lem, pn);
+ }
+ // use trusted lemma
+ TrustNode tlem = TrustNode::mkTrustLemma(lem, d_lemPg.get());
+ if (!trustedLemma(tlem))
+ {
+ Trace("dt-lemma-debug") << "...duplicate lemma" << std::endl;
+ return false;
+ }
+ d_inferenceLemmas << id;
+ return true;
+}
+
+bool InferenceManager::processDtFact(Node conc, Node exp, InferId id)
+{
+ conc = prepareDtInference(conc, exp, id, d_ipc.get());
+ // assert the internal fact, which has the same issue as above
+ bool polarity = conc.getKind() != NOT;
+ TNode atom = polarity ? conc : conc[0];
+ if (isProofEnabled())
+ {
+ std::vector<Node> expv;
+ if (!exp.isNull() && !exp.isConst())
+ {
+ expv.push_back(exp);
+ }
+ assertInternalFact(atom, polarity, expv, d_ipc.get());
+ }
+ else
+ {
+ // use version without proofs
+ assertInternalFact(atom, polarity, exp);
+ }
+ d_inferenceFacts << id;
+ return true;
+}
+
+Node InferenceManager::prepareDtInference(Node conc,
+ Node exp,
+ InferId id,
+ InferProofCons* ipc)
+{
+ Trace("dt-lemma-debug") << "prepareDtInference : " << conc << " via " << exp
+ << " by " << id << std::endl;
+ if (conc.getKind() == EQUAL && conc[0].getType().isBoolean())
+ {
+ // must turn (= conc false) into (not conc)
+ conc = Rewriter::rewrite(conc);
+ }
+ if (isProofEnabled())
+ {
+ Assert(ipc != nullptr);
+ // If proofs are enabled, notify the proof constructor.
+ // Notice that we have to reconstruct a datatypes inference here. This is
+ // because the inference in the pending vector may be destroyed as we are
+ // processing this inference, if we triggered to backtrack based on the
+ // call below, since it is a unique pointer.
+ std::shared_ptr<DatatypesInference> di =
+ std::make_shared<DatatypesInference>(this, conc, exp, id);
+ ipc->notifyFact(di);
+ }
+ return conc;
+}
+
+} // namespace datatypes
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/datatypes/inference_manager.h b/src/theory/datatypes/inference_manager.h
new file mode 100644
index 000000000..88b2befd7
--- /dev/null
+++ b/src/theory/datatypes/inference_manager.h
@@ -0,0 +1,131 @@
+/********************* */
+/*! \file inference_manager.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Datatypes inference manager
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__DATATYPES__INFERENCE_MANAGER_H
+#define CVC4__THEORY__DATATYPES__INFERENCE_MANAGER_H
+
+#include "context/cdhashmap.h"
+#include "expr/node.h"
+#include "theory/datatypes/infer_proof_cons.h"
+#include "theory/datatypes/inference.h"
+#include "theory/inference_manager_buffered.h"
+#include "util/statistics_registry.h"
+
+namespace CVC4 {
+namespace theory {
+namespace datatypes {
+
+/**
+ * The datatypes inference manager, which uses the above class for
+ * inferences.
+ */
+class InferenceManager : public InferenceManagerBuffered
+{
+ friend class DatatypesInference;
+
+ public:
+ InferenceManager(Theory& t, TheoryState& state, ProofNodeManager* pnm);
+ ~InferenceManager();
+ /**
+ * Add pending inference, which may be processed as either a fact or
+ * a lemma based on mustCommunicateFact in DatatypesInference above.
+ *
+ * @param conc The conclusion of the inference
+ * @param exp The explanation of the inference
+ * @param forceLemma Whether this inference *must* be processed as a lemma.
+ * Otherwise, it may be processed as a fact or lemma based on
+ * mustCommunicateFact.
+ * @param i The inference, used for stats and as a hint for constructing
+ * the proof of (conc => exp)
+ */
+ void addPendingInference(Node conc,
+ Node exp,
+ bool forceLemma = false,
+ InferId i = InferId::NONE);
+ /**
+ * Process the current lemmas and facts. This is a custom method that can
+ * be seen as overriding the behavior of calling both doPendingLemmas and
+ * doPendingFacts. It determines whether facts should be sent as lemmas
+ * or processed internally.
+ */
+ void process();
+ /**
+ * Send lemma immediately on the output channel
+ */
+ void sendDtLemma(Node lem,
+ InferId i = InferId::NONE,
+ LemmaProperty p = LemmaProperty::NONE,
+ bool doCache = true);
+ /**
+ * Send conflict immediately on the output channel
+ */
+ void sendDtConflict(const std::vector<Node>& conf, InferId i = InferId::NONE);
+ /**
+ * Send lemmas with property NONE on the output channel immediately.
+ * Returns true if any lemma was sent.
+ */
+ bool sendLemmas(const std::vector<Node>& lemmas);
+
+ private:
+ /** Are proofs enabled? */
+ bool isProofEnabled() const;
+ /**
+ * Process datatype inference as a lemma
+ */
+ bool processDtLemma(Node conc,
+ Node exp,
+ InferId id,
+ LemmaProperty p = LemmaProperty::NONE,
+ bool doCache = true);
+ /**
+ * Process datatype inference as a fact
+ */
+ bool processDtFact(Node conc, Node exp, InferId id);
+ /**
+ * Helper function for the above methods. Returns the conclusion, which
+ * may be modified so that it is compatible with proofs. If proofs are
+ * enabled, it ensures the proof constructor is ready to provide a proof
+ * of (=> exp conc).
+ *
+ * In particular, if conc is a Boolean equality, it is rewritten. This is
+ * to ensure that we do not assert equalities of the form (= t true)
+ * or (= t false) to the equality engine, which have a reserved internal
+ * status for proof generation. If this is not done, then it is possible
+ * to have proofs with missing connections and hence free assumptions.
+ */
+ Node prepareDtInference(Node conc, Node exp, InferId id, InferProofCons* ipc);
+ /** The false node */
+ Node d_false;
+ /**
+ * Counts the number of applications of each type of inference processed by
+ * the above method as facts, lemmas and conflicts.
+ */
+ HistogramStat<InferId> d_inferenceLemmas;
+ HistogramStat<InferId> d_inferenceFacts;
+ HistogramStat<InferId> d_inferenceConflicts;
+ /** Pointer to the proof node manager */
+ ProofNodeManager* d_pnm;
+ /** The inference to proof converter */
+ std::unique_ptr<InferProofCons> d_ipc;
+ /** An eager proof generator for lemmas */
+ std::unique_ptr<EagerProofGenerator> d_lemPg;
+};
+
+} // namespace datatypes
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/datatypes/kinds b/src/theory/datatypes/kinds
index e3c09b635..ef8dd47f1 100644
--- a/src/theory/datatypes/kinds
+++ b/src/theory/datatypes/kinds
@@ -7,7 +7,7 @@
theory THEORY_DATATYPES ::CVC4::theory::datatypes::TheoryDatatypes "theory/datatypes/theory_datatypes.h"
typechecker "theory/datatypes/theory_datatypes_type_rules.h"
-properties check presolve parametric propagate
+properties check parametric
rewriter ::CVC4::theory::datatypes::DatatypesRewriter "theory/datatypes/datatypes_rewriter.h"
@@ -41,15 +41,15 @@ parameterized APPLY_TESTER TESTER_TYPE 1 "tester application; first parameter is
constant DATATYPE_TYPE \
::CVC4::DatatypeIndexConstant \
"::CVC4::DatatypeIndexConstantHashFunction" \
- "expr/datatype.h" \
+ "expr/datatype_index.h" \
"a datatype type index"
cardinality DATATYPE_TYPE \
"%TYPE%.getDType().getCardinality(%TYPE%)" \
- "expr/datatype.h"
+ "expr/dtype.h"
well-founded DATATYPE_TYPE \
"%TYPE%.getDType().isWellFounded()" \
"%TYPE%.getDType().mkGroundTerm(%TYPE%)" \
- "expr/datatype.h"
+ "expr/dtype.h"
enumerator DATATYPE_TYPE \
"::CVC4::theory::datatypes::DatatypesEnumerator" \
@@ -58,11 +58,11 @@ enumerator DATATYPE_TYPE \
operator PARAMETRIC_DATATYPE 1: "parametric datatype"
cardinality PARAMETRIC_DATATYPE \
"%TYPE%.getDType().getCardinality(%TYPE%)" \
- "expr/datatype.h"
+ "expr/dtype.h"
well-founded PARAMETRIC_DATATYPE \
"%TYPE%.getDType().isWellFounded()" \
"%TYPE%.getDType().mkGroundTerm(%TYPE%)" \
- "expr/datatype.h"
+ "expr/dtype.h"
enumerator PARAMETRIC_DATATYPE \
"::CVC4::theory::datatypes::DatatypesEnumerator" \
diff --git a/src/theory/datatypes/proof_checker.cpp b/src/theory/datatypes/proof_checker.cpp
new file mode 100644
index 000000000..98060480b
--- /dev/null
+++ b/src/theory/datatypes/proof_checker.cpp
@@ -0,0 +1,135 @@
+/********************* */
+/*! \file proof_checker.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of datatypes proof checker
+ **/
+
+#include "theory/datatypes/proof_checker.h"
+
+#include "theory/datatypes/theory_datatypes_utils.h"
+#include "theory/rewriter.h"
+
+namespace CVC4 {
+namespace theory {
+namespace datatypes {
+
+void DatatypesProofRuleChecker::registerTo(ProofChecker* pc)
+{
+ pc->registerChecker(PfRule::DT_UNIF, this);
+ pc->registerChecker(PfRule::DT_INST, this);
+ pc->registerChecker(PfRule::DT_COLLAPSE, this);
+ pc->registerChecker(PfRule::DT_SPLIT, this);
+ pc->registerChecker(PfRule::DT_CLASH, this);
+ // trusted rules
+ pc->registerTrustedChecker(PfRule::DT_TRUST, this, 2);
+}
+
+Node DatatypesProofRuleChecker::checkInternal(PfRule id,
+ const std::vector<Node>& children,
+ const std::vector<Node>& args)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ if (id == PfRule::DT_UNIF)
+ {
+ Assert(children.size() == 1);
+ Assert(args.size() == 1);
+ uint32_t i;
+ if (children[0].getKind() != kind::EQUAL
+ || children[0][0].getKind() != kind::APPLY_CONSTRUCTOR
+ || children[0][1].getKind() != kind::APPLY_CONSTRUCTOR
+ || children[0][0].getOperator() != children[0][1].getOperator()
+ || !getUInt32(args[0], i))
+ {
+ return Node::null();
+ }
+ if (i >= children[0][0].getNumChildren())
+ {
+ return Node::null();
+ }
+ Assert(children[0][0].getNumChildren() == children[0][1].getNumChildren());
+ return children[0][0][i].eqNode(children[0][1][i]);
+ }
+ else if (id == PfRule::DT_INST)
+ {
+ Assert(children.empty());
+ Assert(args.size() == 2);
+ Node t = args[0];
+ TypeNode tn = t.getType();
+ uint32_t i;
+ if (!tn.isDatatype() || !getUInt32(args[1], i))
+ {
+ return Node::null();
+ }
+ const DType& dt = tn.getDType();
+ if (i >= dt.getNumConstructors())
+ {
+ return Node::null();
+ }
+ Node tester = utils::mkTester(t, i, dt);
+ Node ticons = Rewriter::rewrite(utils::getInstCons(t, dt, i));
+ return tester.eqNode(t.eqNode(ticons));
+ }
+ else if (id == PfRule::DT_COLLAPSE)
+ {
+ Assert(children.empty());
+ Assert(args.size() == 1);
+ Node t = args[0];
+ if (t.getKind() != kind::APPLY_SELECTOR_TOTAL
+ || t[0].getKind() != kind::APPLY_CONSTRUCTOR)
+ {
+ return Node::null();
+ }
+ Node selector = t.getOperator();
+ size_t constructorIndex = utils::indexOf(t[0].getOperator());
+ const DType& dt = utils::datatypeOf(selector);
+ const DTypeConstructor& dtc = dt[constructorIndex];
+ int selectorIndex = dtc.getSelectorIndexInternal(selector);
+ Node r =
+ selectorIndex < 0 ? t.getType().mkGroundTerm() : t[0][selectorIndex];
+ return t.eqNode(r);
+ }
+ else if (id == PfRule::DT_SPLIT)
+ {
+ Assert(children.empty());
+ Assert(args.size() == 1);
+ TypeNode tn = args[0].getType();
+ if (!tn.isDatatype())
+ {
+ return Node::null();
+ }
+ const DType& dt = tn.getDType();
+ return utils::mkSplit(args[0], dt);
+ }
+ else if (id == PfRule::DT_CLASH)
+ {
+ Assert(children.size() == 2);
+ Assert(args.empty());
+ if (children[0].getKind() != kind::APPLY_TESTER
+ || children[1].getKind() != kind::APPLY_TESTER
+ || children[0][0] != children[1][0] || children[0] == children[1])
+ {
+ return Node::null();
+ }
+ return nm->mkConst(false);
+ }
+ else if (id == PfRule::DT_TRUST)
+ {
+ Assert(!args.empty());
+ Assert(args[0].getType().isBoolean());
+ return args[0];
+ }
+ // no rule
+ return Node::null();
+}
+
+} // namespace datatypes
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/datatypes/proof_checker.h b/src/theory/datatypes/proof_checker.h
new file mode 100644
index 000000000..e5bd7cad5
--- /dev/null
+++ b/src/theory/datatypes/proof_checker.h
@@ -0,0 +1,49 @@
+/********************* */
+/*! \file proof_checker.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Datatypes proof checker utility
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__DATATYPES__PROOF_CHECKER_H
+#define CVC4__THEORY__DATATYPES__PROOF_CHECKER_H
+
+#include "expr/node.h"
+#include "expr/proof_checker.h"
+#include "expr/proof_node.h"
+
+namespace CVC4 {
+namespace theory {
+namespace datatypes {
+
+/** A checker for array reasoning in proofs */
+class DatatypesProofRuleChecker : public ProofRuleChecker
+{
+ public:
+ DatatypesProofRuleChecker() {}
+ ~DatatypesProofRuleChecker() {}
+
+ /** Register all rules owned by this rule checker into pc. */
+ void registerTo(ProofChecker* pc) override;
+
+ protected:
+ /** Return the conclusion of the given proof step, or null if it is invalid */
+ Node checkInternal(PfRule id,
+ const std::vector<Node>& children,
+ const std::vector<Node>& args) override;
+};
+
+} // namespace datatypes
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__DATATYPES__PROOF_CHECKER_H */
diff --git a/src/theory/datatypes/sygus_datatype_utils.cpp b/src/theory/datatypes/sygus_datatype_utils.cpp
index 8ff0f8db2..612722d48 100644
--- a/src/theory/datatypes/sygus_datatype_utils.cpp
+++ b/src/theory/datatypes/sygus_datatype_utils.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -335,6 +335,16 @@ struct SygusToBuiltinVarAttributeId
typedef expr::Attribute<SygusToBuiltinVarAttributeId, Node>
SygusToBuiltinVarAttribute;
+// A variant of the above attribute for cases where we introduce a fresh
+// variable. This is to support sygusToBuiltin on non-constant sygus terms,
+// where sygus variables should be mapped to canonical builtin variables.
+// It is important to cache this so that sygusToBuiltin is deterministic.
+struct BuiltinVarToSygusAttributeId
+{
+};
+typedef expr::Attribute<BuiltinVarToSygusAttributeId, Node>
+ BuiltinVarToSygusAttribute;
+
Node sygusToBuiltin(Node n, bool isExternal)
{
std::unordered_map<TNode, Node, TNodeHashFunction> visited;
@@ -388,6 +398,9 @@ Node sygusToBuiltin(Node n, bool isExternal)
SygusToBuiltinVarAttribute stbv;
cur.setAttribute(stbv, var);
visited[cur] = var;
+ // create backwards mapping
+ BuiltinVarToSygusAttribute bvtsa;
+ var.setAttribute(bvtsa, cur);
}
}
else
@@ -549,6 +562,16 @@ Node sygusToBuiltinEval(Node n, const std::vector<Node>& args)
return visited[n];
}
+Node builtinVarToSygus(Node v)
+{
+ BuiltinVarToSygusAttribute bvtsa;
+ if (v.hasAttribute(bvtsa))
+ {
+ return v.getAttribute(bvtsa);
+ }
+ return Node::null();
+}
+
void getFreeSymbolsSygusType(TypeNode sdt,
std::unordered_set<Node, NodeHashFunction>& syms)
{
@@ -625,7 +648,7 @@ TypeNode substituteAndGeneralizeSygusType(TypeNode sdt,
// must convert all constructors to version with variables in "vars"
std::vector<SygusDatatype> sdts;
- std::set<Type> unres;
+ std::set<TypeNode> unres;
Trace("dtsygus-gen-debug") << "Process sygus type:" << std::endl;
Trace("dtsygus-gen-debug") << sdtd.getName() << std::endl;
@@ -639,7 +662,7 @@ TypeNode substituteAndGeneralizeSygusType(TypeNode sdt,
ssutn0 << sdtd.getName() << "_s";
TypeNode abdTNew =
nm->mkSort(ssutn0.str(), ExprManager::SORT_FLAG_PLACEHOLDER);
- unres.insert(abdTNew.toType());
+ unres.insert(abdTNew);
dtProcessed[sdt] = abdTNew;
// We must convert all symbols in the sygus datatype type sdt to
@@ -683,7 +706,7 @@ TypeNode substituteAndGeneralizeSygusType(TypeNode sdt,
nm->mkSort(ssutn.str(), ExprManager::SORT_FLAG_PLACEHOLDER);
Trace("dtsygus-gen-debug") << " ...unresolved type " << argtNew
<< " for " << argt << std::endl;
- unres.insert(argtNew.toType());
+ unres.insert(argtNew);
dtProcessed[argt] = argtNew;
dtNextToProcess.push_back(argt);
}
@@ -713,22 +736,21 @@ TypeNode substituteAndGeneralizeSygusType(TypeNode sdt,
Trace("dtsygus-gen-debug")
<< "Make " << sdts.size() << " datatype types..." << std::endl;
// extract the datatypes
- std::vector<Datatype> datatypes;
+ std::vector<DType> datatypes;
for (unsigned i = 0, ndts = sdts.size(); i < ndts; i++)
{
datatypes.push_back(sdts[i].getDatatype());
}
// make the datatype types
- std::vector<DatatypeType> datatypeTypes =
- nm->toExprManager()->mkMutualDatatypeTypes(
- datatypes, unres, ExprManager::DATATYPE_FLAG_PLACEHOLDER);
- TypeNode sdtS = TypeNode::fromType(datatypeTypes[0]);
+ std::vector<TypeNode> datatypeTypes = nm->mkMutualDatatypeTypes(
+ datatypes, unres, NodeManager::DATATYPE_FLAG_PLACEHOLDER);
+ TypeNode sdtS = datatypeTypes[0];
if (Trace.isOn("dtsygus-gen-debug"))
{
Trace("dtsygus-gen-debug") << "Made datatype types:" << std::endl;
for (unsigned j = 0, ndts = datatypeTypes.size(); j < ndts; j++)
{
- const DType& dtj = TypeNode::fromType(datatypeTypes[j]).getDType();
+ const DType& dtj = datatypeTypes[j].getDType();
Trace("dtsygus-gen-debug") << "#" << j << ": " << dtj << std::endl;
for (unsigned k = 0, ncons = dtj.getNumConstructors(); k < ncons; k++)
{
diff --git a/src/theory/datatypes/sygus_datatype_utils.h b/src/theory/datatypes/sygus_datatype_utils.h
index 88ee6d33b..3f833702c 100644
--- a/src/theory/datatypes/sygus_datatype_utils.h
+++ b/src/theory/datatypes/sygus_datatype_utils.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -154,12 +154,21 @@ Node applySygusArgs(const DType& dt,
* that was provided. This includes the use of defined functions. This argument
* should typically be false, unless we are e.g. exporting the value of the
* term as a final solution.
- *
+ *
* If n is not constant, then its non-constant subterms that have sygus
* datatype types are replaced by fresh variables (of the same name, if that
* subterm is a variable, and having arbitrary name otherwise).
*/
Node sygusToBuiltin(Node n, bool isExternal = false);
+
+/**
+ * Builtin variable to sygus. Converts from builtin variables introduced by
+ * the method above to their source, which is a sygus variable. It should
+ * be the case that v is a variable introduced by the above method, or otherwise
+ * null is returned.
+ */
+Node builtinVarToSygus(Node v);
+
/** Sygus to builtin eval
*
* This method returns the rewritten form of (DT_SYGUS_EVAL n args). Notice that
diff --git a/src/theory/datatypes/sygus_extension.cpp b/src/theory/datatypes/sygus_extension.cpp
index 0c7954029..18b75e631 100644
--- a/src/theory/datatypes/sygus_extension.cpp
+++ b/src/theory/datatypes/sygus_extension.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/datatypes/sygus_extension.h b/src/theory/datatypes/sygus_extension.h
index 0c475a8e0..349ee07c9 100644
--- a/src/theory/datatypes/sygus_extension.h
+++ b/src/theory/datatypes/sygus_extension.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,7 +25,7 @@
#include "context/cdlist.h"
#include "context/cdo.h"
#include "context/context.h"
-#include "expr/datatype.h"
+#include "expr/dtype.h"
#include "expr/node.h"
#include "theory/datatypes/sygus_simple_sym.h"
#include "theory/quantifiers/sygus/sygus_explain.h"
diff --git a/src/theory/datatypes/sygus_simple_sym.cpp b/src/theory/datatypes/sygus_simple_sym.cpp
index d2fed715b..6b0063ce0 100644
--- a/src/theory/datatypes/sygus_simple_sym.cpp
+++ b/src/theory/datatypes/sygus_simple_sym.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/datatypes/sygus_simple_sym.h b/src/theory/datatypes/sygus_simple_sym.h
index 56fa39359..a16e7a513 100644
--- a/src/theory/datatypes/sygus_simple_sym.h
+++ b/src/theory/datatypes/sygus_simple_sym.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp
index 505d08c38..6bfe136ce 100644
--- a/src/theory/datatypes/theory_datatypes.cpp
+++ b/src/theory/datatypes/theory_datatypes.cpp
@@ -2,10 +2,10 @@
/*! \file theory_datatypes.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Morgan Deters, Mathias Preiner
+ ** Andrew Reynolds, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,7 +18,6 @@
#include <map>
#include "base/check.h"
-#include "expr/datatype.h"
#include "expr/dtype.h"
#include "expr/kind.h"
#include "options/datatypes_options.h"
@@ -48,34 +47,34 @@ TheoryDatatypes::TheoryDatatypes(Context* c,
const LogicInfo& logicInfo,
ProofNodeManager* pnm)
: Theory(THEORY_DATATYPES, c, u, out, valuation, logicInfo, pnm),
- d_infer(c),
- d_infer_exp(c),
d_term_sk(u),
- d_notify(*this),
- d_equalityEngine(d_notify, c, "theory::datatypes", true),
d_labels(c),
d_selector_apps(c),
- d_conflict(c, false),
- d_addedLemma(false),
- d_addedFact(false),
d_collectTermsCache(c),
d_collectTermsCacheU(u),
d_functionTerms(c),
d_singleton_eq(u),
d_lemmas_produced_c(u),
- d_sygusExtension(nullptr)
+ d_sygusExtension(nullptr),
+ d_state(c, u, valuation),
+ d_im(*this, d_state, pnm),
+ d_notify(d_im, *this)
{
- // The kinds we are treating as function application in congruence
- d_equalityEngine.addFunctionKind(kind::APPLY_CONSTRUCTOR);
- d_equalityEngine.addFunctionKind(kind::APPLY_SELECTOR_TOTAL);
- //d_equalityEngine.addFunctionKind(kind::DT_SIZE);
- //d_equalityEngine.addFunctionKind(kind::DT_HEIGHT_BOUND);
- d_equalityEngine.addFunctionKind(kind::APPLY_TESTER);
- //d_equalityEngine.addFunctionKind(kind::APPLY_UF);
d_true = NodeManager::currentNM()->mkConst( true );
d_zero = NodeManager::currentNM()->mkConst( Rational(0) );
d_dtfCounter = 0;
+
+ // indicate we are using the default theory state object
+ d_theoryState = &d_state;
+ d_inferManager = &d_im;
+
+ ProofChecker* pc = pnm != nullptr ? pnm->getChecker() : nullptr;
+ if (pc != nullptr)
+ {
+ // add checkers
+ d_pchecker.registerTo(pc);
+ }
}
TheoryDatatypes::~TheoryDatatypes() {
@@ -87,8 +86,34 @@ TheoryDatatypes::~TheoryDatatypes() {
}
}
-void TheoryDatatypes::setMasterEqualityEngine(eq::EqualityEngine* eq) {
- d_equalityEngine.setMasterEqualityEngine(eq);
+TheoryRewriter* TheoryDatatypes::getTheoryRewriter() { return &d_rewriter; }
+
+bool TheoryDatatypes::needsEqualityEngine(EeSetupInfo& esi)
+{
+ esi.d_notify = &d_notify;
+ esi.d_name = "theory::datatypes::ee";
+ return true;
+}
+
+void TheoryDatatypes::finishInit()
+{
+ Assert(d_equalityEngine != nullptr);
+ // The kinds we are treating as function application in congruence
+ d_equalityEngine->addFunctionKind(kind::APPLY_CONSTRUCTOR);
+ d_equalityEngine->addFunctionKind(kind::APPLY_SELECTOR_TOTAL);
+ d_equalityEngine->addFunctionKind(kind::APPLY_TESTER);
+ // We could but don't do congruence for DT_SIZE and DT_HEIGHT_BOUND here.
+ // It also could make sense in practice to do congruence for APPLY_UF, but
+ // this is not done.
+ if (getQuantifiersEngine() && options::sygus())
+ {
+ d_sygusExtension.reset(
+ new SygusExtension(this, getQuantifiersEngine(), getSatContext()));
+ // do congruence on evaluation functions
+ d_equalityEngine->addFunctionKind(kind::DT_SYGUS_EVAL);
+ }
+ // testers are not relevant for model building
+ d_valuation.setIrrelevantKind(APPLY_TESTER);
}
TheoryDatatypes::EqcInfo* TheoryDatatypes::getOrMakeEqcInfo( TNode n, bool doMake ){
@@ -135,66 +160,49 @@ TNode TheoryDatatypes::getEqcConstructor( TNode r ) {
}
}
-void TheoryDatatypes::check(Effort e) {
- if (done() && e<EFFORT_FULL) {
- return;
- }
- Assert(d_pending.empty() && d_pending_merge.empty());
- d_addedLemma = false;
-
- if( e == EFFORT_LAST_CALL ){
+bool TheoryDatatypes::preCheck(Effort level)
+{
+ d_im.reset();
+ d_im.clearPending();
+ return false;
+}
+
+void TheoryDatatypes::postCheck(Effort level)
+{
+ // Apply any last pending inferences, which may occur if the last processed
+ // fact was an internal one and triggered further internal inferences.
+ d_im.process();
+ if (level == EFFORT_LAST_CALL)
+ {
Assert(d_sygusExtension != nullptr);
- std::vector< Node > lemmas;
+ std::vector<Node> lemmas;
d_sygusExtension->check(lemmas);
- doSendLemmas( lemmas );
+ d_im.sendLemmas(lemmas);
return;
}
-
- TimerStat::CodeTimer checkTimer(d_checkTime);
-
- Trace("datatypes-check") << "Check effort " << e << std::endl;
- while(!done() && !d_conflict) {
- // Get all the assertions
- Assertion assertion = get();
- TNode fact = assertion.d_assertion;
- Trace("datatypes-assert") << "Assert " << fact << std::endl;
-
- TNode atom CVC4_UNUSED = fact.getKind() == kind::NOT ? fact[0] : fact;
-
- // extra debug check to make sure that the rewriter did its job correctly
- Assert(atom.getKind() != kind::EQUAL
- || (atom[0].getKind() != kind::TUPLE_UPDATE
- && atom[1].getKind() != kind::TUPLE_UPDATE
- && atom[0].getKind() != kind::RECORD_UPDATE
- && atom[1].getKind() != kind::RECORD_UPDATE))
- << "tuple/record escaped into datatypes decision procedure; should "
- "have been rewritten away";
-
- //assert the fact
- assertFact( fact, fact );
- flushPendingFacts();
- }
-
- if( e == EFFORT_FULL && !d_conflict && !d_addedLemma && !d_valuation.needCheck() ) {
+ else if (level == EFFORT_FULL && !d_state.isInConflict()
+ && !d_im.hasSentLemma() && !d_valuation.needCheck())
+ {
//check for cycles
- Assert(d_pending.empty() && d_pending_merge.empty());
+ Assert(!d_im.hasPendingFact());
do {
- d_addedFact = false;
+ d_im.reset();
Trace("datatypes-proc") << "Check cycles..." << std::endl;
checkCycles();
Trace("datatypes-proc") << "...finish check cycles" << std::endl;
- flushPendingFacts();
- if( d_conflict || d_addedLemma ){
+ d_im.process();
+ if (d_state.isInConflict() || d_im.hasSentLemma())
+ {
return;
}
- }while( d_addedFact );
-
+ } while (d_im.hasSentFact());
+
//check for splits
- Trace("datatypes-debug") << "Check for splits " << e << endl;
+ Trace("datatypes-debug") << "Check for splits " << endl;
do {
- d_addedFact = false;
+ d_im.reset();
std::map< TypeNode, Node > rec_singletons;
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(d_equalityEngine);
while( !eqcs_i.isFinished() ){
Node n = (*eqcs_i);
//TODO : avoid irrelevant (pre-registered but not asserted) terms here?
@@ -244,7 +252,7 @@ void TheoryDatatypes::check(Effort e) {
assumptions.push_back(assumption);
Node lemma = assumptions.size()==1 ? assumptions[0] : NodeManager::currentNM()->mkNode( OR, assumptions );
Trace("dt-singleton") << "*************Singleton equality lemma " << lemma << std::endl;
- doSendLemma( lemma );
+ d_im.lemma(lemma);
}
}
}else{
@@ -258,8 +266,6 @@ void TheoryDatatypes::check(Effort e) {
//all other cases
std::vector< bool > pcons;
getPossibleCons( eqc, n, pcons );
- //std::map< int, bool > sel_apps;
- //getSelectorsForCons( n, sel_apps );
//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, and its possible values are infinite,
// then do not split.
@@ -301,10 +307,8 @@ void TheoryDatatypes::check(Effort e) {
//this may not be necessary?
//if only one constructor, then this term must be this constructor
Node t = utils::mkTester(n, 0, dt);
- d_pending.push_back( t );
- d_pending_exp[ t ] = d_true;
+ d_im.addPendingInference(t, d_true, false, InferId::SPLIT);
Trace("datatypes-infer") << "DtInfer : 1-cons (full) : " << t << std::endl;
- d_infer.push_back( t );
}else{
Assert(consIndex != -1 || dt.isSygus());
if( options::dtBinarySplit() && consIndex!=-1 ){
@@ -314,14 +318,16 @@ void TheoryDatatypes::check(Effort e) {
NodeBuilder<> nb(kind::OR);
nb << test << test.notNode();
Node lemma = nb;
- doSendLemma( lemma );
+ d_im.lemma(lemma);
d_out->requirePhase( test, true );
}else{
Trace("dt-split") << "*************Split for constructors on " << n << endl;
Node lemma = utils::mkSplit(n, dt);
Trace("dt-split-debug") << "Split lemma is : " << lemma << std::endl;
- d_out->lemma( lemma, false, false, true );
- d_addedLemma = true;
+ d_im.sendDtLemma(lemma,
+ InferId::SPLIT,
+ LemmaProperty::SEND_ATOMS,
+ false);
}
if( !options::dtBlastSplits() ){
break;
@@ -337,41 +343,32 @@ void TheoryDatatypes::check(Effort e) {
}
++eqcs_i;
}
- if (d_addedLemma)
+ if (d_im.hasSentLemma())
{
// clear pending facts: we added a lemma, so internal inferences are
// no longer necessary
- d_pending.clear();
- d_pending_exp.clear();
+ d_im.clearPendingFacts();
}
else
{
// we did not add a lemma, process internal inferences. This loop
// will repeat.
Trace("datatypes-debug") << "Flush pending facts..." << std::endl;
- flushPendingFacts();
+ d_im.process();
}
- /*
- 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 && !d_addedLemma && d_addedFact );
- Trace("datatypes-debug") << "Finished, conflict=" << d_conflict << ", lemmas=" << d_addedLemma << std::endl;
- if( !d_conflict ){
+ } while (!d_state.isInConflict() && !d_im.hasSentLemma()
+ && d_im.hasSentFact());
+ Trace("datatypes-debug")
+ << "Finished, conflict=" << d_state.isInConflict()
+ << ", lemmas=" << d_im.hasSentLemma() << std::endl;
+ if (!d_state.isInConflict())
+ {
Trace("dt-model-debug") << std::endl;
printModelDebug("dt-model-debug");
}
}
- Trace("datatypes-check") << "Finished check effort " << e << std::endl;
+ Trace("datatypes-check") << "Finished check effort " << level << std::endl;
if( Debug.isOn("datatypes") || Debug.isOn("datatypes-split") ) {
Notice() << "TheoryDatatypes::check(): done" << endl;
}
@@ -381,116 +378,19 @@ bool TheoryDatatypes::needsCheckLastEffort() {
return d_sygusExtension != nullptr;
}
-void TheoryDatatypes::flushPendingFacts(){
- doPendingMerges();
- //pending lemmas: used infrequently, only for definitional lemmas
- if( !d_pending_lem.empty() ){
- int i = 0;
- while( i<(int)d_pending_lem.size() ){
- doSendLemma( d_pending_lem[i] );
- i++;
- }
- d_pending_lem.clear();
- doPendingMerges();
- }
- int i = 0;
- while( !d_conflict && i<(int)d_pending.size() ){
- Node fact = d_pending[i];
- Node exp = d_pending_exp[ fact ];
- Trace("datatypes-debug") << "Assert fact (#" << (i+1) << "/" << d_pending.size() << ") " << fact << " with explanation " << exp << std::endl;
- //check to see if we have to communicate it to the rest of the system
- if( mustCommunicateFact( fact, exp ) ){
- Node lem = fact;
- if( exp.isNull() || exp==d_true ){
- Trace("dt-lemma-debug") << "Trivial explanation." << std::endl;
- }else{
- Trace("dt-lemma-debug") << "Get explanation..." << std::endl;
- std::vector< TNode > assumptions;
- //if( options::dtRExplainLemmas() ){
- explain( exp, assumptions );
- //}else{
- // ee_exp = exp;
- //}
- //Trace("dt-lemma-debug") << "Explanation : " << ee_exp << std::endl;
- if( assumptions.empty() ){
- lem = fact;
- }else{
- std::vector< Node > children;
- for (const TNode& assumption : assumptions)
- {
- children.push_back(assumption.negate());
- }
- children.push_back( fact );
- lem = NodeManager::currentNM()->mkNode( OR, children );
- }
- }
- Trace("dt-lemma") << "Datatypes lemma : " << lem << std::endl;
- doSendLemma( lem );
- }else{
- assertFact( fact, exp );
- d_addedFact = true;
- }
- Trace("datatypes-debug") << "Finished fact " << fact << ", now = " << d_conflict << " " << d_pending.size() << std::endl;
- i++;
- }
- d_pending.clear();
- d_pending_exp.clear();
-}
-
-void TheoryDatatypes::doPendingMerges(){
- if( !d_conflict ){
- //do all pending merges
- int i=0;
- while( i<(int)d_pending_merge.size() ){
- Assert(d_pending_merge[i].getKind() == EQUAL);
- merge( d_pending_merge[i][0], d_pending_merge[i][1] );
- i++;
- }
- }
- d_pending_merge.clear();
-}
-
-bool TheoryDatatypes::doSendLemma( Node lem ) {
- if( d_lemmas_produced_c.find( lem )==d_lemmas_produced_c.end() ){
- Trace("dt-lemma-send") << "TheoryDatatypes::doSendLemma : " << lem << std::endl;
- d_lemmas_produced_c[lem] = true;
- d_out->lemma( lem );
- d_addedLemma = true;
- return true;
- }else{
- Trace("dt-lemma-send") << "TheoryDatatypes::doSendLemma : duplicate : "
- << lem << std::endl;
- return false;
- }
-}
-bool TheoryDatatypes::doSendLemmas( std::vector< Node >& lemmas ){
- bool ret = false;
- for (const Node& lem : lemmas)
- {
- bool cret = doSendLemma(lem);
- ret = ret || cret;
- }
- lemmas.clear();
- return ret;
-}
-
-void TheoryDatatypes::assertFact( Node fact, Node exp ){
- Assert(d_pending_merge.empty());
- Trace("datatypes-debug") << "TheoryDatatypes::assertFact : " << fact << std::endl;
- bool polarity = fact.getKind() != kind::NOT;
- TNode atom = polarity ? fact : fact[0];
- if (atom.getKind() == kind::EQUAL) {
- d_equalityEngine.assertEquality( atom, polarity, exp );
- }else{
- d_equalityEngine.assertPredicate( atom, polarity, exp );
- }
- doPendingMerges();
+void TheoryDatatypes::notifyFact(TNode atom,
+ bool polarity,
+ TNode fact,
+ bool isInternal)
+{
+ Trace("datatypes-debug") << "TheoryDatatypes::assertFact : " << fact
+ << ", isInternal = " << isInternal << std::endl;
// could be sygus-specific
if (d_sygusExtension)
{
std::vector< Node > lemmas;
d_sygusExtension->assertFact(atom, polarity, lemmas);
- doSendLemmas( lemmas );
+ d_im.sendLemmas(lemmas);
}
//add to tester if applicable
Node t_arg;
@@ -500,80 +400,51 @@ void TheoryDatatypes::assertFact( Node fact, Node exp ){
Trace("dt-tester") << "Assert tester : " << atom << " for " << t_arg << std::endl;
Node rep = getRepresentative( t_arg );
EqcInfo* eqc = getOrMakeEqcInfo( rep, true );
- addTester( tindex, fact, eqc, rep, t_arg );
+ Node tst =
+ isInternal ? (polarity ? Node(atom) : atom.notNode()) : Node(fact);
+ addTester(tindex, tst, eqc, rep, t_arg);
Trace("dt-tester") << "Done assert tester." << std::endl;
- //do pending merges
- doPendingMerges();
Trace("dt-tester") << "Done pending merges." << std::endl;
- if( !d_conflict && polarity ){
+ if (!d_state.isInConflict() && polarity)
+ {
if (d_sygusExtension)
{
Trace("dt-tester") << "Assert tester to sygus : " << atom << std::endl;
- //Assert( !d_sygus_util->d_conflict );
std::vector< Node > lemmas;
d_sygusExtension->assertTester(tindex, t_arg, atom, lemmas);
Trace("dt-tester") << "Done assert tester to sygus." << std::endl;
- doSendLemmas( lemmas );
+ d_im.sendLemmas(lemmas);
}
}
}else{
Trace("dt-tester-debug") << "Assert (non-tester) : " << atom << std::endl;
}
Trace("datatypes-debug") << "TheoryDatatypes::assertFact : finished " << fact << std::endl;
-}
-
-void TheoryDatatypes::preRegisterTerm(TNode n) {
- Debug("datatypes-prereg") << "TheoryDatatypes::preRegisterTerm() " << n << endl;
- collectTerms( n );
- switch (n.getKind()) {
- case kind::EQUAL:
- // Add the trigger for equality
- d_equalityEngine.addTriggerEquality(n);
- break;
- case kind::APPLY_TESTER:
- // Get triggered for both equal and dis-equal
- d_equalityEngine.addTriggerPredicate(n);
- break;
- default:
- // Function applications/predicates
- d_equalityEngine.addTerm(n);
- if (d_sygusExtension)
- {
- std::vector< Node > lemmas;
- d_sygusExtension->preRegisterTerm(n, lemmas);
- doSendLemmas( lemmas );
- }
- //d_equalityEngine.addTriggerTerm(n, THEORY_DATATYPES);
- break;
- }
- flushPendingFacts();
-}
-
-void TheoryDatatypes::finishInit() {
- if (getQuantifiersEngine() && options::sygus())
+ // now, flush pending facts if this wasn't an internal call
+ if (!isInternal)
{
- d_sygusExtension.reset(
- new SygusExtension(this, getQuantifiersEngine(), getSatContext()));
- // do congruence on evaluation functions
- d_equalityEngine.addFunctionKind(kind::DT_SYGUS_EVAL);
+ d_im.process();
}
}
-TrustNode TheoryDatatypes::expandDefinition(Node n)
+void TheoryDatatypes::preRegisterTerm(TNode n)
{
- NodeManager* nm = NodeManager::currentNM();
+ Trace("datatypes-prereg")
+ << "TheoryDatatypes::preRegisterTerm() " << n << endl;
// must ensure the type is well founded and has no nested recursion if
// the option dtNestedRec is not set to true.
TypeNode tn = n.getType();
if (tn.isDatatype())
{
const DType& dt = tn.getDType();
+ Trace("dt-expand") << "Check properties of " << dt.getName() << std::endl;
if (!dt.isWellFounded())
{
std::stringstream ss;
ss << "Cannot handle non-well-founded datatype " << dt.getName();
throw LogicException(ss.str());
}
+ Trace("dt-expand") << "...well-founded ok" << std::endl;
if (!options::dtNestedRec())
{
if (dt.hasNestedRecursion())
@@ -582,8 +453,35 @@ TrustNode TheoryDatatypes::expandDefinition(Node n)
ss << "Cannot handle nested-recursive datatype " << dt.getName();
throw LogicException(ss.str());
}
+ Trace("dt-expand") << "...nested recursion ok" << std::endl;
+ }
+ }
+ collectTerms( n );
+ switch (n.getKind()) {
+ case kind::EQUAL:
+ case kind::APPLY_TESTER:
+ // add predicate trigger for testers and equalities
+ // Get triggered for both equal and dis-equal
+ d_equalityEngine->addTriggerPredicate(n);
+ break;
+ default:
+ // Function applications/predicates
+ d_equalityEngine->addTerm(n);
+ if (d_sygusExtension)
+ {
+ std::vector< Node > lemmas;
+ d_sygusExtension->preRegisterTerm(n, lemmas);
+ d_im.sendLemmas(lemmas);
}
+ break;
}
+ d_im.process();
+}
+
+TrustNode TheoryDatatypes::expandDefinition(Node n)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ TypeNode tn = n.getType();
Node ret;
switch (n.getKind())
{
@@ -654,10 +552,11 @@ TrustNode TheoryDatatypes::expandDefinition(Node n)
}
else
{
- Assert(tn.toType().isRecord());
- const Record& record = DatatypeType(tn.toType()).getRecord();
- size = record.getNumFields();
- updateIndex = record.getIndex(
+ Assert(tn.isRecord());
+ const DTypeConstructor& recCons = dt[0];
+ size = recCons.getNumArgs();
+ // get the index for the name
+ updateIndex = recCons.getSelectorIndexForName(
n.getOperator().getConst<RecordUpdate>().getField());
}
Debug("tuprec") << "expr is " << n << std::endl;
@@ -693,11 +592,6 @@ TrustNode TheoryDatatypes::expandDefinition(Node n)
return TrustNode::null();
}
-void TheoryDatatypes::presolve()
-{
- Debug("datatypes") << "TheoryDatatypes::presolve()" << endl;
-}
-
TrustNode TheoryDatatypes::ppRewrite(TNode in)
{
Debug("tuprec") << "TheoryDatatypes::ppRewrite(" << in << ")" << endl;
@@ -724,114 +618,9 @@ TrustNode TheoryDatatypes::ppRewrite(TNode in)
return TrustNode::null();
}
-void TheoryDatatypes::addSharedTerm(TNode t) {
- Debug("datatypes") << "TheoryDatatypes::addSharedTerm(): "
- << t << " " << t.getType().isBoolean() << endl;
- d_equalityEngine.addTriggerTerm(t, THEORY_DATATYPES);
- Debug("datatypes") << "TheoryDatatypes::addSharedTerm() finished" << std::endl;
-}
-
-/** propagate */
-void TheoryDatatypes::propagate(Effort effort){
-
-}
-
-/** propagate */
-bool TheoryDatatypes::propagate(TNode literal){
- Debug("dt::propagate") << "TheoryDatatypes::propagate(" << literal << ")" << std::endl;
- // If already in conflict, no more propagation
- if (d_conflict) {
- Debug("dt::propagate") << "TheoryDatatypes::propagate(" << literal << "): already in conflict" << std::endl;
- return false;
- }
- Trace("dt-prop") << "dtPropagate " << literal << std::endl;
- // Propagate out
- bool ok = d_out->propagate(literal);
- if (!ok) {
- Trace("dt-conflict") << "CONFLICT: Eq engine propagate conflict " << std::endl;
- d_conflict = true;
- }
- return ok;
-}
-
-void TheoryDatatypes::addAssumptions( std::vector<TNode>& assumptions, std::vector<TNode>& tassumptions ) {
- std::vector<TNode> ntassumptions;
- for( unsigned i=0; i<tassumptions.size(); i++ ){
- //flatten AND
- if( tassumptions[i].getKind()==AND ){
- for( unsigned j=0; j<tassumptions[i].getNumChildren(); j++ ){
- explain( tassumptions[i][j], ntassumptions );
- }
- }else{
- if( std::find( assumptions.begin(), assumptions.end(), tassumptions[i] )==assumptions.end() ){
- assumptions.push_back( tassumptions[i] );
- }
- }
- }
- if( !ntassumptions.empty() ){
- addAssumptions( assumptions, ntassumptions );
- }
-}
-
-void TheoryDatatypes::explainEquality( TNode a, TNode b, bool polarity, std::vector<TNode>& assumptions ) {
- if( a!=b ){
- std::vector<TNode> tassumptions;
- d_equalityEngine.explainEquality(a, b, polarity, tassumptions);
- addAssumptions( assumptions, tassumptions );
- }
-}
-
-void TheoryDatatypes::explainPredicate( TNode p, bool polarity, std::vector<TNode>& assumptions ) {
- std::vector<TNode> tassumptions;
- d_equalityEngine.explainPredicate(p, polarity, tassumptions);
- addAssumptions( assumptions, tassumptions );
-}
-
-/** explain */
-void TheoryDatatypes::explain(TNode literal, std::vector<TNode>& assumptions){
- Debug("datatypes-explain") << "Explain " << literal << std::endl;
- bool polarity = literal.getKind() != kind::NOT;
- TNode atom = polarity ? literal : literal[0];
- if (atom.getKind() == kind::EQUAL) {
- explainEquality( atom[0], atom[1], polarity, assumptions );
- } else if( atom.getKind() == kind::AND && polarity ){
- for( unsigned i=0; i<atom.getNumChildren(); i++ ){
- explain( atom[i], assumptions );
- }
- } else {
- Assert(atom.getKind() != kind::AND);
- explainPredicate( atom, polarity, assumptions );
- }
-}
-
TrustNode TheoryDatatypes::explain(TNode literal)
{
- Node exp = explainLit(literal);
- return TrustNode::mkTrustPropExp(literal, exp, nullptr);
-}
-
-Node TheoryDatatypes::explainLit(TNode literal)
-{
- std::vector< TNode > assumptions;
- explain( literal, assumptions );
- return mkAnd( assumptions );
-}
-
-Node TheoryDatatypes::explain( std::vector< Node >& lits ) {
- std::vector< TNode > assumptions;
- for( unsigned i=0; i<lits.size(); i++ ){
- explain( lits[i], assumptions );
- }
- return mkAnd( assumptions );
-}
-
-/** Conflict when merging two constants */
-void TheoryDatatypes::conflict(TNode a, TNode b){
- Node eq = a.eqNode(b);
- d_conflictNode = explainLit(eq);
- Trace("dt-conflict") << "CONFLICT: Eq engine conflict : " << d_conflictNode << std::endl;
- d_out->conflict( d_conflictNode );
- d_conflict = true;
+ return d_im.explainLit(literal);
}
/** called when a new equivalance class is created */
@@ -841,21 +630,19 @@ void TheoryDatatypes::eqNotifyNewClass(TNode t){
}
}
-/** called when two equivalance classes will merge */
-void TheoryDatatypes::eqNotifyPreMerge(TNode t1, TNode t2){
-
-}
-
/** called when two equivalance classes have merged */
-void TheoryDatatypes::eqNotifyPostMerge(TNode t1, TNode t2){
+void TheoryDatatypes::eqNotifyMerge(TNode t1, TNode t2)
+{
if( t1.getType().isDatatype() ){
- Trace("datatypes-debug") << "NotifyPostMerge : " << t1 << " " << t2 << std::endl;
- d_pending_merge.push_back( t1.eqNode( t2 ) );
+ Trace("datatypes-debug")
+ << "NotifyMerge : " << t1 << " " << t2 << std::endl;
+ merge(t1,t2);
}
}
void TheoryDatatypes::merge( Node t1, Node t2 ){
- if( !d_conflict ){
+ if (!d_state.isInConflict())
+ {
TNode trep1 = t1;
TNode trep2 = t2;
Trace("datatypes-debug") << "Merge " << t1 << " " << t2 << std::endl;
@@ -881,10 +668,11 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){
std::vector< Node > rew;
if (utils::checkClash(cons1, cons2, rew))
{
- d_conflictNode = explainLit(unifEq);
- Trace("dt-conflict") << "CONFLICT: Clash conflict : " << d_conflictNode << std::endl;
- d_out->conflict( d_conflictNode );
- d_conflict = true;
+ std::vector<Node> conf;
+ conf.push_back(unifEq);
+ Trace("dt-conflict")
+ << "CONFLICT: Clash conflict : " << conf << std::endl;
+ d_im.sendDtConflict(conf, InferId::CLASH_CONFLICT);
return;
}
else
@@ -893,22 +681,10 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){
for( int i=0; i<(int)cons1.getNumChildren(); i++ ) {
if( !areEqual( cons1[i], cons2[i] ) ){
Node eq = cons1[i].eqNode( cons2[i] );
- d_pending.push_back( eq );
- d_pending_exp[ eq ] = unifEq;
+ d_im.addPendingInference(eq, unifEq, false, InferId::UNIF);
Trace("datatypes-infer") << "DtInfer : cons-inj : " << eq << " by " << unifEq << std::endl;
- d_infer.push_back( eq );
- d_infer_exp.push_back( unifEq );
}
}
-/*
- for( unsigned i=0; i<rew.size(); i++ ){
- d_pending.push_back( rew[i] );
- d_pending_exp[ rew[i] ] = unifEq;
- Trace("datatypes-infer") << "DtInfer : cons-inj : " << rew[i] << " by " << unifEq << std::endl;
- d_infer.push_back( rew[i] );
- d_infer_exp.push_back( unifEq );
- }
-*/
}
}
Trace("datatypes-debug") << " instantiated : " << eqc1->d_inst << " " << eqc2->d_inst << std::endl;
@@ -918,7 +694,8 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){
Trace("datatypes-debug") << " must check if it is okay to set the constructor." << std::endl;
checkInst = true;
addConstructor( eqc2->d_constructor.get(), eqc1, t1 );
- if( d_conflict ){
+ if (d_state.isInConflict())
+ {
return;
}
}
@@ -945,7 +722,8 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){
Node t_arg = d_labels_args[t2][i];
unsigned tindex = d_labels_tindex[t2][i];
addTester( tindex, t, eqc1, t1, t_arg );
- if( d_conflict ){
+ if (d_state.isInConflict())
+ {
Trace("datatypes-debug") << " conflict!" << std::endl;
return;
}
@@ -969,7 +747,8 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){
if( checkInst ){
Trace("datatypes-debug") << " checking instantiate" << std::endl;
instantiate( eqc1, t1 );
- if( d_conflict ){
+ if (d_state.isInConflict())
+ {
return;
}
}
@@ -978,11 +757,6 @@ void TheoryDatatypes::merge( Node t1, Node t2 ){
}
}
-/** called when two equivalence classes are made disequal */
-void TheoryDatatypes::eqNotifyDisequal(TNode t1, TNode t2, TNode reason){
-
-}
-
TheoryDatatypes::EqcInfo::EqcInfo( context::Context* c )
: d_inst( c, false )
, d_constructor( c, Node::null() )
@@ -1013,6 +787,8 @@ int TheoryDatatypes::getLabelIndex( EqcInfo* eqc, Node n ){
return -1;
}else{
int tindex = utils::isTester(lbl);
+ Trace("datatypes-debug") << "Label of " << n << " is " << lbl
+ << " with tindex " << tindex << std::endl;
Assert(tindex != -1);
return tindex;
}
@@ -1067,9 +843,7 @@ Node TheoryDatatypes::getTermSkolemFor( Node n ) {
d_term_sk[n] = k;
Node eq = k.eqNode( n );
Trace("datatypes-infer") << "DtInfer : ref : " << eq << std::endl;
- d_pending_lem.push_back( eq );
- //doSendLemma( eq );
- //d_pending_exp[ eq ] = d_true;
+ d_im.addPendingLemma(eq);
return k;
}else{
return (*it).second;
@@ -1085,6 +859,7 @@ void TheoryDatatypes::addTester(
Trace("datatypes-debug") << "Add tester : " << t << " to eqc(" << n << ")" << std::endl;
Debug("datatypes-labels") << "Add tester " << t << " " << n << " " << eqc << std::endl;
bool tpolarity = t.getKind()!=NOT;
+ Assert((tpolarity ? t : t[0]).getKind() == APPLY_TESTER);
Node j, jt;
bool makeConflict = false;
int prevTIndex = getLabelIndex(eqc, n);
@@ -1096,13 +871,12 @@ void TheoryDatatypes::addTester(
{
if( !eqc->d_constructor.get().isNull() ){
//conflict because equivalence class contains a constructor
- std::vector< TNode > assumptions;
- explain( t, assumptions );
- explainEquality( eqc->d_constructor.get(), t_arg, true, assumptions );
- d_conflictNode = mkAnd( assumptions );
- Trace("dt-conflict") << "CONFLICT: Tester eq conflict : " << d_conflictNode << std::endl;
- d_out->conflict( d_conflictNode );
- d_conflict = true;
+ std::vector<Node> conf;
+ conf.push_back(t);
+ conf.push_back(t_arg.eqNode(eqc->d_constructor.get()));
+ Trace("dt-conflict")
+ << "CONFLICT: Tester eq conflict " << conf << std::endl;
+ d_im.sendDtConflict(conf, InferId::TESTER_CONFLICT);
return;
}else{
makeConflict = true;
@@ -1156,16 +930,8 @@ void TheoryDatatypes::addTester(
Debug("datatypes-labels") << "Labels at " << n_lbl << " / " << dt.getNumConstructors() << std::endl;
if( tpolarity ){
instantiate( eqc, n );
- for (unsigned i = 0, ncons = dt.getNumConstructors(); i < ncons; i++)
- {
- if( i!=ttindex && neg_testers.find( i )==neg_testers.end() ){
- Assert(n.getKind() != APPLY_CONSTRUCTOR);
- Node infer = utils::mkTester(n, i, dt).negate();
- Trace("datatypes-infer") << "DtInfer : neg label : " << infer << " by " << t << std::endl;
- d_infer.push_back( infer );
- d_infer_exp.push_back( t );
- }
- }
+ // We could propagate is-C1(x) => not is-C2(x) here for all other
+ // constructors, but empirically this hurts performance.
}else{
//check if we have reached the maximum number of testers
// in this case, add the positive tester
@@ -1201,26 +967,22 @@ void TheoryDatatypes::addTester(
? NodeManager::currentNM()->mkConst(false)
: utils::mkTester(t_arg, testerIndex, dt);
Node t_concl_exp = ( nb.getNumChildren() == 1 ) ? nb.getChild( 0 ) : nb;
- d_pending.push_back( t_concl );
- d_pending_exp[ t_concl ] = t_concl_exp;
+ d_im.addPendingInference(
+ t_concl, t_concl_exp, false, InferId::LABEL_EXH);
Trace("datatypes-infer") << "DtInfer : label : " << t_concl << " by " << t_concl_exp << std::endl;
- d_infer.push_back( t_concl );
- d_infer_exp.push_back( t_concl_exp );
return;
}
}
}
}
if( makeConflict ){
- d_conflict = true;
Debug("datatypes-labels") << "Explain " << j << " " << t << std::endl;
- std::vector< TNode > assumptions;
- explain( j, assumptions );
- explain( t, assumptions );
- explainEquality( jt[0], t_arg, true, assumptions );
- d_conflictNode = mkAnd( assumptions );
- Trace("dt-conflict") << "CONFLICT: Tester conflict : " << d_conflictNode << std::endl;
- d_out->conflict( d_conflictNode );
+ std::vector<Node> conf;
+ conf.push_back(j);
+ conf.push_back(t);
+ conf.push_back(jt[0].eqNode(t_arg));
+ Trace("dt-conflict") << "CONFLICT: Tester conflict : " << conf << std::endl;
+ d_im.sendDtConflict(conf, InferId::TESTER_MERGE_CONFLICT);
}
}
@@ -1273,13 +1035,12 @@ void TheoryDatatypes::addConstructor( Node c, EqcInfo* eqc, Node n ){
unsigned tindex = d_labels_tindex[n][i];
if (tindex == constructorIndex)
{
- std::vector< TNode > assumptions;
- explain( t, assumptions );
- explainEquality( c, t[0][0], true, assumptions );
- d_conflictNode = mkAnd( assumptions );
- Trace("dt-conflict") << "CONFLICT: Tester merge eq conflict : " << d_conflictNode << std::endl;
- d_out->conflict( d_conflictNode );
- d_conflict = true;
+ std::vector<Node> conf;
+ conf.push_back(t);
+ conf.push_back(c.eqNode(t[0][0]));
+ Trace("dt-conflict")
+ << "CONFLICT: Tester merge eq conflict : " << conf << std::endl;
+ d_im.sendDtConflict(conf, InferId::TESTER_CONFLICT);
return;
}
}
@@ -1299,47 +1060,12 @@ void TheoryDatatypes::addConstructor( Node c, EqcInfo* eqc, Node n ){
eqc->d_constructor.set( c );
}
-Node TheoryDatatypes::removeUninterpretedConstants( Node n, std::map< Node, Node >& visited ){
- std::map< Node, Node >::iterator it = visited.find( n );
- if( it==visited.end() ){
- Node ret = n;
- if( n.getKind()==UNINTERPRETED_CONSTANT ){
- std::map< Node, Node >::iterator itu = d_uc_to_fresh_var.find( n );
- if( itu==d_uc_to_fresh_var.end() ){
- Node k = NodeManager::currentNM()->mkSkolem( "w", n.getType(), "Skolem for wrongly applied selector." );
- d_uc_to_fresh_var[n] = k;
- ret = k;
- }else{
- ret = itu->second;
- }
- }else if( n.getNumChildren()>0 ){
- std::vector< Node > children;
- if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
- children.push_back( n.getOperator() );
- }
- bool childChanged = false;
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- Node nc = removeUninterpretedConstants( n[i], visited );
- childChanged = childChanged || nc!=n[i];
- children.push_back( nc );
- }
- if( childChanged ){
- ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
- }
- }
- visited[n] = ret;
- return ret;
- }else{
- return it->second;
- }
-}
-
void TheoryDatatypes::collapseSelector( Node s, Node c ) {
Assert(c.getKind() == APPLY_CONSTRUCTOR);
Trace("dt-collapse-sel") << "collapse selector : " << s << " " << c << std::endl;
Node r;
bool wrong = false;
- Node eq_exp = c.eqNode(s[0]);
+ Node eq_exp = s[0].eqNode(c);
if( s.getKind()==kind::APPLY_SELECTOR_TOTAL ){
Node selector = s.getOperator();
size_t constructorIndex = utils::indexOf(c.getOperator());
@@ -1350,37 +1076,48 @@ void TheoryDatatypes::collapseSelector( Node s, Node c ) {
r = NodeManager::currentNM()->mkNode( kind::APPLY_SELECTOR_TOTAL, s.getOperator(), c );
}
if( !r.isNull() ){
- Node rr = Rewriter::rewrite( r );
- Node rrs = rr;
- if( wrong ){
- // we have inference S_i( C_j( t ) ) = t' for i != j, where t' is result of mkGroundTerm.
- // we must eliminate uninterpreted constants for datatypes that have uninterpreted sort subfields,
- // since uninterpreted constants should not appear in lemmas
- std::map< Node, Node > visited;
- rrs = removeUninterpretedConstants( rr, visited );
+ Node rrs;
+ if (wrong)
+ {
+ // Must use make ground term here instead of the rewriter, since we
+ // do not want to introduce arbitrary values. This is important so that
+ // we avoid constants for types that are not "closed enumerable", e.g.
+ // uninterpreted sorts and arrays, where the solver does not fully
+ // handle values of the sort. The call to mkGroundTerm does not introduce
+ // values for these sorts.
+ rrs = r.getType().mkGroundTerm();
+ Trace("datatypes-wrong-sel")
+ << "Bad apply " << r << " term = " << rrs
+ << ", value = " << r.getType().mkGroundValue() << std::endl;
+ }
+ else
+ {
+ rrs = Rewriter::rewrite(r);
}
if (s != rrs)
{
Node eq = s.eqNode(rrs);
- Node peq = c.eqNode(s[0]);
+ // Since collapsing selectors may generate new terms, we must send
+ // this out as a lemma if it is of an external type, or otherwise we
+ // may ask for the equality status of terms that only datatypes knows
+ // about, see issue #5344.
+ bool forceLemma = !s.getType().isDatatype();
Trace("datatypes-infer") << "DtInfer : collapse sel";
- //Trace("datatypes-infer") << ( wrong ? " wrong" : "");
- Trace("datatypes-infer") << " : " << eq << " by " << peq << std::endl;
- d_pending.push_back( eq );
- d_pending_exp[eq] = peq;
- d_infer.push_back( eq );
- d_infer_exp.push_back(peq);
+ Trace("datatypes-infer") << " : " << eq << " by " << eq_exp << std::endl;
+ d_im.addPendingInference(eq, eq_exp, forceLemma, InferId::COLLAPSE_SEL);
}
}
}
EqualityStatus TheoryDatatypes::getEqualityStatus(TNode a, TNode b){
- Assert(d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b));
- if (d_equalityEngine.areEqual(a, b)) {
+ Assert(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)) {
+ if (d_equalityEngine->areDisequal(a, b, false))
+ {
// The terms are implied to be dis-equal
return EQUALITY_FALSE;
}
@@ -1403,15 +1140,20 @@ void TheoryDatatypes::addCarePairs(TNodeTrie* t1,
for (unsigned k = 0; k < f1.getNumChildren(); ++ k) {
TNode x = f1[k];
TNode y = f2[k];
- Assert(d_equalityEngine.hasTerm(x));
- Assert(d_equalityEngine.hasTerm(y));
+ Assert(d_equalityEngine->hasTerm(x));
+ Assert(d_equalityEngine->hasTerm(y));
Assert(!areDisequal(x, y));
Assert(!areCareDisequal(x, y));
- if( !d_equalityEngine.areEqual( x, y ) ){
+ if (!d_equalityEngine->areEqual(x, y))
+ {
Trace("dt-cg") << "Arg #" << k << " is " << x << " " << y << std::endl;
- if( d_equalityEngine.isTriggerTerm(x, THEORY_DATATYPES) && d_equalityEngine.isTriggerTerm(y, THEORY_DATATYPES) ){
- TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_DATATYPES);
- TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_DATATYPES);
+ if (d_equalityEngine->isTriggerTerm(x, THEORY_DATATYPES)
+ && d_equalityEngine->isTriggerTerm(y, THEORY_DATATYPES))
+ {
+ TNode x_shared = d_equalityEngine->getTriggerTermRepresentative(
+ x, THEORY_DATATYPES);
+ TNode y_shared = d_equalityEngine->getTriggerTermRepresentative(
+ y, THEORY_DATATYPES);
currentPairs.push_back(make_pair(x_shared, y_shared));
}
}
@@ -1440,7 +1182,8 @@ void TheoryDatatypes::addCarePairs(TNodeTrie* t1,
std::map<TNode, TNodeTrie>::iterator it2 = it;
++it2;
for( ; it2 != t1->d_data.end(); ++it2 ){
- if( !d_equalityEngine.areDisequal(it->first, it2->first, false) ){
+ if (!d_equalityEngine->areDisequal(it->first, it2->first, false))
+ {
if( !areCareDisequal(it->first, it2->first) ){
addCarePairs( &it->second, &it2->second, arity, depth+1, n_pairs );
}
@@ -1453,7 +1196,7 @@ void TheoryDatatypes::addCarePairs(TNodeTrie* t1,
{
for (std::pair<const TNode, TNodeTrie>& tt2 : t2->d_data)
{
- if (!d_equalityEngine.areDisequal(tt1.first, tt2.first, false))
+ if (!d_equalityEngine->areDisequal(tt1.first, tt2.first, false))
{
if (!areCareDisequal(tt1.first, tt2.first))
{
@@ -1476,7 +1219,7 @@ void TheoryDatatypes::computeCareGraph(){
unsigned functionTerms = d_functionTerms.size();
for( unsigned i=0; i<functionTerms; i++ ){
TNode f1 = d_functionTerms[i];
- Assert(d_equalityEngine.hasTerm(f1));
+ Assert(d_equalityEngine->hasTerm(f1));
Trace("dt-cg-debug") << "...build for " << f1 << std::endl;
//break into index based on operator, and type of first argument (since some operators are parametric)
Node op = f1.getOperator();
@@ -1484,8 +1227,9 @@ void TheoryDatatypes::computeCareGraph(){
std::vector< TNode > reps;
bool has_trigger_arg = false;
for( unsigned j=0; j<f1.getNumChildren(); j++ ){
- reps.push_back( d_equalityEngine.getRepresentative( f1[j] ) );
- if( d_equalityEngine.isTriggerTerm( f1[j], THEORY_DATATYPES ) ){
+ reps.push_back(d_equalityEngine->getRepresentative(f1[j]));
+ if (d_equalityEngine->isTriggerTerm(f1[j], THEORY_DATATYPES))
+ {
has_trigger_arg = true;
}
}
@@ -1508,26 +1252,17 @@ void TheoryDatatypes::computeCareGraph(){
Trace("dt-cg-summary") << "...done, # pairs = " << n_pairs << std::endl;
}
-bool TheoryDatatypes::collectModelInfo(TheoryModel* m)
+bool TheoryDatatypes::collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet)
{
- Trace("dt-cmi") << "Datatypes : Collect model info " << d_equalityEngine.consistent() << std::endl;
+ Trace("dt-cmi") << "Datatypes : Collect model values "
+ << d_equalityEngine->consistent() << std::endl;
Trace("dt-model") << std::endl;
printModelDebug( "dt-model" );
Trace("dt-model") << std::endl;
-
- set<Node> termSet;
-
- // Compute terms appearing in assertions and shared terms, and in inferred equalities
- getRelevantTerms(termSet);
-
- //combine the equality engine
- if (!m->assertEqualityEngine(&d_equalityEngine, &termSet))
- {
- return false;
- }
//get all constructors
- eq::EqClassesIterator eqccs_i = eq::EqClassesIterator( &d_equalityEngine );
+ eq::EqClassesIterator eqccs_i = eq::EqClassesIterator(d_equalityEngine);
std::vector< Node > cons;
std::vector< Node > nodes;
std::map< Node, Node > eqc_cons;
@@ -1566,7 +1301,8 @@ bool TheoryDatatypes::collectModelInfo(TheoryModel* m)
bool addCons = false;
TypeNode tt = eqc.getType();
const DType& dt = tt.getDType();
- if( !d_equalityEngine.hasTerm( eqc ) ){
+ if (!d_equalityEngine->hasTerm(eqc))
+ {
Assert(false);
}else{
Trace("dt-cmi") << "NOTICE : Datatypes: no constructor in equivalence class " << eqc << std::endl;
@@ -1586,12 +1322,6 @@ bool TheoryDatatypes::collectModelInfo(TheoryModel* m)
bool cfinite = dt[ i ].isInterpretedFinite( tt );
if( pcons[i] && (r==1)==cfinite ){
neqc = utils::getInstCons(eqc, dt, i);
- //for( unsigned j=0; j<neqc.getNumChildren(); j++ ){
- // //if( sels[i].find( j )==sels[i].end() && neqc[j].getType().isDatatype() ){
- // if( !d_equalityEngine.hasTerm( neqc[j] ) && neqc[j].getType().isDatatype() ){
- // nodes.push_back( neqc[j] );
- // }
- //}
break;
}
}
@@ -1678,7 +1408,7 @@ Node TheoryDatatypes::getSingletonLemma( TypeNode tn, bool pol ) {
Node v2 = NodeManager::currentNM()->mkSkolem( "k2", tn );
a = v1.eqNode( v2 ).negate();
//send out immediately as lemma
- doSendLemma( a );
+ d_im.lemma(a);
Trace("dt-singleton") << "******** assert " << a << " to avoid singleton cardinality for type " << tn << std::endl;
}
d_singleton_lemma[index][tn] = a;
@@ -1736,7 +1466,7 @@ void TheoryDatatypes::collectTerms( Node n ) {
Node lem = nm->mkNode(LEQ, d_zero, n);
Trace("datatypes-infer")
<< "DtInfer : size geq zero : " << lem << std::endl;
- d_pending_lem.push_back(lem);
+ d_im.addPendingLemma(lem);
}
else if (nk == DT_HEIGHT_BOUND && n[1].getConst<Rational>().isZero())
{
@@ -1761,7 +1491,7 @@ void TheoryDatatypes::collectTerms( Node n ) {
: nm->mkNode(OR, children));
}
Trace("datatypes-infer") << "DtInfer : zero height : " << lem << std::endl;
- d_pending_lem.push_back(lem);
+ d_im.addPendingLemma(lem);
}
}
@@ -1781,7 +1511,7 @@ Node TheoryDatatypes::getInstantiateCons(Node n, const DType& dt, int index)
//Assert( n_ic==Rewriter::rewrite( n_ic ) );
n_ic = Rewriter::rewrite( n_ic );
collectTerms( n_ic );
- d_equalityEngine.addTerm(n_ic);
+ d_equalityEngine->addTerm(n_ic);
Debug("dt-enum") << "Made instantiate cons " << n_ic << std::endl;
}
d_inst_map[n][index] = n_ic;
@@ -1790,6 +1520,7 @@ Node TheoryDatatypes::getInstantiateCons(Node n, const DType& dt, int index)
}
void TheoryDatatypes::instantiate( EqcInfo* eqc, Node n ){
+ Trace("datatypes-debug") << "Instantiate: " << n << std::endl;
//add constructor to equivalence class if not done so already
int index = getLabelIndex( eqc, n );
if (index == -1 || eqc->d_inst)
@@ -1808,7 +1539,8 @@ void TheoryDatatypes::instantiate( EqcInfo* eqc, Node n ){
exp = getLabel(n);
tt = exp[0];
}
- const DType& dt = tt.getType().getDType();
+ TypeNode ttn = tt.getType();
+ const DType& dt = ttn.getDType();
// instantiate this equivalence class
eqc->d_inst = true;
Node tt_cons = getInstantiateCons(tt, dt, index);
@@ -1818,21 +1550,25 @@ void TheoryDatatypes::instantiate( EqcInfo* eqc, Node n ){
return;
}
eq = tt.eqNode(tt_cons);
- Debug("datatypes-inst") << "DtInstantiate : " << eqc << " " << eq
- << std::endl;
- d_pending.push_back(eq);
- d_pending_exp[eq] = exp;
- Trace("datatypes-infer-debug") << "inst : " << eqc << " " << n << std::endl;
+ // Determine if the equality must be sent out as a lemma. Notice that
+ // we can keep new equalities from the instantiate rule internal as long as
+ // they are for datatype constructors that have no arguments that have
+ // finite external type. Such equalities must be sent because they introduce
+ // selector terms that may contribute to conflicts due to cardinality (good
+ // examples of this are regress0/datatypes/dt-param-card4-bool-sat.smt2 and
+ // regress0/datatypes/list-bool.smt2).
+ bool forceLemma = dt[index].hasFiniteExternalArgType(ttn);
+ Trace("datatypes-infer-debug") << "DtInstantiate : " << eqc << " " << eq
+ << " forceLemma = " << forceLemma << std::endl;
+ d_im.addPendingInference(eq, exp, forceLemma, InferId::INST);
Trace("datatypes-infer") << "DtInfer : instantiate : " << eq << " by " << exp
<< std::endl;
- d_infer.push_back(eq);
- d_infer_exp.push_back(exp);
}
void TheoryDatatypes::checkCycles() {
Trace("datatypes-cycle-check") << "Check acyclicity" << std::endl;
std::vector< Node > cdt_eqc;
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(d_equalityEngine);
while( !eqcs_i.isFinished() ){
Node eqc = (*eqcs_i);
TypeNode tn = eqc.getType();
@@ -1842,7 +1578,7 @@ void TheoryDatatypes::checkCycles() {
//do cycle checks
std::map< TNode, bool > visited;
std::map< TNode, bool > proc;
- std::vector< TNode > expl;
+ std::vector<Node> expl;
Trace("datatypes-cycle-check") << "...search for cycle starting at " << eqc << std::endl;
Node cn = searchForCycle( eqc, eqc, visited, proc, expl );
Trace("datatypes-cycle-check") << "...finish." << std::endl;
@@ -1858,10 +1594,9 @@ void TheoryDatatypes::checkCycles() {
if( !cn.isNull() ) {
Assert(expl.size() > 0);
- d_conflictNode = mkAnd( expl );
- Trace("dt-conflict") << "CONFLICT: Cycle conflict : " << d_conflictNode << std::endl;
- d_out->conflict( d_conflictNode );
- d_conflict = true;
+ Trace("dt-conflict")
+ << "CONFLICT: Cycle conflict : " << expl << std::endl;
+ d_im.sendDtConflict(expl, InferId::CYCLE);
return;
}
}
@@ -1878,7 +1613,7 @@ void TheoryDatatypes::checkCycles() {
printModelDebug("dt-cdt-debug");
Trace("dt-cdt-debug") << "Process " << cdt_eqc.size() << " co-datatypes" << std::endl;
std::vector< std::vector< Node > > part_out;
- std::vector< TNode > exp;
+ std::vector<Node> exp;
std::map< Node, Node > cn;
std::map< Node, std::map< Node, int > > dni;
for( unsigned i=0; i<cdt_eqc.size(); i++ ){
@@ -1910,12 +1645,9 @@ void TheoryDatatypes::checkCycles() {
}
Trace("dt-cdt") << std::endl;
Node eq = part_out[i][0].eqNode( part_out[i][j] );
- Node eqExp = mkAnd( exp );
- d_pending.push_back( eq );
- d_pending_exp[ eq ] = eqExp;
+ Node eqExp = NodeManager::currentNM()->mkAnd(exp);
+ d_im.addPendingInference(eq, eqExp, false, InferId::BISIMILAR);
Trace("datatypes-infer") << "DtInfer : cdt-bisimilar : " << eq << " by " << eqExp << std::endl;
- d_infer.push_back( eq );
- d_infer_exp.push_back( eqExp );
}
}
}
@@ -1923,10 +1655,15 @@ void TheoryDatatypes::checkCycles() {
}
//everything is in terms of representatives
-void TheoryDatatypes::separateBisimilar( std::vector< Node >& part, std::vector< std::vector< Node > >& part_out,
- std::vector< TNode >& exp,
- std::map< Node, Node >& cn,
- std::map< Node, std::map< Node, int > >& dni, int dniLvl, bool mkExp ){
+void TheoryDatatypes::separateBisimilar(
+ std::vector<Node>& part,
+ std::vector<std::vector<Node> >& part_out,
+ std::vector<Node>& exp,
+ std::map<Node, Node>& cn,
+ std::map<Node, std::map<Node, int> >& dni,
+ int dniLvl,
+ bool mkExp)
+{
if( !mkExp ){
Trace("dt-cdt-debug") << "Separate bisimilar : " << std::endl;
for( unsigned i=0; i<part.size(); i++ ){
@@ -1952,8 +1689,9 @@ void TheoryDatatypes::separateBisimilar( std::vector< Node >& part, std::vector<
if( ncons.getKind()==APPLY_CONSTRUCTOR ) {
Node cc = ncons.getOperator();
cn_cons[part[j]] = ncons;
- if( mkExp ){
- explainEquality( c, ncons, true, exp );
+ if (mkExp && c != ncons)
+ {
+ exp.push_back(c.eqNode(ncons));
}
new_part[cc].push_back( part[j] );
if( !mkExp ){ Trace("dt-cdt-debug") << " - " << part[j] << " is datatype " << ncons << "." << std::endl; }
@@ -2011,9 +1749,12 @@ void TheoryDatatypes::separateBisimilar( std::vector< Node >& part, std::vector<
//set current node
for( unsigned k=0; k<split_new_part[j].size(); k++ ){
Node n = split_new_part[j][k];
- cn[n] = getRepresentative( cn_cons[n][cindex] );
- if( mkExp ){
- explainEquality( cn[n], cn_cons[n][cindex], true, exp );
+ Node cnc = cn_cons[n][cindex];
+ Node nr = getRepresentative(cnc);
+ cn[n] = nr;
+ if (mkExp && cnc != nr)
+ {
+ exp.push_back(nr.eqNode(cnc));
}
}
std::vector< std::vector< Node > > c_part_out;
@@ -2034,16 +1775,23 @@ void TheoryDatatypes::separateBisimilar( std::vector< Node >& part, std::vector<
}
//postcondition: if cycle detected, explanation is why n is a subterm of on
-Node TheoryDatatypes::searchForCycle( TNode n, TNode on,
- std::map< TNode, bool >& visited, std::map< TNode, bool >& proc,
- std::vector< TNode >& explanation, bool firstTime ) {
+Node TheoryDatatypes::searchForCycle(TNode n,
+ TNode on,
+ std::map<TNode, bool>& visited,
+ std::map<TNode, bool>& proc,
+ std::vector<Node>& explanation,
+ bool firstTime)
+{
Trace("datatypes-cycle-check2") << "Search for cycle " << n << " " << on << endl;
TNode ncons;
TNode nn;
if( !firstTime ){
nn = getRepresentative( n );
if( nn==on ){
- explainEquality( n, nn, true, explanation );
+ if (n != nn)
+ {
+ explanation.push_back(n.eqNode(nn));
+ }
return on;
}
}else{
@@ -2067,7 +1815,7 @@ Node TheoryDatatypes::searchForCycle( TNode n, TNode on,
//add explanation for why the constructor is connected
if (n != nncons)
{
- explainEquality(n, nncons, true, explanation);
+ explanation.push_back(n.eqNode(nncons));
}
return on;
}else if( !cn.isNull() ){
@@ -2090,48 +1838,13 @@ Node TheoryDatatypes::searchForCycle( TNode n, TNode on,
}
}
-bool TheoryDatatypes::mustCommunicateFact( Node n, Node exp ){
- //the datatypes decision procedure makes "internal" inferences apart from the equality engine :
- // (1) Unification : C( t1...tn ) = C( s1...sn ) => ti = si
- // (2) Label : ~is_C1( t ) ... ~is_C{i-1}( t ) ~is_C{i+1}( t ) ... ~is_Cn( t ) => is_Ci( t )
- // (3) Instantiate : is_C( t ) => t = C( sel_1( t ) ... sel_n( t ) )
- // (4) collapse selector : S( C( t1...tn ) ) = t'
- // (5) collapse term size : size( C( t1...tn ) ) = 1 + size( t1 ) + ... + size( tn )
- // (6) non-negative size : 0 <= size( t )
- //We may need to communicate outwards if the conclusions involve other theories. Also communicate (6) and OR conclusions.
- Trace("dt-lemma-debug") << "Compute for " << exp << " => " << n << std::endl;
- bool addLemma = false;
- if( options::dtInferAsLemmas() && exp!=d_true ){
- addLemma = true;
- }else if( n.getKind()==EQUAL ){
- TypeNode tn = n[0].getType();
- if( !tn.isDatatype() ){
- addLemma = true;
- }else{
- const DType& dt = tn.getDType();
- addLemma = dt.involvesExternalType();
- }
- }else if( n.getKind()==LEQ || n.getKind()==OR ){
- addLemma = true;
- }
- if( addLemma ){
- Trace("dt-lemma-debug") << "Communicate " << n << std::endl;
- return true;
- }else{
- Trace("dt-lemma-debug") << "Do not need to communicate " << n << std::endl;
- return false;
- }
-}
-
-bool TheoryDatatypes::hasTerm( TNode a ){
- return d_equalityEngine.hasTerm( a );
-}
+bool TheoryDatatypes::hasTerm(TNode a) { return d_equalityEngine->hasTerm(a); }
bool TheoryDatatypes::areEqual( TNode a, TNode b ){
if( a==b ){
return true;
}else if( hasTerm( a ) && hasTerm( b ) ){
- return d_equalityEngine.areEqual( a, b );
+ return d_equalityEngine->areEqual(a, b);
}else{
return false;
}
@@ -2141,7 +1854,7 @@ bool TheoryDatatypes::areDisequal( TNode a, TNode b ){
if( a==b ){
return false;
}else if( hasTerm( a ) && hasTerm( b ) ){
- return d_equalityEngine.areDisequal( a, b, false );
+ return d_equalityEngine->areDisequal(a, b, false);
}else{
//TODO : constants here?
return false;
@@ -2149,11 +1862,16 @@ bool TheoryDatatypes::areDisequal( TNode a, TNode b ){
}
bool TheoryDatatypes::areCareDisequal( TNode x, TNode y ) {
- Assert(d_equalityEngine.hasTerm(x));
- Assert(d_equalityEngine.hasTerm(y));
- if( d_equalityEngine.isTriggerTerm(x, THEORY_DATATYPES) && d_equalityEngine.isTriggerTerm(y, THEORY_DATATYPES) ){
- TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_DATATYPES);
- TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_DATATYPES);
+ Trace("datatypes-cg") << "areCareDisequal: " << x << " " << y << std::endl;
+ Assert(d_equalityEngine->hasTerm(x));
+ Assert(d_equalityEngine->hasTerm(y));
+ if (d_equalityEngine->isTriggerTerm(x, THEORY_DATATYPES)
+ && d_equalityEngine->isTriggerTerm(y, THEORY_DATATYPES))
+ {
+ TNode x_shared =
+ d_equalityEngine->getTriggerTermRepresentative(x, THEORY_DATATYPES);
+ TNode y_shared =
+ d_equalityEngine->getTriggerTermRepresentative(y, THEORY_DATATYPES);
EqualityStatus eqStatus = d_valuation.getEqualityStatus(x_shared, y_shared);
if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
return true;
@@ -2164,23 +1882,19 @@ bool TheoryDatatypes::areCareDisequal( TNode x, TNode y ) {
TNode TheoryDatatypes::getRepresentative( TNode a ){
if( hasTerm( a ) ){
- return d_equalityEngine.getRepresentative( a );
+ return d_equalityEngine->getRepresentative(a);
}else{
return a;
}
}
-bool TheoryDatatypes::getCurrentSubstitution( int effort, std::vector< Node >& vars, std::vector< Node >& subs, std::map< Node, std::vector< Node > >& exp ) {
- return false;
-}
-
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 );
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(d_equalityEngine);
while( !eqcs_i.isFinished() ){
Node eqc = (*eqcs_i);
//if( !eqc.getType().isBoolean() ){
@@ -2190,7 +1904,7 @@ void TheoryDatatypes::printModelDebug( const char* c ){
Trace( c ) << eqc << " : " << eqc.getType() << " : " << std::endl;
Trace( c ) << " { ";
//add terms to model
- eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
+ eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, d_equalityEngine);
while( !eqc_i.isFinished() ){
if( (*eqc_i)!=eqc ){
Trace( c ) << (*eqc_i) << " ";
@@ -2235,28 +1949,13 @@ void TheoryDatatypes::printModelDebug( const char* c ){
}
}
-Node TheoryDatatypes::mkAnd( std::vector< TNode >& assumptions ) {
- if( assumptions.empty() ){
- return d_true;
- }else if( assumptions.size()==1 ){
- return assumptions[0];
- }else{
- return NodeManager::currentNM()->mkNode( AND, assumptions );
- }
-}
-
-void TheoryDatatypes::getRelevantTerms( std::set<Node>& termSet ) {
- // Compute terms appearing in assertions and shared terms
- std::set<Kind> irr_kinds;
- // testers are not relevant for model construction
- irr_kinds.insert(APPLY_TESTER);
- computeRelevantTerms(termSet, irr_kinds);
-
+void TheoryDatatypes::computeRelevantTerms(std::set<Node>& termSet)
+{
Trace("dt-cmi") << "Have " << termSet.size() << " relevant terms..."
<< std::endl;
//also include non-singleton equivalence classes TODO : revisit this
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(d_equalityEngine);
while( !eqcs_i.isFinished() ){
TNode r = (*eqcs_i);
bool addedFirst = false;
@@ -2264,7 +1963,7 @@ void TheoryDatatypes::getRelevantTerms( std::set<Node>& termSet ) {
TypeNode rtn = r.getType();
if (!rtn.isBoolean())
{
- eq::EqClassIterator eqc_i = eq::EqClassIterator(r, &d_equalityEngine);
+ eq::EqClassIterator eqc_i = eq::EqClassIterator(r, d_equalityEngine);
while (!eqc_i.isFinished())
{
TNode n = (*eqc_i);
@@ -2292,8 +1991,6 @@ void TheoryDatatypes::getRelevantTerms( std::set<Node>& termSet ) {
}
++eqcs_i;
}
- Trace("dt-cmi") << "After adding non-singletons, has " << termSet.size()
- << " relevant terms..." << std::endl;
}
std::pair<bool, Node> TheoryDatatypes::entailmentCheck(TNode lit)
@@ -2304,23 +2001,25 @@ std::pair<bool, Node> TheoryDatatypes::entailmentCheck(TNode lit)
if( atom.getKind()==APPLY_TESTER ){
Node n = atom[0];
if( hasTerm( n ) ){
- Node r = d_equalityEngine.getRepresentative( n );
+ Node r = d_equalityEngine->getRepresentative(n);
EqcInfo * ei = getOrMakeEqcInfo( r, false );
int l_index = getLabelIndex( ei, r );
int t_index = static_cast<int>(utils::indexOf(atom.getOperator()));
Trace("dt-entail") << " Tester indices are " << t_index << " and " << l_index << std::endl;
if( l_index!=-1 && (l_index==t_index)==pol ){
std::vector< TNode > exp_c;
+ Node eqToExplain;
if( ei && !ei->d_constructor.get().isNull() ){
- explainEquality( n, ei->d_constructor.get(), true, exp_c );
+ eqToExplain = n.eqNode(ei->d_constructor.get());
}else{
Node lbl = getLabel( n );
Assert(!lbl.isNull());
exp_c.push_back( lbl );
Assert(areEqual(n, lbl[0]));
- explainEquality( n, lbl[0], true, exp_c );
+ eqToExplain = n.eqNode(lbl[0]);
}
- Node exp = mkAnd( exp_c );
+ d_equalityEngine->explainLit(eqToExplain, exp_c);
+ Node exp = NodeManager::currentNM()->mkAnd(exp_c);
Trace("dt-entail") << " entailed, explanation is " << exp << std::endl;
return make_pair(true, exp);
}
diff --git a/src/theory/datatypes/theory_datatypes.h b/src/theory/datatypes/theory_datatypes.h
index ba8321e50..45ce76504 100644
--- a/src/theory/datatypes/theory_datatypes.h
+++ b/src/theory/datatypes/theory_datatypes.h
@@ -2,10 +2,10 @@
/*! \file theory_datatypes.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Tim King, Mathias Preiner
+ ** Andrew Reynolds, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -24,11 +24,13 @@
#include "context/cdlist.h"
#include "expr/attribute.h"
-#include "expr/datatype.h"
#include "expr/node_trie.h"
#include "theory/datatypes/datatypes_rewriter.h"
+#include "theory/datatypes/inference_manager.h"
+#include "theory/datatypes/proof_checker.h"
#include "theory/datatypes/sygus_extension.h"
#include "theory/theory.h"
+#include "theory/theory_eq_notify.h"
#include "theory/uf/equality_engine.h"
#include "util/hash.h"
@@ -44,75 +46,26 @@ class TheoryDatatypes : public Theory {
typedef context::CDHashMap<Node, bool, NodeHashFunction> BoolMap;
typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeMap;
- /** inferences */
- NodeList d_infer;
- NodeList d_infer_exp;
- Node d_true;
- Node d_zero;
- /** mkAnd */
- Node mkAnd(std::vector<TNode>& assumptions);
-
private:
//notification class for equality engine
- class NotifyClass : public eq::EqualityEngineNotify {
+ class NotifyClass : public TheoryEqNotifyClass
+ {
TheoryDatatypes& d_dt;
public:
- NotifyClass(TheoryDatatypes& dt): d_dt(dt) {}
- bool eqNotifyTriggerEquality(TNode equality, bool value) override
- {
- Debug("dt") << "NotifyClass::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false" )<< ")" << std::endl;
- if (value) {
- return d_dt.propagate(equality);
- } else {
- // We use only literal triggers so taking not is safe
- return d_dt.propagate(equality.notNode());
- }
- }
- bool eqNotifyTriggerPredicate(TNode predicate, bool value) override
- {
- Debug("dt") << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", " << (value ? "true" : "false") << ")" << std::endl;
- if (value) {
- return d_dt.propagate(predicate);
- } else {
- return d_dt.propagate(predicate.notNode());
- }
- }
- bool eqNotifyTriggerTermEquality(TheoryId tag,
- TNode t1,
- TNode t2,
- bool value) override
- {
- Debug("dt") << "NotifyClass::eqNotifyTriggerTermMerge(" << tag << ", " << t1 << ", " << t2 << ")" << std::endl;
- if (value) {
- return d_dt.propagate(t1.eqNode(t2));
- } else {
- return d_dt.propagate(t1.eqNode(t2).notNode());
- }
- }
- void eqNotifyConstantTermMerge(TNode t1, TNode t2) override
- {
- Debug("dt") << "NotifyClass::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << ")" << std::endl;
- d_dt.conflict(t1, t2);
+ NotifyClass(TheoryInferenceManager& im, TheoryDatatypes& dt)
+ : TheoryEqNotifyClass(im), d_dt(dt)
+ {
+ }
+ void eqNotifyNewClass(TNode t) override
+ {
+ Debug("dt") << "NotifyClass::eqNotifyNewClass(" << t << ")" << std::endl;
+ d_dt.eqNotifyNewClass(t);
}
- void eqNotifyNewClass(TNode t) override
+ void eqNotifyMerge(TNode t1, TNode t2) override
{
- Debug("dt") << "NotifyClass::eqNotifyNewClass(" << t << ")" << std::endl;
- d_dt.eqNotifyNewClass(t);
- }
- void eqNotifyPreMerge(TNode t1, TNode t2) override
- {
- Debug("dt") << "NotifyClass::eqNotifyPreMerge(" << t1 << ", " << t2 << ")" << std::endl;
- d_dt.eqNotifyPreMerge(t1, t2);
- }
- void eqNotifyPostMerge(TNode t1, TNode t2) override
- {
- Debug("dt") << "NotifyClass::eqNotifyPostMerge(" << t1 << ", " << t2 << ")" << std::endl;
- d_dt.eqNotifyPostMerge(t1, t2);
- }
- void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override
- {
- Debug("dt") << "NotifyClass::eqNotifyDisequal(" << t1 << ", " << t2 << ", " << reason << ")" << std::endl;
- d_dt.eqNotifyDisequal(t1, t2, reason);
+ Debug("dt") << "NotifyClass::eqNotifyMerge(" << t1 << ", " << t2 << ")"
+ << std::endl;
+ d_dt.eqNotifyMerge(t1, t2);
}
};/* class TheoryDatatypes::NotifyClass */
private:
@@ -149,10 +102,6 @@ private:
NodeMap d_term_sk;
Node getTermSkolemFor( Node n );
private:
- /** The notify class */
- NotifyClass d_notify;
- /** Equaltity engine */
- eq::EqualityEngine d_equalityEngine;
/** information necessary for equivalence classes */
std::map< Node, EqcInfo* > d_eqc_info;
/** map from nodes to their instantiated equivalent for each constructor type */
@@ -190,20 +139,6 @@ private:
/** selector apps for eqch equivalence class */
NodeUIntMap d_selector_apps;
std::map< Node, std::vector< Node > > d_selector_apps_data;
- /** Are we in conflict */
- context::CDO<bool> d_conflict;
- /** added lemma
- *
- * This flag is set to true during a full effort check if this theory
- * called d_out->lemma(...).
- */
- bool d_addedLemma;
- /** added fact
- *
- * This flag is set to true during a full effort check if this theory
- * added an internal fact to its equality engine.
- */
- bool d_addedFact;
/** The conflict node */
Node d_conflictNode;
/**
@@ -216,11 +151,6 @@ private:
* collectTerms(...) on.
*/
BoolMap d_collectTermsCacheU;
- /** pending assertions/merges */
- std::vector< Node > d_pending_lem;
- std::vector< Node > d_pending;
- std::map< Node, Node > d_pending_exp;
- std::vector< Node > d_pending_merge;
/** All the function terms that the theory has seen */
context::CDList<TNode> d_functionTerms;
/** counter for forcing assignments (ensures fairness) */
@@ -240,14 +170,6 @@ private:
/** assert fact */
void assertFact( Node fact, Node exp );
- /** flush pending facts */
- void flushPendingFacts();
-
- /** do pending merged */
- void doPendingMerges();
- /** do send lemma */
- bool doSendLemma( Node lem );
- bool doSendLemmas( std::vector< Node >& lem );
/** get or make eqc info */
EqcInfo* getOrMakeEqcInfo( TNode n, bool doMake = false );
@@ -275,54 +197,47 @@ private:
ProofNodeManager* pnm = nullptr);
~TheoryDatatypes();
- TheoryRewriter* getTheoryRewriter() override { return &d_rewriter; }
-
- void setMasterEqualityEngine(eq::EqualityEngine* eq) override;
-
- /** propagate */
- void propagate(Effort effort) override;
+ //--------------------------------- initialization
+ /** get the official theory rewriter of this theory */
+ TheoryRewriter* getTheoryRewriter() override;
+ /**
+ * Returns true if we need an equality engine. If so, we initialize the
+ * information regarding how it should be setup. For details, see the
+ * documentation in Theory::needsEqualityEngine.
+ */
+ bool needsEqualityEngine(EeSetupInfo& esi) override;
+ /** finish initialization */
+ void finishInit() override;
+ //--------------------------------- end initialization
/** propagate */
- bool propagate(TNode literal);
- /** explain */
- void addAssumptions( std::vector<TNode>& assumptions, std::vector<TNode>& tassumptions );
- void explainEquality( TNode a, TNode b, bool polarity, std::vector<TNode>& assumptions );
- void explainPredicate( TNode p, bool polarity, std::vector<TNode>& assumptions );
- void explain( TNode literal, std::vector<TNode>& assumptions );
- TrustNode explain(TNode literal) override;
- Node explainLit(TNode literal);
- Node explain( std::vector< Node >& lits );
+ bool propagateLit(TNode literal);
/** Conflict when merging two constants */
void conflict(TNode a, TNode b);
+ /** explain */
+ TrustNode explain(TNode literal) override;
/** 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);
+ void eqNotifyMerge(TNode t1, TNode t2);
- void check(Effort e) override;
+ //--------------------------------- standard check
+ /** Do we need a check call at last call effort? */
bool needsCheckLastEffort() override;
+ /** Pre-check, called before the fact queue of the theory is processed. */
+ bool preCheck(Effort level) override;
+ /** Post-check, called after the fact queue of the theory is processed. */
+ void postCheck(Effort level) override;
+ /** Notify fact */
+ void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal) override;
+ //--------------------------------- end standard check
void preRegisterTerm(TNode n) override;
- void finishInit() override;
TrustNode expandDefinition(Node n) override;
TrustNode ppRewrite(TNode n) override;
- void presolve() override;
- void addSharedTerm(TNode t) override;
EqualityStatus getEqualityStatus(TNode a, TNode b) override;
- bool collectModelInfo(TheoryModel* m) override;
- void shutdown() override {}
std::string identify() const override
{
return std::string("TheoryDatatypes");
}
- /** equality engine */
- eq::EqualityEngine* getEqualityEngine() override { return &d_equalityEngine; }
- bool getCurrentSubstitution(int effort,
- std::vector<Node>& vars,
- std::vector<Node>& subs,
- std::map<Node, std::vector<Node> >& exp) override;
/** debug print */
void printModelDebug( const char* c );
/** entailment check */
@@ -339,18 +254,22 @@ private:
void merge( Node t1, Node t2 );
/** collapse selector, s is of the form sel( n ) where n = c */
void collapseSelector( Node s, Node c );
- /** remove uninterpreted constants */
- Node removeUninterpretedConstants( Node n, std::map< Node, Node >& visited );
/** for checking if cycles exist */
void checkCycles();
- Node searchForCycle( TNode n, TNode on,
- std::map< TNode, bool >& visited, std::map< TNode, bool >& proc,
- std::vector< TNode >& explanation, bool firstTime = true );
+ Node searchForCycle(TNode n,
+ TNode on,
+ std::map<TNode, bool>& visited,
+ std::map<TNode, bool>& proc,
+ std::vector<Node>& explanation,
+ bool firstTime = true);
/** for checking whether two codatatype terms must be equal */
- void separateBisimilar( std::vector< Node >& part, std::vector< std::vector< Node > >& part_out,
- std::vector< TNode >& exp,
- std::map< Node, Node >& cn,
- std::map< Node, std::map< Node, int > >& dni, int dniLvl, bool mkExp );
+ void separateBisimilar(std::vector<Node>& part,
+ std::vector<std::vector<Node> >& part_out,
+ std::vector<Node>& exp,
+ std::map<Node, Node>& cn,
+ std::map<Node, std::map<Node, int> >& dni,
+ int dniLvl,
+ bool mkExp);
/** build model */
Node getCodatatypesValue( Node n, std::map< Node, Node >& eqc_cons, std::map< Node, int >& vmap, int depth );
/** get singleton lemma */
@@ -361,10 +280,6 @@ private:
Node getInstantiateCons(Node n, const DType& dt, int index);
/** check instantiate */
void instantiate( EqcInfo* eqc, Node n );
- /** must communicate fact */
- bool mustCommunicateFact( Node n, Node exp );
- /** get relevant terms */
- void getRelevantTerms( std::set<Node>& termSet );
private:
//equality queries
bool hasTerm( TNode a );
@@ -373,12 +288,29 @@ private:
bool areCareDisequal( TNode x, TNode y );
TNode getRepresentative( TNode a );
- private:
+ /** Collect model values in m based on the relevant terms given by termSet */
+ bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet) override;
+ /**
+ * Compute relevant terms. This includes datatypes in non-singleton
+ * equivalence classes.
+ */
+ void computeRelevantTerms(std::set<Node>& termSet) override;
+ /** Commonly used terms */
+ Node d_true;
+ Node d_zero;
/** sygus symmetry breaking utility */
std::unique_ptr<SygusExtension> d_sygusExtension;
-
/** The theory rewriter for this theory. */
DatatypesRewriter d_rewriter;
+ /** A (default) theory state object */
+ TheoryState d_state;
+ /** The inference manager */
+ InferenceManager d_im;
+ /** The notify class */
+ NotifyClass d_notify;
+ /** Proof checker for datatypes */
+ DatatypesProofRuleChecker d_pchecker;
};/* class TheoryDatatypes */
}/* CVC4::theory::datatypes namespace */
diff --git a/src/theory/datatypes/theory_datatypes_type_rules.h b/src/theory/datatypes/theory_datatypes_type_rules.h
index e9df20c2e..2834b86ba 100644
--- a/src/theory/datatypes/theory_datatypes_type_rules.h
+++ b/src/theory/datatypes/theory_datatypes_type_rules.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -196,8 +196,7 @@ struct DatatypeAscriptionTypeRule {
bool check) {
Debug("typecheck-idt") << "typechecking ascription: " << n << std::endl;
Assert(n.getKind() == kind::APPLY_TYPE_ASCRIPTION);
- TypeNode t = TypeNode::fromType(
- n.getOperator().getConst<AscriptionType>().getType());
+ TypeNode t = n.getOperator().getConst<AscriptionType>().getType();
if (check) {
TypeNode childType = n[0].getType(check);
@@ -282,9 +281,10 @@ struct RecordUpdateTypeRule {
throw TypeCheckingExceptionPrivate(
n, "Record-update expression formed over non-record");
}
- const Record& rec =
- DatatypeType(recordType.toType()).getRecord();
- if (!rec.contains(ru.getField())) {
+ const DType& dt = recordType.getDType();
+ const DTypeConstructor& recCons = dt[0];
+ if (recCons.getSelectorIndexForName(ru.getField()) == -1)
+ {
std::stringstream ss;
ss << "Record-update field `" << ru.getField()
<< "' is not a valid field name for the record type";
diff --git a/src/theory/datatypes/theory_datatypes_utils.cpp b/src/theory/datatypes/theory_datatypes_utils.cpp
index 7020a0e04..c55b4a14f 100644
--- a/src/theory/datatypes/theory_datatypes_utils.cpp
+++ b/src/theory/datatypes/theory_datatypes_utils.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -55,7 +55,7 @@ Node getInstCons(Node n, const DType& dt, int index)
Debug("datatypes-parametric")
<< "Type specification is " << tspec << std::endl;
children[0] = nm->mkNode(APPLY_TYPE_ASCRIPTION,
- nm->mkConst(AscriptionType(tspec.toType())),
+ nm->mkConst(AscriptionType(tspec)),
children[0]);
n_ic = nm->mkNode(APPLY_CONSTRUCTOR, children);
Assert(n_ic.getType() == tn);
diff --git a/src/theory/datatypes/theory_datatypes_utils.h b/src/theory/datatypes/theory_datatypes_utils.h
index 1d106b9f1..6985e6bab 100644
--- a/src/theory/datatypes/theory_datatypes_utils.h
+++ b/src/theory/datatypes/theory_datatypes_utils.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/datatypes/type_enumerator.cpp b/src/theory/datatypes/type_enumerator.cpp
index 3dca74b19..079430342 100644
--- a/src/theory/datatypes/type_enumerator.cpp
+++ b/src/theory/datatypes/type_enumerator.cpp
@@ -2,10 +2,10 @@
/*! \file type_enumerator.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Morgan Deters
+ ** Andrew Reynolds, Morgan Deters, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -143,7 +143,7 @@ Node DatatypesEnumerator::getTermEnum( TypeNode tn, unsigned i ){
NodeManager* nm = NodeManager::currentNM();
TypeNode typ = ctor.getSpecializedConstructorType(d_type);
b << nm->mkNode(kind::APPLY_TYPE_ASCRIPTION,
- nm->mkConst(AscriptionType(typ.toType())),
+ nm->mkConst(AscriptionType(typ)),
ctor.getConstructor());
}
else
@@ -201,7 +201,20 @@ Node DatatypesEnumerator::getTermEnum( TypeNode tn, unsigned i ){
<< d_datatype.isRecursiveSingleton(d_type);
Debug("dt-enum") << " " << d_datatype.isInterpretedFinite(d_type)
<< std::endl;
-
+ // Start with the ground term constructed via mkGroundValue, which does
+ // a traversal over the structure of the datatype to find a finite term.
+ // Notice that mkGroundValue may be dependent upon extracting the first
+ // value of type enumerators for *other non-datatype* subfield types of
+ // this datatype. Since datatypes can not be embedded in non-datatype
+ // types (e.g. (Array D D) cannot be a subfield type of datatype D), this
+ // call is guaranteed to avoid infinite recursion. It is important that we
+ // start with this term, since it has the same shape as the one returned by
+ // TypeNode::mkGroundTerm for d_type, which avoids debug check model
+ // failures.
+ d_zeroTerm = d_datatype.mkGroundValue(d_type);
+ // Only use the zero term if it was successfully constructed. This may
+ // fail for codatatype types whose only values are infinite.
+ d_zeroTermActive = !d_zeroTerm.isNull();
if (d_datatype.isCodatatype() && hasCyclesDt(d_datatype))
{
// start with uninterpreted constant
@@ -214,15 +227,6 @@ Node DatatypesEnumerator::getTermEnum( TypeNode tn, unsigned i ){
{
// find the "zero" term via mkGroundTerm
Debug("dt-enum-debug") << "make ground term..." << std::endl;
- // Start with the ground term constructed via mkGroundValue, which does
- // a traversal over the structure of the datatype to find a finite term.
- // Notice that mkGroundValue may be dependent upon extracting the first
- // value of type enumerators for *other non-datatype* subfield types of
- // this datatype. Since datatypes can not be embedded in non-datatype
- // types (e.g. (Array D D) cannot be a subfield type of datatype D), this
- // call is guaranteed to avoid infinite recursion.
- d_zeroTerm = d_datatype.mkGroundValue(d_type);
- d_zeroTermActive = true;
Debug("dt-enum-debug") << "done : " << d_zeroTerm << std::endl;
Assert(d_zeroTerm.getKind() == kind::APPLY_CONSTRUCTOR);
d_has_debruijn = 0;
diff --git a/src/theory/datatypes/type_enumerator.h b/src/theory/datatypes/type_enumerator.h
index 1aa055bca..a0def66c5 100644
--- a/src/theory/datatypes/type_enumerator.h
+++ b/src/theory/datatypes/type_enumerator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/decision_manager.cpp b/src/theory/decision_manager.cpp
index de5ad2fb1..4137d0a8f 100644
--- a/src/theory/decision_manager.cpp
+++ b/src/theory/decision_manager.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/decision_manager.h b/src/theory/decision_manager.h
index fccac1190..8ee9a22fd 100644
--- a/src/theory/decision_manager.h
+++ b/src/theory/decision_manager.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -61,7 +61,6 @@ class DecisionManager
// "sat" for problems that are unsat.
STRAT_QUANT_CEGQI_FEASIBLE,
STRAT_QUANT_SYGUS_FEASIBLE,
- STRAT_QUANT_SYGUS_STREAM_FEASIBLE,
// placeholder for last model-sound required strategy
STRAT_LAST_M_SOUND,
diff --git a/src/theory/decision_strategy.cpp b/src/theory/decision_strategy.cpp
index 5a98aab8c..efb957138 100644
--- a/src/theory/decision_strategy.cpp
+++ b/src/theory/decision_strategy.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/decision_strategy.h b/src/theory/decision_strategy.h
index d8227da18..adcf1c428 100644
--- a/src/theory/decision_strategy.h
+++ b/src/theory/decision_strategy.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/eager_proof_generator.cpp b/src/theory/eager_proof_generator.cpp
index 9c25fb3e4..c49c33790 100644
--- a/src/theory/eager_proof_generator.cpp
+++ b/src/theory/eager_proof_generator.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,21 +14,26 @@
#include "theory/eager_proof_generator.h"
+#include "expr/proof.h"
#include "expr/proof_node_manager.h"
namespace CVC4 {
namespace theory {
EagerProofGenerator::EagerProofGenerator(ProofNodeManager* pnm,
- context::Context* c)
- : d_pnm(pnm), d_proofs(c == nullptr ? &d_context : c)
+ context::Context* c,
+ std::string name)
+ : d_pnm(pnm), d_name(name), d_proofs(c == nullptr ? &d_context : c)
{
}
void EagerProofGenerator::setProofFor(Node f, std::shared_ptr<ProofNode> pf)
{
// pf should prove f
- Assert(pf->getResult() == f);
+ Assert(pf->getResult() == f)
+ << "EagerProofGenerator::setProofFor: unexpected result" << std::endl
+ << "Expected: " << f << std::endl
+ << "Actual: " << pf->getResult() << std::endl;
d_proofs[f] = pf;
}
void EagerProofGenerator::setProofForConflict(Node conf,
@@ -92,14 +97,27 @@ TrustNode EagerProofGenerator::mkTrustNode(Node n,
return TrustNode::mkTrustLemma(n, this);
}
-TrustNode EagerProofGenerator::mkTrustNode(Node n,
+TrustNode EagerProofGenerator::mkTrustNode(Node conc,
PfRule id,
+ const std::vector<Node>& exp,
const std::vector<Node>& args,
bool isConflict)
{
- std::vector<std::shared_ptr<ProofNode>> children;
- std::shared_ptr<ProofNode> pf = d_pnm->mkNode(id, children, args, n);
- return mkTrustNode(n, pf, isConflict);
+ // if no children, its easy
+ if (exp.empty())
+ {
+ std::shared_ptr<ProofNode> pf = d_pnm->mkNode(id, {}, args, conc);
+ return mkTrustNode(conc, pf, isConflict);
+ }
+ // otherwise, we use CDProof + SCOPE
+ CDProof cdp(d_pnm);
+ cdp.addStep(conc, id, exp, args);
+ std::shared_ptr<ProofNode> pf = cdp.getProofFor(conc);
+ // We use mkNode instead of mkScope, since there is no reason to check
+ // whether the free assumptions of pf are in exp, since they are by the
+ // construction above.
+ std::shared_ptr<ProofNode> pfs = d_pnm->mkNode(PfRule::SCOPE, {pf}, exp);
+ return mkTrustNode(pfs->getResult(), pfs, isConflict);
}
TrustNode EagerProofGenerator::mkTrustedPropagation(
@@ -117,9 +135,10 @@ TrustNode EagerProofGenerator::mkTrustNodeSplit(Node f)
{
// make the lemma
Node lem = f.orNode(f.notNode());
- std::vector<Node> args;
- return mkTrustNode(lem, PfRule::SPLIT, args, false);
+ return mkTrustNode(lem, PfRule::SPLIT, {}, {f}, false);
}
+std::string EagerProofGenerator::identify() const { return d_name; }
+
} // namespace theory
} // namespace CVC4
diff --git a/src/theory/eager_proof_generator.h b/src/theory/eager_proof_generator.h
index 9a00f3612..29f916e00 100644
--- a/src/theory/eager_proof_generator.h
+++ b/src/theory/eager_proof_generator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -86,7 +86,9 @@ class EagerProofGenerator : public ProofGenerator
NodeProofNodeMap;
public:
- EagerProofGenerator(ProofNodeManager* pnm, context::Context* c = nullptr);
+ EagerProofGenerator(ProofNodeManager* pnm,
+ context::Context* c = nullptr,
+ std::string name = "EagerProofGenerator");
~EagerProofGenerator() {}
/** Get the proof for formula f. */
std::shared_ptr<ProofNode> getProofFor(Node f) override;
@@ -114,20 +116,21 @@ class EagerProofGenerator : public ProofGenerator
std::shared_ptr<ProofNode> pf,
bool isConflict = false);
/**
- * Make trust node from a single step proof (with no premises). This is a
- * convenience function that avoids the need to explictly construct ProofNode
- * by the caller.
+ * Make trust node from a single step proof. This is a convenience function
+ * that avoids the need to explictly construct ProofNode by the caller.
*
- * @param n The proven node,
- * @param id The rule of the proof concluding n
- * @param args The arguments to the proof concluding n,
+ * @param conc The conclusion of the rule,
+ * @param id The rule of the proof concluding conc
+ * @param exp The explanation (premises) to the proof concluding conc,
+ * @param args The arguments to the proof concluding conc,
* @param isConflict Whether the returned trust node is a conflict (otherwise
* it is a lemma),
* @return The trust node corresponding to the fact that this generator has
- * a proof of n.
+ * a proof of (children => exp), or of exp if children is empty.
*/
- TrustNode mkTrustNode(Node n,
+ TrustNode mkTrustNode(Node conc,
PfRule id,
+ const std::vector<Node>& exp,
const std::vector<Node>& args,
bool isConflict = false);
/**
@@ -152,7 +155,7 @@ class EagerProofGenerator : public ProofGenerator
TrustNode mkTrustNodeSplit(Node f);
//--------------------------------------- end common proofs
/** identify */
- std::string identify() const override { return "EagerProofGenerator"; }
+ std::string identify() const override;
protected:
/** Set that pf is the proof for conflict conf */
@@ -163,6 +166,8 @@ class EagerProofGenerator : public ProofGenerator
void setProofForPropExp(TNode lit, Node exp, std::shared_ptr<ProofNode> pf);
/** The proof node manager */
ProofNodeManager* d_pnm;
+ /** Name identifier */
+ std::string d_name;
/** A dummy context used by this class if none is provided */
context::Context d_context;
/**
diff --git a/src/theory/ee_manager.cpp b/src/theory/ee_manager.cpp
new file mode 100644
index 000000000..697689fb9
--- /dev/null
+++ b/src/theory/ee_manager.cpp
@@ -0,0 +1,50 @@
+/********************* */
+/*! \file ee_manager.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utilities for management of equality engines.
+ **/
+
+#include "theory/ee_manager.h"
+
+#include "theory/theory_model.h"
+
+namespace CVC4 {
+namespace theory {
+
+EqEngineManager::EqEngineManager(TheoryEngine& te, SharedSolver& shs)
+ : d_te(te), d_sharedSolver(shs)
+{
+}
+
+const EeTheoryInfo* EqEngineManager::getEeTheoryInfo(TheoryId tid) const
+{
+ std::map<TheoryId, EeTheoryInfo>::const_iterator it = d_einfo.find(tid);
+ if (it != d_einfo.end())
+ {
+ return &it->second;
+ }
+ return nullptr;
+}
+
+eq::EqualityEngine* EqEngineManager::allocateEqualityEngine(EeSetupInfo& esi,
+ context::Context* c)
+{
+ if (esi.d_notify != nullptr)
+ {
+ return new eq::EqualityEngine(
+ *esi.d_notify, c, esi.d_name, esi.d_constantsAreTriggers);
+ }
+ // the theory doesn't care about explicit notifications
+ return new eq::EqualityEngine(c, esi.d_name, esi.d_constantsAreTriggers);
+}
+
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/ee_manager.h b/src/theory/ee_manager.h
new file mode 100644
index 000000000..6e40ceb7b
--- /dev/null
+++ b/src/theory/ee_manager.h
@@ -0,0 +1,100 @@
+/********************* */
+/*! \file ee_manager.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utilities for management of equality engines.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__EE_MANAGER__H
+#define CVC4__THEORY__EE_MANAGER__H
+
+#include <map>
+#include <memory>
+
+#include "theory/ee_setup_info.h"
+#include "theory/theory.h"
+#include "theory/uf/equality_engine.h"
+
+namespace CVC4 {
+
+class TheoryEngine;
+
+namespace theory {
+
+class SharedSolver;
+
+/**
+ * This is (theory-agnostic) information associated with the management of
+ * an equality engine for a single theory. This information is maintained
+ * by the manager class below.
+ *
+ * Currently, this simply is the equality engine itself, for memory
+ * management purposes.
+ */
+struct EeTheoryInfo
+{
+ EeTheoryInfo() : d_usedEe(nullptr) {}
+ /** Equality engine that is used (if it exists) */
+ eq::EqualityEngine* d_usedEe;
+ /** Equality engine allocated specifically for this theory (if it exists) */
+ std::unique_ptr<eq::EqualityEngine> d_allocEe;
+};
+
+/** Virtual base class for equality engine managers */
+class EqEngineManager
+{
+ public:
+ /**
+ * @param te Reference to the theory engine
+ * @param sharedSolver The shared solver that is being used in combination
+ * with this equality engine manager
+ */
+ EqEngineManager(TheoryEngine& te, SharedSolver& shs);
+ virtual ~EqEngineManager() {}
+ /**
+ * Initialize theories, called during TheoryEngine::finishInit after theory
+ * objects have been created but prior to their final initialization. This
+ * sets up equality engines for all theories.
+ *
+ * This method is context-independent, and is applied once during
+ * the lifetime of TheoryEngine (during finishInit).
+ */
+ virtual void initializeTheories() = 0;
+ /**
+ * Get the equality engine theory information for theory with the given id.
+ */
+ const EeTheoryInfo* getEeTheoryInfo(TheoryId tid) const;
+ /**
+ * Get the core equality engine, which is the equality engine that the
+ * quantifiers engine should use. This corresponds to the master equality
+ * engine if eeMode is distributed, or the central equality engine if eeMode
+ * is central.
+ */
+ virtual eq::EqualityEngine* getCoreEqualityEngine() = 0;
+
+ /** Allocate equality engine that is context-dependent on c with info esi */
+ eq::EqualityEngine* allocateEqualityEngine(EeSetupInfo& esi,
+ context::Context* c);
+
+ protected:
+ /** Reference to the theory engine */
+ TheoryEngine& d_te;
+ /** Reference to the shared solver */
+ SharedSolver& d_sharedSolver;
+ /** Information related to the equality engine, per theory. */
+ std::map<TheoryId, EeTheoryInfo> d_einfo;
+};
+
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__EE_MANAGER__H */
diff --git a/src/theory/ee_manager_distributed.cpp b/src/theory/ee_manager_distributed.cpp
new file mode 100644
index 000000000..3fb5fc0ce
--- /dev/null
+++ b/src/theory/ee_manager_distributed.cpp
@@ -0,0 +1,123 @@
+/********************* */
+/*! \file ee_manager_distributed.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Management of a distributed approach for equality sharing.
+ **/
+
+#include "theory/ee_manager_distributed.h"
+
+#include "theory/quantifiers_engine.h"
+#include "theory/shared_solver.h"
+#include "theory/theory_engine.h"
+
+namespace CVC4 {
+namespace theory {
+
+EqEngineManagerDistributed::EqEngineManagerDistributed(TheoryEngine& te,
+ SharedSolver& shs)
+ : EqEngineManager(te, shs), d_masterEENotify(nullptr)
+{
+}
+
+EqEngineManagerDistributed::~EqEngineManagerDistributed()
+{
+}
+
+void EqEngineManagerDistributed::initializeTheories()
+{
+ context::Context* c = d_te.getSatContext();
+ // initialize the shared solver
+ EeSetupInfo esis;
+ if (d_sharedSolver.needsEqualityEngine(esis))
+ {
+ // allocate an equality engine for the shared terms database
+ d_stbEqualityEngine.reset(allocateEqualityEngine(esis, c));
+ d_sharedSolver.setEqualityEngine(d_stbEqualityEngine.get());
+ }
+ else
+ {
+ Unhandled() << "Expected shared solver to use equality engine";
+ }
+
+ // allocate equality engines per theory
+ for (TheoryId theoryId = theory::THEORY_FIRST;
+ theoryId != theory::THEORY_LAST;
+ ++theoryId)
+ {
+ Theory* t = d_te.theoryOf(theoryId);
+ if (t == nullptr)
+ {
+ // theory not active, skip
+ continue;
+ }
+ // always allocate an object in d_einfo here
+ EeTheoryInfo& eet = d_einfo[theoryId];
+ EeSetupInfo esi;
+ if (!t->needsEqualityEngine(esi))
+ {
+ // theory said it doesn't need an equality engine, skip
+ continue;
+ }
+ // allocate the equality engine
+ eet.d_allocEe.reset(allocateEqualityEngine(esi, c));
+ // the theory uses the equality engine
+ eet.d_usedEe = eet.d_allocEe.get();
+ }
+
+ const LogicInfo& logicInfo = d_te.getLogicInfo();
+ if (logicInfo.isQuantified())
+ {
+ // construct the master equality engine
+ Assert(d_masterEqualityEngine == nullptr);
+ QuantifiersEngine* qe = d_te.getQuantifiersEngine();
+ Assert(qe != nullptr);
+ d_masterEENotify.reset(new MasterNotifyClass(qe));
+ d_masterEqualityEngine.reset(new eq::EqualityEngine(*d_masterEENotify.get(),
+ d_te.getSatContext(),
+ "theory::master",
+ false));
+
+ for (TheoryId theoryId = theory::THEORY_FIRST;
+ theoryId != theory::THEORY_LAST;
+ ++theoryId)
+ {
+ Theory* t = d_te.theoryOf(theoryId);
+ if (t == nullptr)
+ {
+ // theory not active, skip
+ continue;
+ }
+ EeTheoryInfo& eet = d_einfo[theoryId];
+ // Get the allocated equality engine, and connect it to the master
+ // equality engine.
+ eq::EqualityEngine* eeAlloc = eet.d_allocEe.get();
+ if (eeAlloc != nullptr)
+ {
+ // set the master equality engine of the theory's equality engine
+ eeAlloc->setMasterEqualityEngine(d_masterEqualityEngine.get());
+ }
+ }
+ }
+}
+
+void EqEngineManagerDistributed::MasterNotifyClass::eqNotifyNewClass(TNode t)
+{
+ // adds t to the quantifiers term database
+ d_quantEngine->eqNotifyNewClass(t);
+}
+
+eq::EqualityEngine* EqEngineManagerDistributed::getCoreEqualityEngine()
+{
+ return d_masterEqualityEngine.get();
+}
+
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/ee_manager_distributed.h b/src/theory/ee_manager_distributed.h
new file mode 100644
index 000000000..c7c1e7f4c
--- /dev/null
+++ b/src/theory/ee_manager_distributed.h
@@ -0,0 +1,99 @@
+/********************* */
+/*! \file ee_manager_distributed.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Management of a distributed approach for equality engines over
+ ** all theories.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__EE_MANAGER_DISTRIBUTED__H
+#define CVC4__THEORY__EE_MANAGER_DISTRIBUTED__H
+
+#include <map>
+#include <memory>
+
+#include "theory/ee_manager.h"
+#include "theory/uf/equality_engine.h"
+
+namespace CVC4 {
+namespace theory {
+
+/**
+ * The (distributed) equality engine manager. This encapsulates an architecture
+ * in which all theories maintain their own copy of an equality engine.
+ *
+ * This class is not responsible for actually initializing equality engines in
+ * theories (since this class does not have access to the internals of Theory).
+ * Instead, it is only responsible for the construction of the equality
+ * engine objects themselves. TheoryEngine is responsible for querying this
+ * class during finishInit() to determine the equality engines to pass to each
+ * theories based on getEeTheoryInfo.
+ *
+ * This class is also responsible for setting up the master equality engine,
+ * which is used as a special communication channel to quantifiers engine (e.g.
+ * for ensuring quantifiers E-matching is aware of terms from all theories).
+ */
+class EqEngineManagerDistributed : public EqEngineManager
+{
+ public:
+ EqEngineManagerDistributed(TheoryEngine& te, SharedSolver& shs);
+ ~EqEngineManagerDistributed();
+ /**
+ * Initialize theories. This method allocates unique equality engines
+ * per theories and connects them to a master equality engine.
+ */
+ void initializeTheories() override;
+ /** get the core equality engine */
+ eq::EqualityEngine* getCoreEqualityEngine() override;
+ private:
+ /** notify class for master equality engine */
+ class MasterNotifyClass : public theory::eq::EqualityEngineNotify
+ {
+ public:
+ MasterNotifyClass(QuantifiersEngine* qe) : d_quantEngine(qe) {}
+ /**
+ * Called when a new equivalence class is created in the master equality
+ * engine.
+ */
+ void eqNotifyNewClass(TNode t) override;
+
+ bool eqNotifyTriggerPredicate(TNode predicate, bool value) override
+ {
+ return true;
+ }
+ bool eqNotifyTriggerTermEquality(TheoryId tag,
+ TNode t1,
+ TNode t2,
+ bool value) override
+ {
+ return true;
+ }
+ void eqNotifyConstantTermMerge(TNode t1, TNode t2) override {}
+ void eqNotifyMerge(TNode t1, TNode t2) override {}
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override {}
+
+ private:
+ /** Pointer to quantifiers engine */
+ QuantifiersEngine* d_quantEngine;
+ };
+ /** The master equality engine notify class */
+ std::unique_ptr<MasterNotifyClass> d_masterEENotify;
+ /** The master equality engine. */
+ std::unique_ptr<eq::EqualityEngine> d_masterEqualityEngine;
+ /** The equality engine of the shared solver / shared terms database. */
+ std::unique_ptr<eq::EqualityEngine> d_stbEqualityEngine;
+};
+
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__EE_MANAGER_DISTRIBUTED__H */
diff --git a/src/theory/ee_setup_info.h b/src/theory/ee_setup_info.h
new file mode 100644
index 000000000..78f2f211e
--- /dev/null
+++ b/src/theory/ee_setup_info.h
@@ -0,0 +1,52 @@
+/********************* */
+/*! \file ee_setup_info.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Setup information for an equality engine.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__EE_SETUP_INFO__H
+#define CVC4__THEORY__EE_SETUP_INFO__H
+
+#include <string>
+
+namespace CVC4 {
+namespace theory {
+
+namespace eq {
+class EqualityEngineNotify;
+}
+
+/**
+ * This is a helper class that encapsulates instructions for how a Theory
+ * wishes to initialize and setup notifications with its official equality
+ * engine, e.g. via a notification class (eq::EqualityEngineNotify).
+ *
+ * This includes (at a basic level) the arguments to the equality engine
+ * constructor that theories may wish to modify. This information is determined
+ * by the Theory during needsEqualityEngine.
+ */
+struct EeSetupInfo
+{
+ EeSetupInfo() : d_notify(nullptr), d_constantsAreTriggers(true) {}
+ /** The notification class of the theory */
+ eq::EqualityEngineNotify* d_notify;
+ /** The name of the equality engine */
+ std::string d_name;
+ /** Constants are triggers */
+ bool d_constantsAreTriggers;
+};
+
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__EE_SETUP_INFO__H */
diff --git a/src/theory/engine_output_channel.cpp b/src/theory/engine_output_channel.cpp
index d83d2ba62..cb346d02d 100644
--- a/src/theory/engine_output_channel.cpp
+++ b/src/theory/engine_output_channel.cpp
@@ -2,10 +2,10 @@
/*! \file engine_output_channel.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Guy Katz, Tim King
+ ** Andrew Reynolds, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,10 +14,6 @@
#include "theory/engine_output_channel.h"
-#include "proof/cnf_proof.h"
-#include "proof/lemma_proof.h"
-#include "proof/proof_manager.h"
-#include "proof/theory_proof.h"
#include "prop/prop_engine.h"
#include "smt/smt_statistics_registry.h"
#include "theory/theory_engine.h"
@@ -71,161 +67,23 @@ void EngineOutputChannel::safePoint(ResourceManager::Resource r)
}
}
-theory::LemmaStatus EngineOutputChannel::lemma(TNode lemma,
- ProofRule rule,
- bool removable,
- bool preprocess,
- bool sendAtoms)
+theory::LemmaStatus EngineOutputChannel::lemma(TNode lemma, LemmaProperty p)
{
Debug("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma("
<< lemma << ")"
- << ", preprocess = " << preprocess << std::endl;
+ << ", properties = " << p << std::endl;
++d_statistics.lemmas;
d_engine->d_outputChannelUsed = true;
- PROOF({ registerLemmaRecipe(lemma, lemma, preprocess, d_theory); });
-
TrustNode tlem = TrustNode::mkTrustLemma(lemma);
- theory::LemmaStatus result =
- d_engine->lemma(tlem.getNode(),
- rule,
- false,
- removable,
- preprocess,
- sendAtoms ? d_theory : theory::THEORY_LAST);
+ theory::LemmaStatus result = d_engine->lemma(
+ tlem,
+ p,
+ isLemmaPropertySendAtoms(p) ? d_theory : theory::THEORY_LAST,
+ d_theory);
return result;
}
-void EngineOutputChannel::registerLemmaRecipe(Node lemma,
- Node originalLemma,
- bool preprocess,
- theory::TheoryId theoryId)
-{
- // During CNF conversion, conjunctions will be broken down into
- // multiple lemmas. In order for the recipes to match, we have to do
- // the same here.
- NodeManager* nm = NodeManager::currentNM();
-
- if (preprocess) lemma = d_engine->preprocess(lemma);
-
- bool negated = (lemma.getKind() == NOT);
- Node nnLemma = negated ? lemma[0] : lemma;
-
- switch (nnLemma.getKind())
- {
- case AND:
- if (!negated)
- {
- for (unsigned i = 0; i < nnLemma.getNumChildren(); ++i)
- registerLemmaRecipe(nnLemma[i], originalLemma, false, theoryId);
- }
- else
- {
- NodeBuilder<> builder(OR);
- for (unsigned i = 0; i < nnLemma.getNumChildren(); ++i)
- builder << nnLemma[i].negate();
-
- Node disjunction =
- (builder.getNumChildren() == 1) ? builder[0] : builder;
- registerLemmaRecipe(disjunction, originalLemma, false, theoryId);
- }
- break;
-
- case EQUAL:
- if (nnLemma[0].getType().isBoolean())
- {
- if (!negated)
- {
- registerLemmaRecipe(nm->mkNode(OR, nnLemma[0], nnLemma[1].negate()),
- originalLemma,
- false,
- theoryId);
- registerLemmaRecipe(nm->mkNode(OR, nnLemma[0].negate(), nnLemma[1]),
- originalLemma,
- false,
- theoryId);
- }
- else
- {
- registerLemmaRecipe(nm->mkNode(OR, nnLemma[0], nnLemma[1]),
- originalLemma,
- false,
- theoryId);
- registerLemmaRecipe(
- nm->mkNode(OR, nnLemma[0].negate(), nnLemma[1].negate()),
- originalLemma,
- false,
- theoryId);
- }
- }
- break;
-
- case ITE:
- if (!negated)
- {
- registerLemmaRecipe(nm->mkNode(OR, nnLemma[0].negate(), nnLemma[1]),
- originalLemma,
- false,
- theoryId);
- registerLemmaRecipe(nm->mkNode(OR, nnLemma[0], nnLemma[2]),
- originalLemma,
- false,
- theoryId);
- }
- else
- {
- registerLemmaRecipe(
- nm->mkNode(OR, nnLemma[0].negate(), nnLemma[1].negate()),
- originalLemma,
- false,
- theoryId);
- registerLemmaRecipe(nm->mkNode(OR, nnLemma[0], nnLemma[2].negate()),
- originalLemma,
- false,
- theoryId);
- }
- break;
-
- default: break;
- }
-
- // Theory lemmas have one step that proves the empty clause
- LemmaProofRecipe proofRecipe;
- Node emptyNode;
- LemmaProofRecipe::ProofStep proofStep(theoryId, emptyNode);
-
- // Remember the original lemma, so we can report this later when asked to
- proofRecipe.setOriginalLemma(originalLemma);
-
- // Record the assertions and rewrites
- Node rewritten;
- if (lemma.getKind() == OR)
- {
- for (unsigned i = 0; i < lemma.getNumChildren(); ++i)
- {
- rewritten = theory::Rewriter::rewrite(lemma[i]);
- if (rewritten != lemma[i])
- {
- proofRecipe.addRewriteRule(lemma[i].negate(), rewritten.negate());
- }
- proofStep.addAssertion(lemma[i]);
- proofRecipe.addBaseAssertion(rewritten);
- }
- }
- else
- {
- rewritten = theory::Rewriter::rewrite(lemma);
- if (rewritten != lemma)
- {
- proofRecipe.addRewriteRule(lemma.negate(), rewritten.negate());
- }
- proofStep.addAssertion(lemma);
- proofRecipe.addBaseAssertion(rewritten);
- }
- proofRecipe.addStep(proofStep);
- ProofManager::getCnfProof()->setProofRecipe(&proofRecipe);
-}
-
theory::LemmaStatus EngineOutputChannel::splitLemma(TNode lemma, bool removable)
{
Debug("theory::lemma") << "EngineOutputChannel<" << d_theory << ">::lemma("
@@ -236,8 +94,8 @@ theory::LemmaStatus EngineOutputChannel::splitLemma(TNode lemma, bool removable)
Debug("pf::explain") << "EngineOutputChannel::splitLemma( " << lemma << " )"
<< std::endl;
TrustNode tlem = TrustNode::mkTrustLemma(lemma);
- theory::LemmaStatus result = d_engine->lemma(
- tlem.getNode(), RULE_SPLIT, false, removable, false, d_theory);
+ LemmaProperty p = removable ? LemmaProperty::REMOVABLE : LemmaProperty::NONE;
+ theory::LemmaStatus result = d_engine->lemma(tlem, p, d_theory);
return result;
}
@@ -250,17 +108,15 @@ bool EngineOutputChannel::propagate(TNode literal)
return d_engine->propagate(literal, d_theory);
}
-void EngineOutputChannel::conflict(TNode conflictNode,
- std::unique_ptr<Proof> proof)
+void EngineOutputChannel::conflict(TNode conflictNode)
{
Trace("theory::conflict")
<< "EngineOutputChannel<" << d_theory << ">::conflict(" << conflictNode
<< ")" << std::endl;
- Assert(!proof); // Theory shouldn't be producing proofs yet
++d_statistics.conflicts;
d_engine->d_outputChannelUsed = true;
TrustNode tConf = TrustNode::mkTrustConflict(conflictNode);
- d_engine->conflict(tConf.getNode(), d_theory);
+ d_engine->conflict(tConf, d_theory);
}
void EngineOutputChannel::demandRestart()
@@ -273,7 +129,7 @@ void EngineOutputChannel::demandRestart()
Trace("theory::restart") << "EngineOutputChannel<" << d_theory
<< ">::restart(" << restartVar << ")" << std::endl;
++d_statistics.restartDemands;
- lemma(restartVar, RULE_INVALID, true);
+ lemma(restartVar, LemmaProperty::REMOVABLE);
}
void EngineOutputChannel::requirePhase(TNode n, bool phase)
@@ -305,22 +161,21 @@ void EngineOutputChannel::trustedConflict(TrustNode pconf)
{
Assert(pconf.getKind() == TrustNodeKind::CONFLICT);
Trace("theory::conflict")
- << "EngineOutputChannel<" << d_theory << ">::conflict(" << pconf.getNode()
- << ")" << std::endl;
+ << "EngineOutputChannel<" << d_theory << ">::trustedConflict("
+ << pconf.getNode() << ")" << std::endl;
if (pconf.getGenerator() != nullptr)
{
++d_statistics.trustedConflicts;
}
++d_statistics.conflicts;
d_engine->d_outputChannelUsed = true;
- d_engine->conflict(pconf.getNode(), d_theory);
+ d_engine->conflict(pconf, d_theory);
}
-LemmaStatus EngineOutputChannel::trustedLemma(TrustNode plem,
- bool removable,
- bool preprocess,
- bool sendAtoms)
+LemmaStatus EngineOutputChannel::trustedLemma(TrustNode plem, LemmaProperty p)
{
+ Debug("theory::lemma") << "EngineOutputChannel<" << d_theory
+ << ">::trustedLemma(" << plem << ")" << std::endl;
Assert(plem.getKind() == TrustNodeKind::LEMMA);
if (plem.getGenerator() != nullptr)
{
@@ -329,12 +184,11 @@ LemmaStatus EngineOutputChannel::trustedLemma(TrustNode plem,
++d_statistics.lemmas;
d_engine->d_outputChannelUsed = true;
// now, call the normal interface for lemma
- return d_engine->lemma(plem.getNode(),
- RULE_INVALID,
- false,
- removable,
- preprocess,
- sendAtoms ? d_theory : theory::THEORY_LAST);
+ return d_engine->lemma(
+ plem,
+ p,
+ isLemmaPropertySendAtoms(p) ? d_theory : theory::THEORY_LAST,
+ d_theory);
}
} // namespace theory
diff --git a/src/theory/engine_output_channel.h b/src/theory/engine_output_channel.h
index d7b26928d..7a59dbf2a 100644
--- a/src/theory/engine_output_channel.h
+++ b/src/theory/engine_output_channel.h
@@ -2,10 +2,10 @@
/*! \file engine_output_channel.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Tim King, Dejan Jovanovic
+ ** Andrew Reynolds, Tim King, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -45,15 +45,11 @@ class EngineOutputChannel : public theory::OutputChannel
void safePoint(ResourceManager::Resource r) override;
- void conflict(TNode conflictNode,
- std::unique_ptr<Proof> pf = nullptr) override;
+ void conflict(TNode conflictNode) override;
bool propagate(TNode literal) override;
theory::LemmaStatus lemma(TNode lemma,
- ProofRule rule,
- bool removable = false,
- bool preprocess = false,
- bool sendAtoms = false) override;
+ LemmaProperty p = LemmaProperty::NONE) override;
theory::LemmaStatus splitLemma(TNode lemma, bool removable = false) override;
@@ -81,9 +77,7 @@ class EngineOutputChannel : public theory::OutputChannel
* the same as calling OutputChannel::lemma on lem.
*/
LemmaStatus trustedLemma(TrustNode plem,
- bool removable = false,
- bool preprocess = false,
- bool sendAtoms = false) override;
+ LemmaProperty p = LemmaProperty::NONE) override;
protected:
/**
diff --git a/src/theory/evaluator.cpp b/src/theory/evaluator.cpp
index 7a4940328..fb7034d2c 100644
--- a/src/theory/evaluator.cpp
+++ b/src/theory/evaluator.cpp
@@ -5,7 +5,7 @@
** Andres Noetzli, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -43,6 +43,10 @@ EvalResult::EvalResult(const EvalResult& other)
new (&d_str) String;
d_str = other.d_str;
break;
+ case UCONST:
+ new (&d_uc)
+ UninterpretedConstant(other.d_uc.getType(), other.d_uc.getIndex());
+ break;
case INVALID: break;
}
}
@@ -67,6 +71,10 @@ EvalResult& EvalResult::operator=(const EvalResult& other)
new (&d_str) String;
d_str = other.d_str;
break;
+ case UCONST:
+ new (&d_uc)
+ UninterpretedConstant(other.d_uc.getType(), other.d_uc.getIndex());
+ break;
case INVALID: break;
}
}
@@ -91,9 +99,13 @@ EvalResult::~EvalResult()
{
d_str.~String();
break;
-
- default: break;
}
+ case UCONST:
+ {
+ d_uc.~UninterpretedConstant();
+ break;
+ }
+ default: break;
}
}
@@ -106,6 +118,7 @@ Node EvalResult::toNode() const
case EvalResult::BITVECTOR: return nm->mkConst(d_bv);
case EvalResult::RATIONAL: return nm->mkConst(d_rat);
case EvalResult::STRING: return nm->mkConst(d_str);
+ case EvalResult::UCONST: return nm->mkConst(d_uc);
default:
{
Trace("evaluator") << "Missing conversion from " << d_tag << " to node"
@@ -389,7 +402,13 @@ EvalResult Evaluator::evalInternal(
results[currNode] = EvalResult(r);
break;
}
-
+ case kind::UNINTERPRETED_CONSTANT:
+ {
+ const UninterpretedConstant& uc =
+ currNodeVal.getConst<UninterpretedConstant>();
+ results[currNode] = EvalResult(uc);
+ break;
+ }
case kind::PLUS:
{
Rational res = results[currNode[0]].d_rat;
@@ -824,6 +843,11 @@ EvalResult Evaluator::evalInternal(
results[currNode] = EvalResult(lhs.d_str == rhs.d_str);
break;
}
+ case EvalResult::UCONST:
+ {
+ results[currNode] = EvalResult(lhs.d_uc == rhs.d_uc);
+ break;
+ }
default:
{
diff --git a/src/theory/evaluator.h b/src/theory/evaluator.h
index e986edf1f..f1b0083b3 100644
--- a/src/theory/evaluator.h
+++ b/src/theory/evaluator.h
@@ -2,10 +2,10 @@
/*! \file evaluator.h
** \verbatim
** Top contributors (to current version):
- ** Andres Noetzli, Andrew Reynolds, Mathias Preiner
+ ** Andrew Reynolds, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,6 +25,7 @@
#include "base/output.h"
#include "expr/node.h"
+#include "expr/uninterpreted_constant.h"
#include "util/bitvector.h"
#include "util/rational.h"
#include "util/string.h"
@@ -45,6 +46,7 @@ struct EvalResult
BITVECTOR,
RATIONAL,
STRING,
+ UCONST,
INVALID
} d_tag;
@@ -55,6 +57,7 @@ struct EvalResult
BitVector d_bv;
Rational d_rat;
String d_str;
+ UninterpretedConstant d_uc;
};
EvalResult(const EvalResult& other);
@@ -63,6 +66,7 @@ struct EvalResult
EvalResult(const BitVector& bv) : d_tag(BITVECTOR), d_bv(bv) {}
EvalResult(const Rational& i) : d_tag(RATIONAL), d_rat(i) {}
EvalResult(const String& str) : d_tag(STRING), d_str(str) {}
+ EvalResult(const UninterpretedConstant& u) : d_tag(UCONST), d_uc(u) {}
EvalResult& operator=(const EvalResult& other);
diff --git a/src/theory/example/ecdata.cpp b/src/theory/example/ecdata.cpp
deleted file mode 100644
index bc19f657b..000000000
--- a/src/theory/example/ecdata.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/********************* */
-/*! \file ecdata.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Morgan Deters
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of equivalence class data for UF theory.
- **
- ** Implementation of equivalence class data for UF theory. This is a
- ** context-dependent object.
- **/
-
-#include "theory/uf/tim/ecdata.h"
-
-using namespace CVC4;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::uf;
-using namespace CVC4::theory::uf::tim;
-
-ECData::ECData(Context * context, TNode n) :
- ContextObj(context),
- d_find(this),
- d_rep(n),
- d_watchListSize(0),
- d_first(NULL),
- d_last(NULL) {
-}
-
-bool ECData::isClassRep() {
- return this == this->d_find;
-}
-
-void ECData::addPredecessor(TNode n) {
- Assert(isClassRep());
-
- makeCurrent();
-
- Link * newPred = new(getCMM()) Link(getContext(), n, d_first);
- d_first = newPred;
- if(d_last == NULL) {
- d_last = newPred;
- }
-
- ++d_watchListSize;
-}
-
-ContextObj* ECData::save(ContextMemoryManager* pCMM) {
- return new(pCMM) ECData(*this);
-}
-
-void ECData::restore(ContextObj* pContextObj) {
- ECData* data = (ECData*)pContextObj;
- d_find = data->d_find;
- d_first = data->d_first;
- d_last = data->d_last;
- d_rep = data->d_rep;
- d_watchListSize = data->d_watchListSize;
-}
-
-Node ECData::getRep() {
- return d_rep;
-}
-
-unsigned ECData::getWatchListSize() {
- return d_watchListSize;
-}
-
-void ECData::setFind(ECData * ec) {
- makeCurrent();
- d_find = ec;
-}
-
-ECData* ECData::getFind() {
- return d_find;
-}
-
-Link* ECData::getFirst() {
- return d_first;
-}
-
-void ECData::takeOverDescendantWatchList(ECData* nslave, ECData* nmaster) {
- Assert(nslave != nmaster);
- Assert(nslave->getFind() == nmaster);
-
- nmaster->makeCurrent();
-
- nmaster->d_watchListSize += nslave->d_watchListSize;
-
- if(nmaster->d_first == NULL) {
- nmaster->d_first = nslave->d_first;
- nmaster->d_last = nslave->d_last;
- } else if(nslave->d_first != NULL) {
- Link* currLast = nmaster->d_last;
- currLast->d_next = nslave->d_first;
- nmaster->d_last = nslave->d_last;
- }
-}
diff --git a/src/theory/example/ecdata.h b/src/theory/example/ecdata.h
deleted file mode 100644
index 7b8fcaef5..000000000
--- a/src/theory/example/ecdata.h
+++ /dev/null
@@ -1,258 +0,0 @@
-/********************* */
-/*! \file ecdata.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Morgan Deters, Mathias Preiner, Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Context dependent equivalence class datastructure for nodes.
- **
- ** Context dependent equivalence class datastructure for nodes.
- ** Currently keeps a context dependent watch list.
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__THEORY__UF__TIM__ECDATA_H
-#define CVC4__THEORY__UF__TIM__ECDATA_H
-
-#include "expr/node.h"
-#include "context/context.h"
-#include "context/cdo.h"
-#include "context/context_mm.h"
-
-namespace CVC4 {
-namespace theory {
-namespace uf {
-namespace tim {
-
-/**
- * Link is a context dependent linked list of nodes.
- * Link is intended to be allocated in a Context's memory manager.
- * The next pointer of the list is context dependent, but the node being
- * pointed to is fixed for the life of the Link.
- *
- * Clients of Link are intended not to modify the node that is being pointed
- * to in good faith. This may change in the future.
- */
-struct Link {
- /**
- * Pointer to the next element in linked list.
- * This is context dependent.
- */
- context::CDO<Link*> d_next;
-
- /**
- * Link is supposed to be allocated in a region of a
- * ContextMemoryManager. In order to avoid having to decrement the
- * ref count at deletion time, it is preferrable for the user of
- * Link to maintain the invariant that data will survival for the
- * entire scope of the TNode.
- */
- TNode d_data;
-
- /**
- * Creates a new Link w.r.t. a context for the node n.
- * An optional parameter is to specify the next element in the link.
- */
- Link(context::Context* context, TNode n, Link* l = NULL) :
- d_next(true, context, l),
- d_data(n) {
- Debug("context") << "Link: " << this
- << " so cdo is " << &d_next << std::endl;
- }
-
- /**
- * Allocates a new Link in the region for the provided ContextMemoryManager.
- * This allows for cheap cleanup on pop.
- */
- static void* operator new(size_t size, context::ContextMemoryManager* pCMM) {
- return pCMM->newData(size);
- }
-
- private:
- /**
- * The destructor isn't actually defined. This declaration keeps
- * the compiler from creating (wastefully) a default definition, and
- * ensures that we get a link error if someone uses Link in a way
- * that requires destruction. Objects of class Link should always
- * be allocated in a ContextMemoryManager, which doesn't call
- * destructors.
- */
- ~Link();
-
- /**
- * Just like the destructor, this is not defined. This ensures no
- * one tries to create a Link on the heap.
- */
- static void* operator new(size_t size);
-
-};/* struct Link */
-
-
-/**
- * ECData is a equivalence class object that is context dependent.
- * It is developed in order to support the congruence closure algorithm
- * in TheoryUF, and is not intended to be used outside of that package.
- *
- * ECData maintains:
- * - find pointer for the equivalence class (disjoint set forest)
- * - the node that represents the equivalence class.
- * - maintains a predecessorlist/watchlist
- *
- * ECData does not have support for the canonical find and union operators
- * for disjoint set forests. Instead it only provides access to the find
- * pointer. The implementation of find is ccFind in TheoryUF.
- * union is broken into 2 phases:
- * 1) setting the find point with setFind
- * 2) taking over the watch list of the other node.
- * This is a technical requirement for the implementation of TheoryUF.
- * (See ccUnion in TheoryUF for more information.)
- *
- * The intended paradigm for iterating over the watch list of ec is:
- * for(Link* i = ec->getFirst(); i != NULL; i = i->next );
- *
- * See also ECAttr() in theory_uf.h, and theory_uf.cpp where the codde that uses
- * ECData lives.
- */
-class ECData : public context::ContextObj {
-private:
- /**
- * This is the standard disjoint set forest find pointer.
- *
- * Why an ECData pointer instead of a node?
- * This was chosen to be a ECData pointer in order to shortcut at least one
- * table every time the find pointer is examined.
- */
- ECData* d_find;
-
- /**
- * This is pointer back to the node that represents this equivalence class.
- *
- * The following invariant should be maintained:
- * (n.getAttribute(ECAttr()))->rep == n
- * i.e. rep is equal to the node that maps to the ECData using ECAttr.
- *
- * Tricky part: This needs to be a TNode, not a Node.
- * Suppose that rep were a hard link.
- * When a node n maps to an ECData via the ECAttr() there will be a hard
- * link back to n in the ECData. The attribute does not do garbage collection
- * until the node gets garbage collected, which does not happen until its
- * ref count drops to 0. So because of this cycle neither the node and
- * the ECData will never get garbage collected.
- * So this needs to be a soft link.
- */
- TNode d_rep;
-
- // Watch list data structures follow
-
- /**
- * Maintains watch list size for more efficient merging.
- */
- unsigned d_watchListSize;
-
- /**
- * Pointer to the beginning of the watchlist.
- * This value is NULL iff the watch list is empty.
- */
- Link* d_first;
-
- /**
- * Pointer to the end of the watch-list.
- * This is maintained in order to constant time list merging.
- * (This does not give any asymptotic improve as this is currently always
- * preceeded by an O(|watchlist|) operation.)
- * This value is NULL iff the watch list is empty.
- */
- Link* d_last;
-
- /** Context-dependent operation: save this ECData */
- context::ContextObj* save(context::ContextMemoryManager* pCMM);
-
- /** Context-dependent operation: restore this ECData */
- void restore(context::ContextObj* pContextObj);
-
-public:
- /**
- * Returns true if this ECData object is the current representative of
- * the equivalence class.
- */
- bool isClassRep();
-
- /**
- * Adds a node to the watch list of the equivalence class. Does
- * context-dependent memory allocation in the Context with which
- * this ECData was created.
- *
- * @param n the node to be added.
- * @pre isClassRep() == true
- */
- void addPredecessor(TNode n);
-
- /**
- * Creates a EQ with the representative n
- * @param context the context to associate with this ecdata.
- * This is required as ECData is context dependent
- * @param n the node that corresponds to this ECData
- */
- ECData(context::Context* context, TNode n);
-
- /** Destructor for ECDatas */
- ~ECData() {
- Debug("ufgc") << "Calling ECData destructor" << std::endl;
- destroy();
- }
-
- /**
- * An ECData takes over the watch list of another ECData.
- * This is the second step in the union operator for ECData.
- * This should be called after nslave->setFind(nmaster);
- * After this is done nslave's watch list should never be accessed by
- * getLast() or getFirst()
- */
- static void takeOverDescendantWatchList(ECData * nslave, ECData * nmaster);
-
- /**
- * Returns the representative of this ECData.
- */
- Node getRep();
-
- /**
- * Returns the size of the equivalence class.
- */
- unsigned getWatchListSize();
-
- /**
- * Returns a pointer the first member of the watch list.
- */
- Link* getFirst();
-
-
- /**
- * Returns the find pointer of the ECData.
- * If isClassRep(), then getFind() == this
- */
- ECData* getFind();
-
- /**
- * Sets the find pointer of the equivalence class to be another ECData object.
- *
- * @pre isClassRep() == true
- * @pre ec->isClassRep() == true
- * @post isClassRep() == false
- * @post ec->isClassRep() == true
- */
- void setFind(ECData * ec);
-
-};/* class ECData */
-
-}/* CVC4::theory::uf::tim namespace */
-}/* CVC4::theory::uf namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* CVC4__THEORY__UF__TIM__ECDATA_H */
diff --git a/src/theory/example/theory_uf_tim.cpp b/src/theory/example/theory_uf_tim.cpp
deleted file mode 100644
index 07cad60e5..000000000
--- a/src/theory/example/theory_uf_tim.cpp
+++ /dev/null
@@ -1,327 +0,0 @@
-/********************* */
-/*! \file theory_uf_tim.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Morgan Deters, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Implementation of the theory of uninterpreted functions.
- **
- ** Implementation of the theory of uninterpreted functions.
- **/
-
-#include "theory/uf/tim/theory_uf_tim.h"
-#include "theory/uf/tim/ecdata.h"
-#include "expr/kind.h"
-
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::uf;
-using namespace CVC4::theory::uf::tim;
-
-TheoryUFTim::TheoryUFTim(Context* c, UserContext* u, OutputChannel& out, Valuation valuation) :
- Theory(THEORY_UF, c, u, out, valuation),
- d_assertions(c),
- d_pending(c),
- d_currentPendingIdx(c,0),
- d_disequality(c),
- d_registered(c) {
- Warning() << "NOTE:" << std::endl
- << "NOTE: currently the 'Tim' UF solver is broken," << std::endl
- << "NOTE: since its registerTerm() function is never" << std::endl
- << "NOTE: called." << std::endl
- << "NOTE:" << std::endl;
-}
-
-TheoryUFTim::~TheoryUFTim() {
-}
-
-void TheoryUFTim::preRegisterTerm(TNode n) {
- Debug("uf") << "uf: begin preRegisterTerm(" << n << ")" << std::endl;
- Debug("uf") << "uf: end preRegisterTerm(" << n << ")" << std::endl;
-}
-
-void TheoryUFTim::registerTerm(TNode n) {
-
- Debug("uf") << "uf: begin registerTerm(" << n << ")" << std::endl;
-
- d_registered.push_back(n);
-
- ECData* ecN;
-
- if(n.getAttribute(ECAttr(), ecN)) {
- /* registerTerm(n) is only called when a node has not been seen in the
- * current context. ECAttr() is not a context-dependent attribute.
- * When n.hasAttribute(ECAttr(),...) is true on a registerTerm(n) call,
- * then it must be the case that this attribute was created in a previous
- * and no longer valid context. Because of this we have to reregister the
- * predecessors lists.
- * Also we do not have to worry about duplicates because all of the Link*
- * setup before are removed when the context n was setup in was popped out
- * of. All we are going to do here are sanity checks.
- */
-
- /*
- * Consider the following chain of events:
- * 1) registerTerm(n) is called on node n where n : f(m) in context level X,
- * 2) A new ECData is created on the heap, ecN,
- * 3) n is added to the predessecor list of m in context level X,
- * 4) We pop out of X,
- * 5) n is removed from the predessecor list of m because this is context
- * dependent, the Link* will be destroyed and pointers to the Link
- * structs in the ECData objects will be updated.
- * 6) registerTerm(n) is called on node n in context level Y,
- * 7) If n.hasAttribute(ECAttr(), &ecN), then ecN is still around,
- * but the predecessor list is not
- *
- * The above assumes that the code is working correctly.
- */
- Assert(ecN->getFirst() == NULL)
- << "Equivalence class data exists for the node being registered. "
- "Expected getFirst() == NULL. "
- "This data is either already in use or was not properly maintained "
- "during backtracking";
- /*Assert(ecN->getLast() == NULL,
- "Equivalence class data exists for the node being registered. "
- "Expected getLast() == NULL. "
- "This data is either already in use or was not properly maintained "
- "during backtracking.");*/
- Assert(ecN->isClassRep())
- << "Equivalence class data exists for the node being registered. "
- "Expected isClassRep() to be true. "
- "This data is either already in use or was not properly maintained "
- "during backtracking";
- Assert(ecN->getWatchListSize() == 0)
- << "Equivalence class data exists for the node being registered. "
- "Expected getWatchListSize() == 0. "
- "This data is either already in use or was not properly maintained "
- "during backtracking";
- } else {
- //The attribute does not exist, so it is created and set
- ecN = new (true) ECData(getContext(), n);
- n.setAttribute(ECAttr(), ecN);
- }
-
- /* If the node is an APPLY_UF, we need to add it to the predecessor list
- * of its children.
- */
- if(n.getKind() == APPLY_UF) {
- TNode::iterator cIter = n.begin();
-
- for(; cIter != n.end(); ++cIter) {
- TNode child = *cIter;
-
- /* Because this can be called after nodes have been merged, we need
- * to lookup the representative in the UnionFind datastructure.
- */
- ECData* ecChild = ccFind(child.getAttribute(ECAttr()));
-
- /* Because this can be called after nodes have been merged we may need
- * to be merged with other predecessors of the equivalence class.
- */
- for(Link* Px = ecChild->getFirst(); Px != NULL; Px = Px->d_next ) {
- if(equiv(n, Px->d_data)) {
- Node pend = n.eqNode(Px->d_data);
- d_pending.push_back(pend);
- }
- }
-
- ecChild->addPredecessor(n);
- }
- }
- Debug("uf") << "uf: end registerTerm(" << n << ")" << std::endl;
-
-}
-
-bool TheoryUFTim::sameCongruenceClass(TNode x, TNode y) {
- return
- ccFind(x.getAttribute(ECAttr())) ==
- ccFind(y.getAttribute(ECAttr()));
-}
-
-bool TheoryUFTim::equiv(TNode x, TNode y) {
- Assert(x.getKind() == kind::APPLY_UF);
- Assert(y.getKind() == kind::APPLY_UF);
-
- if(x.getNumChildren() != y.getNumChildren()) {
- return false;
- }
-
- if(x.getOperator() != y.getOperator()) {
- return false;
- }
-
- // intentionally don't look at operator
-
- TNode::iterator xIter = x.begin();
- TNode::iterator yIter = y.begin();
-
- while(xIter != x.end()) {
-
- if(!sameCongruenceClass(*xIter, *yIter)) {
- return false;
- }
-
- ++xIter;
- ++yIter;
- }
- return true;
-}
-
-/* This is a very basic, but *obviously correct* find implementation
- * of the classic find algorithm.
- * TODO after we have done some more testing:
- * 1) Add path compression. This is dependent on changes to ccUnion as
- * many better algorithms use eager path compression.
- * 2) Elminate recursion.
- */
-ECData* TheoryUFTim::ccFind(ECData * x) {
- if(x->getFind() == x) {
- return x;
- } else {
- return ccFind(x->getFind());
- }
- /* Slightly better Find w/ path compression and no recursion*/
- /*
- ECData* start;
- ECData* next = x;
- while(x != x->getFind()) x=x->getRep();
- while( (start = next) != x) {
- next = start->getFind();
- start->setFind(x);
- }
- return x;
- */
-}
-
-void TheoryUFTim::ccUnion(ECData* ecX, ECData* ecY) {
- ECData* nslave;
- ECData* nmaster;
-
- if(ecX->getWatchListSize() <= ecY->getWatchListSize()) {
- nslave = ecX;
- nmaster = ecY;
- } else {
- nslave = ecY;
- nmaster = ecX;
- }
-
- nslave->setFind(nmaster);
-
- for(Link* Px = nmaster->getFirst(); Px != NULL; Px = Px->d_next ) {
- for(Link* Py = nslave->getFirst(); Py != NULL; Py = Py->d_next ) {
- if(equiv(Px->d_data,Py->d_data)) {
- Node pendingEq = (Px->d_data).eqNode(Py->d_data);
- d_pending.push_back(pendingEq);
- }
- }
- }
-
- ECData::takeOverDescendantWatchList(nslave, nmaster);
-}
-
-void TheoryUFTim::merge() {
- while(d_currentPendingIdx < d_pending.size() ) {
- Node assertion = d_pending[d_currentPendingIdx];
- d_currentPendingIdx = d_currentPendingIdx + 1;
-
- TNode x = assertion[0];
- TNode y = assertion[1];
-
- ECData* tmpX = x.getAttribute(ECAttr());
- ECData* tmpY = y.getAttribute(ECAttr());
-
- ECData* ecX = ccFind(tmpX);
- ECData* ecY = ccFind(tmpY);
- if(ecX == ecY)
- continue;
-
- Debug("uf") << "merging equivalence classes for " << std::endl;
- Debug("uf") << "left equivalence class :" << (ecX->getRep()) << std::endl;
- Debug("uf") << "right equivalence class :" << (ecY->getRep()) << std::endl;
- Debug("uf") << std::endl;
-
- ccUnion(ecX, ecY);
- }
-}
-
-Node TheoryUFTim::constructConflict(TNode diseq) {
- Debug("uf") << "uf: begin constructConflict()" << std::endl;
-
- NodeBuilder<> nb(kind::AND);
- nb << diseq;
- for(unsigned i = 0; i < d_assertions.size(); ++i) {
- nb << d_assertions[i];
- }
-
- Assert(nb.getNumChildren() > 0);
- Node conflict = nb.getNumChildren() == 1 ? nb[0] : nb;
-
- Debug("uf") << "conflict constructed : " << conflict << std::endl;
-
- Debug("uf") << "uf: ending constructConflict()" << std::endl;
-
- return conflict;
-}
-
-void TheoryUFTim::check(Effort level) {
- if (done() && !fullEffort(level)) {
- return;
- }
-
- TimerStat::CodeTimer checkTimer(d_checkTime);
-
- Debug("uf") << "uf: begin check(" << level << ")" << std::endl;
-
- while(!done()) {
- Node assertion = get();
- Debug("uf") << "TheoryUFTim::check(): " << assertion << std::endl;
-
- switch(assertion.getKind()) {
- case EQUAL:
- d_assertions.push_back(assertion);
- d_pending.push_back(assertion);
- merge();
- break;
- case NOT:
- Assert(assertion[0].getKind() == EQUAL)
- << "predicates not supported in this UF implementation";
- d_disequality.push_back(assertion[0]);
- break;
- case APPLY_UF:
- Unhandled() << "predicates not supported in this UF implementation";
- default: Unhandled() << assertion.getKind();
- }
-
- Debug("uf") << "TheoryUFTim::check(): done = " << (done() ? "true" : "false") << std::endl;
- }
-
- //Make sure all outstanding merges are completed.
- if(d_currentPendingIdx < d_pending.size()) {
- merge();
- }
-
- if(standardEffortOrMore(level)) {
- for(CDList<Node>::const_iterator diseqIter = d_disequality.begin();
- diseqIter != d_disequality.end();
- ++diseqIter) {
-
- TNode left = (*diseqIter)[0];
- TNode right = (*diseqIter)[1];
- if(sameCongruenceClass(left, right)) {
- Node remakeNeq = (*diseqIter).notNode();
- Node conflict = constructConflict(remakeNeq);
- d_out->conflict(conflict, false);
- return;
- }
- }
- }
-
- Debug("uf") << "uf: end check(" << level << ")" << std::endl;
-}
diff --git a/src/theory/example/theory_uf_tim.h b/src/theory/example/theory_uf_tim.h
deleted file mode 100644
index 438fe33dc..000000000
--- a/src/theory/example/theory_uf_tim.h
+++ /dev/null
@@ -1,213 +0,0 @@
-/********************* */
-/*! \file theory_uf_tim.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Morgan Deters, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief This is a basic implementation of the Theory of Uninterpreted Functions
- ** with Equality.
- **
- ** This is a basic implementation of the Theory of Uninterpreted Functions
- ** with Equality. It is based on the Nelson-Oppen algorithm given in
- ** "Fast Decision Procedures Based on Congruence Closure"
- ** (http://portal.acm.org/ft_gateway.cfm?id=322198&type=pdf)
- ** This has been extended to work in a context-dependent way.
- ** This interacts heavily with the data-structures given in ecdata.h .
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__THEORY__UF__TIM__THEORY_UF_TIM_H
-#define CVC4__THEORY__UF__TIM__THEORY_UF_TIM_H
-
-#include "expr/node.h"
-#include "expr/attribute.h"
-
-#include "theory/theory.h"
-
-#include "context/context.h"
-#include "context/cdo.h"
-#include "context/cdlist.h"
-#include "theory/uf/theory_uf.h"
-#include "theory/uf/tim/ecdata.h"
-
-namespace CVC4 {
-namespace theory {
-namespace uf {
-namespace tim {
-
-class TheoryUFTim : public Theory {
-
-private:
-
- /**
- * List of all of the non-negated literals from the assertion queue.
- * This is used only for conflict generation.
- * This differs from pending as the program generates new equalities that
- * are not in this list.
- * This will probably be phased out in future version.
- */
- context::CDList<Node> d_assertions;
-
- /**
- * List of pending equivalence class merges.
- *
- * Tricky part:
- * Must keep a hard link because new equality terms are created and appended
- * to this list.
- */
- context::CDList<Node> d_pending;
-
- /** Index of the next pending equality to merge. */
- context::CDO<unsigned> d_currentPendingIdx;
-
- /** List of all disequalities this theory has seen. */
- context::CDList<Node> d_disequality;
-
- /**
- * List of all of the terms that are registered in the current context.
- * When registerTerm is called on a term we want to guarentee that there
- * is a hard link to the term for the duration of the context in which
- * register term is called.
- * This invariant is enough for us to use soft links where we want is the
- * current implementation as well as making ECAttr() not context dependent.
- * Soft links used both in ECData, and Link.
- */
- context::CDList<Node> d_registered;
-
-public:
-
- /** Constructs a new instance of TheoryUF w.r.t. the provided context.*/
- TheoryUFTim(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation);
-
- /** Destructor for the TheoryUF object. */
- ~TheoryUFTim();
-
- /**
- * Registers a previously unseen [in this context] node n.
- * For TheoryUF, this sets up and maintains invaraints about
- * equivalence class data-structures.
- *
- * Overloads a void registerTerm(TNode n); from theory.h.
- * See theory/theory.h for more information about this method.
- */
- void registerTerm(TNode n);
-
- /**
- * Currently this does nothing.
- *
- * Overloads a void preRegisterTerm(TNode n); from theory.h.
- * See theory/theory.h for more information about this method.
- */
- void preRegisterTerm(TNode n);
-
- /**
- * Checks whether the set of literals provided to the theory is consistent.
- *
- * If this is called at any effort level, it computes the congruence closure
- * of all of the positive literals in the context.
- *
- * If this is called at full effort it checks if any of the negative literals
- * are inconsistent with the congruence closure.
- *
- * Overloads void check(Effort level); from theory.h.
- * See theory/theory.h for more information about this method.
- */
- void check(Effort level);
-
- void presolve() {
- // do nothing
- }
-
- /**
- * Propagates theory literals. Currently does nothing.
- *
- * Overloads void propagate(Effort level); from theory.h.
- * See theory/theory.h for more information about this method.
- */
- void propagate(Effort level) {}
-
- /**
- * Explains a previously reported conflict. Currently does nothing.
- *
- * Overloads void explain(TNode n, Effort level); from theory.h.
- * See theory/theory.h for more information about this method.
- */
- void explain(TNode n) {}
-
- std::string identify() const { return std::string("TheoryUFTim"); }
-
-private:
- /**
- * Checks whether 2 nodes are already in the same equivalence class tree.
- * This should only be used internally, and it should only be called when
- * the only thing done with the equivalence classes is an equality check.
- *
- * @returns true iff ccFind(x) == ccFind(y);
- */
- bool sameCongruenceClass(TNode x, TNode y);
-
- /**
- * Checks whether Node x and Node y are currently congruent
- * using the equivalence class data structures.
- * @returns true iff
- * |x| = n = |y| and
- * x.getOperator() == y.getOperator() and
- * forall 1 <= i < n : ccFind(x[i]) == ccFind(y[i])
- */
- bool equiv(TNode x, TNode y);
-
- /**
- * Merges 2 equivalence classes, checks wether any predecessors need to
- * be set equal to complete congruence closure.
- * The class with the smaller class size will be merged.
- * @pre ecX->isClassRep()
- * @pre ecY->isClassRep()
- */
- void ccUnion(ECData* ecX, ECData* ecY);
-
- /**
- * Returns the representative of the equivalence class.
- * May modify the find pointers associated with equivalence classes.
- */
- ECData* ccFind(ECData* x);
-
- /** Performs Congruence Closure to reflect the new additions to d_pending. */
- void merge();
-
- /** Constructs a conflict from an inconsistent disequality. */
- Node constructConflict(TNode diseq);
-
-};/* class TheoryUFTim */
-
-
-/**
- * Cleanup function for ECData. This will be used for called whenever
- * a ECAttr is being destructed.
- */
-struct ECCleanupStrategy {
- static void cleanup(ECData* ec) {
- Debug("ufgc") << "cleaning up ECData " << ec << "\n";
- ec->deleteSelf();
- }
-};/* struct ECCleanupStrategy */
-
-/** Unique name to use for constructing ECAttr. */
-struct ECAttrTag {};
-
-/**
- * ECAttr is the attribute that maps a node to an equivalence class.
- */
-typedef expr::Attribute<ECAttrTag, ECData*, ECCleanupStrategy> ECAttr;
-
-}/* CVC4::theory::uf::tim namespace */
-}/* CVC4::theory::uf namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* CVC4__THEORY__UF__TIM__THEORY_UF_TIM_H */
diff --git a/src/theory/ext_theory.cpp b/src/theory/ext_theory.cpp
index f84153c06..ac08b1553 100644
--- a/src/theory/ext_theory.cpp
+++ b/src/theory/ext_theory.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -28,13 +28,41 @@ using namespace std;
namespace CVC4 {
namespace theory {
-ExtTheory::ExtTheory(Theory* p, bool cacheEnabled)
+bool ExtTheoryCallback::getCurrentSubstitution(
+ int effort,
+ const std::vector<Node>& vars,
+ std::vector<Node>& subs,
+ std::map<Node, std::vector<Node> >& exp)
+{
+ return false;
+}
+bool ExtTheoryCallback::isExtfReduced(int effort,
+ Node n,
+ Node on,
+ std::vector<Node>& exp)
+{
+ return n.isConst();
+}
+bool ExtTheoryCallback::getReduction(int effort,
+ Node n,
+ Node& nr,
+ bool& isSatDep)
+{
+ return false;
+}
+
+ExtTheory::ExtTheory(ExtTheoryCallback& p,
+ context::Context* c,
+ context::UserContext* u,
+ OutputChannel& out,
+ bool cacheEnabled)
: d_parent(p),
- d_ext_func_terms(p->getSatContext()),
- d_ci_inactive(p->getUserContext()),
- d_has_extf(p->getSatContext()),
- d_lemmas(p->getUserContext()),
- d_pp_lemmas(p->getUserContext()),
+ d_out(out),
+ d_ext_func_terms(c),
+ d_ci_inactive(u),
+ d_has_extf(c),
+ d_lemmas(u),
+ d_pp_lemmas(u),
d_cacheEnabled(cacheEnabled)
{
d_true = NodeManager::currentNM()->mkConst(true);
@@ -61,7 +89,6 @@ std::vector<Node> ExtTheory::collectVars(Node n)
// (commented below)
if (current.getNumChildren() > 0)
{
- //&& Theory::theoryOf(n)==d_parent->getId() ){
worklist.insert(worklist.end(), current.begin(), current.end());
}
else
@@ -140,7 +167,7 @@ void ExtTheory::getSubstitutedTerms(int effort,
}
}
}
- bool useSubs = d_parent->getCurrentSubstitution(effort, vars, sub, expc);
+ bool useSubs = d_parent.getCurrentSubstitution(effort, vars, sub, expc);
// get the current substitution for all variables
Assert(!useSubs || vars.size() == sub.size());
for (const Node& n : terms)
@@ -206,8 +233,8 @@ bool ExtTheory::doInferencesInternal(int effort,
{
Node nr;
// note: could do reduction with substitution here
- int ret = d_parent->getReduction(effort, n, nr);
- if (ret == 0)
+ bool satDep = false;
+ if (!d_parent.getReduction(effort, n, nr, satDep))
{
nred.push_back(n);
}
@@ -223,7 +250,7 @@ bool ExtTheory::doInferencesInternal(int effort,
addedLemma = true;
}
}
- markReduced(n, ret < 0);
+ markReduced(n, satDep);
}
}
}
@@ -242,7 +269,7 @@ bool ExtTheory::doInferencesInternal(int effort,
Node sr = Rewriter::rewrite(sterms[i]);
// ask the theory if this term is reduced, e.g. is it constant or it
// is a non-extf term.
- if (d_parent->isExtfReduced(effort, sr, terms[i], exp[i]))
+ if (d_parent.isExtfReduced(effort, sr, terms[i], exp[i]))
{
processed = true;
markReduced(terms[i]);
@@ -344,7 +371,7 @@ bool ExtTheory::sendLemma(Node lem, bool preprocess)
if (d_pp_lemmas.find(lem) == d_pp_lemmas.end())
{
d_pp_lemmas.insert(lem);
- d_parent->getOutputChannel().lemma(lem, false, true);
+ d_out.lemma(lem, LemmaProperty::PREPROCESS);
return true;
}
}
@@ -353,7 +380,7 @@ bool ExtTheory::sendLemma(Node lem, bool preprocess)
if (d_lemmas.find(lem) == d_lemmas.end())
{
d_lemmas.insert(lem);
- d_parent->getOutputChannel().lemma(lem);
+ d_out.lemma(lem);
return true;
}
}
@@ -403,8 +430,7 @@ void ExtTheory::registerTerm(Node n)
{
if (d_ext_func_terms.find(n) == d_ext_func_terms.end())
{
- Trace("extt-debug") << "Found extended function : " << n << " in "
- << d_parent->getId() << std::endl;
+ Trace("extt-debug") << "Found extended function : " << n << std::endl;
d_ext_func_terms[n] = true;
d_has_extf = n;
d_extf_info[n].d_vars = collectVars(n);
@@ -435,13 +461,13 @@ void ExtTheory::registerTermRec(Node n)
}
// mark reduced
-void ExtTheory::markReduced(Node n, bool contextDepend)
+void ExtTheory::markReduced(Node n, bool satDep)
{
Trace("extt-debug") << "Mark reduced " << n << std::endl;
registerTerm(n);
Assert(d_ext_func_terms.find(n) != d_ext_func_terms.end());
d_ext_func_terms[n] = false;
- if (!contextDepend)
+ if (!satDep)
{
d_ci_inactive.insert(n);
}
diff --git a/src/theory/ext_theory.h b/src/theory/ext_theory.h
index 420932bfe..1577c8b6f 100644
--- a/src/theory/ext_theory.h
+++ b/src/theory/ext_theory.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -36,6 +36,7 @@
#include <map>
#include <set>
+#include "context/cdhashmap.h"
#include "context/cdhashset.h"
#include "context/context.h"
#include "expr/node.h"
@@ -44,6 +45,57 @@
namespace CVC4 {
namespace theory {
+/**
+ * A callback class for ExtTheory below. This class is responsible for
+ * determining how to apply context-dependent simplification.
+ */
+class ExtTheoryCallback
+{
+ public:
+ virtual ~ExtTheoryCallback() {}
+ /*
+ * Get current substitution at an effort
+ * @param effort The effort identifier
+ * @param vars The variables to get a substitution for
+ * @param subs The terms to substitute for variables, in order. This vector
+ * should be updated to one the same size as vars.
+ * @param exp The map containing the explanation for each variable. Together
+ * with subs, we have that:
+ * ( exp[vars[i]] => vars[i] = subs[i] ) holds for all i
+ * @return true if any (non-identity) substitution was added to subs.
+ */
+ virtual bool getCurrentSubstitution(int effort,
+ const std::vector<Node>& vars,
+ std::vector<Node>& subs,
+ std::map<Node, std::vector<Node> >& exp);
+
+ /*
+ * Is extended function n reduced? This returns true if n is reduced to a
+ * form that requires no further interaction from the theory.
+ *
+ * @param effort The effort identifier
+ * @param n The term to reduce
+ * @param on The original form of n, before substitution
+ * @param exp The explanation of on = n
+ * @return true if n is reduced.
+ */
+ virtual bool isExtfReduced(int effort,
+ Node n,
+ Node on,
+ std::vector<Node>& exp);
+
+ /**
+ * Get reduction for node n.
+ * If return value is true, then n is reduced.
+ * If satDep is updated to false, then n is reduced independent of the
+ * SAT context (e.g. by a lemma that persists at this
+ * user-context level).
+ * If nr is non-null, then ( n = nr ) should be added as a lemma by caller,
+ * and return value of this method should be true.
+ */
+ virtual bool getReduction(int effort, Node n, Node& nr, bool& satDep);
+};
+
/** Extended theory class
*
* This class is used for constructing generic extensions to theory solvers.
@@ -72,7 +124,11 @@ class ExtTheory
*
* If cacheEnabled is false, we do not cache results of getSubstitutedTerm.
*/
- ExtTheory(Theory* p, bool cacheEnabled = false);
+ ExtTheory(ExtTheoryCallback& p,
+ context::Context* c,
+ context::UserContext* u,
+ OutputChannel& out,
+ bool cacheEnabled = false);
virtual ~ExtTheory() {}
/** Tells this class to treat terms with Kind k as extended functions */
void addFunctionKind(Kind k) { d_extf_kind[k] = true; }
@@ -92,10 +148,10 @@ class ExtTheory
void registerTermRec(Node n);
/** set n as reduced/inactive
*
- * If contextDepend = false, then n remains inactive in the duration of this
+ * If satDep = false, then n remains inactive in the duration of this
* user-context level
*/
- void markReduced(Node n, bool contextDepend = true);
+ void markReduced(Node n, bool satDep = true);
/**
* Mark that a and b are congruent terms. This sets b inactive, and sets a to
* inactive if b was inactive.
@@ -193,10 +249,12 @@ class ExtTheory
std::vector<Node>& nred,
bool batch,
bool isRed);
- /** send lemma on the output channel of d_parent */
+ /** send lemma on the output channel */
bool sendLemma(Node lem, bool preprocess = false);
- /** reference to the underlying theory */
- Theory* d_parent;
+ /** reference to the callback */
+ ExtTheoryCallback& d_parent;
+ /** Reference to the output channel we are using */
+ OutputChannel& d_out;
/** the true node */
Node d_true;
/** extended function terms, map to whether they are active */
diff --git a/src/theory/fp/fp_converter.cpp b/src/theory/fp/fp_converter.cpp
index 49be75719..85482bf6d 100644
--- a/src/theory/fp/fp_converter.cpp
+++ b/src/theory/fp/fp_converter.cpp
@@ -5,7 +5,7 @@
** Martin Brain, Mathias Preiner, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -13,11 +13,13 @@
**/
#include "theory/fp/fp_converter.h"
-#include "theory/theory.h"
-// theory.h Only needed for the leaf test
#include <vector>
+#include "theory/theory.h" // theory.h Only needed for the leaf test
+#include "util/floatingpoint.h"
+#include "util/floatingpoint_literal_symfpu.h"
+
#ifdef CVC4_USE_SYMFPU
#include "symfpu/core/add.h"
#include "symfpu/core/classify.h"
@@ -141,7 +143,6 @@ void probabilityAnnotation<traits, traits::prop>(const traits::prop &p,
#endif
#ifndef CVC4_USE_SYMFPU
-#define PRECONDITION(X) Assert((X))
#define SYMFPU_NUMBER_OF_ROUNDING_MODES 5
#endif
@@ -155,19 +156,20 @@ symbolicRoundingMode traits::RNA(void) { return symbolicRoundingMode(0x02); };
symbolicRoundingMode traits::RTP(void) { return symbolicRoundingMode(0x04); };
symbolicRoundingMode traits::RTN(void) { return symbolicRoundingMode(0x08); };
symbolicRoundingMode traits::RTZ(void) { return symbolicRoundingMode(0x10); };
+
void traits::precondition(const bool b)
{
- AlwaysAssert(b);
+ Assert(b);
return;
}
void traits::postcondition(const bool b)
{
- AlwaysAssert(b);
+ Assert(b);
return;
}
void traits::invariant(const bool b)
{
- AlwaysAssert(b);
+ Assert(b);
return;
}
@@ -186,18 +188,19 @@ bool symbolicProposition::checkNodeType(const TNode node)
symbolicProposition::symbolicProposition(const Node n) : nodeWrapper(n)
{
- PRECONDITION(checkNodeType(*this));
+ Assert(checkNodeType(*this));
} // Only used within this header so could be friend'd
symbolicProposition::symbolicProposition(bool v)
: nodeWrapper(
NodeManager::currentNM()->mkConst(BitVector(1U, (v ? 1U : 0U))))
{
- PRECONDITION(checkNodeType(*this));
+ Assert(checkNodeType(*this));
}
+
symbolicProposition::symbolicProposition(const symbolicProposition &old)
: nodeWrapper(old)
{
- PRECONDITION(checkNodeType(*this));
+ Assert(checkNodeType(*this));
}
symbolicProposition symbolicProposition::operator!(void)const
@@ -245,7 +248,7 @@ bool symbolicRoundingMode::checkNodeType(const TNode n)
symbolicRoundingMode::symbolicRoundingMode(const Node n) : nodeWrapper(n)
{
- PRECONDITION(checkNodeType(*this));
+ Assert(checkNodeType(*this));
}
#ifdef CVC4_USE_SYMFPU
@@ -253,8 +256,8 @@ symbolicRoundingMode::symbolicRoundingMode(const unsigned v)
: nodeWrapper(NodeManager::currentNM()->mkConst(
BitVector(SYMFPU_NUMBER_OF_ROUNDING_MODES, v)))
{
- PRECONDITION((v & (v - 1)) == 0 && v != 0); // Exactly one bit set
- PRECONDITION(checkNodeType(*this));
+ Assert((v & (v - 1)) == 0 && v != 0); // Exactly one bit set
+ Assert(checkNodeType(*this));
}
#else
symbolicRoundingMode::symbolicRoundingMode(const unsigned v)
@@ -268,7 +271,7 @@ symbolicRoundingMode::symbolicRoundingMode(const unsigned v)
symbolicRoundingMode::symbolicRoundingMode(const symbolicRoundingMode &old)
: nodeWrapper(old)
{
- PRECONDITION(checkNodeType(*this));
+ Assert(checkNodeType(*this));
}
symbolicProposition symbolicRoundingMode::valid(void) const
@@ -333,7 +336,7 @@ Node symbolicBitVector<isSigned>::toProposition(Node node) const
template <bool isSigned>
symbolicBitVector<isSigned>::symbolicBitVector(const Node n) : nodeWrapper(n)
{
- PRECONDITION(checkNodeType(*this));
+ Assert(checkNodeType(*this));
}
template <bool isSigned>
@@ -346,7 +349,7 @@ template <bool isSigned>
symbolicBitVector<isSigned>::symbolicBitVector(const bwt w, const unsigned v)
: nodeWrapper(NodeManager::currentNM()->mkConst(BitVector(w, v)))
{
- PRECONDITION(checkNodeType(*this));
+ Assert(checkNodeType(*this));
}
template <bool isSigned>
symbolicBitVector<isSigned>::symbolicBitVector(const symbolicProposition &p)
@@ -358,13 +361,13 @@ symbolicBitVector<isSigned>::symbolicBitVector(
const symbolicBitVector<isSigned> &old)
: nodeWrapper(old)
{
- PRECONDITION(checkNodeType(*this));
+ Assert(checkNodeType(*this));
}
template <bool isSigned>
symbolicBitVector<isSigned>::symbolicBitVector(const BitVector &old)
: nodeWrapper(NodeManager::currentNM()->mkConst(old))
{
- PRECONDITION(checkNodeType(*this));
+ Assert(checkNodeType(*this));
}
template <bool isSigned>
@@ -670,7 +673,7 @@ template <bool isSigned>
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::contract(
bwt reduction) const
{
- PRECONDITION(this->getWidth() > reduction);
+ Assert(this->getWidth() > reduction);
NodeBuilder<> construct(kind::BITVECTOR_EXTRACT);
construct << NodeManager::currentNM()->mkConst<BitVectorExtract>(
@@ -704,7 +707,7 @@ template <bool isSigned>
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::matchWidth(
const symbolicBitVector<isSigned> &op) const
{
- PRECONDITION(this->getWidth() <= op.getWidth());
+ Assert(this->getWidth() <= op.getWidth());
return this->extend(op.getWidth() - this->getWidth());
}
@@ -721,7 +724,7 @@ template <bool isSigned>
symbolicBitVector<isSigned> symbolicBitVector<isSigned>::extract(
bwt upper, bwt lower) const
{
- PRECONDITION(upper >= lower);
+ Assert(upper >= lower);
NodeBuilder<> construct(kind::BITVECTOR_EXTRACT);
construct << NodeManager::currentNM()->mkConst<BitVectorExtract>(
@@ -734,7 +737,7 @@ symbolicBitVector<isSigned> symbolicBitVector<isSigned>::extract(
floatingPointTypeInfo::floatingPointTypeInfo(const TypeNode type)
: FloatingPointSize(type.getConst<FloatingPointSize>())
{
- PRECONDITION(type.isFloatingPoint());
+ Assert(type.isFloatingPoint());
}
floatingPointTypeInfo::floatingPointTypeInfo(unsigned exp, unsigned sig)
: FloatingPointSize(exp, sig)
@@ -796,17 +799,17 @@ Node FpConverter::rmToNode(const rm &r) const
Node value = nm->mkNode(
kind::ITE,
nm->mkNode(kind::EQUAL, transVar, RNE),
- nm->mkConst(roundNearestTiesToEven),
+ nm->mkConst(ROUND_NEAREST_TIES_TO_EVEN),
nm->mkNode(kind::ITE,
nm->mkNode(kind::EQUAL, transVar, RNA),
- nm->mkConst(roundNearestTiesToAway),
+ nm->mkConst(ROUND_NEAREST_TIES_TO_AWAY),
nm->mkNode(kind::ITE,
nm->mkNode(kind::EQUAL, transVar, RTP),
- nm->mkConst(roundTowardPositive),
+ nm->mkConst(ROUND_TOWARD_POSITIVE),
nm->mkNode(kind::ITE,
nm->mkNode(kind::EQUAL, transVar, RTN),
- nm->mkConst(roundTowardNegative),
- nm->mkConst(roundTowardZero)))));
+ nm->mkConst(ROUND_TOWARD_NEGATIVE),
+ nm->mkConst(ROUND_TOWARD_ZERO)))));
return value;
}
@@ -874,19 +877,19 @@ Node FpConverter::convert(TNode node)
/******** Constants ********/
switch (current.getConst<RoundingMode>())
{
- case roundNearestTiesToEven:
+ case ROUND_NEAREST_TIES_TO_EVEN:
d_rmMap.insert(current, traits::RNE());
break;
- case roundNearestTiesToAway:
+ case ROUND_NEAREST_TIES_TO_AWAY:
d_rmMap.insert(current, traits::RNA());
break;
- case roundTowardPositive:
+ case ROUND_TOWARD_POSITIVE:
d_rmMap.insert(current, traits::RTP());
break;
- case roundTowardNegative:
+ case ROUND_TOWARD_NEGATIVE:
d_rmMap.insert(current, traits::RTN());
break;
- case roundTowardZero:
+ case ROUND_TOWARD_ZERO:
d_rmMap.insert(current, traits::RTZ());
break;
default: Unreachable() << "Unknown rounding mode"; break;
@@ -918,9 +921,11 @@ Node FpConverter::convert(TNode node)
if (current.getKind() == kind::CONST_FLOATINGPOINT)
{
/******** Constants ********/
- d_fpMap.insert(current,
- symfpu::unpackedFloat<traits>(
- current.getConst<FloatingPoint>().getLiteral()));
+ d_fpMap.insert(
+ current,
+ symfpu::unpackedFloat<traits>(current.getConst<FloatingPoint>()
+ .getLiteral()
+ ->getSymUF()));
}
else
{
@@ -1577,7 +1582,7 @@ Node FpConverter::convert(TNode node)
symfpu::convertFloatToUBV<traits>(fpt(childType),
(*mode).second,
(*arg1).second,
- info.bvs,
+ info.d_bv_size,
ubv(current[2])));
i = d_ubvMap.find(current);
}
@@ -1619,7 +1624,7 @@ Node FpConverter::convert(TNode node)
symfpu::convertFloatToSBV<traits>(fpt(childType),
(*mode).second,
(*arg1).second,
- info.bvs,
+ info.d_bv_size,
sbv(current[2])));
i = d_sbvMap.find(current);
@@ -1710,43 +1715,23 @@ Node FpConverter::getValue(Valuation &val, TNode var)
#ifdef CVC4_USE_SYMFPU
TypeNode t(var.getType());
+ Assert(t.isRoundingMode() || t.isFloatingPoint())
+ << "Asking for the value of a type that is not managed by the "
+ "floating-point theory";
+
if (t.isRoundingMode())
{
rmMap::const_iterator i(d_rmMap.find(var));
- if (i == d_rmMap.end())
- {
- Unreachable() << "Asking for the value of an unregistered expression";
- }
- else
- {
- Node value = rmToNode((*i).second);
- return value;
- }
+ Assert(i != d_rmMap.end())
+ << "Asking for the value of an unregistered expression";
+ return rmToNode((*i).second);
}
- else if (t.isFloatingPoint())
- {
- fpMap::const_iterator i(d_fpMap.find(var));
-
- if (i == d_fpMap.end())
- {
- Unreachable() << "Asking for the value of an unregistered expression";
- }
- else
- {
- Node value = ufToNode(fpt(t), (*i).second);
- return value;
- }
- }
- else
- {
- Unreachable()
- << "Asking for the value of a type that is not managed by the "
- "floating-point theory";
- }
-
- Unreachable() << "Unable to find value";
+ fpMap::const_iterator i(d_fpMap.find(var));
+ Assert(i != d_fpMap.end())
+ << "Asking for the value of an unregistered expression";
+ return ufToNode(fpt(t), (*i).second);
#else
Unimplemented() << "Conversion is dependent on SymFPU";
#endif
diff --git a/src/theory/fp/fp_converter.h b/src/theory/fp/fp_converter.h
index 122e94ac0..59e65c9e1 100644
--- a/src/theory/fp/fp_converter.h
+++ b/src/theory/fp/fp_converter.h
@@ -5,7 +5,7 @@
** Martin Brain, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -29,7 +29,7 @@
#include "expr/type.h"
#include "theory/valuation.h"
#include "util/bitvector.h"
-#include "util/floatingpoint.h"
+#include "util/floatingpoint_size.h"
#include "util/hash.h"
#ifdef CVC4_USE_SYMFPU
diff --git a/src/theory/fp/theory_fp.cpp b/src/theory/fp/theory_fp.cpp
index bffcda7bc..0b15486e2 100644
--- a/src/theory/fp/theory_fp.cpp
+++ b/src/theory/fp/theory_fp.cpp
@@ -2,10 +2,10 @@
/*! \file theory_fp.cpp
** \verbatim
** Top contributors (to current version):
- ** Martin Brain, Andres Noetzli, Haniel Barbosa
+ ** Martin Brain, Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -107,11 +107,9 @@ TheoryFp::TheoryFp(context::Context* c,
ProofNodeManager* pnm)
: Theory(THEORY_FP, c, u, out, valuation, logicInfo, pnm),
d_notification(*this),
- d_equalityEngine(d_notification, c, "theory::fp::ee", true),
d_registeredTerms(u),
d_conv(u),
d_expansionRequested(false),
- d_conflict(c, false),
d_conflictNode(c, Node::null()),
d_minMap(u),
d_maxMap(u),
@@ -120,62 +118,79 @@ TheoryFp::TheoryFp(context::Context* c,
d_toRealMap(u),
realToFloatMap(u),
floatToRealMap(u),
- abstractionMap(u)
+ abstractionMap(u),
+ d_state(c, u, valuation)
{
+ // indicate we are using the default theory state object
+ d_theoryState = &d_state;
+} /* TheoryFp::TheoryFp() */
+
+TheoryRewriter* TheoryFp::getTheoryRewriter() { return &d_rewriter; }
+
+bool TheoryFp::needsEqualityEngine(EeSetupInfo& esi)
+{
+ esi.d_notify = &d_notification;
+ esi.d_name = "theory::fp::ee";
+ return true;
+}
+
+void TheoryFp::finishInit()
+{
+ Assert(d_equalityEngine != nullptr);
// Kinds that are to be handled in the congruence closure
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_ABS);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_NEG);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_PLUS);
- // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_SUB); // Removed
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_MULT);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_DIV);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_FMA);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_SQRT);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_REM);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_RTI);
- // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_MIN); // Removed
- // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_MAX); // Removed
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_MIN_TOTAL);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_MAX_TOTAL);
-
- // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_EQ); // Removed
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_LEQ);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_LT);
- // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_GEQ); // Removed
- // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_GT); // Removed
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_ISN);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_ISSN);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_ISZ);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_ISINF);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_ISNAN);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_ISNEG);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_ISPOS);
-
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_TO_FP_IEEE_BITVECTOR);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_TO_FP_FLOATINGPOINT);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_TO_FP_REAL);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR);
- d_equalityEngine.addFunctionKind(
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_ABS);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_NEG);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_PLUS);
+ // d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_SUB); // Removed
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_MULT);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_DIV);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_FMA);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_SQRT);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_REM);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_RTI);
+ // d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_MIN); // Removed
+ // d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_MAX); // Removed
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_MIN_TOTAL);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_MAX_TOTAL);
+
+ // d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_EQ); // Removed
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_LEQ);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_LT);
+ // d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_GEQ); // Removed
+ // d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_GT); // Removed
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_ISN);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_ISSN);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_ISZ);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_ISINF);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_ISNAN);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_ISNEG);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_ISPOS);
+
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_FP_IEEE_BITVECTOR);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_FP_FLOATINGPOINT);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_FP_REAL);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR);
+ d_equalityEngine->addFunctionKind(
kind::FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR);
- // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_TO_FP_GENERIC); //
+ // d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_FP_GENERIC); //
// Needed in parsing, should be rewritten away
- // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_TO_UBV); // Removed
- // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_TO_SBV); // Removed
- // d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_TO_REAL); // Removed
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_TO_UBV_TOTAL);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_TO_SBV_TOTAL);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_TO_REAL_TOTAL);
-
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_COMPONENT_NAN);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_COMPONENT_INF);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_COMPONENT_ZERO);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_COMPONENT_SIGN);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_COMPONENT_EXPONENT);
- d_equalityEngine.addFunctionKind(kind::FLOATINGPOINT_COMPONENT_SIGNIFICAND);
- d_equalityEngine.addFunctionKind(kind::ROUNDINGMODE_BITBLAST);
-} /* TheoryFp::TheoryFp() */
+ // d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_UBV); // Removed
+ // d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_SBV); // Removed
+ // d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_REAL); // Removed
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_UBV_TOTAL);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_SBV_TOTAL);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_TO_REAL_TOTAL);
+
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_COMPONENT_NAN);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_COMPONENT_INF);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_COMPONENT_ZERO);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_COMPONENT_SIGN);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_COMPONENT_EXPONENT);
+ d_equalityEngine->addFunctionKind(kind::FLOATINGPOINT_COMPONENT_SIGNIFICAND);
+ d_equalityEngine->addFunctionKind(kind::ROUNDINGMODE_BITBLAST);
+}
Node TheoryFp::minUF(Node node) {
Assert(node.getKind() == kind::FLOATINGPOINT_MIN);
@@ -574,7 +589,7 @@ bool TheoryFp::refineAbstraction(TheoryModel *m, TNode abstract, TNode concrete)
nm->mkNode(kind::FLOATINGPOINT_TO_FP_REAL,
nm->mkConst(FloatingPointToFPReal(
concrete[0].getType().getConst<FloatingPointSize>())),
- nm->mkConst(roundTowardPositive),
+ nm->mkConst(ROUND_TOWARD_POSITIVE),
abstractValue));
Node bg = nm->mkNode(
@@ -591,7 +606,7 @@ bool TheoryFp::refineAbstraction(TheoryModel *m, TNode abstract, TNode concrete)
nm->mkNode(kind::FLOATINGPOINT_TO_FP_REAL,
nm->mkConst(FloatingPointToFPReal(
concrete[0].getType().getConst<FloatingPointSize>())),
- nm->mkConst(roundTowardNegative),
+ nm->mkConst(ROUND_TOWARD_NEGATIVE),
abstractValue));
Node bl = nm->mkNode(
@@ -803,11 +818,11 @@ void TheoryFp::registerTerm(TNode node) {
// Add to the equality engine
if (k == kind::EQUAL)
{
- d_equalityEngine.addTriggerEquality(node);
+ d_equalityEngine->addTriggerPredicate(node);
}
else
{
- d_equalityEngine.addTerm(node);
+ d_equalityEngine->addTerm(node);
}
// Give the expansion of classifications in terms of equalities
@@ -892,102 +907,50 @@ void TheoryFp::preRegisterTerm(TNode node)
return;
}
-void TheoryFp::addSharedTerm(TNode node) {
- Trace("fp-addSharedTerm")
- << "TheoryFp::addSharedTerm(): " << node << std::endl;
- // A system-wide invariant; terms must be registered before they are shared
- Assert(isRegistered(node));
- return;
-}
-
void TheoryFp::handleLemma(Node node) {
Trace("fp") << "TheoryFp::handleLemma(): asserting " << node << std::endl;
-
- d_out->lemma(node, false,
- true); // Has to be true because it contains embedded ITEs
+ // Preprocess has to be true because it contains embedded ITEs
+ d_out->lemma(node, LemmaProperty::PREPROCESS);
// Ignore the LemmaStatus structure for now...
return;
}
-bool TheoryFp::handlePropagation(TNode node) {
- Trace("fp") << "TheoryFp::handlePropagation(): propagate " << node
- << std::endl;
+bool TheoryFp::propagateLit(TNode node)
+{
+ Trace("fp") << "TheoryFp::propagateLit(): propagate " << node << std::endl;
bool stat = d_out->propagate(node);
if (!stat)
{
- d_conflict = true;
+ d_state.notifyInConflict();
}
return stat;
}
-void TheoryFp::handleConflict(TNode node) {
- Trace("fp") << "TheoryFp::handleConflict(): conflict detected " << node
- << std::endl;
+void TheoryFp::conflictEqConstantMerge(TNode t1, TNode t2)
+{
+ std::vector<TNode> assumptions;
+ d_equalityEngine->explainEquality(t1, t2, true, assumptions);
+
+ Node conflict = helper::buildConjunct(assumptions);
+ Trace("fp") << "TheoryFp::conflictEqConstantMerge(): conflict detected "
+ << conflict << std::endl;
- d_conflictNode = node;
- d_conflict = true;
- d_out->conflict(node);
+ d_conflictNode = conflict;
+ d_state.notifyInConflict();
+ d_out->conflict(conflict);
return;
}
-void TheoryFp::check(Effort level) {
- Trace("fp") << "TheoryFp::check(): started at effort level " << level
- << std::endl;
-
- while (!done() && !d_conflict) {
- // Get all the assertions
- Assertion assertion = get();
- TNode fact = assertion.d_assertion;
-
- Debug("fp") << "TheoryFp::check(): processing " << fact << std::endl;
-
- // Only handle equalities; the rest should be handled by
- // the bit-vector theory
-
- bool negated = fact.getKind() == kind::NOT;
- TNode predicate = negated ? fact[0] : fact;
-
- if (predicate.getKind() == kind::EQUAL) {
- Assert(!(predicate[0].getType().isFloatingPoint()
- || predicate[0].getType().isRoundingMode())
- || isRegistered(predicate[0]));
- Assert(!(predicate[1].getType().isFloatingPoint()
- || predicate[1].getType().isRoundingMode())
- || isRegistered(predicate[1]));
- registerTerm(predicate); // Needed for float equalities
-
- if (negated) {
- Debug("fp-eq") << "TheoryFp::check(): adding dis-equality " << fact[0]
- << std::endl;
- d_equalityEngine.assertEquality(predicate, false, fact);
-
- } else {
- Debug("fp-eq") << "TheoryFp::check(): adding equality " << fact
- << std::endl;
- d_equalityEngine.assertEquality(predicate, true, fact);
- }
- } else {
- // A system-wide invariant; predicates are registered before they are
- // asserted
- Assert(isRegistered(predicate));
-
- if (d_equalityEngine.isFunctionKind(predicate.getKind())) {
- Debug("fp-eq") << "TheoryFp::check(): adding predicate " << predicate
- << " is " << !negated << std::endl;
- d_equalityEngine.assertPredicate(predicate, !negated, fact);
- }
- }
- }
-
+void TheoryFp::postCheck(Effort level)
+{
// Resolve the abstractions for the conversion lemmas
- // if (level == EFFORT_COMBINATION) {
if (level == EFFORT_LAST_CALL)
{
Trace("fp") << "TheoryFp::check(): checking abstractions" << std::endl;
- TheoryModel *m = getValuation().getModel();
+ TheoryModel* m = getValuation().getModel();
bool lemmaAdded = false;
for (abstractionMapType::const_iterator i = abstractionMap.begin();
@@ -1002,14 +965,34 @@ void TheoryFp::check(Effort level) {
}
Trace("fp") << "TheoryFp::check(): completed" << std::endl;
-
/* Checking should be handled by the bit-vector engine */
- return;
+}
-} /* TheoryFp::check() */
+bool TheoryFp::preNotifyFact(
+ TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal)
+{
+ if (atom.getKind() == kind::EQUAL)
+ {
+ Assert(!(atom[0].getType().isFloatingPoint()
+ || atom[0].getType().isRoundingMode())
+ || isRegistered(atom[0]));
+ Assert(!(atom[1].getType().isFloatingPoint()
+ || atom[1].getType().isRoundingMode())
+ || isRegistered(atom[1]));
+ registerTerm(atom); // Needed for float equalities
+ }
+ else
+ {
+ // A system-wide invariant; predicates are registered before they are
+ // asserted
+ Assert(isRegistered(atom));
-void TheoryFp::setMasterEqualityEngine(eq::EqualityEngine *eq) {
- d_equalityEngine.setMasterEqualityEngine(eq);
+ if (!d_equalityEngine->isFunctionKind(atom.getKind()))
+ {
+ return true;
+ }
+ }
+ return false;
}
TrustNode TheoryFp::explain(TNode n)
@@ -1023,9 +1006,9 @@ TrustNode TheoryFp::explain(TNode n)
bool polarity = n.getKind() != kind::NOT;
TNode atom = polarity ? n : n[0];
if (atom.getKind() == kind::EQUAL) {
- d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions);
+ d_equalityEngine->explainEquality(atom[0], atom[1], polarity, assumptions);
} else {
- d_equalityEngine.explainPredicate(atom, polarity, assumptions);
+ d_equalityEngine->explainPredicate(atom, polarity, assumptions);
}
Node exp = helper::buildConjunct(assumptions);
@@ -1036,16 +1019,18 @@ Node TheoryFp::getModelValue(TNode var) {
return d_conv.getValue(d_valuation, var);
}
-bool TheoryFp::collectModelInfo(TheoryModel *m)
+bool TheoryFp::collectModelInfo(TheoryModel* m,
+ const std::set<Node>& relevantTerms)
{
- std::set<Node> relevantTerms;
+ // this override behavior to not assert equality engine
+ return collectModelValues(m, relevantTerms);
+}
+bool TheoryFp::collectModelValues(TheoryModel* m,
+ const std::set<Node>& relevantTerms)
+{
Trace("fp-collectModelInfo")
<< "TheoryFp::collectModelInfo(): begin" << std::endl;
-
- // Work out which variables are needed
- computeRelevantTerms(relevantTerms);
-
if (Trace.isOn("fp-collectModelInfo")) {
for (std::set<Node>::const_iterator i(relevantTerms.begin());
i != relevantTerms.end(); ++i) {
@@ -1135,19 +1120,6 @@ bool TheoryFp::collectModelInfo(TheoryModel *m)
return true;
}
-bool TheoryFp::NotifyClass::eqNotifyTriggerEquality(TNode equality,
- bool value) {
- Debug("fp-eq")
- << "TheoryFp::eqNotifyTriggerEquality(): call back as equality "
- << equality << " is " << value << std::endl;
-
- if (value) {
- return d_theorySolver.handlePropagation(equality);
- } else {
- return d_theorySolver.handlePropagation(equality.notNode());
- }
-}
-
bool TheoryFp::NotifyClass::eqNotifyTriggerPredicate(TNode predicate,
bool value) {
Debug("fp-eq")
@@ -1155,10 +1127,9 @@ bool TheoryFp::NotifyClass::eqNotifyTriggerPredicate(TNode predicate,
<< predicate << " is " << value << std::endl;
if (value) {
- return d_theorySolver.handlePropagation(predicate);
- } else {
- return d_theorySolver.handlePropagation(predicate.notNode());
+ return d_theorySolver.propagateLit(predicate);
}
+ return d_theorySolver.propagateLit(predicate.notNode());
}
bool TheoryFp::NotifyClass::eqNotifyTriggerTermEquality(TheoryId tag, TNode t1,
@@ -1167,22 +1138,15 @@ bool TheoryFp::NotifyClass::eqNotifyTriggerTermEquality(TheoryId tag, TNode t1,
<< t1 << (value ? " = " : " != ") << t2 << std::endl;
if (value) {
- return d_theorySolver.handlePropagation(t1.eqNode(t2));
- } else {
- return d_theorySolver.handlePropagation(t1.eqNode(t2).notNode());
+ return d_theorySolver.propagateLit(t1.eqNode(t2));
}
+ return d_theorySolver.propagateLit(t1.eqNode(t2).notNode());
}
void TheoryFp::NotifyClass::eqNotifyConstantTermMerge(TNode t1, TNode t2) {
Debug("fp-eq") << "TheoryFp::eqNotifyConstantTermMerge(): call back as " << t1
<< " = " << t2 << std::endl;
-
- std::vector<TNode> assumptions;
- d_theorySolver.d_equalityEngine.explainEquality(t1, t2, true, assumptions);
-
- Node conflict = helper::buildConjunct(assumptions);
-
- d_theorySolver.handleConflict(conflict);
+ d_theorySolver.conflictEqConstantMerge(t1, t2);
}
} // namespace fp
diff --git a/src/theory/fp/theory_fp.h b/src/theory/fp/theory_fp.h
index a3e0dd94a..42c009893 100644
--- a/src/theory/fp/theory_fp.h
+++ b/src/theory/fp/theory_fp.h
@@ -2,10 +2,10 @@
/*! \file theory_fp.h
** \verbatim
** Top contributors (to current version):
- ** Martin Brain, Mathias Preiner, Tim King
+ ** Martin Brain, Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -42,26 +42,48 @@ class TheoryFp : public Theory {
Valuation valuation,
const LogicInfo& logicInfo,
ProofNodeManager* pnm = nullptr);
-
- TheoryRewriter* getTheoryRewriter() override { return &d_rewriter; }
+ //--------------------------------- initialization
+ /** get the official theory rewriter of this theory */
+ TheoryRewriter* getTheoryRewriter() override;
+ /**
+ * Returns true if we need an equality engine. If so, we initialize the
+ * information regarding how it should be setup. For details, see the
+ * documentation in Theory::needsEqualityEngine.
+ */
+ bool needsEqualityEngine(EeSetupInfo& esi) override;
+ /** finish initialization */
+ void finishInit() override;
+ //--------------------------------- end initialization
TrustNode expandDefinition(Node node) override;
void preRegisterTerm(TNode node) override;
- void addSharedTerm(TNode node) override;
TrustNode ppRewrite(TNode node) override;
- void check(Effort) override;
-
+ //--------------------------------- standard check
+ /** Do we need a check call at last call effort? */
bool needsCheckLastEffort() override { return true; }
+ /** Post-check, called after the fact queue of the theory is processed. */
+ void postCheck(Effort level) override;
+ /** Pre-notify fact, return true if processed. */
+ bool preNotifyFact(TNode atom,
+ bool pol,
+ TNode fact,
+ bool isPrereg,
+ bool isInternal) override;
+ //--------------------------------- end standard check
+
Node getModelValue(TNode var) override;
- bool collectModelInfo(TheoryModel* m) override;
+ bool collectModelInfo(TheoryModel* m,
+ const std::set<Node>& relevantTerms) override;
+ /** Collect model values in m based on the relevant terms given by
+ * relevantTerms */
+ bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& relevantTerms) override;
std::string identify() const override { return "THEORY_FP"; }
- void setMasterEqualityEngine(eq::EqualityEngine* eq) override;
-
TrustNode explain(TNode n) override;
protected:
@@ -72,7 +94,6 @@ class TheoryFp : public Theory {
public:
NotifyClass(TheoryFp& solver) : d_theorySolver(solver) {}
- bool eqNotifyTriggerEquality(TNode equality, bool value) override;
bool eqNotifyTriggerPredicate(TNode predicate, bool value) override;
bool eqNotifyTriggerTermEquality(TheoryId tag,
TNode t1,
@@ -80,14 +101,12 @@ class TheoryFp : public Theory {
bool value) override;
void eqNotifyConstantTermMerge(TNode t1, TNode t2) override;
void eqNotifyNewClass(TNode t) override {}
- void eqNotifyPreMerge(TNode t1, TNode t2) override {}
- void eqNotifyPostMerge(TNode t1, TNode t2) override {}
+ void eqNotifyMerge(TNode t1, TNode t2) override {}
void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override {}
};
friend NotifyClass;
NotifyClass d_notification;
- eq::EqualityEngine d_equalityEngine;
/** General utility **/
void registerTerm(TNode node);
@@ -103,10 +122,17 @@ class TheoryFp : public Theory {
/** Interaction with the rest of the solver **/
void handleLemma(Node node);
- bool handlePropagation(TNode node);
- void handleConflict(TNode node);
+ /**
+ * Called when literal node is inferred by the equality engine. This
+ * propagates node on the output channel.
+ */
+ bool propagateLit(TNode node);
+ /**
+ * Called when two constants t1 and t2 merge in the equality engine. This
+ * sends a conflict on the output channel.
+ */
+ void conflictEqConstantMerge(TNode t1, TNode t2);
- context::CDO<bool> d_conflict;
context::CDO<Node> d_conflictNode;
typedef context::CDHashMap<TypeNode, Node, TypeNodeHashFunction>
@@ -148,6 +174,8 @@ class TheoryFp : public Theory {
/** The theory rewriter for this theory. */
TheoryFpRewriter d_rewriter;
+ /** A (default) theory state object */
+ TheoryState d_state;
}; /* class TheoryFp */
} // namespace fp
diff --git a/src/theory/fp/theory_fp_rewriter.cpp b/src/theory/fp/theory_fp_rewriter.cpp
index 3d42591b0..78aba415b 100644
--- a/src/theory/fp/theory_fp_rewriter.cpp
+++ b/src/theory/fp/theory_fp_rewriter.cpp
@@ -6,7 +6,7 @@
** Copyright (c) 2013 University of Oxford
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -369,7 +369,7 @@ namespace constantFold {
FloatingPoint arg1(node[1].getConst<FloatingPoint>());
FloatingPoint arg2(node[2].getConst<FloatingPoint>());
- Assert(arg1.t == arg2.t);
+ Assert(arg1.d_fp_size == arg2.d_fp_size);
return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(arg1.plus(rm, arg2)));
}
@@ -382,7 +382,7 @@ namespace constantFold {
FloatingPoint arg1(node[1].getConst<FloatingPoint>());
FloatingPoint arg2(node[2].getConst<FloatingPoint>());
- Assert(arg1.t == arg2.t);
+ Assert(arg1.d_fp_size == arg2.d_fp_size);
return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(arg1.mult(rm, arg2)));
}
@@ -396,8 +396,8 @@ namespace constantFold {
FloatingPoint arg2(node[2].getConst<FloatingPoint>());
FloatingPoint arg3(node[3].getConst<FloatingPoint>());
- Assert(arg1.t == arg2.t);
- Assert(arg1.t == arg3.t);
+ Assert(arg1.d_fp_size == arg2.d_fp_size);
+ Assert(arg1.d_fp_size == arg3.d_fp_size);
return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(arg1.fma(rm, arg2, arg3)));
}
@@ -410,7 +410,7 @@ namespace constantFold {
FloatingPoint arg1(node[1].getConst<FloatingPoint>());
FloatingPoint arg2(node[2].getConst<FloatingPoint>());
- Assert(arg1.t == arg2.t);
+ Assert(arg1.d_fp_size == arg2.d_fp_size);
return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(arg1.div(rm, arg2)));
}
@@ -442,7 +442,7 @@ namespace constantFold {
FloatingPoint arg1(node[0].getConst<FloatingPoint>());
FloatingPoint arg2(node[1].getConst<FloatingPoint>());
- Assert(arg1.t == arg2.t);
+ Assert(arg1.d_fp_size == arg2.d_fp_size);
return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(arg1.rem(arg2)));
}
@@ -454,7 +454,7 @@ namespace constantFold {
FloatingPoint arg1(node[0].getConst<FloatingPoint>());
FloatingPoint arg2(node[1].getConst<FloatingPoint>());
- Assert(arg1.t == arg2.t);
+ Assert(arg1.d_fp_size == arg2.d_fp_size);
FloatingPoint::PartialFloatingPoint res(arg1.min(arg2));
@@ -474,7 +474,7 @@ namespace constantFold {
FloatingPoint arg1(node[0].getConst<FloatingPoint>());
FloatingPoint arg2(node[1].getConst<FloatingPoint>());
- Assert(arg1.t == arg2.t);
+ Assert(arg1.d_fp_size == arg2.d_fp_size);
FloatingPoint::PartialFloatingPoint res(arg1.max(arg2));
@@ -494,7 +494,7 @@ namespace constantFold {
FloatingPoint arg1(node[0].getConst<FloatingPoint>());
FloatingPoint arg2(node[1].getConst<FloatingPoint>());
- Assert(arg1.t == arg2.t);
+ Assert(arg1.d_fp_size == arg2.d_fp_size);
// Can be called with the third argument non-constant
if (node[2].getMetaKind() == kind::metakind::CONSTANT) {
@@ -524,7 +524,7 @@ namespace constantFold {
FloatingPoint arg1(node[0].getConst<FloatingPoint>());
FloatingPoint arg2(node[1].getConst<FloatingPoint>());
- Assert(arg1.t == arg2.t);
+ Assert(arg1.d_fp_size == arg2.d_fp_size);
// Can be called with the third argument non-constant
if (node[2].getMetaKind() == kind::metakind::CONSTANT) {
@@ -558,7 +558,7 @@ namespace constantFold {
FloatingPoint arg1(node[0].getConst<FloatingPoint>());
FloatingPoint arg2(node[1].getConst<FloatingPoint>());
- Assert(arg1.t == arg2.t);
+ Assert(arg1.d_fp_size == arg2.d_fp_size);
return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(arg1 == arg2));
@@ -580,7 +580,7 @@ namespace constantFold {
FloatingPoint arg1(node[0].getConst<FloatingPoint>());
FloatingPoint arg2(node[1].getConst<FloatingPoint>());
- Assert(arg1.t == arg2.t);
+ Assert(arg1.d_fp_size == arg2.d_fp_size);
return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(arg1 <= arg2));
}
@@ -593,7 +593,7 @@ namespace constantFold {
FloatingPoint arg1(node[0].getConst<FloatingPoint>());
FloatingPoint arg2(node[1].getConst<FloatingPoint>());
- Assert(arg1.t == arg2.t);
+ Assert(arg1.d_fp_size == arg2.d_fp_size);
return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(arg1 < arg2));
}
@@ -654,12 +654,12 @@ namespace constantFold {
TNode op = node.getOperator();
const FloatingPointToFPIEEEBitVector &param = op.getConst<FloatingPointToFPIEEEBitVector>();
const BitVector &bv = node[0].getConst<BitVector>();
-
- Node lit =
- NodeManager::currentNM()->mkConst(FloatingPoint(param.t.exponent(),
- param.t.significand(),
- bv));
-
+
+ Node lit = NodeManager::currentNM()->mkConst(
+ FloatingPoint(param.d_fp_size.exponentWidth(),
+ param.d_fp_size.significandWidth(),
+ bv));
+
return RewriteResponse(REWRITE_DONE, lit);
}
@@ -671,7 +671,9 @@ namespace constantFold {
FloatingPoint arg1(node[1].getConst<FloatingPoint>());
FloatingPointToFPFloatingPoint info = node.getOperator().getConst<FloatingPointToFPFloatingPoint>();
- return RewriteResponse(REWRITE_DONE, NodeManager::currentNM()->mkConst(arg1.convert(info.t,rm)));
+ return RewriteResponse(
+ REWRITE_DONE,
+ NodeManager::currentNM()->mkConst(arg1.convert(info.d_fp_size, rm)));
}
RewriteResponse convertFromRealLiteral (TNode node, bool) {
@@ -683,8 +685,8 @@ namespace constantFold {
RoundingMode rm(node[0].getConst<RoundingMode>());
Rational arg(node[1].getConst<Rational>());
- FloatingPoint res(param.t, rm, arg);
-
+ FloatingPoint res(param.d_fp_size, rm, arg);
+
Node lit = NodeManager::currentNM()->mkConst(res);
return RewriteResponse(REWRITE_DONE, lit);
@@ -699,8 +701,8 @@ namespace constantFold {
RoundingMode rm(node[0].getConst<RoundingMode>());
BitVector arg(node[1].getConst<BitVector>());
- FloatingPoint res(param.t, rm, arg, true);
-
+ FloatingPoint res(param.d_fp_size, rm, arg, true);
+
Node lit = NodeManager::currentNM()->mkConst(res);
return RewriteResponse(REWRITE_DONE, lit);
@@ -715,8 +717,8 @@ namespace constantFold {
RoundingMode rm(node[0].getConst<RoundingMode>());
BitVector arg(node[1].getConst<BitVector>());
- FloatingPoint res(param.t, rm, arg, false);
-
+ FloatingPoint res(param.d_fp_size, rm, arg, false);
+
Node lit = NodeManager::currentNM()->mkConst(res);
return RewriteResponse(REWRITE_DONE, lit);
@@ -731,7 +733,8 @@ namespace constantFold {
RoundingMode rm(node[0].getConst<RoundingMode>());
FloatingPoint arg(node[1].getConst<FloatingPoint>());
- FloatingPoint::PartialBitVector res(arg.convertToBV(param.bvs, rm, false));
+ FloatingPoint::PartialBitVector res(
+ arg.convertToBV(param.d_bv_size, rm, false));
if (res.second) {
Node lit = NodeManager::currentNM()->mkConst(res.first);
@@ -751,7 +754,8 @@ namespace constantFold {
RoundingMode rm(node[0].getConst<RoundingMode>());
FloatingPoint arg(node[1].getConst<FloatingPoint>());
- FloatingPoint::PartialBitVector res(arg.convertToBV(param.bvs, rm, true));
+ FloatingPoint::PartialBitVector res(
+ arg.convertToBV(param.d_bv_size, rm, true));
if (res.second) {
Node lit = NodeManager::currentNM()->mkConst(res.first);
@@ -791,12 +795,14 @@ namespace constantFold {
if (node[2].getMetaKind() == kind::metakind::CONSTANT) {
BitVector partialValue(node[2].getConst<BitVector>());
- BitVector folded(arg.convertToBVTotal(param.bvs, rm, false, partialValue));
+ BitVector folded(
+ arg.convertToBVTotal(param.d_bv_size, rm, false, partialValue));
Node lit = NodeManager::currentNM()->mkConst(folded);
return RewriteResponse(REWRITE_DONE, lit);
} else {
- FloatingPoint::PartialBitVector res(arg.convertToBV(param.bvs, rm, false));
+ FloatingPoint::PartialBitVector res(
+ arg.convertToBV(param.d_bv_size, rm, false));
if (res.second) {
Node lit = NodeManager::currentNM()->mkConst(res.first);
@@ -821,13 +827,14 @@ namespace constantFold {
if (node[2].getMetaKind() == kind::metakind::CONSTANT) {
BitVector partialValue(node[2].getConst<BitVector>());
- BitVector folded(arg.convertToBVTotal(param.bvs, rm, true, partialValue));
+ BitVector folded(
+ arg.convertToBVTotal(param.d_bv_size, rm, true, partialValue));
Node lit = NodeManager::currentNM()->mkConst(folded);
return RewriteResponse(REWRITE_DONE, lit);
} else {
-
- FloatingPoint::PartialBitVector res(arg.convertToBV(param.bvs, rm, true));
+ FloatingPoint::PartialBitVector res(
+ arg.convertToBV(param.d_bv_size, rm, true));
if (res.second) {
Node lit = NodeManager::currentNM()->mkConst(res.first);
@@ -880,18 +887,10 @@ namespace constantFold {
switch (k)
{
#ifdef CVC4_USE_SYMFPU
- case kind::FLOATINGPOINT_COMPONENT_NAN:
- result = arg0.getLiteral().nan;
- break;
- case kind::FLOATINGPOINT_COMPONENT_INF:
- result = arg0.getLiteral().inf;
- break;
- case kind::FLOATINGPOINT_COMPONENT_ZERO:
- result = arg0.getLiteral().zero;
- break;
- case kind::FLOATINGPOINT_COMPONENT_SIGN:
- result = arg0.getLiteral().sign;
- break;
+ case kind::FLOATINGPOINT_COMPONENT_NAN: result = arg0.isNaN(); break;
+ case kind::FLOATINGPOINT_COMPONENT_INF: result = arg0.isInfinite(); break;
+ case kind::FLOATINGPOINT_COMPONENT_ZERO: result = arg0.isZero(); break;
+ case kind::FLOATINGPOINT_COMPONENT_SIGN: result = arg0.getSign(); break;
#endif
default: Unreachable() << "Unknown kind used in componentFlag"; break;
}
@@ -912,11 +911,11 @@ namespace constantFold {
return RewriteResponse(
REWRITE_DONE,
#ifdef CVC4_USE_SYMFPU
- NodeManager::currentNM()->mkConst((BitVector)arg0.getLiteral().exponent)
+ NodeManager::currentNM()->mkConst((BitVector)arg0.getExponent())
#else
node
#endif
- );
+ );
}
RewriteResponse componentSignificand(TNode node, bool)
@@ -925,14 +924,14 @@ namespace constantFold {
FloatingPoint arg0(node[0].getConst<FloatingPoint>());
- return RewriteResponse(REWRITE_DONE,
+ return RewriteResponse(
+ REWRITE_DONE,
#ifdef CVC4_USE_SYMFPU
- NodeManager::currentNM()->mkConst(
- (BitVector)arg0.getLiteral().significand)
+ NodeManager::currentNM()->mkConst((BitVector)arg0.getSignificand())
#else
- node
+ node
#endif
- );
+ );
}
RewriteResponse roundingModeBitBlast(TNode node, bool)
@@ -947,23 +946,23 @@ namespace constantFold {
RoundingMode arg0(node[0].getConst<RoundingMode>());
switch (arg0)
{
- case roundNearestTiesToEven:
+ case ROUND_NEAREST_TIES_TO_EVEN:
value = symfpuSymbolic::traits::RNE().getConst<BitVector>();
break;
- case roundNearestTiesToAway:
+ case ROUND_NEAREST_TIES_TO_AWAY:
value = symfpuSymbolic::traits::RNA().getConst<BitVector>();
break;
- case roundTowardPositive:
+ case ROUND_TOWARD_POSITIVE:
value = symfpuSymbolic::traits::RTP().getConst<BitVector>();
break;
- case roundTowardNegative:
+ case ROUND_TOWARD_NEGATIVE:
value = symfpuSymbolic::traits::RTN().getConst<BitVector>();
break;
- case roundTowardZero:
+ case ROUND_TOWARD_ZERO:
value = symfpuSymbolic::traits::RTZ().getConst<BitVector>();
break;
@@ -1344,58 +1343,65 @@ TheoryFpRewriter::TheoryFpRewriter()
}
}
- if (allChildrenConst) {
- RewriteStatus rs = REWRITE_DONE; // This is a bit messy because
- Node rn = res.d_node; // RewriteResponse is too functional..
+ if (allChildrenConst)
+ {
+ RewriteStatus rs = REWRITE_DONE; // This is a bit messy because
+ Node rn = res.d_node; // RewriteResponse is too functional..
- if (apartFromRoundingMode) {
+ if (apartFromRoundingMode)
+ {
if (!(res.d_node.getKind() == kind::EQUAL)
&& // Avoid infinite recursion...
!(res.d_node.getKind() == kind::ROUNDINGMODE_BITBLAST))
- { // Don't eliminate the bit-blast
+ {
+ // Don't eliminate the bit-blast
// We are close to being able to constant fold this
// and in many cases the rounding mode really doesn't matter.
// So we can try brute forcing our way through them.
- NodeManager *nm = NodeManager::currentNM();
+ NodeManager* nm = NodeManager::currentNM();
- Node RNE(nm->mkConst(roundNearestTiesToEven));
- Node RNA(nm->mkConst(roundNearestTiesToAway));
- Node RTZ(nm->mkConst(roundTowardPositive));
- Node RTN(nm->mkConst(roundTowardNegative));
- Node RTP(nm->mkConst(roundTowardZero));
+ Node rne(nm->mkConst(ROUND_NEAREST_TIES_TO_EVEN));
+ Node rna(nm->mkConst(ROUND_NEAREST_TIES_TO_AWAY));
+ Node rtz(nm->mkConst(ROUND_TOWARD_POSITIVE));
+ Node rtn(nm->mkConst(ROUND_TOWARD_NEGATIVE));
+ Node rtp(nm->mkConst(ROUND_TOWARD_ZERO));
- TNode RM(res.d_node[0]);
+ TNode rm(res.d_node[0]);
- Node wRNE(res.d_node.substitute(RM, TNode(RNE)));
- Node wRNA(res.d_node.substitute(RM, TNode(RNA)));
- Node wRTZ(res.d_node.substitute(RM, TNode(RTZ)));
- Node wRTN(res.d_node.substitute(RM, TNode(RTN)));
- Node wRTP(res.d_node.substitute(RM, TNode(RTP)));
+ Node w_rne(res.d_node.substitute(rm, TNode(rne)));
+ Node w_rna(res.d_node.substitute(rm, TNode(rna)));
+ Node w_rtz(res.d_node.substitute(rm, TNode(rtz)));
+ Node w_rtn(res.d_node.substitute(rm, TNode(rtn)));
+ Node w_rtp(res.d_node.substitute(rm, TNode(rtp)));
rs = REWRITE_AGAIN_FULL;
- rn = nm->mkNode(kind::ITE,
- nm->mkNode(kind::EQUAL, RM, RNE),
- wRNE,
- nm->mkNode(kind::ITE,
- nm->mkNode(kind::EQUAL, RM, RNA),
- wRNA,
- nm->mkNode(kind::ITE,
- nm->mkNode(kind::EQUAL, RM, RTZ),
- wRTZ,
- nm->mkNode(kind::ITE,
- nm->mkNode(kind::EQUAL, RM, RTN),
- wRTN,
- wRTP))));
- }
- } else {
+ rn = nm->mkNode(
+ kind::ITE,
+ nm->mkNode(kind::EQUAL, rm, rne),
+ w_rne,
+ nm->mkNode(
+ kind::ITE,
+ nm->mkNode(kind::EQUAL, rm, rna),
+ w_rna,
+ nm->mkNode(kind::ITE,
+ nm->mkNode(kind::EQUAL, rm, rtz),
+ w_rtz,
+ nm->mkNode(kind::ITE,
+ nm->mkNode(kind::EQUAL, rm, rtn),
+ w_rtn,
+ w_rtp))));
+ }
+ }
+ else
+ {
RewriteResponse tmp =
d_constantFoldTable[res.d_node.getKind()](res.d_node, false);
rs = tmp.d_status;
rn = tmp.d_node;
}
- RewriteResponse constRes(rs,rn);
+ RewriteResponse constRes(rs, rn);
if (constRes.d_node != res.d_node)
{
diff --git a/src/theory/fp/theory_fp_rewriter.h b/src/theory/fp/theory_fp_rewriter.h
index f5d1c5234..1232e9c75 100644
--- a/src/theory/fp/theory_fp_rewriter.h
+++ b/src/theory/fp/theory_fp_rewriter.h
@@ -5,7 +5,7 @@
** Andres Noetzli, Martin Brain, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/fp/theory_fp_type_rules.h b/src/theory/fp/theory_fp_type_rules.h
index e3bd5f048..d632e80c8 100644
--- a/src/theory/fp/theory_fp_type_rules.h
+++ b/src/theory/fp/theory_fp_type_rules.h
@@ -5,7 +5,7 @@
** Martin Brain, Tim King, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,6 +19,7 @@
// This is only needed for checking that components are only applied to leaves.
#include "theory/theory.h"
+#include "util/roundingmode.h"
#ifndef CVC4__THEORY__FP__THEORY_FP_TYPE_RULES_H
#define CVC4__THEORY__FP__THEORY_FP_TYPE_RULES_H
@@ -39,17 +40,20 @@ class FloatingPointConstantTypeRule {
const FloatingPoint& f = n.getConst<FloatingPoint>();
- if (check) {
- if (!(validExponentSize(f.t.exponent()))) {
+ if (check)
+ {
+ if (!(validExponentSize(f.d_fp_size.exponentWidth())))
+ {
throw TypeCheckingExceptionPrivate(
n, "constant with invalid exponent size");
}
- if (!(validSignificandSize(f.t.significand()))) {
+ if (!(validSignificandSize(f.d_fp_size.significandWidth())))
+ {
throw TypeCheckingExceptionPrivate(
n, "constant with invalid significand size");
}
}
- return nodeManager->mkFloatingPointType(f.t);
+ return nodeManager->mkFloatingPointType(f.d_fp_size);
}
};
@@ -252,13 +256,17 @@ class FloatingPointToFPIEEEBitVectorTypeRule {
if (check) {
TypeNode operandType = n[0].getType(check);
- if (!(operandType.isBitVector())) {
+ if (!(operandType.isBitVector()))
+ {
throw TypeCheckingExceptionPrivate(n,
"conversion to floating-point from "
"bit vector used with sort other "
"than bit vector");
- } else if (!(operandType.getBitVectorSize() ==
- info.t.exponent() + info.t.significand())) {
+ }
+ else if (!(operandType.getBitVectorSize()
+ == info.d_fp_size.exponentWidth()
+ + info.d_fp_size.significandWidth()))
+ {
throw TypeCheckingExceptionPrivate(
n,
"conversion to floating-point from bit vector used with bit vector "
@@ -266,7 +274,7 @@ class FloatingPointToFPIEEEBitVectorTypeRule {
}
}
- return nodeManager->mkFloatingPointType(info.t);
+ return nodeManager->mkFloatingPointType(info.d_fp_size);
}
};
@@ -298,7 +306,7 @@ class FloatingPointToFPFloatingPointTypeRule {
}
}
- return nodeManager->mkFloatingPointType(info.t);
+ return nodeManager->mkFloatingPointType(info.d_fp_size);
}
};
@@ -330,7 +338,7 @@ class FloatingPointToFPRealTypeRule {
}
}
- return nodeManager->mkFloatingPointType(info.t);
+ return nodeManager->mkFloatingPointType(info.d_fp_size);
}
};
@@ -362,7 +370,7 @@ class FloatingPointToFPSignedBitVectorTypeRule {
}
}
- return nodeManager->mkFloatingPointType(info.t);
+ return nodeManager->mkFloatingPointType(info.d_fp_size);
}
};
@@ -394,7 +402,7 @@ class FloatingPointToFPUnsignedBitVectorTypeRule {
}
}
- return nodeManager->mkFloatingPointType(info.t);
+ return nodeManager->mkFloatingPointType(info.d_fp_size);
}
};
@@ -419,7 +427,7 @@ class FloatingPointToFPGenericTypeRule {
}
}
- return nodeManager->mkFloatingPointType(info.t);
+ return nodeManager->mkFloatingPointType(info.d_fp_size);
}
};
@@ -450,7 +458,7 @@ class FloatingPointToUBVTypeRule {
}
}
- return nodeManager->mkBitVectorType(info.bvs);
+ return nodeManager->mkBitVectorType(info.d_bv_size);
}
};
@@ -481,7 +489,7 @@ class FloatingPointToSBVTypeRule {
}
}
- return nodeManager->mkBitVectorType(info.bvs);
+ return nodeManager->mkBitVectorType(info.d_bv_size);
}
};
@@ -522,7 +530,7 @@ class FloatingPointToUBVTotalTypeRule {
}
}
- return nodeManager->mkBitVectorType(info.bvs);
+ return nodeManager->mkBitVectorType(info.d_bv_size);
}
};
@@ -563,7 +571,7 @@ class FloatingPointToSBVTotalTypeRule {
}
}
- return nodeManager->mkBitVectorType(info.bvs);
+ return nodeManager->mkBitVectorType(info.d_bv_size);
}
};
@@ -686,12 +694,10 @@ class FloatingPointComponentExponent
* Here we use types from floatingpoint.h which are the literal
* back-end but it should't make a difference. */
FloatingPointSize fps = operandType.getConst<FloatingPointSize>();
- symfpuLiteral::fpt format(fps); // The symfpu interface to type info
- unsigned bw = FloatingPointLiteral::exponentWidth(format);
+ unsigned bw = FloatingPoint::getUnpackedExponentWidth(fps);
#else
unsigned bw = 2;
#endif
-
return nodeManager->mkBitVectorType(bw);
}
};
@@ -729,12 +735,10 @@ class FloatingPointComponentSignificand
#ifdef CVC4_USE_SYMFPU
/* As before we need to use some of sympfu. */
FloatingPointSize fps = operandType.getConst<FloatingPointSize>();
- symfpuLiteral::fpt format(fps);
- unsigned bw = FloatingPointLiteral::significandWidth(format);
+ unsigned bw = FloatingPoint::getUnpackedSignificandWidth(fps);
#else
unsigned bw = 1;
#endif
-
return nodeManager->mkBitVectorType(bw);
}
};
@@ -764,12 +768,7 @@ class RoundingModeBitBlast
}
}
-#ifdef CVC4_USE_SYMFPU
- /* Uses sympfu for the macro. */
- return nodeManager->mkBitVectorType(SYMFPU_NUMBER_OF_ROUNDING_MODES);
-#else
- return nodeManager->mkBitVectorType(5);
-#endif
+ return nodeManager->mkBitVectorType(CVC4_NUM_ROUNDING_MODES);
}
};
@@ -791,8 +790,8 @@ public:
* = 5 + ((2^e)-1)*2^s
*/
- Integer significandValues = Integer(2).pow(fps.significand());
- Integer exponentValues = Integer(2).pow(fps.exponent());
+ Integer significandValues = Integer(2).pow(fps.significandWidth());
+ Integer exponentValues = Integer(2).pow(fps.exponentWidth());
exponentValues -= Integer(1);
return Integer(5) + exponentValues * significandValues;
diff --git a/src/theory/fp/type_enumerator.h b/src/theory/fp/type_enumerator.h
index 9741a7ee0..47266eda8 100644
--- a/src/theory/fp/type_enumerator.h
+++ b/src/theory/fp/type_enumerator.h
@@ -6,7 +6,7 @@
** Copyright (c) 2009-2015 New York University and The University of Iowa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -86,8 +86,10 @@ class RoundingModeEnumerator
public:
RoundingModeEnumerator(TypeNode type, TypeEnumeratorProperties* tep = nullptr)
: TypeEnumeratorBase<RoundingModeEnumerator>(type),
- d_rm(roundNearestTiesToEven),
- d_enumerationComplete(false) {}
+ d_rm(ROUND_NEAREST_TIES_TO_EVEN),
+ d_enumerationComplete(false)
+ {
+ }
/** Throws NoMoreValuesException if the enumeration is complete. */
Node operator*() override {
@@ -99,21 +101,11 @@ class RoundingModeEnumerator
RoundingModeEnumerator& operator++() override {
switch (d_rm) {
- case roundNearestTiesToEven:
- d_rm = roundTowardPositive;
- break;
- case roundTowardPositive:
- d_rm = roundTowardNegative;
- break;
- case roundTowardNegative:
- d_rm = roundTowardZero;
- break;
- case roundTowardZero:
- d_rm = roundNearestTiesToAway;
- break;
- case roundNearestTiesToAway:
- d_enumerationComplete = true;
- break;
+ case ROUND_NEAREST_TIES_TO_EVEN: d_rm = ROUND_TOWARD_POSITIVE; break;
+ case ROUND_TOWARD_POSITIVE: d_rm = ROUND_TOWARD_NEGATIVE; break;
+ case ROUND_TOWARD_NEGATIVE: d_rm = ROUND_TOWARD_ZERO; break;
+ case ROUND_TOWARD_ZERO: d_rm = ROUND_NEAREST_TIES_TO_AWAY; break;
+ case ROUND_NEAREST_TIES_TO_AWAY: d_enumerationComplete = true; break;
default: Unreachable() << "Unknown rounding mode?"; break;
}
return *this;
diff --git a/src/theory/inference_manager_buffered.cpp b/src/theory/inference_manager_buffered.cpp
new file mode 100644
index 000000000..cdba5dfd6
--- /dev/null
+++ b/src/theory/inference_manager_buffered.cpp
@@ -0,0 +1,146 @@
+/********************* */
+/*! \file inference_manager_buffered.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief A buffered inference manager
+ **/
+
+#include "theory/inference_manager_buffered.h"
+
+#include "theory/rewriter.h"
+#include "theory/theory.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+
+InferenceManagerBuffered::InferenceManagerBuffered(Theory& t,
+ TheoryState& state,
+ ProofNodeManager* pnm)
+ : TheoryInferenceManager(t, state, pnm), d_processingPendingLemmas(false)
+{
+}
+
+bool InferenceManagerBuffered::hasPending() const
+{
+ return hasPendingFact() || hasPendingLemma();
+}
+
+bool InferenceManagerBuffered::hasPendingFact() const
+{
+ return !d_pendingFact.empty();
+}
+
+bool InferenceManagerBuffered::hasPendingLemma() const
+{
+ return !d_pendingLem.empty();
+}
+
+void InferenceManagerBuffered::addPendingLemma(Node lem,
+ LemmaProperty p,
+ ProofGenerator* pg)
+{
+ // make the simple theory lemma
+ d_pendingLem.emplace_back(new SimpleTheoryLemma(lem, p, pg));
+}
+
+void InferenceManagerBuffered::addPendingLemma(
+ std::unique_ptr<TheoryInference> lemma)
+{
+ d_pendingLem.emplace_back(std::move(lemma));
+}
+
+void InferenceManagerBuffered::addPendingFact(Node conc,
+ Node exp,
+ ProofGenerator* pg)
+{
+ // make a simple theory internal fact
+ Assert(conc.getKind() != AND && conc.getKind() != OR);
+ d_pendingFact.emplace_back(new SimpleTheoryInternalFact(conc, exp, pg));
+}
+
+void InferenceManagerBuffered::addPendingFact(
+ std::unique_ptr<TheoryInference> fact)
+{
+ d_pendingFact.emplace_back(std::move(fact));
+}
+
+void InferenceManagerBuffered::addPendingPhaseRequirement(Node lit, bool pol)
+{
+ // it is the responsibility of the caller to ensure lit is rewritten
+ d_pendingReqPhase[lit] = pol;
+}
+
+void InferenceManagerBuffered::doPendingFacts()
+{
+ size_t i = 0;
+ while (!d_theoryState.isInConflict() && i < d_pendingFact.size())
+ {
+ // process this fact, which notice may enqueue more pending facts in this
+ // loop.
+ d_pendingFact[i]->process(this, false);
+ i++;
+ }
+ d_pendingFact.clear();
+}
+
+void InferenceManagerBuffered::doPendingLemmas()
+{
+ if (d_processingPendingLemmas)
+ {
+ // already processing
+ return;
+ }
+ d_processingPendingLemmas = true;
+ size_t i = 0;
+ while (i < d_pendingLem.size())
+ {
+ // process this lemma, which notice may enqueue more pending lemmas in this
+ // loop, or clear the lemmas.
+ d_pendingLem[i]->process(this, true);
+ i++;
+ }
+ d_pendingLem.clear();
+ d_processingPendingLemmas = false;
+}
+
+void InferenceManagerBuffered::doPendingPhaseRequirements()
+{
+ // process the pending require phase calls
+ for (const std::pair<const Node, bool>& prp : d_pendingReqPhase)
+ {
+ requirePhase(prp.first, prp.second);
+ }
+ d_pendingReqPhase.clear();
+}
+void InferenceManagerBuffered::clearPending()
+{
+ d_pendingFact.clear();
+ d_pendingLem.clear();
+ d_pendingReqPhase.clear();
+}
+void InferenceManagerBuffered::clearPendingFacts() { d_pendingFact.clear(); }
+void InferenceManagerBuffered::clearPendingLemmas() { d_pendingLem.clear(); }
+void InferenceManagerBuffered::clearPendingPhaseRequirements()
+{
+ d_pendingReqPhase.clear();
+}
+
+
+ std::size_t InferenceManagerBuffered::numPendingLemmas() const {
+ return d_pendingLem.size();
+ }
+ std::size_t InferenceManagerBuffered::numPendingFacts() const {
+ return d_pendingFact.size();
+ }
+
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/inference_manager_buffered.h b/src/theory/inference_manager_buffered.h
new file mode 100644
index 000000000..6edc0298f
--- /dev/null
+++ b/src/theory/inference_manager_buffered.h
@@ -0,0 +1,150 @@
+/********************* */
+/*! \file inference_manager_buffered.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief A buffered inference manager
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__INFERENCE_MANAGER_BUFFERED_H
+#define CVC4__THEORY__INFERENCE_MANAGER_BUFFERED_H
+
+#include "context/cdhashmap.h"
+#include "expr/node.h"
+#include "theory/theory_inference.h"
+#include "theory/theory_inference_manager.h"
+
+namespace CVC4 {
+namespace theory {
+
+/**
+ * The buffered inference manager. This class implements standard methods
+ * for buffering facts, lemmas and phase requirements.
+ */
+class InferenceManagerBuffered : public TheoryInferenceManager
+{
+ public:
+ InferenceManagerBuffered(Theory& t,
+ TheoryState& state,
+ ProofNodeManager* pnm);
+ virtual ~InferenceManagerBuffered() {}
+ /**
+ * Do we have a pending fact or lemma?
+ */
+ bool hasPending() const;
+ /**
+ * Do we have a pending fact to add as an internal fact to the equality
+ * engine?
+ */
+ bool hasPendingFact() const;
+ /** Do we have a pending lemma to send on the output channel? */
+ bool hasPendingLemma() const;
+ /**
+ * Add pending lemma lem with property p, with proof generator pg. If
+ * non-null, pg must be able to provide a proof for lem for the remainder
+ * of the user context. Pending lemmas are sent to the output channel using
+ * doPendingLemmas.
+ */
+ void addPendingLemma(Node lem,
+ LemmaProperty p = LemmaProperty::NONE,
+ ProofGenerator* pg = nullptr);
+ /**
+ * Add pending lemma, where lemma can be a (derived) class of the
+ * theory inference base class.
+ */
+ void addPendingLemma(std::unique_ptr<TheoryInference> lemma);
+ /**
+ * Add pending fact, which adds a fact on the pending fact queue. It must
+ * be the case that:
+ * (1) exp => conc is valid,
+ * (2) exp is a literal (or conjunction of literals) that holds in the
+ * equality engine of the theory.
+ *
+ * Pending facts are sent to the equality engine of this class using
+ * doPendingFacts.
+ */
+ void addPendingFact(Node conc, Node exp, ProofGenerator* pg = nullptr);
+ /**
+ * Add pending fact, where fact can be a (derived) class of the
+ * theory inference base class.
+ */
+ void addPendingFact(std::unique_ptr<TheoryInference> fact);
+ /** Add pending phase requirement
+ *
+ * This method is called to indicate this class should send a phase
+ * requirement request to the output channel for literal lit to be
+ * decided with polarity pol. The literal lit should be a SAT literal
+ * by the time that doPendingPhaseRequirements is called. Typically,
+ * lit is a literal that is a subformula of a pending lemma that is processed
+ * prior to sending the phase requirement.
+ */
+ void addPendingPhaseRequirement(Node lit, bool pol);
+ /** Do pending facts
+ *
+ * This method asserts pending facts (d_pendingFact) with explanations
+ * to the equality engine of the theory via calls
+ * to assertInternalFact.
+ *
+ * It terminates early if a conflict is encountered, for instance, by
+ * equality reasoning within the equality engine.
+ *
+ * Regardless of whether a conflict is encountered, the vector d_pendingFact
+ * is cleared after this call.
+ */
+ void doPendingFacts();
+ /** Do pending lemmas
+ *
+ * This method send all pending lemmas (d_pendingLem) on the output
+ * channel of the theory.
+ *
+ * Unlike doPendingFacts, this function will not terminate early if a conflict
+ * has already been encountered by the theory. The vector d_pendingLem is
+ * cleared after this call.
+ */
+ void doPendingLemmas();
+ /**
+ * Do pending phase requirements. Calls the output channel for all pending
+ * phase requirements and clears d_pendingReqPhase.
+ */
+ void doPendingPhaseRequirements();
+ /** Clear pending facts, lemmas, and phase requirements without processing */
+ void clearPending();
+ /** Clear pending facts, without processing */
+ void clearPendingFacts();
+ /** Clear pending lemmas, without processing */
+ void clearPendingLemmas();
+ /** Clear pending phase requirements, without processing */
+ void clearPendingPhaseRequirements();
+
+ /** Returns the number of pending lemmas. */
+ std::size_t numPendingLemmas() const;
+ /** Returns the number of pending facts. */
+ std::size_t numPendingFacts() const;
+
+ protected:
+ /** A set of pending inferences to be processed as lemmas */
+ std::vector<std::unique_ptr<TheoryInference>> d_pendingLem;
+ /** A set of pending inferences to be processed as facts */
+ std::vector<std::unique_ptr<TheoryInference>> d_pendingFact;
+ /** A map from literals to their pending phase requirement */
+ std::map<Node, bool> d_pendingReqPhase;
+ /**
+ * Whether we are currently processing pending lemmas. This flag ensures
+ * that we do not call pending lemmas recursively, which may lead to
+ * segfaults.
+ */
+ bool d_processingPendingLemmas;
+};
+
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/interrupted.h b/src/theory/interrupted.h
index d336e9314..f208dd3ac 100644
--- a/src/theory/interrupted.h
+++ b/src/theory/interrupted.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/logic_info.cpp b/src/theory/logic_info.cpp
index 9805f602e..73cd920d2 100644
--- a/src/theory/logic_info.cpp
+++ b/src/theory/logic_info.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -23,6 +23,7 @@
#include <string>
#include "base/check.h"
+#include "base/configuration.h"
#include "expr/kind.h"
using namespace std;
@@ -43,7 +44,12 @@ LogicInfo::LogicInfo()
d_higherOrder(true),
d_locked(false)
{
- for(TheoryId id = THEORY_FIRST; id < THEORY_LAST; ++id) {
+ for (TheoryId id = THEORY_FIRST; id < THEORY_LAST; ++id)
+ {
+ if (id == THEORY_FP && !Configuration::isBuiltWithSymFPU())
+ {
+ continue;
+ }
enableTheory(id);
}
}
@@ -332,6 +338,11 @@ std::string LogicInfo::getLogicString() const {
ss << "FS";
++seen;
}
+ if (d_theories[THEORY_BAGS])
+ {
+ ss << "FB";
+ ++seen;
+ }
if(seen != d_sharingTheories) {
Unhandled()
<< "can't extract a logic string from LogicInfo; at least one "
diff --git a/src/theory/logic_info.h b/src/theory/logic_info.h
index dd2bbe30c..e97ae8a9d 100644
--- a/src/theory/logic_info.h
+++ b/src/theory/logic_info.h
@@ -5,7 +5,7 @@
** Morgan Deters, Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/mkrewriter b/src/theory/mkrewriter
index 3c27f1b53..871927760 100755
--- a/src/theory/mkrewriter
+++ b/src/theory/mkrewriter
@@ -243,10 +243,6 @@ check_builtin_theory_seen
## output
-# generate warnings about incorrect #line annotations in templates
-nl -ba -s' ' "$template" | grep '^ *[0-9][0-9]* # *line' |
- awk '{OFS="";if($1+1!=$3) print "'"$template"':",$1,": warning: incorrect annotation \"#line ",$3,"\" (it should be \"#line ",($1+1),"\")"}' >&2
-
text=$(cat "$template")
for var in \
rewriter_includes \
diff --git a/src/theory/mktheorytraits b/src/theory/mktheorytraits
index a87203015..1b1350abe 100755
--- a/src/theory/mktheorytraits
+++ b/src/theory/mktheorytraits
@@ -214,20 +214,15 @@ function enumerator {
lineno=${BASH_LINENO[0]}
check_theory_seen
type_enumerator_includes="${type_enumerator_includes}
-#line $lineno \"$kf\"
#include \"$3\""
if expr "$type_constants" : '.* '"$1"' ' &>/dev/null; then
mk_type_enumerator_type_constant_cases="${mk_type_enumerator_type_constant_cases}
-#line $lineno \"$kf\"
case $1:
-#line $lineno \"$kf\"
return new $2(type, tep);
"
elif expr "$type_kinds" : '.* '"$1"' ' &>/dev/null; then
mk_type_enumerator_cases="${mk_type_enumerator_cases}
-#line $lineno \"$kf\"
case kind::$1:
-#line $lineno \"$kf\"
return new $2(type, tep);
"
else
@@ -395,10 +390,6 @@ check_builtin_theory_seen
eval "theory_constructors=\"$theory_constructors\""
-# generate warnings about incorrect #line annotations in templates
-nl -ba -s' ' "$template" | grep '^ *[0-9][0-9]* # *line' |
- awk '{OFS="";if($1+1!=$3) print "'"$template"':",$1,": warning: incorrect annotation \"#line ",$3,"\" (it should be \"#line ",($1+1),"\")"}' >&2
-
text=$(cat "$template")
for var in \
theory_traits \
diff --git a/src/theory/model_manager.cpp b/src/theory/model_manager.cpp
new file mode 100644
index 000000000..e4dddfdbf
--- /dev/null
+++ b/src/theory/model_manager.cpp
@@ -0,0 +1,228 @@
+/********************* */
+/*! \file model_manager.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Abstract management of models for TheoryEngine.
+ **/
+
+#include "theory/model_manager.h"
+
+#include "options/theory_options.h"
+#include "theory/quantifiers_engine.h"
+#include "theory/theory_engine.h"
+
+namespace CVC4 {
+namespace theory {
+
+ModelManager::ModelManager(TheoryEngine& te, EqEngineManager& eem)
+ : d_te(te),
+ d_logicInfo(te.getLogicInfo()),
+ d_eem(eem),
+ d_modelEqualityEngine(nullptr),
+ d_modelEqualityEngineAlloc(nullptr),
+ d_model(nullptr),
+ d_modelBuilder(nullptr),
+ d_modelBuilt(false),
+ d_modelBuiltSuccess(false)
+{
+}
+
+ModelManager::~ModelManager() {}
+
+void ModelManager::finishInit(eq::EqualityEngineNotify* notify)
+{
+ // construct the model
+ const LogicInfo& logicInfo = d_te.getLogicInfo();
+ // Initialize the model and model builder.
+ if (logicInfo.isQuantified())
+ {
+ QuantifiersEngine* qe = d_te.getQuantifiersEngine();
+ Assert(qe != nullptr);
+ d_modelBuilder = qe->getModelBuilder();
+ d_model = qe->getModel();
+ }
+ else
+ {
+ context::Context* u = d_te.getUserContext();
+ d_alocModel.reset(
+ new TheoryModel(u, "DefaultModel", options::assignFunctionValues()));
+ d_model = d_alocModel.get();
+ }
+
+ // make the default builder, e.g. in the case that the quantifiers engine does
+ // not have a model builder
+ if (d_modelBuilder == nullptr)
+ {
+ d_alocModelBuilder.reset(new TheoryEngineModelBuilder(&d_te));
+ d_modelBuilder = d_alocModelBuilder.get();
+ }
+ // notice that the equality engine of the model has yet to be assigned.
+ initializeModelEqEngine(notify);
+}
+
+void ModelManager::resetModel()
+{
+ d_modelBuilt = false;
+ d_modelBuiltSuccess = false;
+ // Reset basic information on the model object
+ d_model->reset();
+}
+
+bool ModelManager::buildModel()
+{
+ if (d_modelBuilt)
+ {
+ // already computed
+ return d_modelBuiltSuccess;
+ }
+ // reset the flags now
+ d_modelBuilt = true;
+ d_modelBuiltSuccess = false;
+
+ // prepare the model, which is specific to the manager
+ if (!prepareModel())
+ {
+ Trace("model-builder") << "ModelManager: fail prepare model" << std::endl;
+ return false;
+ }
+
+ // now, finish building the model
+ d_modelBuiltSuccess = finishBuildModel();
+ return d_modelBuiltSuccess;
+}
+
+bool ModelManager::isModelBuilt() const { return d_modelBuilt; }
+
+void ModelManager::postProcessModel(bool incomplete)
+{
+ if (!d_modelBuilt)
+ {
+ // model not built, nothing to do
+ return;
+ }
+ Trace("model-builder") << "ModelManager: post-process model..." << std::endl;
+ // model construction should always succeed unless lemmas were added
+ AlwaysAssert(d_modelBuiltSuccess);
+ if (!options::produceModels())
+ {
+ return;
+ }
+ // Do post-processing of model from the theories (used for THEORY_SEP
+ // to construct heap model)
+ for (TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST;
+ ++theoryId)
+ {
+ Theory* t = d_te.theoryOf(theoryId);
+ if (t == nullptr)
+ {
+ // theory not active, skip
+ continue;
+ }
+ Trace("model-builder-debug")
+ << " PostProcessModel on theory: " << theoryId << std::endl;
+ t->postProcessModel(d_model);
+ }
+ // also call the model builder's post-process model
+ d_modelBuilder->postProcessModel(incomplete, d_model);
+}
+
+theory::TheoryModel* ModelManager::getModel() { return d_model; }
+
+bool ModelManager::collectModelBooleanVariables()
+{
+ Trace("model-builder") << " CollectModelInfo boolean variables" << std::endl;
+ // Get value of the Boolean variables
+ prop::PropEngine* propEngine = d_te.getPropEngine();
+ std::vector<TNode> boolVars;
+ propEngine->getBooleanVariables(boolVars);
+ std::vector<TNode>::iterator it, iend = boolVars.end();
+ bool hasValue, value;
+ for (it = boolVars.begin(); it != iend; ++it)
+ {
+ TNode var = *it;
+ hasValue = propEngine->hasValue(var, value);
+ // Should we assert that hasValue is true?
+ if (!hasValue)
+ {
+ Trace("model-builder-assertions")
+ << " has no value : " << var << std::endl;
+ value = false;
+ }
+ Trace("model-builder-assertions")
+ << "(assert" << (value ? " " : " (not ") << var
+ << (value ? ");" : "));") << std::endl;
+ if (!d_model->assertPredicate(var, value))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+void ModelManager::collectAssertedTerms(TheoryId tid,
+ std::set<Node>& termSet,
+ bool includeShared) const
+{
+ Theory* t = d_te.theoryOf(tid);
+ // Collect all terms appearing in assertions
+ context::CDList<Assertion>::const_iterator assert_it = t->facts_begin(),
+ assert_it_end = t->facts_end();
+ for (; assert_it != assert_it_end; ++assert_it)
+ {
+ collectTerms(tid, *assert_it, termSet);
+ }
+
+ if (includeShared)
+ {
+ // Add terms that are shared terms
+ context::CDList<TNode>::const_iterator shared_it = t->shared_terms_begin(),
+ shared_it_end =
+ t->shared_terms_end();
+ for (; shared_it != shared_it_end; ++shared_it)
+ {
+ collectTerms(tid, *shared_it, termSet);
+ }
+ }
+}
+
+void ModelManager::collectTerms(TheoryId tid,
+ TNode n,
+ std::set<Node>& termSet) const
+{
+ const std::set<Kind>& irrKinds = d_model->getIrrelevantKinds();
+ std::vector<TNode> visit;
+ TNode cur;
+ visit.push_back(n);
+ do
+ {
+ cur = visit.back();
+ visit.pop_back();
+ if (termSet.find(cur) != termSet.end())
+ {
+ // already visited
+ continue;
+ }
+ Kind k = cur.getKind();
+ // only add to term set if a relevant kind
+ if (irrKinds.find(k) == irrKinds.end())
+ {
+ termSet.insert(cur);
+ }
+ // traverse owned terms, don't go under quantifiers
+ if ((k == kind::NOT || k == kind::EQUAL || Theory::theoryOf(cur) == tid)
+ && !cur.isClosure())
+ {
+ visit.insert(visit.end(), cur.begin(), cur.end());
+ }
+ } while (!visit.empty());
+}
+
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/model_manager.h b/src/theory/model_manager.h
new file mode 100644
index 000000000..8ebeff16b
--- /dev/null
+++ b/src/theory/model_manager.h
@@ -0,0 +1,156 @@
+/********************* */
+/*! \file model_manager.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Abstract management of models for TheoryEngine.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__MODEL_MANAGER__H
+#define CVC4__THEORY__MODEL_MANAGER__H
+
+#include <memory>
+
+#include "theory/ee_manager.h"
+#include "theory/logic_info.h"
+#include "theory/theory_model.h"
+#include "theory/theory_model_builder.h"
+
+namespace CVC4 {
+
+class TheoryEngine;
+
+namespace theory {
+
+/**
+ * A base class for managing models. Its main feature is to implement a
+ * buildModel command. Overall, its behavior is specific to the kind of equality
+ * engine management mode we are using. In particular, the prepare model
+ * method is a manager-specific way for setting up the equality engine of the
+ * model in preparation for model building.
+ */
+class ModelManager
+{
+ public:
+ ModelManager(TheoryEngine& te, EqEngineManager& eem);
+ virtual ~ModelManager();
+ /**
+ * Finish initializing this class, which allocates the model, the model
+ * builder as well as the equality engine of the model. The equality engine
+ * to use is determined by the virtual method initializeModelEqEngine.
+ *
+ * @param notify The object that wants to be notified for callbacks occurring
+ */
+ void finishInit(eq::EqualityEngineNotify* notify);
+ /** Reset model, called during full effort check before the model is built */
+ void resetModel();
+ /**
+ * Build the model. If we have yet to build the model on this round, this
+ * method calls the (manager-specific) prepareModel method and then calls
+ * finishBuildModel.
+ *
+ * @return true if model building was successful.
+ */
+ bool buildModel();
+ /**
+ * Have we called buildModel this round? Note this returns true whether or
+ * not the model building was successful.
+ */
+ bool isModelBuilt() const;
+ /**
+ * Post process model, which is used as a way of each theory adding additional
+ * information to the model after successfully building a model.
+ */
+ void postProcessModel(bool incomplete);
+ /** Get a pointer to model object maintained by this class. */
+ theory::TheoryModel* getModel();
+ //------------------------ finer grained control over model building
+ /**
+ * Prepare model, which is the manager-specific method for setting up the
+ * equality engine of the model. This should assert all relevant information
+ * about the model into the equality engine of d_model.
+ *
+ * @return true if we are in conflict (i.e. the equality engine of the model
+ * equality engine is inconsistent).
+ */
+ virtual bool prepareModel() = 0;
+ /**
+ * Finish build model, which calls the theory model builder to assign values
+ * to all equivalence classes. This should be run after prepareModel.
+ *
+ * @return true if model building was successful.
+ */
+ virtual bool finishBuildModel() const = 0;
+ //------------------------ end finer grained control over model building
+ protected:
+ /**
+ * Initialize model equality engine. This is called at the end of finish
+ * init, after we have created a model object but before we have assigned it
+ * an equality engine.
+ */
+ virtual void initializeModelEqEngine(eq::EqualityEngineNotify* notify) = 0;
+ /**
+ * Collect model Boolean variables.
+ * This asserts the values of all boolean variables to the equality engine of
+ * the model, based on their value in the prop engine.
+ *
+ * @return true if we are in conflict.
+ */
+ bool collectModelBooleanVariables();
+ /**
+ * Collect asserted terms for theory with the given identifier, add to
+ * termSet.
+ *
+ * @param tid The theory whose assertions we are collecting
+ * @param termSet The set to add terms to
+ * @param includeShared Whether to include the shared terms of the theory
+ */
+ void collectAssertedTerms(TheoryId tid,
+ std::set<Node>& termSet,
+ bool includeShared = true) const;
+ /**
+ * Helper function for collectAssertedTerms, adds all subterms
+ * belonging to theory tid to termSet.
+ */
+ void collectTerms(TheoryId tid, TNode n, std::set<Node>& termSet) const;
+ /** Reference to the theory engine */
+ TheoryEngine& d_te;
+ /** Logic info of theory engine (cached) */
+ const LogicInfo& d_logicInfo;
+ /** The equality engine manager */
+ EqEngineManager& d_eem;
+ /**
+ * A dummy context for the model equality engine, so we can clear it
+ * independently of search context.
+ */
+ context::Context d_modelEeContext;
+ /** Pointer to the equality engine of the model */
+ eq::EqualityEngine* d_modelEqualityEngine;
+ /** The equality engine of the model, if we allocated it */
+ std::unique_ptr<eq::EqualityEngine> d_modelEqualityEngineAlloc;
+ /** The model object we are using */
+ theory::TheoryModel* d_model;
+ /** The model object we have allocated (if one exists) */
+ std::unique_ptr<theory::TheoryModel> d_alocModel;
+ /** The model builder object we are using */
+ theory::TheoryEngineModelBuilder* d_modelBuilder;
+ /** The model builder object we have allocated (if one exists) */
+ std::unique_ptr<theory::TheoryEngineModelBuilder> d_alocModelBuilder;
+ /** whether we have tried to build this model in the current context */
+ bool d_modelBuilt;
+ /** whether this model has been built successfully */
+ bool d_modelBuiltSuccess;
+};
+
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__MODEL_MANAGER__H */
diff --git a/src/theory/model_manager_distributed.cpp b/src/theory/model_manager_distributed.cpp
new file mode 100644
index 000000000..7d121af53
--- /dev/null
+++ b/src/theory/model_manager_distributed.cpp
@@ -0,0 +1,116 @@
+/********************* */
+/*! \file model_manager_distributed.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Management of a distributed approach for model generation.
+ **/
+
+#include "theory/model_manager_distributed.h"
+
+#include "theory/theory_engine.h"
+#include "theory/theory_model.h"
+
+namespace CVC4 {
+namespace theory {
+
+ModelManagerDistributed::ModelManagerDistributed(TheoryEngine& te,
+ EqEngineManager& eem)
+ : ModelManager(te, eem)
+{
+}
+
+ModelManagerDistributed::~ModelManagerDistributed()
+{
+ // pop the model context which we pushed on initialization
+ d_modelEeContext.pop();
+}
+
+void ModelManagerDistributed::initializeModelEqEngine(
+ eq::EqualityEngineNotify* notify)
+{
+ // initialize the model equality engine, use the provided notification object,
+ // which belongs e.g. to CombinationModelBased
+ EeSetupInfo esim;
+ esim.d_notify = notify;
+ esim.d_name = d_model->getName() + "::ee";
+ esim.d_constantsAreTriggers = false;
+ d_modelEqualityEngineAlloc.reset(
+ d_eem.allocateEqualityEngine(esim, &d_modelEeContext));
+ d_modelEqualityEngine = d_modelEqualityEngineAlloc.get();
+ // finish initializing the model
+ d_model->finishInit(d_modelEqualityEngine);
+ // We push a context during initialization since the model is cleared during
+ // collectModelInfo using pop/push.
+ d_modelEeContext.push();
+}
+
+bool ModelManagerDistributed::prepareModel()
+{
+ Trace("model-builder") << "ModelManagerDistributed: reset model..."
+ << std::endl;
+
+ // push/pop to clear the equality engine of the model
+ d_modelEeContext.pop();
+ d_modelEeContext.push();
+
+ // Collect model info from the theories
+ Trace("model-builder") << "ModelManagerDistributed: Collect model info..."
+ << std::endl;
+ // Consult each active theory to get all relevant information concerning the
+ // model, which includes both dump their equality information and assigning
+ // values. Notice the order of theories here is important and is the same
+ // as the list in CVC4_FOR_EACH_THEORY in theory_engine.cpp.
+ for (TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST;
+ ++theoryId)
+ {
+ if (!d_logicInfo.isTheoryEnabled(theoryId))
+ {
+ // theory not active, skip
+ continue;
+ }
+ Theory* t = d_te.theoryOf(theoryId);
+ Trace("model-builder") << " CollectModelInfo on theory: " << theoryId
+ << std::endl;
+ // collect the asserted terms
+ std::set<Node> termSet;
+ collectAssertedTerms(theoryId, termSet);
+ // also get relevant terms
+ t->computeRelevantTerms(termSet);
+ if (!t->collectModelInfo(d_model, termSet))
+ {
+ Trace("model-builder")
+ << "ModelManagerDistributed: fail collect model info" << std::endl;
+ return false;
+ }
+ }
+
+ if (!collectModelBooleanVariables())
+ {
+ Trace("model-builder") << "ModelManagerDistributed: fail Boolean variables"
+ << std::endl;
+ return false;
+ }
+
+ return true;
+}
+
+bool ModelManagerDistributed::finishBuildModel() const
+{
+ // do not use relevant terms
+ if (!d_modelBuilder->buildModel(d_model))
+ {
+ Trace("model-builder") << "ModelManager: fail build model" << std::endl;
+ return false;
+ }
+ return true;
+}
+
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/model_manager_distributed.h b/src/theory/model_manager_distributed.h
new file mode 100644
index 000000000..4b17f2460
--- /dev/null
+++ b/src/theory/model_manager_distributed.h
@@ -0,0 +1,63 @@
+/********************* */
+/*! \file model_manager_distributed.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Management of a distributed approach for model generation.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__MODEL_MANAGER_DISTRIBUTED__H
+#define CVC4__THEORY__MODEL_MANAGER_DISTRIBUTED__H
+
+#include <memory>
+
+#include "theory/ee_manager.h"
+#include "theory/model_manager.h"
+
+namespace CVC4 {
+
+class TheoryEngine;
+
+namespace theory {
+
+/**
+ * Manager for building models where the equality engine of the model is
+ * a separate instance. Notice that this manager can be used regardless of the
+ * method for managing the equality engines of the theories (which is the
+ * responsibility of the equality engine manager eem referenced by this class).
+ *
+ * Its prepare model method uses collectModelInfo to assert all equalities from
+ * the equality engine of each theory into the equality engine of the model. It
+ * additionally uses the model equality engine context to clear the information
+ * from the model's equality engine, which is maintained by this class.
+ */
+class ModelManagerDistributed : public ModelManager
+{
+ public:
+ ModelManagerDistributed(TheoryEngine& te, EqEngineManager& eem);
+ ~ModelManagerDistributed();
+
+ /** Prepare the model, as described above. */
+ bool prepareModel() override;
+ /**
+ * Assign values to all equivalence classes in the equality engine of the
+ * model, return true if successful.
+ */
+ bool finishBuildModel() const override;
+ protected:
+ /** Initialize model equality engine */
+ void initializeModelEqEngine(eq::EqualityEngineNotify* notify) override;
+};
+
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__MODEL_MANAGER_DISTRIBUTED__H */
diff --git a/src/theory/output_channel.cpp b/src/theory/output_channel.cpp
new file mode 100644
index 000000000..91f30514c
--- /dev/null
+++ b/src/theory/output_channel.cpp
@@ -0,0 +1,114 @@
+/********************* */
+/*! \file output_channel.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The theory output channel interface
+ **/
+
+#include "theory/output_channel.h"
+
+namespace CVC4 {
+namespace theory {
+
+LemmaProperty operator|(LemmaProperty lhs, LemmaProperty rhs)
+{
+ return static_cast<LemmaProperty>(static_cast<uint32_t>(lhs)
+ | static_cast<uint32_t>(rhs));
+}
+LemmaProperty& operator|=(LemmaProperty& lhs, LemmaProperty rhs)
+{
+ lhs = lhs | rhs;
+ return lhs;
+}
+LemmaProperty operator&(LemmaProperty lhs, LemmaProperty rhs)
+{
+ return static_cast<LemmaProperty>(static_cast<uint32_t>(lhs)
+ & static_cast<uint32_t>(rhs));
+}
+LemmaProperty& operator&=(LemmaProperty& lhs, LemmaProperty rhs)
+{
+ lhs = lhs & rhs;
+ return lhs;
+}
+bool isLemmaPropertyRemovable(LemmaProperty p)
+{
+ return (p & LemmaProperty::REMOVABLE) != LemmaProperty::NONE;
+}
+bool isLemmaPropertyPreprocess(LemmaProperty p)
+{
+ return (p & LemmaProperty::PREPROCESS) != LemmaProperty::NONE;
+}
+bool isLemmaPropertySendAtoms(LemmaProperty p)
+{
+ return (p & LemmaProperty::SEND_ATOMS) != LemmaProperty::NONE;
+}
+bool isLemmaPropertyNeedsJustify(LemmaProperty p)
+{
+ return (p & LemmaProperty::NEEDS_JUSTIFY) != LemmaProperty::NONE;
+}
+
+std::ostream& operator<<(std::ostream& out, LemmaProperty p)
+{
+ if (p == LemmaProperty::NONE)
+ {
+ out << "NONE";
+ }
+ else
+ {
+ out << "{";
+ if (isLemmaPropertyRemovable(p))
+ {
+ out << " REMOVABLE";
+ }
+ if (isLemmaPropertyPreprocess(p))
+ {
+ out << " PREPROCESS";
+ }
+ if (isLemmaPropertySendAtoms(p))
+ {
+ out << " SEND_ATOMS";
+ }
+ if (isLemmaPropertyNeedsJustify(p))
+ {
+ out << " NEEDS_JUSTIFY";
+ }
+ out << " }";
+ }
+ return out;
+}
+
+LemmaStatus::LemmaStatus(TNode rewrittenLemma, unsigned level)
+ : d_rewrittenLemma(rewrittenLemma), d_level(level)
+{
+}
+
+TNode LemmaStatus::getRewrittenLemma() const { return d_rewrittenLemma; }
+
+unsigned LemmaStatus::getLevel() const { return d_level; }
+
+LemmaStatus OutputChannel::split(TNode n)
+{
+ return splitLemma(n.orNode(n.notNode()));
+}
+
+void OutputChannel::trustedConflict(TrustNode pconf)
+{
+ Unreachable() << "OutputChannel::trustedConflict: no implementation"
+ << std::endl;
+}
+
+LemmaStatus OutputChannel::trustedLemma(TrustNode lem, LemmaProperty p)
+{
+ Unreachable() << "OutputChannel::trustedLemma: no implementation"
+ << std::endl;
+}
+
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/output_channel.h b/src/theory/output_channel.h
index ff13d1b6b..197e42a99 100644
--- a/src/theory/output_channel.h
+++ b/src/theory/output_channel.h
@@ -2,10 +2,10 @@
/*! \file output_channel.h
** \verbatim
** Top contributors (to current version):
- ** Morgan Deters, Tim King, Liana Hadarean
+ ** Morgan Deters, Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -22,16 +22,54 @@
#include <memory>
#include "expr/proof_node.h"
-#include "proof/proof_manager.h"
#include "smt/logic_exception.h"
#include "theory/interrupted.h"
#include "theory/trust_node.h"
-#include "util/proof.h"
#include "util/resource_manager.h"
namespace CVC4 {
namespace theory {
+/** Properties of lemmas */
+enum class LemmaProperty : uint32_t
+{
+ // default
+ NONE = 0,
+ // whether the lemma is removable
+ REMOVABLE = 1,
+ // whether the lemma needs preprocessing
+ PREPROCESS = 2,
+ // whether the processing of the lemma should send atoms to the caller
+ SEND_ATOMS = 4,
+ // whether the lemma is part of the justification for answering "sat"
+ NEEDS_JUSTIFY = 8
+};
+/** Define operator lhs | rhs */
+LemmaProperty operator|(LemmaProperty lhs, LemmaProperty rhs);
+/** Define operator lhs |= rhs */
+LemmaProperty& operator|=(LemmaProperty& lhs, LemmaProperty rhs);
+/** Define operator lhs & rhs */
+LemmaProperty operator&(LemmaProperty lhs, LemmaProperty rhs);
+/** Define operator lhs &= rhs */
+LemmaProperty& operator&=(LemmaProperty& lhs, LemmaProperty rhs);
+/** is the removable bit set on p? */
+bool isLemmaPropertyRemovable(LemmaProperty p);
+/** is the preprocess bit set on p? */
+bool isLemmaPropertyPreprocess(LemmaProperty p);
+/** is the send atoms bit set on p? */
+bool isLemmaPropertySendAtoms(LemmaProperty p);
+/** is the needs justify bit set on p? */
+bool isLemmaPropertyNeedsJustify(LemmaProperty p);
+
+/**
+ * Writes an lemma property name to a stream.
+ *
+ * @param out The stream to write to
+ * @param p The lemma property to write to the stream
+ * @return The stream
+ */
+std::ostream& operator<<(std::ostream& out, LemmaProperty p);
+
class Theory;
/**
@@ -41,17 +79,17 @@ class Theory;
*/
class LemmaStatus {
public:
- LemmaStatus(TNode rewrittenLemma, unsigned level)
- : d_rewrittenLemma(rewrittenLemma), d_level(level) {}
+ LemmaStatus(TNode rewrittenLemma, unsigned level);
/** Get the T-rewritten form of the lemma. */
- TNode getRewrittenLemma() const { return d_rewrittenLemma; }
+ TNode getRewrittenLemma() const;
/**
* Get the user-level at which the lemma resides. After this user level
* is popped, the lemma is un-asserted from the SAT layer. This level
* will be 0 if the lemma didn't reach the SAT layer at all.
*/
- unsigned getLevel() const { return d_level; }
+ unsigned getLevel() const;
+
private:
Node d_rewrittenLemma;
unsigned d_level;
@@ -95,10 +133,8 @@ class OutputChannel {
* assigned false), or else a literal by itself (in the case of a
* unit conflict) which is assigned TRUE (and T-conflicting) in the
* current assignment.
- * @param pf - a proof of the conflict. This is only non-null if proofs
- * are enabled.
*/
- virtual void conflict(TNode n, std::unique_ptr<Proof> pf = nullptr) = 0;
+ virtual void conflict(TNode n) = 0;
/**
* Propagate a theory literal.
@@ -113,24 +149,11 @@ class OutputChannel {
* been detected. (This requests a split.)
*
* @param n - a theory lemma valid at decision level 0
- * @param rule - the proof rule for this lemma
- * @param removable - whether the lemma can be removed at any point
- * @param preprocess - whether to apply more aggressive preprocessing
- * @param sendAtoms - whether to ensure atoms are sent to the theory
+ * @param p The properties of the lemma
* @return the "status" of the lemma, including user level at which
* the lemma resides; the lemma will be removed when this user level pops
*/
- virtual LemmaStatus lemma(TNode n, ProofRule rule, bool removable = false,
- bool preprocess = false,
- bool sendAtoms = false) = 0;
-
- /**
- * Variant of the lemma function that does not require providing a proof rule.
- */
- virtual LemmaStatus lemma(TNode n, bool removable = false,
- bool preprocess = false, bool sendAtoms = false) {
- return lemma(n, RULE_INVALID, removable, preprocess, sendAtoms);
- }
+ virtual LemmaStatus lemma(TNode n, LemmaProperty p = LemmaProperty::NONE) = 0;
/**
* Request a split on a new theory atom. This is equivalent to
@@ -138,7 +161,7 @@ class OutputChannel {
*
* @param n - a theory atom; must be of Boolean type
*/
- LemmaStatus split(TNode n) { return splitLemma(n.orNode(n.notNode())); }
+ LemmaStatus split(TNode n);
virtual LemmaStatus splitLemma(TNode n, bool removable = false) = 0;
@@ -197,11 +220,7 @@ class OutputChannel {
* by the generator pfg. Apart from pfg, the interface for this method is
* the same as OutputChannel.
*/
- virtual void trustedConflict(TrustNode pconf)
- {
- Unreachable() << "OutputChannel::trustedConflict: no implementation"
- << std::endl;
- }
+ virtual void trustedConflict(TrustNode pconf);
/**
* Let plem be the pair (Node lem, ProofGenerator * pfg).
* Send lem on the output channel of this class whose proof can be generated
@@ -209,13 +228,7 @@ class OutputChannel {
* the same as OutputChannel.
*/
virtual LemmaStatus trustedLemma(TrustNode lem,
- bool removable = false,
- bool preprocess = false,
- bool sendAtoms = false)
- {
- Unreachable() << "OutputChannel::trustedLemma: no implementation"
- << std::endl;
- }
+ LemmaProperty p = LemmaProperty::NONE);
//---------------------------- end new proof
}; /* class OutputChannel */
diff --git a/src/theory/quantifiers/alpha_equivalence.cpp b/src/theory/quantifiers/alpha_equivalence.cpp
index 624c49698..20fcaad49 100644
--- a/src/theory/quantifiers/alpha_equivalence.cpp
+++ b/src/theory/quantifiers/alpha_equivalence.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -17,12 +17,12 @@
#include "theory/quantifiers_engine.h"
-using namespace CVC4;
-using namespace std;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
using namespace CVC4::kind;
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
struct sortTypeOrder {
expr::TermCanonize* d_tu;
bool operator() (TypeNode i, TypeNode j) {
@@ -142,15 +142,23 @@ Node AlphaEquivalence::reduceQuantifier(Node q)
Node lem;
if (ret != q)
{
- // do not reduce annotated quantified formulas based on alpha equivalence
- if (q.getNumChildren() == 2)
+ // lemma ( q <=> d_quant )
+ // Notice that we infer this equivalence regardless of whether q or ret
+ // have annotations (e.g. user patterns, names, etc.).
+ Trace("alpha-eq") << "Alpha equivalent : " << std::endl;
+ Trace("alpha-eq") << " " << q << std::endl;
+ Trace("alpha-eq") << " " << ret << std::endl;
+ lem = q.eqNode(ret);
+ if (q.getNumChildren() == 3)
{
- // lemma ( q <=> d_quant )
- Trace("alpha-eq") << "Alpha equivalent : " << std::endl;
- Trace("alpha-eq") << " " << q << std::endl;
- Trace("alpha-eq") << " " << ret << std::endl;
- lem = q.eqNode(ret);
+ Notice() << "Ignoring annotated quantified formula based on alpha "
+ "equivalence: "
+ << q << std::endl;
}
}
return lem;
}
+
+} // namespace quantifiers
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/quantifiers/alpha_equivalence.h b/src/theory/quantifiers/alpha_equivalence.h
index 9e3645f4e..c2e8e2214 100644
--- a/src/theory/quantifiers/alpha_equivalence.h
+++ b/src/theory/quantifiers/alpha_equivalence.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Paul Meng
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/anti_skolem.cpp b/src/theory/quantifiers/anti_skolem.cpp
index f8c894c17..531dd8d21 100644
--- a/src/theory/quantifiers/anti_skolem.cpp
+++ b/src/theory/quantifiers/anti_skolem.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/anti_skolem.h b/src/theory/quantifiers/anti_skolem.h
index e7577de22..93834d7ce 100644
--- a/src/theory/quantifiers/anti_skolem.h
+++ b/src/theory/quantifiers/anti_skolem.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/bv_inverter.cpp b/src/theory/quantifiers/bv_inverter.cpp
index 6f2eea0be..8d5e98780 100644
--- a/src/theory/quantifiers/bv_inverter.cpp
+++ b/src/theory/quantifiers/bv_inverter.cpp
@@ -5,7 +5,7 @@
** Aina Niemetz, Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/bv_inverter.h b/src/theory/quantifiers/bv_inverter.h
index dbd04aad1..1952cb6e3 100644
--- a/src/theory/quantifiers/bv_inverter.h
+++ b/src/theory/quantifiers/bv_inverter.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/bv_inverter_utils.cpp b/src/theory/quantifiers/bv_inverter_utils.cpp
index 131e894c2..0f1cdfadb 100644
--- a/src/theory/quantifiers/bv_inverter_utils.cpp
+++ b/src/theory/quantifiers/bv_inverter_utils.cpp
@@ -5,7 +5,7 @@
** Aina Niemetz, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/bv_inverter_utils.h b/src/theory/quantifiers/bv_inverter_utils.h
index 11cfadcca..3a0d89282 100644
--- a/src/theory/quantifiers/bv_inverter_utils.h
+++ b/src/theory/quantifiers/bv_inverter_utils.h
@@ -5,7 +5,7 @@
** Aina Niemetz, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/candidate_rewrite_database.cpp b/src/theory/quantifiers/candidate_rewrite_database.cpp
index 4593f36f1..fef9bec22 100644
--- a/src/theory/quantifiers/candidate_rewrite_database.cpp
+++ b/src/theory/quantifiers/candidate_rewrite_database.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,7 +16,6 @@
#include "api/cvc4cpp.h"
#include "options/base_options.h"
-#include "options/quantifiers_options.h"
#include "printer/printer.h"
#include "smt/smt_engine.h"
#include "smt/smt_engine_scope.h"
@@ -33,12 +32,16 @@ namespace CVC4 {
namespace theory {
namespace quantifiers {
-CandidateRewriteDatabase::CandidateRewriteDatabase()
+CandidateRewriteDatabase::CandidateRewriteDatabase(bool doCheck,
+ bool rewAccel,
+ bool silent)
: d_qe(nullptr),
d_tds(nullptr),
d_ext_rewrite(nullptr),
- d_using_sygus(false),
- d_silent(false)
+ d_doCheck(doCheck),
+ d_rewAccel(rewAccel),
+ d_silent(silent),
+ d_using_sygus(false)
{
}
void CandidateRewriteDatabase::initialize(const std::vector<Node>& vars,
@@ -69,13 +72,13 @@ void CandidateRewriteDatabase::initializeSygus(const std::vector<Node>& vars,
ExprMiner::initialize(vars, ss);
}
-bool CandidateRewriteDatabase::addTerm(Node sol,
+Node CandidateRewriteDatabase::addTerm(Node sol,
bool rec,
std::ostream& out,
bool& rew_print)
{
// have we added this term before?
- std::unordered_map<Node, bool, NodeHashFunction>::iterator itac =
+ std::unordered_map<Node, Node, NodeHashFunction>::iterator itac =
d_add_term_cache.find(sol);
if (itac != d_add_term_cache.end())
{
@@ -127,7 +130,7 @@ bool CandidateRewriteDatabase::addTerm(Node sol,
bool verified = false;
Trace("rr-check") << "Check candidate rewrite..." << std::endl;
// verify it if applicable
- if (options::sygusRewSynthCheck())
+ if (d_doCheck)
{
Node crr = solbr.eqNode(eq_solr).negate();
Trace("rr-check") << "Check candidate rewrite : " << crr << std::endl;
@@ -169,7 +172,7 @@ bool CandidateRewriteDatabase::addTerm(Node sol,
if (val.isNull())
{
Assert(!refv.isNull() && refv.getKind() != BOUND_VARIABLE);
- val = Node::fromExpr(rrChecker->getValue(refv.toExpr()));
+ val = rrChecker->getValue(refv);
}
Trace("rr-check") << " " << v << " -> " << val << std::endl;
pt.push_back(val);
@@ -177,8 +180,8 @@ bool CandidateRewriteDatabase::addTerm(Node sol,
d_sampler->addSamplePoint(pt);
// add the solution again
// by construction of the above point, we should be unique now
- Node eq_sol_new = d_sampler->registerTerm(sol);
- Assert(eq_sol_new == sol);
+ eq_sol = d_sampler->registerTerm(sol);
+ Assert(eq_sol == sol);
}
else
{
@@ -188,7 +191,11 @@ bool CandidateRewriteDatabase::addTerm(Node sol,
else
{
// just insist that constants are not relevant pairs
- is_unique_term = solb.isConst() && eq_solb.isConst();
+ if (solb.isConst() && eq_solb.isConst())
+ {
+ is_unique_term = true;
+ eq_sol = sol;
+ }
}
if (!is_unique_term)
{
@@ -222,7 +229,7 @@ bool CandidateRewriteDatabase::addTerm(Node sol,
Trace("sygus-rr-debug")
<< "; candidate #2 ext-rewrites to: " << eq_solr << std::endl;
}
- if (options::sygusRewSynthAccel() && d_using_sygus)
+ if (d_rewAccel && d_using_sygus)
{
Assert(d_tds != nullptr);
// Add a symmetry breaking clause that excludes the larger
@@ -258,18 +265,19 @@ bool CandidateRewriteDatabase::addTerm(Node sol,
// it discards it as a redundant candidate rewrite rule before
// checking its correctness.
}
- d_add_term_cache[sol] = is_unique_term;
- return is_unique_term;
+ d_add_term_cache[sol] = eq_sol;
+ return eq_sol;
}
-bool CandidateRewriteDatabase::addTerm(Node sol, bool rec, std::ostream& out)
+Node CandidateRewriteDatabase::addTerm(Node sol, bool rec, std::ostream& out)
{
bool rew_print = false;
return addTerm(sol, rec, out, rew_print);
}
bool CandidateRewriteDatabase::addTerm(Node sol, std::ostream& out)
{
- return addTerm(sol, false, out);
+ Node rsol = addTerm(sol, false, out);
+ return sol == rsol;
}
void CandidateRewriteDatabase::setSilent(bool flag) { d_silent = flag; }
diff --git a/src/theory/quantifiers/candidate_rewrite_database.h b/src/theory/quantifiers/candidate_rewrite_database.h
index 9173a654b..41ec0677b 100644
--- a/src/theory/quantifiers/candidate_rewrite_database.h
+++ b/src/theory/quantifiers/candidate_rewrite_database.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -44,7 +44,17 @@ namespace quantifiers {
class CandidateRewriteDatabase : public ExprMiner
{
public:
- CandidateRewriteDatabase();
+ /**
+ * Constructor
+ * @param doCheck Whether to check rewrite rules using subsolvers.
+ * @param rewAccel Whether to construct symmetry breaking lemmas based on
+ * discovered rewrites (see option sygusRewSynthAccel()).
+ * @param silent Whether to silence the output of rewrites discovered by this
+ * class.
+ */
+ CandidateRewriteDatabase(bool doCheck,
+ bool rewAccel = false,
+ bool silent = false);
~CandidateRewriteDatabase() {}
/** Initialize this class */
void initialize(const std::vector<Node>& var,
@@ -69,15 +79,22 @@ class CandidateRewriteDatabase : public ExprMiner
*
* Notifies this class that the solution sol was enumerated. This may
* cause a candidate-rewrite to be printed on the output stream out.
- * We return true if the term sol is distinct (up to equivalence) with
- * all previous terms added to this class. The argument rew_print is set to
- * true if this class printed a rewrite involving sol.
*
- * If the flag rec is true, then we also recursively add all subterms of sol
+ * @param sol The term to add to this class.
+ * @param rec If true, then we also recursively add all subterms of sol
* to this class as well.
+ * @param out The stream to output rewrite rules on.
+ * @param rew_print Set to true if this class printed a rewrite involving sol.
+ * @return A previous term eq_sol added to this class, such that sol is
+ * equivalent to eq_sol based on the criteria used by this class.
+ */
+ Node addTerm(Node sol, bool rec, std::ostream& out, bool& rew_print);
+ Node addTerm(Node sol, bool rec, std::ostream& out);
+ /**
+ * Same as above, returns true if the return value of addTerm was equal to
+ * sol, in other words, sol was a new unique term. This assumes false for
+ * the argument rec.
*/
- bool addTerm(Node sol, bool rec, std::ostream& out, bool& rew_print);
- bool addTerm(Node sol, bool rec, std::ostream& out);
bool addTerm(Node sol, std::ostream& out) override;
/** sets whether this class should output candidate rewrites it finds */
void setSilent(bool flag);
@@ -93,14 +110,21 @@ class CandidateRewriteDatabase : public ExprMiner
ExtendedRewriter* d_ext_rewrite;
/** the function-to-synthesize we are testing (if sygus) */
Node d_candidate;
+ /** whether we are checking equivalence using subsolver */
+ bool d_doCheck;
+ /**
+ * If true, we use acceleration for symmetry breaking rewrites (see option
+ * sygusRewSynthAccel()).
+ */
+ bool d_rewAccel;
+ /** if true, we silence the output of candidate rewrites */
+ bool d_silent;
/** whether we are using sygus */
bool d_using_sygus;
/** candidate rewrite filter */
CandidateRewriteFilter d_crewrite_filter;
/** the cache for results of addTerm */
- std::unordered_map<Node, bool, NodeHashFunction> d_add_term_cache;
- /** if true, we silence the output of candidate rewrites */
- bool d_silent;
+ std::unordered_map<Node, Node, NodeHashFunction> d_add_term_cache;
};
} /* CVC4::theory::quantifiers namespace */
diff --git a/src/theory/quantifiers/candidate_rewrite_filter.cpp b/src/theory/quantifiers/candidate_rewrite_filter.cpp
index 45b627ba4..7f1f1f444 100644
--- a/src/theory/quantifiers/candidate_rewrite_filter.cpp
+++ b/src/theory/quantifiers/candidate_rewrite_filter.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/candidate_rewrite_filter.h b/src/theory/quantifiers/candidate_rewrite_filter.h
index e65de51a1..70a43e769 100644
--- a/src/theory/quantifiers/candidate_rewrite_filter.h
+++ b/src/theory/quantifiers/candidate_rewrite_filter.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/cegqi/ceg_arith_instantiator.cpp b/src/theory/quantifiers/cegqi/ceg_arith_instantiator.cpp
index d6ee23bd1..d620da7b5 100644
--- a/src/theory/quantifiers/cegqi/ceg_arith_instantiator.cpp
+++ b/src/theory/quantifiers/cegqi/ceg_arith_instantiator.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/cegqi/ceg_arith_instantiator.h b/src/theory/quantifiers/cegqi/ceg_arith_instantiator.h
index c7a4f2606..cf47ab83a 100644
--- a/src/theory/quantifiers/cegqi/ceg_arith_instantiator.h
+++ b/src/theory/quantifiers/cegqi/ceg_arith_instantiator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/cegqi/ceg_bv_instantiator.cpp b/src/theory/quantifiers/cegqi/ceg_bv_instantiator.cpp
index cb3bcbf9c..eed315a00 100644
--- a/src/theory/quantifiers/cegqi/ceg_bv_instantiator.cpp
+++ b/src/theory/quantifiers/cegqi/ceg_bv_instantiator.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/cegqi/ceg_bv_instantiator.h b/src/theory/quantifiers/cegqi/ceg_bv_instantiator.h
index ea75f4d0b..32d375959 100644
--- a/src/theory/quantifiers/cegqi/ceg_bv_instantiator.h
+++ b/src/theory/quantifiers/cegqi/ceg_bv_instantiator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/cegqi/ceg_bv_instantiator_utils.cpp b/src/theory/quantifiers/cegqi/ceg_bv_instantiator_utils.cpp
index 3a449cbce..d440c12d7 100644
--- a/src/theory/quantifiers/cegqi/ceg_bv_instantiator_utils.cpp
+++ b/src/theory/quantifiers/cegqi/ceg_bv_instantiator_utils.cpp
@@ -5,7 +5,7 @@
** Mathias Preiner, Aina Niemetz, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/cegqi/ceg_bv_instantiator_utils.h b/src/theory/quantifiers/cegqi/ceg_bv_instantiator_utils.h
index 2dd1e662c..a942f7aba 100644
--- a/src/theory/quantifiers/cegqi/ceg_bv_instantiator_utils.h
+++ b/src/theory/quantifiers/cegqi/ceg_bv_instantiator_utils.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Aina Niemetz, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/cegqi/ceg_dt_instantiator.cpp b/src/theory/quantifiers/cegqi/ceg_dt_instantiator.cpp
index 202d3f9a1..16f0f3957 100644
--- a/src/theory/quantifiers/cegqi/ceg_dt_instantiator.cpp
+++ b/src/theory/quantifiers/cegqi/ceg_dt_instantiator.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/cegqi/ceg_dt_instantiator.h b/src/theory/quantifiers/cegqi/ceg_dt_instantiator.h
index 2fcea291f..22f698cd7 100644
--- a/src/theory/quantifiers/cegqi/ceg_dt_instantiator.h
+++ b/src/theory/quantifiers/cegqi/ceg_dt_instantiator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/cegqi/ceg_epr_instantiator.cpp b/src/theory/quantifiers/cegqi/ceg_epr_instantiator.cpp
index 9fcb11c4e..3a7e03c12 100644
--- a/src/theory/quantifiers/cegqi/ceg_epr_instantiator.cpp
+++ b/src/theory/quantifiers/cegqi/ceg_epr_instantiator.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/cegqi/ceg_epr_instantiator.h b/src/theory/quantifiers/cegqi/ceg_epr_instantiator.h
index 51463b7c4..7b46d8a45 100644
--- a/src/theory/quantifiers/cegqi/ceg_epr_instantiator.h
+++ b/src/theory/quantifiers/cegqi/ceg_epr_instantiator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/cegqi/ceg_instantiator.cpp b/src/theory/quantifiers/cegqi/ceg_instantiator.cpp
index 7f0e93997..59666f6fd 100644
--- a/src/theory/quantifiers/cegqi/ceg_instantiator.cpp
+++ b/src/theory/quantifiers/cegqi/ceg_instantiator.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Piotr Trojanek, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -630,20 +630,6 @@ bool CegInstantiator::constructInstantiation(SolvedForm& sf, unsigned i)
&& (vinst->useModelValue(this, sf, pv, d_effort) || is_sv)
&& vinst->allowModelValue(this, sf, pv, d_effort))
{
-#ifdef CVC4_ASSERTIONS
- // the instantiation strategy for quantified linear integer/real
- // arithmetic with arbitrary quantifier nesting is "monotonic" as a
- // consequence of Lemmas 5, 9 and Theorem 4 of Reynolds et al, "Solving
- // Quantified Linear Arithmetic by Counterexample Guided Instantiation",
- // FMSD 2017. We throw an assertion failure if we detect a case where the
- // strategy was not monotonic.
- if (options::cegqiNestedQE() && d_qe->getLogicInfo().isPure(THEORY_ARITH)
- && d_qe->getLogicInfo().isLinear())
- {
- Trace("cegqi-warn") << "Had to resort to model value." << std::endl;
- Assert(false);
- }
-#endif
Node mv = getModelValue( pv );
TermProperties pv_prop_m;
Trace("cegqi-inst-debug") << "[4] " << i << "...try model value " << mv << std::endl;
@@ -1394,7 +1380,7 @@ void CegInstantiator::presolve( Node q ) {
lem = NodeManager::currentNM()->mkNode( OR, g, lem );
Trace("cegqi-presolve-debug") << "Presolve lemma : " << lem << std::endl;
Assert(!expr::hasFreeVar(lem));
- d_qe->getOutputChannel().lemma( lem, false, true );
+ d_qe->getOutputChannel().lemma(lem, LemmaProperty::PREPROCESS);
}
}
}
diff --git a/src/theory/quantifiers/cegqi/ceg_instantiator.h b/src/theory/quantifiers/cegqi/ceg_instantiator.h
index 28266bbfa..49268c180 100644
--- a/src/theory/quantifiers/cegqi/ceg_instantiator.h
+++ b/src/theory/quantifiers/cegqi/ceg_instantiator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/cegqi/inst_strategy_cegqi.cpp b/src/theory/quantifiers/cegqi/inst_strategy_cegqi.cpp
index c156cbdf8..1a67a2b16 100644
--- a/src/theory/quantifiers/cegqi/inst_strategy_cegqi.cpp
+++ b/src/theory/quantifiers/cegqi/inst_strategy_cegqi.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -42,10 +42,10 @@ InstRewriterCegqi::InstRewriterCegqi(InstStrategyCegqi* p)
{
}
-Node InstRewriterCegqi::rewriteInstantiation(Node q,
- std::vector<Node>& terms,
- Node inst,
- bool doVts)
+TrustNode InstRewriterCegqi::rewriteInstantiation(Node q,
+ std::vector<Node>& terms,
+ Node inst,
+ bool doVts)
{
return d_parent->rewriteInstantiation(q, terms, inst, doVts);
}
@@ -56,20 +56,20 @@ InstStrategyCegqi::InstStrategyCegqi(QuantifiersEngine* qe)
d_cbqi_set_quant_inactive(false),
d_incomplete_check(false),
d_added_cbqi_lemma(qe->getUserContext()),
- d_elim_quants(qe->getSatContext()),
d_vtsCache(new VtsTermCache(qe)),
- d_bv_invert(nullptr),
- d_nested_qe_waitlist_size(qe->getUserContext()),
- d_nested_qe_waitlist_proc(qe->getUserContext())
+ d_bv_invert(nullptr)
{
- d_qid_count = 0;
d_small_const =
NodeManager::currentNM()->mkConst(Rational(1) / Rational(1000000));
d_check_vts_lemma_lc = false;
if (options::cegqiBv())
{
// if doing instantiation for BV, need the inverter class
- d_bv_invert.reset(new quantifiers::BvInverter);
+ d_bv_invert.reset(new BvInverter);
+ }
+ if (options::cegqiNestedQE())
+ {
+ d_nestedQe.reset(new NestedQe(qe->getUserContext()));
}
}
@@ -82,9 +82,12 @@ bool InstStrategyCegqi::needsCheck(Theory::Effort e)
QuantifiersModule::QEffort InstStrategyCegqi::needsModel(Theory::Effort e)
{
- for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
+ size_t nquant = d_quantEngine->getModel()->getNumAssertedQuantifiers();
+ for (size_t i = 0; i < nquant; i++)
+ {
Node q = d_quantEngine->getModel()->getAssertedQuantifier( i );
- if( doCbqi( q ) && d_quantEngine->getModel()->isQuantifierActive( q ) ){
+ if (doCbqi(q))
+ {
return QEFFORT_STANDARD;
}
}
@@ -174,16 +177,6 @@ bool InstStrategyCegqi::registerCbqiLemma(Node q)
if( doCbqi( quants[i] ) ){
registerCbqiLemma( quants[i] );
}
- if( options::cegqiNestedQE() ){
- //record these as counterexample quantifiers
- QAttributes qa;
- QuantAttributes::computeQuantAttributes( quants[i], qa );
- if( !qa.d_qid_num.isNull() ){
- d_id_to_ce_quant[ qa.d_qid_num ] = quants[i];
- d_ce_quant_to_id[ quants[i] ] = qa.d_qid_num;
- Trace("cegqi-nqe") << "CE quant id = " << qa.d_qid_num << " is " << quants[i] << std::endl;
- }
- }
}
}
// The decision strategy for this quantified formula ensures that its
@@ -205,7 +198,7 @@ bool InstStrategyCegqi::registerCbqiLemma(Node q)
dlds = itds->second.get();
}
// it is appended to the list of strategies
- d_quantEngine->getTheoryEngine()->getDecisionManager()->registerStrategy(
+ d_quantEngine->getDecisionManager()->registerStrategy(
DecisionManager::STRAT_QUANT_CEGQI_FEASIBLE, dlds);
return true;
}else{
@@ -223,7 +216,6 @@ void InstStrategyCegqi::reset_round(Theory::Effort effort)
Node q = d_quantEngine->getModel()->getAssertedQuantifier( i );
//it is not active if it corresponds to a rewrite rule: we will process in rewrite engine
if( doCbqi( q ) ){
- Assert(hasAddedCbqiLemma(q));
if( d_quantEngine->getModel()->isQuantifierActive( q ) ){
d_active_quant[q] = true;
Debug("cegqi-debug") << "Check quantified formula " << q << "..." << std::endl;
@@ -239,20 +231,6 @@ void InstStrategyCegqi::reset_round(Theory::Effort effort)
d_quantEngine->getModel()->setQuantifierActive( q, false );
d_cbqi_set_quant_inactive = true;
d_active_quant.erase( q );
- d_elim_quants.insert( q );
- Trace("cegqi-nqe") << "Inactive, waitlist proc/size = " << d_nested_qe_waitlist_proc[q].get() << "/" << d_nested_qe_waitlist_size[q].get() << std::endl;
- //process from waitlist
- while( d_nested_qe_waitlist_proc[q]<d_nested_qe_waitlist_size[q] ){
- int index = d_nested_qe_waitlist_proc[q];
- Assert(index >= 0);
- Assert(index < (int)d_nested_qe_waitlist[q].size());
- Node nq = d_nested_qe_waitlist[q][index];
- Node nqeqn = doNestedQENode( d_nested_qe_info[nq].d_q, q, nq, d_nested_qe_info[nq].d_inst_terms, d_nested_qe_info[nq].d_doVts );
- Node dqelem = nq.eqNode( nqeqn );
- Trace("cegqi-lemma") << "Delayed nested quantifier elimination lemma : " << dqelem << std::endl;
- d_quantEngine->getOutputChannel().lemma( dqelem );
- d_nested_qe_waitlist_proc[q] = index + 1;
- }
}
}
}else{
@@ -309,14 +287,10 @@ void InstStrategyCegqi::check(Theory::Effort e, QEffort quant_e)
for( std::map< Node, bool >::iterator it = d_active_quant.begin(); it != d_active_quant.end(); ++it ){
Node q = it->first;
Trace("cegqi") << "CBQI : Process quantifier " << q[0] << " at effort " << ee << std::endl;
- if( d_nested_qe.find( q )==d_nested_qe.end() ){
- process( q, e, ee );
- if( d_quantEngine->inConflict() ){
- break;
- }
- }else{
- Trace("cegqi-warn") << "CBQI : Cannot process already eliminated quantified formula " << q << std::endl;
- Assert(false);
+ process(q, e, ee);
+ if (d_quantEngine->inConflict())
+ {
+ break;
}
}
if( d_quantEngine->inConflict() || d_quantEngine->getNumLemmasWaiting()>lastWaiting ){
@@ -352,55 +326,6 @@ bool InstStrategyCegqi::checkCompleteFor(Node q)
}
}
-Node InstStrategyCegqi::getIdMarkedQuantNode(Node n,
- std::map<Node, Node>& visited)
-{
- std::map< Node, Node >::iterator it = visited.find( n );
- if( it==visited.end() ){
- Node ret = n;
- if( n.getKind()==FORALL ){
- QAttributes qa;
- QuantAttributes::computeQuantAttributes( n, qa );
- if( qa.d_qid_num.isNull() ){
- std::vector< Node > rc;
- rc.push_back( n[0] );
- rc.push_back( getIdMarkedQuantNode( n[1], visited ) );
- Node avar = NodeManager::currentNM()->mkSkolem( "id", NodeManager::currentNM()->booleanType() );
- QuantIdNumAttribute ida;
- avar.setAttribute(ida,d_qid_count);
- d_qid_count++;
- std::vector< Node > iplc;
- iplc.push_back( NodeManager::currentNM()->mkNode( INST_ATTRIBUTE, avar ) );
- if( n.getNumChildren()==3 ){
- for( unsigned i=0; i<n[2].getNumChildren(); i++ ){
- iplc.push_back( n[2][i] );
- }
- }
- rc.push_back( NodeManager::currentNM()->mkNode( INST_PATTERN_LIST, iplc ) );
- ret = NodeManager::currentNM()->mkNode( FORALL, rc );
- }
- }else if( n.getNumChildren()>0 ){
- std::vector< Node > children;
- if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
- children.push_back( n.getOperator() );
- }
- bool childChanged = false;
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- Node nc = getIdMarkedQuantNode( n[i], visited );
- childChanged = childChanged || nc!=n[i];
- children.push_back( nc );
- }
- if( childChanged ){
- ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
- }
- }
- visited[n] = ret;
- return ret;
- }else{
- return it->second;
- }
-}
-
void InstStrategyCegqi::checkOwnership(Node q)
{
if( d_quantEngine->getOwner( q )==NULL && doCbqi( q ) ){
@@ -414,34 +339,13 @@ void InstStrategyCegqi::checkOwnership(Node q)
void InstStrategyCegqi::preRegisterQuantifier(Node q)
{
- // mark all nested quantifiers with id
- if (options::cegqiNestedQE())
+ if (doCbqi(q))
{
- if( d_quantEngine->getOwner(q)==this )
+ if (processNestedQe(q, true))
{
- std::map<Node, Node> visited;
- Node mq = getIdMarkedQuantNode(q[1], visited);
- if (mq != q[1])
- {
- // do not do cbqi, we are reducing this quantified formula to a marked
- // one
- d_do_cbqi[q] = CEG_UNHANDLED;
- // instead do reduction
- std::vector<Node> qqc;
- qqc.push_back(q[0]);
- qqc.push_back(mq);
- if (q.getNumChildren() == 3)
- {
- qqc.push_back(q[2]);
- }
- Node qq = NodeManager::currentNM()->mkNode(FORALL, qqc);
- Node mlem = NodeManager::currentNM()->mkNode(IMPLIES, q, qq);
- Trace("cegqi-lemma") << "Mark quant id lemma : " << mlem << std::endl;
- d_quantEngine->addLemma(mlem);
- }
+ // will process using nested quantifier elimination
+ return;
}
- }
- if( doCbqi( q ) ){
// get the instantiator
if (options::cegqiPreRegInst())
{
@@ -453,11 +357,12 @@ void InstStrategyCegqi::preRegisterQuantifier(Node q)
}
}
}
-Node InstStrategyCegqi::rewriteInstantiation(Node q,
- std::vector<Node>& terms,
- Node inst,
- bool doVts)
+TrustNode InstStrategyCegqi::rewriteInstantiation(Node q,
+ std::vector<Node>& terms,
+ Node inst,
+ bool doVts)
{
+ Node prevInst = inst;
if (doVts)
{
// do virtual term substitution
@@ -466,11 +371,12 @@ Node InstStrategyCegqi::rewriteInstantiation(Node q,
inst = d_vtsCache->rewriteVtsSymbols(inst);
Trace("quant-vts-debug") << "...got " << inst << std::endl;
}
- if (options::cegqiNestedQE())
+ if (prevInst != inst)
{
- inst = doNestedQE(q, terms, inst, doVts);
+ // not proof producing yet
+ return TrustNode::mkTrustRewrite(prevInst, inst, nullptr);
}
- return inst;
+ return TrustNode::null();
}
InstantiationRewriter* InstStrategyCegqi::getInstRewriter() const
@@ -478,110 +384,6 @@ InstantiationRewriter* InstStrategyCegqi::getInstRewriter() const
return d_irew.get();
}
-Node InstStrategyCegqi::doNestedQENode(
- Node q, Node ceq, Node n, std::vector<Node>& inst_terms, bool doVts)
-{
- // there is a nested quantified formula (forall y. nq[y,x]) such that
- // q is (forall y. nq[y,t]) for ground terms t,
- // ceq is (forall y. nq[y,e]) for CE variables e.
- // we call this function when we know (forall y. nq[y,e]) is equivalent to quantifier-free formula C[e].
- // in this case, q is equivalent to the quantifier-free formula C[t].
- if( d_nested_qe.find( ceq )==d_nested_qe.end() ){
- d_nested_qe[ceq] = d_quantEngine->getInstantiatedConjunction( ceq );
- Trace("cegqi-nqe") << "CE quantifier elimination : " << std::endl;
- Trace("cegqi-nqe") << " " << ceq << std::endl;
- Trace("cegqi-nqe") << " " << d_nested_qe[ceq] << std::endl;
- //should not contain quantifiers
- Assert(!expr::hasClosure(d_nested_qe[ceq]));
- }
- Assert(d_quantEngine->getTermUtil()->d_inst_constants[q].size()
- == inst_terms.size());
- //replace inst constants with instantiation
- Node ret = d_nested_qe[ceq].substitute( d_quantEngine->getTermUtil()->d_inst_constants[q].begin(),
- d_quantEngine->getTermUtil()->d_inst_constants[q].end(),
- inst_terms.begin(), inst_terms.end() );
- if( doVts ){
- //do virtual term substitution
- ret = Rewriter::rewrite( ret );
- ret = d_vtsCache->rewriteVtsSymbols(ret);
- }
- Trace("cegqi-nqe") << "Nested quantifier elimination: " << std::endl;
- Trace("cegqi-nqe") << " " << n << std::endl;
- Trace("cegqi-nqe") << " " << ret << std::endl;
- return ret;
-}
-
-Node InstStrategyCegqi::doNestedQERec(Node q,
- Node n,
- std::map<Node, Node>& visited,
- std::vector<Node>& inst_terms,
- bool doVts)
-{
- if( visited.find( n )==visited.end() ){
- Node ret = n;
- if( n.getKind()==FORALL ){
- QAttributes qa;
- QuantAttributes::computeQuantAttributes( n, qa );
- if( !qa.d_qid_num.isNull() ){
- //if it has an id, check whether we have done quantifier elimination for this id
- std::map< Node, Node >::iterator it = d_id_to_ce_quant.find( qa.d_qid_num );
- if( it!=d_id_to_ce_quant.end() ){
- Node ceq = it->second;
- bool doNestedQe = d_elim_quants.contains( ceq );
- if( doNestedQe ){
- ret = doNestedQENode( q, ceq, n, inst_terms, doVts );
- }else{
- Trace("cegqi-nqe") << "Add to nested qe waitlist : " << std::endl;
- Node nr = Rewriter::rewrite( n );
- Trace("cegqi-nqe") << " " << ceq << std::endl;
- Trace("cegqi-nqe") << " " << nr << std::endl;
- int wlsize = d_nested_qe_waitlist_size[ceq] + 1;
- d_nested_qe_waitlist_size[ceq] = wlsize;
- if( wlsize<(int)d_nested_qe_waitlist[ceq].size() ){
- d_nested_qe_waitlist[ceq][wlsize] = nr;
- }else{
- d_nested_qe_waitlist[ceq].push_back( nr );
- }
- d_nested_qe_info[nr].d_q = q;
- d_nested_qe_info[nr].d_inst_terms.clear();
- d_nested_qe_info[nr].d_inst_terms.insert( d_nested_qe_info[nr].d_inst_terms.end(), inst_terms.begin(), inst_terms.end() );
- d_nested_qe_info[nr].d_doVts = doVts;
- //TODO: ensure this holds by restricting prenex when cbqiNestedQe is true.
- Assert(!options::cegqiInnermost());
- }
- }
- }
- }else if( n.getNumChildren()>0 ){
- std::vector< Node > children;
- if( n.getMetaKind() == kind::metakind::PARAMETERIZED ){
- children.push_back( n.getOperator() );
- }
- bool childChanged = false;
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- Node nc = doNestedQERec( q, n[i], visited, inst_terms, doVts );
- childChanged = childChanged || nc!=n[i];
- children.push_back( nc );
- }
- if( childChanged ){
- ret = NodeManager::currentNM()->mkNode( n.getKind(), children );
- }
- }
- visited[n] = ret;
- return ret;
- }else{
- return n;
- }
-}
-
-Node InstStrategyCegqi::doNestedQE(Node q,
- std::vector<Node>& inst_terms,
- Node lem,
- bool doVts)
-{
- std::map< Node, Node > visited;
- return doNestedQERec( q, lem, visited, inst_terms, doVts );
-}
-
void InstStrategyCegqi::registerCounterexampleLemma(Node q, Node lem)
{
// must register with the instantiator
@@ -594,7 +396,8 @@ void InstStrategyCegqi::registerCounterexampleLemma(Node q, Node lem)
ce_vars.push_back(tutil->getInstantiationConstant(q, i));
}
CegInstantiator* cinst = getInstantiator(q);
- LemmaStatus status = d_quantEngine->getOutputChannel().lemma(lem);
+ LemmaStatus status =
+ d_quantEngine->getOutputChannel().lemma(lem, LemmaProperty::PREPROCESS);
Node ppLem = status.getRewrittenLemma();
Trace("cegqi-debug") << "Counterexample lemma (post-preprocess): " << ppLem
<< std::endl;
@@ -621,6 +424,13 @@ bool InstStrategyCegqi::doCbqi(Node q)
}
void InstStrategyCegqi::process( Node q, Theory::Effort effort, int e ) {
+ // If we are doing nested quantifier elimination, check if q was already
+ // processed.
+ if (processNestedQe(q, false))
+ {
+ // don't need to process this, since it has been reduced
+ return;
+ }
if( e==0 ){
CegInstantiator * cinst = getInstantiator( q );
Trace("inst-alg") << "-> Run cegqi for " << q << std::endl;
@@ -733,6 +543,33 @@ void InstStrategyCegqi::presolve() {
}
}
+bool InstStrategyCegqi::processNestedQe(Node q, bool isPreregister)
+{
+ if (d_nestedQe != nullptr)
+ {
+ if (isPreregister)
+ {
+ // If at preregister, we are done if we have nested quantification.
+ // We will process nested quantification.
+ return NestedQe::hasNestedQuantification(q);
+ }
+ // if not a preregister, we process, which may trigger quantifier
+ // elimination in subsolvers.
+ std::vector<Node> lems;
+ if (d_nestedQe->process(q, lems))
+ {
+ // add lemmas to process
+ for (const Node& lem : lems)
+ {
+ d_quantEngine->addLemma(lem);
+ }
+ // don't need to process this, since it has been reduced
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace quantifiers
} // namespace theory
} // namespace CVC4
diff --git a/src/theory/quantifiers/cegqi/inst_strategy_cegqi.h b/src/theory/quantifiers/cegqi/inst_strategy_cegqi.h
index dac5a198c..2ca232699 100644
--- a/src/theory/quantifiers/cegqi/inst_strategy_cegqi.h
+++ b/src/theory/quantifiers/cegqi/inst_strategy_cegqi.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,6 +21,7 @@
#include "theory/decision_manager.h"
#include "theory/quantifiers/bv_inverter.h"
#include "theory/quantifiers/cegqi/ceg_instantiator.h"
+#include "theory/quantifiers/cegqi/nested_qe.h"
#include "theory/quantifiers/cegqi/vts_term_cache.h"
#include "theory/quantifiers/instantiate.h"
#include "theory/quantifiers/quant_util.h"
@@ -43,12 +44,13 @@ class InstRewriterCegqi : public InstantiationRewriter
~InstRewriterCegqi() {}
/**
* Rewrite the instantiation via d_parent, based on virtual term substitution
- * and nested quantifier elimination.
+ * and nested quantifier elimination. Returns a TrustNode of kind REWRITE,
+ * corresponding to the rewrite and its proof generator.
*/
- Node rewriteInstantiation(Node q,
- std::vector<Node>& terms,
- Node inst,
- bool doVts) override;
+ TrustNode rewriteInstantiation(Node q,
+ std::vector<Node>& terms,
+ Node inst,
+ bool doVts) override;
private:
/** pointer to the parent of this class */
@@ -106,11 +108,14 @@ class InstStrategyCegqi : public QuantifiersModule
* We rewrite inst based on virtual term substitution and nested quantifier
* elimination. For details, see "Solving Quantified Linear Arithmetic via
* Counterexample-Guided Instantiation" FMSD 2017, Reynolds et al.
+ *
+ * Returns a TrustNode of kind REWRITE, corresponding to the rewrite and its
+ * proof generator.
*/
- Node rewriteInstantiation(Node q,
- std::vector<Node>& terms,
- Node inst,
- bool doVts);
+ TrustNode rewriteInstantiation(Node q,
+ std::vector<Node>& terms,
+ Node inst,
+ bool doVts);
/** get the instantiation rewriter object */
InstantiationRewriter* getInstRewriter() const;
@@ -139,8 +144,6 @@ class InstStrategyCegqi : public QuantifiersModule
bool d_incomplete_check;
/** whether we have added cbqi lemma */
NodeSet d_added_cbqi_lemma;
- /** whether we have added cbqi lemma */
- NodeSet d_elim_quants;
/** parent guards */
std::map< Node, std::vector< Node > > d_parent_quant;
std::map< Node, std::vector< Node > > d_children_quant;
@@ -189,6 +192,14 @@ class InstStrategyCegqi : public QuantifiersModule
void registerCounterexampleLemma(Node q, Node lem);
/** has added cbqi lemma */
bool hasAddedCbqiLemma( Node q ) { return d_added_cbqi_lemma.find( q )!=d_added_cbqi_lemma.end(); }
+ /**
+ * Return true if q can be processed with nested quantifier elimination.
+ * This may add a lemma on the output channel of quantifiers engine if so.
+ *
+ * @param q The quantified formula to process
+ * @param isPreregister Whether this method is being called at preregister.
+ */
+ bool processNestedQe(Node q, bool isPreregister);
/** process functions */
void process(Node q, Theory::Effort effort, int e);
/**
@@ -200,44 +211,10 @@ class InstStrategyCegqi : public QuantifiersModule
Node getCounterexampleLiteral(Node q);
/** map from universal quantifiers to their counterexample literals */
std::map<Node, Node> d_ce_lit;
-
- //for identification
- uint64_t d_qid_count;
- //nested qe map
- std::map< Node, Node > d_nested_qe;
- //mark ids on quantifiers
- Node getIdMarkedQuantNode( Node n, std::map< Node, Node >& visited );
- // id to ce quant
- std::map< Node, Node > d_id_to_ce_quant;
- std::map< Node, Node > d_ce_quant_to_id;
- //do nested quantifier elimination recursive
- Node doNestedQENode( Node q, Node ceq, Node n, std::vector< Node >& inst_terms, bool doVts );
- Node doNestedQERec( Node q, Node n, std::map< Node, Node >& visited, std::vector< Node >& inst_terms, bool doVts );
- //elimination information (for delayed elimination)
- class NestedQEInfo {
- public:
- NestedQEInfo() : d_doVts(false){}
- ~NestedQEInfo(){}
- Node d_q;
- std::vector< Node > d_inst_terms;
- bool d_doVts;
- };
- std::map< Node, NestedQEInfo > d_nested_qe_info;
- NodeIntMap d_nested_qe_waitlist_size;
- NodeIntMap d_nested_qe_waitlist_proc;
- std::map< Node, std::vector< Node > > d_nested_qe_waitlist;
-
- /** Do nested quantifier elimination.
- *
- * This rewrites the quantified formulas in inst based on nested quantifier
- * elimination. In this method, inst is the instantiation of quantified
- * formula q for the vector terms. The flag doVts indicates whether we must
- * apply virtual term substitution (if terms contains virtual terms).
- */
- Node doNestedQE(Node q, std::vector<Node>& terms, Node inst, bool doVts);
+ /** The nested quantifier elimination utility */
+ std::unique_ptr<NestedQe> d_nestedQe;
};
-
}
}
}
diff --git a/src/theory/quantifiers/cegqi/nested_qe.cpp b/src/theory/quantifiers/cegqi/nested_qe.cpp
new file mode 100644
index 000000000..72e7ef66f
--- /dev/null
+++ b/src/theory/quantifiers/cegqi/nested_qe.cpp
@@ -0,0 +1,155 @@
+/********************* */
+/*! \file nested_qe.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Methods for counterexample-guided quantifier instantiation
+ ** based on nested quantifier elimination.
+ **/
+
+#include "theory/quantifiers/cegqi/nested_qe.h"
+
+#include "expr/node_algorithm.h"
+#include "expr/subs.h"
+#include "theory/smt_engine_subsolver.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+NestedQe::NestedQe(context::UserContext* u) : d_qnqe(u) {}
+
+bool NestedQe::process(Node q, std::vector<Node>& lems)
+{
+ NodeNodeMap::iterator it = d_qnqe.find(q);
+ if (it != d_qnqe.end())
+ {
+ // already processed
+ return (*it).second != q;
+ }
+ Trace("cegqi-nested-qe") << "Check nested QE on " << q << std::endl;
+ Node qqe = doNestedQe(q, true);
+ d_qnqe[q] = qqe;
+ if (qqe == q)
+ {
+ Trace("cegqi-nested-qe") << "...did not apply nested QE" << std::endl;
+ return false;
+ }
+ Trace("cegqi-nested-qe") << "...applied nested QE" << std::endl;
+ Trace("cegqi-nested-qe") << "Result is " << qqe << std::endl;
+
+ // add as lemma
+ lems.push_back(q.eqNode(qqe));
+ return true;
+}
+
+bool NestedQe::hasProcessed(Node q) const
+{
+ return d_qnqe.find(q) != d_qnqe.end();
+}
+
+bool NestedQe::getNestedQuantification(
+ Node q, std::unordered_set<Node, NodeHashFunction>& nqs)
+{
+ expr::getKindSubterms(q[1], kind::FORALL, true, nqs);
+ return !nqs.empty();
+}
+
+bool NestedQe::hasNestedQuantification(Node q)
+{
+ std::unordered_set<Node, NodeHashFunction> nqs;
+ return getNestedQuantification(q, nqs);
+}
+
+Node NestedQe::doNestedQe(Node q, bool keepTopLevel)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ Node qOrig = q;
+ bool inputExists = false;
+ if (q.getKind() == kind::EXISTS)
+ {
+ q = nm->mkNode(kind::FORALL, q[0], q[1].negate());
+ inputExists = true;
+ }
+ Assert(q.getKind() == kind::FORALL);
+ std::unordered_set<Node, NodeHashFunction> nqs;
+ if (!getNestedQuantification(q, nqs))
+ {
+ Trace("cegqi-nested-qe-debug")
+ << "...no nested quantification" << std::endl;
+ if (keepTopLevel)
+ {
+ return qOrig;
+ }
+ // just do ordinary quantifier elimination
+ Node qqe = doQe(q);
+ Trace("cegqi-nested-qe-debug") << "...did ordinary qe" << std::endl;
+ return qqe;
+ }
+ Trace("cegqi-nested-qe-debug")
+ << "..." << nqs.size() << " nested quantifiers" << std::endl;
+ // otherwise, skolemize the arguments of this and apply
+ std::vector<Node> vars(q[0].begin(), q[0].end());
+ Subs sk;
+ sk.add(vars);
+ // do nested quantifier elimination on each nested quantifier, skolemizing the
+ // free variables
+ Subs snqe;
+ for (const Node& nq : nqs)
+ {
+ Node nqk = sk.apply(nq);
+ Node nqqe = doNestedQe(nqk);
+ if (nqqe == nqk)
+ {
+ // failed
+ Trace("cegqi-nested-qe-debug")
+ << "...failed to apply to nested" << std::endl;
+ return q;
+ }
+ snqe.add(nqk, nqqe);
+ }
+ // get the result of nested quantifier elimination
+ Node qeBody = sk.apply(q[1]);
+ qeBody = snqe.apply(qeBody);
+ // undo the skolemization
+ qeBody = sk.rapply(qeBody, true);
+ // reconstruct the body
+ std::vector<Node> qargs;
+ qargs.push_back(q[0]);
+ qargs.push_back(inputExists ? qeBody.negate() : qeBody);
+ if (q.getNumChildren() == 3)
+ {
+ qargs.push_back(q[2]);
+ }
+ return nm->mkNode(inputExists ? kind::EXISTS : kind::FORALL, qargs);
+}
+
+Node NestedQe::doQe(Node q)
+{
+ Assert(q.getKind() == kind::FORALL);
+ Trace("cegqi-nested-qe") << " Apply qe to " << q << std::endl;
+ NodeManager* nm = NodeManager::currentNM();
+ q = nm->mkNode(kind::EXISTS, q[0], q[1].negate());
+ std::unique_ptr<SmtEngine> smt_qe;
+ initializeSubsolver(smt_qe);
+ Node qqe = smt_qe->getQuantifierElimination(q, true, false);
+ if (expr::hasBoundVar(qqe))
+ {
+ Trace("cegqi-nested-qe") << " ...failed QE" << std::endl;
+ //...failed to apply
+ return q;
+ }
+ Node res = qqe.negate();
+ Trace("cegqi-nested-qe") << " ...success, result = " << res << std::endl;
+ return res;
+}
+
+} // namespace quantifiers
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/quantifiers/cegqi/nested_qe.h b/src/theory/quantifiers/cegqi/nested_qe.h
new file mode 100644
index 000000000..ef690afd5
--- /dev/null
+++ b/src/theory/quantifiers/cegqi/nested_qe.h
@@ -0,0 +1,86 @@
+/********************* */
+/*! \file nested_qe.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Methods for counterexample-guided quantifier instantiation
+ ** based on nested quantifier elimination.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__QUANTIFIERS__CEQGI__NESTED_QE_H
+#define CVC4__THEORY__QUANTIFIERS__CEQGI__NESTED_QE_H
+
+#include <unordered_set>
+
+#include "context/cdhashmap.h"
+#include "expr/node.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+class NestedQe
+{
+ using NodeNodeMap = context::CDHashMap<Node, Node, NodeHashFunction>;
+
+ public:
+ NestedQe(context::UserContext* u);
+ ~NestedQe() {}
+ /**
+ * Process quantified formula. If this returns true, then q was processed
+ * via nested quantifier elimination (either during this call or previously
+ * in this user context). If q was processed in this call, the lemma:
+ * (= q qqe)
+ * is added to lem, where qqe is the result of nested quantifier elimination
+ * on q.
+ */
+ bool process(Node q, std::vector<Node>& lems);
+ /**
+ * Have we processed q using the above method?
+ */
+ bool hasProcessed(Node q) const;
+
+ /**
+ * Get nested quantification. Returns true if q has nested quantifiers.
+ * Adds each nested quantifier in the body of q to nqs.
+ */
+ static bool getNestedQuantification(
+ Node q, std::unordered_set<Node, NodeHashFunction>& nqs);
+ /**
+ * Does quantified formula q have nested quantification?
+ */
+ static bool hasNestedQuantification(Node q);
+ /**
+ * Do nested quantifier elimination. Returns a formula that is equivalent to
+ * q and has no nested quantification. If keepTopLevel is false, then the
+ * returned formula is quantifier-free. Otherwise, it is a quantified formula
+ * with no nested quantification.
+ */
+ static Node doNestedQe(Node q, bool keepTopLevel = false);
+ /**
+ * Run quantifier elimination on quantified formula q, where q has no nested
+ * quantification. This method invokes a subsolver for performing quantifier
+ * elimination.
+ */
+ static Node doQe(Node q);
+
+ private:
+ /**
+ * Mapping from quantified formulas q to the result of doNestedQe(q, true).
+ */
+ NodeNodeMap d_qnqe;
+};
+
+} // namespace quantifiers
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/quantifiers/cegqi/vts_term_cache.cpp b/src/theory/quantifiers/cegqi/vts_term_cache.cpp
index 858e471d4..ecc52e47c 100644
--- a/src/theory/quantifiers/cegqi/vts_term_cache.cpp
+++ b/src/theory/quantifiers/cegqi/vts_term_cache.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/cegqi/vts_term_cache.h b/src/theory/quantifiers/cegqi/vts_term_cache.h
index 8ed34e30b..b9b86dd8b 100644
--- a/src/theory/quantifiers/cegqi/vts_term_cache.h
+++ b/src/theory/quantifiers/cegqi/vts_term_cache.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/conjecture_generator.cpp b/src/theory/quantifiers/conjecture_generator.cpp
index 2926e09cb..e13902077 100644
--- a/src/theory/quantifiers/conjecture_generator.cpp
+++ b/src/theory/quantifiers/conjecture_generator.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -122,7 +122,8 @@ void ConjectureGenerator::eqNotifyNewClass( TNode t ){
d_upendingAdds.push_back( t );
}
-void ConjectureGenerator::eqNotifyPreMerge(TNode t1, TNode t2) {
+void ConjectureGenerator::eqNotifyMerge(TNode t1, TNode t2)
+{
//get maintained representatives
TNode rt1 = t1;
TNode rt2 = t2;
@@ -151,15 +152,6 @@ void ConjectureGenerator::eqNotifyPreMerge(TNode t1, TNode t2) {
}
}
-void ConjectureGenerator::eqNotifyPostMerge(TNode t1, TNode t2) {
-
-}
-
-void ConjectureGenerator::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
- Trace("thm-ee-debug") << "UEE : disequality holds : " << t1 << " != " << t2 << std::endl;
-
-}
-
ConjectureGenerator::EqcInfo::EqcInfo( context::Context* c ) : d_rep( c, Node::null() ){
diff --git a/src/theory/quantifiers/conjecture_generator.h b/src/theory/quantifiers/conjecture_generator.h
index d7c314a9a..0c8106ad5 100644
--- a/src/theory/quantifiers/conjecture_generator.h
+++ b/src/theory/quantifiers/conjecture_generator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -246,10 +246,6 @@ private:
ConjectureGenerator& d_sg;
public:
NotifyClass(ConjectureGenerator& sg): d_sg(sg) {}
- bool eqNotifyTriggerEquality(TNode equality, bool value) override
- {
- return true;
- }
bool eqNotifyTriggerPredicate(TNode predicate, bool value) override
{
return true;
@@ -263,17 +259,12 @@ private:
}
void eqNotifyConstantTermMerge(TNode t1, TNode t2) override {}
void eqNotifyNewClass(TNode t) override { d_sg.eqNotifyNewClass(t); }
- void eqNotifyPreMerge(TNode t1, TNode t2) override
- {
- d_sg.eqNotifyPreMerge(t1, t2);
- }
- void eqNotifyPostMerge(TNode t1, TNode t2) override
+ void eqNotifyMerge(TNode t1, TNode t2) override
{
- d_sg.eqNotifyPostMerge(t1, t2);
+ d_sg.eqNotifyMerge(t1, t2);
}
void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override
{
- d_sg.eqNotifyDisequal(t1, t2, reason);
}
};/* class ConjectureGenerator::NotifyClass */
/** The notify class */
@@ -299,12 +290,8 @@ private:
std::map< Node, EqcInfo* > d_eqc_info;
/** 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);
+ void eqNotifyMerge(TNode t1, TNode t2);
/** are universal equal */
bool areUniversalEqual( TNode n1, TNode n2 );
/** are universal disequal */
diff --git a/src/theory/quantifiers/dynamic_rewrite.cpp b/src/theory/quantifiers/dynamic_rewrite.cpp
index eedaec4e3..7bcec0cb4 100644
--- a/src/theory/quantifiers/dynamic_rewrite.cpp
+++ b/src/theory/quantifiers/dynamic_rewrite.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/dynamic_rewrite.h b/src/theory/quantifiers/dynamic_rewrite.h
index 6d2267adf..5c1d28ec0 100644
--- a/src/theory/quantifiers/dynamic_rewrite.h
+++ b/src/theory/quantifiers/dynamic_rewrite.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/ematching/candidate_generator.cpp b/src/theory/quantifiers/ematching/candidate_generator.cpp
index 49d700a6a..a2471c704 100644
--- a/src/theory/quantifiers/ematching/candidate_generator.cpp
+++ b/src/theory/quantifiers/ematching/candidate_generator.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Francois Bobot
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/ematching/candidate_generator.h b/src/theory/quantifiers/ematching/candidate_generator.h
index c8d2b7015..d7f61b17b 100644
--- a/src/theory/quantifiers/ematching/candidate_generator.h
+++ b/src/theory/quantifiers/ematching/candidate_generator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/ematching/ho_trigger.cpp b/src/theory/quantifiers/ematching/ho_trigger.cpp
index b68f9b1aa..4672c10c7 100644
--- a/src/theory/quantifiers/ematching/ho_trigger.cpp
+++ b/src/theory/quantifiers/ematching/ho_trigger.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/ematching/ho_trigger.h b/src/theory/quantifiers/ematching/ho_trigger.h
index 713e249a4..a369aa7c5 100644
--- a/src/theory/quantifiers/ematching/ho_trigger.h
+++ b/src/theory/quantifiers/ematching/ho_trigger.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/ematching/inst_match_generator.cpp b/src/theory/quantifiers/ematching/inst_match_generator.cpp
index 176f275f0..2099a2cb8 100644
--- a/src/theory/quantifiers/ematching/inst_match_generator.cpp
+++ b/src/theory/quantifiers/ematching/inst_match_generator.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,7 +14,6 @@
**/
#include "theory/quantifiers/ematching/inst_match_generator.h"
-#include "expr/datatype.h"
#include "options/datatypes_options.h"
#include "options/quantifiers_options.h"
#include "theory/datatypes/theory_datatypes_utils.h"
diff --git a/src/theory/quantifiers/ematching/inst_match_generator.h b/src/theory/quantifiers/ematching/inst_match_generator.h
index 94c768d5f..c3b021acd 100644
--- a/src/theory/quantifiers/ematching/inst_match_generator.h
+++ b/src/theory/quantifiers/ematching/inst_match_generator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/ematching/inst_strategy_e_matching.cpp b/src/theory/quantifiers/ematching/inst_strategy_e_matching.cpp
index dcec05f5a..513897cc9 100644
--- a/src/theory/quantifiers/ematching/inst_strategy_e_matching.cpp
+++ b/src/theory/quantifiers/ematching/inst_strategy_e_matching.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/ematching/inst_strategy_e_matching.h b/src/theory/quantifiers/ematching/inst_strategy_e_matching.h
index 8f560256f..45d3db275 100644
--- a/src/theory/quantifiers/ematching/inst_strategy_e_matching.h
+++ b/src/theory/quantifiers/ematching/inst_strategy_e_matching.h
@@ -5,7 +5,7 @@
** Morgan Deters, Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/ematching/instantiation_engine.cpp b/src/theory/quantifiers/ematching/instantiation_engine.cpp
index 5626c8aab..ad9c53e0f 100644
--- a/src/theory/quantifiers/ematching/instantiation_engine.cpp
+++ b/src/theory/quantifiers/ematching/instantiation_engine.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,19 +18,21 @@
#include "theory/quantifiers/ematching/inst_strategy_e_matching.h"
#include "theory/quantifiers/ematching/trigger.h"
#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
#include "theory/quantifiers/term_database.h"
#include "theory/quantifiers/term_util.h"
#include "theory/quantifiers_engine.h"
#include "theory/theory_engine.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;
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
InstantiationEngine::InstantiationEngine(QuantifiersEngine* qe)
: QuantifiersModule(qe),
d_instStrategies(),
@@ -123,42 +125,64 @@ void InstantiationEngine::reset_round( Theory::Effort e ){
void InstantiationEngine::check(Theory::Effort e, QEffort quant_e)
{
CodeTimer codeTimer(d_quantEngine->d_statistics.d_ematching_time);
- if (quant_e == QEFFORT_STANDARD)
+ if (quant_e != QEFFORT_STANDARD)
{
- double clSet = 0;
- if( Trace.isOn("inst-engine") ){
- clSet = double(clock())/double(CLOCKS_PER_SEC);
- Trace("inst-engine") << "---Instantiation Engine Round, effort = " << e << "---" << std::endl;
- }
- //collect all active quantified formulas belonging to this
- bool quantActive = false;
- d_quants.clear();
- for( unsigned i=0; i<d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
- Node q = d_quantEngine->getModel()->getAssertedQuantifier( i, true );
- if( d_quantEngine->hasOwnership( q, this ) && d_quantEngine->getModel()->isQuantifierActive( q ) ){
- quantActive = true;
- d_quants.push_back( q );
- }
+ return;
+ }
+ double clSet = 0;
+ if (Trace.isOn("inst-engine"))
+ {
+ clSet = double(clock()) / double(CLOCKS_PER_SEC);
+ Trace("inst-engine") << "---Instantiation Engine Round, effort = " << e
+ << "---" << std::endl;
+ }
+ // collect all active quantified formulas belonging to this
+ bool quantActive = false;
+ d_quants.clear();
+ FirstOrderModel* m = d_quantEngine->getModel();
+ size_t nquant = m->getNumAssertedQuantifiers();
+ for (size_t i = 0; i < nquant; i++)
+ {
+ Node q = d_quantEngine->getModel()->getAssertedQuantifier(i, true);
+ if (shouldProcess(q) && m->isQuantifierActive(q))
+ {
+ quantActive = true;
+ d_quants.push_back(q);
}
- Trace("inst-engine-debug") << "InstEngine: check: # asserted quantifiers " << d_quants.size() << "/";
- Trace("inst-engine-debug") << d_quantEngine->getModel()->getNumAssertedQuantifiers() << " " << quantActive << std::endl;
- if( quantActive ){
- unsigned lastWaiting = d_quantEngine->getNumLemmasWaiting();
- doInstantiationRound( e );
- if( d_quantEngine->inConflict() ){
- Assert(d_quantEngine->getNumLemmasWaiting() > lastWaiting);
- Trace("inst-engine") << "Conflict, added lemmas = " << (d_quantEngine->getNumLemmasWaiting()-lastWaiting) << std::endl;
- }else if( d_quantEngine->hasAddedLemma() ){
- Trace("inst-engine") << "Added lemmas = " << (d_quantEngine->getNumLemmasWaiting()-lastWaiting) << std::endl;
- }
- }else{
- d_quants.clear();
+ }
+ Trace("inst-engine-debug")
+ << "InstEngine: check: # asserted quantifiers " << d_quants.size() << "/";
+ Trace("inst-engine-debug") << nquant << " " << quantActive << std::endl;
+ if (quantActive)
+ {
+ unsigned lastWaiting = d_quantEngine->getNumLemmasWaiting();
+ doInstantiationRound(e);
+ if (d_quantEngine->inConflict())
+ {
+ Assert(d_quantEngine->getNumLemmasWaiting() > lastWaiting);
+ Trace("inst-engine") << "Conflict, added lemmas = "
+ << (d_quantEngine->getNumLemmasWaiting()
+ - lastWaiting)
+ << std::endl;
}
- if( Trace.isOn("inst-engine") ){
- double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
- Trace("inst-engine") << "Finished instantiation engine, time = " << (clSet2-clSet) << std::endl;
+ else if (d_quantEngine->hasAddedLemma())
+ {
+ Trace("inst-engine") << "Added lemmas = "
+ << (d_quantEngine->getNumLemmasWaiting()
+ - lastWaiting)
+ << std::endl;
}
}
+ else
+ {
+ d_quants.clear();
+ }
+ if (Trace.isOn("inst-engine"))
+ {
+ double clSet2 = double(clock()) / double(CLOCKS_PER_SEC);
+ Trace("inst-engine") << "Finished instantiation engine, time = "
+ << (clSet2 - clSet) << std::endl;
+ }
}
bool InstantiationEngine::checkCompleteFor( Node q ) {
@@ -185,7 +209,7 @@ void InstantiationEngine::checkOwnership(Node q)
void InstantiationEngine::registerQuantifier(Node q)
{
- if (!d_quantEngine->hasOwnership(q, this))
+ if (!shouldProcess(q))
{
return;
}
@@ -225,3 +249,22 @@ void InstantiationEngine::addUserNoPattern(Node q, Node pat) {
d_i_ag->addUserNoPattern(q, pat);
}
}
+
+bool InstantiationEngine::shouldProcess(Node q)
+{
+ if (!d_quantEngine->hasOwnership(q, this))
+ {
+ return false;
+ }
+ // also ignore internal quantifiers
+ QuantAttributes* qattr = d_quantEngine->getQuantAttributes();
+ if (qattr->isInternal(q))
+ {
+ return false;
+ }
+ return true;
+}
+
+} // namespace quantifiers
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/quantifiers/ematching/instantiation_engine.h b/src/theory/quantifiers/ematching/instantiation_engine.h
index d783374be..f2f013f1c 100644
--- a/src/theory/quantifiers/ematching/instantiation_engine.h
+++ b/src/theory/quantifiers/ematching/instantiation_engine.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -88,6 +88,8 @@ class InstantiationEngine : public QuantifiersModule {
std::string identify() const override { return "InstEngine"; }
private:
+ /** Return true if this module should process quantified formula q */
+ bool shouldProcess(Node q);
/** for computing relevance of quantifiers */
std::unique_ptr<QuantRelevance> d_quant_rel;
}; /* class InstantiationEngine */
diff --git a/src/theory/quantifiers/ematching/trigger.cpp b/src/theory/quantifiers/ematching/trigger.cpp
index f177ebf40..95ab0674f 100644
--- a/src/theory/quantifiers/ematching/trigger.cpp
+++ b/src/theory/quantifiers/ematching/trigger.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -408,7 +408,7 @@ bool Trigger::isAtomicTriggerKind( Kind k ) {
|| k == APPLY_SELECTOR_TOTAL || k == APPLY_TESTER || k == UNION
|| k == INTERSECTION || k == SUBSET || k == SETMINUS || k == MEMBER
|| k == SINGLETON || k == SEP_PTO || k == BITVECTOR_TO_NAT
- || k == INT_TO_BITVECTOR || k == HO_APPLY;
+ || k == INT_TO_BITVECTOR || k == HO_APPLY || k == SEQ_NTH;
}
bool Trigger::isRelationalTrigger( Node n ) {
diff --git a/src/theory/quantifiers/ematching/trigger.h b/src/theory/quantifiers/ematching/trigger.h
index fc2ad9416..7b0b51fb6 100644
--- a/src/theory/quantifiers/ematching/trigger.h
+++ b/src/theory/quantifiers/ematching/trigger.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/equality_infer.cpp b/src/theory/quantifiers/equality_infer.cpp
index 7a4d444f7..63fecdd9e 100644
--- a/src/theory/quantifiers/equality_infer.cpp
+++ b/src/theory/quantifiers/equality_infer.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/equality_infer.h b/src/theory/quantifiers/equality_infer.h
index dfc0ef285..fed458ade 100644
--- a/src/theory/quantifiers/equality_infer.h
+++ b/src/theory/quantifiers/equality_infer.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/equality_query.cpp b/src/theory/quantifiers/equality_query.cpp
index 94e60513c..0b4539d7a 100644
--- a/src/theory/quantifiers/equality_query.cpp
+++ b/src/theory/quantifiers/equality_query.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -182,7 +182,7 @@ Node EqualityQueryQuantifiersEngine::getInternalRepresentative(Node a,
}
eq::EqualityEngine* EqualityQueryQuantifiersEngine::getEngine(){
- return d_qe->getActiveEqualityEngine();
+ return d_qe->getMasterEqualityEngine();
}
void EqualityQueryQuantifiersEngine::getEquivalenceClass( Node a, std::vector< Node >& eqc ){
diff --git a/src/theory/quantifiers/equality_query.h b/src/theory/quantifiers/equality_query.h
index b06e42143..b11dbe033 100644
--- a/src/theory/quantifiers/equality_query.h
+++ b/src/theory/quantifiers/equality_query.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/expr_miner.cpp b/src/theory/quantifiers/expr_miner.cpp
index 72e47fac8..759d3e69f 100644
--- a/src/theory/quantifiers/expr_miner.cpp
+++ b/src/theory/quantifiers/expr_miner.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/expr_miner.h b/src/theory/quantifiers/expr_miner.h
index e603075c4..aa0e62891 100644
--- a/src/theory/quantifiers/expr_miner.h
+++ b/src/theory/quantifiers/expr_miner.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -23,7 +23,6 @@
#include "expr/expr.h"
#include "expr/expr_manager.h"
-#include "expr/variable_type_map.h"
#include "smt/smt_engine.h"
#include "theory/quantifiers/sygus_sampler.h"
diff --git a/src/theory/quantifiers/expr_miner_manager.cpp b/src/theory/quantifiers/expr_miner_manager.cpp
index f99b06567..fdcfe8ac5 100644
--- a/src/theory/quantifiers/expr_miner_manager.cpp
+++ b/src/theory/quantifiers/expr_miner_manager.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -27,7 +27,8 @@ ExpressionMinerManager::ExpressionMinerManager()
d_doFilterLogicalStrength(false),
d_use_sygus_type(false),
d_qe(nullptr),
- d_tds(nullptr)
+ d_tds(nullptr),
+ d_crd(options::sygusRewSynthCheck(), options::sygusRewSynthAccel(), false)
{
}
@@ -142,7 +143,8 @@ bool ExpressionMinerManager::addTerm(Node sol,
bool ret = true;
if (d_doRewSynth)
{
- ret = d_crd.addTerm(sol, options::sygusRewSynthRec(), out, rew_print);
+ Node rsol = d_crd.addTerm(sol, options::sygusRewSynthRec(), out, rew_print);
+ ret = (sol == rsol);
}
// a unique term, let's try the query generator
diff --git a/src/theory/quantifiers/expr_miner_manager.h b/src/theory/quantifiers/expr_miner_manager.h
index 82c0959c6..e6474f53f 100644
--- a/src/theory/quantifiers/expr_miner_manager.h
+++ b/src/theory/quantifiers/expr_miner_manager.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/extended_rewrite.cpp b/src/theory/quantifiers/extended_rewrite.cpp
index c1a0b8ee9..6897287d6 100644
--- a/src/theory/quantifiers/extended_rewrite.cpp
+++ b/src/theory/quantifiers/extended_rewrite.cpp
@@ -2,10 +2,10 @@
/*! \file extended_rewrite.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Mathias Preiner, Andres Noetzli
+ ** Andrew Reynolds, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/extended_rewrite.h b/src/theory/quantifiers/extended_rewrite.h
index 5ed6ee3f3..8b5f74a2f 100644
--- a/src/theory/quantifiers/extended_rewrite.h
+++ b/src/theory/quantifiers/extended_rewrite.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/first_order_model.cpp b/src/theory/quantifiers/first_order_model.cpp
index 61eb4ff39..ba91960e1 100644
--- a/src/theory/quantifiers/first_order_model.cpp
+++ b/src/theory/quantifiers/first_order_model.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -51,7 +51,8 @@ void FirstOrderModel::assertQuantifier( Node n ){
}
}
-unsigned FirstOrderModel::getNumAssertedQuantifiers() {
+size_t FirstOrderModel::getNumAssertedQuantifiers() const
+{
return d_forall_asserts.size();
}
diff --git a/src/theory/quantifiers/first_order_model.h b/src/theory/quantifiers/first_order_model.h
index 4e1ef6d7f..a26401dd1 100644
--- a/src/theory/quantifiers/first_order_model.h
+++ b/src/theory/quantifiers/first_order_model.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Paul Meng, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -17,6 +17,7 @@
#ifndef CVC4__FIRST_ORDER_MODEL_H
#define CVC4__FIRST_ORDER_MODEL_H
+#include "context/cdlist.h"
#include "expr/attribute.h"
#include "theory/theory_model.h"
#include "theory/uf/theory_uf_model.h"
@@ -59,7 +60,7 @@ class FirstOrderModel : public TheoryModel
/** assert quantifier */
void assertQuantifier( Node n );
/** get number of asserted quantifiers */
- unsigned getNumAssertedQuantifiers();
+ size_t getNumAssertedQuantifiers() const;
/** get asserted quantifier */
Node getAssertedQuantifier( unsigned i, bool ordered = false );
/** initialize model for term */
diff --git a/src/theory/quantifiers/fmf/bounded_integers.cpp b/src/theory/quantifiers/fmf/bounded_integers.cpp
index b3ea69dbc..2d6af9a63 100644
--- a/src/theory/quantifiers/fmf/bounded_integers.cpp
+++ b/src/theory/quantifiers/fmf/bounded_integers.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -676,7 +676,7 @@ Node BoundedIntegers::getSetRangeValue( Node q, Node v, RepSetIterator * rsi ) {
Assert(i < d_setm_choice[sro].size());
choice_i = d_setm_choice[sro][i];
choices.push_back(choice_i);
- Node sChoiceI = nm->mkNode(SINGLETON, choice_i);
+ Node sChoiceI = nm->mkSingleton(choice_i.getType(), choice_i);
if (nsr.isNull())
{
nsr = sChoiceI;
@@ -723,7 +723,7 @@ bool BoundedIntegers::getRsiSubsitution( Node q, Node v, std::vector< Node >& va
nn = nn.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
Node lem = NodeManager::currentNM()->mkNode( LEQ, nn, d_range[q][v] );
Trace("bound-int-lemma") << "*** Add lemma to minimize instantiated non-ground term " << lem << std::endl;
- d_quantEngine->getOutputChannel().lemma(lem, false, true);
+ d_quantEngine->getOutputChannel().lemma(lem, LemmaProperty::PREPROCESS);
}
return false;
}else{
diff --git a/src/theory/quantifiers/fmf/bounded_integers.h b/src/theory/quantifiers/fmf/bounded_integers.h
index a21c9d81b..bc509d78a 100644
--- a/src/theory/quantifiers/fmf/bounded_integers.h
+++ b/src/theory/quantifiers/fmf/bounded_integers.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Mudathir Mohamed
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/fmf/full_model_check.cpp b/src/theory/quantifiers/fmf/full_model_check.cpp
index 802271858..683dde688 100644
--- a/src/theory/quantifiers/fmf/full_model_check.cpp
+++ b/src/theory/quantifiers/fmf/full_model_check.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -527,7 +527,7 @@ bool FullModelChecker::processBuildModel(TheoryModel* m){
void FullModelChecker::preInitializeType( FirstOrderModelFmc * fm, TypeNode tn ){
if( d_preinitialized_types.find( tn )==d_preinitialized_types.end() ){
d_preinitialized_types[tn] = true;
- if (!tn.isFunction() || options::ufHo())
+ if (tn.isFirstClass())
{
Trace("fmc") << "Get model basis term " << tn << "..." << std::endl;
Node mb = fm->getModelBasisTerm(tn);
diff --git a/src/theory/quantifiers/fmf/full_model_check.h b/src/theory/quantifiers/fmf/full_model_check.h
index 4a6c62827..c49cd596b 100644
--- a/src/theory/quantifiers/fmf/full_model_check.h
+++ b/src/theory/quantifiers/fmf/full_model_check.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/fmf/model_builder.cpp b/src/theory/quantifiers/fmf/model_builder.cpp
index c8e0ba89a..796ee85fa 100644
--- a/src/theory/quantifiers/fmf/model_builder.cpp
+++ b/src/theory/quantifiers/fmf/model_builder.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -17,7 +17,6 @@
#include "options/quantifiers_options.h"
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/fmf/model_engine.h"
-#include "theory/quantifiers/fun_def_process.h"
#include "theory/quantifiers/instantiate.h"
#include "theory/quantifiers/quant_rep_bound_ext.h"
#include "theory/quantifiers_engine.h"
diff --git a/src/theory/quantifiers/fmf/model_builder.h b/src/theory/quantifiers/fmf/model_builder.h
index 432686c60..052f6f802 100644
--- a/src/theory/quantifiers/fmf/model_builder.h
+++ b/src/theory/quantifiers/fmf/model_builder.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/fmf/model_engine.cpp b/src/theory/quantifiers/fmf/model_engine.cpp
index 879bfd1c1..07840655a 100644
--- a/src/theory/quantifiers/fmf/model_engine.cpp
+++ b/src/theory/quantifiers/fmf/model_engine.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Kshitij Bansal
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -24,9 +24,7 @@
#include "theory/quantifiers/term_util.h"
#include "theory/quantifiers_engine.h"
#include "theory/theory_engine.h"
-#include "theory/uf/cardinality_extension.h"
#include "theory/uf/equality_engine.h"
-#include "theory/uf/theory_uf.h"
using namespace std;
using namespace CVC4;
@@ -79,7 +77,6 @@ void ModelEngine::check(Theory::Effort e, QEffort quant_e)
if( doCheck ){
Assert(!d_quantEngine->inConflict());
int addedLemmas = 0;
- FirstOrderModel* fm = d_quantEngine->getModel();
//the following will test that the model satisfies all asserted universal quantifiers by
// (model-based) exhaustive instantiation.
@@ -88,28 +85,16 @@ void ModelEngine::check(Theory::Effort e, QEffort quant_e)
Trace("model-engine") << "---Model Engine Round---" << std::endl;
clSet = double(clock())/double(CLOCKS_PER_SEC);
}
-
- Trace("model-engine-debug") << "Verify uf ss is minimal..." << std::endl;
- // Let the cardinality extension verify that the model is minimal.
- // This will if there are terms in the model that the cardinality extension
- // was not notified of.
- uf::CardinalityExtension* ufss =
- static_cast<uf::TheoryUF*>(
- d_quantEngine->getTheoryEngine()->theoryOf(THEORY_UF))
- ->getCardinalityExtension();
- if( !ufss || ufss->debugModel( fm ) ){
- Trace("model-engine-debug") << "Check model..." << std::endl;
- d_incomplete_check = false;
- //print debug
- if( Trace.isOn("fmf-model-complete") ){
- Trace("fmf-model-complete") << std::endl;
- debugPrint("fmf-model-complete");
- }
- //successfully built an acceptable model, now check it
- addedLemmas += checkModel();
- }else{
- addedLemmas++;
+ Trace("model-engine-debug") << "Check model..." << std::endl;
+ d_incomplete_check = false;
+ // print debug
+ if (Trace.isOn("fmf-model-complete"))
+ {
+ Trace("fmf-model-complete") << std::endl;
+ debugPrint("fmf-model-complete");
}
+ // successfully built an acceptable model, now check it
+ addedLemmas += checkModel();
if( Trace.isOn("model-engine") ){
double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
diff --git a/src/theory/quantifiers/fmf/model_engine.h b/src/theory/quantifiers/fmf/model_engine.h
index a46c7cbf3..6d9d3bfe3 100644
--- a/src/theory/quantifiers/fmf/model_engine.h
+++ b/src/theory/quantifiers/fmf/model_engine.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/fun_def_evaluator.cpp b/src/theory/quantifiers/fun_def_evaluator.cpp
index 951899883..d6d7351b9 100644
--- a/src/theory/quantifiers/fun_def_evaluator.cpp
+++ b/src/theory/quantifiers/fun_def_evaluator.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/fun_def_evaluator.h b/src/theory/quantifiers/fun_def_evaluator.h
index 7e159bb26..c8390ecf5 100644
--- a/src/theory/quantifiers/fun_def_evaluator.h
+++ b/src/theory/quantifiers/fun_def_evaluator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/fun_def_process.cpp b/src/theory/quantifiers/fun_def_process.cpp
deleted file mode 100644
index 2c5eab94c..000000000
--- a/src/theory/quantifiers/fun_def_process.cpp
+++ /dev/null
@@ -1,340 +0,0 @@
-/********************* */
-/*! \file fun_def_process.cpp
- ** \verbatim
- ** Top contributors (to current version):
- ** Andrew Reynolds, Mathias Preiner, Morgan Deters
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Sort inference module
- **
- ** This class implements pre-process steps for admissible recursive function definitions (Reynolds et al IJCAR2016)
- **/
-
-#include <vector>
-
-#include "theory/quantifiers/fun_def_process.h"
-#include "theory/quantifiers/quantifiers_attributes.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/quantifiers/term_util.h"
-#include "proof/proof_manager.h"
-
-using namespace CVC4;
-using namespace std;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
-using namespace CVC4::kind;
-
-
-void FunDefFmf::simplify( std::vector< Node >& assertions ) {
- std::vector< int > fd_assertions;
- std::map< int, Node > subs_head;
- //first pass : find defined functions, transform quantifiers
- NodeManager* nm = NodeManager::currentNM();
- for( unsigned i=0; i<assertions.size(); i++ ){
- Node n = QuantAttributes::getFunDefHead( assertions[i] );
- if( !n.isNull() ){
- Assert(n.getKind() == APPLY_UF);
- Node f = n.getOperator();
-
- //check if already defined, if so, throw error
- if( d_sorts.find( f )!=d_sorts.end() ){
- Message() << "Cannot define function " << f << " more than once." << std::endl;
- AlwaysAssert(false);
- }
-
- Node bd = QuantAttributes::getFunDefBody( assertions[i] );
- Trace("fmf-fun-def-debug") << "Process function " << n << ", body = " << bd << std::endl;
- if( !bd.isNull() ){
- d_funcs.push_back( f );
- bd = NodeManager::currentNM()->mkNode( EQUAL, n, bd );
-
- //create a sort S that represents the inputs of the function
- std::stringstream ss;
- ss << "I_" << f;
- TypeNode iType = NodeManager::currentNM()->mkSort( ss.str() );
- AbsTypeFunDefAttribute atfda;
- iType.setAttribute(atfda,true);
- d_sorts[f] = iType;
-
- //create functions f1...fn mapping from this sort to concrete elements
- for( unsigned j=0; j<n.getNumChildren(); j++ ){
- TypeNode typ = NodeManager::currentNM()->mkFunctionType( iType, n[j].getType() );
- std::stringstream ssf;
- ssf << f << "_arg_" << j;
- d_input_arg_inj[f].push_back(
- nm->mkSkolem(ssf.str(), typ, "op created during fun def fmf"));
- }
-
- //construct new quantifier forall S. F[f1(S)/x1....fn(S)/xn]
- std::vector< Node > children;
- Node bv = NodeManager::currentNM()->mkBoundVar("?i", iType );
- Node bvl = NodeManager::currentNM()->mkNode( kind::BOUND_VAR_LIST, bv );
- std::vector< Node > subs;
- std::vector< Node > vars;
- for( unsigned j=0; j<n.getNumChildren(); j++ ){
- vars.push_back( n[j] );
- subs.push_back( NodeManager::currentNM()->mkNode( APPLY_UF, d_input_arg_inj[f][j], bv ) );
- }
- bd = bd.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
- subs_head[i] = n.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
-
- Trace("fmf-fun-def") << "FMF fun def: FUNCTION : rewrite " << assertions[i] << std::endl;
- Trace("fmf-fun-def") << " to " << std::endl;
- Node new_q = NodeManager::currentNM()->mkNode( FORALL, bvl, bd );
- new_q = Rewriter::rewrite( new_q );
- PROOF( ProofManager::currentPM()->addDependence(new_q, assertions[i]); );
- assertions[i] = new_q;
- Trace("fmf-fun-def") << " " << assertions[i] << std::endl;
- fd_assertions.push_back( i );
- }else{
- //can be, e.g. in corner cases forall x. f(x)=f(x), forall x. f(x)=f(x)+1
- }
- }
- }
- //second pass : rewrite assertions
- std::map< int, std::map< Node, Node > > visited;
- std::map< int, std::map< Node, Node > > visited_cons;
- for( unsigned i=0; i<assertions.size(); i++ ){
- bool is_fd = std::find( fd_assertions.begin(), fd_assertions.end(), i )!=fd_assertions.end();
- std::vector<Node> constraints;
- Trace("fmf-fun-def-rewrite") << "Rewriting " << assertions[i]
- << ", is function definition = " << is_fd
- << std::endl;
- Node n = simplifyFormula(assertions[i],
- true,
- true,
- constraints,
- is_fd ? subs_head[i] : Node::null(),
- is_fd,
- visited,
- visited_cons);
- Assert(constraints.empty());
- if (n != assertions[i])
- {
- n = Rewriter::rewrite(n);
- Trace("fmf-fun-def-rewrite") << "FMF fun def : rewrite " << assertions[i]
- << std::endl;
- Trace("fmf-fun-def-rewrite") << " to " << std::endl;
- Trace("fmf-fun-def-rewrite") << " " << n << std::endl;
- PROOF(ProofManager::currentPM()->addDependence(n, assertions[i]););
- assertions[i] = n;
- }
- }
-}
-
-Node FunDefFmf::simplifyFormula( Node n, bool pol, bool hasPol, std::vector< Node >& constraints, Node hd, bool is_fun_def,
- std::map< int, std::map< Node, Node > >& visited,
- std::map< int, std::map< Node, Node > >& visited_cons ) {
- Assert(constraints.empty());
- int index = ( is_fun_def ? 1 : 0 ) + 2*( hasPol ? ( pol ? 1 : -1 ) : 0 );
- std::map< Node, Node >::iterator itv = visited[index].find( n );
- if( itv!=visited[index].end() ){
- //constraints.insert( visited_cons[index]
- std::map< Node, Node >::iterator itvc = visited_cons[index].find( n );
- if( itvc != visited_cons[index].end() ){
- constraints.push_back( itvc->second );
- }
- return itv->second;
- }else{
- Node ret;
- Trace("fmf-fun-def-debug2") << "Simplify " << n << " " << pol << " " << hasPol << " " << is_fun_def << std::endl;
- if( n.getKind()==FORALL ){
- Node c = simplifyFormula( n[1], pol, hasPol, constraints, hd, is_fun_def, visited, visited_cons );
- //append prenex to constraints
- for( unsigned i=0; i<constraints.size(); i++ ){
- constraints[i] = NodeManager::currentNM()->mkNode( FORALL, n[0], constraints[i] );
- constraints[i] = Rewriter::rewrite( constraints[i] );
- }
- if( c!=n[1] ){
- ret = NodeManager::currentNM()->mkNode( FORALL, n[0], c );
- }else{
- ret = n;
- }
- }else{
- Node nn = n;
- bool isBool = n.getType().isBoolean();
- if( isBool && n.getKind()!=APPLY_UF ){
- std::vector< Node > children;
- bool childChanged = false;
- // are we at a branch position (not all children are necessarily relevant)?
- bool branch_pos = ( n.getKind()==ITE || n.getKind()==OR || n.getKind()==AND );
- std::vector< Node > branch_constraints;
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- Node c = n[i];
- //do not process LHS of definition
- if( !is_fun_def || c!=hd ){
- bool newHasPol;
- bool newPol;
- QuantPhaseReq::getPolarity( n, i, hasPol, pol, newHasPol, newPol );
- //get child constraints
- std::vector< Node > cconstraints;
- c = simplifyFormula( n[i], newPol, newHasPol, cconstraints, hd, false, visited, visited_cons );
- if( branch_pos ){
- // if at a branching position, the other constraints don't matter if this is satisfied
- Node bcons = cconstraints.empty() ? NodeManager::currentNM()->mkConst( true ) :
- ( cconstraints.size()==1 ? cconstraints[0] : NodeManager::currentNM()->mkNode( AND, cconstraints ) );
- branch_constraints.push_back( bcons );
- Trace("fmf-fun-def-debug2") << "Branching constraint at arg " << i << " is " << bcons << std::endl;
- }
- constraints.insert( constraints.end(), cconstraints.begin(), cconstraints.end() );
- }
- children.push_back( c );
- childChanged = c!=n[i] || childChanged;
- }
- if( childChanged ){
- nn = NodeManager::currentNM()->mkNode( n.getKind(), children );
- }
- if( branch_pos && !constraints.empty() ){
- // if we are at a branching position in the formula, we can
- // minimize recursive constraints on recursively defined predicates if we know one child forces
- // the overall evaluation of this formula.
- Node branch_cond;
- if( n.getKind()==ITE ){
- // always care about constraints on the head of the ITE, but only care about one of the children depending on how it evaluates
- branch_cond = NodeManager::currentNM()->mkNode( kind::AND, branch_constraints[0],
- NodeManager::currentNM()->mkNode( kind::ITE, n[0], branch_constraints[1], branch_constraints[2] ) );
- }else{
- // in the default case, we care about all conditions
- branch_cond = constraints.size()==1 ? constraints[0] : NodeManager::currentNM()->mkNode( AND, constraints );
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- // if this child holds with forcing polarity (true child of OR or false child of AND),
- // then we only care about its associated recursive conditions
- branch_cond = NodeManager::currentNM()->mkNode( kind::ITE,
- ( n.getKind()==OR ? n[i] : n[i].negate() ), branch_constraints[i], branch_cond );
- }
- }
- Trace("fmf-fun-def-debug2") << "Made branching condition " << branch_cond << std::endl;
- constraints.clear();
- constraints.push_back( branch_cond );
- }
- }else{
- //simplify term
- std::map<Node, Node> visitedT;
- getConstraints(n, constraints, visitedT);
- }
- if( !constraints.empty() && isBool && hasPol ){
- //conjoin with current
- Node cons = constraints.size()==1 ? constraints[0] : NodeManager::currentNM()->mkNode( AND, constraints );
- if( pol ){
- ret = NodeManager::currentNM()->mkNode( AND, nn, cons );
- }else{
- ret = NodeManager::currentNM()->mkNode( OR, nn, cons.negate() );
- }
- Trace("fmf-fun-def-debug2") << "Add constraint to obtain " << ret << std::endl;
- constraints.clear();
- }else{
- ret = nn;
- }
- }
- if( !constraints.empty() ){
- Node cons;
- //flatten to AND node for the purposes of caching
- if( constraints.size()>1 ){
- cons = NodeManager::currentNM()->mkNode( AND, constraints );
- cons = Rewriter::rewrite( cons );
- constraints.clear();
- constraints.push_back( cons );
- }else{
- cons = constraints[0];
- }
- visited_cons[index][n] = cons;
- Assert(constraints.size() == 1 && constraints[0] == cons);
- }
- visited[index][n] = ret;
- return ret;
- }
-}
-
-void FunDefFmf::getConstraints(Node n,
- std::vector<Node>& constraints,
- std::map<Node, Node>& visited)
-{
- std::map<Node, Node>::iterator itv = visited.find(n);
- if (itv != visited.end())
- {
- // already visited
- if (!itv->second.isNull())
- {
- // add the cached constraint if it does not already occur
- if (std::find(constraints.begin(), constraints.end(), itv->second)
- == constraints.end())
- {
- constraints.push_back(itv->second);
- }
- }
- return;
- }
- visited[n] = Node::null();
- std::vector<Node> currConstraints;
- NodeManager* nm = NodeManager::currentNM();
- if (n.getKind() == ITE)
- {
- // collect constraints for the condition
- getConstraints(n[0], currConstraints, visited);
- // collect constraints for each branch
- Node cs[2];
- for (unsigned i = 0; i < 2; i++)
- {
- std::vector<Node> ccons;
- getConstraints(n[i + 1], ccons, visited);
- cs[i] = ccons.empty()
- ? nm->mkConst(true)
- : (ccons.size() == 1 ? ccons[0] : nm->mkNode(AND, ccons));
- }
- if (!cs[0].isConst() || !cs[1].isConst())
- {
- Node itec = nm->mkNode(ITE, n[0], cs[0], cs[1]);
- currConstraints.push_back(itec);
- Trace("fmf-fun-def-debug")
- << "---> add constraint " << itec << " for " << n << std::endl;
- }
- }
- else
- {
- if (n.getKind() == APPLY_UF)
- {
- // check if f is defined, if so, we must enforce domain constraints for
- // this f-application
- Node f = n.getOperator();
- std::map<Node, TypeNode>::iterator it = d_sorts.find(f);
- if (it != d_sorts.end())
- {
- // create existential
- Node z = nm->mkBoundVar("?z", it->second);
- Node bvl = nm->mkNode(BOUND_VAR_LIST, z);
- std::vector<Node> children;
- for (unsigned j = 0, size = n.getNumChildren(); j < size; j++)
- {
- Node uz = nm->mkNode(APPLY_UF, d_input_arg_inj[f][j], z);
- children.push_back(uz.eqNode(n[j]));
- }
- Node bd =
- children.size() == 1 ? children[0] : nm->mkNode(AND, children);
- bd = bd.negate();
- Node ex = nm->mkNode(FORALL, bvl, bd);
- ex = ex.negate();
- currConstraints.push_back(ex);
- Trace("fmf-fun-def-debug")
- << "---> add constraint " << ex << " for " << n << std::endl;
- }
- }
- for (const Node& cn : n)
- {
- getConstraints(cn, currConstraints, visited);
- }
- }
- // set the visited cache
- if (!currConstraints.empty())
- {
- Node finalc = currConstraints.size() == 1
- ? currConstraints[0]
- : nm->mkNode(AND, currConstraints);
- visited[n] = finalc;
- // add to constraints
- getConstraints(n, constraints, visited);
- }
-}
diff --git a/src/theory/quantifiers/fun_def_process.h b/src/theory/quantifiers/fun_def_process.h
deleted file mode 100644
index ce2d2e239..000000000
--- a/src/theory/quantifiers/fun_def_process.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/********************* */
-/*! \file fun_def_process.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Andrew Reynolds, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief Pre-process step for admissible recursively defined functions
- **/
-
-#include "cvc4_private.h"
-
-#ifndef CVC4__QUANTIFIERS_FUN_DEF_PROCESS_H
-#define CVC4__QUANTIFIERS_FUN_DEF_PROCESS_H
-
-#include <map>
-#include <vector>
-#include "expr/attribute.h"
-#include "expr/node.h"
-#include "expr/type_node.h"
-
-namespace CVC4 {
-namespace theory {
-
-/**
- * Attribute marked true for types that are used as abstraction types in
- * the algorithm below.
- */
-struct AbsTypeFunDefAttributeId
-{
-};
-typedef expr::Attribute<AbsTypeFunDefAttributeId, bool> AbsTypeFunDefAttribute;
-
-namespace quantifiers {
-
-//Preprocessing pass to allow finite model finding for admissible recursive function definitions
-// For details, see Reynolds et al "Model Finding for Recursive Functions" IJCAR 2016
-class FunDefFmf {
-private:
- /** simplify formula
- * This is A_0 in Figure 1 of Reynolds et al "Model Finding for Recursive Functions".
- * The input of A_0 in that paper is a pair ( term t, polarity p )
- * The return value of A_0 in that paper is a pair ( term t', set of formulas X ).
- *
- * This function implements this such that :
- * n is t
- * pol/hasPol is p
- * the return value is t'
- * the set of formulas X are stored in "constraints"
- *
- * Additionally, is_fun_def is whether we are currently processing the top of a function defintion,
- * since this affects whether we process the head of the definition.
- */
- Node simplifyFormula( Node n, bool pol, bool hasPol, std::vector< Node >& constraints, Node hd, bool is_fun_def,
- std::map< int, std::map< Node, Node > >& visited,
- std::map< int, std::map< Node, Node > >& visited_cons );
-public:
- FunDefFmf(){}
- ~FunDefFmf(){}
- //defined functions to input sort (alpha)
- std::map< Node, TypeNode > d_sorts;
- //defined functions to injections input -> argument elements (gamma)
- std::map< Node, std::vector< Node > > d_input_arg_inj;
- // (newly) defined functions
- std::vector< Node > d_funcs;
- /** simplify, which does the following:
- * (1) records all top-level recursive function definitions in assertions,
- * (2) runs Figure 1 of Reynolds et al "Model Finding for Recursive Functions"
- * IJCAR 2016 on all formulas in assertions based on the definitions from part (1),
- * which are Sigma^{dfn} in that paper.
- */
- void simplify( std::vector< Node >& assertions );
- /** get constraints
- *
- * This computes constraints for the final else branch of A_0 in Figure 1
- * of Reynolds et al "Model Finding for Recursive Functions". The range of
- * the cache visited stores the constraint (if any) for each node.
- */
- void getConstraints(Node n,
- std::vector<Node>& constraints,
- std::map<Node, Node>& visited);
-};
-
-
-}
-}
-}
-
-#endif
diff --git a/src/theory/quantifiers/inst_match.cpp b/src/theory/quantifiers/inst_match.cpp
index 69b228f8e..b2b58220a 100644
--- a/src/theory/quantifiers/inst_match.cpp
+++ b/src/theory/quantifiers/inst_match.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Francois Bobot
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/inst_match.h b/src/theory/quantifiers/inst_match.h
index 46741d098..a51c0ecdc 100644
--- a/src/theory/quantifiers/inst_match.h
+++ b/src/theory/quantifiers/inst_match.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/inst_match_trie.cpp b/src/theory/quantifiers/inst_match_trie.cpp
index e5ab44032..aaf7cb4bc 100644
--- a/src/theory/quantifiers/inst_match_trie.cpp
+++ b/src/theory/quantifiers/inst_match_trie.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -256,6 +256,32 @@ void InstMatchTrie::getExplanationForInstLemmas(
}
}
+void InstMatchTrie::getInstantiations(
+ Node q, std::vector<std::vector<Node>>& insts) const
+{
+ std::vector<Node> terms;
+ getInstantiations(q, insts, terms);
+}
+
+void InstMatchTrie::getInstantiations(Node q,
+ std::vector<std::vector<Node>>& insts,
+ std::vector<Node>& terms) const
+{
+ if (terms.size() == q[0].getNumChildren())
+ {
+ insts.push_back(terms);
+ }
+ else
+ {
+ for (const std::pair<const Node, InstMatchTrie>& d : d_data)
+ {
+ terms.push_back(d.first);
+ d.second.getInstantiations(q, insts, terms);
+ terms.pop_back();
+ }
+ }
+}
+
CDInstMatchTrie::~CDInstMatchTrie()
{
for (std::pair<const Node, CDInstMatchTrie*>& d : d_data)
@@ -517,6 +543,36 @@ void CDInstMatchTrie::getExplanationForInstLemmas(
}
}
+void CDInstMatchTrie::getInstantiations(
+ Node q, std::vector<std::vector<Node>>& insts) const
+{
+ std::vector<Node> terms;
+ getInstantiations(q, insts, terms);
+}
+
+void CDInstMatchTrie::getInstantiations(Node q,
+ std::vector<std::vector<Node>>& insts,
+ std::vector<Node>& terms) const
+{
+ if (!d_valid.get())
+ {
+ // do nothing
+ }
+ else if (terms.size() == q[0].getNumChildren())
+ {
+ insts.push_back(terms);
+ }
+ else
+ {
+ for (const std::pair<const Node, CDInstMatchTrie*>& d : d_data)
+ {
+ terms.push_back(d.first);
+ d.second->getInstantiations(q, insts, terms);
+ terms.pop_back();
+ }
+ }
+}
+
} /* CVC4::theory::inst namespace */
} /* CVC4::theory namespace */
} /* CVC4 namespace */
diff --git a/src/theory/quantifiers/inst_match_trie.h b/src/theory/quantifiers/inst_match_trie.h
index 961d1608c..a63954838 100644
--- a/src/theory/quantifiers/inst_match_trie.h
+++ b/src/theory/quantifiers/inst_match_trie.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -125,6 +125,10 @@ class InstMatchTrie
Node lem,
ImtIndexOrder* imtio = NULL,
unsigned index = 0);
+ /**
+ * Adds the instantiations for q into insts.
+ */
+ void getInstantiations(Node q, std::vector<std::vector<Node>>& insts) const;
/** get instantiations
*
@@ -174,6 +178,10 @@ class InstMatchTrie
std::map<Node, InstMatchTrie> d_data;
private:
+ /** Helper for getInstantiations.*/
+ void getInstantiations(Node q,
+ std::vector<std::vector<Node>>& insts,
+ std::vector<Node>& terms) const;
/** helper for print
* terms accumulates the path we are on in the trie.
*/
@@ -293,6 +301,10 @@ class CDInstMatchTrie
std::vector<Node>& m,
Node lem,
unsigned index = 0);
+ /**
+ * Adds the instantiations for q into insts.
+ */
+ void getInstantiations(Node q, std::vector<std::vector<Node>>& insts) const;
/** get instantiations
*
@@ -338,6 +350,10 @@ class CDInstMatchTrie
}
private:
+ /** Helper for getInstantiations.*/
+ void getInstantiations(Node q,
+ std::vector<std::vector<Node>>& insts,
+ std::vector<Node>& terms) const;
/** the data */
std::map<Node, CDInstMatchTrie*> d_data;
/** is valid */
diff --git a/src/theory/quantifiers/inst_strategy_enumerative.cpp b/src/theory/quantifiers/inst_strategy_enumerative.cpp
index b85537e64..3f6943a72 100644
--- a/src/theory/quantifiers/inst_strategy_enumerative.cpp
+++ b/src/theory/quantifiers/inst_strategy_enumerative.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/inst_strategy_enumerative.h b/src/theory/quantifiers/inst_strategy_enumerative.h
index 070878a3d..a77eb8a90 100644
--- a/src/theory/quantifiers/inst_strategy_enumerative.h
+++ b/src/theory/quantifiers/inst_strategy_enumerative.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/instantiate.cpp b/src/theory/quantifiers/instantiate.cpp
index c9048fc95..fb622452e 100644
--- a/src/theory/quantifiers/instantiate.cpp
+++ b/src/theory/quantifiers/instantiate.cpp
@@ -2,10 +2,10 @@
/*! \file instantiate.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Morgan Deters, Tim King
+ ** Andrew Reynolds, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,6 +16,8 @@
#include "expr/node_algorithm.h"
#include "options/quantifiers_options.h"
+#include "options/smt_options.h"
+#include "proof/proof_manager.h"
#include "smt/smt_statistics_registry.h"
#include "theory/quantifiers/cegqi/inst_strategy_cegqi.h"
#include "theory/quantifiers/first_order_model.h"
@@ -33,12 +35,16 @@ namespace CVC4 {
namespace theory {
namespace quantifiers {
-Instantiate::Instantiate(QuantifiersEngine* qe, context::UserContext* u)
+Instantiate::Instantiate(QuantifiersEngine* qe,
+ context::UserContext* u,
+ ProofNodeManager* pnm)
: d_qe(qe),
+ d_pnm(pnm),
d_term_db(nullptr),
d_term_util(nullptr),
d_total_inst_debug(u),
- d_c_inst_match_trie_dom(u)
+ d_c_inst_match_trie_dom(u),
+ d_pfInst(pnm ? new CDProof(pnm) : nullptr)
{
}
@@ -229,35 +235,100 @@ bool Instantiate::addInstantiation(
return false;
}
+ // Set up a proof if proofs are enabled. This proof stores a proof of
+ // the instantiation body with q as a free assumption.
+ std::shared_ptr<LazyCDProof> pfTmp;
+ if (isProofEnabled())
+ {
+ pfTmp.reset(new LazyCDProof(
+ d_pnm, nullptr, nullptr, "Instantiate::LazyCDProof::tmp"));
+ }
+
// construct the instantiation
Trace("inst-add-debug") << "Constructing instantiation..." << std::endl;
Assert(d_term_util->d_vars[q].size() == terms.size());
// get the instantiation
- Node body = getInstantiation(q, d_term_util->d_vars[q], terms, doVts);
+ Node body =
+ getInstantiation(q, d_term_util->d_vars[q], terms, doVts, pfTmp.get());
Node orig_body = body;
- // now preprocess
- body = quantifiers::QuantifiersRewriter::preprocess(body, true);
+ // now preprocess, storing the trust node for the rewrite
+ TrustNode tpBody = quantifiers::QuantifiersRewriter::preprocess(body, true);
+ if (!tpBody.isNull())
+ {
+ Assert(tpBody.getKind() == TrustNodeKind::REWRITE);
+ body = tpBody.getNode();
+ // do a tranformation step
+ if (pfTmp != nullptr)
+ {
+ // ----------------- from preprocess
+ // orig_body orig_body = body
+ // ------------------------------ EQ_RESOLVE
+ // body
+ Node proven = tpBody.getProven();
+ // add the transformation proof, or THEORY_PREPROCESS if none provided
+ pfTmp->addLazyStep(proven,
+ tpBody.getGenerator(),
+ PfRule::THEORY_PREPROCESS,
+ true,
+ "Instantiate::getInstantiation:qpreprocess");
+ pfTmp->addStep(body, PfRule::EQ_RESOLVE, {orig_body, proven}, {});
+ }
+ }
Trace("inst-debug") << "...preprocess to " << body << std::endl;
// construct the lemma
Trace("inst-assert") << "(assert " << body << ")" << std::endl;
- if (d_qe->usingModelEqualityEngine() && options::instNoModelTrue())
+ // construct the instantiation, and rewrite the lemma
+ Node lem = NodeManager::currentNM()->mkNode(kind::IMPLIES, q, body);
+
+ // If proofs are enabled, construct the proof, which is of the form:
+ // ... free assumption q ...
+ // ------------------------- from pfTmp
+ // body
+ // ------------------------- SCOPE
+ // (=> q body)
+ // -------------------------- MACRO_SR_PRED_ELIM
+ // lem
+ bool hasProof = false;
+ if (isProofEnabled())
+ {
+ // make the proof of body
+ std::shared_ptr<ProofNode> pfn = pfTmp->getProofFor(body);
+ // make the scope proof to get (=> q body)
+ std::vector<Node> assumps;
+ assumps.push_back(q);
+ std::shared_ptr<ProofNode> pfns = d_pnm->mkScope({pfn}, assumps);
+ Assert(assumps.size() == 1 && assumps[0] == q);
+ // store in the main proof
+ d_pfInst->addProof(pfns);
+ Node prevLem = lem;
+ lem = Rewriter::rewrite(lem);
+ if (prevLem != lem)
+ {
+ d_pfInst->addStep(lem, PfRule::MACRO_SR_PRED_ELIM, {prevLem}, {});
+ }
+ hasProof = true;
+ }
+ else
{
- Node val_body = d_qe->getModel()->getValue(body);
- if (val_body.isConst() && val_body.getConst<bool>())
- {
- Trace("inst-add-debug") << " --> True in model." << std::endl;
- ++(d_statistics.d_inst_duplicate_model_true);
- return false;
- }
+ lem = Rewriter::rewrite(lem);
}
- Node lem = NodeManager::currentNM()->mkNode(kind::OR, q.negate(), body);
- lem = Rewriter::rewrite(lem);
+ // added lemma, which checks for lemma duplication
+ bool addedLem = false;
+ if (hasProof)
+ {
+ // use trust interface
+ TrustNode tlem = TrustNode::mkTrustLemma(lem, d_pfInst.get());
+ addedLem = d_qe->addTrustedLemma(tlem, true, false);
+ }
+ else
+ {
+ addedLem = d_qe->addLemma(lem, true, false);
+ }
- // check for lemma duplication
- if (!d_qe->addLemma(lem, true, false))
+ if (!addedLem)
{
Trace("inst-add-debug") << " --> Lemma already exists." << std::endl;
++(d_statistics.d_inst_duplicate);
@@ -376,7 +447,8 @@ bool Instantiate::existsInstantiation(Node q,
Node Instantiate::getInstantiation(Node q,
std::vector<Node>& vars,
std::vector<Node>& terms,
- bool doVts)
+ bool doVts,
+ LazyCDProof* pf)
{
Node body;
Assert(vars.size() == terms.size());
@@ -384,10 +456,33 @@ Node Instantiate::getInstantiation(Node q,
// Notice that this could be optimized, but no significant performance
// improvements were observed with alternative implementations (see #1386).
body = q[1].substitute(vars.begin(), vars.end(), terms.begin(), terms.end());
+
+ // store the proof of the instantiated body, with (open) assumption q
+ if (pf != nullptr)
+ {
+ pf->addStep(body, PfRule::INSTANTIATE, {q}, terms);
+ }
+
// run rewriters to rewrite the instantiation in sequence.
for (InstantiationRewriter*& ir : d_instRewrite)
{
- body = ir->rewriteInstantiation(q, terms, body, doVts);
+ TrustNode trn = ir->rewriteInstantiation(q, terms, body, doVts);
+ if (!trn.isNull())
+ {
+ Node newBody = trn.getNode();
+ // if using proofs, we store a preprocess + transformation step.
+ if (pf != nullptr)
+ {
+ Node proven = trn.getProven();
+ pf->addLazyStep(proven,
+ trn.getGenerator(),
+ PfRule::THEORY_PREPROCESS,
+ true,
+ "Instantiate::getInstantiation:rewrite_inst");
+ pf->addStep(newBody, PfRule::EQ_RESOLVE, {body, proven}, {});
+ }
+ body = newBody;
+ }
}
return body;
}
@@ -588,18 +683,21 @@ void Instantiate::getInstantiatedQuantifiedFormulas(std::vector<Node>& qs)
bool Instantiate::getUnsatCoreLemmas(std::vector<Node>& active_lemmas)
{
// only if unsat core available
- if (options::proof())
+ if (options::unsatCores())
{
if (!ProofManager::currentPM()->unsatCoreAvailable())
{
return false;
}
}
+ else
+ {
+ return false;
+ }
Trace("inst-unsat-core") << "Get instantiations in unsat core..."
<< std::endl;
- ProofManager::currentPM()->getLemmasInUnsatCore(theory::THEORY_QUANTIFIERS,
- active_lemmas);
+ ProofManager::currentPM()->getLemmasInUnsatCore(active_lemmas);
if (Trace.isOn("inst-unsat-core"))
{
Trace("inst-unsat-core") << "Quantifiers lemmas in unsat core: "
@@ -613,38 +711,42 @@ bool Instantiate::getUnsatCoreLemmas(std::vector<Node>& active_lemmas)
return true;
}
-bool Instantiate::getUnsatCoreLemmas(std::vector<Node>& active_lemmas,
- std::map<Node, Node>& weak_imp)
+void Instantiate::getInstantiationTermVectors(
+ Node q, std::vector<std::vector<Node> >& tvecs)
{
- if (getUnsatCoreLemmas(active_lemmas))
+ // if track instantiations is true, we use the instantiation + explanation
+ // methods for doing minimization based on unsat cores.
+ if (options::trackInstLemmas())
{
- for (unsigned i = 0, size = active_lemmas.size(); i < size; ++i)
+ std::vector<Node> lemmas;
+ getInstantiations(q, lemmas);
+ std::map<Node, Node> quant;
+ std::map<Node, std::vector<Node> > tvec;
+ getExplanationForInstLemmas(lemmas, quant, tvec);
+ for (std::pair<const Node, std::vector<Node> >& t : tvec)
{
- Node n = ProofManager::currentPM()->getWeakestImplicantInUnsatCore(
- active_lemmas[i]);
- if (n != active_lemmas[i])
- {
- Trace("inst-unsat-core") << " weaken : " << active_lemmas[i] << " -> "
- << n << std::endl;
- }
- weak_imp[active_lemmas[i]] = n;
+ tvecs.push_back(t.second);
}
- return true;
+ return;
}
- return false;
-}
-void Instantiate::getInstantiationTermVectors(
- Node q, std::vector<std::vector<Node> >& tvecs)
-{
- std::vector<Node> lemmas;
- getInstantiations(q, lemmas);
- std::map<Node, Node> quant;
- std::map<Node, std::vector<Node> > tvec;
- getExplanationForInstLemmas(lemmas, quant, tvec);
- for (std::pair<const Node, std::vector<Node> >& t : tvec)
+ if (options::incrementalSolving())
{
- tvecs.push_back(t.second);
+ std::map<Node, inst::CDInstMatchTrie*>::const_iterator it =
+ d_c_inst_match_trie.find(q);
+ if (it != d_c_inst_match_trie.end())
+ {
+ it->second->getInstantiations(q, tvecs);
+ }
+ }
+ else
+ {
+ std::map<Node, inst::InstMatchTrie>::const_iterator it =
+ d_inst_match_trie.find(q);
+ if (it != d_inst_match_trie.end())
+ {
+ it->second.getInstantiations(q, tvecs);
+ }
}
}
@@ -653,14 +755,14 @@ void Instantiate::getInstantiationTermVectors(
{
if (options::incrementalSolving())
{
- for (std::pair<const Node, inst::CDInstMatchTrie*>& t : d_c_inst_match_trie)
+ for (const auto& t : d_c_inst_match_trie)
{
getInstantiationTermVectors(t.first, insts[t.first]);
}
}
else
{
- for (std::pair<const Node, inst::InstMatchTrie>& t : d_inst_match_trie)
+ for (const auto& t : d_inst_match_trie)
{
getInstantiationTermVectors(t.first, insts[t.first]);
}
@@ -702,6 +804,8 @@ void Instantiate::getExplanationForInstLemmas(
#endif
}
+bool Instantiate::isProofEnabled() const { return d_pfInst != nullptr; }
+
void Instantiate::getInstantiations(std::map<Node, std::vector<Node> >& insts)
{
if (!options::trackInstLemmas())
@@ -845,14 +949,12 @@ Instantiate::Statistics::Statistics()
: d_instantiations("Instantiate::Instantiations_Total", 0),
d_inst_duplicate("Instantiate::Duplicate_Inst", 0),
d_inst_duplicate_eq("Instantiate::Duplicate_Inst_Eq", 0),
- d_inst_duplicate_ent("Instantiate::Duplicate_Inst_Entailed", 0),
- d_inst_duplicate_model_true("Instantiate::Duplicate_Inst_Model_True", 0)
+ d_inst_duplicate_ent("Instantiate::Duplicate_Inst_Entailed", 0)
{
smtStatisticsRegistry()->registerStat(&d_instantiations);
smtStatisticsRegistry()->registerStat(&d_inst_duplicate);
smtStatisticsRegistry()->registerStat(&d_inst_duplicate_eq);
smtStatisticsRegistry()->registerStat(&d_inst_duplicate_ent);
- smtStatisticsRegistry()->registerStat(&d_inst_duplicate_model_true);
}
Instantiate::Statistics::~Statistics()
@@ -861,7 +963,6 @@ Instantiate::Statistics::~Statistics()
smtStatisticsRegistry()->unregisterStat(&d_inst_duplicate);
smtStatisticsRegistry()->unregisterStat(&d_inst_duplicate_eq);
smtStatisticsRegistry()->unregisterStat(&d_inst_duplicate_ent);
- smtStatisticsRegistry()->unregisterStat(&d_inst_duplicate_model_true);
}
} /* CVC4::theory::quantifiers namespace */
diff --git a/src/theory/quantifiers/instantiate.h b/src/theory/quantifiers/instantiate.h
index 16ff1f2c3..4cc3c3d6d 100644
--- a/src/theory/quantifiers/instantiate.h
+++ b/src/theory/quantifiers/instantiate.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,6 +20,7 @@
#include <map>
#include "expr/node.h"
+#include "expr/proof.h"
#include "theory/quantifiers/inst_match_trie.h"
#include "theory/quantifiers/quant_util.h"
#include "util/statistics_registry.h"
@@ -53,11 +54,14 @@ class InstantiationRewriter
*
* The flag doVts is whether we must apply virtual term substitution to the
* instantiation.
+ *
+ * Returns a TrustNode of kind REWRITE, corresponding to the rewrite of inst
+ * and its proof generator.
*/
- virtual Node rewriteInstantiation(Node q,
- std::vector<Node>& terms,
- Node inst,
- bool doVts) = 0;
+ virtual TrustNode rewriteInstantiation(Node q,
+ std::vector<Node>& terms,
+ Node inst,
+ bool doVts) = 0;
};
/** Instantiate
@@ -84,7 +88,9 @@ class Instantiate : public QuantifiersUtil
typedef context::CDHashMap<Node, uint32_t, NodeHashFunction> NodeUIntMap;
public:
- Instantiate(QuantifiersEngine* qe, context::UserContext* u);
+ Instantiate(QuantifiersEngine* qe,
+ context::UserContext* u,
+ ProofNodeManager* pnm = nullptr);
~Instantiate();
/** reset */
@@ -174,11 +180,16 @@ class Instantiate : public QuantifiersUtil
*
* Returns the instantiation lemma for q under substitution { vars -> terms }.
* doVts is whether to apply virtual term substitution to its body.
+ *
+ * If provided, pf is a lazy proof for which we store a proof of the
+ * returned formula with free assumption q. This typically stores a
+ * single INSTANTIATE step concluding the instantiated body of q from q.
*/
Node getInstantiation(Node q,
std::vector<Node>& vars,
std::vector<Node>& terms,
- bool doVts = false);
+ bool doVts = false,
+ LazyCDProof* pf = nullptr);
/** get instantiation
*
* Same as above, but with vars/terms specified by InstMatch m.
@@ -268,21 +279,6 @@ class Instantiate : public QuantifiersUtil
* This method returns false if the unsat core is not available.
*/
bool getUnsatCoreLemmas(std::vector<Node>& active_lemmas);
- /** get unsat core lemmas
- *
- * If this method returns true, then it appends to active_lemmas all lemmas
- * that are in the unsat core that originated from the theory of quantifiers.
- * This method returns false if the unsat core is not available.
- *
- * It also computes a weak implicant for each of these lemmas. For each lemma
- * L in active_lemmas, this is a formula L' such that:
- * L => L'
- * and replacing L by L' in the unsat core results in a set that is still
- * unsatisfiable. The map weak_imp stores this formula for each formula in
- * active_lemmas.
- */
- bool getUnsatCoreLemmas(std::vector<Node>& active_lemmas,
- std::map<Node, Node>& weak_imp);
/** get explanation for instantiation lemmas
*
*
@@ -292,6 +288,9 @@ class Instantiate : public QuantifiersUtil
std::map<Node, std::vector<Node> >& tvec);
//--------------------------------------end user-level interface utilities
+ /** Are proofs enabled for this object? */
+ bool isProofEnabled() const;
+
/** statistics class
*
* This tracks statistics on the number of instantiations successfully
@@ -305,7 +304,6 @@ class Instantiate : public QuantifiersUtil
IntStat d_inst_duplicate;
IntStat d_inst_duplicate_eq;
IntStat d_inst_duplicate_ent;
- IntStat d_inst_duplicate_model_true;
Statistics();
~Statistics();
}; /* class Instantiate::Statistics */
@@ -343,6 +341,8 @@ class Instantiate : public QuantifiersUtil
/** pointer to the quantifiers engine */
QuantifiersEngine* d_qe;
+ /** pointer to the proof node manager */
+ ProofNodeManager* d_pnm;
/** cache of term database for quantifiers engine */
TermDb* d_term_db;
/** cache of term util for quantifiers engine */
@@ -375,6 +375,10 @@ class Instantiate : public QuantifiersUtil
* of these instantiations, for each quantified formula.
*/
std::vector<std::pair<Node, std::vector<Node> > > d_recorded_inst;
+ /**
+ * A CDProof storing instantiation steps.
+ */
+ std::unique_ptr<CDProof> d_pfInst;
};
} /* CVC4::theory::quantifiers namespace */
diff --git a/src/theory/quantifiers/lazy_trie.cpp b/src/theory/quantifiers/lazy_trie.cpp
index 41722822e..1347e6aca 100644
--- a/src/theory/quantifiers/lazy_trie.cpp
+++ b/src/theory/quantifiers/lazy_trie.cpp
@@ -5,7 +5,7 @@
** Haniel Barbosa, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/lazy_trie.h b/src/theory/quantifiers/lazy_trie.h
index 7f8e306e9..02f773219 100644
--- a/src/theory/quantifiers/lazy_trie.h
+++ b/src/theory/quantifiers/lazy_trie.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/proof_checker.cpp b/src/theory/quantifiers/proof_checker.cpp
index a1a581d1c..5f6e4a119 100644
--- a/src/theory/quantifiers/proof_checker.cpp
+++ b/src/theory/quantifiers/proof_checker.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,6 +14,7 @@
#include "theory/quantifiers/proof_checker.h"
+#include "expr/node_algorithm.h"
#include "expr/skolem_manager.h"
#include "theory/builtin/proof_checker.h"
@@ -36,23 +37,47 @@ Node QuantifiersProofRuleChecker::checkInternal(
PfRule id, const std::vector<Node>& children, const std::vector<Node>& args)
{
NodeManager* nm = NodeManager::currentNM();
+ SkolemManager* sm = nm->getSkolemManager();
// compute what was proven
- if (id == PfRule::WITNESS_INTRO || id == PfRule::EXISTS_INTRO)
+ if (id == PfRule::EXISTS_INTRO)
{
Assert(children.size() == 1);
Assert(args.size() == 1);
- SkolemManager* sm = nm->getSkolemManager();
Node p = children[0];
- Node t = args[0];
- Node exists = sm->mkExistential(t, p);
- if (id == PfRule::EXISTS_INTRO)
+ Node exists = args[0];
+ if (exists.getKind() != kind::EXISTS || exists[0].getNumChildren() != 1)
{
- return exists;
+ return Node::null();
+ }
+ std::unordered_map<Node, Node, NodeHashFunction> subs;
+ if (!expr::match(exists[1], p, subs))
+ {
+ return Node::null();
+ }
+ // substitution must contain only the variable of the existential
+ for (const std::pair<const Node, Node>& s : subs)
+ {
+ if (s.first != exists[0][0])
+ {
+ return Node::null();
+ }
+ }
+ return exists;
+ }
+ else if (id == PfRule::WITNESS_INTRO)
+ {
+ Assert(children.size() == 1);
+ Assert(args.empty());
+ if (children[0].getKind() != EXISTS || children[0][0].getNumChildren() != 1)
+ {
+ return Node::null();
}
std::vector<Node> skolems;
- sm->mkSkolemize(exists, skolems, "k");
+ sm->mkSkolemize(children[0], skolems, "k");
Assert(skolems.size() == 1);
- return skolems[0];
+ Node witness = SkolemManager::getWitnessForm(skolems[0]);
+ Assert(witness.getKind() == WITNESS && witness[0] == children[0][0]);
+ return skolems[0].eqNode(witness);
}
else if (id == PfRule::SKOLEMIZE)
{
@@ -64,7 +89,6 @@ Node QuantifiersProofRuleChecker::checkInternal(
{
return Node::null();
}
- SkolemManager* sm = nm->getSkolemManager();
Node exists;
if (children[0].getKind() == EXISTS)
{
@@ -73,6 +97,7 @@ Node QuantifiersProofRuleChecker::checkInternal(
else
{
std::vector<Node> echildren(children[0][0].begin(), children[0][0].end());
+ echildren[1] = echildren[1].notNode();
exists = nm->mkNode(EXISTS, echildren);
}
std::vector<Node> skolems;
diff --git a/src/theory/quantifiers/proof_checker.h b/src/theory/quantifiers/proof_checker.h
index 1e107e6bb..f611e4045 100644
--- a/src/theory/quantifiers/proof_checker.h
+++ b/src/theory/quantifiers/proof_checker.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/quant_conflict_find.cpp b/src/theory/quantifiers/quant_conflict_find.cpp
index b3e9eb22a..fa8982760 100644
--- a/src/theory/quantifiers/quant_conflict_find.cpp
+++ b/src/theory/quantifiers/quant_conflict_find.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/quant_conflict_find.h b/src/theory/quantifiers/quant_conflict_find.h
index f3ba5db6b..90385865b 100644
--- a/src/theory/quantifiers/quant_conflict_find.h
+++ b/src/theory/quantifiers/quant_conflict_find.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/quant_epr.cpp b/src/theory/quantifiers/quant_epr.cpp
index 8c3e7e5ed..cf2deee11 100644
--- a/src/theory/quantifiers/quant_epr.cpp
+++ b/src/theory/quantifiers/quant_epr.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/quant_epr.h b/src/theory/quantifiers/quant_epr.h
index 60700bf5b..752b80d6c 100644
--- a/src/theory/quantifiers/quant_epr.h
+++ b/src/theory/quantifiers/quant_epr.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/quant_relevance.cpp b/src/theory/quantifiers/quant_relevance.cpp
index 0ddbe9a05..175bb149a 100644
--- a/src/theory/quantifiers/quant_relevance.cpp
+++ b/src/theory/quantifiers/quant_relevance.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/quant_relevance.h b/src/theory/quantifiers/quant_relevance.h
index c03f8d229..3396c2099 100644
--- a/src/theory/quantifiers/quant_relevance.h
+++ b/src/theory/quantifiers/quant_relevance.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/quant_rep_bound_ext.cpp b/src/theory/quantifiers/quant_rep_bound_ext.cpp
index 5034d926a..5bb50c926 100644
--- a/src/theory/quantifiers/quant_rep_bound_ext.cpp
+++ b/src/theory/quantifiers/quant_rep_bound_ext.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/quant_rep_bound_ext.h b/src/theory/quantifiers/quant_rep_bound_ext.h
index 1f8ad19fa..53cd11015 100644
--- a/src/theory/quantifiers/quant_rep_bound_ext.h
+++ b/src/theory/quantifiers/quant_rep_bound_ext.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/quant_split.cpp b/src/theory/quantifiers/quant_split.cpp
index a61a60edf..57778b4c8 100644
--- a/src/theory/quantifiers/quant_split.cpp
+++ b/src/theory/quantifiers/quant_split.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/quant_split.h b/src/theory/quantifiers/quant_split.h
index 1aa57c1c3..12cf5e5af 100644
--- a/src/theory/quantifiers/quant_split.h
+++ b/src/theory/quantifiers/quant_split.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/quant_util.cpp b/src/theory/quantifiers/quant_util.cpp
index a8eda10bb..23815dc37 100644
--- a/src/theory/quantifiers/quant_util.cpp
+++ b/src/theory/quantifiers/quant_util.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -32,7 +32,7 @@ QuantifiersModule::QEffort QuantifiersModule::needsModel(Theory::Effort e)
eq::EqualityEngine* QuantifiersModule::getEqualityEngine() const
{
- return d_quantEngine->getActiveEqualityEngine();
+ return d_quantEngine->getMasterEqualityEngine();
}
bool QuantifiersModule::areEqual(TNode n1, TNode n2) const
diff --git a/src/theory/quantifiers/quant_util.h b/src/theory/quantifiers/quant_util.h
index db77c10e8..507c71698 100644
--- a/src/theory/quantifiers/quant_util.h
+++ b/src/theory/quantifiers/quant_util.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/quantifiers_attributes.cpp b/src/theory/quantifiers/quantifiers_attributes.cpp
index c00d3c579..0f5ada549 100644
--- a/src/theory/quantifiers/quantifiers_attributes.cpp
+++ b/src/theory/quantifiers/quantifiers_attributes.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Paul Meng, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -30,7 +30,8 @@ namespace quantifiers {
bool QAttributes::isStandard() const
{
- return !d_sygus && !d_quant_elim && !isFunDef() && d_name.isNull();
+ return !d_sygus && !d_quant_elim && !isFunDef() && d_name.isNull()
+ && !d_isInternal;
}
QuantAttributes::QuantAttributes( QuantifiersEngine * qe ) :
@@ -45,10 +46,6 @@ void QuantAttributes::setUserAttribute( const std::string& attr, Node n, std::ve
Trace("quant-attr-debug") << "Set function definition " << n << std::endl;
FunDefAttribute fda;
n.setAttribute( fda, true );
- }else if( attr=="sygus" ){
- Trace("quant-attr-debug") << "Set sygus " << n << std::endl;
- SygusAttribute ca;
- n.setAttribute( ca, true );
}
else if (attr == "qid")
{
@@ -56,17 +53,6 @@ void QuantAttributes::setUserAttribute( const std::string& attr, Node n, std::ve
Trace("quant-attr-debug") << "Set quant-name " << n << std::endl;
QuantNameAttribute qna;
n.setAttribute(qna, true);
- } else if (attr == "sygus-synth-grammar") {
- Assert(node_values.size() == 1);
- Trace("quant-attr-debug") << "Set sygus synth grammar " << n << " to "
- << node_values[0] << std::endl;
- SygusSynthGrammarAttribute ssg;
- n.setAttribute(ssg, node_values[0]);
- }else if( attr=="sygus-synth-fun-var-list" ){
- Assert(node_values.size() == 1);
- Trace("quant-attr-debug") << "Set sygus synth fun var list to " << n << " to " << node_values[0] << std::endl;
- SygusSynthFunVarListAttribute ssfvla;
- n.setAttribute( ssfvla, node_values[0] );
}else if( attr=="quant-inst-max-level" ){
Assert(node_values.size() == 1);
uint64_t lvl = node_values[0].getConst<Rational>().getNumerator().getLong();
@@ -250,6 +236,11 @@ void QuantAttributes::computeQuantAttributes( Node q, QAttributes& qa ){
qa.d_quant_elim_partial = true;
//don't set owner, should happen naturally
}
+ if (avar.getAttribute(InternalQuantAttribute()))
+ {
+ Trace("quant-attr") << "Attribute : internal : " << q << std::endl;
+ qa.d_isInternal = true;
+ }
if( avar.hasAttribute(QuantIdNumAttribute()) ){
qa.d_qid_num = avar;
Trace("quant-attr") << "Attribute : id number " << qa.d_qid_num.getAttribute(QuantIdNumAttribute()) << " : " << q << std::endl;
@@ -304,6 +295,16 @@ bool QuantAttributes::isQuantElimPartial( Node q ) {
}
}
+bool QuantAttributes::isInternal(Node q) const
+{
+ std::map<Node, QAttributes>::const_iterator it = d_qattr.find(q);
+ if (it != d_qattr.end())
+ {
+ return it->second.d_isInternal;
+ }
+ return false;
+}
+
Node QuantAttributes::getQuantName(Node q) const
{
std::map<Node, QAttributes>::const_iterator it = d_qattr.find(q);
diff --git a/src/theory/quantifiers/quantifiers_attributes.h b/src/theory/quantifiers/quantifiers_attributes.h
index cadf0b0d6..9fdb127e6 100644
--- a/src/theory/quantifiers/quantifiers_attributes.h
+++ b/src/theory/quantifiers/quantifiers_attributes.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -88,11 +88,33 @@ struct SygusVarToTermAttributeId
typedef expr::Attribute<SygusVarToTermAttributeId, Node>
SygusVarToTermAttribute;
-namespace quantifiers {
+/**
+ * Attribute marked true for types that are used as abstraction types in
+ * the finite model finding for function definitions algorithm.
+ */
+struct AbsTypeFunDefAttributeId
+{
+};
+typedef expr::Attribute<AbsTypeFunDefAttributeId, bool> AbsTypeFunDefAttribute;
-/** Attribute priority for rewrite rules */
-//struct RrPriorityAttributeId {};
-//typedef expr::Attribute< RrPriorityAttributeId, uint64_t > RrPriorityAttribute;
+/**
+ * Attribute true for quantifiers that have been internally generated, e.g.
+ * for reductions of string operators.
+ *
+ * Currently, this attribute is used for indicating that E-matching should
+ * not be applied, as E-matching should not be applied to quantifiers
+ * generated for strings reductions.
+ *
+ * This attribute can potentially be generalized to an identifier indicating
+ * the internal source of the quantified formula (of which strings reduction
+ * is one possibility).
+ */
+struct InternalQuantAttributeId
+{
+};
+typedef expr::Attribute<InternalQuantAttributeId, bool> InternalQuantAttribute;
+
+namespace quantifiers {
/** This struct stores attributes for a single quantified formula */
struct QAttributes
@@ -103,7 +125,8 @@ struct QAttributes
d_sygus(false),
d_qinstLevel(-1),
d_quant_elim(false),
- d_quant_elim_partial(false)
+ d_quant_elim_partial(false),
+ d_isInternal(false)
{
}
~QAttributes(){}
@@ -123,6 +146,8 @@ struct QAttributes
bool d_quant_elim;
/** is this formula marked for partial quantifier elimination? */
bool d_quant_elim_partial;
+ /** Is this formula internally generated? */
+ bool d_isInternal;
/** the instantiation pattern list for this quantified formula (its 3rd child)
*/
Node d_ipl;
@@ -192,12 +217,12 @@ public:
bool isSygus( Node q );
/** get instantiation level */
int getQuantInstLevel( Node q );
- /** get rewrite rule priority */
- int getRewriteRulePriority( Node q );
/** is quant elim */
bool isQuantElim( Node q );
/** is quant elim partial */
bool isQuantElimPartial( Node q );
+ /** is internal quantifier */
+ bool isInternal(Node q) const;
/** get quant name, which is used for :qid */
Node getQuantName(Node q) const;
/** get (internal) quant id num */
diff --git a/src/theory/quantifiers/quantifiers_modules.cpp b/src/theory/quantifiers/quantifiers_modules.cpp
new file mode 100644
index 000000000..1efd6d38f
--- /dev/null
+++ b/src/theory/quantifiers/quantifiers_modules.cpp
@@ -0,0 +1,113 @@
+/********************* */
+/*! \file quantifiers_modules.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Class for initializing the modules of quantifiers engine
+ **/
+
+#include "theory/quantifiers/quantifiers_modules.h"
+
+#include "options/quantifiers_options.h"
+#include "theory/quantifiers_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+QuantifiersModules::QuantifiersModules()
+ : d_rel_dom(nullptr),
+ d_alpha_equiv(nullptr),
+ d_inst_engine(nullptr),
+ d_model_engine(nullptr),
+ d_bint(nullptr),
+ d_qcf(nullptr),
+ d_sg_gen(nullptr),
+ d_synth_e(nullptr),
+ d_fs(nullptr),
+ d_i_cbqi(nullptr),
+ d_qsplit(nullptr),
+ d_anti_skolem(nullptr),
+ d_sygus_inst(nullptr)
+{
+}
+QuantifiersModules::~QuantifiersModules() {}
+void QuantifiersModules::initialize(QuantifiersEngine* qe,
+ context::Context* c,
+ std::vector<QuantifiersModule*>& modules)
+{
+ // add quantifiers modules
+ if (options::quantConflictFind())
+ {
+ d_qcf.reset(new quantifiers::QuantConflictFind(qe, c));
+ modules.push_back(d_qcf.get());
+ }
+ if (options::conjectureGen())
+ {
+ d_sg_gen.reset(new quantifiers::ConjectureGenerator(qe, c));
+ modules.push_back(d_sg_gen.get());
+ }
+ if (!options::finiteModelFind() || options::fmfInstEngine())
+ {
+ d_inst_engine.reset(new quantifiers::InstantiationEngine(qe));
+ modules.push_back(d_inst_engine.get());
+ }
+ if (options::cegqi())
+ {
+ d_i_cbqi.reset(new quantifiers::InstStrategyCegqi(qe));
+ modules.push_back(d_i_cbqi.get());
+ qe->getInstantiate()->addRewriter(d_i_cbqi->getInstRewriter());
+ }
+ if (options::sygus())
+ {
+ d_synth_e.reset(new quantifiers::SynthEngine(qe, c));
+ modules.push_back(d_synth_e.get());
+ }
+ // finite model finding
+ if (options::fmfBound())
+ {
+ d_bint.reset(new quantifiers::BoundedIntegers(c, qe));
+ modules.push_back(d_bint.get());
+ }
+ if (options::finiteModelFind() || options::fmfBound())
+ {
+ d_model_engine.reset(new quantifiers::ModelEngine(c, qe));
+ modules.push_back(d_model_engine.get());
+ }
+ if (options::quantDynamicSplit() != options::QuantDSplitMode::NONE)
+ {
+ d_qsplit.reset(new quantifiers::QuantDSplit(qe, c));
+ modules.push_back(d_qsplit.get());
+ }
+ if (options::quantAntiSkolem())
+ {
+ d_anti_skolem.reset(new quantifiers::QuantAntiSkolem(qe));
+ modules.push_back(d_anti_skolem.get());
+ }
+ if (options::quantAlphaEquiv())
+ {
+ d_alpha_equiv.reset(new quantifiers::AlphaEquivalence(qe));
+ }
+ // full saturation : instantiate from relevant domain, then arbitrary terms
+ if (options::fullSaturateQuant() || options::fullSaturateInterleave())
+ {
+ d_rel_dom.reset(new quantifiers::RelevantDomain(qe));
+ d_fs.reset(new quantifiers::InstStrategyEnum(qe, d_rel_dom.get()));
+ modules.push_back(d_fs.get());
+ }
+ if (options::sygusInst())
+ {
+ d_sygus_inst.reset(new quantifiers::SygusInst(qe));
+ modules.push_back(d_sygus_inst.get());
+ }
+}
+
+} // namespace quantifiers
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/quantifiers/quantifiers_modules.h b/src/theory/quantifiers/quantifiers_modules.h
new file mode 100644
index 000000000..87d8af37b
--- /dev/null
+++ b/src/theory/quantifiers/quantifiers_modules.h
@@ -0,0 +1,93 @@
+/********************* */
+/*! \file quantifiers_modules.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Class for initializing the modules of quantifiers engine
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_MODULES_H
+#define CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_MODULES_H
+
+#include "theory/quantifiers/alpha_equivalence.h"
+#include "theory/quantifiers/anti_skolem.h"
+#include "theory/quantifiers/conjecture_generator.h"
+#include "theory/quantifiers/ematching/instantiation_engine.h"
+#include "theory/quantifiers/fmf/bounded_integers.h"
+#include "theory/quantifiers/fmf/model_engine.h"
+#include "theory/quantifiers/inst_strategy_enumerative.h"
+#include "theory/quantifiers/quant_conflict_find.h"
+#include "theory/quantifiers/quant_split.h"
+#include "theory/quantifiers/sygus/synth_engine.h"
+#include "theory/quantifiers/sygus_inst.h"
+
+namespace CVC4 {
+namespace theory {
+
+class QuantifiersEngine;
+
+namespace quantifiers {
+
+/**
+ * This class is responsible for constructing the vector of modules to be
+ * used by quantifiers engine. It generates this list of modules in its
+ * initialize method, which is based on the options.
+ */
+class QuantifiersModules
+{
+ friend class ::CVC4::theory::QuantifiersEngine;
+ public:
+ QuantifiersModules();
+ ~QuantifiersModules();
+ /** initialize
+ *
+ * This constructs the above modules based on the current options. It adds
+ * a pointer to each module it constructs to modules.
+ */
+ void initialize(QuantifiersEngine* qe,
+ context::Context* c,
+ std::vector<QuantifiersModule*>& modules);
+ private:
+ //------------------------------ quantifier utilities
+ /** relevant domain */
+ std::unique_ptr<quantifiers::RelevantDomain> d_rel_dom;
+ //------------------------------ quantifiers modules
+ /** alpha equivalence */
+ std::unique_ptr<quantifiers::AlphaEquivalence> d_alpha_equiv;
+ /** instantiation engine */
+ std::unique_ptr<quantifiers::InstantiationEngine> d_inst_engine;
+ /** model engine */
+ std::unique_ptr<quantifiers::ModelEngine> d_model_engine;
+ /** bounded integers utility */
+ std::unique_ptr<quantifiers::BoundedIntegers> d_bint;
+ /** Conflict find mechanism for quantifiers */
+ std::unique_ptr<quantifiers::QuantConflictFind> d_qcf;
+ /** subgoal generator */
+ std::unique_ptr<quantifiers::ConjectureGenerator> d_sg_gen;
+ /** ceg instantiation */
+ std::unique_ptr<quantifiers::SynthEngine> d_synth_e;
+ /** full saturation */
+ std::unique_ptr<quantifiers::InstStrategyEnum> d_fs;
+ /** counterexample-based quantifier instantiation */
+ std::unique_ptr<quantifiers::InstStrategyCegqi> d_i_cbqi;
+ /** quantifiers splitting */
+ std::unique_ptr<quantifiers::QuantDSplit> d_qsplit;
+ /** quantifiers anti-skolemization */
+ std::unique_ptr<quantifiers::QuantAntiSkolem> d_anti_skolem;
+ /** SyGuS instantiation engine */
+ std::unique_ptr<quantifiers::SygusInst> d_sygus_inst;
+};
+
+} // namespace quantifiers
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_MODULES_H */
diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp
index 0848032f8..6d7275fac 100644
--- a/src/theory/quantifiers/quantifiers_rewriter.cpp
+++ b/src/theory/quantifiers/quantifiers_rewriter.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -1865,8 +1865,9 @@ bool QuantifiersRewriter::doOperation(Node q,
}
else if (computeOption == COMPUTE_PROCESS_TERMS)
{
- return options::elimExtArithQuant()
- || options::iteLiftQuant() != options::IteLiftQuantMode::NONE;
+ return is_std
+ && (options::elimExtArithQuant()
+ || options::iteLiftQuant() != options::IteLiftQuantMode::NONE);
}
else if (computeOption == COMPUTE_COND_SPLIT)
{
@@ -2052,8 +2053,8 @@ Node QuantifiersRewriter::preSkolemizeQuantifiers( Node n, bool polarity, std::v
return n;
}
-
-Node QuantifiersRewriter::preprocess( Node n, bool isInst ) {
+TrustNode QuantifiersRewriter::preprocess(Node n, bool isInst)
+{
Node prev = n;
if( options::preSkolemQuant() ){
@@ -2078,8 +2079,9 @@ Node QuantifiersRewriter::preprocess( Node n, bool isInst ) {
if( n!=prev ){
Trace("quantifiers-preprocess") << "Preprocess " << prev << std::endl;
Trace("quantifiers-preprocess") << "..returned " << n << std::endl;
+ return TrustNode::mkTrustRewrite(prev, n, nullptr);
}
- return n;
+ return TrustNode::null();
}
}/* CVC4::theory::quantifiers namespace */
diff --git a/src/theory/quantifiers/quantifiers_rewriter.h b/src/theory/quantifiers/quantifiers_rewriter.h
index da3bd2212..550f5b1dc 100644
--- a/src/theory/quantifiers/quantifiers_rewriter.h
+++ b/src/theory/quantifiers/quantifiers_rewriter.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,6 +20,7 @@
#define CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_REWRITER_H
#include "theory/theory_rewriter.h"
+#include "theory/trust_node.h"
namespace CVC4 {
namespace theory {
@@ -284,8 +285,10 @@ public:
* registered quantified formula. If this flag is true, we do not apply
* certain steps like pre-skolemization since we know they will have no
* effect.
+ *
+ * The result is wrapped in a trust node of kind TrustNodeKind::REWRITE.
*/
- static Node preprocess( Node n, bool isInst = false );
+ static TrustNode preprocess(Node n, bool isInst = false);
static Node mkForAll( std::vector< Node >& args, Node body, QAttributes& qa );
static Node mkForall( std::vector< Node >& args, Node body, bool marked = false );
static Node mkForall( std::vector< Node >& args, Node body, std::vector< Node >& iplc, bool marked = false );
diff --git a/src/theory/quantifiers/quantifiers_state.cpp b/src/theory/quantifiers/quantifiers_state.cpp
new file mode 100644
index 000000000..48b6b2b66
--- /dev/null
+++ b/src/theory/quantifiers/quantifiers_state.cpp
@@ -0,0 +1,30 @@
+/********************* */
+/*! \file quantifiers_state.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utility for quantifiers state
+ **/
+
+#include "theory/quantifiers/quantifiers_state.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+QuantifiersState::QuantifiersState(context::Context* c,
+ context::UserContext* u,
+ Valuation val)
+ : TheoryState(c, u, val)
+{
+}
+
+} // namespace quantifiers
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/quantifiers/quantifiers_state.h b/src/theory/quantifiers/quantifiers_state.h
new file mode 100644
index 000000000..76baab7ca
--- /dev/null
+++ b/src/theory/quantifiers/quantifiers_state.h
@@ -0,0 +1,40 @@
+/********************* */
+/*! \file quantifiers_state.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utility for quantifiers state
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_STATE_H
+#define CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_STATE_H
+
+#include "theory/theory_state.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+/**
+ * The quantifiers state.
+ */
+class QuantifiersState : public TheoryState
+{
+ public:
+ QuantifiersState(context::Context* c, context::UserContext* u, Valuation val);
+ ~QuantifiersState() {}
+};
+
+} // namespace quantifiers
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__QUANTIFIERS__QUANTIFIERS_STATE_H */
diff --git a/src/theory/quantifiers/query_generator.cpp b/src/theory/quantifiers/query_generator.cpp
index 39d27373d..55beea4ca 100644
--- a/src/theory/quantifiers/query_generator.cpp
+++ b/src/theory/quantifiers/query_generator.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/query_generator.h b/src/theory/quantifiers/query_generator.h
index 8b861a9b9..fd091ae95 100644
--- a/src/theory/quantifiers/query_generator.h
+++ b/src/theory/quantifiers/query_generator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/relevant_domain.cpp b/src/theory/quantifiers/relevant_domain.cpp
index 8946ca44a..1a3851800 100644
--- a/src/theory/quantifiers/relevant_domain.cpp
+++ b/src/theory/quantifiers/relevant_domain.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/relevant_domain.h b/src/theory/quantifiers/relevant_domain.h
index aeff5716c..6da4ce75a 100644
--- a/src/theory/quantifiers/relevant_domain.h
+++ b/src/theory/quantifiers/relevant_domain.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/single_inv_partition.cpp b/src/theory/quantifiers/single_inv_partition.cpp
index 7047aa9ea..c329d924b 100644
--- a/src/theory/quantifiers/single_inv_partition.cpp
+++ b/src/theory/quantifiers/single_inv_partition.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/single_inv_partition.h b/src/theory/quantifiers/single_inv_partition.h
index 3245228d8..d560287f6 100644
--- a/src/theory/quantifiers/single_inv_partition.h
+++ b/src/theory/quantifiers/single_inv_partition.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/skolemize.cpp b/src/theory/quantifiers/skolemize.cpp
index 364665e7a..61dd0c15e 100644
--- a/src/theory/quantifiers/skolemize.cpp
+++ b/src/theory/quantifiers/skolemize.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,6 +14,7 @@
#include "theory/quantifiers/skolemize.h"
+#include "expr/skolem_manager.h"
#include "options/quantifiers_options.h"
#include "theory/quantifiers/quantifiers_attributes.h"
#include "theory/quantifiers/term_util.h"
@@ -27,24 +28,65 @@ namespace CVC4 {
namespace theory {
namespace quantifiers {
-Skolemize::Skolemize(QuantifiersEngine* qe, context::UserContext* u)
- : d_quantEngine(qe), d_skolemized(u)
+Skolemize::Skolemize(QuantifiersEngine* qe,
+ context::UserContext* u,
+ ProofNodeManager* pnm)
+ : d_quantEngine(qe),
+ d_skolemized(u),
+ d_pnm(pnm),
+ d_epg(pnm == nullptr ? nullptr
+ : new EagerProofGenerator(pnm, u, "Skolemize::epg"))
{
}
-Node Skolemize::process(Node q)
+TrustNode Skolemize::process(Node q)
{
+ Assert(q.getKind() == FORALL);
// do skolemization
- if (d_skolemized.find(q) == d_skolemized.end())
+ if (d_skolemized.find(q) != d_skolemized.end())
{
+ return TrustNode::null();
+ }
+ Node lem;
+ ProofGenerator* pg = nullptr;
+ if (isProofEnabled() && !options::dtStcInduction()
+ && !options::intWfInduction())
+ {
+ // if using proofs and not using induction, we use the justified
+ // skolemization
+ NodeManager* nm = NodeManager::currentNM();
+ SkolemManager* skm = nm->getSkolemManager();
+ std::vector<Node> echildren(q.begin(), q.end());
+ echildren[1] = echildren[1].notNode();
+ Node existsq = nm->mkNode(EXISTS, echildren);
+ Node res = skm->mkSkolemize(existsq, d_skolem_constants[q], "skv");
+ Node qnot = q.notNode();
+ CDProof cdp(d_pnm);
+ cdp.addStep(res, PfRule::SKOLEMIZE, {qnot}, {});
+ std::shared_ptr<ProofNode> pf = cdp.getProofFor(res);
+ std::vector<Node> assumps;
+ assumps.push_back(qnot);
+ std::shared_ptr<ProofNode> pfs = d_pnm->mkScope({pf}, assumps);
+ lem = nm->mkNode(IMPLIES, qnot, res);
+ d_epg->setProofFor(lem, pfs);
+ pg = d_epg.get();
+ Trace("quantifiers-sk")
+ << "Skolemize (with proofs) : " << d_skolem_constants[q] << " for "
+ << std::endl;
+ Trace("quantifiers-sk") << " " << q << std::endl;
+ Trace("quantifiers-sk") << " " << res << std::endl;
+ }
+ else
+ {
+ // otherwise, we use the more general skolemization with inductive
+ // strengthening, which does not support proofs
Node body = getSkolemizedBody(q);
NodeBuilder<> nb(kind::OR);
nb << q << body.notNode();
- Node lem = nb;
- d_skolemized[q] = lem;
- return lem;
+ lem = nb;
}
- return Node::null();
+ d_skolemized[q] = lem;
+ return TrustNode::mkTrustLemma(lem, pg);
}
bool Skolemize::getSkolemConstants(Node q, std::vector<Node>& skolems)
@@ -274,16 +316,8 @@ Node Skolemize::mkSkolemizedBody(Node f,
ret, f.getAttribute(InstLevelAttribute()));
}
- if (Trace.isOn("quantifiers-sk"))
- {
- Trace("quantifiers-sk") << "Skolemize : ";
- for (unsigned i = 0; i < sk.size(); i++)
- {
- Trace("quantifiers-sk") << sk[i] << " ";
- }
- Trace("quantifiers-sk") << "for " << std::endl;
- Trace("quantifiers-sk") << " " << f << std::endl;
- }
+ Trace("quantifiers-sk") << "Skolemize : " << sk << " for " << std::endl;
+ Trace("quantifiers-sk") << " " << f << std::endl;
return ret;
}
@@ -291,14 +325,17 @@ Node Skolemize::mkSkolemizedBody(Node f,
Node Skolemize::getSkolemizedBody(Node f)
{
Assert(f.getKind() == FORALL);
- if (d_skolem_body.find(f) == d_skolem_body.end())
+ std::unordered_map<Node, Node, NodeHashFunction>::iterator it =
+ d_skolem_body.find(f);
+ if (it == d_skolem_body.end())
{
std::vector<TypeNode> fvTypes;
std::vector<TNode> fvs;
Node sub;
std::vector<unsigned> sub_vars;
- d_skolem_body[f] = mkSkolemizedBody(
+ Node ret = mkSkolemizedBody(
f, f[1], fvTypes, fvs, d_skolem_constants[f], sub, sub_vars);
+ d_skolem_body[f] = ret;
// store sub quantifier information
if (!sub.isNull())
{
@@ -320,8 +357,9 @@ Node Skolemize::getSkolemizedBody(Node f)
f, f[0][i], d_skolem_constants[f][i]);
}
}
+ return ret;
}
- return d_skolem_body[f];
+ return it->second;
}
bool Skolemize::isInductionTerm(Node n)
@@ -332,7 +370,7 @@ bool Skolemize::isInductionTerm(Node n)
const DType& dt = tn.getDType();
return !dt.isCodatatype();
}
- if (options::intWfInduction() && n.getType().isInteger())
+ if (options::intWfInduction() && tn.isInteger())
{
return true;
}
@@ -364,6 +402,8 @@ bool Skolemize::printSkolemization(std::ostream& out)
return printed;
}
+bool Skolemize::isProofEnabled() const { return d_epg != nullptr; }
+
} /* CVC4::theory::quantifiers namespace */
} /* CVC4::theory namespace */
} /* CVC4 namespace */
diff --git a/src/theory/quantifiers/skolemize.h b/src/theory/quantifiers/skolemize.h
index 0fe6bef00..4469fe851 100644
--- a/src/theory/quantifiers/skolemize.h
+++ b/src/theory/quantifiers/skolemize.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,12 +21,15 @@
#include <unordered_set>
#include "context/cdhashmap.h"
-#include "expr/datatype.h"
#include "expr/node.h"
#include "expr/type_node.h"
#include "theory/quantifiers/quant_util.h"
+#include "theory/trust_node.h"
namespace CVC4 {
+
+class DTypeConstructor;
+
namespace theory {
namespace quantifiers {
@@ -61,15 +64,16 @@ class Skolemize
typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
public:
- Skolemize(QuantifiersEngine* qe, context::UserContext* u);
+ Skolemize(QuantifiersEngine* qe,
+ context::UserContext* u,
+ ProofNodeManager* pnm);
~Skolemize() {}
/** skolemize quantified formula q
- * If the return value ret of this function
- * is non-null, then ret is a new skolemization lemma
- * we generated for q. These lemmas are constructed
- * once per user-context.
+ * If the return value ret of this function is non-null, then ret is a trust
+ * node corresponding to a new skolemization lemma we generated for q. These
+ * lemmas are constructed once per user-context.
*/
- Node process(Node q);
+ TrustNode process(Node q);
/** get skolem constants for quantified formula q */
bool getSkolemConstants(Node q, std::vector<Node>& skolems);
/** get the i^th skolem constant for quantified formula q */
@@ -117,6 +121,8 @@ class Skolemize
bool printSkolemization(std::ostream& out);
private:
+ /** Are proofs enabled? */
+ bool isProofEnabled() const;
/** get self selectors
* For datatype constructor dtc with type dt,
* this collects the set of datatype selector applications,
@@ -137,6 +143,10 @@ class Skolemize
d_skolem_constants;
/** map from quantified formulas to their skolemized body */
std::unordered_map<Node, Node, NodeHashFunction> d_skolem_body;
+ /** Pointer to the proof node manager */
+ ProofNodeManager* d_pnm;
+ /** Eager proof generator for skolemization lemmas */
+ std::unique_ptr<EagerProofGenerator> d_epg;
};
} /* CVC4::theory::quantifiers namespace */
diff --git a/src/theory/quantifiers/solution_filter.cpp b/src/theory/quantifiers/solution_filter.cpp
index d4637a636..cabc82ca1 100644
--- a/src/theory/quantifiers/solution_filter.cpp
+++ b/src/theory/quantifiers/solution_filter.cpp
@@ -2,10 +2,10 @@
/*! \file solution_filter.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Mathias Preiner
+ ** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/solution_filter.h b/src/theory/quantifiers/solution_filter.h
index 0be71371e..b9fe8b8c2 100644
--- a/src/theory/quantifiers/solution_filter.h
+++ b/src/theory/quantifiers/solution_filter.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/ce_guided_single_inv.cpp b/src/theory/quantifiers/sygus/ce_guided_single_inv.cpp
index cd9bbeb1f..e9e15ef3b 100644
--- a/src/theory/quantifiers/sygus/ce_guided_single_inv.cpp
+++ b/src/theory/quantifiers/sygus/ce_guided_single_inv.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -34,9 +34,8 @@ namespace CVC4 {
namespace theory {
namespace quantifiers {
-CegSingleInv::CegSingleInv(QuantifiersEngine* qe, SynthConjecture* p)
+CegSingleInv::CegSingleInv(QuantifiersEngine* qe)
: d_qe(qe),
- d_parent(p),
d_sip(new SingleInvocationPartition),
d_sol(new CegSingleInvSol(qe)),
d_isSolved(false),
@@ -61,20 +60,7 @@ void CegSingleInv::initialize(Node q)
// infer single invocation-ness
// get the variables
- std::vector< Node > progs;
- std::map< Node, std::vector< Node > > prog_vars;
- for (const Node& sf : q[0])
- {
- progs.push_back( sf );
- Node sfvl = CegGrammarConstructor::getSygusVarList(sf);
- if (!sfvl.isNull())
- {
- for (const Node& sfv : sfvl)
- {
- prog_vars[sf].push_back(sfv);
- }
- }
- }
+ std::vector<Node> progs(q[0].begin(), q[0].end());
// compute single invocation partition
Node qq;
if (q[1].getKind() == NOT && q[1][0].getKind() == FORALL)
@@ -113,163 +99,8 @@ void CegSingleInv::initialize(Node q)
if (options::cegqiSingleInvMode() != options::CegqiSingleInvMode::NONE)
{
d_single_invocation = true;
- return;
- }
- }
- // We are processing without single invocation techniques, now check if
- // we should fix an invariant template (post-condition strengthening or
- // pre-condition weakening).
- options::SygusInvTemplMode tmode = options::sygusInvTemplMode();
- if (tmode != options::SygusInvTemplMode::NONE)
- {
- // currently only works for single predicate synthesis
- if (q[0].getNumChildren() > 1 || !q[0][0].getType().isPredicate())
- {
- tmode = options::SygusInvTemplMode::NONE;
- }
- else if (!options::sygusInvTemplWhenSyntax())
- {
- // only use invariant templates if no syntactic restrictions
- if (CegGrammarConstructor::hasSyntaxRestrictions(q))
- {
- tmode = options::SygusInvTemplMode::NONE;
- }
- }
- }
-
- if (tmode == options::SygusInvTemplMode::NONE)
- {
- // not processing invariant templates
- return;
- }
- // if we are doing invariant templates, then construct the template
- Trace("sygus-si") << "- Do transition inference..." << std::endl;
- d_ti[q].process(qq, q[0][0]);
- Trace("cegqi-inv") << std::endl;
- Node prog = d_ti[q].getFunction();
- if (!d_ti[q].isComplete())
- {
- // the invariant could not be inferred
- return;
- }
- Assert(prog == q[0][0]);
- NodeManager* nm = NodeManager::currentNM();
- // map the program back via non-single invocation map
- std::vector<Node> prog_templ_vars;
- d_ti[q].getVariables(prog_templ_vars);
- d_trans_pre[prog] = d_ti[q].getPreCondition();
- d_trans_post[prog] = d_ti[q].getPostCondition();
- Trace("cegqi-inv") << " precondition : " << d_trans_pre[prog] << std::endl;
- Trace("cegqi-inv") << " postcondition : " << d_trans_post[prog] << std::endl;
- std::vector<Node> sivars;
- d_sip->getSingleInvocationVariables(sivars);
- Node invariant = d_sip->getFunctionInvocationFor(prog);
- if (invariant.isNull())
- {
- // the conjecture did not have an instance of the invariant
- // (e.g. it is trivially true/false).
- return;
- }
- invariant = invariant.substitute(sivars.begin(),
- sivars.end(),
- prog_templ_vars.begin(),
- prog_templ_vars.end());
- Trace("cegqi-inv") << " invariant : " << invariant << std::endl;
-
- // store simplified version of quantified formula
- d_simp_quant = d_sip->getFullSpecification();
- std::vector<Node> new_bv;
- for( const Node& v : sivars )
- {
- new_bv.push_back(nm->mkBoundVar(v.getType()));
- }
- d_simp_quant = d_simp_quant.substitute(
- sivars.begin(), sivars.end(), new_bv.begin(), new_bv.end());
- Assert(q[1].getKind() == NOT && q[1][0].getKind() == FORALL);
- for (const Node& v : q[1][0][0])
- {
- new_bv.push_back(v);
- }
- d_simp_quant =
- nm->mkNode(FORALL, nm->mkNode(BOUND_VAR_LIST, new_bv), d_simp_quant)
- .negate();
- d_simp_quant = Rewriter::rewrite(d_simp_quant);
- d_simp_quant = nm->mkNode(FORALL, q[0], d_simp_quant, q[2]);
- Trace("sygus-si") << "Rewritten quantifier : " << d_simp_quant << std::endl;
-
- // construct template argument
- d_templ_arg[prog] = nm->mkSkolem("I", invariant.getType());
-
- // construct template
- Node templ;
- if (options::sygusInvAutoUnfold())
- {
- if (d_ti[q].isComplete())
- {
- Trace("cegqi-inv-auto-unfold")
- << "Automatic deterministic unfolding... " << std::endl;
- // auto-unfold
- DetTrace dt;
- int init_dt = d_ti[q].initializeTrace(dt);
- if (init_dt == 0)
- {
- Trace("cegqi-inv-auto-unfold") << " Init : ";
- dt.print("cegqi-inv-auto-unfold");
- Trace("cegqi-inv-auto-unfold") << std::endl;
- unsigned counter = 0;
- unsigned status = 0;
- while (counter < 100 && status == 0)
- {
- status = d_ti[q].incrementTrace(dt);
- counter++;
- Trace("cegqi-inv-auto-unfold") << " #" << counter << " : ";
- dt.print("cegqi-inv-auto-unfold");
- Trace("cegqi-inv-auto-unfold")
- << "...status = " << status << std::endl;
- }
- if (status == 1)
- {
- // we have a trivial invariant
- templ = d_ti[q].constructFormulaTrace(dt);
- Trace("cegqi-inv") << "By finite deterministic terminating trace, a "
- "solution invariant is : "
- << std::endl;
- Trace("cegqi-inv") << " " << templ << std::endl;
- // this should be unnecessary
- templ = nm->mkNode(AND, templ, d_templ_arg[prog]);
- }
- }
- else
- {
- Trace("cegqi-inv-auto-unfold") << "...failed initialize." << std::endl;
- }
- }
- }
- Trace("cegqi-inv") << "Make the template... " << tmode << " " << templ
- << std::endl;
- if (templ.isNull())
- {
- if (tmode == options::SygusInvTemplMode::PRE)
- {
- templ = nm->mkNode(OR, d_trans_pre[prog], d_templ_arg[prog]);
- }
- else
- {
- Assert(tmode == options::SygusInvTemplMode::POST);
- templ = nm->mkNode(AND, d_trans_post[prog], d_templ_arg[prog]);
}
}
- Trace("cegqi-inv") << " template (pre-substitution) : " << templ
- << std::endl;
- Assert(!templ.isNull());
- // subsitute the template arguments
- Assert(prog_templ_vars.size() == prog_vars[prog].size());
- templ = templ.substitute(prog_templ_vars.begin(),
- prog_templ_vars.end(),
- prog_vars[prog].begin(),
- prog_vars[prog].end());
- Trace("cegqi-inv") << " template : " << templ << std::endl;
- d_templ[prog] = templ;
}
void CegSingleInv::finishInit(bool syntaxRestricted)
@@ -386,7 +217,7 @@ bool CegSingleInv::solve()
return false;
}
// now, get the instantiations
- std::vector<Expr> qs;
+ std::vector<Node> qs;
siSmt->getInstantiatedQuantifiedFormulas(qs);
Assert(qs.size() <= 1);
// track the instantiations, as solution construction is based on this
@@ -394,30 +225,28 @@ bool CegSingleInv::solve()
<< std::endl;
d_inst.clear();
d_instConds.clear();
- for (const Expr& q : qs)
+ for (const Node& q : qs)
{
- TNode qn = Node::fromExpr(q);
- Assert(qn.getKind() == FORALL);
- std::vector<std::vector<Expr> > tvecs;
- siSmt->getInstantiationTermVectors(q, tvecs);
- Trace("sygus-si") << "#instantiations of " << q << "=" << tvecs.size()
+ Assert(q.getKind() == FORALL);
+ siSmt->getInstantiationTermVectors(q, d_inst);
+ Trace("sygus-si") << "#instantiations of " << q << "=" << d_inst.size()
<< std::endl;
+ // We use the original synthesis conjecture siq, since q may contain
+ // internal symbols e.g. termITE skolem after preprocessing.
std::vector<Node> vars;
- for (const Node& v : qn[0])
+ for (const Node& v : siq[0])
{
vars.push_back(v);
}
- Node body = qn[1];
- for (unsigned i = 0, ninsts = tvecs.size(); i < ninsts; i++)
+ Node body = siq[1];
+ for (unsigned i = 0, ninsts = d_inst.size(); i < ninsts; i++)
{
- std::vector<Expr>& tvi = tvecs[i];
- std::vector<Node> inst;
- for (const Expr& t : tvi)
- {
- inst.push_back(Node::fromExpr(t));
- }
+ // note we do not convert to witness form here, since we could be
+ // an internal subsolver
+ std::vector<Node>& inst = d_inst[i];
Trace("sygus-si") << " Instantiation: " << inst << std::endl;
- d_inst.push_back(inst);
+ // instantiation should have same arity since we are not allowed to
+ // eliminate variables from quantifiers marked with QuantElimAttribute.
Assert(inst.size() == vars.size());
Node ilem =
body.substitute(vars.begin(), vars.end(), inst.begin(), inst.end());
@@ -573,6 +402,9 @@ Node CegSingleInv::reconstructToSyntax(Node s,
// In this case, we fail, since the solution is not valid.
Trace("csi-sol") << "FAIL : solution " << d_solution
<< " contains free constants." << std::endl;
+ Warning() <<
+ "Cannot get synth function: free constants encountered in synthesis "
+ "solution.";
reconstructed = -1;
}
if( Trace.isOn("cegqi-stats") ){
diff --git a/src/theory/quantifiers/sygus/ce_guided_single_inv.h b/src/theory/quantifiers/sygus/ce_guided_single_inv.h
index b16e3997a..0e1ddba1f 100644
--- a/src/theory/quantifiers/sygus/ce_guided_single_inv.h
+++ b/src/theory/quantifiers/sygus/ce_guided_single_inv.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -22,7 +22,6 @@
#include "theory/quantifiers/inst_match_trie.h"
#include "theory/quantifiers/single_inv_partition.h"
#include "theory/quantifiers/sygus/ce_guided_single_inv_sol.h"
-#include "theory/quantifiers/sygus/transition_inference.h"
namespace CVC4 {
namespace theory {
@@ -52,12 +51,8 @@ class CegSingleInv
private:
/** pointer to the quantifiers engine */
QuantifiersEngine* d_qe;
- /** the parent of this class */
- SynthConjecture* d_parent;
// single invocation inference utility
SingleInvocationPartition* d_sip;
- // transition inference module for each function to synthesize
- std::map< Node, TransitionInference > d_ti;
// solution reconstruction
CegSingleInvSol* d_sol;
@@ -100,16 +95,9 @@ class CegSingleInv
bool d_single_invocation;
// single invocation portion of quantified formula
Node d_single_inv;
- // transition relation version per program
- std::map< Node, Node > d_trans_pre;
- std::map< Node, Node > d_trans_post;
- // the template for each function to synthesize
- std::map< Node, Node > d_templ;
- // the template argument for each function to synthesize (occurs in exactly one position of its template)
- std::map< Node, Node > d_templ_arg;
public:
- CegSingleInv(QuantifiersEngine* qe, SynthConjecture* p);
+ CegSingleInv(QuantifiersEngine* qe);
~CegSingleInv();
// get simplified conjecture
@@ -144,35 +132,6 @@ class CegSingleInv
/** preregister conjecture */
void preregisterConjecture( Node q );
- Node getTransPre(Node prog) const {
- std::map<Node, Node>::const_iterator location = d_trans_pre.find(prog);
- return location->second;
- }
-
- Node getTransPost(Node prog) const {
- std::map<Node, Node>::const_iterator location = d_trans_post.find(prog);
- return location->second;
- }
- // get template for program prog. This returns a term of the form t[x] where x is the template argument (see below)
- Node getTemplate(Node prog) const {
- std::map<Node, Node>::const_iterator tmpl = d_templ.find(prog);
- if( tmpl!=d_templ.end() ){
- return tmpl->second;
- }else{
- return Node::null();
- }
- }
- // get the template argument for program prog.
- // This is a variable which indicates the position of the function/predicate to synthesize.
- Node getTemplateArg(Node prog) const {
- std::map<Node, Node>::const_iterator tmpla = d_templ_arg.find(prog);
- if( tmpla != d_templ_arg.end() ){
- return tmpla->second;
- }else{
- return Node::null();
- }
- }
-
private:
/** solve trivial
*
diff --git a/src/theory/quantifiers/sygus/ce_guided_single_inv_sol.cpp b/src/theory/quantifiers/sygus/ce_guided_single_inv_sol.cpp
index d6d854c44..be62d2e09 100644
--- a/src/theory/quantifiers/sygus/ce_guided_single_inv_sol.cpp
+++ b/src/theory/quantifiers/sygus/ce_guided_single_inv_sol.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,10 +14,10 @@
**/
#include "theory/quantifiers/sygus/ce_guided_single_inv_sol.h"
-#include "expr/datatype.h"
#include "expr/dtype.h"
#include "expr/node_algorithm.h"
#include "options/quantifiers_options.h"
+#include "smt/command.h"
#include "theory/arith/arith_msum.h"
#include "theory/quantifiers/ematching/trigger.h"
#include "theory/quantifiers/first_order_model.h"
diff --git a/src/theory/quantifiers/sygus/ce_guided_single_inv_sol.h b/src/theory/quantifiers/sygus/ce_guided_single_inv_sol.h
index 847fd2d9b..6a2b23503 100644
--- a/src/theory/quantifiers/sygus/ce_guided_single_inv_sol.h
+++ b/src/theory/quantifiers/sygus/ce_guided_single_inv_sol.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,6 +21,7 @@
#include <vector>
#include "context/cdhashmap.h"
+#include "expr/dtype.h"
#include "expr/node.h"
namespace CVC4 {
diff --git a/src/theory/quantifiers/sygus/cegis.cpp b/src/theory/quantifiers/sygus/cegis.cpp
index cf9611eb2..9470b4e49 100644
--- a/src/theory/quantifiers/sygus/cegis.cpp
+++ b/src/theory/quantifiers/sygus/cegis.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/cegis.h b/src/theory/quantifiers/sygus/cegis.h
index d976a5c4b..c466afe0f 100644
--- a/src/theory/quantifiers/sygus/cegis.h
+++ b/src/theory/quantifiers/sygus/cegis.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/cegis_core_connective.cpp b/src/theory/quantifiers/sygus/cegis_core_connective.cpp
index a7f32155c..4549a0945 100644
--- a/src/theory/quantifiers/sygus/cegis_core_connective.cpp
+++ b/src/theory/quantifiers/sygus/cegis_core_connective.cpp
@@ -2,10 +2,10 @@
/*! \file cegis_core_connective.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Mathias Preiner
+ ** Andrew Reynolds, Mathias Preiner, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,7 +14,6 @@
#include "theory/quantifiers/sygus/cegis_core_connective.h"
-#include "expr/datatype.h"
#include "options/base_options.h"
#include "printer/printer.h"
#include "proof/unsat_core.h"
@@ -22,6 +21,7 @@
#include "smt/smt_engine_scope.h"
#include "theory/datatypes/theory_datatypes_utils.h"
#include "theory/quantifiers/sygus/ce_guided_single_inv.h"
+#include "theory/quantifiers/sygus/transition_inference.h"
#include "theory/quantifiers/term_util.h"
#include "theory/quantifiers_engine.h"
#include "theory/smt_engine_subsolver.h"
@@ -597,7 +597,7 @@ void CegisCoreConnective::getModel(SmtEngine& smt,
{
for (const Node& v : d_vars)
{
- Node mv = Node::fromExpr(smt.getValue(v.toExpr()));
+ Node mv = smt.getValue(v);
Trace("sygus-ccore-model") << v << " -> " << mv << " ";
vals.push_back(mv);
}
@@ -612,7 +612,7 @@ bool CegisCoreConnective::getUnsatCore(
bool hasQuery = false;
for (UnsatCore::const_iterator i = uc.begin(); i != uc.end(); ++i)
{
- Node uassert = Node::fromExpr(*i);
+ Node uassert = *i;
Trace("sygus-ccore-debug") << " uc " << uassert << std::endl;
if (queryAsserts.find(uassert) != queryAsserts.end())
{
diff --git a/src/theory/quantifiers/sygus/cegis_core_connective.h b/src/theory/quantifiers/sygus/cegis_core_connective.h
index c1b4c31a2..d70624f0a 100644
--- a/src/theory/quantifiers/sygus/cegis_core_connective.h
+++ b/src/theory/quantifiers/sygus/cegis_core_connective.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/cegis_unif.cpp b/src/theory/quantifiers/sygus/cegis_unif.cpp
index 582fa067d..9c98d6608 100644
--- a/src/theory/quantifiers/sygus/cegis_unif.cpp
+++ b/src/theory/quantifiers/sygus/cegis_unif.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -465,8 +465,8 @@ Node CegisUnifEnumDecisionStrategy::mkLiteral(unsigned n)
std::string veName("_virtual_enum_grammar");
SygusDatatype sdt(veName);
TypeNode u = nm->mkSort(veName, ExprManager::SORT_FLAG_PLACEHOLDER);
- std::set<Type> unresolvedTypes;
- unresolvedTypes.insert(u.toType());
+ std::set<TypeNode> unresolvedTypes;
+ unresolvedTypes.insert(u);
std::vector<TypeNode> cargsEmpty;
Node cr = nm->mkConst(Rational(1));
sdt.addConstructor(cr, "1", cargsEmpty);
@@ -475,15 +475,11 @@ Node CegisUnifEnumDecisionStrategy::mkLiteral(unsigned n)
cargsPlus.push_back(u);
sdt.addConstructor(PLUS, cargsPlus);
sdt.initializeDatatype(nm->integerType(), bvl, false, false);
- std::vector<Datatype> datatypes;
+ std::vector<DType> datatypes;
datatypes.push_back(sdt.getDatatype());
- std::vector<DatatypeType> dtypes =
- nm->toExprManager()->mkMutualDatatypeTypes(
- datatypes,
- unresolvedTypes,
- ExprManager::DATATYPE_FLAG_PLACEHOLDER);
- TypeNode vtn = TypeNode::fromType(dtypes[0]);
- d_virtual_enum = nm->mkSkolem("_ve", vtn);
+ std::vector<TypeNode> dtypes = nm->mkMutualDatatypeTypes(
+ datatypes, unresolvedTypes, NodeManager::DATATYPE_FLAG_PLACEHOLDER);
+ d_virtual_enum = nm->mkSkolem("_ve", dtypes[0]);
d_tds->registerEnumerator(
d_virtual_enum, Node::null(), d_parent, ROLE_ENUM_CONSTRAINED);
}
@@ -561,7 +557,7 @@ void CegisUnifEnumDecisionStrategy::initialize(
}
// register this strategy
- d_qe->getTheoryEngine()->getDecisionManager()->registerStrategy(
+ d_qe->getDecisionManager()->registerStrategy(
DecisionManager::STRAT_QUANT_CEGIS_UNIF_NUM_ENUMS, this);
// create single condition enumerator for each decision tree strategy
diff --git a/src/theory/quantifiers/sygus/cegis_unif.h b/src/theory/quantifiers/sygus/cegis_unif.h
index c3da1b481..aca85a691 100644
--- a/src/theory/quantifiers/sygus/cegis_unif.h
+++ b/src/theory/quantifiers/sygus/cegis_unif.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/enum_stream_substitution.cpp b/src/theory/quantifiers/sygus/enum_stream_substitution.cpp
index 76223b9df..360476399 100644
--- a/src/theory/quantifiers/sygus/enum_stream_substitution.cpp
+++ b/src/theory/quantifiers/sygus/enum_stream_substitution.cpp
@@ -5,7 +5,7 @@
** Haniel Barbosa, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/enum_stream_substitution.h b/src/theory/quantifiers/sygus/enum_stream_substitution.h
index b8619715d..d39eed7d5 100644
--- a/src/theory/quantifiers/sygus/enum_stream_substitution.h
+++ b/src/theory/quantifiers/sygus/enum_stream_substitution.h
@@ -5,7 +5,7 @@
** Haniel Barbosa, Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/example_eval_cache.cpp b/src/theory/quantifiers/sygus/example_eval_cache.cpp
index c3a0604c7..19a334ec1 100644
--- a/src/theory/quantifiers/sygus/example_eval_cache.cpp
+++ b/src/theory/quantifiers/sygus/example_eval_cache.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/example_eval_cache.h b/src/theory/quantifiers/sygus/example_eval_cache.h
index 886ff6bf2..c7a67cc18 100644
--- a/src/theory/quantifiers/sygus/example_eval_cache.h
+++ b/src/theory/quantifiers/sygus/example_eval_cache.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/example_infer.cpp b/src/theory/quantifiers/sygus/example_infer.cpp
index 70bac99ce..eae5a79e8 100644
--- a/src/theory/quantifiers/sygus/example_infer.cpp
+++ b/src/theory/quantifiers/sygus/example_infer.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/example_infer.h b/src/theory/quantifiers/sygus/example_infer.h
index e413d49c6..79a70b15e 100644
--- a/src/theory/quantifiers/sygus/example_infer.h
+++ b/src/theory/quantifiers/sygus/example_infer.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/example_min_eval.cpp b/src/theory/quantifiers/sygus/example_min_eval.cpp
index 92cd0f3ca..91d11ed8d 100644
--- a/src/theory/quantifiers/sygus/example_min_eval.cpp
+++ b/src/theory/quantifiers/sygus/example_min_eval.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/example_min_eval.h b/src/theory/quantifiers/sygus/example_min_eval.h
index 966d4a180..24964c198 100644
--- a/src/theory/quantifiers/sygus/example_min_eval.h
+++ b/src/theory/quantifiers/sygus/example_min_eval.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_abduct.cpp b/src/theory/quantifiers/sygus/sygus_abduct.cpp
index ee37d7b4b..fa369b467 100644
--- a/src/theory/quantifiers/sygus/sygus_abduct.cpp
+++ b/src/theory/quantifiers/sygus/sygus_abduct.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -15,7 +15,6 @@
#include "theory/quantifiers/sygus/sygus_abduct.h"
-#include "expr/datatype.h"
#include "expr/dtype.h"
#include "expr/node_algorithm.h"
#include "expr/sygus_datatype.h"
diff --git a/src/theory/quantifiers/sygus/sygus_abduct.h b/src/theory/quantifiers/sygus/sygus_abduct.h
index 046bad946..9fc8e703c 100644
--- a/src/theory/quantifiers/sygus/sygus_abduct.h
+++ b/src/theory/quantifiers/sygus/sygus_abduct.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_enumerator.cpp b/src/theory/quantifiers/sygus/sygus_enumerator.cpp
index 86bf53b23..e0159049b 100644
--- a/src/theory/quantifiers/sygus/sygus_enumerator.cpp
+++ b/src/theory/quantifiers/sygus/sygus_enumerator.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,6 +14,7 @@
#include "theory/quantifiers/sygus/sygus_enumerator.h"
+#include "expr/node_algorithm.h"
#include "options/datatypes_options.h"
#include "options/quantifiers_options.h"
#include "theory/datatypes/theory_datatypes_utils.h"
@@ -27,8 +28,14 @@ namespace quantifiers {
SygusEnumerator::SygusEnumerator(TermDbSygus* tds,
SynthConjecture* p,
- SygusStatistics& s)
- : d_tds(tds), d_parent(p), d_stats(s), d_tlEnum(nullptr), d_abortSize(-1)
+ SygusStatistics& s,
+ bool enumShapes)
+ : d_tds(tds),
+ d_parent(p),
+ d_stats(s),
+ d_enumShapes(enumShapes),
+ d_tlEnum(nullptr),
+ d_abortSize(-1)
{
}
@@ -142,6 +149,8 @@ Node SygusEnumerator::getCurrent()
return ret;
}
+bool SygusEnumerator::isEnumShapes() const { return d_enumShapes; }
+
SygusEnumerator::TermCache::TermCache()
: d_tds(nullptr),
d_eec(nullptr),
@@ -595,6 +604,8 @@ SygusEnumerator::TermEnum* SygusEnumerator::getMasterEnumForType(TypeNode tn)
SygusEnumerator::TermEnumMaster::TermEnumMaster()
: TermEnum(),
+ d_enumShapes(false),
+ d_enumShapesInit(false),
d_isIncrementing(false),
d_currTermSet(false),
d_consClassNum(0),
@@ -609,6 +620,7 @@ bool SygusEnumerator::TermEnumMaster::initialize(SygusEnumerator* se,
TypeNode tn)
{
Trace("sygus-enum-debug") << "master(" << tn << "): init...\n";
+ d_tds = se->d_tds;
d_se = se;
d_tn = tn;
@@ -617,6 +629,8 @@ bool SygusEnumerator::TermEnumMaster::initialize(SygusEnumerator* se,
d_consClassNum = 0;
d_currChildSize = 0;
d_ccCons.clear();
+ d_enumShapes = se->isEnumShapes();
+ d_enumShapesInit = false;
d_isIncrementing = false;
d_currTermSet = false;
bool ret = increment();
@@ -651,6 +665,11 @@ Node SygusEnumerator::TermEnumMaster::getCurrent()
}
children.push_back(cc);
}
+ if (d_enumShapes)
+ {
+ // ensure all variables are unique
+ childrenToShape(children);
+ }
d_currTerm = NodeManager::currentNM()->mkNode(APPLY_CONSTRUCTOR, children);
return d_currTerm;
}
@@ -693,6 +712,17 @@ bool SygusEnumerator::TermEnumMaster::incrementInternal()
unsigned ncc = tc.getLastConstructorClassIndexForWeight(d_currSize);
Trace("sygus-enum-debug2") << "Last constructor class " << d_currSize << ": "
<< ncc << std::endl;
+ // If we are enumerating shapes, the first enumerated term is a free variable.
+ if (d_enumShapes && !d_enumShapesInit)
+ {
+ Node fv = d_tds->getFreeVar(d_tn, 0);
+ d_enumShapesInit = true;
+ d_currTermSet = true;
+ d_currTerm = fv;
+ // must add to term cache
+ tc.addTerm(fv);
+ return true;
+ }
// have we initialized the current constructor class?
while (d_ccCons.empty() && d_consClassNum < ncc)
@@ -995,6 +1025,117 @@ bool SygusEnumerator::TermEnumMaster::initializeChild(unsigned i,
return true;
}
+void SygusEnumerator::TermEnumMaster::childrenToShape(
+ std::vector<Node>& children)
+{
+ if (children.size() <= 2)
+ {
+ // don't need to convert constants and unary applications
+ return;
+ }
+ std::map<TypeNode, int> vcounter;
+ // Buffered child, so that we only compute vcounter if there are more than
+ // one children with free variables, since otherwise there is no change.
+ // For example, if we are given { C, (+ x1 x2), 1 }, we buffer child (+ x1 x2)
+ // noting that it has free variables. We proceed with processing the remaining
+ // children, and note that no other child contains free variables, and hence
+ // no change is necessary (since by construction, all children have the
+ // property of having unique variable subterms). On the other hand if the
+ // last child above was x1, then this would trigger us to convert (+ x1 x2)
+ // while computing vcounter, and subsequently update x1 to x3 to obtain
+ // { C, (+ x1 x2), x3 }.
+ // Have we set the buffer child index
+ bool bufferChildSet = false;
+ // Have we processed the buffer child index
+ bool bufferChildProcessed = false;
+ // The buffer child index
+ size_t bufferChild = 0;
+ for (size_t i = 1, nchildren = children.size(); i < nchildren; i++)
+ {
+ if (!expr::hasBoundVar(children[i]))
+ {
+ // don't need to care about expressions with no bound variables
+ continue;
+ }
+ else if (!bufferChildSet)
+ {
+ bufferChild = i;
+ bufferChildSet = true;
+ continue;
+ }
+ else if (!bufferChildProcessed)
+ {
+ // process the buffer child
+ children[bufferChild] = convertShape(children[bufferChild], vcounter);
+ bufferChildProcessed = true;
+ }
+ children[i] = convertShape(children[i], vcounter);
+ }
+}
+
+Node SygusEnumerator::TermEnumMaster::convertShape(
+ Node n, std::map<TypeNode, int>& vcounter)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ std::unordered_map<TNode, Node, TNodeHashFunction> visited;
+ std::unordered_map<TNode, Node, TNodeHashFunction>::iterator it;
+ std::vector<TNode> visit;
+ TNode cur;
+ visit.push_back(n);
+ do
+ {
+ cur = visit.back();
+ visit.pop_back();
+ it = visited.find(cur);
+
+ if (it == visited.end())
+ {
+ if (cur.isVar())
+ {
+ // do the conversion
+ visited[cur] = d_tds->getFreeVarInc(cur.getType(), vcounter);
+ }
+ else if (!expr::hasBoundVar(cur))
+ {
+ // no bound variables, no change
+ visited[cur] = cur;
+ }
+ else
+ {
+ visited[cur] = Node::null();
+ visit.push_back(cur);
+ visit.insert(visit.end(), cur.begin(), cur.end());
+ }
+ }
+ else if (it->second.isNull())
+ {
+ Node ret = cur;
+ bool childChanged = false;
+ std::vector<Node> children;
+ if (cur.getMetaKind() == metakind::PARAMETERIZED)
+ {
+ children.push_back(cur.getOperator());
+ }
+ for (const Node& cn : cur)
+ {
+ it = visited.find(cn);
+ Assert(it != visited.end());
+ Assert(!it->second.isNull());
+ childChanged = childChanged || cn != it->second;
+ children.push_back(it->second);
+ }
+ if (childChanged)
+ {
+ ret = nm->mkNode(cur.getKind(), children);
+ }
+ visited[cur] = ret;
+ }
+ } while (!visit.empty());
+ Assert(visited.find(n) != visited.end());
+ Assert(!visited.find(n)->second.isNull());
+ return visited[n];
+}
+
SygusEnumerator::TermEnumMasterInterp::TermEnumMasterInterp(TypeNode tn)
: TermEnum(), d_te(tn), d_currNumConsts(0), d_nextIndexEnd(0)
{
diff --git a/src/theory/quantifiers/sygus/sygus_enumerator.h b/src/theory/quantifiers/sygus/sygus_enumerator.h
index 4bf4fb332..05105c27d 100644
--- a/src/theory/quantifiers/sygus/sygus_enumerator.h
+++ b/src/theory/quantifiers/sygus/sygus_enumerator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -40,11 +40,25 @@ class SygusPbe;
* builtin terms (TermDb::sygusToBuiltin) can be shown to be equivalent via
* rewriting. It enumerates terms in order of sygus term size
* (TermDb::getSygusTermSize).
+ *
+ * It also can be configured to enumerates sygus terms with free variables,
+ * (as opposed to variables bound in the formal arguments list of the
+ * function-to-synthesize), where each free variable appears in exactly one
+ * subterm. For grammar:
+ * S -> 0 | 1 | x | S+S
+ * this enumerator will generate the stream:
+ * z1, C_0, C_1, C_x, C_+(z1, z2), C_+(z1, C_1), C_+(C_1, C_1) ...
+ * and so on, where z1 and z2 are variables of sygus datatype type S. We call
+ * these "shapes". This feature can be enabled by setting enumShapes to true
+ * in the constructor below.
*/
class SygusEnumerator : public EnumValGenerator
{
public:
- SygusEnumerator(TermDbSygus* tds, SynthConjecture* p, SygusStatistics& s);
+ SygusEnumerator(TermDbSygus* tds,
+ SynthConjecture* p,
+ SygusStatistics& s,
+ bool enumShapes = false);
~SygusEnumerator() {}
/** initialize this class with enumerator e */
void initialize(Node e) override;
@@ -54,6 +68,8 @@ class SygusEnumerator : public EnumValGenerator
bool increment() override;
/** Get the next concrete value generated by this class. */
Node getCurrent() override;
+ /** Are we enumerating shapes? */
+ bool isEnumShapes() const;
private:
/** pointer to term database sygus */
@@ -62,6 +78,8 @@ class SygusEnumerator : public EnumValGenerator
SynthConjecture* d_parent;
/** reference to the statistics of parent */
SygusStatistics& d_stats;
+ /** Whether we are enumerating shapes */
+ bool d_enumShapes;
/** Term cache
*
* This stores a list of terms for a given sygus type. The key features of
@@ -340,6 +358,12 @@ class SygusEnumerator : public EnumValGenerator
bool increment() override;
private:
+ /** pointer to term database sygus */
+ TermDbSygus* d_tds;
+ /** are we enumerating shapes? */
+ bool d_enumShapes;
+ /** have we initialized the shape enumeration? */
+ bool d_enumShapesInit;
/** are we currently inside a increment() call? */
bool d_isIncrementing;
/** cache for getCurrent() */
@@ -393,6 +417,19 @@ class SygusEnumerator : public EnumValGenerator
bool initializeChild(unsigned i, unsigned sizeMin);
/** increment internal, helper for increment() */
bool incrementInternal();
+ /**
+ * The vector children is a set of terms given to
+ * NodeManager::mkNode(APPLY_CONSTRUCTOR, children)
+ * This converts children so that all sygus free variables are unique. Note
+ * that the first child is a constructor operator and should be skipped.
+ */
+ void childrenToShape(std::vector<Node>& children);
+ /**
+ * Convert n into shape based on the variable counters. For example if
+ * vcounter is { Int -> 7 }, then (+ x1 x2) is converted to (+ x7 x8) and
+ * vouncter is updated to { Int -> 9 }.
+ */
+ Node convertShape(Node n, std::map<TypeNode, int>& vcounter);
};
/** an interpreted value enumerator
*
diff --git a/src/theory/quantifiers/sygus/sygus_enumerator_basic.cpp b/src/theory/quantifiers/sygus/sygus_enumerator_basic.cpp
index 84337d3b5..d4edc7c45 100644
--- a/src/theory/quantifiers/sygus/sygus_enumerator_basic.cpp
+++ b/src/theory/quantifiers/sygus/sygus_enumerator_basic.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_enumerator_basic.h b/src/theory/quantifiers/sygus/sygus_enumerator_basic.h
index 2931eb51f..ccf99f265 100644
--- a/src/theory/quantifiers/sygus/sygus_enumerator_basic.h
+++ b/src/theory/quantifiers/sygus/sygus_enumerator_basic.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_eval_unfold.cpp b/src/theory/quantifiers/sygus/sygus_eval_unfold.cpp
index 6d147fe46..9f3ed4f4f 100644
--- a/src/theory/quantifiers/sygus/sygus_eval_unfold.cpp
+++ b/src/theory/quantifiers/sygus/sygus_eval_unfold.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_eval_unfold.h b/src/theory/quantifiers/sygus/sygus_eval_unfold.h
index 8970ce153..cf22938a4 100644
--- a/src/theory/quantifiers/sygus/sygus_eval_unfold.h
+++ b/src/theory/quantifiers/sygus/sygus_eval_unfold.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_explain.cpp b/src/theory/quantifiers/sygus/sygus_explain.cpp
index 85f6f3428..0f9d2ccd1 100644
--- a/src/theory/quantifiers/sygus/sygus_explain.cpp
+++ b/src/theory/quantifiers/sygus/sygus_explain.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_explain.h b/src/theory/quantifiers/sygus/sygus_explain.h
index c4cf37833..a3b8f4d29 100644
--- a/src/theory/quantifiers/sygus/sygus_explain.h
+++ b/src/theory/quantifiers/sygus/sygus_explain.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Fabian Wolff
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_grammar_cons.cpp b/src/theory/quantifiers/sygus/sygus_grammar_cons.cpp
index bd5f7ae50..79fc1a36e 100644
--- a/src/theory/quantifiers/sygus/sygus_grammar_cons.cpp
+++ b/src/theory/quantifiers/sygus/sygus_grammar_cons.cpp
@@ -2,10 +2,10 @@
/*! \file sygus_grammar_cons.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Haniel Barbosa, Mathias Preiner
+ ** Andrew Reynolds, Haniel Barbosa, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,7 +16,6 @@
#include <stack>
-#include "expr/datatype.h"
#include "options/quantifiers_options.h"
#include "theory/bv/theory_bv_utils.h"
#include "theory/datatypes/sygus_datatype_utils.h"
@@ -378,10 +377,11 @@ Node CegGrammarConstructor::convertToEmbedding(Node n)
return visited[n];
}
-
-TypeNode CegGrammarConstructor::mkUnresolvedType(const std::string& name, std::set<Type>& unres) {
+TypeNode CegGrammarConstructor::mkUnresolvedType(const std::string& name,
+ std::set<TypeNode>& unres)
+{
TypeNode unresolved = NodeManager::currentNM()->mkSort(name, ExprManager::SORT_FLAG_PLACEHOLDER);
- unres.insert( unresolved.toType() );
+ unres.insert(unresolved);
return unresolved;
}
@@ -421,7 +421,33 @@ void CegGrammarConstructor::mkSygusConstantsForType(TypeNode type,
Node c = type.mkGroundTerm();
ops.push_back(c);
}
- // TODO #1178 : add other missing types
+ else if (type.isRoundingMode())
+ {
+ ops.push_back(nm->mkConst(RoundingMode::ROUND_NEAREST_TIES_TO_AWAY));
+ ops.push_back(nm->mkConst(RoundingMode::ROUND_NEAREST_TIES_TO_EVEN));
+ ops.push_back(nm->mkConst(RoundingMode::ROUND_TOWARD_NEGATIVE));
+ ops.push_back(nm->mkConst(RoundingMode::ROUND_TOWARD_POSITIVE));
+ ops.push_back(nm->mkConst(RoundingMode::ROUND_TOWARD_ZERO));
+ }
+ else if (type.isFloatingPoint())
+ {
+ FloatingPointType fp_type = static_cast<FloatingPointType>(type.toType());
+ FloatingPointSize fp_size(FloatingPointType(fp_type).getExponentSize(),
+ FloatingPointType(fp_type).getSignificandSize());
+ ops.push_back(nm->mkConst(FloatingPoint::makeNaN(fp_size)));
+ ops.push_back(nm->mkConst(FloatingPoint::makeInf(fp_size, true)));
+ ops.push_back(nm->mkConst(FloatingPoint::makeInf(fp_size, false)));
+ ops.push_back(nm->mkConst(FloatingPoint::makeZero(fp_size, true)));
+ ops.push_back(nm->mkConst(FloatingPoint::makeZero(fp_size, false)));
+ ops.push_back(nm->mkConst(FloatingPoint::makeMinSubnormal(fp_size, true)));
+ ops.push_back(nm->mkConst(FloatingPoint::makeMinSubnormal(fp_size, false)));
+ ops.push_back(nm->mkConst(FloatingPoint::makeMaxSubnormal(fp_size, true)));
+ ops.push_back(nm->mkConst(FloatingPoint::makeMaxSubnormal(fp_size, false)));
+ ops.push_back(nm->mkConst(FloatingPoint::makeMinNormal(fp_size, true)));
+ ops.push_back(nm->mkConst(FloatingPoint::makeMinNormal(fp_size, false)));
+ ops.push_back(nm->mkConst(FloatingPoint::makeMaxNormal(fp_size, true)));
+ ops.push_back(nm->mkConst(FloatingPoint::makeMaxNormal(fp_size, false)));
+ }
}
void CegGrammarConstructor::collectSygusGrammarTypesFor(
@@ -472,6 +498,12 @@ void CegGrammarConstructor::collectSygusGrammarTypesFor(
}
collectSygusGrammarTypesFor(range.getRangeType(), types);
}
+ else if (range.isFloatingPoint())
+ {
+ // FP also includes RoundingMode type
+ TypeNode rmType = NodeManager::currentNM()->roundingModeType();
+ collectSygusGrammarTypesFor(rmType, types);
+ }
}
}
}
@@ -529,7 +561,7 @@ void CegGrammarConstructor::mkSygusDefaultGrammar(
include_cons,
std::unordered_set<Node, NodeHashFunction>& term_irrelevant,
std::vector<SygusDatatypeGenerator>& sdts,
- std::set<Type>& unres)
+ std::set<TypeNode>& unres)
{
NodeManager* nm = NodeManager::currentNM();
Trace("sygus-grammar-def") << "Construct default grammar for " << fun << " "
@@ -773,7 +805,7 @@ void CegGrammarConstructor::mkSygusDefaultGrammar(
}
else if (types[i].isBitVector())
{
- // unary apps
+ // unary ops
std::vector<Kind> un_kinds = {BITVECTOR_NOT, BITVECTOR_NEG};
std::vector<TypeNode> cargsUnary;
cargsUnary.push_back(unres_t);
@@ -782,7 +814,7 @@ void CegGrammarConstructor::mkSygusDefaultGrammar(
Trace("sygus-grammar-def") << "...add for " << kind << std::endl;
sdts[i].addConstructor(kind, cargsUnary);
}
- // binary apps
+ // binary ops
std::vector<Kind> bin_kinds = {BITVECTOR_AND,
BITVECTOR_OR,
BITVECTOR_XOR,
@@ -805,6 +837,61 @@ void CegGrammarConstructor::mkSygusDefaultGrammar(
sdts[i].addConstructor(kind, cargsBinary);
}
}
+ else if (types[i].isFloatingPoint())
+ {
+ // unary ops
+ std::vector<Kind> unary_kinds = {
+ FLOATINGPOINT_ABS,
+ FLOATINGPOINT_NEG,
+ };
+ std::vector<TypeNode> cargs = {unres_t};
+ for (const Kind kind : unary_kinds)
+ {
+ Trace("sygus-grammar-def") << "...add for " << kind << std::endl;
+ sdts[i].addConstructor(kind, cargs);
+ }
+ // binary ops
+ {
+ const Kind kind = FLOATINGPOINT_REM;
+ cargs.push_back(unres_t);
+ Trace("sygus-grammar-def") << "...add for " << kind << std::endl;
+ sdts[i].addConstructor(kind, cargs);
+ }
+ // binary ops with RM
+ std::vector<Kind> binary_rm_kinds = {
+ FLOATINGPOINT_SQRT,
+ FLOATINGPOINT_RTI,
+ };
+ TypeNode rmType = nm->roundingModeType();
+ Assert(std::find(types.begin(), types.end(), rmType) != types.end());
+ TypeNode unres_rm_t = type_to_unres[rmType];
+ std::vector<TypeNode> cargs_rm = {unres_rm_t, unres_t};
+ for (const Kind kind : binary_rm_kinds)
+ {
+ Trace("sygus-grammar-def") << "...add for " << kind << std::endl;
+ sdts[i].addConstructor(kind, cargs_rm);
+ }
+ // ternary ops with RM
+ std::vector<Kind> ternary_rm_kinds = {
+ FLOATINGPOINT_PLUS,
+ FLOATINGPOINT_SUB,
+ FLOATINGPOINT_MULT,
+ FLOATINGPOINT_DIV,
+ };
+ cargs_rm.push_back(unres_t);
+ for (const Kind kind : ternary_rm_kinds)
+ {
+ Trace("sygus-grammar-def") << "...add for " << kind << std::endl;
+ sdts[i].addConstructor(kind, cargs_rm);
+ }
+ // quaternary ops
+ {
+ cargs_rm.push_back(unres_t);
+ const Kind kind = FLOATINGPOINT_FMA;
+ Trace("sygus-grammar-def") << "...add for " << kind << std::endl;
+ sdts[i].addConstructor(kind, cargs_rm);
+ }
+ }
else if (types[i].isStringLike())
{
// concatenation
@@ -879,7 +966,13 @@ void CegGrammarConstructor::mkSygusDefaultGrammar(
Trace("sygus-grammar-def") << "...add for singleton" << std::endl;
std::vector<TypeNode> cargsSingleton;
cargsSingleton.push_back(unresElemType);
- sdts[i].addConstructor(SINGLETON, cargsSingleton);
+
+ // lambda x . (singleton (singleton_op T) x) where T = x.getType()
+ Node x = nm->mkBoundVar(etype);
+ Node vars = nm->mkNode(BOUND_VAR_LIST, x);
+ Node singleton = nm->mkSingleton(etype, x);
+ Node lambda = nm->mkNode(LAMBDA,vars, singleton);
+ sdts[i].addConstructor(lambda, "singleton", cargsSingleton);
// add for union, difference, intersection
std::vector<Kind> bin_kinds = {UNION, INTERSECTION, SETMINUS};
@@ -931,7 +1024,8 @@ void CegGrammarConstructor::mkSygusDefaultGrammar(
sdts[i].addConstructor(cop, dt[l].getName(), cargsCons);
}
}
- else if (types[i].isSort() || types[i].isFunction())
+ else if (types[i].isSort() || types[i].isFunction()
+ || types[i].isRoundingMode())
{
// do nothing
}
@@ -944,13 +1038,10 @@ void CegGrammarConstructor::mkSygusDefaultGrammar(
if (sdts[i].d_sdt.getNumConstructors() == 0)
{
- // if there are no constructors yet by this point, we cannot make
- // datatype, which can happen e.g. for unimplemented types
- // that have no variables in the argument list of the
- // function-to-synthesize.
- std::stringstream ss;
- ss << "Cannot make default grammar for " << types[i];
- throw LogicException(ss.str());
+ // if there are not constructors yet by this point, which can happen,
+ // e.g. for unimplemented types that have no variables in the argument
+ // list of the function-to-synthesize, create a fresh ground term
+ sdts[i].addConstructor(types[i].mkGroundTerm(), "", {});
}
// always add ITE
@@ -1294,6 +1385,28 @@ void CegGrammarConstructor::mkSygusDefaultGrammar(
sdtBool.addConstructor(kind, cargs);
}
}
+ else if (types[i].isFloatingPoint())
+ {
+ Trace("sygus-grammar-def") << "...add FP predicates" << std::endl;
+ std::vector<Kind> fp_unary_predicates = {FLOATINGPOINT_ISN,
+ FLOATINGPOINT_ISSN,
+ FLOATINGPOINT_ISZ,
+ FLOATINGPOINT_ISINF,
+ FLOATINGPOINT_ISNAN,
+ FLOATINGPOINT_ISNEG,
+ FLOATINGPOINT_ISPOS};
+ for (const Kind kind : fp_unary_predicates)
+ {
+ sdtBool.addConstructor(kind, cargs);
+ }
+ std::vector<Kind> fp_binary_predicates = {FLOATINGPOINT_LEQ,
+ FLOATINGPOINT_LT};
+ cargs.push_back(unres_types[iuse]);
+ for (const Kind kind : fp_binary_predicates)
+ {
+ sdtBool.addConstructor(kind, cargs);
+ }
+ }
else if (types[i].isDatatype())
{
//add for testers
@@ -1389,7 +1502,7 @@ TypeNode CegGrammarConstructor::mkSygusDefaultType(
{
Trace("sygus-grammar-def") << " ...using " << it->second.size() << " extra constants for " << it->first << std::endl;
}
- std::set<Type> unres;
+ std::set<TypeNode> unres;
std::vector<SygusDatatypeGenerator> sdts;
mkSygusDefaultGrammar(range,
bvl,
@@ -1401,19 +1514,18 @@ TypeNode CegGrammarConstructor::mkSygusDefaultType(
sdts,
unres);
// extract the datatypes from the sygus datatype generator objects
- std::vector<Datatype> datatypes;
+ std::vector<DType> datatypes;
for (unsigned i = 0, ndts = sdts.size(); i < ndts; i++)
{
datatypes.push_back(sdts[i].d_sdt.getDatatype());
}
Trace("sygus-grammar-def") << "...made " << datatypes.size() << " datatypes, now make mutual datatype types..." << std::endl;
Assert(!datatypes.empty());
- std::vector<DatatypeType> types =
- NodeManager::currentNM()->toExprManager()->mkMutualDatatypeTypes(
- datatypes, unres, ExprManager::DATATYPE_FLAG_PLACEHOLDER);
+ std::vector<TypeNode> types = NodeManager::currentNM()->mkMutualDatatypeTypes(
+ datatypes, unres, NodeManager::DATATYPE_FLAG_PLACEHOLDER);
Trace("sygus-grammar-def") << "...finished" << std::endl;
Assert(types.size() == datatypes.size());
- return TypeNode::fromType( types[0] );
+ return types[0];
}
TypeNode CegGrammarConstructor::mkSygusTemplateTypeRec( Node templ, Node templ_arg, TypeNode templ_arg_sygus_type, Node bvl,
@@ -1423,7 +1535,7 @@ TypeNode CegGrammarConstructor::mkSygusTemplateTypeRec( Node templ, Node templ_a
return templ_arg_sygus_type;
}else{
tcount++;
- std::set<Type> unres;
+ std::set<TypeNode> unres;
std::vector<SygusDatatype> sdts;
std::stringstream ssd;
ssd << fun << "_templ_" << tcount;
@@ -1450,16 +1562,16 @@ TypeNode CegGrammarConstructor::mkSygusTemplateTypeRec( Node templ, Node templ_a
sdts.back().addConstructor(op, ssdc.str(), argTypes);
sdts.back().initializeDatatype(templ.getType(), bvl, true, true);
// extract the datatypes from the sygus datatype objects
- std::vector<Datatype> datatypes;
+ std::vector<DType> datatypes;
for (unsigned i = 0, ndts = sdts.size(); i < ndts; i++)
{
datatypes.push_back(sdts[i].getDatatype());
}
- std::vector<DatatypeType> types =
- NodeManager::currentNM()->toExprManager()->mkMutualDatatypeTypes(
- datatypes, unres, ExprManager::DATATYPE_FLAG_PLACEHOLDER);
+ std::vector<TypeNode> types =
+ NodeManager::currentNM()->mkMutualDatatypeTypes(
+ datatypes, unres, NodeManager::DATATYPE_FLAG_PLACEHOLDER);
Assert(types.size() == 1);
- return TypeNode::fromType( types[0] );
+ return types[0];
}
}
diff --git a/src/theory/quantifiers/sygus/sygus_grammar_cons.h b/src/theory/quantifiers/sygus/sygus_grammar_cons.h
index fd7f84484..872bed060 100644
--- a/src/theory/quantifiers/sygus/sygus_grammar_cons.h
+++ b/src/theory/quantifiers/sygus/sygus_grammar_cons.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Yoni Zohar, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -54,9 +54,10 @@ namespace quantifiers {
class SynthConjecture;
-/** utility for constructing datatypes that correspond to syntactic restrictions,
-* and applying the deep embedding from Section 4 of Reynolds et al CAV 2015.
-*/
+/**
+ * Utility for constructing datatypes that correspond to syntactic restrictions,
+ * and applying the deep embedding from Section 4 of Reynolds et al CAV 2015.
+ */
class CegGrammarConstructor
{
public:
@@ -88,9 +89,12 @@ public:
const std::map<Node, Node>& templates,
const std::map<Node, Node>& templates_arg,
const std::vector<Node>& ebvl);
- /** is the syntax restricted? */
+
+ /** Is the syntax restricted? */
bool isSyntaxRestricted() { return d_is_syntax_restricted; }
- /** make the default sygus datatype type corresponding to builtin type range
+
+ /**
+ * Make the default sygus datatype type corresponding to builtin type range
* arguments:
* - bvl: the set of free variables to include in the grammar
* - fun: used for naming
@@ -113,7 +117,10 @@ public:
std::map<TypeNode, std::unordered_set<Node, NodeHashFunction>>&
include_cons,
std::unordered_set<Node, NodeHashFunction>& term_irrelevant);
- /** make the default sygus datatype type corresponding to builtin type range */
+
+ /**
+ * Make the default sygus datatype type corresponding to builtin type range.
+ */
static TypeNode mkSygusDefaultType(TypeNode range,
Node bvl,
const std::string& fun)
@@ -130,6 +137,7 @@ public:
include_cons,
term_irrelevant);
}
+
/** make the sygus datatype type that encodes the solution space (lambda
* templ_arg. templ[templ_arg]) where templ_arg
* has syntactic restrictions encoded by sygus type templ_arg_sygus_type
@@ -222,7 +230,8 @@ public:
};
// helper for mkSygusDefaultGrammar (makes unresolved type for mutually recursive datatype construction)
- static TypeNode mkUnresolvedType(const std::string& name, std::set<Type>& unres);
+ static TypeNode mkUnresolvedType(const std::string& name,
+ std::set<TypeNode>& unres);
// collect the list of types that depend on type range
static void collectSygusGrammarTypesFor(TypeNode range,
std::vector<TypeNode>& types);
@@ -243,7 +252,7 @@ public:
include_cons,
std::unordered_set<Node, NodeHashFunction>& term_irrelevant,
std::vector<SygusDatatypeGenerator>& sdts,
- std::set<Type>& unres);
+ std::set<TypeNode>& unres);
// helper function for mkSygusTemplateType
static TypeNode mkSygusTemplateTypeRec(Node templ,
diff --git a/src/theory/quantifiers/sygus/sygus_grammar_norm.cpp b/src/theory/quantifiers/sygus/sygus_grammar_norm.cpp
index 939256b2b..bbb16dfd5 100644
--- a/src/theory/quantifiers/sygus/sygus_grammar_norm.cpp
+++ b/src/theory/quantifiers/sygus/sygus_grammar_norm.cpp
@@ -5,7 +5,7 @@
** Haniel Barbosa, Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -15,7 +15,6 @@
#include "theory/quantifiers/sygus/sygus_grammar_norm.h"
-#include "expr/datatype.h"
#include "expr/node_manager_attributes.h" // for VarNameAttr
#include "options/quantifiers_options.h"
#include "smt/smt_engine.h"
@@ -122,7 +121,7 @@ void SygusGrammarNorm::TypeObject::initializeDatatype(
<< "...built datatype " << d_sdt.getDatatype() << " ";
/* Add to global accumulators */
sygus_norm->d_dt_all.push_back(d_sdt.getDatatype());
- sygus_norm->d_unres_t_all.insert(d_unres_tn.toType());
+ sygus_norm->d_unres_t_all.insert(d_unres_tn);
Trace("sygus-grammar-normalize") << "---------------------------------\n";
}
@@ -463,7 +462,6 @@ TypeNode SygusGrammarNorm::normalizeSygusRec(TypeNode tn,
// Remaining operators are rebuilt as they are.
// Notice that we must extract the Datatype here to get the (Expr-layer)
// sygus print callback.
- const Datatype& dtt = DatatypeType(tn.toType()).getDatatype();
for (unsigned i = 0, size = op_pos.size(); i < size; ++i)
{
unsigned oi = op_pos[i];
@@ -520,22 +518,21 @@ TypeNode SygusGrammarNorm::normalizeSygusType(TypeNode tn, Node sygus_vars)
Trace("sygus-grammar-normalize-build") << d_dt_all[i];
}
Trace("sygus-grammar-normalize-build") << " and unresolved types\n";
- for (const Type& unres_t : d_unres_t_all)
+ for (const TypeNode& unres_t : d_unres_t_all)
{
Trace("sygus-grammar-normalize-build") << unres_t << " ";
}
Trace("sygus-grammar-normalize-build") << "\n";
}
Assert(d_dt_all.size() == d_unres_t_all.size());
- std::vector<DatatypeType> types =
- NodeManager::currentNM()->toExprManager()->mkMutualDatatypeTypes(
- d_dt_all, d_unres_t_all, ExprManager::DATATYPE_FLAG_PLACEHOLDER);
+ std::vector<TypeNode> types = NodeManager::currentNM()->mkMutualDatatypeTypes(
+ d_dt_all, d_unres_t_all, NodeManager::DATATYPE_FLAG_PLACEHOLDER);
Assert(types.size() == d_dt_all.size());
/* Clear accumulators */
d_dt_all.clear();
d_unres_t_all.clear();
/* By construction the normalized type node will be the last one considered */
- return TypeNode::fromType(types.back());
+ return types.back();
}
} // namespace quantifiers
diff --git a/src/theory/quantifiers/sygus/sygus_grammar_norm.h b/src/theory/quantifiers/sygus/sygus_grammar_norm.h
index 5994d0e7d..acafeec3c 100644
--- a/src/theory/quantifiers/sygus/sygus_grammar_norm.h
+++ b/src/theory/quantifiers/sygus/sygus_grammar_norm.h
@@ -5,7 +5,7 @@
** Haniel Barbosa, Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -22,7 +22,6 @@
#include <string>
#include <vector>
-#include "expr/datatype.h"
#include "expr/node.h"
#include "expr/sygus_datatype.h"
#include "expr/type.h"
@@ -376,9 +375,9 @@ class SygusGrammarNorm
*/
TNode d_sygus_vars;
/* Datatypes to be resolved */
- std::vector<Datatype> d_dt_all;
+ std::vector<DType> d_dt_all;
/* Types to be resolved */
- std::set<Type> d_unres_t_all;
+ std::set<TypeNode> d_unres_t_all;
/* Associates type nodes with OpPosTries */
std::map<TypeNode, OpPosTrie> d_tries;
/* Map of type nodes into their identity operators (\lambda x. x) */
diff --git a/src/theory/quantifiers/sygus/sygus_grammar_red.cpp b/src/theory/quantifiers/sygus/sygus_grammar_red.cpp
index 21d0200c4..e6b9b3593 100644
--- a/src/theory/quantifiers/sygus/sygus_grammar_red.cpp
+++ b/src/theory/quantifiers/sygus/sygus_grammar_red.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_grammar_red.h b/src/theory/quantifiers/sygus/sygus_grammar_red.h
index 361226678..7fda6acbe 100644
--- a/src/theory/quantifiers/sygus/sygus_grammar_red.h
+++ b/src/theory/quantifiers/sygus/sygus_grammar_red.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,7 +20,6 @@
#include <map>
#include <vector>
-#include "expr/datatype.h"
#include "expr/node.h"
namespace CVC4 {
diff --git a/src/theory/quantifiers/sygus/sygus_interpol.cpp b/src/theory/quantifiers/sygus/sygus_interpol.cpp
index 42572a0c7..d5ab0e51f 100644
--- a/src/theory/quantifiers/sygus/sygus_interpol.cpp
+++ b/src/theory/quantifiers/sygus/sygus_interpol.cpp
@@ -2,10 +2,10 @@
/*! \file sygus_interpol.cpp
** \verbatim
** Top contributors (to current version):
- ** Ying Sheng
+ ** Ying Sheng, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,17 +16,14 @@
#include "theory/quantifiers/sygus/sygus_interpol.h"
-#include "expr/datatype.h"
#include "expr/dtype.h"
#include "expr/node_algorithm.h"
-#include "expr/sygus_datatype.h"
#include "options/smt_options.h"
#include "theory/datatypes/sygus_datatype_utils.h"
#include "theory/quantifiers/quantifiers_attributes.h"
-#include "theory/quantifiers/quantifiers_rewriter.h"
#include "theory/quantifiers/sygus/sygus_grammar_cons.h"
-#include "theory/quantifiers/term_util.h"
#include "theory/rewriter.h"
+#include "theory/smt_engine_subsolver.h"
namespace CVC4 {
namespace theory {
@@ -34,36 +31,185 @@ namespace quantifiers {
SygusInterpol::SygusInterpol() {}
-SygusInterpol::SygusInterpol(LogicInfo logic) : d_logic(logic) {}
-
void SygusInterpol::collectSymbols(const std::vector<Node>& axioms,
const Node& conj)
{
+ Trace("sygus-interpol-debug") << "Collect symbols..." << std::endl;
+ std::unordered_set<Node, NodeHashFunction> symSetAxioms;
+ std::unordered_set<Node, NodeHashFunction> symSetConj;
+ for (size_t i = 0, size = axioms.size(); i < size; i++)
+ {
+ expr::getSymbols(axioms[i], symSetAxioms);
+ }
+ expr::getSymbols(conj, symSetConj);
+ d_syms.insert(d_syms.end(), symSetAxioms.begin(), symSetAxioms.end());
+ d_syms.insert(d_syms.end(), symSetConj.begin(), symSetConj.end());
+ for (const Node& elem : symSetConj)
+ {
+ if (symSetAxioms.find(elem) != symSetAxioms.end())
+ {
+ d_symSetShared.insert(elem);
+ }
+ }
+ Trace("sygus-interpol-debug")
+ << "...finish, got " << d_syms.size() << " symbols in total. And "
+ << d_symSetShared.size() << " shared symbols." << std::endl;
}
void SygusInterpol::createVariables(bool needsShared)
{
+ NodeManager* nm = NodeManager::currentNM();
+ for (const Node& s : d_syms)
+ {
+ TypeNode tn = s.getType();
+ if (tn.isConstructor() || tn.isSelector() || tn.isTester())
+ {
+ // datatype symbols should be considered interpreted symbols here, not
+ // (higher-order) variables.
+ continue;
+ }
+ // Notice that we allow for non-first class (e.g. function) variables here.
+ std::stringstream ss;
+ ss << s;
+ Node var = nm->mkBoundVar(tn);
+ d_vars.push_back(var);
+ Node vlv = nm->mkBoundVar(ss.str(), tn);
+ // set that this variable encodes the term s
+ SygusVarToTermAttribute sta;
+ vlv.setAttribute(sta, s);
+ d_vlvs.push_back(vlv);
+ if (!needsShared || d_symSetShared.find(s) != d_symSetShared.end())
+ {
+ d_varsShared.push_back(var);
+ d_vlvsShared.push_back(vlv);
+ d_varTypesShared.push_back(tn);
+ }
+ }
+ // make the sygus variable list
+ d_ibvlShared = nm->mkNode(kind::BOUND_VAR_LIST, d_vlvsShared);
+ Trace("sygus-interpol-debug") << "...finish" << std::endl;
}
-std::map<TypeNode, std::unordered_set<Node, NodeHashFunction> > getIncludeCons(
- const std::vector<Node>& assumptions, const Node& conclusion)
+void SygusInterpol::getIncludeCons(
+ const std::vector<Node>& axioms,
+ const Node& conj,
+ std::map<TypeNode, std::unordered_set<Node, NodeHashFunction>>& result)
{
- std::map<TypeNode, std::unordered_set<Node, NodeHashFunction> > result =
- std::map<TypeNode, std::unordered_set<Node, NodeHashFunction> >();
- return result;
+ NodeManager* nm = NodeManager::currentNM();
+ Assert(options::produceInterpols() != options::ProduceInterpols::NONE);
+ // ASSUMPTIONS
+ if (options::produceInterpols() == options::ProduceInterpols::ASSUMPTIONS)
+ {
+ Node tmpAssumptions =
+ (axioms.size() == 1 ? axioms[0] : nm->mkNode(kind::AND, axioms));
+ expr::getOperatorsMap(tmpAssumptions, result);
+ }
+ // CONJECTURE
+ else if (options::produceInterpols() == options::ProduceInterpols::CONJECTURE)
+ {
+ expr::getOperatorsMap(conj, result);
+ }
+ // SHARED
+ else if (options::produceInterpols() == options::ProduceInterpols::SHARED)
+ {
+ // Get operators from axioms
+ std::map<TypeNode, std::unordered_set<Node, NodeHashFunction>>
+ include_cons_axioms;
+ Node tmpAssumptions =
+ (axioms.size() == 1 ? axioms[0] : nm->mkNode(kind::AND, axioms));
+ expr::getOperatorsMap(tmpAssumptions, include_cons_axioms);
+
+ // Get operators from conj
+ std::map<TypeNode, std::unordered_set<Node, NodeHashFunction>>
+ include_cons_conj;
+ expr::getOperatorsMap(conj, include_cons_conj);
+
+ // Compute intersection
+ for (std::map<TypeNode,
+ std::unordered_set<Node, NodeHashFunction>>::iterator it =
+ include_cons_axioms.begin();
+ it != include_cons_axioms.end();
+ it++)
+ {
+ TypeNode tn = it->first;
+ std::unordered_set<Node, NodeHashFunction> axiomsOps = it->second;
+ std::map<TypeNode, std::unordered_set<Node, NodeHashFunction>>::iterator
+ concIter = include_cons_conj.find(tn);
+ if (concIter != include_cons_conj.end())
+ {
+ std::unordered_set<Node, NodeHashFunction> conjOps = concIter->second;
+ for (const Node& n : axiomsOps)
+ {
+ if (conjOps.find(n) != conjOps.end())
+ {
+ if (result.find(tn) == result.end())
+ {
+ result[tn] = std::unordered_set<Node, NodeHashFunction>();
+ }
+ result[tn].insert(n);
+ }
+ }
+ }
+ }
+ }
+ // ALL
+ else if (options::produceInterpols() == options::ProduceInterpols::ALL)
+ {
+ Node tmpAssumptions =
+ (axioms.size() == 1 ? axioms[0] : nm->mkNode(kind::AND, axioms));
+ Node tmpAll = nm->mkNode(kind::AND, tmpAssumptions, conj);
+ expr::getOperatorsMap(tmpAll, result);
+ }
}
TypeNode SygusInterpol::setSynthGrammar(const TypeNode& itpGType,
const std::vector<Node>& axioms,
const Node& conj)
{
+ Trace("sygus-interpol-debug") << "Setup grammar..." << std::endl;
TypeNode itpGTypeS;
+ if (!itpGType.isNull())
+ {
+ // set user-defined grammar
+ Assert(itpGType.isDatatype() && itpGType.getDType().isSygus());
+ itpGTypeS = datatypes::utils::substituteAndGeneralizeSygusType(
+ itpGType, d_syms, d_vlvs);
+ Assert(itpGTypeS.isDatatype() && itpGTypeS.getDType().isSygus());
+ // TODO(Ying Sheng) check if the vars in user-defined grammar, are
+ // consistent with the shared vars
+ }
+ else
+ {
+ // set default grammar
+ std::map<TypeNode, std::unordered_set<Node, NodeHashFunction>> extra_cons;
+ std::map<TypeNode, std::unordered_set<Node, NodeHashFunction>> exclude_cons;
+ std::map<TypeNode, std::unordered_set<Node, NodeHashFunction>> include_cons;
+ getIncludeCons(axioms, conj, include_cons);
+ std::unordered_set<Node, NodeHashFunction> terms_irrelevant;
+ itpGTypeS = CegGrammarConstructor::mkSygusDefaultType(
+ NodeManager::currentNM()->booleanType(),
+ d_ibvlShared,
+ "interpolation_grammar",
+ extra_cons,
+ exclude_cons,
+ include_cons,
+ terms_irrelevant);
+ }
+ Trace("sygus-interpol-debug") << "...finish setting up grammar" << std::endl;
return itpGTypeS;
}
Node SygusInterpol::mkPredicate(const std::string& name)
{
- Node itp;
+ NodeManager* nm = NodeManager::currentNM();
+ // make the interpolation predicate to synthesize
+ Trace("sygus-interpol-debug")
+ << "Make interpolation predicate..." << std::endl;
+ TypeNode itpType = d_varTypesShared.empty()
+ ? nm->booleanType()
+ : nm->mkPredicateType(d_varTypesShared);
+ Node itp = nm->mkBoundVar(name.c_str(), itpType);
+ Trace("sygus-interpol-debug") << "...finish" << std::endl;
return itp;
}
@@ -71,19 +217,148 @@ void SygusInterpol::mkSygusConjecture(Node itp,
const std::vector<Node>& axioms,
const Node& conj)
{
+ NodeManager* nm = NodeManager::currentNM();
+ // make the interpolation application to synthesize
+ Trace("sygus-interpol-debug")
+ << "Make interpolation predicate app..." << std::endl;
+ std::vector<Node> ichildren;
+ ichildren.push_back(itp);
+ ichildren.insert(ichildren.end(), d_varsShared.begin(), d_varsShared.end());
+ Node itpApp =
+ d_varsShared.empty() ? itp : nm->mkNode(kind::APPLY_UF, ichildren);
+ Trace("sygus-interpol-debug") << "itpApp: " << itpApp << std::endl
+ << std::endl;
+ Trace("sygus-interpol-debug") << "...finish" << std::endl;
+
+ // set the sygus bound variable list
+ Trace("sygus-interpol-debug") << "Set attributes..." << std::endl;
+ itp.setAttribute(SygusSynthFunVarListAttribute(), d_ibvlShared);
+ // sygus attribute
+ Node sygusVar = nm->mkSkolem("sygus", nm->booleanType());
+ SygusAttribute ca;
+ sygusVar.setAttribute(ca, true);
+ Node instAttr = nm->mkNode(kind::INST_ATTRIBUTE, sygusVar);
+ std::vector<Node> iplc;
+ iplc.push_back(instAttr);
+ Node instAttrList = nm->mkNode(kind::INST_PATTERN_LIST, iplc);
+ Trace("sygus-interpol-debug") << "...finish" << std::endl;
+
+ // Fa( x )
+ Trace("sygus-interpol-debug") << "Make conjecture body..." << std::endl;
+ Node Fa = axioms.size() == 1 ? axioms[0] : nm->mkNode(kind::AND, axioms);
+ // Fa( x ) => A( x )
+ Node firstImplication = nm->mkNode(kind::IMPLIES, Fa, itpApp);
+ Trace("sygus-interpol-debug")
+ << "first implication: " << firstImplication << std::endl
+ << std::endl;
+ // A( x ) => Fc( x )
+ Node Fc = conj;
+ Node secondImplication = nm->mkNode(kind::IMPLIES, itpApp, Fc);
+ Trace("sygus-interpol-debug")
+ << "second implication: " << secondImplication << std::endl
+ << std::endl;
+ // Fa( x ) => A( x ) ^ A( x ) => Fc( x )
+ Node constraint = nm->mkNode(kind::AND, firstImplication, secondImplication);
+ constraint = constraint.substitute(
+ d_syms.begin(), d_syms.end(), d_vars.begin(), d_vars.end());
+ Trace("sygus-interpol-debug") << constraint << "...finish" << std::endl;
+ constraint = Rewriter::rewrite(constraint);
+
+ d_sygusConj = constraint;
+ Trace("sygus-interpol") << "Generate: " << d_sygusConj << std::endl;
}
-bool SygusInterpol::findInterpol(Expr& interpol, Node itp)
+bool SygusInterpol::findInterpol(SmtEngine* subSolver, Node& interpol, Node itp)
{
- return false;
+ // get the synthesis solution
+ std::map<Node, Node> sols;
+ subSolver->getSynthSolutions(sols);
+ Assert(sols.size() == 1);
+ std::map<Node, Node>::iterator its = sols.find(itp);
+ if (its == sols.end())
+ {
+ Trace("sygus-interpol")
+ << "SmtEngine::getInterpol: could not find solution!" << std::endl;
+ throw RecoverableModalException(
+ "Could not find solution for get-interpol.");
+ return false;
+ }
+ Trace("sygus-interpol") << "SmtEngine::getInterpol: solution is "
+ << its->second << std::endl;
+ interpol = its->second;
+ // replace back the created variables to original symbols.
+ if (interpol.getKind() == kind::LAMBDA)
+ {
+ interpol = interpol[1];
+ }
+
+ // get the grammar type for the interpolant
+ Node igdtbv = itp.getAttribute(SygusSynthFunVarListAttribute());
+ Assert(!igdtbv.isNull());
+ Assert(igdtbv.getKind() == kind::BOUND_VAR_LIST);
+ // convert back to original
+ // must replace formal arguments of itp with the free variables in the
+ // input problem that they correspond to.
+ std::vector<Node> vars;
+ std::vector<Node> syms;
+ SygusVarToTermAttribute sta;
+ for (const Node& bv : igdtbv)
+ {
+ vars.push_back(bv);
+ syms.push_back(bv.hasAttribute(sta) ? bv.getAttribute(sta) : bv);
+ }
+ interpol =
+ interpol.substitute(vars.begin(), vars.end(), syms.begin(), syms.end());
+
+ return true;
}
-bool SygusInterpol::SolveInterpolation(const std::string& name,
+bool SygusInterpol::solveInterpolation(const std::string& name,
const std::vector<Node>& axioms,
const Node& conj,
const TypeNode& itpGType,
- Expr& interpol)
+ Node& interpol)
{
+ // Some instructions in setSynthGrammar and mkSygusConjecture need a fully
+ // initialized solver to work properly. Notice, however, that the sub-solver
+ // created below is not fully initialized by the time those two methods are
+ // needed. Therefore, we call them while the current parent solver is in scope
+ // (i.e., before creating the sub-solver).
+ collectSymbols(axioms, conj);
+ createVariables(itpGType.isNull());
+ TypeNode grammarType = setSynthGrammar(itpGType, axioms, conj);
+
+ Node itp = mkPredicate(name);
+ mkSygusConjecture(itp, axioms, conj);
+
+ std::unique_ptr<SmtEngine> subSolver;
+ initializeSubsolver(subSolver);
+ // get the logic
+ LogicInfo l = subSolver->getLogicInfo().getUnlockedCopy();
+ // enable everything needed for sygus
+ l.enableSygus();
+ subSolver->setLogic(l);
+
+ for (Node var : d_vars)
+ {
+ subSolver->declareSygusVar(name, var, var.getType());
+ }
+ std::vector<Node> vars_empty;
+ subSolver->declareSynthFun(name, itp, grammarType, false, vars_empty);
+ Trace("sygus-interpol") << "SmtEngine::getInterpol: made conjecture : "
+ << d_sygusConj << ", solving for "
+ << d_sygusConj[0][0] << std::endl;
+ subSolver->assertSygusConstraint(d_sygusConj);
+
+ Trace("sygus-interpol") << " SmtEngine::getInterpol check sat..."
+ << std::endl;
+ Result r = subSolver->checkSynth();
+ Trace("sygus-interpol") << " SmtEngine::getInterpol result: " << r
+ << std::endl;
+ if (r.asSatisfiabilityResult().isSat() == Result::UNSAT)
+ {
+ return findInterpol(subSolver.get(), interpol, itp);
+ }
return false;
}
diff --git a/src/theory/quantifiers/sygus/sygus_interpol.h b/src/theory/quantifiers/sygus/sygus_interpol.h
index 4655822ec..916f2d9b5 100644
--- a/src/theory/quantifiers/sygus/sygus_interpol.h
+++ b/src/theory/quantifiers/sygus/sygus_interpol.h
@@ -5,7 +5,7 @@
** Ying Sheng
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -34,20 +34,32 @@ namespace quantifiers {
* F( x ) for free symbol x, and is partitioned into axioms Fa and conjecture Fc
* then the sygus conjecture we construct is:
*
- * exists A. forall x. ( (Fa( x ) => A( x )) ^ (A( x ) => Fc( x )) )
+ * (Fa( x ) => A( x )) ^ (A( x ) => Fc( x ))
*
* where A( x ) is a predicate over the free symbols of our input that are
* shared between Fa and Fc. In other words, A( x ) must be implied by our
* axioms Fa( x ) and implies Fc( x ). Then, to solve the interpolation problem,
* we just need to synthesis A( x ).
+ *
+ * This class uses a fresh copy of the SMT engine which is used for solving the
+ * interpolation problem. In particular, consider the input: (assert A)
+ * (get-interpol s B)
+ * In the copy of the SMT engine where these commands are issued, we maintain
+ * A in the assertion stack. In solving the interpolation problem, we will
+ * need to call a SMT engine solver with a different assertion stack, which is
+ * a sygus conjecture build from A and B. Then to solve the interpolation
+ * problem, instead of modifying the assertion stack to remove A and add the
+ * sygus conjecture (exists I. ...), we invoke a fresh copy of the SMT engine
+ * and leave the original assertion stack unchanged. This copy of the SMT
+ * engine will have the assertion stack with the sygus conjecture. This copy
+ * of the SMT engine can be further queried for information regarding further
+ * solutions.
*/
class SygusInterpol
{
public:
SygusInterpol();
- SygusInterpol(LogicInfo logic);
-
/**
* Returns the sygus conjecture in interpol corresponding to the interpolation
* problem for input problem (F above) given by axioms (Fa above), and conj
@@ -61,17 +73,17 @@ class SygusInterpol
* grammar that should be used for solutions of the interpolation conjecture.
* @interpol the solution to the sygus conjecture.
*/
- bool SolveInterpolation(const std::string& name,
+ bool solveInterpolation(const std::string& name,
const std::vector<Node>& axioms,
const Node& conj,
const TypeNode& itpGType,
- Expr& interpol);
+ Node& interpol);
private:
/**
* Collects symbols from axioms (axioms) and conjecture (conj), which are
* stored in d_syms, and computes the shared symbols between axioms and
- * conjecture, stored in d_symsShared.
+ * conjecture, stored in d_symSetShared.
*
* @param axioms the assertions (Fa above)
* @param conj the conjecture (Fc above)
@@ -80,11 +92,11 @@ class SygusInterpol
/**
* Creates free variables and shared free variables from d_syms and
- * d_symsShared, which are stored in d_vars and d_varsShared. And also creates
- * the corresponding set of variables for the formal argument list, which is
- * stored in d_vlvs and d_vlvsShared. Extracts the types of shared variables,
- * which are stored in d_varTypesShared. Creates the formal argument list of
- * the interpol-to-synthesis, stored in d_ibvlShared.
+ * d_symSetShared, which are stored in d_vars and d_varsShared. And also
+ * creates the corresponding set of variables for the formal argument list,
+ * which is stored in d_vlvs and d_vlvsShared. Extracts the types of shared
+ * variables, which are stored in d_varTypesShared. Creates the formal
+ * argument list of the interpol-to-synthese, stored in d_ibvlShared.
*
* When using default grammar, the needsShared is true. When using
* user-defined gramar, the needsShared is false.
@@ -96,17 +108,32 @@ class SygusInterpol
void createVariables(bool needsShared);
/**
+ * Get include_cons for mkSygusDefaultType.
+ * mkSygusDefaultType() is a function to make default grammar. It has an
+ * arguemnt include_cons, which will restrict what operators we want in the
+ * grammar. The return value depends on options::produceInterpols(). In
+ * ASSUMPTIONS option, it will return the operators from axioms. In CONJECTURE
+ * option, it will return the operators from conj. In SHARED option, it will
+ * return the oprators shared by axioms and conj. In ALL option, it will
+ * return the operators from either axioms or conj.
+ *
+ * @param axioms input argument
+ * @param conj input argument
+ * @param result the return value
+ */
+ void getIncludeCons(
+ const std::vector<Node>& axioms,
+ const Node& conj,
+ std::map<TypeNode, std::unordered_set<Node, NodeHashFunction>>& result);
+
+ /**
* Set up the grammar for the interpol-to-synthesis.
*
* The user-defined grammar will be encoded by itpGType. The options for
* grammar is given by options::produceInterpols(). In DEFAULT option, it will
* set up the grammar from itpGType. And if itpGType is null, it will set up
- * the default grammar. In ASSUMPTIONS option, it will set up the grammar by
- * only using the operators from axioms. In CONJECTURE option, it will set up
- * the grammar by only using the operators from conj. In SHARED option, it
- * will set up the grammar by only using the operators shared by axioms and
- * conj. In ALL option, it will set up the grammar by only using the operators
- * from either axioms or conj.
+ * the default grammar, which is built according to a policy handled by
+ * getIncludeCons().
*
* @param itpGType (if non-null) a sygus datatype type that encodes the
* grammar that should be used for solutions of the interpolation conjecture.
@@ -126,6 +153,8 @@ class SygusInterpol
/**
* Make the sygus conjecture to be synthesis.
+ * The conjecture body is Fa( x ) => A( x ) ^ A( x ) => Fc( x ) as described
+ * above.
*
* @param itp the interpolation predicate.
* @param axioms the assertions (Fa above)
@@ -141,39 +170,16 @@ class SygusInterpol
* @param interpol the solution to the sygus conjecture.
* @param itp the interpolation predicate.
*/
- bool findInterpol(Expr& interpol, Node itp);
-
- /** The SMT engine subSolver
- *
- * This is a fresh copy of the SMT engine which is used for solving the
- * interpolation problem. In particular, consider the input: (assert A)
- * (get-interpol s B)
- * In the copy of the SMT engine where these commands are issued, we maintain
- * A in the assertion stack. In solving the interpolation problem, we will
- * need to call a SMT engine solver with a different assertion stack, which is
- * a sygus conjecture build from A and B. Then to solve the interpolation
- * problem, instead of modifying the assertion stack to remove A and add the
- * sygus conjecture (exists I. ...), we invoke a fresh copy of the SMT engine
- * and leave the original assertion stack unchanged. This copy of the SMT
- * engine will have the assertion stack with the sygus conjecture. This copy
- * of the SMT engine can be further queried for information regarding further
- * solutions.
- */
- std::unique_ptr<SmtEngine> d_subSolver;
-
- /**
- * The logic for the local copy of SMT engine (d_subSolver).
- */
- LogicInfo d_logic;
+ bool findInterpol(SmtEngine* subsolver, Node& interpol, Node itp);
/**
* symbols from axioms and conjecture.
*/
std::vector<Node> d_syms;
/**
- * shared symbols between axioms and conjecture.
+ * unordered set for shared symbols between axioms and conjecture.
*/
- std::vector<Node> d_symsShared;
+ std::unordered_set<Node, NodeHashFunction> d_symSetShared;
/**
* free variables created from d_syms.
*/
@@ -183,7 +189,7 @@ class SygusInterpol
*/
std::vector<Node> d_vlvs;
/**
- * free variables created from d_symsShared.
+ * free variables created from d_symSetShared.
*/
std::vector<Node> d_varsShared;
/**
diff --git a/src/theory/quantifiers/sygus/sygus_invariance.cpp b/src/theory/quantifiers/sygus/sygus_invariance.cpp
index 02a0c56a6..df4c31521 100644
--- a/src/theory/quantifiers/sygus/sygus_invariance.cpp
+++ b/src/theory/quantifiers/sygus/sygus_invariance.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_invariance.h b/src/theory/quantifiers/sygus/sygus_invariance.h
index 23c2ff964..d00634576 100644
--- a/src/theory/quantifiers/sygus/sygus_invariance.h
+++ b/src/theory/quantifiers/sygus/sygus_invariance.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_module.cpp b/src/theory/quantifiers/sygus/sygus_module.cpp
index 536072c47..807764230 100644
--- a/src/theory/quantifiers/sygus/sygus_module.cpp
+++ b/src/theory/quantifiers/sygus/sygus_module.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_module.h b/src/theory/quantifiers/sygus/sygus_module.h
index 3c41f4962..7eef6c46a 100644
--- a/src/theory/quantifiers/sygus/sygus_module.h
+++ b/src/theory/quantifiers/sygus/sygus_module.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_pbe.cpp b/src/theory/quantifiers/sygus/sygus_pbe.cpp
index 0921fba30..b1cb330f6 100644
--- a/src/theory/quantifiers/sygus/sygus_pbe.cpp
+++ b/src/theory/quantifiers/sygus/sygus_pbe.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,7 +14,6 @@
**/
#include "theory/quantifiers/sygus/sygus_pbe.h"
-#include "expr/datatype.h"
#include "options/quantifiers_options.h"
#include "theory/quantifiers/sygus/example_infer.h"
#include "theory/quantifiers/sygus/synth_conjecture.h"
diff --git a/src/theory/quantifiers/sygus/sygus_pbe.h b/src/theory/quantifiers/sygus/sygus_pbe.h
index ebe58f80b..1999f82c3 100644
--- a/src/theory/quantifiers/sygus/sygus_pbe.h
+++ b/src/theory/quantifiers/sygus/sygus_pbe.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_process_conj.cpp b/src/theory/quantifiers/sygus/sygus_process_conj.cpp
index 6df8619f7..1e67bb8cc 100644
--- a/src/theory/quantifiers/sygus/sygus_process_conj.cpp
+++ b/src/theory/quantifiers/sygus/sygus_process_conj.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,7 +16,6 @@
#include <stack>
-#include "expr/datatype.h"
#include "options/quantifiers_options.h"
#include "theory/quantifiers/sygus/term_database_sygus.h"
#include "theory/quantifiers/term_util.h"
diff --git a/src/theory/quantifiers/sygus/sygus_process_conj.h b/src/theory/quantifiers/sygus/sygus_process_conj.h
index 80426f924..93003f6d6 100644
--- a/src/theory/quantifiers/sygus/sygus_process_conj.h
+++ b/src/theory/quantifiers/sygus/sygus_process_conj.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_qe_preproc.cpp b/src/theory/quantifiers/sygus/sygus_qe_preproc.cpp
new file mode 100644
index 000000000..1a92cfc7f
--- /dev/null
+++ b/src/theory/quantifiers/sygus/sygus_qe_preproc.cpp
@@ -0,0 +1,147 @@
+/********************* */
+/*! \file sygus_qe_preproc.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Sygus quantifier elimination preprocessor
+ **/
+
+#include "theory/quantifiers/sygus/sygus_qe_preproc.h"
+
+#include "expr/node_algorithm.h"
+#include "theory/quantifiers/single_inv_partition.h"
+#include "theory/rewriter.h"
+#include "theory/smt_engine_subsolver.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+SygusQePreproc::SygusQePreproc(QuantifiersEngine* qe) {}
+
+Node SygusQePreproc::preprocess(Node q)
+{
+ Node body = q[1];
+ if (body.getKind() == NOT && body[0].getKind() == FORALL)
+ {
+ body = body[0][1];
+ }
+ NodeManager* nm = NodeManager::currentNM();
+ Trace("cegqi-qep") << "Compute single invocation for " << q << "..."
+ << std::endl;
+ quantifiers::SingleInvocationPartition sip;
+ std::vector<Node> funcs0;
+ funcs0.insert(funcs0.end(), q[0].begin(), q[0].end());
+ sip.init(funcs0, body);
+ Trace("cegqi-qep") << "...finished, got:" << std::endl;
+ sip.debugPrint("cegqi-qep");
+
+ if (sip.isPurelySingleInvocation() || !sip.isNonGroundSingleInvocation())
+ {
+ return Node::null();
+ }
+ // create new smt engine to do quantifier elimination
+ std::unique_ptr<SmtEngine> smt_qe;
+ initializeSubsolver(smt_qe);
+ Trace("cegqi-qep") << "Property is non-ground single invocation, run "
+ "QE to obtain single invocation."
+ << std::endl;
+ // partition variables
+ std::vector<Node> all_vars;
+ sip.getAllVariables(all_vars);
+ std::vector<Node> si_vars;
+ sip.getSingleInvocationVariables(si_vars);
+ std::vector<Node> qe_vars;
+ std::vector<Node> nqe_vars;
+ for (unsigned i = 0, size = all_vars.size(); i < size; i++)
+ {
+ Node v = all_vars[i];
+ if (std::find(funcs0.begin(), funcs0.end(), v) != funcs0.end())
+ {
+ Trace("cegqi-qep") << "- fun var: " << v << std::endl;
+ }
+ else if (std::find(si_vars.begin(), si_vars.end(), v) == si_vars.end())
+ {
+ qe_vars.push_back(v);
+ Trace("cegqi-qep") << "- qe var: " << v << std::endl;
+ }
+ else
+ {
+ nqe_vars.push_back(v);
+ Trace("cegqi-qep") << "- non qe var: " << v << std::endl;
+ }
+ }
+ std::vector<Node> orig;
+ std::vector<Node> subs;
+ // skolemize non-qe variables
+ for (unsigned i = 0, size = nqe_vars.size(); i < size; i++)
+ {
+ Node k = nm->mkSkolem(
+ "k", nqe_vars[i].getType(), "qe for non-ground single invocation");
+ orig.push_back(nqe_vars[i]);
+ subs.push_back(k);
+ Trace("cegqi-qep") << " subs : " << nqe_vars[i] << " -> " << k
+ << std::endl;
+ }
+ std::vector<Node> funcs1;
+ sip.getFunctions(funcs1);
+ for (unsigned i = 0, size = funcs1.size(); i < size; i++)
+ {
+ Node f = funcs1[i];
+ Node fi = sip.getFunctionInvocationFor(f);
+ Node fv = sip.getFirstOrderVariableForFunction(f);
+ Assert(!fi.isNull());
+ orig.push_back(fi);
+ Node k = nm->mkSkolem(
+ "k", fv.getType(), "qe for function in non-ground single invocation");
+ subs.push_back(k);
+ Trace("cegqi-qep") << " subs : " << fi << " -> " << k << std::endl;
+ }
+ Node conj_se_ngsi = sip.getFullSpecification();
+ Trace("cegqi-qep") << "Full specification is " << conj_se_ngsi << std::endl;
+ Node conj_se_ngsi_subs = conj_se_ngsi.substitute(
+ orig.begin(), orig.end(), subs.begin(), subs.end());
+ Assert(!qe_vars.empty());
+ conj_se_ngsi_subs = nm->mkNode(
+ EXISTS, nm->mkNode(BOUND_VAR_LIST, qe_vars), conj_se_ngsi_subs.negate());
+
+ Trace("cegqi-qep") << "Run quantifier elimination on " << conj_se_ngsi_subs
+ << std::endl;
+ Node qeRes = smt_qe->getQuantifierElimination(conj_se_ngsi_subs, true, false);
+ Trace("cegqi-qep") << "Result : " << qeRes << std::endl;
+
+ // create single invocation conjecture, if QE was successful
+ if (!expr::hasBoundVar(qeRes))
+ {
+ qeRes =
+ qeRes.substitute(subs.begin(), subs.end(), orig.begin(), orig.end());
+ if (!nqe_vars.empty())
+ {
+ qeRes = nm->mkNode(EXISTS, nm->mkNode(BOUND_VAR_LIST, nqe_vars), qeRes);
+ }
+ Assert(q.getNumChildren() == 3);
+ qeRes = nm->mkNode(FORALL, q[0], qeRes, q[2]);
+ Trace("cegqi-qep") << "Converted conjecture after QE : " << qeRes
+ << std::endl;
+ qeRes = Rewriter::rewrite(qeRes);
+ Node nq = qeRes;
+ // must assert it is equivalent to the original
+ Node lem = q.eqNode(nq);
+ Trace("cegqi-lemma") << "Cegqi::Lemma : qe-preprocess : " << lem
+ << std::endl;
+ return lem;
+ }
+ return Node::null();
+}
+
+} // namespace quantifiers
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/quantifiers/sygus/sygus_qe_preproc.h b/src/theory/quantifiers/sygus/sygus_qe_preproc.h
new file mode 100644
index 000000000..2214d4beb
--- /dev/null
+++ b/src/theory/quantifiers/sygus/sygus_qe_preproc.h
@@ -0,0 +1,60 @@
+/********************* */
+/*! \file sygus_qe_preproc.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Sygus quantifier elimination preprocessor
+ **/
+
+#ifndef CVC4__THEORY__QUANTIFIERS__SYGUS__SYGUS_QE_PREPROC_H
+#define CVC4__THEORY__QUANTIFIERS__SYGUS__SYGUS_QE_PREPROC_H
+
+#include <string>
+#include <vector>
+#include "expr/node.h"
+#include "expr/type.h"
+
+namespace CVC4 {
+namespace theory {
+
+class QuantifiersEngine;
+
+namespace quantifiers {
+
+/**
+ * This module does quantifier elimination as a preprocess step
+ * for "non-ground single invocation synthesis conjectures":
+ * exists f. forall xy. P[ f(x), x, y ]
+ * We run quantifier elimination:
+ * exists y. P[ z, x, y ] ----> Q[ z, x ]
+ * Where we replace the original conjecture with:
+ * exists f. forall x. Q[ f(x), x ]
+ * For more details, see Example 6 of Reynolds et al. SYNT 2017.
+ */
+class SygusQePreproc
+{
+ public:
+ SygusQePreproc(QuantifiersEngine* qe);
+ ~SygusQePreproc() {}
+ /**
+ * Preprocess. Returns a lemma of the form q = nq where nq is obtained
+ * by the quantifier elimination technique outlined above.
+ */
+ Node preprocess(Node q);
+
+ private:
+ /** Pointer to quantifiers engine */
+ QuantifiersEngine* d_quantEngine;
+};
+
+} // namespace quantifiers
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__QUANTIFIERS__SYGUS__SYGUS_QE_PREPROC_H */
diff --git a/src/theory/quantifiers/sygus/sygus_repair_const.cpp b/src/theory/quantifiers/sygus/sygus_repair_const.cpp
index 2514b05e2..989f7b758 100644
--- a/src/theory/quantifiers/sygus/sygus_repair_const.cpp
+++ b/src/theory/quantifiers/sygus/sygus_repair_const.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -250,7 +250,7 @@ bool SygusRepairConst::repairSolution(Node sygusBody,
{
Assert(d_sk_to_fo.find(v) != d_sk_to_fo.end());
Node fov = d_sk_to_fo[v];
- Node fov_m = Node::fromExpr(repcChecker->getValue(fov.toExpr()));
+ Node fov_m = repcChecker->getValue(fov);
Trace("sygus-repair-const") << " " << fov << " = " << fov_m << std::endl;
// convert to sygus
Node fov_m_to_sygus = d_tds->getProxyVariable(v.getType(), fov_m);
diff --git a/src/theory/quantifiers/sygus/sygus_repair_const.h b/src/theory/quantifiers/sygus/sygus_repair_const.h
index e02ca1f3e..5644af895 100644
--- a/src/theory/quantifiers/sygus/sygus_repair_const.h
+++ b/src/theory/quantifiers/sygus/sygus_repair_const.h
@@ -2,10 +2,10 @@
/*! \file sygus_repair_const.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Haniel Barbosa, Mathias Preiner
+ ** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_stats.cpp b/src/theory/quantifiers/sygus/sygus_stats.cpp
index ccec37b25..86b32301f 100644
--- a/src/theory/quantifiers/sygus/sygus_stats.cpp
+++ b/src/theory/quantifiers/sygus/sygus_stats.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_stats.h b/src/theory/quantifiers/sygus/sygus_stats.h
index 11f3c9e60..52b9a4318 100644
--- a/src/theory/quantifiers/sygus/sygus_stats.h
+++ b/src/theory/quantifiers/sygus/sygus_stats.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_unif.cpp b/src/theory/quantifiers/sygus/sygus_unif.cpp
index ee30de50e..37ed7f952 100644
--- a/src/theory/quantifiers/sygus/sygus_unif.cpp
+++ b/src/theory/quantifiers/sygus/sygus_unif.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Aina Niemetz, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_unif.h b/src/theory/quantifiers/sygus/sygus_unif.h
index 8201ead6e..a0417890e 100644
--- a/src/theory/quantifiers/sygus/sygus_unif.h
+++ b/src/theory/quantifiers/sygus/sygus_unif.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_unif_io.cpp b/src/theory/quantifiers/sygus/sygus_unif_io.cpp
index ce13b6744..3bd755f79 100644
--- a/src/theory/quantifiers/sygus/sygus_unif_io.cpp
+++ b/src/theory/quantifiers/sygus/sygus_unif_io.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -47,9 +47,16 @@ bool UnifContextIo::updateContext(SygusUnifIo* sui,
Assert(d_vals.size() == vals.size());
bool changed = false;
Node poln = pol ? d_true : d_false;
- for (unsigned i = 0; i < vals.size(); i++)
+ for (size_t i = 0, vsize = vals.size(); i < vsize; i++)
{
- if (vals[i] != poln)
+ Node v = vals[i];
+ if (v.isNull())
+ {
+ // nothing can be inferred if the evaluation is unknown, e.g. if using
+ // partial functions.
+ continue;
+ }
+ if (v != poln)
{
if (d_vals[i] == d_true)
{
@@ -571,8 +578,6 @@ void SygusUnifIo::notifyEnumeration(Node e, Node v, std::vector<Node>& lemmas)
eec->evaluateVec(bv, base_results);
// get the results for each slave enumerator
std::map<Node, std::vector<Node>> srmap;
- Evaluator* ev = d_tds->getEvaluator();
- bool tryEval = options::sygusEvalOpt();
for (const Node& xs : ei.d_enum_slave)
{
Assert(srmap.find(xs) == srmap.end());
@@ -580,34 +585,15 @@ void SygusUnifIo::notifyEnumeration(Node e, Node v, std::vector<Node>& lemmas)
Node templ = eiv.d_template;
if (!templ.isNull())
{
- TNode templ_var = eiv.d_template_arg;
- std::vector<Node> args;
- args.push_back(templ_var);
+ // Substitute and evaluate, notice that the template skeleton may
+ // involve the sygus variables e.g. (>= x _) where x is a sygus
+ // variable, hence we must compute the substituted template before
+ // calling the evaluator.
+ TNode targ = eiv.d_template_arg;
+ TNode tbv = bv;
+ Node stempl = templ.substitute(targ, tbv);
std::vector<Node> sresults;
- for (const Node& res : base_results)
- {
- TNode tres = res;
- Node sres;
- // It may not be constant, e.g. if we involve a partial operator
- // like datatype selectors. In this case, we avoid using the evaluator,
- // which expects a constant substitution.
- if (tres.isConst())
- {
- std::vector<Node> vals;
- vals.push_back(tres);
- if (tryEval)
- {
- sres = ev->eval(templ, args, vals);
- }
- }
- if (sres.isNull())
- {
- // fall back on rewriter
- sres = templ.substitute(templ_var, tres);
- sres = Rewriter::rewrite(sres);
- }
- sresults.push_back(sres);
- }
+ eec->evaluateVec(stempl, sresults);
srmap[xs] = sresults;
}
else
@@ -658,6 +644,7 @@ void SygusUnifIo::notifyEnumeration(Node e, Node v, std::vector<Node>& lemmas)
std::vector<Node> results;
std::map<Node, bool> cond_vals;
std::map<Node, std::vector<Node>>::iterator itsr = srmap.find(xs);
+ Trace("sygus-sui-debug") << " {" << itsr->second << "} ";
Assert(itsr != srmap.end());
for (unsigned j = 0, size = itsr->second.size(); j < size; j++)
{
@@ -1003,6 +990,8 @@ bool SygusUnifIo::getExplanationForEnumeratorExclude(
void SygusUnifIo::EnumCache::addEnumValue(Node v, std::vector<Node>& results)
{
+ Trace("sygus-sui-debug") << "Add enum value " << this << " " << v << " : "
+ << results << std::endl;
// should not have been enumerated before
Assert(d_enum_val_to_index.find(v) == d_enum_val_to_index.end());
d_enum_val_to_index[v] = d_enum_vals.size();
@@ -1080,7 +1069,7 @@ Node SygusUnifIo::constructSol(
{
ret_dt = constructBestSolvedTerm(e, subsumed_by);
indent("sygus-sui-dt", ind);
- Trace("sygus-sui-dt") << "return PBE: success : conditionally solved"
+ Trace("sygus-sui-dt") << "return PBE: success : conditionally solved "
<< d_tds->sygusToBuiltin(ret_dt) << std::endl;
}
else
@@ -1442,12 +1431,33 @@ Node SygusUnifIo::constructSol(
}
else
{
- // TODO (#1250) : degenerate case where children have different
- // types?
- indent("sygus-sui-dt", ind);
- Trace("sygus-sui-dt") << "return PBE: failed ITE strategy, "
- "cannot find a distinguishable condition"
- << std::endl;
+ // if the branch types are different, it could still make a
+ // difference to recurse, for instance see issue #4790. We do this
+ // if either branch is a different type from the current type.
+ TypeNode branchType1 = etis->d_cenum[1].first.getType();
+ TypeNode branchType2 = etis->d_cenum[2].first.getType();
+ bool childTypesEqual = branchType1 == etn && branchType2 == etn;
+ if (!childTypesEqual)
+ {
+ if (!ecache_child.d_enum_vals.empty())
+ {
+ // take arbitrary
+ rec_c = constructBestConditional(ce, ecache_child.d_enum_vals);
+ indent("sygus-sui-dt", ind);
+ Trace("sygus-sui-dt")
+ << "PBE: ITE strategy : choose arbitrary conditional due "
+ "to disequal child types "
+ << d_tds->sygusToBuiltin(rec_c) << std::endl;
+ }
+ }
+ if (rec_c.isNull())
+ {
+ indent("sygus-sui-dt", ind);
+ Trace("sygus-sui-dt")
+ << "return PBE: failed ITE strategy, "
+ "cannot find a distinguishable condition, childTypesEqual="
+ << childTypesEqual << std::endl;
+ }
}
if (!rec_c.isNull())
{
diff --git a/src/theory/quantifiers/sygus/sygus_unif_io.h b/src/theory/quantifiers/sygus/sygus_unif_io.h
index 055f77ea4..2e915d437 100644
--- a/src/theory/quantifiers/sygus/sygus_unif_io.h
+++ b/src/theory/quantifiers/sygus/sygus_unif_io.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_unif_rl.cpp b/src/theory/quantifiers/sygus/sygus_unif_rl.cpp
index 86cb69f48..2a2883d72 100644
--- a/src/theory/quantifiers/sygus/sygus_unif_rl.cpp
+++ b/src/theory/quantifiers/sygus/sygus_unif_rl.cpp
@@ -5,7 +5,7 @@
** Haniel Barbosa, Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_unif_rl.h b/src/theory/quantifiers/sygus/sygus_unif_rl.h
index 38122fc1b..973998dfc 100644
--- a/src/theory/quantifiers/sygus/sygus_unif_rl.h
+++ b/src/theory/quantifiers/sygus/sygus_unif_rl.h
@@ -5,7 +5,7 @@
** Haniel Barbosa, Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_unif_strat.cpp b/src/theory/quantifiers/sygus/sygus_unif_strat.cpp
index 07e623b28..f0d3e47b6 100644
--- a/src/theory/quantifiers/sygus/sygus_unif_strat.cpp
+++ b/src/theory/quantifiers/sygus/sygus_unif_strat.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/sygus_unif_strat.h b/src/theory/quantifiers/sygus/sygus_unif_strat.h
index 64e6e1f6b..ffc9a84b1 100644
--- a/src/theory/quantifiers/sygus/sygus_unif_strat.h
+++ b/src/theory/quantifiers/sygus/sygus_unif_strat.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/synth_conjecture.cpp b/src/theory/quantifiers/sygus/synth_conjecture.cpp
index 379d29782..6135015db 100644
--- a/src/theory/quantifiers/sygus/synth_conjecture.cpp
+++ b/src/theory/quantifiers/sygus/synth_conjecture.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,7 +14,6 @@
**/
#include "theory/quantifiers/sygus/synth_conjecture.h"
-#include "expr/datatype.h"
#include "options/base_options.h"
#include "options/datatypes_options.h"
#include "options/quantifiers_options.h"
@@ -43,12 +42,14 @@ namespace CVC4 {
namespace theory {
namespace quantifiers {
-SynthConjecture::SynthConjecture(QuantifiersEngine* qe, SygusStatistics& s)
+SynthConjecture::SynthConjecture(QuantifiersEngine* qe,
+ SygusStatistics& s)
: d_qe(qe),
d_stats(s),
d_tds(qe->getTermDatabaseSygus()),
d_hasSolution(false),
- d_ceg_si(new CegSingleInv(qe, this)),
+ d_ceg_si(new CegSingleInv(qe)),
+ d_templInfer(new SygusTemplateInfer),
d_ceg_proc(new SynthConjectureProcess(qe)),
d_ceg_gc(new CegGrammarConstructor(qe, this)),
d_sygus_rconst(new SygusRepairConst(qe)),
@@ -114,15 +115,18 @@ void SynthConjecture::assign(Node q)
{
d_ceg_si->initialize(d_simp_quant);
d_simp_quant = d_ceg_si->getSimplifiedConjecture();
+ if (!d_ceg_si->isSingleInvocation())
+ {
+ d_templInfer->initialize(d_simp_quant);
+ }
// carry the templates
- for (unsigned i = 0; i < q[0].getNumChildren(); i++)
+ for (const Node& v : q[0])
{
- Node v = q[0][i];
- Node templ = d_ceg_si->getTemplate(v);
+ Node templ = d_templInfer->getTemplate(v);
if (!templ.isNull())
{
templates[v] = templ;
- templates_arg[v] = d_ceg_si->getTemplateArg(v);
+ templates_arg[v] = d_templInfer->getTemplateArg(v);
}
}
}
@@ -233,7 +237,7 @@ void SynthConjecture::assign(Node q)
d_feasible_guard,
d_qe->getSatContext(),
d_qe->getValuation()));
- d_qe->getTheoryEngine()->getDecisionManager()->registerStrategy(
+ d_qe->getDecisionManager()->registerStrategy(
DecisionManager::STRAT_QUANT_SYGUS_FEASIBLE, d_feasible_strategy.get());
// this must be called, both to ensure that the feasible guard is
// decided on with true polariy, but also to ensure that output channel
@@ -249,15 +253,6 @@ void SynthConjecture::assign(Node q)
d_qe->getOutputChannel().lemma(lem);
}
- if (options::sygusStream())
- {
- d_stream_strategy.reset(new SygusStreamDecisionStrategy(
- d_qe->getSatContext(), d_qe->getValuation()));
- d_qe->getTheoryEngine()->getDecisionManager()->registerStrategy(
- DecisionManager::STRAT_QUANT_SYGUS_STREAM_FEASIBLE,
- d_stream_strategy.get());
- d_current_stream_guard = d_stream_strategy->getLiteral(0);
- }
Trace("cegqi") << "...finished, single invocation = " << isSingleInvocation()
<< std::endl;
}
@@ -308,9 +303,7 @@ bool SynthConjecture::doCheck(std::vector<Node>& lems)
{
d_hasSolution = true;
// the conjecture has a solution, so its negation holds
- Node lem = d_quant.negate();
- lem = getStreamGuardedLemma(lem);
- lems.push_back(lem);
+ lems.push_back(d_quant.negate());
}
return true;
}
@@ -321,24 +314,6 @@ bool SynthConjecture::doCheck(std::vector<Node>& lems)
std::vector<Node> terms;
d_master->getTermList(d_candidates, terms);
- // process the sygus streaming guard
- if (options::sygusStream())
- {
- Assert(!isSingleInvocation());
- // it may be the case that we have a new solution now
- Node currGuard = getCurrentStreamGuard();
- if (currGuard != d_current_stream_guard)
- {
- std::vector<Node> vals;
- std::vector<int> status;
- getSynthSolutionsInternal(vals, status);
- // we have a new guard, print and continue the stream
- printAndContinueStream(terms, vals);
- d_current_stream_guard = currGuard;
- return true;
- }
- }
-
Assert(!d_candidates.empty());
Trace("cegqi-check") << "CegConjuncture : check, build candidates..."
@@ -513,34 +488,25 @@ bool SynthConjecture::doCheck(std::vector<Node>& lems)
inst = d_base_inst;
}
- // check whether we will run CEGIS on inner skolem variables
- bool sk_refine = (!isGround() || d_refine_count == 0) && constructed_cand;
- if (sk_refine)
+ if (!constructed_cand)
{
- if (options::cegisSample() == options::CegisSampleMode::TRUST)
- {
- // we have that the current candidate passed a sample test
- // since we trust sampling in this mode, we assert there is no
- // counterexample to the conjecture here.
- Node lem = nm->mkNode(OR, d_quant.negate(), nm->mkConst(false));
- lem = getStreamGuardedLemma(lem);
- lems.push_back(lem);
- recordInstantiation(candidate_values);
- d_hasSolution = true;
- return true;
- }
- Assert(!d_set_ce_sk_vars);
+ return false;
}
- else
+
+ // if we trust the sampling we ran, we terminate now
+ if (options::cegisSample() == options::CegisSampleMode::TRUST)
{
- if (!constructed_cand)
- {
- return false;
- }
+ // we have that the current candidate passed a sample test
+ // since we trust sampling in this mode, we assert there is no
+ // counterexample to the conjecture here.
+ lems.push_back(d_quant.negate());
+ recordSolution(candidate_values);
+ return true;
}
+ Assert(!d_set_ce_sk_vars);
// immediately skolemize inner existentials
- Node lem;
+ Node query;
// introduce the skolem variables
std::vector<Node> sks;
std::vector<Node> vars;
@@ -571,70 +537,53 @@ bool SynthConjecture::doCheck(std::vector<Node>& lems)
Trace("cegqi-check-debug")
<< " introduce skolem " << sk << " for " << v << "\n";
}
- lem = inst[0][1].substitute(
+ query = inst[0][1].substitute(
vars.begin(), vars.end(), sks.begin(), sks.end());
- lem = lem.negate();
+ query = query.negate();
}
else
{
// use the instance itself
- lem = inst;
+ query = inst;
}
}
- if (sk_refine)
- {
- d_ce_sk_vars.insert(d_ce_sk_vars.end(), sks.begin(), sks.end());
- d_set_ce_sk_vars = true;
- }
+ d_ce_sk_vars.insert(d_ce_sk_vars.end(), sks.begin(), sks.end());
+ d_set_ce_sk_vars = true;
- if (lem.isNull())
+ if (query.isNull())
{
// no lemma to check
return false;
}
// simplify the lemma based on the term database sygus utility
- lem = d_tds->rewriteNode(lem);
+ query = d_tds->rewriteNode(query);
// eagerly unfold applications of evaluation function
- Trace("cegqi-debug") << "pre-unfold counterexample : " << lem << std::endl;
- // record the instantiation
- // this is used for remembering the solution
- recordInstantiation(candidate_values);
-
- Node query = lem;
- bool success = false;
- if (query.isConst() && !query.getConst<bool>())
- {
- // short circuit the check
- lem = d_quant.negate();
- success = true;
- }
- else
+ Trace("cegqi-debug") << "pre-unfold counterexample : " << query << std::endl;
+ // Record the solution, which may be falsified below. We require recording
+ // here since the result of the satisfiability test may be unknown.
+ recordSolution(candidate_values);
+
+ if (!query.isConst() || query.getConst<bool>())
{
- // This is the "verification lemma", which states
- // either this conjecture does not have a solution, or candidate_values
- // is a solution for this conjecture.
- lem = nm->mkNode(OR, d_quant.negate(), query);
- if (options::sygusVerifySubcall())
+ Trace("sygus-engine") << " *** Verify with subcall..." << std::endl;
+ Result r =
+ checkWithSubsolver(query.toExpr(), d_ce_sk_vars, d_ce_sk_var_mvs);
+ Trace("sygus-engine") << " ...got " << r << std::endl;
+ if (r.asSatisfiabilityResult().isSat() == Result::SAT)
{
- Trace("sygus-engine") << " *** Verify with subcall..." << std::endl;
-
- Result r =
- checkWithSubsolver(query.toExpr(), d_ce_sk_vars, d_ce_sk_var_mvs);
- Trace("sygus-engine") << " ...got " << r << std::endl;
- if (r.asSatisfiabilityResult().isSat() == Result::SAT)
+ if (Trace.isOn("sygus-engine"))
{
- if (Trace.isOn("sygus-engine"))
+ Trace("sygus-engine") << " * Verification lemma failed for:\n ";
+ for (unsigned i = 0, size = d_ce_sk_vars.size(); i < size; i++)
{
- Trace("sygus-engine") << " * Verification lemma failed for:\n ";
- for (unsigned i = 0, size = d_ce_sk_vars.size(); i < size; i++)
- {
- Trace("sygus-engine")
- << d_ce_sk_vars[i] << " -> " << d_ce_sk_var_mvs[i] << " ";
- }
- Trace("sygus-engine") << std::endl;
+ Trace("sygus-engine")
+ << d_ce_sk_vars[i] << " -> " << d_ce_sk_var_mvs[i] << " ";
}
-#ifdef CVC4_ASSERTIONS
+ Trace("sygus-engine") << std::endl;
+ }
+ if (Configuration::isAssertionBuild())
+ {
// the values for the query should be a complete model
Node squery = query.substitute(d_ce_sk_vars.begin(),
d_ce_sk_vars.end(),
@@ -645,37 +594,36 @@ bool SynthConjecture::doCheck(std::vector<Node>& lems)
Trace("cegqi-debug") << "...rewrites to : " << squery << std::endl;
Assert(options::sygusRecFun()
|| (squery.isConst() && squery.getConst<bool>()));
-#endif
- return false;
}
- else if (r.asSatisfiabilityResult().isSat() == Result::UNSAT)
- {
- // if the result in the subcall was unsatisfiable, we avoid
- // rechecking, hence we drop "query" from the verification lemma
- lem = d_quant.negate();
- // we can short circuit adding the lemma (for sygus stream)
- success = true;
- }
- // In the rare case that the subcall is unknown, we add the verification
- // lemma in the main solver. This should only happen if the quantifier
- // free logic is undecidable.
+ return false;
}
- }
- if (success)
- {
- d_hasSolution = true;
- if (options::sygusStream())
+ else if (r.asSatisfiabilityResult().isSat() != Result::UNSAT)
{
- // if we were successful, we immediately print the current solution.
- // this saves us from introducing a verification lemma and a new guard.
- printAndContinueStream(terms, candidate_values);
- // streaming means now we immediately are looking for a new solution
- d_hasSolution = false;
+ // In the rare case that the subcall is unknown, we simply exclude the
+ // solution, without adding a counterexample point. This should only
+ // happen if the quantifier free logic is undecidable.
+ excludeCurrentSolution(terms, candidate_values);
+ // We should set incomplete, since a "sat" answer should not be
+ // interpreted as "infeasible", which would make a difference in the rare
+ // case where e.g. we had a finite grammar and exhausted the grammar.
+ d_qe->getOutputChannel().setIncomplete();
return false;
}
+ // otherwise we are unsat, and we will process the solution below
}
- lem = getStreamGuardedLemma(lem);
- lems.push_back(lem);
+ // now mark that we have a solution
+ d_hasSolution = true;
+ if (options::sygusStream())
+ {
+ // immediately print the current solution
+ printAndContinueStream(terms, candidate_values);
+ // streaming means now we immediately are looking for a new solution
+ d_hasSolution = false;
+ return false;
+ }
+ // Use lemma to terminate with "unsat", this is justified by the verification
+ // check above, which confirms the synthesis conjecture is solved.
+ lems.push_back(d_quant.negate());
return true;
}
@@ -698,9 +646,9 @@ bool SynthConjecture::checkSideCondition(const std::vector<Node>& cvals) const
return true;
}
-void SynthConjecture::doRefine(std::vector<Node>& lems)
+bool SynthConjecture::doRefine()
{
- Assert(lems.empty());
+ std::vector<Node> lems;
Assert(d_set_ce_sk_vars);
// first, make skolem substitution
@@ -766,6 +714,47 @@ void SynthConjecture::doRefine(std::vector<Node>& lems)
d_set_ce_sk_vars = false;
d_ce_sk_vars.clear();
d_ce_sk_var_mvs.clear();
+
+ // now send the lemmas
+ bool addedLemma = false;
+ for (const Node& lem : lems)
+ {
+ Trace("cegqi-lemma") << "Cegqi::Lemma : candidate refinement : " << lem
+ << std::endl;
+ bool res = d_qe->addLemma(lem);
+ if (res)
+ {
+ ++(d_stats.d_cegqi_lemmas_refine);
+ d_refine_count++;
+ addedLemma = true;
+ }
+ else
+ {
+ Trace("cegqi-warn") << " ...FAILED to add refinement!" << std::endl;
+ }
+ }
+ if (addedLemma)
+ {
+ Trace("sygus-engine-debug") << " ...refine candidate." << std::endl;
+ }
+ else
+ {
+ Trace("sygus-engine-debug") << " ...(warning) failed to refine candidate, "
+ "manually exclude candidate."
+ << std::endl;
+ std::vector<Node> cvals;
+ for (const Node& c : d_candidates)
+ {
+ cvals.push_back(d_cinfo[c].d_inst.back());
+ }
+ // something went wrong, exclude the current candidate
+ excludeCurrentSolution(d_candidates, cvals);
+ // Note this happens when evaluation is incapable of disproving a candidate
+ // for counterexample point c, but satisfiability checking happened to find
+ // the the same point c is indeed a true counterexample. It is sound
+ // to exclude the candidate in this case.
+ }
+ return addedLemma;
}
void SynthConjecture::preregisterConjecture(Node q)
@@ -982,47 +971,6 @@ void SynthConjecture::debugPrint(const char* c)
Trace(c) << " * Counterexample skolems : " << d_ce_sk_vars << std::endl;
}
-Node SynthConjecture::getCurrentStreamGuard() const
-{
- if (d_stream_strategy != nullptr)
- {
- // the stream guard is the current asserted literal of the stream strategy
- Node lit = d_stream_strategy->getAssertedLiteral();
- if (lit.isNull())
- {
- // if none exist, get the first
- lit = d_stream_strategy->getLiteral(0);
- }
- return lit;
- }
- return Node::null();
-}
-
-Node SynthConjecture::getStreamGuardedLemma(Node n) const
-{
- if (options::sygusStream())
- {
- // if we are in streaming mode, we guard with the current stream guard
- Node csg = getCurrentStreamGuard();
- Assert(!csg.isNull());
- return NodeManager::currentNM()->mkNode(kind::OR, csg.negate(), n);
- }
- return n;
-}
-
-SynthConjecture::SygusStreamDecisionStrategy::SygusStreamDecisionStrategy(
- context::Context* satContext, Valuation valuation)
- : DecisionStrategyFmf(satContext, valuation)
-{
-}
-
-Node SynthConjecture::SygusStreamDecisionStrategy::mkLiteral(unsigned i)
-{
- NodeManager* nm = NodeManager::currentNM();
- Node curr_stream_guard = nm->mkSkolem("G_Stream", nm->booleanType());
- return curr_stream_guard;
-}
-
void SynthConjecture::printAndContinueStream(const std::vector<Node>& enums,
const std::vector<Node>& values)
{
@@ -1038,6 +986,8 @@ void SynthConjecture::printAndContinueStream(const std::vector<Node>& enums,
void SynthConjecture::excludeCurrentSolution(const std::vector<Node>& enums,
const std::vector<Node>& values)
{
+ Trace("cegqi-debug") << "Exclude current solution: " << enums << " / "
+ << values << std::endl;
// We will not refine the current candidate solution since it is a solution
// thus, we clear information regarding the current refinement
d_set_ce_sk_vars = false;
@@ -1252,6 +1202,16 @@ bool SynthConjecture::getSynthSolutions(
return true;
}
+void SynthConjecture::recordSolution(std::vector<Node>& vs)
+{
+ Assert(vs.size() == d_candidates.size());
+ d_cinfo.clear();
+ for (unsigned i = 0; i < vs.size(); i++)
+ {
+ d_cinfo[d_candidates[i]].d_inst.push_back(vs[i]);
+ }
+}
+
bool SynthConjecture::getSynthSolutionsInternal(std::vector<Node>& sols,
std::vector<int>& statuses)
{
@@ -1280,7 +1240,7 @@ bool SynthConjecture::getSynthSolutionsInternal(std::vector<Node>& sols,
}
else
{
- Node cprog = getCandidate(i);
+ Node cprog = d_candidates[i];
if (!d_cinfo[cprog].d_inst.empty())
{
// the solution is just the last instantiated term
@@ -1289,7 +1249,7 @@ bool SynthConjecture::getSynthSolutionsInternal(std::vector<Node>& sols,
// check if there was a template
Node sf = d_quant[0][i];
- Node templ = d_ceg_si->getTemplate(sf);
+ Node templ = d_templInfer->getTemplate(sf);
if (!templ.isNull())
{
Trace("cegqi-inv-debug")
@@ -1297,7 +1257,7 @@ bool SynthConjecture::getSynthSolutionsInternal(std::vector<Node>& sols,
// if it was not embedded into the grammar
if (!options::sygusTemplEmbedGrammar())
{
- TNode templa = d_ceg_si->getTemplateArg(sf);
+ TNode templa = d_templInfer->getTemplateArg(sf);
// make the builtin version of the full solution
sol = d_tds->sygusToBuiltin(sol, sol.getType());
Trace("cegqi-inv") << "Builtin version of solution is : " << sol
diff --git a/src/theory/quantifiers/sygus/synth_conjecture.h b/src/theory/quantifiers/sygus/synth_conjecture.h
index 7b63cd96d..7786f57ad 100644
--- a/src/theory/quantifiers/sygus/synth_conjecture.h
+++ b/src/theory/quantifiers/sygus/synth_conjecture.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -33,12 +33,12 @@
#include "theory/quantifiers/sygus/sygus_process_conj.h"
#include "theory/quantifiers/sygus/sygus_repair_const.h"
#include "theory/quantifiers/sygus/sygus_stats.h"
+#include "theory/quantifiers/sygus/template_infer.h"
namespace CVC4 {
namespace theory {
namespace quantifiers {
-class SynthEngine;
class SygusStatistics;
/**
@@ -87,13 +87,10 @@ class SynthConjecture
/** presolve */
void presolve();
/** get original version of conjecture */
- Node getConjecture() { return d_quant; }
+ Node getConjecture() const { return d_quant; }
/** get deep embedding version of conjecture */
- Node getEmbeddedConjecture() { return d_embed_quant; }
+ Node getEmbeddedConjecture() const { return d_embed_quant; }
//-------------------------------for counterexample-guided check/refine
- /** increment the number of times we have successfully done candidate
- * refinement */
- void incrementRefineCount() { d_refine_count++; }
/** whether the conjecture is waiting for a call to doCheck below */
bool needsCheck();
/** whether the conjecture is waiting for a call to doRefine below */
@@ -113,9 +110,24 @@ class SynthConjecture
*/
bool doCheck(std::vector<Node>& lems);
/** do refinement
+ *
* This is step 2(b) of Figure 3 of Reynolds et al CAV 2015.
+ *
+ * This method is run when needsRefinement() returns true, indicating that
+ * the last call to doCheck found a counterexample to the last candidate.
+ *
+ * This method adds a refinement lemma on the output channel of quantifiers
+ * engine. If the refinement lemma is a duplicate, then we manually
+ * exclude the current candidate via excludeCurrentSolution. This should
+ * only occur when the synthesis conjecture for the current candidate fails
+ * to evaluate to false for a given counterexample point, but regardless its
+ * negation is satisfiable for the current candidate and that point. This is
+ * exclusive to theories with partial functions, e.g. (non-linear) division.
+ *
+ * This method returns true if a lemma was added on the output channel, and
+ * false otherwise.
*/
- void doRefine(std::vector<Node>& lems);
+ bool doRefine();
//-------------------------------end for counterexample-guided check/refine
/**
* Prints the synthesis solution to output stream out. This invokes solution
@@ -202,6 +214,8 @@ class SynthConjecture
std::unique_ptr<DecisionStrategy> d_feasible_strategy;
/** single invocation utility */
std::unique_ptr<CegSingleInv> d_ceg_si;
+ /** template inference utility */
+ std::unique_ptr<SygusTemplateInfer> d_templInfer;
/** utility for static preprocessing and analysis of conjectures */
std::unique_ptr<SynthConjectureProcess> d_ceg_proc;
/** grammar utility */
@@ -343,17 +357,8 @@ class SynthConjecture
unsigned d_repair_index;
/** number of times we have called doRefine */
unsigned d_refine_count;
- /** get candidadate */
- Node getCandidate(unsigned int i) { return d_candidates[i]; }
- /** record instantiation (this is used to construct solutions later) */
- void recordInstantiation(std::vector<Node>& vs)
- {
- Assert(vs.size() == d_candidates.size());
- for (unsigned i = 0; i < vs.size(); i++)
- {
- d_cinfo[d_candidates[i]].d_inst.push_back(vs[i]);
- }
- }
+ /** record solution (this is used to construct solutions later) */
+ void recordSolution(std::vector<Node>& vs);
/** get synth solutions internal
*
* This function constructs the body of solutions for all
@@ -375,31 +380,6 @@ class SynthConjecture
bool getSynthSolutionsInternal(std::vector<Node>& sols,
std::vector<int>& status);
//-------------------------------- sygus stream
- /** current stream guard */
- Node d_current_stream_guard;
- /** the decision strategy for streaming solutions */
- class SygusStreamDecisionStrategy : public DecisionStrategyFmf
- {
- public:
- SygusStreamDecisionStrategy(context::Context* satContext,
- Valuation valuation);
- /** make literal */
- Node mkLiteral(unsigned i) override;
- /** identify */
- std::string identify() const override
- {
- return std::string("sygus_stream");
- }
- };
- std::unique_ptr<SygusStreamDecisionStrategy> d_stream_strategy;
- /** get current stream guard */
- Node getCurrentStreamGuard() const;
- /** get stream guarded lemma
- *
- * If sygusStream is enabled, this returns ( G V n ) where G is the guard
- * returned by getCurrentStreamGuard, otherwise this returns n.
- */
- Node getStreamGuardedLemma(Node n) const;
/**
* Prints the current synthesis solution to the output stream indicated by
* the Options object, send a lemma blocking the current solution to the
diff --git a/src/theory/quantifiers/sygus/synth_engine.cpp b/src/theory/quantifiers/sygus/synth_engine.cpp
index ea08edc2f..3e40d6654 100644
--- a/src/theory/quantifiers/sygus/synth_engine.cpp
+++ b/src/theory/quantifiers/sygus/synth_engine.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,7 +21,6 @@
#include "theory/quantifiers/sygus/term_database_sygus.h"
#include "theory/quantifiers/term_util.h"
#include "theory/quantifiers_engine.h"
-#include "theory/smt_engine_subsolver.h"
#include "theory/theory_engine.h"
using namespace CVC4::kind;
@@ -32,7 +31,10 @@ namespace theory {
namespace quantifiers {
SynthEngine::SynthEngine(QuantifiersEngine* qe, context::Context* c)
- : QuantifiersModule(qe), d_tds(qe->getTermDatabaseSygus())
+ : QuantifiersModule(qe),
+ d_tds(qe->getTermDatabaseSygus()),
+ d_conj(nullptr),
+ d_sqp(qe)
{
d_conjs.push_back(std::unique_ptr<SynthConjecture>(
new SynthConjecture(d_quantEngine, d_statistics)));
@@ -143,125 +145,14 @@ void SynthEngine::assignConjecture(Node q)
Trace("sygus-engine") << "SynthEngine::assignConjecture " << q << std::endl;
if (options::sygusQePreproc())
{
- // the following does quantifier elimination as a preprocess step
- // for "non-ground single invocation synthesis conjectures":
- // exists f. forall xy. P[ f(x), x, y ]
- // We run quantifier elimination:
- // exists y. P[ z, x, y ] ----> Q[ z, x ]
- // Where we replace the original conjecture with:
- // exists f. forall x. Q[ f(x), x ]
- // For more details, see Example 6 of Reynolds et al. SYNT 2017.
- Node body = q[1];
- if (body.getKind() == NOT && body[0].getKind() == FORALL)
+ Node lem = d_sqp.preprocess(q);
+ if (!lem.isNull())
{
- body = body[0][1];
- }
- NodeManager* nm = NodeManager::currentNM();
- Trace("cegqi-qep") << "Compute single invocation for " << q << "..."
- << std::endl;
- quantifiers::SingleInvocationPartition sip;
- std::vector<Node> funcs0;
- funcs0.insert(funcs0.end(), q[0].begin(), q[0].end());
- sip.init(funcs0, body);
- Trace("cegqi-qep") << "...finished, got:" << std::endl;
- sip.debugPrint("cegqi-qep");
-
- if (!sip.isPurelySingleInvocation() && sip.isNonGroundSingleInvocation())
- {
- // create new smt engine to do quantifier elimination
- std::unique_ptr<SmtEngine> smt_qe;
- initializeSubsolver(smt_qe);
- Trace("cegqi-qep") << "Property is non-ground single invocation, run "
- "QE to obtain single invocation."
- << std::endl;
- // partition variables
- std::vector<Node> all_vars;
- sip.getAllVariables(all_vars);
- std::vector<Node> si_vars;
- sip.getSingleInvocationVariables(si_vars);
- std::vector<Node> qe_vars;
- std::vector<Node> nqe_vars;
- for (unsigned i = 0, size = all_vars.size(); i < size; i++)
- {
- Node v = all_vars[i];
- if (std::find(si_vars.begin(), si_vars.end(), v) == si_vars.end())
- {
- qe_vars.push_back(v);
- }
- else
- {
- nqe_vars.push_back(v);
- }
- }
- std::vector<Node> orig;
- std::vector<Node> subs;
- // skolemize non-qe variables
- for (unsigned i = 0, size = nqe_vars.size(); i < size; i++)
- {
- Node k = nm->mkSkolem(
- "k", nqe_vars[i].getType(), "qe for non-ground single invocation");
- orig.push_back(nqe_vars[i]);
- subs.push_back(k);
- Trace("cegqi-qep") << " subs : " << nqe_vars[i] << " -> " << k
+ Trace("cegqi-lemma") << "Cegqi::Lemma : qe-preprocess : " << lem
<< std::endl;
- }
- std::vector<Node> funcs1;
- sip.getFunctions(funcs1);
- for (unsigned i = 0, size = funcs1.size(); i < size; i++)
- {
- Node f = funcs1[i];
- Node fi = sip.getFunctionInvocationFor(f);
- Node fv = sip.getFirstOrderVariableForFunction(f);
- Assert(!fi.isNull());
- orig.push_back(fi);
- Node k =
- nm->mkSkolem("k",
- fv.getType(),
- "qe for function in non-ground single invocation");
- subs.push_back(k);
- Trace("cegqi-qep") << " subs : " << fi << " -> " << k << std::endl;
- }
- Node conj_se_ngsi = sip.getFullSpecification();
- Trace("cegqi-qep") << "Full specification is " << conj_se_ngsi
- << std::endl;
- Node conj_se_ngsi_subs = conj_se_ngsi.substitute(
- orig.begin(), orig.end(), subs.begin(), subs.end());
- Assert(!qe_vars.empty());
- conj_se_ngsi_subs = nm->mkNode(EXISTS,
- nm->mkNode(BOUND_VAR_LIST, qe_vars),
- conj_se_ngsi_subs.negate());
-
- Trace("cegqi-qep") << "Run quantifier elimination on "
- << conj_se_ngsi_subs << std::endl;
- Expr qe_res = smt_qe->doQuantifierElimination(
- conj_se_ngsi_subs.toExpr(), true, false);
- Trace("cegqi-qep") << "Result : " << qe_res << std::endl;
-
- // create single invocation conjecture, if QE was successful
- Node qe_res_n = Node::fromExpr(qe_res);
- if (!expr::hasBoundVar(qe_res_n))
- {
- qe_res_n = qe_res_n.substitute(
- subs.begin(), subs.end(), orig.begin(), orig.end());
- if (!nqe_vars.empty())
- {
- qe_res_n = nm->mkNode(
- EXISTS, nm->mkNode(BOUND_VAR_LIST, nqe_vars), qe_res_n);
- }
- Assert(q.getNumChildren() == 3);
- qe_res_n = nm->mkNode(FORALL, q[0], qe_res_n, q[2]);
- Trace("cegqi-qep") << "Converted conjecture after QE : " << qe_res_n
- << std::endl;
- qe_res_n = Rewriter::rewrite(qe_res_n);
- Node nq = qe_res_n;
- // must assert it is equivalent to the original
- Node lem = q.eqNode(nq);
- Trace("cegqi-lemma")
- << "Cegqi::Lemma : qe-preprocess : " << lem << std::endl;
- d_quantEngine->getOutputChannel().lemma(lem);
- // we've reduced the original to a preprocessed version, return
- return;
- }
+ d_quantEngine->getOutputChannel().lemma(lem);
+ // we've reduced the original to a preprocessed version, return
+ return;
}
}
// allocate a new synthesis conjecture if not assigned
@@ -305,8 +196,6 @@ void SynthEngine::registerQuantifier(Node q)
bool SynthEngine::checkConjecture(SynthConjecture* conj)
{
- Node q = conj->getEmbeddedConjecture();
- Node aq = conj->getConjecture();
if (Trace.isOn("sygus-engine-debug"))
{
conj->debugPrint("sygus-engine-debug");
@@ -341,46 +230,14 @@ bool SynthEngine::checkConjecture(SynthConjecture* conj)
<< " ...check for counterexample." << std::endl;
return true;
}
- else
- {
- if (conj->needsRefinement())
- {
- // immediately go to refine candidate
- return checkConjecture(conj);
- }
- }
- return ret;
- }
- else
- {
- Trace("sygus-engine-debug")
- << " *** Refine candidate phase..." << std::endl;
- std::vector<Node> rlems;
- conj->doRefine(rlems);
- bool addedLemma = false;
- for (unsigned i = 0; i < rlems.size(); i++)
- {
- Node lem = rlems[i];
- Trace("cegqi-lemma") << "Cegqi::Lemma : candidate refinement : " << lem
- << std::endl;
- bool res = d_quantEngine->addLemma(lem);
- if (res)
- {
- ++(d_statistics.d_cegqi_lemmas_refine);
- conj->incrementRefineCount();
- addedLemma = true;
- }
- else
- {
- Trace("cegqi-warn") << " ...FAILED to add refinement!" << std::endl;
- }
- }
- if (addedLemma)
+ if (!conj->needsRefinement())
{
- Trace("sygus-engine-debug") << " ...refine candidate." << std::endl;
+ return ret;
}
+ // otherwise, immediately go to refine candidate
}
- return true;
+ Trace("sygus-engine-debug") << " *** Refine candidate phase..." << std::endl;
+ return conj->doRefine();
}
void SynthEngine::printSynthSolution(std::ostream& out)
diff --git a/src/theory/quantifiers/sygus/synth_engine.h b/src/theory/quantifiers/sygus/synth_engine.h
index c5e97f4ea..25981748e 100644
--- a/src/theory/quantifiers/sygus/synth_engine.h
+++ b/src/theory/quantifiers/sygus/synth_engine.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,6 +20,7 @@
#include "context/cdhashmap.h"
#include "theory/quantifiers/quant_util.h"
+#include "theory/quantifiers/sygus/sygus_qe_preproc.h"
#include "theory/quantifiers/sygus/sygus_stats.h"
#include "theory/quantifiers/sygus/synth_conjecture.h"
@@ -86,6 +87,10 @@ class SynthEngine : public QuantifiersModule
* preregisterAssertion.
*/
SynthConjecture* d_conj;
+ /**
+ * The quantifier elimination preprocess module.
+ */
+ SygusQePreproc d_sqp;
/** The statistics */
SygusStatistics d_statistics;
/** assign quantified formula q as a conjecture
diff --git a/src/theory/quantifiers/sygus/template_infer.cpp b/src/theory/quantifiers/sygus/template_infer.cpp
new file mode 100644
index 000000000..2f6964f3a
--- /dev/null
+++ b/src/theory/quantifiers/sygus/template_infer.cpp
@@ -0,0 +1,205 @@
+/********************* */
+/*! \file template_infer.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Mathias Preiner, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief utility for processing single invocation synthesis conjectures
+ **
+ **/
+#include "theory/quantifiers/sygus/template_infer.h"
+
+#include "options/quantifiers_options.h"
+#include "theory/quantifiers/sygus/sygus_grammar_cons.h"
+#include "theory/quantifiers/term_util.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+void SygusTemplateInfer::initialize(Node q)
+{
+ Assert(d_quant.isNull());
+ Assert(q.getKind() == FORALL);
+ d_quant = q;
+ // We are processing without single invocation techniques, now check if
+ // we should fix an invariant template (post-condition strengthening or
+ // pre-condition weakening).
+ options::SygusInvTemplMode tmode = options::sygusInvTemplMode();
+ if (tmode != options::SygusInvTemplMode::NONE)
+ {
+ // currently only works for single predicate synthesis
+ if (q[0].getNumChildren() > 1 || !q[0][0].getType().isPredicate())
+ {
+ tmode = options::SygusInvTemplMode::NONE;
+ }
+ else if (!options::sygusInvTemplWhenSyntax())
+ {
+ // only use invariant templates if no syntactic restrictions
+ if (CegGrammarConstructor::hasSyntaxRestrictions(q))
+ {
+ tmode = options::SygusInvTemplMode::NONE;
+ }
+ }
+ }
+
+ if (tmode == options::SygusInvTemplMode::NONE)
+ {
+ // not processing invariant templates
+ return;
+ }
+
+ Node qq;
+ if (q[1].getKind() == NOT && q[1][0].getKind() == FORALL)
+ {
+ qq = q[1][0][1];
+ }
+ else
+ {
+ qq = TermUtil::simpleNegate(q[1]);
+ }
+ if (qq.isConst())
+ {
+ // trivial, do not use transition inference
+ return;
+ }
+
+ // if we are doing invariant templates, then construct the template
+ Trace("sygus-si") << "- Do transition inference..." << std::endl;
+ d_ti.process(qq, q[0][0]);
+ Trace("cegqi-inv") << std::endl;
+ Node prog = d_ti.getFunction();
+ if (!d_ti.isComplete())
+ {
+ // the invariant could not be inferred
+ return;
+ }
+ Assert(prog == q[0][0]);
+ NodeManager* nm = NodeManager::currentNM();
+ // map the program back via non-single invocation map
+ std::vector<Node> prog_templ_vars;
+ d_ti.getVariables(prog_templ_vars);
+ d_trans_pre[prog] = d_ti.getPreCondition();
+ d_trans_post[prog] = d_ti.getPostCondition();
+ Trace("cegqi-inv") << " precondition : " << d_trans_pre[prog] << std::endl;
+ Trace("cegqi-inv") << " postcondition : " << d_trans_post[prog] << std::endl;
+
+ // construct template argument
+ TypeNode atn = prog.getType();
+ if (atn.isFunction())
+ {
+ atn = atn.getRangeType();
+ }
+ d_templ_arg[prog] = nm->mkSkolem("I", atn);
+
+ // construct template
+ Node templ;
+ if (options::sygusInvAutoUnfold())
+ {
+ if (d_ti.isComplete())
+ {
+ Trace("cegqi-inv-auto-unfold")
+ << "Automatic deterministic unfolding... " << std::endl;
+ // auto-unfold
+ DetTrace dt;
+ int init_dt = d_ti.initializeTrace(dt);
+ if (init_dt == 0)
+ {
+ Trace("cegqi-inv-auto-unfold") << " Init : ";
+ dt.print("cegqi-inv-auto-unfold");
+ Trace("cegqi-inv-auto-unfold") << std::endl;
+ unsigned counter = 0;
+ unsigned status = 0;
+ while (counter < 100 && status == 0)
+ {
+ status = d_ti.incrementTrace(dt);
+ counter++;
+ Trace("cegqi-inv-auto-unfold") << " #" << counter << " : ";
+ dt.print("cegqi-inv-auto-unfold");
+ Trace("cegqi-inv-auto-unfold")
+ << "...status = " << status << std::endl;
+ }
+ if (status == 1)
+ {
+ // we have a trivial invariant
+ templ = d_ti.constructFormulaTrace(dt);
+ Trace("cegqi-inv") << "By finite deterministic terminating trace, a "
+ "solution invariant is : "
+ << std::endl;
+ Trace("cegqi-inv") << " " << templ << std::endl;
+ // this should be unnecessary
+ templ = nm->mkNode(AND, templ, d_templ_arg[prog]);
+ }
+ }
+ else
+ {
+ Trace("cegqi-inv-auto-unfold") << "...failed initialize." << std::endl;
+ }
+ }
+ }
+ Trace("cegqi-inv") << "Make the template... " << tmode << " " << templ
+ << std::endl;
+ if (templ.isNull())
+ {
+ if (tmode == options::SygusInvTemplMode::PRE)
+ {
+ templ = nm->mkNode(OR, d_trans_pre[prog], d_templ_arg[prog]);
+ }
+ else
+ {
+ Assert(tmode == options::SygusInvTemplMode::POST);
+ templ = nm->mkNode(AND, d_trans_post[prog], d_templ_arg[prog]);
+ }
+ }
+ Trace("cegqi-inv") << " template (pre-substitution) : " << templ
+ << std::endl;
+ Assert(!templ.isNull());
+
+ // get the variables
+ Node sfvl = CegGrammarConstructor::getSygusVarList(prog);
+ if (!sfvl.isNull())
+ {
+ std::vector<Node> prog_vars(sfvl.begin(), sfvl.end());
+ // subsitute the template arguments
+ Trace("cegqi-inv") << "vars : " << prog_templ_vars << " " << prog_vars
+ << std::endl;
+ Assert(prog_templ_vars.size() == prog_vars.size());
+ templ = templ.substitute(prog_templ_vars.begin(),
+ prog_templ_vars.end(),
+ prog_vars.begin(),
+ prog_vars.end());
+ }
+ Trace("cegqi-inv") << " template : " << templ << std::endl;
+ d_templ[prog] = templ;
+}
+
+Node SygusTemplateInfer::getTemplate(Node prog) const
+{
+ std::map<Node, Node>::const_iterator tmpl = d_templ.find(prog);
+ if (tmpl != d_templ.end())
+ {
+ return tmpl->second;
+ }
+ return Node::null();
+}
+
+Node SygusTemplateInfer::getTemplateArg(Node prog) const
+{
+ std::map<Node, Node>::const_iterator tmpla = d_templ_arg.find(prog);
+ if (tmpla != d_templ_arg.end())
+ {
+ return tmpla->second;
+ }
+ return Node::null();
+}
+
+} // namespace quantifiers
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/quantifiers/sygus/template_infer.h b/src/theory/quantifiers/sygus/template_infer.h
new file mode 100644
index 000000000..97879dc22
--- /dev/null
+++ b/src/theory/quantifiers/sygus/template_infer.h
@@ -0,0 +1,76 @@
+/********************* */
+/*! \file template_infer.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief utility for inferring templates for invariant problems
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__QUANTIFIERS__SYGUS__TEMPLATE_INFER_H
+#define CVC4__THEORY__QUANTIFIERS__SYGUS__TEMPLATE_INFER_H
+
+#include <map>
+
+#include "expr/node.h"
+#include "theory/quantifiers/sygus/transition_inference.h"
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
+
+/**
+ * This class infers templates for an invariant-to-synthesize based on the
+ * template mode. It uses the transition inference to choose a template.
+ */
+class SygusTemplateInfer
+{
+ public:
+ SygusTemplateInfer() {}
+ ~SygusTemplateInfer() {}
+ /**
+ * Initialize this class for synthesis conjecture q. If applicable, the
+ * templates for functions-to-synthesize for q are accessible by the
+ * calls below afterwards.
+ */
+ void initialize(Node q);
+ /**
+ * Get template for program prog. This returns a term of the form t[x] where
+ * x is the template argument (see below)
+ */
+ Node getTemplate(Node prog) const;
+ /**
+ * Get the template argument for program prog. This is a variable which
+ * indicates the position of the function/predicate to synthesize.
+ */
+ Node getTemplateArg(Node prog) const;
+
+ private:
+ /** The quantified formula we initialized with */
+ Node d_quant;
+ /** transition relation pre and post version per function to synthesize */
+ std::map<Node, Node> d_trans_pre;
+ std::map<Node, Node> d_trans_post;
+ /** the template for each function to synthesize */
+ std::map<Node, Node> d_templ;
+ /**
+ * The template argument for each function to synthesize (occurs in exactly
+ * one position of its template)
+ */
+ std::map<Node, Node> d_templ_arg;
+ /** transition inference module */
+ TransitionInference d_ti;
+};
+
+} // namespace quantifiers
+} // namespace theory
+} /* namespace CVC4 */
+
+#endif
diff --git a/src/theory/quantifiers/sygus/term_database_sygus.cpp b/src/theory/quantifiers/sygus/term_database_sygus.cpp
index c2a02e715..ccc23f109 100644
--- a/src/theory/quantifiers/sygus/term_database_sygus.cpp
+++ b/src/theory/quantifiers/sygus/term_database_sygus.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -89,7 +89,7 @@ TNode TermDbSygus::getFreeVar( TypeNode tn, int i, bool useSygusType ) {
ss << "fv_" << tn << "_" << i;
}
Assert(!vtn.isNull());
- Node v = nm->mkSkolem(ss.str(), vtn, "for sygus invariance testing");
+ Node v = nm->mkBoundVar(ss.str(), vtn);
// store its id, which is unique per builtin type, regardless of how it is
// otherwise cached.
d_fvId[v] = d_fvTypeIdCounter[builtinType];
@@ -731,6 +731,11 @@ void TermDbSygus::toStreamSygus(const char* c, Node n)
void TermDbSygus::toStreamSygus(std::ostream& out, Node n)
{
+ if (n.isNull())
+ {
+ out << n;
+ return;
+ }
// use external conversion
out << datatypes::utils::sygusToBuiltin(n, true);
}
diff --git a/src/theory/quantifiers/sygus/term_database_sygus.h b/src/theory/quantifiers/sygus/term_database_sygus.h
index 921b08de5..e082cf15b 100644
--- a/src/theory/quantifiers/sygus/term_database_sygus.h
+++ b/src/theory/quantifiers/sygus/term_database_sygus.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/transition_inference.cpp b/src/theory/quantifiers/sygus/transition_inference.cpp
index afc223f26..9f57f63f8 100644
--- a/src/theory/quantifiers/sygus/transition_inference.cpp
+++ b/src/theory/quantifiers/sygus/transition_inference.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/transition_inference.h b/src/theory/quantifiers/sygus/transition_inference.h
index 5d6e16e81..bee4ba00c 100644
--- a/src/theory/quantifiers/sygus/transition_inference.h
+++ b/src/theory/quantifiers/sygus/transition_inference.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/type_info.cpp b/src/theory/quantifiers/sygus/type_info.cpp
index ba5b23866..d44d2eda8 100644
--- a/src/theory/quantifiers/sygus/type_info.cpp
+++ b/src/theory/quantifiers/sygus/type_info.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/type_info.h b/src/theory/quantifiers/sygus/type_info.h
index c2b122a15..ee4abcb5d 100644
--- a/src/theory/quantifiers/sygus/type_info.h
+++ b/src/theory/quantifiers/sygus/type_info.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/type_node_id_trie.cpp b/src/theory/quantifiers/sygus/type_node_id_trie.cpp
index 09bb51a2a..1e8715ae3 100644
--- a/src/theory/quantifiers/sygus/type_node_id_trie.cpp
+++ b/src/theory/quantifiers/sygus/type_node_id_trie.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus/type_node_id_trie.h b/src/theory/quantifiers/sygus/type_node_id_trie.h
index 098acf1f3..698761034 100644
--- a/src/theory/quantifiers/sygus/type_node_id_trie.h
+++ b/src/theory/quantifiers/sygus/type_node_id_trie.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus_inst.cpp b/src/theory/quantifiers/sygus_inst.cpp
index 672f3937a..119cd925c 100644
--- a/src/theory/quantifiers/sygus_inst.cpp
+++ b/src/theory/quantifiers/sygus_inst.cpp
@@ -5,7 +5,7 @@
** Mathias Preiner, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,6 +18,7 @@
#include <unordered_set>
#include "expr/node_algorithm.h"
+#include "theory/bv/theory_bv_utils.h"
#include "theory/datatypes/sygus_datatype_utils.h"
#include "theory/quantifiers/sygus/sygus_enumerator.h"
#include "theory/quantifiers/sygus/sygus_grammar_cons.h"
@@ -29,10 +30,161 @@ namespace CVC4 {
namespace theory {
namespace quantifiers {
+namespace {
+
+/**
+ * Collect maximal ground terms with type tn in node n.
+ *
+ * @param n: Node to traverse.
+ * @param tn: Collects only terms with type tn.
+ * @param terms: Collected terms.
+ * @param cache: Caches visited nodes.
+ * @param skip_quant: Do not traverse quantified formulas (skip quantifiers).
+ */
+void getMaxGroundTerms(TNode n,
+ TypeNode tn,
+ std::unordered_set<Node, NodeHashFunction>& terms,
+ std::unordered_set<TNode, TNodeHashFunction>& cache,
+ bool skip_quant = false)
+{
+ if (options::sygusInstTermSel() != options::SygusInstTermSelMode::MAX
+ && options::sygusInstTermSel() != options::SygusInstTermSelMode::BOTH)
+ {
+ return;
+ }
+
+ Trace("sygus-inst-term") << "Find maximal terms with type " << tn
+ << " in: " << n << std::endl;
+
+ Node cur;
+ std::vector<TNode> visit;
+
+ visit.push_back(n);
+ do
+ {
+ cur = visit.back();
+ visit.pop_back();
+
+ if (cache.find(cur) != cache.end())
+ {
+ continue;
+ }
+ cache.insert(cur);
+
+ if (expr::hasBoundVar(cur) || cur.getType() != tn)
+ {
+ if (!skip_quant || cur.getKind() != kind::FORALL)
+ {
+ visit.insert(visit.end(), cur.begin(), cur.end());
+ }
+ }
+ else
+ {
+ terms.insert(cur);
+ Trace("sygus-inst-term") << " found: " << cur << std::endl;
+ }
+ } while (!visit.empty());
+}
+
+/*
+ * Collect minimal ground terms with type tn in node n.
+ *
+ * @param n: Node to traverse.
+ * @param tn: Collects only terms with type tn.
+ * @param terms: Collected terms.
+ * @param cache: Caches visited nodes and flags indicating whether a minimal
+ * term was already found in a subterm.
+ * @param skip_quant: Do not traverse quantified formulas (skip quantifiers).
+ */
+void getMinGroundTerms(
+ TNode n,
+ TypeNode tn,
+ std::unordered_set<Node, NodeHashFunction>& terms,
+ std::unordered_map<TNode, std::pair<bool, bool>, TNodeHashFunction>& cache,
+ bool skip_quant = false)
+{
+ if (options::sygusInstTermSel() != options::SygusInstTermSelMode::MIN
+ && options::sygusInstTermSel() != options::SygusInstTermSelMode::BOTH)
+ {
+ return;
+ }
+
+ Trace("sygus-inst-term") << "Find minimal terms with type " << tn
+ << " in: " << n << std::endl;
+
+ Node cur;
+ std::vector<TNode> visit;
+
+ visit.push_back(n);
+ do
+ {
+ cur = visit.back();
+ visit.pop_back();
+
+ auto it = cache.find(cur);
+ if (it == cache.end())
+ {
+ cache.emplace(cur, std::make_pair(false, false));
+ if (!skip_quant || cur.getKind() != kind::FORALL)
+ {
+ visit.push_back(cur);
+ visit.insert(visit.end(), cur.begin(), cur.end());
+ }
+ }
+ /* up-traversal */
+ else if (!it->second.first)
+ {
+ bool found_min_term = false;
+
+ /* Check if we found a minimal term in one of the children. */
+ for (const Node& c : cur)
+ {
+ found_min_term |= cache[c].second;
+ if (found_min_term) break;
+ }
+
+ /* If we haven't found a minimal term yet, add this term if it has the
+ * right type. */
+ if (cur.getType() == tn && !expr::hasBoundVar(cur) && !found_min_term)
+ {
+ terms.insert(cur);
+ found_min_term = true;
+ Trace("sygus-inst-term") << " found: " << cur << std::endl;
+ }
+
+ it->second.first = true;
+ it->second.second = found_min_term;
+ }
+ } while (!visit.empty());
+}
+
+/*
+ * Add special values for a given type.
+ *
+ * @param tn: The type node.
+ * @param extra_cons: A map of TypeNode to constants, which are added in
+ * addition to the default grammar.
+ */
+void addSpecialValues(
+ const TypeNode& tn,
+ std::map<TypeNode, std::unordered_set<Node, NodeHashFunction>>& extra_cons)
+{
+ if (tn.isBitVector())
+ {
+ uint32_t size = tn.getBitVectorSize();
+ extra_cons[tn].insert(bv::utils::mkOnes(size));
+ extra_cons[tn].insert(bv::utils::mkMinSigned(size));
+ extra_cons[tn].insert(bv::utils::mkMaxSigned(size));
+ }
+}
+
+} // namespace
+
SygusInst::SygusInst(QuantifiersEngine* qe)
: QuantifiersModule(qe),
- d_lemma_cache(qe->getUserContext()),
- d_ce_lemma_added(qe->getUserContext())
+ d_ce_lemma_added(qe->getUserContext()),
+ d_global_terms(qe->getUserContext()),
+ d_notified_assertions(qe->getUserContext())
{
}
@@ -92,14 +244,20 @@ void SygusInst::check(Theory::Effort e, QEffort quant_e)
TermDbSygus* db = d_quantEngine->getTermDatabaseSygus();
SygusExplain syexplain(db);
NodeManager* nm = NodeManager::currentNM();
+ options::SygusInstMode mode = options::sygusInstMode();
for (const Node& q : d_active_quant)
{
- std::vector<Node> terms;
- for (const Node& var : q[0])
+ const std::vector<Node>& inst_constants = d_inst_constants.at(q);
+ const std::vector<Node>& dt_evals = d_var_eval.at(q);
+ Assert(inst_constants.size() == dt_evals.size());
+ Assert(inst_constants.size() == q[0].getNumChildren());
+
+ std::vector<Node> terms, eval_unfold_lemmas;
+ for (size_t i = 0, size = q[0].getNumChildren(); i < size; ++i)
{
- Node dt_var = d_inst_constants[var];
- Node dt_eval = d_var_eval[var];
+ Node dt_var = inst_constants[i];
+ Node dt_eval = dt_evals[i];
Node value = model->getValue(dt_var);
Node t = datatypes::utils::sygusToBuiltin(value);
terms.push_back(t);
@@ -117,22 +275,43 @@ void SygusInst::check(Theory::Effort e, QEffort quant_e)
exp.size() == 1 ? exp[0] : nm->mkNode(kind::AND, exp),
dt_eval.eqNode(t));
}
+ eval_unfold_lemmas.push_back(lem);
+ }
- if (d_lemma_cache.find(lem) == d_lemma_cache.end())
+ if (mode == options::SygusInstMode::PRIORITY_INST)
+ {
+ if (!inst->addInstantiation(q, terms))
{
- Trace("sygus-inst") << "Evaluation unfolding: " << lem << std::endl;
- d_quantEngine->addLemma(lem, false);
- d_lemma_cache.insert(lem);
+ sendEvalUnfoldLemmas(eval_unfold_lemmas);
}
}
-
- if (inst->addInstantiation(q, terms))
+ else if (mode == options::SygusInstMode::PRIORITY_EVAL)
{
- Trace("sygus-inst") << "Instantiate " << q << std::endl;
+ if (!sendEvalUnfoldLemmas(eval_unfold_lemmas))
+ {
+ inst->addInstantiation(q, terms);
+ }
+ }
+ else
+ {
+ Assert(mode == options::SygusInstMode::INTERLEAVE);
+ inst->addInstantiation(q, terms);
+ sendEvalUnfoldLemmas(eval_unfold_lemmas);
}
}
}
+bool SygusInst::sendEvalUnfoldLemmas(const std::vector<Node>& lemmas)
+{
+ bool added_lemma = false;
+ for (const Node& lem : lemmas)
+ {
+ Trace("sygus-inst") << "Evaluation unfolding: " << lem << std::endl;
+ added_lemma |= d_quantEngine->addLemma(lem);
+ }
+ return added_lemma;
+}
+
bool SygusInst::checkCompleteFor(Node q)
{
return d_inactive_quant.find(q) != d_inactive_quant.end();
@@ -149,14 +328,79 @@ void SygusInst::registerQuantifier(Node q)
std::map<TypeNode, std::unordered_set<Node, NodeHashFunction>> include_cons;
std::unordered_set<Node, NodeHashFunction> term_irrelevant;
- /* Collect extra symbols in 'q' to be used in the grammar. */
- std::unordered_set<Node, NodeHashFunction> syms;
- expr::getSymbols(q, syms);
- for (const Node& var : syms)
+ /* Collect relevant local ground terms for each variable type. */
+ if (options::sygusInstScope() == options::SygusInstScope::IN
+ || options::sygusInstScope() == options::SygusInstScope::BOTH)
+ {
+ std::unordered_map<TypeNode,
+ std::unordered_set<Node, NodeHashFunction>,
+ TypeNodeHashFunction>
+ relevant_terms;
+ for (const Node& var : q[0])
+ {
+ TypeNode tn = var.getType();
+
+ /* Collect relevant ground terms for type tn. */
+ if (relevant_terms.find(tn) == relevant_terms.end())
+ {
+ std::unordered_set<Node, NodeHashFunction> terms;
+ std::unordered_set<TNode, TNodeHashFunction> cache_max;
+ std::unordered_map<TNode, std::pair<bool, bool>, TNodeHashFunction>
+ cache_min;
+
+ getMinGroundTerms(q, tn, terms, cache_min);
+ getMaxGroundTerms(q, tn, terms, cache_max);
+ relevant_terms.emplace(tn, terms);
+ }
+
+ /* Add relevant ground terms to grammar. */
+ auto& terms = relevant_terms[tn];
+ for (const auto& t : terms)
+ {
+ TypeNode ttn = t.getType();
+ extra_cons[ttn].insert(t);
+ Trace("sygus-inst") << "Adding (local) extra cons: " << t << std::endl;
+ }
+ }
+ }
+
+ /* Collect relevant global ground terms for each variable type. */
+ if (options::sygusInstScope() == options::SygusInstScope::OUT
+ || options::sygusInstScope() == options::SygusInstScope::BOTH)
{
- TypeNode tn = var.getType();
- extra_cons[tn].insert(var);
- Trace("sygus-inst") << "Found symbol: " << var << std::endl;
+ for (const Node& var : q[0])
+ {
+ TypeNode tn = var.getType();
+
+ /* Collect relevant ground terms for type tn. */
+ if (d_global_terms.find(tn) == d_global_terms.end())
+ {
+ std::unordered_set<Node, NodeHashFunction> terms;
+ std::unordered_set<TNode, TNodeHashFunction> cache_max;
+ std::unordered_map<TNode, std::pair<bool, bool>, TNodeHashFunction>
+ cache_min;
+
+ for (const Node& a : d_notified_assertions)
+ {
+ getMinGroundTerms(a, tn, terms, cache_min, true);
+ getMaxGroundTerms(a, tn, terms, cache_max, true);
+ }
+ d_global_terms.insert(tn, terms);
+ }
+
+ /* Add relevant ground terms to grammar. */
+ auto it = d_global_terms.find(tn);
+ if (it != d_global_terms.end())
+ {
+ for (const auto& t : (*it).second)
+ {
+ TypeNode ttn = t.getType();
+ extra_cons[ttn].insert(t);
+ Trace("sygus-inst")
+ << "Adding (global) extra cons: " << t << std::endl;
+ }
+ }
+ }
}
/* Construct grammar for each bound variable of 'q'. */
@@ -164,6 +408,7 @@ void SygusInst::registerQuantifier(Node q)
std::vector<TypeNode> types;
for (const Node& var : q[0])
{
+ addSpecialValues(var.getType(), extra_cons);
TypeNode tn = CegGrammarConstructor::mkSygusDefaultType(var.getType(),
Node(),
var.toString(),
@@ -190,6 +435,14 @@ void SygusInst::preRegisterQuantifier(Node q)
addCeLemma(q);
}
+void SygusInst::ppNotifyAssertions(const std::vector<Node>& assertions)
+{
+ for (const Node& a : assertions)
+ {
+ d_notified_assertions.insert(a);
+ }
+}
+
/*****************************************************************************/
/* private methods */
/*****************************************************************************/
@@ -213,6 +466,10 @@ void SygusInst::registerCeLemma(Node q, std::vector<TypeNode>& types)
{
Assert(q[0].getNumChildren() == types.size());
Assert(d_ce_lemmas.find(q) == d_ce_lemmas.end());
+ Assert(d_inst_constants.find(q) == d_inst_constants.end());
+ Assert(d_var_eval.find(q) == d_var_eval.end());
+
+ Trace("sygus-inst") << "Register CE Lemma for " << q << std::endl;
/* Generate counterexample lemma for 'q'. */
NodeManager* nm = NodeManager::currentNM();
@@ -221,8 +478,8 @@ void SygusInst::registerCeLemma(Node q, std::vector<TypeNode>& types)
/* For each variable x_i of \forall x_i . P[x_i], create a fresh datatype
* instantiation constant ic_i with type types[i] and wrap each ic_i in
* DT_SYGUS_EVAL(ic_i), which will be used to instantiate x_i. */
- std::vector<Node> vars;
std::vector<Node> evals;
+ std::vector<Node> inst_constants;
for (size_t i = 0, size = types.size(); i < size; ++i)
{
TypeNode tn = types[i];
@@ -232,6 +489,7 @@ void SygusInst::registerCeLemma(Node q, std::vector<TypeNode>& types)
Node ic = nm->mkInstConstant(tn);
InstConstantAttribute ica;
ic.setAttribute(ica, q);
+ Trace("sygus-inst") << "Create " << ic << " for " << var << std::endl;
db->registerEnumerator(ic, ic, nullptr, ROLE_ENUM_MULTI_SOLUTION);
@@ -243,13 +501,13 @@ void SygusInst::registerCeLemma(Node q, std::vector<TypeNode>& types)
}
Node eval = nm->mkNode(kind::DT_SYGUS_EVAL, args);
- d_inst_constants.emplace(std::make_pair(var, ic));
- d_var_eval.emplace(std::make_pair(var, eval));
-
- vars.push_back(var);
+ inst_constants.push_back(ic);
evals.push_back(eval);
}
+ d_inst_constants.emplace(q, inst_constants);
+ d_var_eval.emplace(q, evals);
+
Node lit = getCeLiteral(q);
d_quantEngine->addRequirePhase(lit, true);
@@ -264,12 +522,12 @@ void SygusInst::registerCeLemma(Node q, std::vector<TypeNode>& types)
d_quantEngine->getValuation());
d_dstrat[q].reset(ds);
- d_quantEngine->getTheoryEngine()->getDecisionManager()->registerStrategy(
+ d_quantEngine->getDecisionManager()->registerStrategy(
DecisionManager::STRAT_QUANT_CEGQI_FEASIBLE, ds);
/* Add counterexample lemma (lit => ~P[x_i/eval_i]) */
Node body =
- q[1].substitute(vars.begin(), vars.end(), evals.begin(), evals.end());
+ q[1].substitute(q[0].begin(), q[0].end(), evals.begin(), evals.end());
Node lem = nm->mkNode(kind::OR, lit.negate(), body.negate());
lem = Rewriter::rewrite(lem);
diff --git a/src/theory/quantifiers/sygus_inst.h b/src/theory/quantifiers/sygus_inst.h
index 62d640a67..0358b4984 100644
--- a/src/theory/quantifiers/sygus_inst.h
+++ b/src/theory/quantifiers/sygus_inst.h
@@ -5,7 +5,7 @@
** Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -82,6 +82,9 @@ class SygusInst : public QuantifiersModule
/* Called once for every quantifier 'q' per context. */
void preRegisterQuantifier(Node q) override;
+ /* For collecting global terms from all available assertions. */
+ void ppNotifyAssertions(const std::vector<Node>& assertions);
+
std::string identify() const override { return "SygusInst"; }
private:
@@ -96,11 +99,17 @@ class SygusInst : public QuantifiersModule
* preRegisterQuantifier() call.*/
void addCeLemma(Node q);
- /* Maps bound variables to corresponding instantiation constants. */
- std::unordered_map<Node, Node, NodeHashFunction> d_inst_constants;
+ /* Send evaluation unfolding lemmas and cache them.
+ * Returns true if a new lemma (not cached) was added, and false otherwise.
+ */
+ bool sendEvalUnfoldLemmas(const std::vector<Node>& lemmas);
+
+ /* Maps quantifiers to a vector of instantiation constants. */
+ std::unordered_map<Node, std::vector<Node>, NodeHashFunction>
+ d_inst_constants;
- /* Maps bound variables to corresponding DT_SYGUS_EVAL term. */
- std::unordered_map<Node, Node, NodeHashFunction> d_var_eval;
+ /* Maps quantifiers to a vector of DT_SYGUS_EVAL terms. */
+ std::unordered_map<Node, std::vector<Node>, NodeHashFunction> d_var_eval;
/* Maps quantified formulas to registered counterexample literals. */
std::unordered_map<Node, Node, NodeHashFunction> d_ce_lits;
@@ -115,15 +124,21 @@ class SygusInst : public QuantifiersModule
/* Currently inactive quantifiers. */
std::unordered_set<Node, NodeHashFunction> d_inactive_quant;
- /* Evaluation unfolding lemma. */
- context::CDHashSet<Node, NodeHashFunction> d_lemma_cache;
-
/* Registered counterexample lemma cache. */
std::unordered_map<Node, Node, NodeHashFunction> d_ce_lemmas;
/* Indicates whether a counterexample lemma was added for a quantified
* formula in the current context. */
context::CDHashSet<Node, NodeHashFunction> d_ce_lemma_added;
+
+ /* Set of global ground terms in assertions (outside of quantifiers). */
+ context::CDHashMap<TypeNode,
+ std::unordered_set<Node, NodeHashFunction>,
+ TypeNodeHashFunction>
+ d_global_terms;
+
+ /* Assertions sent by ppNotifyAssertions. */
+ context::CDHashSet<Node, NodeHashFunction> d_notified_assertions;
};
} // namespace quantifiers
diff --git a/src/theory/quantifiers/sygus_sampler.cpp b/src/theory/quantifiers/sygus_sampler.cpp
index b9a188270..22c2ac142 100644
--- a/src/theory/quantifiers/sygus_sampler.cpp
+++ b/src/theory/quantifiers/sygus_sampler.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/sygus_sampler.h b/src/theory/quantifiers/sygus_sampler.h
index 6a454cab3..10c65244f 100644
--- a/src/theory/quantifiers/sygus_sampler.h
+++ b/src/theory/quantifiers/sygus_sampler.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Fabian Wolff
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp
index 9c0e51596..23448ca17 100644
--- a/src/theory/quantifiers/term_database.cpp
+++ b/src/theory/quantifiers/term_database.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -166,8 +166,11 @@ Node TermDb::getOrMakeTypeFreshVariable(TypeNode tn)
Node TermDb::getMatchOperator( Node n ) {
Kind k = n.getKind();
//datatype operators may be parametric, always assume they are
- if( k==SELECT || k==STORE || k==UNION || k==INTERSECTION || k==SUBSET || k==SETMINUS || k==MEMBER || k==SINGLETON ||
- k==APPLY_SELECTOR_TOTAL || k==APPLY_TESTER || k==SEP_PTO || k==HO_APPLY ){
+ if (k == SELECT || k == STORE || k == UNION || k == INTERSECTION
+ || k == SUBSET || k == SETMINUS || k == MEMBER || k == SINGLETON
+ || k == APPLY_SELECTOR_TOTAL || k == APPLY_TESTER || k == SEP_PTO
+ || k == HO_APPLY || k == SEQ_NTH)
+ {
//since it is parametric, use a particular one as op
TypeNode tn = n[0].getType();
Node op = n.getOperator();
@@ -249,7 +252,7 @@ void TermDb::addTerm(Node n,
void TermDb::computeArgReps( TNode n ) {
if (d_arg_reps.find(n) == d_arg_reps.end())
{
- eq::EqualityEngine * ee = d_quantEngine->getActiveEqualityEngine();
+ eq::EqualityEngine* ee = d_quantEngine->getMasterEqualityEngine();
for (const TNode& nc : n)
{
TNode r = ee->hasTerm(nc) ? ee->getRepresentative(nc) : nc;
@@ -272,8 +275,8 @@ void TermDb::computeUfEqcTerms( TNode f ) {
{
ops.insert(ops.end(), d_ho_op_slaves[f].begin(), d_ho_op_slaves[f].end());
}
- eq::EqualityEngine* ee = d_quantEngine->getActiveEqualityEngine();
- for (const TNode& ff : ops)
+ eq::EqualityEngine* ee = d_quantEngine->getMasterEqualityEngine();
+ for (const Node& ff : ops)
{
for (const Node& n : d_op_map[ff])
{
@@ -307,7 +310,7 @@ void TermDb::computeUfTerms( TNode f ) {
unsigned nonCongruentCount = 0;
unsigned alreadyCongruentCount = 0;
unsigned relevantCount = 0;
- eq::EqualityEngine* ee = d_quantEngine->getActiveEqualityEngine();
+ eq::EqualityEngine* ee = d_quantEngine->getMasterEqualityEngine();
NodeManager* nm = NodeManager::currentNM();
for (const TNode& ff : ops)
{
@@ -503,8 +506,8 @@ bool TermDb::inRelevantDomain( TNode f, unsigned i, TNode r ) {
f = getOperatorRepresentative( f );
}
computeUfTerms( f );
- Assert(!d_quantEngine->getActiveEqualityEngine()->hasTerm(r)
- || d_quantEngine->getActiveEqualityEngine()->getRepresentative(r)
+ Assert(!d_quantEngine->getMasterEqualityEngine()->hasTerm(r)
+ || d_quantEngine->getMasterEqualityEngine()->getRepresentative(r)
== r);
std::map< Node, std::map< unsigned, std::vector< Node > > >::iterator it = d_func_map_rel_dom.find( f );
if( it != d_func_map_rel_dom.end() ){
@@ -905,22 +908,18 @@ void TermDb::setTermInactive( Node n ) {
bool TermDb::hasTermCurrent( Node n, bool useMode ) {
if( !useMode ){
return d_has_map.find( n )!=d_has_map.end();
- }else{
- //return d_quantEngine->getActiveEqualityEngine()->hasTerm( n ); //some assertions are not sent to EE
- if (options::termDbMode() == options::TermDbMode::ALL)
- {
- return true;
- }
- else if (options::termDbMode() == options::TermDbMode::RELEVANT)
- {
- return d_has_map.find( n )!=d_has_map.end();
- }
- else
- {
- Assert(false);
- return false;
- }
}
+ //some assertions are not sent to EE
+ if (options::termDbMode() == options::TermDbMode::ALL)
+ {
+ return true;
+ }
+ else if (options::termDbMode() == options::TermDbMode::RELEVANT)
+ {
+ return d_has_map.find( n )!=d_has_map.end();
+ }
+ Assert(false) << "TermDb::hasTermCurrent: Unknown termDbMode : " << options::termDbMode();
+ return false;
}
bool TermDb::isTermEligibleForInstantiation(TNode n, TNode f)
@@ -966,7 +965,7 @@ Node TermDb::getEligibleTermInEqc( TNode r ) {
std::map< Node, Node >::iterator it = d_term_elig_eqc.find( r );
if( it==d_term_elig_eqc.end() ){
Node h;
- eq::EqualityEngine* ee = d_quantEngine->getActiveEqualityEngine();
+ eq::EqualityEngine* ee = d_quantEngine->getMasterEqualityEngine();
eq::EqClassIterator eqc_i = eq::EqClassIterator( r, ee );
while (!eqc_i.isFinished())
{
@@ -1021,7 +1020,7 @@ bool TermDb::reset( Theory::Effort effort ){
d_func_map_rel_dom.clear();
d_consistent_ee = true;
- eq::EqualityEngine* ee = d_quantEngine->getActiveEqualityEngine();
+ eq::EqualityEngine* ee = d_quantEngine->getMasterEqualityEngine();
Assert(ee->consistent());
// if higher-order, add equalities for the purification terms now
@@ -1095,15 +1094,25 @@ bool TermDb::reset( Theory::Effort effort ){
}
++eqcs_i;
}
- for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) {
- Theory* theory = d_quantEngine->getTheoryEngine()->d_theoryTable[theoryId];
- if (theory && d_quantEngine->getTheoryEngine()->d_logicInfo.isTheoryEnabled(theoryId)) {
- 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).d_assertion.getKind() != INST_CLOSURE)
- {
- setHasTerm((*it).d_assertion);
- }
+ TheoryEngine* te = d_quantEngine->getTheoryEngine();
+ const LogicInfo& logicInfo = te->getLogicInfo();
+ for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId)
+ {
+ if (!logicInfo.isTheoryEnabled(theoryId))
+ {
+ continue;
+ }
+ Theory* theory = te->theoryOf(theoryId);
+ Assert(theory != nullptr);
+ for (context::CDList<Assertion>::const_iterator
+ it = theory->facts_begin(),
+ it_end = theory->facts_end();
+ it != it_end;
+ ++it)
+ {
+ if ((*it).d_assertion.getKind() != INST_CLOSURE)
+ {
+ setHasTerm((*it).d_assertion);
}
}
}
diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h
index a81cd2e05..dff595757 100644
--- a/src/theory/quantifiers/term_database.h
+++ b/src/theory/quantifiers/term_database.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/term_enumeration.cpp b/src/theory/quantifiers/term_enumeration.cpp
index 30ee1c4a9..55e8058ad 100644
--- a/src/theory/quantifiers/term_enumeration.cpp
+++ b/src/theory/quantifiers/term_enumeration.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/term_enumeration.h b/src/theory/quantifiers/term_enumeration.h
index dd387ac4f..75b28e604 100644
--- a/src/theory/quantifiers/term_enumeration.h
+++ b/src/theory/quantifiers/term_enumeration.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/term_util.cpp b/src/theory/quantifiers/term_util.cpp
index f657062ed..808c88b78 100644
--- a/src/theory/quantifiers/term_util.cpp
+++ b/src/theory/quantifiers/term_util.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,7 +14,6 @@
#include "theory/quantifiers/term_util.h"
-#include "expr/datatype.h"
#include "expr/node_algorithm.h"
#include "options/base_options.h"
#include "options/datatypes_options.h"
diff --git a/src/theory/quantifiers/term_util.h b/src/theory/quantifiers/term_util.h
index c4e0a8586..fb982eea8 100644
--- a/src/theory/quantifiers/term_util.h
+++ b/src/theory/quantifiers/term_util.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers/theory_quantifiers.cpp b/src/theory/quantifiers/theory_quantifiers.cpp
index 7365960e9..387a3e9d8 100644
--- a/src/theory/quantifiers/theory_quantifiers.cpp
+++ b/src/theory/quantifiers/theory_quantifiers.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -29,12 +29,12 @@
#include "theory/quantifiers_engine.h"
#include "theory/valuation.h"
-using namespace std;
-using namespace CVC4;
using namespace CVC4::kind;
using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::quantifiers;
+
+namespace CVC4 {
+namespace theory {
+namespace quantifiers {
TheoryQuantifiers::TheoryQuantifiers(Context* c,
context::UserContext* u,
@@ -42,13 +42,11 @@ TheoryQuantifiers::TheoryQuantifiers(Context* c,
Valuation valuation,
const LogicInfo& logicInfo,
ProofNodeManager* pnm)
- : Theory(THEORY_QUANTIFIERS, c, u, out, valuation, logicInfo, pnm)
+ : Theory(THEORY_QUANTIFIERS, c, u, out, valuation, logicInfo, pnm),
+ d_qstate(c, u, valuation)
{
out.handleUserAttribute( "fun-def", this );
- out.handleUserAttribute( "sygus", this );
out.handleUserAttribute("qid", this);
- out.handleUserAttribute("sygus-synth-grammar", this);
- out.handleUserAttribute( "sygus-synth-fun-var-list", this );
out.handleUserAttribute( "quant-inst-max-level", this );
out.handleUserAttribute( "quant-elim", this );
out.handleUserAttribute( "quant-elim-partial", this );
@@ -59,38 +57,41 @@ TheoryQuantifiers::TheoryQuantifiers(Context* c,
// add the proof rules
d_qChecker.registerTo(pc);
}
+ // indicate we are using the quantifiers theory state object
+ d_theoryState = &d_qstate;
}
TheoryQuantifiers::~TheoryQuantifiers() {
}
+TheoryRewriter* TheoryQuantifiers::getTheoryRewriter() { return &d_rewriter; }
void TheoryQuantifiers::finishInit()
{
// quantifiers are not evaluated in getModelValue
- TheoryModel* tm = d_valuation.getModel();
- Assert(tm != nullptr);
- tm->setUnevaluatedKind(EXISTS);
- tm->setUnevaluatedKind(FORALL);
+ d_valuation.setUnevaluatedKind(EXISTS);
+ d_valuation.setUnevaluatedKind(FORALL);
// witness is used in several instantiation strategies
- tm->setUnevaluatedKind(WITNESS);
+ d_valuation.setUnevaluatedKind(WITNESS);
}
-void TheoryQuantifiers::preRegisterTerm(TNode n) {
+void TheoryQuantifiers::preRegisterTerm(TNode n)
+{
if (n.getKind() != FORALL)
{
return;
}
- Debug("quantifiers-prereg") << "TheoryQuantifiers::preRegisterTerm() " << n << endl;
+ Debug("quantifiers-prereg")
+ << "TheoryQuantifiers::preRegisterTerm() " << n << std::endl;
// Preregister the quantified formula.
// This initializes the modules used for handling n in this user context.
getQuantifiersEngine()->preRegisterQuantifier(n);
Debug("quantifiers-prereg")
- << "TheoryQuantifiers::preRegisterTerm() done " << n << endl;
+ << "TheoryQuantifiers::preRegisterTerm() done " << n << std::endl;
}
void TheoryQuantifiers::presolve() {
- Debug("quantifiers-presolve") << "TheoryQuantifiers::presolve()" << endl;
+ Debug("quantifiers-presolve") << "TheoryQuantifiers::presolve()" << std::endl;
if( getQuantifiersEngine() ){
getQuantifiersEngine()->presolve();
}
@@ -105,13 +106,14 @@ void TheoryQuantifiers::ppNotifyAssertions(
}
}
-bool TheoryQuantifiers::collectModelInfo(TheoryModel* m)
+bool TheoryQuantifiers::collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet)
{
for(assertions_iterator i = facts_begin(); i != facts_end(); ++i) {
- if ((*i).d_assertion.getKind() == kind::NOT)
+ if ((*i).d_assertion.getKind() == NOT)
{
Debug("quantifiers::collectModelInfo")
- << "got quant FALSE: " << (*i).d_assertion[0] << endl;
+ << "got quant FALSE: " << (*i).d_assertion[0] << std::endl;
if (!m->assertPredicate((*i).d_assertion[0], false))
{
return false;
@@ -119,7 +121,8 @@ bool TheoryQuantifiers::collectModelInfo(TheoryModel* m)
}
else
{
- Debug("quantifiers::collectModelInfo") << "got quant TRUE : " << *i << endl;
+ Debug("quantifiers::collectModelInfo")
+ << "got quant TRUE : " << *i << std::endl;
if (!m->assertPredicate(*i, true))
{
return false;
@@ -129,51 +132,44 @@ bool TheoryQuantifiers::collectModelInfo(TheoryModel* m)
return true;
}
-void TheoryQuantifiers::check(Effort e) {
- if (done() && !fullEffort(e)) {
- return;
- }
+void TheoryQuantifiers::postCheck(Effort level)
+{
+ // call the quantifiers engine to check
+ getQuantifiersEngine()->check(level);
+}
- TimerStat::CodeTimer checkTimer(d_checkTime);
-
- Trace("quantifiers-check") << "quantifiers::check(" << e << ")" << std::endl;
- while(!done()) {
- Node assertion = get();
- Trace("quantifiers-assert") << "quantifiers::assert(): " << assertion << std::endl;
- switch(assertion.getKind()) {
- case kind::FORALL:
- getQuantifiersEngine()->assertQuantifier(assertion, true);
- break;
- case kind::INST_CLOSURE:
- getQuantifiersEngine()->addTermToDatabase( assertion[0], false, true );
- if( !options::lteRestrictInstClosure() ){
- getQuantifiersEngine()->getMasterEqualityEngine()->addTerm( assertion[0] );
- }
- break;
- case kind::EQUAL:
- //do nothing
- break;
- case kind::NOT:
- {
- switch( assertion[0].getKind()) {
- case kind::FORALL:
- getQuantifiersEngine()->assertQuantifier(assertion[0], false);
- break;
- case kind::EQUAL:
- //do nothing
- break;
- case kind::INST_CLOSURE:
- default: Unhandled() << assertion[0].getKind(); break;
- }
- }
- break;
- default: Unhandled() << assertion.getKind(); break;
+bool TheoryQuantifiers::preNotifyFact(
+ TNode atom, bool polarity, TNode fact, bool isPrereg, bool isInternal)
+{
+ Kind k = atom.getKind();
+ if (k == FORALL)
+ {
+ getQuantifiersEngine()->assertQuantifier(atom, polarity);
+ }
+ else if (k == INST_CLOSURE)
+ {
+ if (!polarity)
+ {
+ Unhandled() << "Unexpected inst-closure fact " << fact;
+ }
+ getQuantifiersEngine()->addTermToDatabase(atom[0], false, true);
+ if (!options::lteRestrictInstClosure())
+ {
+ getQuantifiersEngine()->getMasterEqualityEngine()->addTerm(atom[0]);
}
}
- // call the quantifiers engine to check
- getQuantifiersEngine()->check( e );
+ else
+ {
+ Unhandled() << "Unexpected fact " << fact;
+ }
+ // don't use equality engine, always return true
+ return true;
}
void TheoryQuantifiers::setUserAttribute(const std::string& attr, Node n, std::vector<Node> node_values, std::string str_value){
QuantAttributes::setUserAttribute( attr, n, node_values, str_value );
}
+
+} // namespace quantifiers
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/quantifiers/theory_quantifiers.h b/src/theory/quantifiers/theory_quantifiers.h
index 3168af195..b46390284 100644
--- a/src/theory/quantifiers/theory_quantifiers.h
+++ b/src/theory/quantifiers/theory_quantifiers.h
@@ -2,10 +2,10 @@
/*! \file theory_quantifiers.h
** \verbatim
** Top contributors (to current version):
- ** Tim King, Morgan Deters, Andres Noetzli
+ ** Andrew Reynolds, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,14 +19,12 @@
#ifndef CVC4__THEORY__QUANTIFIERS__THEORY_QUANTIFIERS_H
#define CVC4__THEORY__QUANTIFIERS__THEORY_QUANTIFIERS_H
-#include "context/context.h"
#include "expr/node.h"
-#include "theory/output_channel.h"
#include "theory/quantifiers/proof_checker.h"
#include "theory/quantifiers/quantifiers_rewriter.h"
+#include "theory/quantifiers/quantifiers_state.h"
#include "theory/theory.h"
#include "theory/valuation.h"
-#include "util/statistics_registry.h"
namespace CVC4 {
namespace theory {
@@ -42,15 +40,29 @@ class TheoryQuantifiers : public Theory {
ProofNodeManager* pnm = nullptr);
~TheoryQuantifiers();
- TheoryRewriter* getTheoryRewriter() override { return &d_rewriter; }
-
+ //--------------------------------- initialization
+ /** get the official theory rewriter of this theory */
+ TheoryRewriter* getTheoryRewriter() override;
/** finish initialization */
void finishInit() override;
+ //--------------------------------- end initialization
+
void preRegisterTerm(TNode n) override;
void presolve() override;
void ppNotifyAssertions(const std::vector<Node>& assertions) override;
- void check(Effort e) override;
- bool collectModelInfo(TheoryModel* m) override;
+ //--------------------------------- standard check
+ /** Post-check, called after the fact queue of the theory is processed. */
+ void postCheck(Effort level) override;
+ /** Pre-notify fact, return true if processed. */
+ bool preNotifyFact(TNode atom,
+ bool pol,
+ TNode fact,
+ bool isPrereg,
+ bool isInternal) override;
+ //--------------------------------- end standard check
+ /** Collect model values in m based on the relevant terms given by termSet */
+ bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet) override;
void shutdown() override {}
std::string identify() const override
{
@@ -66,6 +78,8 @@ class TheoryQuantifiers : public Theory {
QuantifiersRewriter d_rewriter;
/** The proof rule checker */
QuantifiersProofRuleChecker d_qChecker;
+ /** The quantifiers state */
+ QuantifiersState d_qstate;
};/* class TheoryQuantifiers */
}/* CVC4::theory::quantifiers namespace */
diff --git a/src/theory/quantifiers/theory_quantifiers_type_rules.h b/src/theory/quantifiers/theory_quantifiers_type_rules.h
index 1fdef3359..c7cbb278f 100644
--- a/src/theory/quantifiers/theory_quantifiers_type_rules.h
+++ b/src/theory/quantifiers/theory_quantifiers_type_rules.h
@@ -5,7 +5,7 @@
** Morgan Deters, Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp
index 6dcf1a980..297f11690 100644
--- a/src/theory/quantifiers_engine.cpp
+++ b/src/theory/quantifiers_engine.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,20 +18,9 @@
#include "options/uf_options.h"
#include "smt/smt_engine_scope.h"
#include "smt/smt_statistics_registry.h"
-#include "theory/quantifiers/alpha_equivalence.h"
-#include "theory/quantifiers/anti_skolem.h"
-#include "theory/quantifiers/conjecture_generator.h"
-#include "theory/quantifiers/ematching/instantiation_engine.h"
-#include "theory/quantifiers/fmf/bounded_integers.h"
#include "theory/quantifiers/fmf/full_model_check.h"
-#include "theory/quantifiers/fmf/model_engine.h"
-#include "theory/quantifiers/inst_strategy_enumerative.h"
-#include "theory/quantifiers/quant_conflict_find.h"
-#include "theory/quantifiers/quant_split.h"
+#include "theory/quantifiers/quantifiers_modules.h"
#include "theory/quantifiers/quantifiers_rewriter.h"
-#include "theory/quantifiers/sygus/synth_engine.h"
-#include "theory/quantifiers/sygus_inst.h"
-#include "theory/sep/theory_sep.h"
#include "theory/theory_engine.h"
#include "theory/uf/equality_engine.h"
@@ -41,172 +30,39 @@ using namespace CVC4::kind;
namespace CVC4 {
namespace theory {
-class QuantifiersEnginePrivate
-{
- public:
- QuantifiersEnginePrivate()
- : d_rel_dom(nullptr),
- d_alpha_equiv(nullptr),
- d_inst_engine(nullptr),
- d_model_engine(nullptr),
- d_bint(nullptr),
- d_qcf(nullptr),
- d_sg_gen(nullptr),
- d_synth_e(nullptr),
- d_fs(nullptr),
- d_i_cbqi(nullptr),
- d_qsplit(nullptr),
- d_anti_skolem(nullptr),
- d_sygus_inst(nullptr)
- {
- }
- ~QuantifiersEnginePrivate() {}
- //------------------------------ private quantifier utilities
- /** relevant domain */
- std::unique_ptr<quantifiers::RelevantDomain> d_rel_dom;
- //------------------------------ end private quantifier utilities
- //------------------------------ quantifiers modules
- /** alpha equivalence */
- std::unique_ptr<quantifiers::AlphaEquivalence> d_alpha_equiv;
- /** instantiation engine */
- std::unique_ptr<quantifiers::InstantiationEngine> d_inst_engine;
- /** model engine */
- std::unique_ptr<quantifiers::ModelEngine> d_model_engine;
- /** bounded integers utility */
- std::unique_ptr<quantifiers::BoundedIntegers> d_bint;
- /** Conflict find mechanism for quantifiers */
- std::unique_ptr<quantifiers::QuantConflictFind> d_qcf;
- /** subgoal generator */
- std::unique_ptr<quantifiers::ConjectureGenerator> d_sg_gen;
- /** ceg instantiation */
- std::unique_ptr<quantifiers::SynthEngine> d_synth_e;
- /** full saturation */
- std::unique_ptr<quantifiers::InstStrategyEnum> d_fs;
- /** counterexample-based quantifier instantiation */
- std::unique_ptr<quantifiers::InstStrategyCegqi> d_i_cbqi;
- /** quantifiers splitting */
- std::unique_ptr<quantifiers::QuantDSplit> d_qsplit;
- /** quantifiers anti-skolemization */
- std::unique_ptr<quantifiers::QuantAntiSkolem> d_anti_skolem;
- /** SyGuS instantiation engine */
- std::unique_ptr<quantifiers::SygusInst> d_sygus_inst;
- //------------------------------ end quantifiers modules
- /** initialize
- *
- * This constructs the above modules based on the current options. It adds
- * a pointer to each module it constructs to modules. This method sets
- * needsBuilder to true if we require a strategy-specific model builder
- * utility.
- */
- void initialize(QuantifiersEngine* qe,
- context::Context* c,
- std::vector<QuantifiersModule*>& modules,
- bool& needsBuilder)
- {
- // add quantifiers modules
- if (options::quantConflictFind())
- {
- d_qcf.reset(new quantifiers::QuantConflictFind(qe, c));
- modules.push_back(d_qcf.get());
- }
- if (options::conjectureGen())
- {
- d_sg_gen.reset(new quantifiers::ConjectureGenerator(qe, c));
- modules.push_back(d_sg_gen.get());
- }
- if (!options::finiteModelFind() || options::fmfInstEngine())
- {
- d_inst_engine.reset(new quantifiers::InstantiationEngine(qe));
- modules.push_back(d_inst_engine.get());
- }
- if (options::cegqi())
- {
- d_i_cbqi.reset(new quantifiers::InstStrategyCegqi(qe));
- modules.push_back(d_i_cbqi.get());
- qe->getInstantiate()->addRewriter(d_i_cbqi->getInstRewriter());
- }
- if (options::sygus())
- {
- d_synth_e.reset(new quantifiers::SynthEngine(qe, c));
- modules.push_back(d_synth_e.get());
- }
- // finite model finding
- if (options::fmfBound())
- {
- d_bint.reset(new quantifiers::BoundedIntegers(c, qe));
- modules.push_back(d_bint.get());
- }
- if (options::finiteModelFind() || options::fmfBound())
- {
- d_model_engine.reset(new quantifiers::ModelEngine(c, qe));
- modules.push_back(d_model_engine.get());
- // finite model finder has special ways of building the model
- needsBuilder = true;
- }
- if (options::quantDynamicSplit() != options::QuantDSplitMode::NONE)
- {
- d_qsplit.reset(new quantifiers::QuantDSplit(qe, c));
- modules.push_back(d_qsplit.get());
- }
- if (options::quantAntiSkolem())
- {
- d_anti_skolem.reset(new quantifiers::QuantAntiSkolem(qe));
- modules.push_back(d_anti_skolem.get());
- }
- if (options::quantAlphaEquiv())
- {
- d_alpha_equiv.reset(new quantifiers::AlphaEquivalence(qe));
- }
- // full saturation : instantiate from relevant domain, then arbitrary terms
- if (options::fullSaturateQuant() || options::fullSaturateInterleave())
- {
- d_rel_dom.reset(new quantifiers::RelevantDomain(qe));
- d_fs.reset(new quantifiers::InstStrategyEnum(qe, d_rel_dom.get()));
- modules.push_back(d_fs.get());
- }
- if (options::sygusInst())
- {
- d_sygus_inst.reset(new quantifiers::SygusInst(qe));
- modules.push_back(d_sygus_inst.get());
- }
- }
-};
-
-QuantifiersEngine::QuantifiersEngine(context::Context* c,
- context::UserContext* u,
- TheoryEngine* te)
+QuantifiersEngine::QuantifiersEngine(TheoryEngine* te,
+ DecisionManager& dm,
+ ProofNodeManager* pnm)
: d_te(te),
- d_eq_query(new quantifiers::EqualityQueryQuantifiersEngine(c, this)),
+ d_context(te->getSatContext()),
+ d_userContext(te->getUserContext()),
+ d_decManager(dm),
+ d_masterEqualityEngine(nullptr),
+ d_eq_query(
+ new quantifiers::EqualityQueryQuantifiersEngine(d_context, this)),
d_tr_trie(new inst::TriggerTrie),
d_model(nullptr),
d_builder(nullptr),
d_qepr(nullptr),
d_term_util(new quantifiers::TermUtil(this)),
d_term_canon(new expr::TermCanonize),
- d_term_db(new quantifiers::TermDb(c, u, this)),
+ d_term_db(new quantifiers::TermDb(d_context, d_userContext, this)),
d_sygus_tdb(nullptr),
d_quant_attr(new quantifiers::QuantAttributes(this)),
- d_instantiate(new quantifiers::Instantiate(this, u)),
- d_skolemize(new quantifiers::Skolemize(this, u)),
+ d_instantiate(new quantifiers::Instantiate(this, d_userContext, pnm)),
+ d_skolemize(new quantifiers::Skolemize(this, d_userContext, pnm)),
d_term_enum(new quantifiers::TermEnumeration),
- d_conflict_c(c, false),
- // d_quants(u),
- d_quants_prereg(u),
- d_quants_red(u),
- d_lemmas_produced_c(u),
- d_ierCounter_c(c),
- // d_ierCounter(c),
- // d_ierCounter_lc(c),
- // d_ierCounterLastLc(c),
- d_presolve(u, true),
- d_presolve_in(u),
- d_presolve_cache(u),
- d_presolve_cache_wq(u),
- d_presolve_cache_wic(u)
+ d_conflict_c(d_context, false),
+ d_quants_prereg(d_userContext),
+ d_quants_red(d_userContext),
+ d_lemmas_produced_c(d_userContext),
+ d_ierCounter_c(d_context),
+ d_presolve(d_userContext, true),
+ d_presolve_in(d_userContext),
+ d_presolve_cache(d_userContext),
+ d_presolve_cache_wq(d_userContext),
+ d_presolve_cache_wic(d_userContext)
{
- // initialize the private utility
- d_private.reset(new QuantifiersEnginePrivate);
-
//---- utilities
d_util.push_back(d_eq_query.get());
// term util must come before the other utilities
@@ -215,15 +71,15 @@ QuantifiersEngine::QuantifiersEngine(context::Context* c,
if (options::sygus() || options::sygusInst())
{
- d_sygus_tdb.reset(new quantifiers::TermDbSygus(c, this));
- }
+ // must be constructed here since it is required for datatypes finistInit
+ d_sygus_tdb.reset(new quantifiers::TermDbSygus(d_context, this));
+ }
d_util.push_back(d_instantiate.get());
d_curr_effort_level = QuantifiersModule::QEFFORT_NONE;
d_conflict = false;
d_hasAddedLemma = false;
- d_useModelEe = false;
//don't add true lemma
d_lemmas_produced_c[d_term_util->d_true] = true;
@@ -243,16 +99,11 @@ QuantifiersEngine::QuantifiersEngine(context::Context* c,
d_ierCounterLastLc = 0;
d_inst_when_phase = 1 + ( options::instWhenPhase()<1 ? 1 : options::instWhenPhase() );
- bool needsBuilder = false;
- d_private->initialize(this, c, d_modules, needsBuilder);
-
- if (d_private->d_rel_dom.get())
+ // Finite model finding requires specialized ways of building the model.
+ // We require constructing the model and model builder here, since it is
+ // required for initializing the CombinationEngine.
+ if (options::finiteModelFind() || options::fmfBound())
{
- d_util.push_back(d_private->d_rel_dom.get());
- }
-
- // if we require specialized ways of building the model
- if( needsBuilder ){
Trace("quant-engine-debug") << "Initialize model engine, mbqi : " << options::mbqiMode() << " " << options::fmfBound() << std::endl;
if (options::mbqiMode() == options::MbqiMode::FMC
|| options::mbqiMode() == options::MbqiMode::TRUST
@@ -260,29 +111,53 @@ QuantifiersEngine::QuantifiersEngine(context::Context* c,
{
Trace("quant-engine-debug") << "...make fmc builder." << std::endl;
d_model.reset(new quantifiers::fmcheck::FirstOrderModelFmc(
- this, c, "FirstOrderModelFmc"));
- d_builder.reset(new quantifiers::fmcheck::FullModelChecker(c, this));
+ this, d_context, "FirstOrderModelFmc"));
+ d_builder.reset(
+ new quantifiers::fmcheck::FullModelChecker(d_context, this));
}else{
Trace("quant-engine-debug") << "...make default model builder." << std::endl;
d_model.reset(
- new quantifiers::FirstOrderModel(this, c, "FirstOrderModel"));
- d_builder.reset(new quantifiers::QModelBuilder(c, this));
+ new quantifiers::FirstOrderModel(this, d_context, "FirstOrderModel"));
+ d_builder.reset(new quantifiers::QModelBuilder(d_context, this));
}
}else{
- d_model.reset(new quantifiers::FirstOrderModel(this, c, "FirstOrderModel"));
+ d_model.reset(
+ new quantifiers::FirstOrderModel(this, d_context, "FirstOrderModel"));
}
}
QuantifiersEngine::~QuantifiersEngine() {}
-context::Context* QuantifiersEngine::getSatContext()
+void QuantifiersEngine::finishInit()
+{
+ // Initialize the modules and the utilities here. We delay their
+ // initialization to here, since this is after TheoryQuantifiers finishInit,
+ // which has initialized the state and inference manager of this engine.
+ d_qmodules.reset(new quantifiers::QuantifiersModules);
+ d_qmodules->initialize(this, d_context, d_modules);
+ if (d_qmodules->d_rel_dom.get())
+ {
+ d_util.push_back(d_qmodules->d_rel_dom.get());
+ }
+}
+
+void QuantifiersEngine::setMasterEqualityEngine(eq::EqualityEngine* mee)
+{
+ d_masterEqualityEngine = mee;
+}
+
+TheoryEngine* QuantifiersEngine::getTheoryEngine() const { return d_te; }
+
+DecisionManager* QuantifiersEngine::getDecisionManager()
{
- return d_te->theoryOf(THEORY_QUANTIFIERS)->getSatContext();
+ return &d_decManager;
}
+context::Context* QuantifiersEngine::getSatContext() { return d_context; }
+
context::UserContext* QuantifiersEngine::getUserContext()
{
- return d_te->theoryOf(THEORY_QUANTIFIERS)->getUserContext();
+ return d_userContext;
}
OutputChannel& QuantifiersEngine::getOutputChannel()
@@ -380,14 +255,14 @@ void QuantifiersEngine::setOwner(Node q, quantifiers::QAttributes& qa)
{
if (qa.d_sygus || (options::sygusRecFun() && !qa.d_fundef_f.isNull()))
{
- if (d_private->d_synth_e.get() == nullptr)
+ if (d_qmodules->d_synth_e.get() == nullptr)
{
Trace("quant-warn") << "WARNING : synth engine is null, and we have : "
<< q << std::endl;
}
// set synth engine as owner since this is either a conjecture or a function
// definition to be used by sygus
- setOwner(q, d_private->d_synth_e.get(), 2);
+ setOwner(q, d_qmodules->d_synth_e.get(), 2);
}
}
@@ -398,7 +273,7 @@ bool QuantifiersEngine::hasOwnership( Node q, QuantifiersModule * m ) {
bool QuantifiersEngine::isFiniteBound(Node q, Node v) const
{
- quantifiers::BoundedIntegers* bi = d_private->d_bint.get();
+ quantifiers::BoundedIntegers* bi = d_qmodules->d_bint.get();
if (bi && bi->isBound(q, v))
{
return true;
@@ -417,7 +292,7 @@ bool QuantifiersEngine::isFiniteBound(Node q, Node v) const
BoundVarType QuantifiersEngine::getBoundVarType(Node q, Node v) const
{
- quantifiers::BoundedIntegers* bi = d_private->d_bint.get();
+ quantifiers::BoundedIntegers* bi = d_qmodules->d_bint.get();
if (bi)
{
return bi->getBoundVarType(q, v);
@@ -430,7 +305,7 @@ void QuantifiersEngine::getBoundVarIndices(Node q,
{
Assert(indices.empty());
// we take the bounded variables first
- quantifiers::BoundedIntegers* bi = d_private->d_bint.get();
+ quantifiers::BoundedIntegers* bi = d_qmodules->d_bint.get();
if (bi)
{
bi->getBoundVarIndices(q, indices);
@@ -451,7 +326,7 @@ bool QuantifiersEngine::getBoundElements(RepSetIterator* rsi,
Node v,
std::vector<Node>& elements) const
{
- quantifiers::BoundedIntegers* bi = d_private->d_bint.get();
+ quantifiers::BoundedIntegers* bi = d_qmodules->d_bint.get();
if (bi)
{
return bi->getBoundElements(rsi, initial, q, v, elements);
@@ -488,47 +363,29 @@ void QuantifiersEngine::ppNotifyAssertions(
quantifiers::QuantAttributes::setInstantiationLevelAttr(a, 0);
}
}
- if (d_qepr != NULL)
- {
- for (const Node& a : assertions)
- {
- d_qepr->registerAssertion(a);
- }
- // must handle sources of other new constants e.g. separation logic
- // FIXME (as part of project 3) : cleanup
- sep::TheorySep* theory_sep =
- static_cast<sep::TheorySep*>(getTheoryEngine()->theoryOf(THEORY_SEP));
- theory_sep->initializeBounds();
- d_qepr->finishInit();
- }
if (options::sygus())
{
- quantifiers::SynthEngine* sye = d_private->d_synth_e.get();
+ quantifiers::SynthEngine* sye = d_qmodules->d_synth_e.get();
for (const Node& a : assertions)
{
sye->preregisterAssertion(a);
}
}
+ /* The SyGuS instantiation module needs a global view of all available
+ * assertions to collect global terms that get added to each grammar.
+ */
+ if (options::sygusInst())
+ {
+ quantifiers::SygusInst* si = d_qmodules->d_sygus_inst.get();
+ si->ppNotifyAssertions(assertions);
+ }
}
void QuantifiersEngine::check( Theory::Effort e ){
CodeTimer codeTimer(d_statistics.d_time);
- d_useModelEe = options::quantModelEe() && ( e>=Theory::EFFORT_LAST_CALL );
- // if we want to use the model's equality engine, build the model now
- if( d_useModelEe && !d_model->isBuilt() ){
- Trace("quant-engine-debug") << "Build the model." << std::endl;
- if (!d_te->getModelBuilder()->buildModel(d_model.get()))
- {
- //we are done if model building was unsuccessful
- flushLemmas();
- if( d_hasAddedLemma ){
- Trace("quant-engine-debug") << "...failed." << std::endl;
- return;
- }
- }
- }
-
- if( !getActiveEqualityEngine()->consistent() ){
+
+ if (!getMasterEqualityEngine()->consistent())
+ {
Trace("quant-engine-debug") << "Master equality engine not consistent, return." << std::endl;
return;
}
@@ -583,12 +440,12 @@ void QuantifiersEngine::check( Theory::Effort e ){
Trace("quant-engine-debug2") << "Quantifiers Engine call to check, level = " << e << ", needsCheck=" << needsCheck << std::endl;
if( needsCheck ){
- //flush previous lemmas (for instance, if was interupted), or other lemmas to process
+ //flush previous lemmas (for instance, if was interrupted), or other lemmas to process
flushLemmas();
if( d_hasAddedLemma ){
return;
}
-
+
double clSet = 0;
if( Trace.isOn("quant-engine") ){
clSet = double(clock())/double(CLOCKS_PER_SEC);
@@ -678,23 +535,15 @@ void QuantifiersEngine::check( Theory::Effort e ){
QuantifiersModule::QEffort quant_e =
static_cast<QuantifiersModule::QEffort>(qef);
d_curr_effort_level = quant_e;
- //build the model if any module requested it
+ // Force the theory engine to build the model if any module requested it.
if (needsModelE == quant_e)
{
- if (!d_model->isBuilt())
- {
- // theory engine's model builder is quantifier engine's builder if it
- // has one
- Assert(!getModelBuilder()
- || getModelBuilder() == d_te->getModelBuilder());
- Trace("quant-engine-debug") << "Build model..." << std::endl;
- if (!d_te->getModelBuilder()->buildModel(d_model.get()))
- {
- flushLemmas();
- }
- }
- if (!d_model->isBuiltSuccess())
+ Trace("quant-engine-debug") << "Build model..." << std::endl;
+ if (!d_te->buildModel())
{
+ // If we failed to build the model, flush all pending lemmas and
+ // finish.
+ flushLemmas();
break;
}
}
@@ -821,7 +670,7 @@ void QuantifiersEngine::check( Theory::Effort e ){
Trace("quant-engine") << ", added lemma = " << d_hasAddedLemma;
Trace("quant-engine") << std::endl;
}
-
+
Trace("quant-engine-debug2") << "Finished quantifiers engine check." << std::endl;
}else{
Trace("quant-engine-debug2") << "Quantifiers Engine does not need check." << std::endl;
@@ -851,11 +700,11 @@ bool QuantifiersEngine::reduceQuantifier( Node q ) {
Node lem;
std::map< Node, Node >::iterator itr = d_quants_red_lem.find( q );
if( itr==d_quants_red_lem.end() ){
- if (d_private->d_alpha_equiv)
+ if (d_qmodules->d_alpha_equiv)
{
Trace("quant-engine-red") << "Alpha equivalence " << q << "?" << std::endl;
//add equivalence with another quantified formula
- lem = d_private->d_alpha_equiv->reduceQuantifier(q);
+ lem = d_qmodules->d_alpha_equiv->reduceQuantifier(q);
if( !lem.isNull() ){
Trace("quant-engine-red") << "...alpha equivalence success." << std::endl;
++(d_statistics.d_red_alpha_equiv);
@@ -961,16 +810,17 @@ void QuantifiersEngine::assertQuantifier( Node f, bool pol ){
}
if( !pol ){
// do skolemization
- Node lem = d_skolemize->process(f);
+ TrustNode lem = d_skolemize->process(f);
if (!lem.isNull())
{
if (Trace.isOn("quantifiers-sk-debug"))
{
- Node slem = Rewriter::rewrite(lem);
+ Node slem = Rewriter::rewrite(lem.getNode());
Trace("quantifiers-sk-debug")
<< "Skolemize lemma : " << slem << std::endl;
}
- getOutputChannel().lemma(lem, false, true);
+ getOutputChannel().trustedLemma(
+ lem, LemmaProperty::PREPROCESS | LemmaProperty::NEEDS_JUSTIFY);
}
return;
}
@@ -1021,7 +871,6 @@ bool QuantifiersEngine::addLemma( Node lem, bool doCache, bool doRewrite ){
Trace("inst-add-debug") << "Adding lemma : " << lem << std::endl;
BoolMap::const_iterator itp = d_lemmas_produced_c.find( lem );
if( itp==d_lemmas_produced_c.end() || !(*itp).second ){
- //d_curr_out->lemma( lem, false, true );
d_lemmas_produced_c[ lem ] = true;
d_lemmas_waiting.push_back( lem );
Trace("inst-add-debug") << "Added lemma" << std::endl;
@@ -1037,6 +886,19 @@ bool QuantifiersEngine::addLemma( Node lem, bool doCache, bool doRewrite ){
}
}
+bool QuantifiersEngine::addTrustedLemma(TrustNode tlem,
+ bool doCache,
+ bool doRewrite)
+{
+ Node lem = tlem.getProven();
+ if (!addLemma(lem, doCache, doRewrite))
+ {
+ return false;
+ }
+ d_lemmasWaitingPg[lem] = tlem.getGenerator();
+ return true;
+}
+
bool QuantifiersEngine::removeLemma( Node lem ) {
std::vector< Node >::iterator it = std::find( d_lemmas_waiting.begin(), d_lemmas_waiting.end(), lem );
if( it!=d_lemmas_waiting.end() ){
@@ -1051,7 +913,7 @@ bool QuantifiersEngine::removeLemma( Node lem ) {
void QuantifiersEngine::addRequirePhase( Node lit, bool req ){
d_phase_req_waiting[lit] = req;
}
-
+
void QuantifiersEngine::markRelevant( Node q ) {
d_model->markRelevant( q );
}
@@ -1064,9 +926,10 @@ bool QuantifiersEngine::theoryEngineNeedsCheck() const
return d_te->needCheck();
}
-void QuantifiersEngine::setConflict() {
- d_conflict = true;
- d_conflict_c = true;
+void QuantifiersEngine::setConflict()
+{
+ d_conflict = true;
+ d_conflict_c = true;
}
bool QuantifiersEngine::getInstWhenNeedsCheck( Theory::Effort e ) {
@@ -1117,32 +980,39 @@ options::UserPatMode QuantifiersEngine::getInstUserPatMode()
}
void QuantifiersEngine::flushLemmas(){
+ OutputChannel& out = getOutputChannel();
if( !d_lemmas_waiting.empty() ){
//take default output channel if none is provided
d_hasAddedLemma = true;
- for( unsigned i=0; i<d_lemmas_waiting.size(); i++ ){
- Trace("qe-lemma") << "Lemma : " << d_lemmas_waiting[i] << std::endl;
- getOutputChannel().lemma( d_lemmas_waiting[i], false, true );
+ std::map<Node, ProofGenerator*>::iterator itp;
+ // Note: Do not use foreach loop here and do not cache size() call.
+ // New lemmas can be added while iterating over d_lemmas_waiting.
+ for (size_t i = 0; i < d_lemmas_waiting.size(); ++i)
+ {
+ const Node& lemw = d_lemmas_waiting[i];
+ Trace("qe-lemma") << "Lemma : " << lemw << std::endl;
+ itp = d_lemmasWaitingPg.find(lemw);
+ if (itp != d_lemmasWaitingPg.end())
+ {
+ TrustNode tlemw = TrustNode::mkTrustLemma(lemw, itp->second);
+ out.trustedLemma(tlemw, LemmaProperty::PREPROCESS);
+ }
+ else
+ {
+ out.lemma(lemw, LemmaProperty::PREPROCESS);
+ }
}
d_lemmas_waiting.clear();
}
if( !d_phase_req_waiting.empty() ){
for( std::map< Node, bool >::iterator it = d_phase_req_waiting.begin(); it != d_phase_req_waiting.end(); ++it ){
Trace("qe-lemma") << "Require phase : " << it->first << " -> " << it->second << std::endl;
- getOutputChannel().requirePhase( it->first, it->second );
+ out.requirePhase(it->first, it->second);
}
d_phase_req_waiting.clear();
}
}
-bool QuantifiersEngine::getUnsatCoreLemmas( std::vector< Node >& active_lemmas ) {
- return d_instantiate->getUnsatCoreLemmas(active_lemmas);
-}
-
-bool QuantifiersEngine::getUnsatCoreLemmas( std::vector< Node >& active_lemmas, std::map< Node, Node >& weak_imp ) {
- return d_instantiate->getUnsatCoreLemmas(active_lemmas, weak_imp);
-}
-
void QuantifiersEngine::getInstantiationTermVectors( Node q, std::vector< std::vector< Node > >& tvecs ) {
d_instantiate->getInstantiationTermVectors(q, tvecs);
}
@@ -1151,14 +1021,6 @@ void QuantifiersEngine::getInstantiationTermVectors( std::map< Node, std::vector
d_instantiate->getInstantiationTermVectors(insts);
}
-void QuantifiersEngine::getExplanationForInstLemmas(
- const std::vector<Node>& lems,
- std::map<Node, Node>& quant,
- std::map<Node, std::vector<Node> >& tvec)
-{
- d_instantiate->getExplanationForInstLemmas(lems, quant, tvec);
-}
-
void QuantifiersEngine::printInstantiations( std::ostream& out ) {
bool printed = false;
// print the skolemizations
@@ -1180,9 +1042,9 @@ void QuantifiersEngine::printInstantiations( std::ostream& out ) {
}
void QuantifiersEngine::printSynthSolution( std::ostream& out ) {
- if (d_private->d_synth_e)
+ if (d_qmodules->d_synth_e)
{
- d_private->d_synth_e->printSynthSolution(out);
+ d_qmodules->d_synth_e->printSynthSolution(out);
}else{
out << "Internal error : module for synth solution not found." << std::endl;
}
@@ -1192,18 +1054,6 @@ void QuantifiersEngine::getInstantiatedQuantifiedFormulas( std::vector< Node >&
d_instantiate->getInstantiatedQuantifiedFormulas(qs);
}
-void QuantifiersEngine::getInstantiations( std::map< Node, std::vector< Node > >& insts ) {
- d_instantiate->getInstantiations(insts);
-}
-
-void QuantifiersEngine::getInstantiations( Node q, std::vector< Node >& insts ) {
- d_instantiate->getInstantiations(q, insts);
-}
-
-Node QuantifiersEngine::getInstantiatedConjunction( Node q ) {
- return d_instantiate->getInstantiatedConjunction(q);
-}
-
QuantifiersEngine::Statistics::Statistics()
: d_time("theory::QuantifiersEngine::time"),
d_qcf_time("theory::QuantifiersEngine::time_qcf"),
@@ -1273,33 +1123,21 @@ QuantifiersEngine::Statistics::~Statistics(){
eq::EqualityEngine* QuantifiersEngine::getMasterEqualityEngine() const
{
- return d_te->getMasterEqualityEngine();
-}
-
-eq::EqualityEngine* QuantifiersEngine::getActiveEqualityEngine() const
-{
- if( d_useModelEe ){
- return d_model->getEqualityEngine();
- }
- return d_te->getMasterEqualityEngine();
+ return d_masterEqualityEngine;
}
Node QuantifiersEngine::getInternalRepresentative( Node a, Node q, int index ){
- bool prevModelEe = d_useModelEe;
- d_useModelEe = false;
- Node ret = d_eq_query->getInternalRepresentative( a, q, index );
- d_useModelEe = prevModelEe;
- return ret;
+ return d_eq_query->getInternalRepresentative(a, q, index);
}
bool QuantifiersEngine::getSynthSolutions(
std::map<Node, std::map<Node, Node> >& sol_map)
{
- return d_private->d_synth_e->getSynthSolutions(sol_map);
+ return d_qmodules->d_synth_e->getSynthSolutions(sol_map);
}
void QuantifiersEngine::debugPrintEqualityEngine( const char * c ) {
- eq::EqualityEngine* ee = getActiveEqualityEngine();
+ eq::EqualityEngine* ee = getMasterEqualityEngine();
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee );
std::map< TypeNode, int > typ_num;
while( !eqcs_i.isFinished() ){
diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h
index a4d858b16..8dcaf668f 100644
--- a/src/theory/quantifiers_engine.h
+++ b/src/theory/quantifiers_engine.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -45,21 +45,31 @@ class TheoryEngine;
namespace theory {
-class QuantifiersEnginePrivate;
+class DecisionManager;
+
+namespace quantifiers {
+class QuantifiersModules;
+}
// TODO: organize this more/review this, github issue #1163
class QuantifiersEngine {
+ friend class ::CVC4::TheoryEngine;
typedef context::CDHashMap< Node, bool, NodeHashFunction > BoolMap;
typedef context::CDList<Node> NodeList;
typedef context::CDList<bool> BoolList;
typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
-public:
- QuantifiersEngine(context::Context* c, context::UserContext* u, TheoryEngine* te);
+ public:
+ QuantifiersEngine(TheoryEngine* te, DecisionManager& dm,
+ ProofNodeManager* pnm);
~QuantifiersEngine();
+ /** finish initialize */
+ void finishInit();
//---------------------- external interface
/** get theory engine */
- TheoryEngine* getTheoryEngine() const { return d_te; }
+ TheoryEngine* getTheoryEngine() const;
+ /** Get the decision manager */
+ DecisionManager* getDecisionManager();
/** get default sat context for quantifiers engine */
context::Context* getSatContext();
/** get default sat context for quantifiers engine */
@@ -74,8 +84,6 @@ public:
//---------------------- utilities
/** get the master equality engine */
eq::EqualityEngine* getMasterEqualityEngine() const;
- /** get the active equality engine */
- eq::EqualityEngine* getActiveEqualityEngine() const;
/** get equality query */
EqualityQuery* getEqualityQuery() const;
/** get the model builder */
@@ -104,6 +112,10 @@ public:
inst::TriggerTrie* getTriggerDatabase() const;
//---------------------- end utilities
private:
+ //---------------------- private initialization
+ /** Set the master equality engine */
+ void setMasterEqualityEngine(eq::EqualityEngine* mee);
+ //---------------------- end private initialization
/**
* Maps quantified formulas to the module that owns them, if any module has
* specifically taken ownership of it.
@@ -115,7 +127,7 @@ public:
* precendence.
*/
std::map< Node, int > d_owner_priority;
-public:
+ public:
/** get owner */
QuantifiersModule * getOwner( Node q );
/**
@@ -193,104 +205,106 @@ private:
void flushLemmas();
public:
- /** add lemma lem */
- bool addLemma( Node lem, bool doCache = true, bool doRewrite = true );
- /** remove pending lemma */
- bool removeLemma( Node lem );
- /** add require phase */
- void addRequirePhase( Node lit, bool req );
- /** mark relevant quantified formula, this will indicate it should be checked before the others */
- void markRelevant( Node q );
- /** has added lemma */
- bool hasAddedLemma() const;
- /** theory engine needs check
- *
- * This is true if the theory engine has more constraints to process. When
- * it is false, we are tentatively going to terminate solving with
- * sat/unknown. For details, see TheoryEngine::needCheck.
- */
- bool theoryEngineNeedsCheck() const;
- /** is in conflict */
- bool inConflict() { return d_conflict; }
- /** set conflict */
- void setConflict();
- /** get current q effort */
- QuantifiersModule::QEffort getCurrentQEffort() { return d_curr_effort_level; }
- /** get number of waiting lemmas */
- unsigned getNumLemmasWaiting() { return d_lemmas_waiting.size(); }
- /** get needs check */
- bool getInstWhenNeedsCheck( Theory::Effort e );
- /** get user pat mode */
- options::UserPatMode getInstUserPatMode();
+ /**
+ * Add lemma to the lemma buffer of this quantifiers engine.
+ * @param lem The lemma to send
+ * @param doCache Whether to cache the lemma (to check for duplicate lemmas)
+ * @param doRewrite Whether to rewrite the lemma
+ * @return true if the lemma was successfully added to the buffer
+ */
+ bool addLemma(Node lem, bool doCache = true, bool doRewrite = true);
+ /**
+ * Add trusted lemma lem, same as above, but where a proof generator may be
+ * provided along with the lemma.
+ */
+ bool addTrustedLemma(TrustNode tlem,
+ bool doCache = true,
+ bool doRewrite = true);
+ /** remove pending lemma */
+ bool removeLemma(Node lem);
+ /** add require phase */
+ void addRequirePhase(Node lit, bool req);
+ /** mark relevant quantified formula, this will indicate it should be checked
+ * before the others */
+ void markRelevant(Node q);
+ /** has added lemma */
+ bool hasAddedLemma() const;
+ /** theory engine needs check
+ *
+ * This is true if the theory engine has more constraints to process. When
+ * it is false, we are tentatively going to terminate solving with
+ * sat/unknown. For details, see TheoryEngine::needCheck.
+ */
+ bool theoryEngineNeedsCheck() const;
+ /** is in conflict */
+ bool inConflict() { return d_conflict; }
+ /** set conflict */
+ void setConflict();
+ /** get current q effort */
+ QuantifiersModule::QEffort getCurrentQEffort() { return d_curr_effort_level; }
+ /** get number of waiting lemmas */
+ unsigned getNumLemmasWaiting() { return d_lemmas_waiting.size(); }
+ /** get needs check */
+ bool getInstWhenNeedsCheck(Theory::Effort e);
+ /** get user pat mode */
+ options::UserPatMode getInstUserPatMode();
- public:
- /** add term to database */
- void addTermToDatabase( Node n, bool withinQuant = false, bool withinInstClosure = false );
- /** notification when master equality engine is updated */
- void eqNotifyNewClass(TNode t);
- /** use model equality engine */
- bool usingModelEqualityEngine() const { return d_useModelEe; }
- /** debug print equality engine */
- void debugPrintEqualityEngine( const char * c );
- /** get internal representative
- *
- * Choose a term that is equivalent to a in the current context that is the
- * best term for instantiating the index^th variable of quantified formula q.
- * If no legal term can be found, we return null. This can occur if:
- * - a's type is not a subtype of the type of the index^th variable of q,
- * - a is in an equivalent class with all terms that are restricted not to
- * appear in instantiations of q, e.g. INST_CONSTANT terms for counterexample
- * guided instantiation.
- */
- Node getInternalRepresentative( Node a, Node q, int index );
+public:
+ /** add term to database */
+ void addTermToDatabase(Node n,
+ bool withinQuant = false,
+ bool withinInstClosure = false);
+ /** notification when master equality engine is updated */
+ void eqNotifyNewClass(TNode t);
+ /** debug print equality engine */
+ void debugPrintEqualityEngine(const char* c);
+ /** get internal representative
+ *
+ * Choose a term that is equivalent to a in the current context that is the
+ * best term for instantiating the index^th variable of quantified formula q.
+ * If no legal term can be found, we return null. This can occur if:
+ * - a's type is not a subtype of the type of the index^th variable of q,
+ * - a is in an equivalent class with all terms that are restricted not to
+ * appear in instantiations of q, e.g. INST_CONSTANT terms for counterexample
+ * guided instantiation.
+ */
+ Node getInternalRepresentative(Node a, Node q, int index);
- public:
- //----------user interface for instantiations (see quantifiers/instantiate.h)
- /** print instantiations */
- void printInstantiations(std::ostream& out);
- /** print solution for synthesis conjectures */
- void printSynthSolution(std::ostream& out);
- /** get list of quantified formulas that were instantiated */
- void getInstantiatedQuantifiedFormulas(std::vector<Node>& qs);
- /** get instantiations */
- void getInstantiations(Node q, std::vector<Node>& insts);
- void getInstantiations(std::map<Node, std::vector<Node> >& insts);
- /** get instantiation term vectors */
- void getInstantiationTermVectors(Node q,
- std::vector<std::vector<Node> >& tvecs);
- void getInstantiationTermVectors(
- std::map<Node, std::vector<std::vector<Node> > >& insts);
- /** get instantiated conjunction */
- Node getInstantiatedConjunction(Node q);
- /** get unsat core lemmas */
- bool getUnsatCoreLemmas(std::vector<Node>& active_lemmas);
- bool getUnsatCoreLemmas(std::vector<Node>& active_lemmas,
- std::map<Node, Node>& weak_imp);
- /** get explanation for instantiation lemmas */
- void getExplanationForInstLemmas(const std::vector<Node>& lems,
- std::map<Node, Node>& quant,
- std::map<Node, std::vector<Node> >& tvec);
+public:
+ //----------user interface for instantiations (see quantifiers/instantiate.h)
+ /** print instantiations */
+ void printInstantiations(std::ostream& out);
+ /** print solution for synthesis conjectures */
+ void printSynthSolution(std::ostream& out);
+ /** get list of quantified formulas that were instantiated */
+ void getInstantiatedQuantifiedFormulas(std::vector<Node>& qs);
+ /** get instantiation term vectors */
+ void getInstantiationTermVectors(Node q,
+ std::vector<std::vector<Node> >& tvecs);
+ void getInstantiationTermVectors(
+ std::map<Node, std::vector<std::vector<Node> > >& insts);
- /** get synth solutions
- *
- * This method returns true if there is a synthesis solution available. This
- * is the case if the last call to check satisfiability originated in a
- * check-synth call, and the synthesis engine module of this class
- * successfully found a solution for all active synthesis conjectures.
- *
- * This method adds entries to sol_map that map functions-to-synthesize with
- * their solutions, for all active conjectures. This should be called
- * immediately after the solver answers unsat for sygus input.
- *
- * For details on what is added to sol_map, see
- * SynthConjecture::getSynthSolutions.
- */
- bool getSynthSolutions(std::map<Node, std::map<Node, Node> >& sol_map);
+ /** get synth solutions
+ *
+ * This method returns true if there is a synthesis solution available. This
+ * is the case if the last call to check satisfiability originated in a
+ * check-synth call, and the synthesis engine module of this class
+ * successfully found a solution for all active synthesis conjectures.
+ *
+ * This method adds entries to sol_map that map functions-to-synthesize with
+ * their solutions, for all active conjectures. This should be called
+ * immediately after the solver answers unsat for sygus input.
+ *
+ * For details on what is added to sol_map, see
+ * SynthConjecture::getSynthSolutions.
+ */
+ bool getSynthSolutions(std::map<Node, std::map<Node, Node> >& sol_map);
- //----------end user interface for instantiations
+ //----------end user interface for instantiations
- /** statistics class */
- class Statistics {
+ /** statistics class */
+ class Statistics
+ {
public:
TimerStat d_time;
TimerStat d_qcf_time;
@@ -316,10 +330,18 @@ public:
~Statistics();
};/* class QuantifiersEngine::Statistics */
Statistics d_statistics;
-
+
private:
- /** reference to theory engine object */
+ /** Pointer to theory engine object */
TheoryEngine* d_te;
+ /** The SAT context */
+ context::Context* d_context;
+ /** The user context */
+ context::UserContext* d_userContext;
+ /** Reference to the decision manager of the theory engine */
+ DecisionManager& d_decManager;
+ /** Pointer to the master equality engine */
+ eq::EqualityEngine* d_masterEqualityEngine;
/** vector of utilities for quantifiers */
std::vector<QuantifiersUtil*> d_util;
/** vector of modules for quantifiers */
@@ -353,9 +375,9 @@ public:
std::unique_ptr<quantifiers::TermEnumeration> d_term_enum;
//------------- end quantifiers utilities
/**
- * The private utility, which contains all of the quantifiers modules.
+ * The modules utility, which contains all of the quantifiers modules.
*/
- std::unique_ptr<QuantifiersEnginePrivate> d_private;
+ std::unique_ptr<quantifiers::QuantifiersModules> d_qmodules;
//------------- temporary information during check
/** current effort level */
QuantifiersModule::QEffort d_curr_effort_level;
@@ -364,8 +386,6 @@ public:
context::CDO<bool> d_conflict_c;
/** has added lemma this round */
bool d_hasAddedLemma;
- /** whether to use model equality engine */
- bool d_useModelEe;
//------------- end temporary information during check
private:
/** list of all quantifiers seen */
@@ -380,6 +400,8 @@ public:
BoolMap d_lemmas_produced_c;
/** lemmas waiting */
std::vector<Node> d_lemmas_waiting;
+ /** map from waiting lemmas to their proof generators */
+ std::map<Node, ProofGenerator*> d_lemmasWaitingPg;
/** phase requirements waiting */
std::map<Node, bool> d_phase_req_waiting;
/** inst round counters TODO: make context-dependent? */
diff --git a/src/theory/relevance_manager.cpp b/src/theory/relevance_manager.cpp
new file mode 100644
index 000000000..e79c47b36
--- /dev/null
+++ b/src/theory/relevance_manager.cpp
@@ -0,0 +1,315 @@
+/********************* */
+/*! \file relevance_manager.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of relevance manager.
+ **/
+
+#include "theory/relevance_manager.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+
+RelevanceManager::RelevanceManager(context::UserContext* userContext,
+ Valuation val)
+ : d_val(val), d_input(userContext), d_computed(false), d_success(false)
+{
+}
+
+void RelevanceManager::notifyPreprocessedAssertions(
+ const std::vector<Node>& assertions)
+{
+ // add to input list, which is user-context dependent
+ std::vector<Node> toProcess;
+ for (const Node& a : assertions)
+ {
+ if (a.getKind() == AND)
+ {
+ // split top-level AND
+ for (const Node& ac : a)
+ {
+ toProcess.push_back(ac);
+ }
+ }
+ else
+ {
+ d_input.push_back(a);
+ }
+ }
+ addAssertionsInternal(toProcess);
+}
+
+void RelevanceManager::notifyPreprocessedAssertion(Node n)
+{
+ std::vector<Node> toProcess;
+ toProcess.push_back(n);
+ addAssertionsInternal(toProcess);
+}
+
+void RelevanceManager::addAssertionsInternal(std::vector<Node>& toProcess)
+{
+ size_t i = 0;
+ while (i < toProcess.size())
+ {
+ Node a = toProcess[i];
+ if (a.getKind() == AND)
+ {
+ // split AND
+ for (const Node& ac : a)
+ {
+ toProcess.push_back(ac);
+ }
+ }
+ else
+ {
+ // note that a could be a literal, in which case we could add it to
+ // an "always relevant" set here.
+ d_input.push_back(a);
+ }
+ i++;
+ }
+}
+
+void RelevanceManager::resetRound()
+{
+ d_computed = false;
+ d_rset.clear();
+}
+
+void RelevanceManager::computeRelevance()
+{
+ d_computed = true;
+ Trace("rel-manager") << "RelevanceManager::computeRelevance..." << std::endl;
+ std::unordered_map<TNode, int, TNodeHashFunction> cache;
+ for (const Node& node: d_input)
+ {
+ TNode n = node;
+ int val = justify(n, cache);
+ if (val != 1)
+ {
+ std::stringstream serr;
+ serr << "RelevanceManager::computeRelevance: WARNING: failed to justify "
+ << n;
+ Trace("rel-manager") << serr.str() << std::endl;
+ Assert(false) << serr.str();
+ d_success = false;
+ return;
+ }
+ }
+ Trace("rel-manager") << "...success, size = " << d_rset.size() << std::endl;
+ d_success = true;
+}
+
+bool RelevanceManager::isBooleanConnective(TNode cur)
+{
+ Kind k = cur.getKind();
+ return k == NOT || k == IMPLIES || k == AND || k == OR || k == ITE || k == XOR
+ || (k == EQUAL && cur[0].getType().isBoolean());
+}
+
+bool RelevanceManager::updateJustifyLastChild(
+ TNode cur,
+ std::vector<int>& childrenJustify,
+ std::unordered_map<TNode, int, TNodeHashFunction>& cache)
+{
+ // This method is run when we are informed that child index of cur
+ // has justify status lastChildJustify. We return true if we would like to
+ // compute the next child, in this case we push the status of the current
+ // child to childrenJustify.
+ size_t nchildren = cur.getNumChildren();
+ Assert(isBooleanConnective(cur));
+ size_t index = childrenJustify.size();
+ Assert(index < nchildren);
+ Assert(cache.find(cur[index]) != cache.end());
+ Kind k = cur.getKind();
+ // Lookup the last child's value in the overall cache, we may choose to
+ // add this to childrenJustify if we return true.
+ int lastChildJustify = cache[cur[index]];
+ if (k == NOT)
+ {
+ cache[cur] = -lastChildJustify;
+ }
+ else if (k == IMPLIES || k == AND || k == OR)
+ {
+ if (lastChildJustify != 0)
+ {
+ // See if we short circuited? The value for short circuiting is false if
+ // we are AND or the first child of IMPLIES.
+ if (lastChildJustify
+ == ((k == AND || (k == IMPLIES && index == 0)) ? -1 : 1))
+ {
+ cache[cur] = k == AND ? -1 : 1;
+ return false;
+ }
+ }
+ if (index + 1 == nchildren)
+ {
+ // finished all children, compute the overall value
+ int ret = k == AND ? 1 : -1;
+ for (int cv : childrenJustify)
+ {
+ if (cv == 0)
+ {
+ ret = 0;
+ break;
+ }
+ }
+ cache[cur] = ret;
+ }
+ else
+ {
+ // continue
+ childrenJustify.push_back(lastChildJustify);
+ return true;
+ }
+ }
+ else if (lastChildJustify == 0)
+ {
+ // all other cases, an unknown child implies we are unknown
+ cache[cur] = 0;
+ }
+ else if (k == ITE)
+ {
+ if (index == 0)
+ {
+ Assert(lastChildJustify != 0);
+ // continue with branch
+ childrenJustify.push_back(lastChildJustify);
+ if (lastChildJustify == -1)
+ {
+ // also mark first branch as don't care
+ childrenJustify.push_back(0);
+ }
+ return true;
+ }
+ else
+ {
+ // should be in proper branch
+ Assert(childrenJustify[0] == (index == 1 ? 1 : -1));
+ // we are the value of the branch
+ cache[cur] = lastChildJustify;
+ }
+ }
+ else
+ {
+ Assert(k == XOR || k == EQUAL);
+ Assert(nchildren == 2);
+ Assert(lastChildJustify != 0);
+ if (index == 0)
+ {
+ // must compute the other child
+ childrenJustify.push_back(lastChildJustify);
+ return true;
+ }
+ else
+ {
+ // both children known, compute value
+ Assert(childrenJustify.size() == 1 && childrenJustify[0] != 0);
+ cache[cur] =
+ ((k == XOR ? -1 : 1) * lastChildJustify == childrenJustify[0]) ? 1
+ : -1;
+ }
+ }
+ return false;
+}
+
+int RelevanceManager::justify(
+ TNode n, std::unordered_map<TNode, int, TNodeHashFunction>& cache)
+{
+ // the vector of values of children
+ std::unordered_map<TNode, std::vector<int>, TNodeHashFunction> childJustify;
+ std::unordered_map<TNode, int, TNodeHashFunction>::iterator it;
+ std::unordered_map<TNode, std::vector<int>, TNodeHashFunction>::iterator itc;
+ std::vector<TNode> visit;
+ TNode cur;
+ visit.push_back(n);
+ do
+ {
+ cur = visit.back();
+ // should always have Boolean type
+ Assert(cur.getType().isBoolean());
+ it = cache.find(cur);
+ if (it != cache.end())
+ {
+ visit.pop_back();
+ // already computed value
+ continue;
+ }
+ itc = childJustify.find(cur);
+ // have we traversed to children yet?
+ if (itc == childJustify.end())
+ {
+ // are we not a Boolean connective (including NOT)?
+ if (isBooleanConnective(cur))
+ {
+ // initialize its children justify vector as empty
+ childJustify[cur].clear();
+ // start with the first child
+ visit.push_back(cur[0]);
+ }
+ else
+ {
+ visit.pop_back();
+ // The atom case, lookup the value in the valuation class to
+ // see its current value in the SAT solver, if it has one.
+ int ret = 0;
+ // otherwise we look up the value
+ bool value;
+ if (d_val.hasSatValue(cur, value))
+ {
+ ret = value ? 1 : -1;
+ d_rset.insert(cur);
+ }
+ cache[cur] = ret;
+ }
+ }
+ else
+ {
+ // this processes the impact of the current child on the value of cur,
+ // and possibly requests that a new child is computed.
+ if (updateJustifyLastChild(cur, itc->second, cache))
+ {
+ Assert(itc->second.size() < cur.getNumChildren());
+ TNode nextChild = cur[itc->second.size()];
+ visit.push_back(nextChild);
+ }
+ else
+ {
+ visit.pop_back();
+ }
+ }
+ } while (!visit.empty());
+ Assert(cache.find(n) != cache.end());
+ return cache[n];
+}
+
+bool RelevanceManager::isRelevant(Node lit)
+{
+ if (!d_computed)
+ {
+ computeRelevance();
+ }
+ if (!d_success)
+ {
+ // always relevant if we failed to compute
+ return true;
+ }
+ // agnostic to negation
+ while (lit.getKind() == NOT)
+ {
+ lit = lit[0];
+ }
+ return d_rset.find(lit) != d_rset.end();
+}
+
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/relevance_manager.h b/src/theory/relevance_manager.h
new file mode 100644
index 000000000..6415ce287
--- /dev/null
+++ b/src/theory/relevance_manager.h
@@ -0,0 +1,154 @@
+/********************* */
+/*! \file relevance_manager.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Relevance manager.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__RELEVANCE_MANAGER__H
+#define CVC4__THEORY__RELEVANCE_MANAGER__H
+
+#include <unordered_map>
+#include <unordered_set>
+
+#include "context/cdlist.h"
+#include "expr/node.h"
+#include "theory/valuation.h"
+
+namespace CVC4 {
+namespace theory {
+
+/**
+ * This class manages queries related to relevance of asserted literals.
+ * In particular, note the following definition:
+ *
+ * Let F be a formula, and let L = { l_1, ..., l_n } be a set of
+ * literals that propositionally entail it. A "relevant selection of L with
+ * respect to F" is a subset of L that also propositionally entails F.
+ *
+ * This class computes a relevant selection of the current assertion stack
+ * at FULL effort with respect to the input formula + theory lemmas that are
+ * critical to justify (see LemmaProperty::NEEDS_JUSTIFY). By default, theory
+ * lemmas are not critical to justify; in fact, all T-valid theory lemmas
+ * are not critical to justify, since they are guaranteed to be satisfied in
+ * all inputs. However, some theory lemmas that introduce skolems need
+ * justification.
+ *
+ * As an example of such a lemma, take the example input formula:
+ * (and (exists ((x Int)) (P x)) (not (P 0)))
+ * A skolemization lemma like the following needs justification:
+ * (=> (exists ((x Int)) (P x)) (P k))
+ * Intuitively, this is because the satisfiability of the existential above is
+ * being deferred to the satisfiability of (P k) where k is fresh. Thus,
+ * a relevant selection must include both (exists ((x Int)) (P x)) and (P k)
+ * in this example.
+ *
+ * Theories are responsible for marking such lemmas using the NEEDS_JUSTIFY
+ * property when calling OutputChannel::lemma.
+ *
+ * Notice that this class has some relation to the justification decision
+ * heuristic (--decision=justification), which constructs a relevant selection
+ * of the input formula by construction. This class is orthogonal to this
+ * method, since it computes relevant selection *after* a full assignment. Thus
+ * its main advantage with respect to decision=justification is that it can be
+ * used in combination with any SAT decision heuristic.
+ *
+ * Internally, this class stores the input assertions and can be asked if an
+ * asserted literal is part of the current relevant selection. The relevant
+ * selection is computed lazily, i.e. only when someone asks if a literal is
+ * relevant, and only at most once per FULL effort check.
+ */
+class RelevanceManager
+{
+ typedef context::CDList<Node> NodeList;
+
+ public:
+ RelevanceManager(context::UserContext* userContext, Valuation val);
+ /**
+ * Notify (preprocessed) assertions. This is called for input formulas or
+ * lemmas that need justification that have been fully processed, just before
+ * adding them to the PropEngine.
+ */
+ void notifyPreprocessedAssertions(const std::vector<Node>& assertions);
+ /** Singleton version of above */
+ void notifyPreprocessedAssertion(Node n);
+ /**
+ * Reset round, called at the beginning of a full effort check in
+ * TheoryEngine.
+ */
+ void resetRound();
+ /**
+ * Is lit part of the current relevant selection? This call is valid during
+ * full effort check in TheoryEngine. This means that theories can query this
+ * during FULL or LAST_CALL efforts, through the Valuation class.
+ */
+ bool isRelevant(Node lit);
+
+ private:
+ /**
+ * Add the set of assertions to the formulas known to this class. This
+ * method handles optimizations such as breaking apart top-level applications
+ * of and.
+ */
+ void addAssertionsInternal(std::vector<Node>& toProcess);
+ /** compute the relevant selection */
+ void computeRelevance();
+ /**
+ * Justify formula n. To "justify" means we have added literals to our
+ * relevant selection set (d_rset) whose current values ensure that n
+ * evaluates to true or false.
+ *
+ * This method returns 1 if we justified n to be true, -1 means
+ * justified n to be false, 0 means n could not be justified.
+ */
+ int justify(TNode n,
+ std::unordered_map<TNode, int, TNodeHashFunction>& cache);
+ /** Is the top symbol of cur a Boolean connective? */
+ bool isBooleanConnective(TNode cur);
+ /**
+ * Update justify last child. This method is a helper function for justify,
+ * which is called at the moment that Boolean connective formula cur
+ * has a new child that has been computed in the justify cache.
+ *
+ * @param cur The Boolean connective formula
+ * @param childrenJustify The values of the previous children (not including
+ * the current one)
+ * @param cache The justify cache
+ * @return True if we wish to visit the next child. If this is the case, then
+ * the justify value of the current child is added to childrenJustify.
+ */
+ bool updateJustifyLastChild(
+ TNode cur,
+ std::vector<int>& childrenJustify,
+ std::unordered_map<TNode, int, TNodeHashFunction>& cache);
+ /** The valuation object, used to query current value of theory literals */
+ Valuation d_val;
+ /** The input assertions */
+ NodeList d_input;
+ /** The current relevant selection. */
+ std::unordered_set<TNode, TNodeHashFunction> d_rset;
+ /** Have we computed the relevant selection this round? */
+ bool d_computed;
+ /**
+ * Did we succeed in computing the relevant selection? If this is false, there
+ * was a syncronization issue between the input formula and the satisfying
+ * assignment since this class found that the input formula was not satisfied
+ * by the assignment. This should never happen, but if it does, this class
+ * aborts and indicates that all literals are relevant.
+ */
+ bool d_success;
+};
+
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__RELEVANCE_MANAGER__H */
diff --git a/src/theory/rep_set.cpp b/src/theory/rep_set.cpp
index 7e2c47ba7..6c2901bd3 100644
--- a/src/theory/rep_set.cpp
+++ b/src/theory/rep_set.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -41,7 +41,7 @@ bool RepSet::hasRep(TypeNode tn, Node n) const
}
}
-unsigned RepSet::getNumRepresentatives(TypeNode tn) const
+size_t RepSet::getNumRepresentatives(TypeNode tn) const
{
const std::vector<Node>* reps = getTypeRepsOrNull(tn);
return (reps != nullptr) ? reps->size() : 0;
diff --git a/src/theory/rep_set.h b/src/theory/rep_set.h
index 55871e5ce..acf214787 100644
--- a/src/theory/rep_set.h
+++ b/src/theory/rep_set.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -71,7 +71,7 @@ class RepSet {
/** does this set have representative n of type tn? */
bool hasRep(TypeNode tn, Node n) const;
/** get the number of representatives for type */
- unsigned getNumRepresentatives(TypeNode tn) const;
+ size_t getNumRepresentatives(TypeNode tn) const;
/** get representative at index */
Node getRepresentative(TypeNode tn, unsigned i) const;
/**
diff --git a/src/theory/rewriter.cpp b/src/theory/rewriter.cpp
index f2e13d1e0..725fa5cd8 100644
--- a/src/theory/rewriter.cpp
+++ b/src/theory/rewriter.cpp
@@ -2,10 +2,10 @@
/*! \file rewriter.cpp
** \verbatim
** Top contributors (to current version):
- ** Dejan Jovanovic, Andres Noetzli, Mathias Preiner
+ ** Andrew Reynolds, Andres Noetzli, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,6 +21,7 @@
#include "smt/smt_engine.h"
#include "smt/smt_engine_scope.h"
#include "smt/smt_statistics_registry.h"
+#include "theory/builtin/proof_checker.h"
#include "theory/rewriter_tables.h"
#include "theory/theory.h"
#include "util/resource_manager.h"
@@ -30,6 +31,13 @@ using namespace std;
namespace CVC4 {
namespace theory {
+/** Attribute true for nodes that have been rewritten with proofs enabled */
+struct RewriteWithProofsAttributeId
+{
+};
+typedef expr::Attribute<RewriteWithProofsAttributeId, bool>
+ RewriteWithProofsAttribute;
+
// Note that this function is a simplified version of Theory::theoryOf for
// (type-based) theoryOfMode. We expand and simplify it here for the sake of
// efficiency.
@@ -99,7 +107,6 @@ Node Rewriter::rewrite(TNode node) {
}
TrustNode Rewriter::rewriteWithProof(TNode node,
- bool elimTheoryRewrite,
bool isExtEq)
{
// must set the proof checker before calling this
@@ -115,13 +122,19 @@ TrustNode Rewriter::rewriteWithProof(TNode node,
return TrustNode::mkTrustRewrite(node, ret, d_tpg.get());
}
-void Rewriter::setProofChecker(ProofChecker* pc)
+void Rewriter::setProofNodeManager(ProofNodeManager* pnm)
{
// if not already initialized with proof support
if (d_tpg == nullptr)
{
- d_pnm.reset(new ProofNodeManager(pc));
- d_tpg.reset(new TConvProofGenerator(d_pnm.get()));
+ Trace("rewriter") << "Rewriter::setProofNodeManager" << std::endl;
+ // the rewriter is staticly determinstic, thus use static cache policy
+ // for the term conversion proof generator
+ d_tpg.reset(new TConvProofGenerator(pnm,
+ nullptr,
+ TConvPolicy::FIXPOINT,
+ TConvCachePolicy::STATIC,
+ "Rewriter::TConvProofGenerator"));
}
}
@@ -176,6 +189,7 @@ Node Rewriter::rewriteTo(theory::TheoryId theoryId,
Node node,
TConvProofGenerator* tcpg)
{
+ RewriteWithProofsAttribute rpfa;
#ifdef CVC4_ASSERTIONS
bool isEquality = node.getKind() == kind::EQUAL && (!node[0].getType().isBoolean());
@@ -189,7 +203,7 @@ Node Rewriter::rewriteTo(theory::TheoryId theoryId,
// Check if it's been cached already
Node cached = getPostRewriteCache(theoryId, node);
- if (!cached.isNull() && (tcpg == nullptr || tcpg->hasRewriteStep(node)))
+ if (!cached.isNull() && (tcpg == nullptr || node.getAttribute(rpfa)))
{
return cached;
}
@@ -205,11 +219,9 @@ Node Rewriter::rewriteTo(theory::TheoryId theoryId,
}
// Rewrite until the stack is empty
for (;;){
-
- if (hasSmtEngine &&
- d_iterationCount % ResourceManager::getFrequencyCount() == 0) {
+ if (hasSmtEngine)
+ {
rm->spendResource(ResourceManager::Resource::RewriteStep);
- d_iterationCount = 0;
}
// Get the top of the recursion stack
@@ -226,7 +238,7 @@ Node Rewriter::rewriteTo(theory::TheoryId theoryId,
cached = getPreRewriteCache(rewriteStackTop.getTheoryId(),
rewriteStackTop.d_node);
if (cached.isNull()
- || (tcpg != nullptr && !tcpg->hasRewriteStep(rewriteStackTop.d_node)))
+ || (tcpg != nullptr && !rewriteStackTop.d_node.getAttribute(rpfa)))
{
// Rewrite until fix-point is reached
for(;;) {
@@ -265,7 +277,7 @@ Node Rewriter::rewriteTo(theory::TheoryId theoryId,
rewriteStackTop.d_node);
// If not, go through the children
if (cached.isNull()
- || (tcpg != nullptr && !tcpg->hasRewriteStep(rewriteStackTop.d_node)))
+ || (tcpg != nullptr && !rewriteStackTop.d_node.getAttribute(rpfa)))
{
// The child we need to rewrite
unsigned child = rewriteStackTop.d_nextChild++;
@@ -349,6 +361,37 @@ Node Rewriter::rewriteTo(theory::TheoryId theoryId,
}
// We're done with the post rewrite, so we add to the cache
+ if (tcpg != nullptr)
+ {
+ // if proofs are enabled, mark that we've rewritten with proofs
+ rewriteStackTop.d_original.setAttribute(rpfa, true);
+ if (!cached.isNull())
+ {
+ // We may have gotten a different node, due to non-determinism in
+ // theory rewriters (e.g. quantifiers rewriter which introduces
+ // fresh BOUND_VARIABLE). This can happen if we wrote once without
+ // proofs and then rewrote again with proofs.
+ if (rewriteStackTop.d_node != cached)
+ {
+ Trace("rewriter-proof") << "WARNING: Rewritten forms with and "
+ "without proofs were not equivalent"
+ << std::endl;
+ Trace("rewriter-proof")
+ << " original: " << rewriteStackTop.d_original << std::endl;
+ Trace("rewriter-proof")
+ << "with proofs: " << rewriteStackTop.d_node << std::endl;
+ Trace("rewriter-proof") << " w/o proofs: " << cached << std::endl;
+ Node eq = rewriteStackTop.d_node.eqNode(cached);
+ tcpg->addRewriteStep(rewriteStackTop.d_node,
+ cached,
+ PfRule::TRUST_REWRITE,
+ {},
+ {eq});
+ // don't overwrite the cache, should be the same
+ rewriteStackTop.d_node = cached;
+ }
+ }
+ }
setPostRewriteCache(rewriteStackTop.getOriginalTheoryId(),
rewriteStackTop.d_original,
rewriteStackTop.d_node);
@@ -391,7 +434,7 @@ RewriteResponse Rewriter::preRewrite(theory::TheoryId theoryId,
d_theoryRewriters[theoryId]->preRewriteWithProof(n);
// process the trust rewrite response: store the proof step into
// tcpg if necessary and then convert to rewrite response.
- return processTrustRewriteResponse(tresponse, true, tcpg);
+ return processTrustRewriteResponse(theoryId, tresponse, true, tcpg);
}
return d_theoryRewriters[theoryId]->preRewrite(n);
}
@@ -412,7 +455,7 @@ RewriteResponse Rewriter::postRewrite(theory::TheoryId theoryId,
// same as above, for post-rewrite
TrustRewriteResponse tresponse =
d_theoryRewriters[theoryId]->postRewriteWithProof(n);
- return processTrustRewriteResponse(tresponse, false, tcpg);
+ return processTrustRewriteResponse(theoryId, tresponse, false, tcpg);
}
return d_theoryRewriters[theoryId]->postRewrite(n);
}
@@ -420,6 +463,7 @@ RewriteResponse Rewriter::postRewrite(theory::TheoryId theoryId,
}
RewriteResponse Rewriter::processTrustRewriteResponse(
+ theory::TheoryId theoryId,
const TrustRewriteResponse& tresponse,
bool isPre,
TConvProofGenerator* tcpg)
@@ -433,13 +477,15 @@ RewriteResponse Rewriter::processTrustRewriteResponse(
ProofGenerator* pg = trn.getGenerator();
if (pg == nullptr)
{
+ Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(theoryId);
// add small step trusted rewrite
- NodeManager* nm = NodeManager::currentNM();
+ Node rid = mkMethodId(isPre ? MethodId::RW_REWRITE_THEORY_PRE
+ : MethodId::RW_REWRITE_THEORY_POST);
tcpg->addRewriteStep(proven[0],
proven[1],
PfRule::THEORY_REWRITE,
{},
- {proven[0], nm->mkConst(isPre)});
+ {proven, tidn, rid});
}
else
{
diff --git a/src/theory/rewriter.h b/src/theory/rewriter.h
index c57844f23..572662483 100644
--- a/src/theory/rewriter.h
+++ b/src/theory/rewriter.h
@@ -2,10 +2,10 @@
/*! \file rewriter.h
** \verbatim
** Top contributors (to current version):
- ** Andres Noetzli, Dejan Jovanovic, Morgan Deters
+ ** Andres Noetzli, Andrew Reynolds, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -80,22 +80,19 @@ class Rewriter {
/**
* Rewrite with proof production, which is managed by the term conversion
* proof generator managed by this class (d_tpg). This method requires a call
- * to setProofChecker prior to this call.
+ * to setProofNodeManager prior to this call.
*
* @param node The node to rewrite.
- * @param elimTheoryRewrite Whether we also want fine-grained proofs for
- * THEORY_REWRITE steps.
* @param isExtEq Whether node is an equality which we are applying
* rewriteEqualityExt on.
* @return The trust node of kind TrustNodeKind::REWRITE that contains the
* rewritten form of node.
*/
TrustNode rewriteWithProof(TNode node,
- bool elimTheoryRewrite = false,
bool isExtEq = false);
- /** Set proof checker */
- void setProofChecker(ProofChecker* pc);
+ /** Set proof node manager */
+ void setProofNodeManager(ProofNodeManager* pnm);
/**
* Garbage collects the rewrite caches.
@@ -189,6 +186,7 @@ class Rewriter {
TConvProofGenerator* tcpg = nullptr);
/** processes a trust rewrite response */
RewriteResponse processTrustRewriteResponse(
+ theory::TheoryId theoryId,
const TrustRewriteResponse& tresponse,
bool isPre,
TConvProofGenerator* tcpg);
@@ -203,8 +201,6 @@ class Rewriter {
/** Theory rewriters used by this rewriter instance */
TheoryRewriter* d_theoryRewriters[theory::THEORY_LAST];
- unsigned long d_iterationCount = 0;
-
/** Rewriter table for prewrites. Maps kinds to rewriter function. */
std::function<RewriteResponse(RewriteEnvironment*, TNode)>
d_preRewriters[kind::LAST_KIND];
@@ -226,8 +222,6 @@ class Rewriter {
RewriteEnvironment d_re;
- /** The proof node manager */
- std::unique_ptr<ProofNodeManager> d_pnm;
/** The proof generator */
std::unique_ptr<TConvProofGenerator> d_tpg;
#ifdef CVC4_ASSERTIONS
diff --git a/src/theory/rewriter_attributes.h b/src/theory/rewriter_attributes.h
index 1e5e882fe..ec3ca351a 100644
--- a/src/theory/rewriter_attributes.h
+++ b/src/theory/rewriter_attributes.h
@@ -5,7 +5,7 @@
** Dejan Jovanovic, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/rewriter_tables_template.h b/src/theory/rewriter_tables_template.h
index 4ef96cc5e..4e350dca9 100644
--- a/src/theory/rewriter_tables_template.h
+++ b/src/theory/rewriter_tables_template.h
@@ -5,7 +5,7 @@
** Dejan Jovanovic, Tim King, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -61,7 +61,7 @@ ${post_rewrite_set_cache}
}
}
-Rewriter::Rewriter()
+Rewriter::Rewriter() : d_tpg(nullptr)
{
for (size_t i = 0; i < kind::LAST_KIND; ++i)
{
diff --git a/src/theory/sep/kinds b/src/theory/sep/kinds
index 235b61172..7a3fb00a4 100644
--- a/src/theory/sep/kinds
+++ b/src/theory/sep/kinds
@@ -8,7 +8,7 @@ theory THEORY_SEP ::CVC4::theory::sep::TheorySep "theory/sep/theory_sep.h"
typechecker "theory/sep/theory_sep_type_rules.h"
properties polite stable-infinite parametric
-properties check propagate presolve
+properties check presolve
rewriter ::CVC4::theory::sep::TheorySepRewriter "theory/sep/theory_sep_rewriter.h"
diff --git a/src/theory/sep/theory_sep.cpp b/src/theory/sep/theory_sep.cpp
index 2f5e40be5..4a7f4367e 100644
--- a/src/theory/sep/theory_sep.cpp
+++ b/src/theory/sep/theory_sep.cpp
@@ -2,10 +2,10 @@
/*! \file theory_sep.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Dejan Jovanovic, Tim King
+ ** Andrew Reynolds, Tim King, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -34,6 +34,7 @@
#include "theory/valuation.h"
using namespace std;
+using namespace CVC4::kind;
namespace CVC4 {
namespace theory {
@@ -47,21 +48,19 @@ TheorySep::TheorySep(context::Context* c,
ProofNodeManager* pnm)
: Theory(THEORY_SEP, c, u, out, valuation, logicInfo, pnm),
d_lemmas_produced_c(u),
+ d_bounds_init(false),
+ d_state(c, u, valuation),
+ d_im(*this, d_state, nullptr),
d_notify(*this),
- d_equalityEngine(d_notify, c, "theory::sep::ee", true),
- d_conflict(c, false),
d_reduce(u),
- d_infer(c),
- d_infer_exp(c),
d_spatial_assertions(c)
{
d_true = NodeManager::currentNM()->mkConst<bool>(true);
d_false = NodeManager::currentNM()->mkConst<bool>(false);
- d_bounds_init = false;
-
- // The kinds we are treating as function application in congruence
- d_equalityEngine.addFunctionKind(kind::SEP_PTO);
- //d_equalityEngine.addFunctionKind(kind::SEP_STAR);
+
+ // indicate we are using the default theory state object
+ d_theoryState = &d_state;
+ d_inferManager = &d_im;
}
TheorySep::~TheorySep() {
@@ -70,8 +69,46 @@ TheorySep::~TheorySep() {
}
}
-void TheorySep::setMasterEqualityEngine(eq::EqualityEngine* eq) {
- d_equalityEngine.setMasterEqualityEngine(eq);
+void TheorySep::declareSepHeap(TypeNode locT, TypeNode dataT)
+{
+ if (!d_type_ref.isNull())
+ {
+ TypeNode te1 = d_loc_to_data_type.begin()->first;
+ std::stringstream ss;
+ ss << "ERROR: cannot declare heap types for separation logic more than "
+ "once. We are declaring heap of type ";
+ ss << locT << " -> " << dataT << ", but we already have ";
+ ss << d_type_ref << " -> " << d_type_data;
+ throw LogicException(ss.str());
+ }
+ Node nullAtom;
+ registerRefDataTypes(locT, dataT, nullAtom);
+}
+
+TheoryRewriter* TheorySep::getTheoryRewriter() { return &d_rewriter; }
+
+bool TheorySep::needsEqualityEngine(EeSetupInfo& esi)
+{
+ esi.d_notify = &d_notify;
+ esi.d_name = "theory::sep::ee";
+ return true;
+}
+
+void TheorySep::finishInit()
+{
+ Assert(d_equalityEngine != nullptr);
+ // The kinds we are treating as function application in congruence
+ d_equalityEngine->addFunctionKind(kind::SEP_PTO);
+ // we could but don't do congruence on SEP_STAR here.
+}
+
+void TheorySep::preRegisterTerm(TNode n)
+{
+ Kind k = n.getKind();
+ if (k == SEP_PTO || k == SEP_EMP || k == SEP_STAR || k == SEP_WAND)
+ {
+ registerRefDataTypesAtom(n);
+ }
}
Node TheorySep::mkAnd( std::vector< TNode >& assumptions ) {
@@ -84,67 +121,32 @@ Node TheorySep::mkAnd( std::vector< TNode >& assumptions ) {
}
}
-/////////////////////////////////////////////////////////////////////////////
-// PREPROCESSING
-/////////////////////////////////////////////////////////////////////////////
-
-
-Theory::PPAssertStatus TheorySep::ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
-
- return PP_ASSERT_STATUS_UNSOLVED;
-}
-
/////////////////////////////////////////////////////////////////////////////
// T-PROPAGATION / REGISTRATION
/////////////////////////////////////////////////////////////////////////////
-
-bool TheorySep::propagate(TNode literal)
+bool TheorySep::propagateLit(TNode literal)
{
- Debug("sep") << "TheorySep::propagate(" << literal << ")" << std::endl;
+ Debug("sep") << "TheorySep::propagateLit(" << literal << ")" << std::endl;
// If already in conflict, no more propagation
- if (d_conflict) {
- Debug("sep") << "TheorySep::propagate(" << literal << "): already in conflict" << std::endl;
+ if (d_state.isInConflict())
+ {
+ Debug("sep") << "TheorySep::propagateLit(" << literal
+ << "): already in conflict" << std::endl;
return false;
}
bool ok = d_out->propagate(literal);
if (!ok) {
- d_conflict = true;
+ d_state.notifyInConflict();
}
return ok;
-}/* TheorySep::propagate(TNode) */
-
-
-void TheorySep::explain(TNode literal, std::vector<TNode>& assumptions) {
- if( literal.getKind()==kind::SEP_LABEL ||
- ( literal.getKind()==kind::NOT && literal[0].getKind()==kind::SEP_LABEL ) ){
- //labelled assertions are never given to equality engine and should only come from the outside
- assumptions.push_back( literal );
- }else{
- // Do the work
- bool polarity = literal.getKind() != kind::NOT;
- TNode atom = polarity ? literal : literal[0];
- if (atom.getKind() == kind::EQUAL) {
- d_equalityEngine.explainEquality( atom[0], atom[1], polarity, assumptions, NULL );
- } else {
- d_equalityEngine.explainPredicate( atom, polarity, assumptions );
- }
- }
-}
-
-
-void TheorySep::propagate(Effort e){
-
}
TrustNode TheorySep::explain(TNode literal)
{
Debug("sep") << "TheorySep::explain(" << literal << ")" << std::endl;
- std::vector<TNode> assumptions;
- explain(literal, assumptions);
- Node exp = mkAnd(assumptions);
- return TrustNode::mkTrustPropExp(literal, exp, nullptr);
+ return d_im.explainLit(literal);
}
@@ -152,27 +154,6 @@ TrustNode TheorySep::explain(TNode literal)
// SHARING
/////////////////////////////////////////////////////////////////////////////
-
-void TheorySep::addSharedTerm(TNode t) {
- Debug("sep") << "TheorySep::addSharedTerm(" << t << ")" << std::endl;
- d_equalityEngine.addTriggerTerm(t, THEORY_SEP);
-}
-
-
-EqualityStatus TheorySep::getEqualityStatus(TNode a, TNode b) {
- Assert(d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b));
- if (d_equalityEngine.areEqual(a, b)) {
- // The terms are implied to be equal
- return EQUALITY_TRUE;
- }
- else if (d_equalityEngine.areDisequal(a, b, false)) {
- // The terms are implied to be dis-equal
- return EQUALITY_FALSE;
- }
- return EQUALITY_UNKNOWN;//FALSE_IN_MODEL;
-}
-
-
void TheorySep::computeCareGraph() {
Debug("sharing") << "Theory::computeCareGraph<" << getId() << ">()" << endl;
for (unsigned i = 0; i < d_sharedTerms.size(); ++ i) {
@@ -203,17 +184,6 @@ void TheorySep::computeCareGraph() {
// MODEL GENERATION
/////////////////////////////////////////////////////////////////////////////
-bool TheorySep::collectModelInfo(TheoryModel* m)
-{
- set<Node> termSet;
-
- // Compute terms appearing in assertions and shared terms
- computeRelevantTerms(termSet);
-
- // Send the equality engine information to the model
- return m->assertEqualityEngine(&d_equalityEngine, &termSet);
-}
-
void TheorySep::postProcessModel( TheoryModel* m ){
Trace("sep-model") << "Printing model for TheorySep..." << std::endl;
@@ -294,7 +264,6 @@ void TheorySep::postProcessModel( TheoryModel* m ){
void TheorySep::presolve() {
Trace("sep-pp") << "Presolving" << std::endl;
- //TODO: cleanup if incremental?
}
@@ -302,532 +271,665 @@ void TheorySep::presolve() {
// MAIN SOLVER
/////////////////////////////////////////////////////////////////////////////
-
-void TheorySep::check(Effort e) {
- if (done() && !fullEffort(e) && e != EFFORT_LAST_CALL) {
- return;
+bool TheorySep::preNotifyFact(
+ TNode atom, bool polarity, TNode fact, bool isPrereg, bool isInternal)
+{
+ TNode satom = atom.getKind() == SEP_LABEL ? atom[0] : atom;
+ TNode slbl = atom.getKind() == SEP_LABEL ? atom[1] : TNode::null();
+ bool isSpatial = isSpatialKind(satom.getKind());
+ if (isSpatial)
+ {
+ reduceFact(atom, polarity, fact);
+ if (!slbl.isNull())
+ {
+ d_spatial_assertions.push_back(fact);
+ }
+ }
+ // assert to equality if non-spatial or a labelled pto
+ if (!isSpatial || (!slbl.isNull() && satom.getKind() == SEP_PTO))
+ {
+ return false;
}
+ // otherwise, maybe propagate
+ doPending();
+ return true;
+}
- getOutputChannel().spendResource(ResourceManager::Resource::TheoryCheckStep);
+void TheorySep::notifyFact(TNode atom,
+ bool polarity,
+ TNode fact,
+ bool isInternal)
+{
+ TNode satom = atom.getKind() == SEP_LABEL ? atom[0] : atom;
+ if (atom.getKind() == SEP_LABEL && atom[0].getKind() == SEP_PTO)
+ {
+ // associate the equivalence class of the lhs with this pto
+ Node r = getRepresentative(atom[1]);
+ HeapAssertInfo* ei = getOrMakeEqcInfo(r, true);
+ addPto(ei, r, atom, polarity);
+ }
+ // maybe propagate
+ doPending();
+}
- TimerStat::CodeTimer checkTimer(d_checkTime);
- Trace("sep-check") << "Sep::check(): " << e << endl;
+void TheorySep::reduceFact(TNode atom, bool polarity, TNode fact)
+{
+ if (d_reduce.find(fact) != d_reduce.end())
+ {
+ // already reduced
+ return;
+ }
+ d_reduce.insert(fact);
+ TNode satom = atom.getKind() == SEP_LABEL ? atom[0] : atom;
+ TNode slbl = atom.getKind() == SEP_LABEL ? atom[1] : TNode::null();
NodeManager* nm = NodeManager::currentNM();
-
- while( !done() && !d_conflict ){
- // Get all the assertions
- Assertion assertion = get();
- TNode fact = assertion.d_assertion;
-
- Trace("sep-assert") << "TheorySep::check(): processing " << fact << std::endl;
-
- bool polarity = fact.getKind() != kind::NOT;
- TNode atom = polarity ? fact : fact[0];
- /*
- if( atom.getKind()==kind::SEP_EMP ){
- TypeNode tn = atom[0].getType();
- if( d_emp_arg.find( tn )==d_emp_arg.end() ){
- d_emp_arg[tn] = atom[0];
- }else{
- //normalize argument TODO
- }
+ if (slbl.isNull())
+ {
+ Trace("sep-lemma-debug")
+ << "Reducing unlabelled assertion " << atom << std::endl;
+ // introduce top-level label, add iff
+ TypeNode refType = getReferenceType(satom);
+ Trace("sep-lemma-debug")
+ << "...reference type is : " << refType << std::endl;
+ Node b_lbl = getBaseLabel(refType);
+ Node satom_new = nm->mkNode(SEP_LABEL, satom, b_lbl);
+ Node lem;
+ Trace("sep-lemma-debug") << "...polarity is " << polarity << std::endl;
+ if (polarity)
+ {
+ lem = nm->mkNode(OR, satom.negate(), satom_new);
}
- */
- TNode s_atom = atom.getKind()==kind::SEP_LABEL ? atom[0] : atom;
- TNode s_lbl = atom.getKind()==kind::SEP_LABEL ? atom[1] : TNode::null();
- bool is_spatial = s_atom.getKind()==kind::SEP_STAR || s_atom.getKind()==kind::SEP_WAND || s_atom.getKind()==kind::SEP_PTO || s_atom.getKind()==kind::SEP_EMP;
- if( is_spatial && s_lbl.isNull() ){
- if( d_reduce.find( fact )==d_reduce.end() ){
- Trace("sep-lemma-debug") << "Reducing unlabelled assertion " << atom << std::endl;
- d_reduce.insert( fact );
- //introduce top-level label, add iff
- TypeNode refType = getReferenceType( s_atom );
- Trace("sep-lemma-debug") << "...reference type is : " << refType << std::endl;
- Node b_lbl = getBaseLabel( refType );
- Node s_atom_new = NodeManager::currentNM()->mkNode( kind::SEP_LABEL, s_atom, b_lbl );
- Node lem;
- Trace("sep-lemma-debug") << "...polarity is " << polarity << std::endl;
- if( polarity ){
- lem = NodeManager::currentNM()->mkNode( kind::OR, s_atom.negate(), s_atom_new );
- }else{
- lem = NodeManager::currentNM()->mkNode( kind::OR, s_atom, s_atom_new.negate() );
- }
- Trace("sep-lemma-debug") << "Sep::Lemma : base reduction : " << lem << std::endl;
- d_out->lemma( lem );
+ else
+ {
+ lem = nm->mkNode(OR, satom, satom_new.negate());
+ }
+ Trace("sep-lemma-debug")
+ << "Sep::Lemma : base reduction : " << lem << std::endl;
+ d_out->lemma(lem);
+ return;
+ }
+ Trace("sep-lemma-debug") << "Reducing assertion " << fact << std::endl;
+ Node conc;
+ if (Node* in_map = FindOrNull(d_red_conc[slbl], satom))
+ {
+ conc = *in_map;
+ }
+ else
+ {
+ // make conclusion based on type of assertion
+ if (satom.getKind() == SEP_STAR || satom.getKind() == SEP_WAND)
+ {
+ std::vector<Node> children;
+ std::vector<Node> c_lems;
+ TypeNode tn = getReferenceType(satom);
+ if (d_reference_bound_max.find(tn) != d_reference_bound_max.end())
+ {
+ c_lems.push_back(nm->mkNode(SUBSET, slbl, d_reference_bound_max[tn]));
}
- }else{
- //do reductions
- if( is_spatial ){
- if( d_reduce.find( fact )==d_reduce.end() ){
- Trace("sep-lemma-debug") << "Reducing assertion " << fact << std::endl;
- d_reduce.insert( fact );
- Node conc;
- if (Node* in_map = FindOrNull(d_red_conc[s_lbl], s_atom))
- {
- conc = *in_map;
- }
- else
+ std::vector<Node> labels;
+ getLabelChildren(satom, slbl, children, labels);
+ Node empSet = nm->mkConst(EmptySet(slbl.getType()));
+ Assert(children.size() > 1);
+ if (satom.getKind() == SEP_STAR)
+ {
+ // reduction for heap : union, pairwise disjoint
+ Node ulem = nm->mkNode(UNION, labels[0], labels[1]);
+ size_t lsize = labels.size();
+ for (size_t i = 2; i < lsize; i++)
+ {
+ ulem = nm->mkNode(UNION, ulem, labels[i]);
+ }
+ ulem = slbl.eqNode(ulem);
+ Trace("sep-lemma-debug")
+ << "Sep::Lemma : star reduction, union : " << ulem << std::endl;
+ c_lems.push_back(ulem);
+ for (size_t i = 0; i < lsize; i++)
+ {
+ for (size_t j = (i + 1); j < lsize; j++)
{
- //make conclusion based on type of assertion
- if( s_atom.getKind()==kind::SEP_STAR || s_atom.getKind()==kind::SEP_WAND ){
- std::vector< Node > children;
- std::vector< Node > c_lems;
- TypeNode tn = getReferenceType( s_atom );
- if( d_reference_bound_max.find( tn )!=d_reference_bound_max.end() ){
- c_lems.push_back( NodeManager::currentNM()->mkNode( kind::SUBSET, s_lbl, d_reference_bound_max[tn] ) );
- }
- std::vector< Node > labels;
- getLabelChildren( s_atom, s_lbl, children, labels );
- Node empSet =
- NodeManager::currentNM()->mkConst(EmptySet(s_lbl.getType()));
- Assert(children.size() > 1);
- if( s_atom.getKind()==kind::SEP_STAR ){
- //reduction for heap : union, pairwise disjoint
- Node ulem = NodeManager::currentNM()->mkNode( kind::UNION, labels[0], labels[1] );
- for( unsigned i=2; i<labels.size(); i++ ){
- ulem = NodeManager::currentNM()->mkNode( kind::UNION, ulem, labels[i] );
- }
- ulem = s_lbl.eqNode( ulem );
- Trace("sep-lemma-debug") << "Sep::Lemma : star reduction, union : " << ulem << std::endl;
- c_lems.push_back( ulem );
- for( unsigned i=0; i<labels.size(); i++ ){
- for( unsigned j=(i+1); j<labels.size(); j++ ){
- Node s = NodeManager::currentNM()->mkNode( kind::INTERSECTION, labels[i], labels[j] );
- Node ilem = s.eqNode( empSet );
- Trace("sep-lemma-debug") << "Sep::Lemma : star reduction, disjoint : " << ilem << std::endl;
- c_lems.push_back( ilem );
- }
- }
- }else{
- Node ulem = NodeManager::currentNM()->mkNode( kind::UNION, s_lbl, labels[0] );
- ulem = ulem.eqNode( labels[1] );
- Trace("sep-lemma-debug") << "Sep::Lemma : wand reduction, union : " << ulem << std::endl;
- c_lems.push_back( ulem );
- Node s = NodeManager::currentNM()->mkNode( kind::INTERSECTION, s_lbl, labels[0] );
- Node ilem = s.eqNode( empSet );
- Trace("sep-lemma-debug") << "Sep::Lemma : wand reduction, disjoint : " << ilem << std::endl;
- c_lems.push_back( ilem );
- //nil does not occur in labels[0]
- Node nr = getNilRef( tn );
- Node nrlem = NodeManager::currentNM()->mkNode( kind::MEMBER, nr, labels[0] ).negate();
- Trace("sep-lemma") << "Sep::Lemma: sep.nil not in wand antecedant heap : " << nrlem << std::endl;
- d_out->lemma( nrlem );
- }
- //send out definitional lemmas for introduced sets
- for( unsigned j=0; j<c_lems.size(); j++ ){
- Trace("sep-lemma") << "Sep::Lemma : definition : " << c_lems[j] << std::endl;
- d_out->lemma( c_lems[j] );
- }
- //children.insert( children.end(), c_lems.begin(), c_lems.end() );
- conc = NodeManager::currentNM()->mkNode( kind::AND, children );
- }else if( s_atom.getKind()==kind::SEP_PTO ){
- Node ss = NodeManager::currentNM()->mkNode( kind::SINGLETON, s_atom[0] );
- if( s_lbl!=ss ){
- conc = s_lbl.eqNode( ss );
- }
- //not needed anymore: semantics of sep.nil is enforced globally
- //Node ssn = NodeManager::currentNM()->mkNode( kind::EQUAL, s_atom[0], getNilRef(s_atom[0].getType()) ).negate();
- //conc = conc.isNull() ? ssn : NodeManager::currentNM()->mkNode( kind::AND, conc, ssn );
-
- }else if( s_atom.getKind()==kind::SEP_EMP ){
- // conc = s_lbl.eqNode(
- // NodeManager::currentNM()->mkConst(EmptySet(s_lbl.getType())) );
- Node lem;
- Node emp_s =
- NodeManager::currentNM()->mkConst(EmptySet(s_lbl.getType()));
- if( polarity ){
- lem = NodeManager::currentNM()->mkNode( kind::OR, fact.negate(), s_lbl.eqNode( emp_s ) );
- }else{
- Node kl = NodeManager::currentNM()->mkSkolem( "loc", getReferenceType( s_atom ) );
- Node kd = NodeManager::currentNM()->mkSkolem( "data", getDataType( s_atom ) );
- Node econc = NodeManager::currentNM()->mkNode( kind::SEP_LABEL,
- NodeManager::currentNM()->mkNode( kind::SEP_STAR, NodeManager::currentNM()->mkNode( kind::SEP_PTO, kl, kd ), d_true ), s_lbl );
- //Node econc = NodeManager::currentNM()->mkNode( kind::AND, s_lbl.eqNode( emp_s ).negate(),
- lem = NodeManager::currentNM()->mkNode( kind::OR, fact.negate(), econc );
- }
- Trace("sep-lemma") << "Sep::Lemma : emp : " << lem << std::endl;
- d_out->lemma( lem );
-
- }else{
- //labeled emp should be rewritten
- Assert(false);
- }
- d_red_conc[s_lbl][s_atom] = conc;
- }
- if( !conc.isNull() ){
- bool use_polarity = s_atom.getKind()==kind::SEP_WAND ? !polarity : polarity;
- if( !use_polarity ){
- // introduce guard, assert positive version
- Trace("sep-lemma-debug") << "Negated spatial constraint asserted to sep theory: " << fact << std::endl;
- Node g = nm->mkSkolem("G", nm->booleanType());
- d_neg_guard_strategy[g].reset(new DecisionStrategySingleton(
- "sep_neg_guard", g, getSatContext(), getValuation()));
- DecisionStrategySingleton* ds = d_neg_guard_strategy[g].get();
- getDecisionManager()->registerStrategy(
- DecisionManager::STRAT_SEP_NEG_GUARD, ds);
- Node lit = ds->getLiteral(0);
- d_neg_guard[s_lbl][s_atom] = lit;
- Trace("sep-lemma-debug") << "Neg guard : " << s_lbl << " " << s_atom << " " << lit << std::endl;
- AlwaysAssert(!lit.isNull());
- d_neg_guards.push_back( lit );
- d_guard_to_assertion[lit] = s_atom;
- //Node lem = NodeManager::currentNM()->mkNode( kind::EQUAL, lit, conc );
- Node lem = NodeManager::currentNM()->mkNode( kind::OR, lit.negate(), conc );
- Trace("sep-lemma") << "Sep::Lemma : (neg) reduction : " << lem << std::endl;
- d_out->lemma( lem );
- }else{
- //reduce based on implication
- Node lem = NodeManager::currentNM()->mkNode( kind::OR, fact.negate(), conc );
- Trace("sep-lemma") << "Sep::Lemma : reduction : " << lem << std::endl;
- d_out->lemma( lem );
- }
- }else{
- Trace("sep-lemma-debug") << "Trivial conclusion, do not add lemma." << std::endl;
+ Node s = nm->mkNode(INTERSECTION, labels[i], labels[j]);
+ Node ilem = s.eqNode(empSet);
+ Trace("sep-lemma-debug")
+ << "Sep::Lemma : star reduction, disjoint : " << ilem
+ << std::endl;
+ c_lems.push_back(ilem);
}
}
}
- //assert to equality engine
- if( !is_spatial ){
- Trace("sep-assert") << "Asserting " << atom << ", pol = " << polarity << " to EE..." << std::endl;
- if( s_atom.getKind()==kind::EQUAL ){
- d_equalityEngine.assertEquality(atom, polarity, fact);
- }else{
- d_equalityEngine.assertPredicate(atom, polarity, fact);
- }
- Trace("sep-assert") << "Done asserting " << atom << " to EE." << std::endl;
- }else if( s_atom.getKind()==kind::SEP_PTO ){
- Node pto_lbl = NodeManager::currentNM()->mkNode( kind::SINGLETON, s_atom[0] );
- Assert(s_lbl == pto_lbl);
- Trace("sep-assert") << "Asserting " << s_atom << std::endl;
- d_equalityEngine.assertPredicate(s_atom, polarity, fact);
- //associate the equivalence class of the lhs with this pto
- Node r = getRepresentative( s_lbl );
- HeapAssertInfo * ei = getOrMakeEqcInfo( r, true );
- addPto( ei, r, atom, polarity );
+ else
+ {
+ Node ulem = nm->mkNode(UNION, slbl, labels[0]);
+ ulem = ulem.eqNode(labels[1]);
+ Trace("sep-lemma-debug")
+ << "Sep::Lemma : wand reduction, union : " << ulem << std::endl;
+ c_lems.push_back(ulem);
+ Node s = nm->mkNode(INTERSECTION, slbl, labels[0]);
+ Node ilem = s.eqNode(empSet);
+ Trace("sep-lemma-debug")
+ << "Sep::Lemma : wand reduction, disjoint : " << ilem << std::endl;
+ c_lems.push_back(ilem);
+ // nil does not occur in labels[0]
+ Node nr = getNilRef(tn);
+ Node nrlem = nm->mkNode(MEMBER, nr, labels[0]).negate();
+ Trace("sep-lemma")
+ << "Sep::Lemma: sep.nil not in wand antecedant heap : " << nrlem
+ << std::endl;
+ d_out->lemma(nrlem);
}
- //maybe propagate
- doPendingFacts();
- //add to spatial assertions
- if( !d_conflict && is_spatial ){
- d_spatial_assertions.push_back( fact );
+ // send out definitional lemmas for introduced sets
+ for (const Node& clem : c_lems)
+ {
+ Trace("sep-lemma") << "Sep::Lemma : definition : " << clem << std::endl;
+ d_out->lemma(clem);
+ }
+ conc = nm->mkNode(AND, children);
+ }
+ else if (satom.getKind() == SEP_PTO)
+ {
+ // TODO(project##230): Find a safe type for the singleton operator
+ Node ss = nm->mkSingleton(satom[0].getType(), satom[0]);
+ if (slbl != ss)
+ {
+ conc = slbl.eqNode(ss);
+ }
+ // note semantics of sep.nil is enforced globally
+ }
+ else if (satom.getKind() == SEP_EMP)
+ {
+ Node lem;
+ Node emp_s = nm->mkConst(EmptySet(slbl.getType()));
+ if (polarity)
+ {
+ lem = nm->mkNode(OR, fact.negate(), slbl.eqNode(emp_s));
+ }
+ else
+ {
+ Node kl = nm->mkSkolem("loc", getReferenceType(satom));
+ Node kd = nm->mkSkolem("data", getDataType(satom));
+ Node econc = nm->mkNode(
+ SEP_LABEL,
+ nm->mkNode(SEP_STAR, nm->mkNode(SEP_PTO, kl, kd), d_true),
+ slbl);
+ // Node econc = nm->mkNode( AND, slbl.eqNode( emp_s ).negate(),
+ lem = nm->mkNode(OR, fact.negate(), econc);
}
+ Trace("sep-lemma") << "Sep::Lemma : emp : " << lem << std::endl;
+ d_out->lemma(lem);
}
+ else
+ {
+ // labeled emp should be rewritten
+ Unreachable();
+ }
+ d_red_conc[slbl][satom] = conc;
+ }
+ if (conc.isNull())
+ {
+ Trace("sep-lemma-debug")
+ << "Trivial conclusion, do not add lemma." << std::endl;
+ return;
+ }
+ bool use_polarity = satom.getKind() == SEP_WAND ? !polarity : polarity;
+ if (!use_polarity)
+ {
+ // introduce guard, assert positive version
+ Trace("sep-lemma-debug")
+ << "Negated spatial constraint asserted to sep theory: " << fact
+ << std::endl;
+ Node g = nm->mkSkolem("G", nm->booleanType());
+ d_neg_guard_strategy[g].reset(new DecisionStrategySingleton(
+ "sep_neg_guard", g, getSatContext(), getValuation()));
+ DecisionStrategySingleton* ds = d_neg_guard_strategy[g].get();
+ getDecisionManager()->registerStrategy(DecisionManager::STRAT_SEP_NEG_GUARD,
+ ds);
+ Node lit = ds->getLiteral(0);
+ d_neg_guard[slbl][satom] = lit;
+ Trace("sep-lemma-debug")
+ << "Neg guard : " << slbl << " " << satom << " " << lit << std::endl;
+ AlwaysAssert(!lit.isNull());
+ d_neg_guards.push_back(lit);
+ d_guard_to_assertion[lit] = satom;
+ // Node lem = nm->mkNode( EQUAL, lit, conc );
+ Node lem = nm->mkNode(OR, lit.negate(), conc);
+ Trace("sep-lemma") << "Sep::Lemma : (neg) reduction : " << lem << std::endl;
+ d_out->lemma(lem);
+ }
+ else
+ {
+ // reduce based on implication
+ Node lem = nm->mkNode(OR, fact.negate(), conc);
+ Trace("sep-lemma") << "Sep::Lemma : reduction : " << lem << std::endl;
+ d_out->lemma(lem);
}
+}
- if( e == EFFORT_LAST_CALL && !d_conflict && !d_valuation.needCheck() ){
- Trace("sep-process") << "Checking heap at full effort..." << std::endl;
- d_label_model.clear();
- d_tmodel.clear();
- d_pto_model.clear();
- Trace("sep-process") << "---Locations---" << std::endl;
- std::map< Node, int > min_id;
- for( std::map< TypeNode, std::vector< Node > >::iterator itt = d_type_references_all.begin(); itt != d_type_references_all.end(); ++itt ){
- for( unsigned k=0; k<itt->second.size(); k++ ){
- Node t = itt->second[k];
- Trace("sep-process") << " " << t << " = ";
- if( d_valuation.getModel()->hasTerm( t ) ){
- Node v = d_valuation.getModel()->getRepresentative( t );
- Trace("sep-process") << v << std::endl;
- //take minimal id
- std::map< Node, unsigned >::iterator itrc = d_type_ref_card_id.find( t );
- int tid = itrc==d_type_ref_card_id.end() ? -1 : (int)itrc->second;
- bool set_term_model;
- if( d_tmodel.find( v )==d_tmodel.end() ){
- set_term_model = true;
- }else{
- set_term_model = min_id[v]>tid;
- }
- if( set_term_model ){
- d_tmodel[v] = t;
- min_id[v] = tid;
- }
+bool TheorySep::isSpatialKind(Kind k) const
+{
+ return k == SEP_STAR || k == SEP_WAND || k == SEP_PTO || k == SEP_EMP;
+}
+
+void TheorySep::postCheck(Effort level)
+{
+ if (level != EFFORT_LAST_CALL || d_state.isInConflict()
+ || d_valuation.needCheck())
+ {
+ return;
+ }
+ NodeManager* nm = NodeManager::currentNM();
+ Trace("sep-process") << "Checking heap at full effort..." << std::endl;
+ d_label_model.clear();
+ d_tmodel.clear();
+ d_pto_model.clear();
+ Trace("sep-process") << "---Locations---" << std::endl;
+ std::map<Node, int> min_id;
+ for (std::map<TypeNode, std::vector<Node> >::iterator itt =
+ d_type_references_all.begin();
+ itt != d_type_references_all.end();
+ ++itt)
+ {
+ for (const Node& t : itt->second)
+ {
+ Trace("sep-process") << " " << t << " = ";
+ if (d_valuation.getModel()->hasTerm(t))
+ {
+ Node v = d_valuation.getModel()->getRepresentative(t);
+ Trace("sep-process") << v << std::endl;
+ // take minimal id
+ std::map<Node, unsigned>::iterator itrc = d_type_ref_card_id.find(t);
+ int tid = itrc == d_type_ref_card_id.end() ? -1 : (int)itrc->second;
+ bool set_term_model;
+ if (d_tmodel.find(v) == d_tmodel.end())
+ {
+ set_term_model = true;
}else{
- Trace("sep-process") << "?" << std::endl;
+ set_term_model = min_id[v] > tid;
+ }
+ if (set_term_model)
+ {
+ d_tmodel[v] = t;
+ min_id[v] = tid;
}
}
+ else
+ {
+ Trace("sep-process") << "?" << std::endl;
+ }
}
- Trace("sep-process") << "---" << std::endl;
- //build positive/negative assertion lists for labels
- std::map< Node, bool > assert_active;
- //get the inactive assertions
- std::map< Node, std::vector< Node > > lbl_to_assertions;
- for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
- Node fact = (*i);
- bool polarity = fact.getKind() != kind::NOT;
- TNode atom = polarity ? fact : fact[0];
- Assert(atom.getKind() == kind::SEP_LABEL);
- TNode s_atom = atom[0];
- TNode s_lbl = atom[1];
- lbl_to_assertions[s_lbl].push_back( fact );
- //check whether assertion is active : either polarity=true, or guard is not asserted false
- assert_active[fact] = true;
- bool use_polarity = s_atom.getKind()==kind::SEP_WAND ? !polarity : polarity;
- if( use_polarity ){
- if( s_atom.getKind()==kind::SEP_PTO ){
- Node vv = d_valuation.getModel()->getRepresentative( s_atom[0] );
- if( d_pto_model.find( vv )==d_pto_model.end() ){
- Trace("sep-process") << "Pto : " << s_atom[0] << " (" << vv << ") -> " << s_atom[1] << std::endl;
- d_pto_model[vv] = s_atom[1];
-
- //replace this on pto-model since this term is more relevant
- TypeNode vtn = vv.getType();
- if( std::find( d_type_references_all[vtn].begin(), d_type_references_all[vtn].end(), s_atom[0] )!=d_type_references_all[vtn].end() ){
- d_tmodel[vv] = s_atom[0];
- }
- }
- }
- }else{
- if( d_neg_guard[s_lbl].find( s_atom )!=d_neg_guard[s_lbl].end() ){
- //check if the guard is asserted positively
- Node guard = d_neg_guard[s_lbl][s_atom];
- bool value;
- if( getValuation().hasSatValue( guard, value ) ) {
- assert_active[fact] = value;
+ }
+ Trace("sep-process") << "---" << std::endl;
+ // build positive/negative assertion lists for labels
+ std::map<Node, bool> assert_active;
+ // get the inactive assertions
+ std::map<Node, std::vector<Node> > lbl_to_assertions;
+ for (NodeList::const_iterator i = d_spatial_assertions.begin();
+ i != d_spatial_assertions.end();
+ ++i)
+ {
+ Node fact = (*i);
+ bool polarity = fact.getKind() != NOT;
+ TNode atom = polarity ? fact : fact[0];
+ Assert(atom.getKind() == SEP_LABEL);
+ TNode satom = atom[0];
+ TNode slbl = atom[1];
+ lbl_to_assertions[slbl].push_back(fact);
+ // check whether assertion is active : either polarity=true, or guard is not
+ // asserted false
+ assert_active[fact] = true;
+ bool use_polarity = satom.getKind() == SEP_WAND ? !polarity : polarity;
+ if (use_polarity)
+ {
+ if (satom.getKind() == SEP_PTO)
+ {
+ Node vv = d_valuation.getModel()->getRepresentative(satom[0]);
+ if (d_pto_model.find(vv) == d_pto_model.end())
+ {
+ Trace("sep-process") << "Pto : " << satom[0] << " (" << vv << ") -> "
+ << satom[1] << std::endl;
+ d_pto_model[vv] = satom[1];
+
+ // replace this on pto-model since this term is more relevant
+ TypeNode vtn = vv.getType();
+ if (std::find(d_type_references_all[vtn].begin(),
+ d_type_references_all[vtn].end(),
+ satom[0])
+ != d_type_references_all[vtn].end())
+ {
+ d_tmodel[vv] = satom[0];
}
}
}
}
- //(recursively) set inactive sub-assertions
- for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
- Node fact = (*i);
- if( !assert_active[fact] ){
- setInactiveAssertionRec( fact, lbl_to_assertions, assert_active );
+ else
+ {
+ if (d_neg_guard[slbl].find(satom) != d_neg_guard[slbl].end())
+ {
+ // check if the guard is asserted positively
+ Node guard = d_neg_guard[slbl][satom];
+ bool value;
+ if (getValuation().hasSatValue(guard, value))
+ {
+ assert_active[fact] = value;
+ }
}
}
- //set up model information based on active assertions
+ }
+ //(recursively) set inactive sub-assertions
+ for (NodeList::const_iterator i = d_spatial_assertions.begin();
+ i != d_spatial_assertions.end();
+ ++i)
+ {
+ Node fact = (*i);
+ if (!assert_active[fact])
+ {
+ setInactiveAssertionRec(fact, lbl_to_assertions, assert_active);
+ }
+ }
+ // set up model information based on active assertions
+ for (NodeList::const_iterator i = d_spatial_assertions.begin();
+ i != d_spatial_assertions.end();
+ ++i)
+ {
+ Node fact = (*i);
+ bool polarity = fact.getKind() != NOT;
+ TNode atom = polarity ? fact : fact[0];
+ TNode satom = atom[0];
+ TNode slbl = atom[1];
+ if (assert_active[fact])
+ {
+ computeLabelModel(slbl);
+ }
+ }
+ // debug print
+ if (Trace.isOn("sep-process"))
+ {
+ Trace("sep-process") << "--- Current spatial assertions : " << std::endl;
for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
Node fact = (*i);
- bool polarity = fact.getKind() != kind::NOT;
- TNode atom = polarity ? fact : fact[0];
- TNode s_atom = atom[0];
- TNode s_lbl = atom[1];
- if( assert_active[fact] ){
- computeLabelModel( s_lbl );
- }
- }
- //debug print
- if( Trace.isOn("sep-process") ){
- Trace("sep-process") << "--- Current spatial assertions : " << std::endl;
- for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
- Node fact = (*i);
- Trace("sep-process") << " " << fact;
- if( !assert_active[fact] ){
- Trace("sep-process") << " [inactive]";
- }
- Trace("sep-process") << std::endl;
+ Trace("sep-process") << " " << fact;
+ if (!assert_active[fact])
+ {
+ Trace("sep-process") << " [inactive]";
}
- Trace("sep-process") << "---" << std::endl;
+ Trace("sep-process") << std::endl;
}
- if(Trace.isOn("sep-eqc")) {
- eq::EqClassesIterator eqcs2_i = eq::EqClassesIterator( &d_equalityEngine );
- Trace("sep-eqc") << "EQC:" << std::endl;
- while( !eqcs2_i.isFinished() ){
- Node eqc = (*eqcs2_i);
- eq::EqClassIterator eqc2_i = eq::EqClassIterator( eqc, &d_equalityEngine );
- Trace("sep-eqc") << "Eqc( " << eqc << " ) : { ";
- while( !eqc2_i.isFinished() ) {
- if( (*eqc2_i)!=eqc ){
- Trace("sep-eqc") << (*eqc2_i) << " ";
- }
- ++eqc2_i;
+ Trace("sep-process") << "---" << std::endl;
+ }
+ if (Trace.isOn("sep-eqc"))
+ {
+ eq::EqClassesIterator eqcs2_i = eq::EqClassesIterator(d_equalityEngine);
+ Trace("sep-eqc") << "EQC:" << std::endl;
+ while (!eqcs2_i.isFinished())
+ {
+ Node eqc = (*eqcs2_i);
+ eq::EqClassIterator eqc2_i = eq::EqClassIterator(eqc, d_equalityEngine);
+ Trace("sep-eqc") << "Eqc( " << eqc << " ) : { ";
+ while (!eqc2_i.isFinished())
+ {
+ if ((*eqc2_i) != eqc)
+ {
+ Trace("sep-eqc") << (*eqc2_i) << " ";
}
- Trace("sep-eqc") << " } " << std::endl;
- ++eqcs2_i;
+ ++eqc2_i;
}
- Trace("sep-eqc") << std::endl;
+ Trace("sep-eqc") << " } " << std::endl;
+ ++eqcs2_i;
}
-
- bool addedLemma = false;
- bool needAddLemma = false;
- //check negated star / positive wand
- if( options::sepCheckNeg() ){
- //get active labels
- std::map< Node, bool > active_lbl;
- if( options::sepMinimalRefine() ){
- for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
- Node fact = (*i);
- bool polarity = fact.getKind() != kind::NOT;
- TNode atom = polarity ? fact : fact[0];
- TNode s_atom = atom[0];
- bool use_polarity = s_atom.getKind()==kind::SEP_WAND ? !polarity : polarity;
- if( !use_polarity ){
- Assert(assert_active.find(fact) != assert_active.end());
- if( assert_active[fact] ){
- Assert(atom.getKind() == kind::SEP_LABEL);
- TNode s_lbl = atom[1];
- std::map<Node, std::map<int, Node> >& lms = d_label_map[s_atom];
- if (lms.find(s_lbl) != lms.end())
- {
- Trace("sep-process-debug") << "Active lbl : " << s_lbl << std::endl;
- active_lbl[s_lbl] = true;
- }
- }
- }
- }
- }
+ Trace("sep-eqc") << std::endl;
+ }
- //process spatial assertions
+ bool addedLemma = false;
+ bool needAddLemma = false;
+ // check negated star / positive wand
+ if (options::sepCheckNeg())
+ {
+ // get active labels
+ std::map<Node, bool> active_lbl;
+ if (options::sepMinimalRefine())
+ {
for( NodeList::const_iterator i = d_spatial_assertions.begin(); i != d_spatial_assertions.end(); ++i ) {
Node fact = (*i);
- bool polarity = fact.getKind() != kind::NOT;
+ bool polarity = fact.getKind() != NOT;
TNode atom = polarity ? fact : fact[0];
- TNode s_atom = atom[0];
-
- bool use_polarity = s_atom.getKind()==kind::SEP_WAND ? !polarity : polarity;
- Trace("sep-process-debug") << " check atom : " << s_atom << " use polarity " << use_polarity << std::endl;
+ TNode satom = atom[0];
+ bool use_polarity = satom.getKind() == SEP_WAND ? !polarity : polarity;
if( !use_polarity ){
Assert(assert_active.find(fact) != assert_active.end());
if( assert_active[fact] ){
- Assert(atom.getKind() == kind::SEP_LABEL);
- TNode s_lbl = atom[1];
- Trace("sep-process") << "--> Active negated atom : " << s_atom << ", lbl = " << s_lbl << std::endl;
- //add refinement lemma
- if (ContainsKey(d_label_map[s_atom], s_lbl))
- {
- needAddLemma = true;
- TypeNode tn = getReferenceType( s_atom );
- tn = NodeManager::currentNM()->mkSetType(tn);
- //tn = NodeManager::currentNM()->mkSetType(NodeManager::currentNM()->mkRefType(tn));
- Node o_b_lbl_mval = d_label_model[s_lbl].getValue( tn );
- Trace("sep-process") << " Model for " << s_lbl << " : " << o_b_lbl_mval << std::endl;
-
- //get model values
- std::map< int, Node > mvals;
- for (const std::pair<const int, Node>& sub_element :
- d_label_map[s_atom][s_lbl])
- {
- int sub_index = sub_element.first;
- Node sub_lbl = sub_element.second;
- computeLabelModel( sub_lbl );
- Node lbl_mval = d_label_model[sub_lbl].getValue( tn );
- Trace("sep-process-debug") << " child " << sub_index << " : " << sub_lbl << ", mval = " << lbl_mval << std::endl;
- mvals[sub_index] = lbl_mval;
- }
-
- // Now, assert model-instantiated implication based on the negation
- Assert(d_label_model.find(s_lbl) != d_label_model.end());
- std::vector< Node > conc;
- bool inst_success = true;
- //new refinement
- //instantiate the label
- std::map< Node, Node > visited;
- Node inst = instantiateLabel( s_atom, s_lbl, s_lbl, o_b_lbl_mval, visited, d_pto_model, tn, active_lbl );
- Trace("sep-inst-debug") << " applied inst : " << inst << std::endl;
- if( inst.isNull() ){
- inst_success = false;
- }else{
- inst = Rewriter::rewrite( inst );
- if( inst==( polarity ? d_true : d_false ) ){
- inst_success = false;
- }
- conc.push_back( polarity ? inst : inst.negate() );
- }
- if( inst_success ){
- std::vector< Node > lemc;
- Node pol_atom = atom;
- if( polarity ){
- pol_atom = atom.negate();
- }
- lemc.push_back( pol_atom );
-
- //lemc.push_back( s_lbl.eqNode( o_b_lbl_mval ).negate() );
- //lemc.push_back( NodeManager::currentNM()->mkNode( kind::SUBSET, o_b_lbl_mval, s_lbl ).negate() );
- lemc.insert( lemc.end(), conc.begin(), conc.end() );
- Node lem = NodeManager::currentNM()->mkNode( kind::OR, lemc );
- if( std::find( d_refinement_lem[s_atom][s_lbl].begin(), d_refinement_lem[s_atom][s_lbl].end(), lem )==d_refinement_lem[s_atom][s_lbl].end() ){
- d_refinement_lem[s_atom][s_lbl].push_back( lem );
- Trace("sep-process") << "-----> refinement lemma (#" << d_refinement_lem[s_atom][s_lbl].size() << ") : " << lem << std::endl;
- Trace("sep-lemma") << "Sep::Lemma : negated star/wand refinement : " << lem << std::endl;
- d_out->lemma( lem );
- addedLemma = true;
- }else{
- //this typically should not happen, should never happen for complete base theories
- Trace("sep-process") << "*** repeated refinement lemma : " << lem << std::endl;
- Trace("sep-warn") << "TheorySep : WARNING : repeated refinement lemma : " << lem << "!!!" << std::endl;
- }
- }
- }
- else
+ Assert(atom.getKind() == SEP_LABEL);
+ TNode slbl = atom[1];
+ std::map<Node, std::map<int, Node> >& lms = d_label_map[satom];
+ if (lms.find(slbl) != lms.end())
{
- Trace("sep-process-debug") << " no children." << std::endl;
- Assert(s_atom.getKind() == kind::SEP_PTO
- || s_atom.getKind() == kind::SEP_EMP);
+ Trace("sep-process-debug")
+ << "Active lbl : " << slbl << std::endl;
+ active_lbl[slbl] = true;
}
- }else{
- Trace("sep-process-debug") << "--> inactive negated assertion " << s_atom << std::endl;
}
}
}
- Trace("sep-process") << "...finished check of negated assertions, addedLemma=" << addedLemma << ", needAddLemma=" << needAddLemma << std::endl;
}
- if( !addedLemma ){
- //must witness finite data points-to
- for( std::map< TypeNode, Node >::iterator it = d_base_label.begin(); it != d_base_label.end(); ++it ){
- TypeNode data_type = d_loc_to_data_type[it->first];
- //if the data type is finite
- if( data_type.isInterpretedFinite() ){
- computeLabelModel( it->second );
- Trace("sep-process-debug") << "Check heap data for " << it->first << " -> " << data_type << std::endl;
- for( unsigned j=0; j<d_label_model[it->second].d_heap_locs_model.size(); j++ ){
- Assert(d_label_model[it->second].d_heap_locs_model[j].getKind()
- == kind::SINGLETON);
- Node l = d_label_model[it->second].d_heap_locs_model[j][0];
- Trace("sep-process-debug") << " location : " << l << std::endl;
- if( d_pto_model[l].isNull() ){
- needAddLemma = true;
- Node ll;
- std::map< Node, Node >::iterator itm = d_tmodel.find( l );
- if( itm!=d_tmodel.end() ) {
- ll = itm->second;
- }else{
- //try to assign arbitrary skolem?
- }
- if( !ll.isNull() ){
- Trace("sep-process") << "Must witness label : " << ll << ", data type is " << data_type << std::endl;
- Node dsk = NodeManager::currentNM()->mkSkolem( "dsk", data_type, "pto-data for implicit location" );
- // if location is in the heap, then something must point to it
- Node lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, NodeManager::currentNM()->mkNode( kind::MEMBER, ll, it->second ),
- NodeManager::currentNM()->mkNode( kind::SEP_STAR,
- NodeManager::currentNM()->mkNode( kind::SEP_PTO, ll, dsk ),
- d_true ) );
- Trace("sep-lemma") << "Sep::Lemma : witness finite data-pto : " << lem << std::endl;
- d_out->lemma( lem );
- addedLemma = true;
- }else{
- //This should only happen if we are in an unbounded fragment
- Trace("sep-warn") << "TheorySep : WARNING : no term corresponding to location " << l << " in heap!!!" << std::endl;
- }
- }else{
- Trace("sep-process-debug") << " points-to data witness : " << d_pto_model[l] << std::endl;
- }
- }
- }
+
+ // process spatial assertions
+ for (NodeList::const_iterator i = d_spatial_assertions.begin();
+ i != d_spatial_assertions.end();
+ ++i)
+ {
+ Node fact = (*i);
+ bool polarity = fact.getKind() != NOT;
+ TNode atom = polarity ? fact : fact[0];
+ TNode satom = atom[0];
+
+ bool use_polarity = satom.getKind() == SEP_WAND ? !polarity : polarity;
+ Trace("sep-process-debug")
+ << " check atom : " << satom << " use polarity " << use_polarity
+ << std::endl;
+ if (use_polarity)
+ {
+ continue;
}
- if( !addedLemma ){
- //set up model
- Trace("sep-process-debug") << "...preparing sep model..." << std::endl;
- d_heap_locs_nptos.clear();
- //collect data points that are not pointed to
- for( context::CDList<Assertion>::const_iterator it = facts_begin(); it != facts_end(); ++ it) {
- Node lit = (*it).d_assertion;
- if( lit.getKind()==kind::NOT && lit[0].getKind()==kind::SEP_PTO ){
- Node s_atom = lit[0];
- Node v1 = d_valuation.getModel()->getRepresentative( s_atom[0] );
- Node v2 = d_valuation.getModel()->getRepresentative( s_atom[1] );
- Trace("sep-process-debug") << v1 << " does not point-to " << v2 << std::endl;
- d_heap_locs_nptos[v1].push_back( v2 );
- }
- }
-
- if( needAddLemma ){
- d_out->setIncomplete();
+ Assert(assert_active.find(fact) != assert_active.end());
+ if (!assert_active[fact])
+ {
+ Trace("sep-process-debug")
+ << "--> inactive negated assertion " << satom << std::endl;
+ continue;
+ }
+ Assert(atom.getKind() == SEP_LABEL);
+ TNode slbl = atom[1];
+ Trace("sep-process") << "--> Active negated atom : " << satom
+ << ", lbl = " << slbl << std::endl;
+ // add refinement lemma
+ if (!ContainsKey(d_label_map[satom], slbl))
+ {
+ Trace("sep-process-debug") << " no children." << std::endl;
+ Assert(satom.getKind() == SEP_PTO || satom.getKind() == SEP_EMP);
+ continue;
+ }
+ needAddLemma = true;
+ TypeNode tn = getReferenceType(satom);
+ tn = nm->mkSetType(tn);
+ // tn = nm->mkSetType(nm->mkRefType(tn));
+ Node o_b_lbl_mval = d_label_model[slbl].getValue(tn);
+ Trace("sep-process") << " Model for " << slbl << " : " << o_b_lbl_mval
+ << std::endl;
+
+ // get model values
+ std::map<int, Node> mvals;
+ for (const std::pair<int, Node>& sub_element : d_label_map[satom][slbl])
+ {
+ int sub_index = sub_element.first;
+ Node sub_lbl = sub_element.second;
+ computeLabelModel(sub_lbl);
+ Node lbl_mval = d_label_model[sub_lbl].getValue(tn);
+ Trace("sep-process-debug")
+ << " child " << sub_index << " : " << sub_lbl
+ << ", mval = " << lbl_mval << std::endl;
+ mvals[sub_index] = lbl_mval;
+ }
+
+ // Now, assert model-instantiated implication based on the negation
+ Assert(d_label_model.find(slbl) != d_label_model.end());
+ std::vector<Node> conc;
+ bool inst_success = true;
+ // new refinement
+ // instantiate the label
+ std::map<Node, Node> visited;
+ Node inst = instantiateLabel(satom,
+ slbl,
+ slbl,
+ o_b_lbl_mval,
+ visited,
+ d_pto_model,
+ tn,
+ active_lbl);
+ Trace("sep-inst-debug") << " applied inst : " << inst << std::endl;
+ if (inst.isNull())
+ {
+ inst_success = false;
+ }
+ else
+ {
+ inst = Rewriter::rewrite(inst);
+ if (inst == (polarity ? d_true : d_false))
+ {
+ inst_success = false;
}
+ conc.push_back(polarity ? inst : inst.negate());
+ }
+ if (!inst_success)
+ {
+ continue;
+ }
+ std::vector<Node> lemc;
+ Node pol_atom = atom;
+ if (polarity)
+ {
+ pol_atom = atom.negate();
+ }
+ lemc.push_back(pol_atom);
+ lemc.insert(lemc.end(), conc.begin(), conc.end());
+ Node lem = nm->mkNode(OR, lemc);
+ std::vector<Node>& rlems = d_refinement_lem[satom][slbl];
+ if (std::find(rlems.begin(), rlems.end(), lem) == rlems.end())
+ {
+ rlems.push_back(lem);
+ Trace("sep-process") << "-----> refinement lemma (#" << rlems.size()
+ << ") : " << lem << std::endl;
+ Trace("sep-lemma") << "Sep::Lemma : negated star/wand refinement : "
+ << lem << std::endl;
+ d_out->lemma(lem);
+ addedLemma = true;
+ }
+ else
+ {
+ // this typically should not happen, should never happen for complete
+ // base theories
+ Trace("sep-process")
+ << "*** repeated refinement lemma : " << lem << std::endl;
+ Trace("sep-warn")
+ << "TheorySep : WARNING : repeated refinement lemma : " << lem
+ << "!!!" << std::endl;
}
}
+ Trace("sep-process")
+ << "...finished check of negated assertions, addedLemma=" << addedLemma
+ << ", needAddLemma=" << needAddLemma << std::endl;
+ }
+ if (addedLemma)
+ {
+ return;
+ }
+ // must witness finite data points-to
+ for (std::map<TypeNode, Node>::iterator it = d_base_label.begin();
+ it != d_base_label.end();
+ ++it)
+ {
+ TypeNode data_type = d_loc_to_data_type[it->first];
+ // if the data type is finite
+ if (!data_type.isInterpretedFinite())
+ {
+ continue;
+ }
+ computeLabelModel(it->second);
+ Trace("sep-process-debug") << "Check heap data for " << it->first << " -> "
+ << data_type << std::endl;
+ std::vector<Node>& hlmodel = d_label_model[it->second].d_heap_locs_model;
+ for (size_t j = 0, hsize = hlmodel.size(); j < hsize; j++)
+ {
+ Assert(hlmodel[j].getKind() == SINGLETON);
+ Node l = hlmodel[j][0];
+ Trace("sep-process-debug") << " location : " << l << std::endl;
+ if (!d_pto_model[l].isNull())
+ {
+ Trace("sep-process-debug")
+ << " points-to data witness : " << d_pto_model[l] << std::endl;
+ continue;
+ }
+ needAddLemma = true;
+ Node ll;
+ std::map<Node, Node>::iterator itm = d_tmodel.find(l);
+ if (itm != d_tmodel.end())
+ {
+ ll = itm->second;
+ }
+ // otherwise, could try to assign arbitrary skolem?
+ if (!ll.isNull())
+ {
+ Trace("sep-process") << "Must witness label : " << ll
+ << ", data type is " << data_type << std::endl;
+ Node dsk =
+ nm->mkSkolem("dsk", data_type, "pto-data for implicit location");
+ // if location is in the heap, then something must point to it
+ Node lem = nm->mkNode(
+ IMPLIES,
+ nm->mkNode(MEMBER, ll, it->second),
+ nm->mkNode(SEP_STAR, nm->mkNode(SEP_PTO, ll, dsk), d_true));
+ Trace("sep-lemma") << "Sep::Lemma : witness finite data-pto : " << lem
+ << std::endl;
+ d_out->lemma(lem);
+ addedLemma = true;
+ }
+ else
+ {
+ // This should only happen if we are in an unbounded fragment
+ Trace("sep-warn")
+ << "TheorySep : WARNING : no term corresponding to location " << l
+ << " in heap!!!" << std::endl;
+ }
+ }
+ }
+ if (addedLemma)
+ {
+ return;
+ }
+ // set up model
+ Trace("sep-process-debug") << "...preparing sep model..." << std::endl;
+ d_heap_locs_nptos.clear();
+ // collect data points that are not pointed to
+ for (context::CDList<Assertion>::const_iterator it = facts_begin();
+ it != facts_end();
+ ++it)
+ {
+ Node lit = (*it).d_assertion;
+ if (lit.getKind() == NOT && lit[0].getKind() == SEP_PTO)
+ {
+ Node satom = lit[0];
+ Node v1 = d_valuation.getModel()->getRepresentative(satom[0]);
+ Node v2 = d_valuation.getModel()->getRepresentative(satom[1]);
+ Trace("sep-process-debug")
+ << v1 << " does not point-to " << v2 << std::endl;
+ d_heap_locs_nptos[v1].push_back(v2);
+ }
}
- Trace("sep-check") << "Sep::check(): " << e << " done, conflict=" << d_conflict.get() << endl;
-}
+ if (needAddLemma)
+ {
+ d_out->setIncomplete();
+ }
+ Trace("sep-check") << "Sep::check(): " << level
+ << " done, conflict=" << d_state.isInConflict()
+ << std::endl;
+}
bool TheorySep::needsCheckLastEffort() {
return hasFacts();
@@ -835,12 +937,7 @@ bool TheorySep::needsCheckLastEffort() {
void TheorySep::conflict(TNode a, TNode b) {
Trace("sep-conflict") << "Sep::conflict : " << a << " " << b << std::endl;
- Node eq = a.eqNode(b);
- std::vector<TNode> assumptions;
- explain(eq, assumptions);
- Node conflictNode = mkAnd(assumptions);
- d_conflict = true;
- d_out->conflict( conflictNode );
+ d_im.conflictEqConstantMerge(a, b);
}
@@ -893,6 +990,22 @@ void TheorySep::ppNotifyAssertions(const std::vector<Node>& assertions) {
d_loc_to_data_type[d_type_ref] = d_type_data;
}
}
+ // initialize the EPR utility
+ QuantifiersEngine* qe = getQuantifiersEngine();
+ if (qe != nullptr)
+ {
+ quantifiers::QuantEPR* qepr = qe->getQuantEPR();
+ if (qepr != nullptr)
+ {
+ for (const Node& a : assertions)
+ {
+ qepr->registerAssertion(a);
+ }
+ // must handle sources of other new constants e.g. separation logic
+ initializeBounds();
+ qepr->finishInit();
+ }
+ }
}
//return cardinality
@@ -905,9 +1018,7 @@ int TheorySep::processAssertion( Node n, std::map< int, std::map< Node, int > >&
if( it==visited[index].end() ){
Trace("sep-pp-debug") << "process assertion : " << n << ", index = " << index << std::endl;
if( n.getKind()==kind::SEP_EMP ){
- TypeNode tn = n[0].getType();
- TypeNode tnd = n[1].getType();
- registerRefDataTypes( tn, tnd, n );
+ registerRefDataTypesAtom(n);
if( hasPol && pol ){
references[index][n].clear();
references_strict[index][n] = true;
@@ -915,10 +1026,9 @@ int TheorySep::processAssertion( Node n, std::map< int, std::map< Node, int > >&
card = 1;
}
}else if( n.getKind()==kind::SEP_PTO ){
- TypeNode tn1 = n[0].getType();
- TypeNode tn2 = n[1].getType();
- registerRefDataTypes( tn1, tn2, n );
+ registerRefDataTypesAtom(n);
if( quantifiers::TermUtil::hasBoundVarAttr( n[0] ) ){
+ TypeNode tn1 = n[0].getType();
if( d_bound_kind[tn1]!=bound_strict && d_bound_kind[tn1]!=bound_invalid ){
if( options::quantEpr() && n[0].getKind()==kind::BOUND_VARIABLE ){
// still valid : bound on heap models will include Herbrand universe of n[0].getType()
@@ -1029,49 +1139,62 @@ int TheorySep::processAssertion( Node n, std::map< int, std::map< Node, int > >&
return card;
}
-void TheorySep::registerRefDataTypes( TypeNode tn1, TypeNode tn2, Node atom ){
- //separation logic is effectively enabled when we find at least one spatial constraint occurs in the input
- if( options::incrementalSolving() ){
- std::stringstream ss;
- ss << "ERROR: cannot use separation logic in incremental mode." << std::endl;
- throw LogicException(ss.str());
+void TheorySep::registerRefDataTypesAtom(Node atom)
+{
+ TypeNode tn1;
+ TypeNode tn2;
+ Kind k = atom.getKind();
+ if (k == SEP_PTO || k == SEP_EMP)
+ {
+ tn1 = atom[0].getType();
+ tn2 = atom[1].getType();
+ }
+ else
+ {
+ Assert(k == SEP_STAR || k == SEP_WAND);
}
- std::map< TypeNode, TypeNode >::iterator itt = d_loc_to_data_type.find( tn1 );
- if( itt==d_loc_to_data_type.end() ){
- if( !d_loc_to_data_type.empty() ){
- TypeNode te1 = d_loc_to_data_type.begin()->first;
+ registerRefDataTypes(tn1, tn2, atom);
+}
+
+void TheorySep::registerRefDataTypes(TypeNode tn1, TypeNode tn2, Node atom)
+{
+ if (!d_type_ref.isNull())
+ {
+ Assert(!atom.isNull());
+ // already declared, ensure compatible
+ if ((!tn1.isNull() && !tn1.isComparableTo(d_type_ref))
+ || (!tn2.isNull() && !tn2.isComparableTo(d_type_data)))
+ {
std::stringstream ss;
- ss << "ERROR: specifying heap constraints for two different types : " << tn1 << " -> " << tn2 << " and " << te1 << " -> " << d_loc_to_data_type[te1] << std::endl;
- throw LogicException(ss.str());
- Assert(false);
- }
- if( tn2.isNull() ){
- Trace("sep-type") << "Sep: assume location type " << tn1 << " (from " << atom << ")" << std::endl;
- }else{
- Trace("sep-type") << "Sep: assume location type " << tn1 << " is associated with data type " << tn2 << " (from " << atom << ")" << std::endl;
- }
- d_loc_to_data_type[tn1] = tn2;
- //for now, we only allow heap constraints of one type
- d_type_ref = tn1;
- d_type_data = tn2;
- d_bound_kind[tn1] = bound_default;
- }else{
- if( !tn2.isNull() ){
- if( itt->second!=tn2 ){
- if( itt->second.isNull() ){
- Trace("sep-type") << "Sep: assume location type " << tn1 << " is associated with data type " << tn2 << " (from " << atom << ")" << std::endl;
- //now we know data type
- d_loc_to_data_type[tn1] = tn2;
- d_type_data = tn2;
- }else{
- std::stringstream ss;
- ss << "ERROR: location type " << tn1 << " is already associated with data type " << itt->second << ", offending atom is " << atom << " with data type " << tn2 << std::endl;
- throw LogicException(ss.str());
- Assert(false);
- }
- }
+ ss << "ERROR: the separation logic heap type has already been set to "
+ << d_type_ref << " -> " << d_type_data
+ << " but we have a constraint that uses different heap types, "
+ "offending atom is "
+ << atom << " with associated heap type " << tn1 << " -> " << tn2
+ << std::endl;
}
+ return;
}
+ // if not declared yet, and we have a separation logic constraint, throw
+ // an error.
+ if (!atom.isNull())
+ {
+ std::stringstream ss;
+ // error, heap not declared
+ ss << "ERROR: the type of the separation logic heap has not been declared "
+ "(e.g. via a declare-heap command), and we have a separation logic "
+ "constraint "
+ << atom << std::endl;
+ throw LogicException(ss.str());
+ }
+ // otherwise set it
+ Trace("sep-type") << "Sep: assume location type " << tn1
+ << " is associated with data type " << tn2 << std::endl;
+ d_loc_to_data_type[tn1] = tn2;
+ // for now, we only allow heap constraints of one type
+ d_type_ref = tn1;
+ d_type_data = tn2;
+ d_bound_kind[tn1] = bound_default;
}
void TheorySep::initializeBounds() {
@@ -1243,7 +1366,7 @@ Node TheorySep::mkUnion( TypeNode tn, std::vector< Node >& locs ) {
for( unsigned i=0; i<locs.size(); i++ ){
Node s = locs[i];
Assert(!s.isNull());
- s = NodeManager::currentNM()->mkNode( kind::SINGLETON, s );
+ s = NodeManager::currentNM()->mkSingleton(tn, s);
if( u.isNull() ){
u = s;
}else{
@@ -1414,12 +1537,14 @@ Node TheorySep::instantiateLabel( Node n, Node o_lbl, Node lbl, Node lbl_v, std:
//check if this pto reference is in the base label, if not, then it does not need to be added as an assumption
Assert(d_label_model.find(o_lbl) != d_label_model.end());
Node vr = d_valuation.getModel()->getRepresentative( n[0] );
- Node svr = NodeManager::currentNM()->mkNode( kind::SINGLETON, vr );
+ // TODO(project##230): Find a safe type for the singleton operator
+ Node svr = NodeManager::currentNM()->mkSingleton(vr.getType(), vr);
bool inBaseHeap = std::find( d_label_model[o_lbl].d_heap_locs_model.begin(), d_label_model[o_lbl].d_heap_locs_model.end(), svr )!=d_label_model[o_lbl].d_heap_locs_model.end();
Trace("sep-inst-debug") << "Is in base (non-instantiating) heap : " << inBaseHeap << " for value ref " << vr << " in " << o_lbl << std::endl;
std::vector< Node > children;
if( inBaseHeap ){
- Node s = NodeManager::currentNM()->mkNode( kind::SINGLETON, n[0] );
+ // TODO(project##230): Find a safe type for the singleton operator
+ Node s = NodeManager::currentNM()->mkSingleton(n[0].getType(), n[0]);
children.push_back( NodeManager::currentNM()->mkNode( kind::SEP_LABEL, NodeManager::currentNM()->mkNode( kind::SEP_PTO, n[0], n[1] ), s ) );
}else{
//look up value of data
@@ -1431,8 +1556,10 @@ Node TheorySep::instantiateLabel( Node n, Node o_lbl, Node lbl, Node lbl_v, std:
}else{
Trace("sep-inst-debug") << "Data for " << vr << " was not specified, do not add condition." << std::endl;
}
- }
- children.push_back( NodeManager::currentNM()->mkNode( kind::EQUAL, NodeManager::currentNM()->mkNode( kind::SINGLETON, n[0] ), lbl_v ) );
+ }
+ // TODO(project##230): Find a safe type for the singleton operator
+ Node singleton = NodeManager::currentNM()->mkSingleton(n[0].getType(), n[0]);
+ children.push_back(singleton.eqNode(lbl_v));
Node ret = children.empty() ? NodeManager::currentNM()->mkConst( true ) : ( children.size()==1 ? children[0] : NodeManager::currentNM()->mkNode( kind::AND, children ) );
Trace("sep-inst-debug") << "Return " << ret << std::endl;
return ret;
@@ -1476,11 +1603,13 @@ void TheorySep::setInactiveAssertionRec( Node fact, std::map< Node, std::vector<
assert_active[fact] = false;
bool polarity = fact.getKind() != kind::NOT;
TNode atom = polarity ? fact : fact[0];
- TNode s_atom = atom[0];
- TNode s_lbl = atom[1];
- if( s_atom.getKind()==kind::SEP_WAND || s_atom.getKind()==kind::SEP_STAR ){
- for( unsigned j=0; j<s_atom.getNumChildren(); j++ ){
- Node lblc = getLabel( s_atom, j, s_lbl );
+ TNode satom = atom[0];
+ TNode slbl = atom[1];
+ if (satom.getKind() == SEP_WAND || satom.getKind() == SEP_STAR)
+ {
+ for (size_t j = 0, nchild = satom.getNumChildren(); j < nchild; j++)
+ {
+ Node lblc = getLabel(satom, j, slbl);
for( unsigned k=0; k<lbl_to_assertions[lblc].size(); k++ ){
setInactiveAssertionRec( lbl_to_assertions[lblc][k], lbl_to_assertions, assert_active );
}
@@ -1488,14 +1617,20 @@ void TheorySep::setInactiveAssertionRec( Node fact, std::map< Node, std::vector<
}
}
-void TheorySep::getLabelChildren( Node s_atom, Node lbl, std::vector< Node >& children, std::vector< Node >& labels ) {
- for( unsigned i=0; i<s_atom.getNumChildren(); i++ ){
- Node lblc = getLabel( s_atom, i, lbl );
+void TheorySep::getLabelChildren(Node satom,
+ Node lbl,
+ std::vector<Node>& children,
+ std::vector<Node>& labels)
+{
+ for (size_t i = 0, nchild = satom.getNumChildren(); i < nchild; i++)
+ {
+ Node lblc = getLabel(satom, i, lbl);
Assert(!lblc.isNull());
std::map< Node, Node > visited;
- Node lc = applyLabel( s_atom[i], lblc, visited );
+ Node lc = applyLabel(satom[i], lblc, visited);
Assert(!lc.isNull());
- if( i==1 && s_atom.getKind()==kind::SEP_WAND ){
+ if (i == 1 && satom.getKind() == SEP_WAND)
+ {
lc = lc.negate();
}
children.push_back( lc );
@@ -1514,9 +1649,9 @@ void TheorySep::computeLabelModel( Node lbl ) {
Trace("sep-process") << "Model value (from valuation) for " << lbl << " : " << v_val << std::endl;
if( v_val.getKind()!=kind::EMPTYSET ){
while( v_val.getKind()==kind::UNION ){
- Assert(v_val[1].getKind() == kind::SINGLETON);
- d_label_model[lbl].d_heap_locs_model.push_back( v_val[1] );
- v_val = v_val[0];
+ Assert(v_val[0].getKind() == kind::SINGLETON);
+ d_label_model[lbl].d_heap_locs_model.push_back(v_val[0]);
+ v_val = v_val[1];
}
if( v_val.getKind()==kind::SINGLETON ){
d_label_model[lbl].d_heap_locs_model.push_back( v_val );
@@ -1544,7 +1679,8 @@ void TheorySep::computeLabelModel( Node lbl ) {
}else{
tt = itm->second;
}
- Node stt = NodeManager::currentNM()->mkNode( kind::SINGLETON, tt );
+ // TODO(project##230): Find a safe type for the singleton operator
+ Node stt = NodeManager::currentNM()->mkSingleton(tt.getType(), tt);
Trace("sep-process-debug") << "...model : add " << tt << " for " << u << " in lbl " << lbl << std::endl;
d_label_model[lbl].d_heap_locs.push_back( stt );
}
@@ -1552,22 +1688,21 @@ void TheorySep::computeLabelModel( Node lbl ) {
}
Node TheorySep::getRepresentative( Node t ) {
- if( d_equalityEngine.hasTerm( t ) ){
- return d_equalityEngine.getRepresentative( t );
+ if (d_equalityEngine->hasTerm(t))
+ {
+ return d_equalityEngine->getRepresentative(t);
}else{
return t;
}
}
-bool TheorySep::hasTerm( Node a ){
- return d_equalityEngine.hasTerm( a );
-}
+bool TheorySep::hasTerm(Node a) { return d_equalityEngine->hasTerm(a); }
bool TheorySep::areEqual( Node a, Node b ){
if( a==b ){
return true;
}else if( hasTerm( a ) && hasTerm( b ) ){
- return d_equalityEngine.areEqual( a, b );
+ return d_equalityEngine->areEqual(a, b);
}else{
return false;
}
@@ -1577,19 +1712,16 @@ bool TheorySep::areDisequal( Node a, Node b ){
if( a==b ){
return false;
}else if( hasTerm( a ) && hasTerm( b ) ){
- if( d_equalityEngine.areDisequal( a, b, false ) ){
+ if (d_equalityEngine->areDisequal(a, b, false))
+ {
return true;
}
}
return false;
}
-
-void TheorySep::eqNotifyPreMerge(TNode t1, TNode t2) {
-
-}
-
-void TheorySep::eqNotifyPostMerge(TNode t1, TNode t2) {
+void TheorySep::eqNotifyMerge(TNode t1, TNode t2)
+{
HeapAssertInfo * e2 = getOrMakeEqcInfo( t2, false );
if( e2 && ( !e2->d_pto.get().isNull() || e2->d_has_neg_pto.get() ) ){
HeapAssertInfo * e1 = getOrMakeEqcInfo( t1, true );
@@ -1615,8 +1747,9 @@ void TheorySep::validatePto( HeapAssertInfo * ei, Node ei_n ) {
{
TNode atom = fact[0];
Assert(atom.getKind() == kind::SEP_LABEL);
- TNode s_atom = atom[0];
- if( s_atom.getKind()==kind::SEP_PTO ){
+ TNode satom = atom[0];
+ if (satom.getKind() == SEP_PTO)
+ {
if( areEqual( atom[1], ei_n ) ){
addPto( ei, ei_n, atom, false );
}
@@ -1696,79 +1829,29 @@ void TheorySep::sendLemma( std::vector< Node >& ant, Node conc, const char * c,
Trace("sep-lemma-debug") << "Got : " << conc << std::endl;
if( conc!=d_true ){
if( infer && conc!=d_false ){
- Node ant_n;
- if( ant.empty() ){
- ant_n = d_true;
- }else if( ant.size()==1 ){
- ant_n = ant[0];
- }else{
- ant_n = NodeManager::currentNM()->mkNode( kind::AND, ant );
- }
+ Node ant_n = NodeManager::currentNM()->mkAnd(ant);
Trace("sep-lemma") << "Sep::Infer: " << conc << " from " << ant_n << " by " << c << std::endl;
- d_pending_exp.push_back( ant_n );
- d_pending.push_back( conc );
- d_infer.push_back( ant_n );
- d_infer_exp.push_back( conc );
+ d_im.addPendingFact(conc, ant_n);
}else{
- std::vector< TNode > ant_e;
- for( unsigned i=0; i<ant.size(); i++ ){
- Trace("sep-lemma-debug") << "Explain : " << ant[i] << std::endl;
- explain( ant[i], ant_e );
- }
- Node ant_n;
- if( ant_e.empty() ){
- ant_n = d_true;
- }else if( ant_e.size()==1 ){
- ant_n = ant_e[0];
- }else{
- ant_n = NodeManager::currentNM()->mkNode( kind::AND, ant_e );
- }
if( conc==d_false ){
- Trace("sep-lemma") << "Sep::Conflict: " << ant_n << " by " << c << std::endl;
- d_out->conflict( ant_n );
- d_conflict = true;
+ Trace("sep-lemma") << "Sep::Conflict: " << ant << " by " << c
+ << std::endl;
+ d_im.conflictExp(ant, nullptr);
}else{
- Trace("sep-lemma") << "Sep::Lemma: " << conc << " from " << ant_n << " by " << c << std::endl;
- d_pending_exp.push_back( ant_n );
- d_pending.push_back( conc );
- d_pending_lem.push_back( d_pending.size()-1 );
+ Trace("sep-lemma") << "Sep::Lemma: " << conc << " from " << ant
+ << " by " << c << std::endl;
+ TrustNode trn = d_im.mkLemmaExp(conc, ant, {});
+ d_im.addPendingLemma(
+ trn.getNode(), LemmaProperty::NONE, trn.getGenerator());
}
}
}
}
-void TheorySep::doPendingFacts() {
- if( d_pending_lem.empty() ){
- for( unsigned i=0; i<d_pending.size(); i++ ){
- if( d_conflict ){
- break;
- }
- Node atom = d_pending[i].getKind()==kind::NOT ? d_pending[i][0] : d_pending[i];
- bool pol = d_pending[i].getKind()!=kind::NOT;
- Trace("sep-pending") << "Sep : Assert to EE : " << atom << ", pol = " << pol << std::endl;
- if( atom.getKind()==kind::EQUAL ){
- d_equalityEngine.assertEquality(atom, pol, d_pending_exp[i]);
- }else{
- d_equalityEngine.assertPredicate(atom, pol, d_pending_exp[i]);
- }
- }
- }else{
- for( unsigned i=0; i<d_pending_lem.size(); i++ ){
- if( d_conflict ){
- break;
- }
- int index = d_pending_lem[i];
- Node lem = NodeManager::currentNM()->mkNode( kind::IMPLIES, d_pending_exp[index], d_pending[index] );
- if( d_lemmas_produced_c.find( lem )==d_lemmas_produced_c.end() ){
- d_lemmas_produced_c.insert( lem );
- d_out->lemma( lem );
- Trace("sep-pending") << "Sep : Lemma : " << lem << std::endl;
- }
- }
- }
- d_pending_exp.clear();
- d_pending.clear();
- d_pending_lem.clear();
+void TheorySep::doPending()
+{
+ d_im.doPendingFacts();
+ d_im.doPendingLemmas();
}
void TheorySep::debugPrintHeap( HeapInfo& heap, const char * c ) {
@@ -1785,15 +1868,13 @@ Node TheorySep::HeapInfo::getValue( TypeNode tn ) {
Assert(d_heap_locs.size() == d_heap_locs_model.size());
if( d_heap_locs.empty() ){
return NodeManager::currentNM()->mkConst(EmptySet(tn));
- }else if( d_heap_locs.size()==1 ){
- return d_heap_locs[0];
- }else{
- Node curr = NodeManager::currentNM()->mkNode( kind::UNION, d_heap_locs[0], d_heap_locs[1] );
- for( unsigned j=2; j<d_heap_locs.size(); j++ ){
- curr = NodeManager::currentNM()->mkNode( kind::UNION, curr, d_heap_locs[j] );
- }
- return curr;
}
+ Node curr = d_heap_locs[0];
+ for (unsigned j = 1; j < d_heap_locs.size(); j++)
+ {
+ curr = NodeManager::currentNM()->mkNode(kind::UNION, d_heap_locs[j], curr);
+ }
+ return curr;
}
}/* CVC4::theory::sep namespace */
diff --git a/src/theory/sep/theory_sep.h b/src/theory/sep/theory_sep.h
index 3685ea063..9e96dccc3 100644
--- a/src/theory/sep/theory_sep.h
+++ b/src/theory/sep/theory_sep.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -23,6 +23,7 @@
#include "context/cdhashset.h"
#include "context/cdlist.h"
#include "context/cdqueue.h"
+#include "theory/inference_manager_buffered.h"
#include "theory/sep/theory_sep_rewriter.h"
#include "theory/theory.h"
#include "theory/uf/equality_engine.h"
@@ -58,6 +59,10 @@ class TheorySep : public Theory {
bool d_bounds_init;
TheorySepRewriter d_rewriter;
+ /** A (default) theory state object */
+ TheoryState d_state;
+ /** A buffered inference manager */
+ InferenceManagerBuffered d_im;
Node mkAnd( std::vector< TNode >& assumptions );
@@ -74,9 +79,29 @@ class TheorySep : public Theory {
ProofNodeManager* pnm = nullptr);
~TheorySep();
- TheoryRewriter* getTheoryRewriter() override { return &d_rewriter; }
-
- void setMasterEqualityEngine(eq::EqualityEngine* eq) override;
+ /**
+ * Declare heap. For smt2 inputs, this is called when the command
+ * (declare-heap (locT datat)) is invoked by the user. This sets locT as the
+ * location type and dataT is the data type for the heap. This command can be
+ * executed once only, and must be invoked before solving separation logic
+ * inputs.
+ */
+ void declareSepHeap(TypeNode locT, TypeNode dataT) override;
+
+ //--------------------------------- initialization
+ /** get the official theory rewriter of this theory */
+ TheoryRewriter* getTheoryRewriter() override;
+ /**
+ * Returns true if we need an equality engine. If so, we initialize the
+ * information regarding how it should be setup. For details, see the
+ * documentation in Theory::needsEqualityEngine.
+ */
+ bool needsEqualityEngine(EeSetupInfo& esi) override;
+ /** finish initialization */
+ void finishInit() override;
+ //--------------------------------- end initialization
+ /** preregister term */
+ void preRegisterTerm(TNode n) override;
std::string identify() const override { return std::string("TheorySep"); }
@@ -85,8 +110,6 @@ class TheorySep : public Theory {
/////////////////////////////////////////////////////////////////////////////
public:
- PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions) override;
-
void ppNotifyAssertions(const std::vector<Node>& assertions) override;
/////////////////////////////////////////////////////////////////////////////
// T-PROPAGATION / REGISTRATION
@@ -94,18 +117,14 @@ class TheorySep : public Theory {
private:
/** Should be called to propagate the literal. */
- bool propagate(TNode literal);
-
- /** Explain why this literal is true by adding assumptions */
- void explain(TNode literal, std::vector<TNode>& assumptions);
+ bool propagateLit(TNode literal);
+ /** Conflict when merging constants */
+ void conflict(TNode a, TNode b);
public:
- void propagate(Effort e) override;
TrustNode explain(TNode n) override;
public:
- void addSharedTerm(TNode t) override;
- EqualityStatus getEqualityStatus(TNode a, TNode b) override;
void computeCareGraph() override;
/////////////////////////////////////////////////////////////////////////////
@@ -113,7 +132,6 @@ class TheorySep : public Theory {
/////////////////////////////////////////////////////////////////////////////
public:
- bool collectModelInfo(TheoryModel* m) override;
void postProcessModel(TheoryModel* m) override;
/////////////////////////////////////////////////////////////////////////////
@@ -128,12 +146,27 @@ class TheorySep : public Theory {
/////////////////////////////////////////////////////////////////////////////
// MAIN SOLVER
/////////////////////////////////////////////////////////////////////////////
- public:
- void check(Effort e) override;
+ //--------------------------------- standard check
+ /** Do we need a check call at last call effort? */
bool needsCheckLastEffort() override;
+ /** Post-check, called after the fact queue of the theory is processed. */
+ void postCheck(Effort level) override;
+ /** Pre-notify fact, return true if processed. */
+ bool preNotifyFact(TNode atom,
+ bool pol,
+ TNode fact,
+ bool isPrereg,
+ bool isInternal) override;
+ /** Notify fact */
+ void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal) override;
+ //--------------------------------- end standard check
private:
+ /** Ensures that the reduction has been added for the given fact */
+ void reduceFact(TNode atom, bool polarity, TNode fact);
+ /** Is spatial kind? */
+ bool isSpatialKind(Kind k) const;
// NotifyClass: template helper class for d_equalityEngine - handles
// call-back from congruence closure module
class NotifyClass : public eq::EqualityEngineNotify
@@ -143,27 +176,19 @@ class TheorySep : public Theory {
public:
NotifyClass(TheorySep& sep) : d_sep(sep) {}
- bool eqNotifyTriggerEquality(TNode equality, bool value) override
+ bool eqNotifyTriggerPredicate(TNode predicate, bool value) override
{
Debug("sep::propagate")
- << "NotifyClass::eqNotifyTriggerEquality(" << equality << ", "
+ << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", "
<< (value ? "true" : "false") << ")" << std::endl;
+ Assert(predicate.getKind() == kind::EQUAL);
// Just forward to sep
if (value)
{
- return d_sep.propagate(equality);
- }
- else
- {
- return d_sep.propagate(equality.notNode());
+ return d_sep.propagateLit(predicate);
}
+ return d_sep.propagateLit(predicate.notNode());
}
-
- bool eqNotifyTriggerPredicate(TNode predicate, bool value) override
- {
- Unreachable();
- }
-
bool eqNotifyTriggerTermEquality(TheoryId tag,
TNode t1,
TNode t2,
@@ -175,13 +200,9 @@ class TheorySep : public Theory {
if (value)
{
// Propagate equality between shared terms
- return d_sep.propagate(t1.eqNode(t2));
- }
- else
- {
- return d_sep.propagate(t1.eqNode(t2).notNode());
+ return d_sep.propagateLit(t1.eqNode(t2));
}
- return true;
+ return d_sep.propagateLit(t1.eqNode(t2).notNode());
}
void eqNotifyConstantTermMerge(TNode t1, TNode t2) override
@@ -192,13 +213,9 @@ class TheorySep : public Theory {
}
void eqNotifyNewClass(TNode t) override {}
- void eqNotifyPreMerge(TNode t1, TNode t2) override
- {
- d_sep.eqNotifyPreMerge(t1, t2);
- }
- void eqNotifyPostMerge(TNode t1, TNode t2) override
+ void eqNotifyMerge(TNode t1, TNode t2) override
{
- d_sep.eqNotifyPostMerge(t1, t2);
+ d_sep.eqNotifyMerge(t1, t2);
}
void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override {}
};
@@ -206,21 +223,9 @@ class TheorySep : public Theory {
/** The notify class for d_equalityEngine */
NotifyClass d_notify;
- /** Equaltity engine */
- eq::EqualityEngine d_equalityEngine;
-
- /** Are we in conflict? */
- context::CDO<bool> d_conflict;
- std::vector< Node > d_pending_exp;
- std::vector< Node > d_pending;
- std::vector< int > d_pending_lem;
-
/** list of all refinement lemms */
std::map< Node, std::map< Node, std::vector< Node > > > d_refinement_lem;
- /** Conflict when merging constants */
- void conflict(TNode a, TNode b);
-
//cache for positive polarity start reduction
NodeSet d_reduce;
std::map< Node, std::map< Node, Node > > d_red_conc;
@@ -230,9 +235,6 @@ class TheorySep : public Theory {
std::map<Node, std::unique_ptr<DecisionStrategySingleton> >
d_neg_guard_strategy;
std::map< Node, Node > d_guard_to_assertion;
- /** inferences: maintained to ensure ref count for internally introduced nodes */
- NodeList d_infer;
- NodeList d_infer_exp;
NodeList d_spatial_assertions;
//data,ref type (globally fixed)
@@ -283,7 +285,19 @@ class TheorySep : public Theory {
//get global reference/data type
TypeNode getReferenceType( Node n );
TypeNode getDataType( Node n );
- void registerRefDataTypes( TypeNode tn1, TypeNode tn2, Node atom );
+ /**
+ * Register reference data types for atom. Calls the method below for
+ * the appropriate types.
+ */
+ void registerRefDataTypesAtom(Node atom);
+ /**
+ * This is called either when:
+ * (A) a declare-heap command is issued with tn1/tn2, and atom is null, or
+ * (B) an atom specifying the heap type tn1/tn2 is registered to this theory.
+ * We set the heap type if we are are case (A), and check whether the
+ * heap type is consistent in the case of (B).
+ */
+ void registerRefDataTypes(TypeNode tn1, TypeNode tn2, Node atom);
//get location/data type
//get the base label for the spatial assertion
Node getBaseLabel( TypeNode tn );
@@ -324,14 +338,12 @@ class TheorySep : public Theory {
bool hasTerm( Node a );
bool areEqual( Node a, Node b );
bool areDisequal( Node a, Node b );
- void eqNotifyPreMerge(TNode t1, TNode t2);
- void eqNotifyPostMerge(TNode t1, TNode t2);
+ void eqNotifyMerge(TNode t1, TNode t2);
void sendLemma( std::vector< Node >& ant, Node conc, const char * c, bool infer = false );
- void doPendingFacts();
+ void doPending();
public:
- eq::EqualityEngine* getEqualityEngine() override { return &d_equalityEngine; }
void initializeBounds();
};/* class TheorySep */
diff --git a/src/theory/sep/theory_sep_rewriter.cpp b/src/theory/sep/theory_sep_rewriter.cpp
index 10348a415..78837508e 100644
--- a/src/theory/sep/theory_sep_rewriter.cpp
+++ b/src/theory/sep/theory_sep_rewriter.cpp
@@ -2,10 +2,10 @@
/*! \file theory_sep_rewriter.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds
+ ** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -102,7 +102,9 @@ RewriteResponse TheorySepRewriter::postRewrite(TNode node) {
switch (node.getKind()) {
case kind::SEP_LABEL: {
if( node[0].getKind()==kind::SEP_PTO ){
- Node s = NodeManager::currentNM()->mkNode( kind::SINGLETON, node[0][0] );
+ // TODO(project##230): Find a safe type for the singleton operator
+ Node s = NodeManager::currentNM()->mkSingleton(node[0][0].getType(),
+ node[0][0]);
if( node[1]!=s ){
Node c1 = node[1].eqNode( s );
Node c2 = NodeManager::currentNM()->mkNode( kind::SEP_LABEL, NodeManager::currentNM()->mkNode( kind::SEP_PTO, node[0][0], node[0][1] ), s );
diff --git a/src/theory/sep/theory_sep_rewriter.h b/src/theory/sep/theory_sep_rewriter.h
index 99020ce41..f7ef8b025 100644
--- a/src/theory/sep/theory_sep_rewriter.h
+++ b/src/theory/sep/theory_sep_rewriter.h
@@ -5,7 +5,7 @@
** Andres Noetzli, Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/sep/theory_sep_type_rules.h b/src/theory/sep/theory_sep_type_rules.h
index 2c1035834..ac1657aea 100644
--- a/src/theory/sep/theory_sep_type_rules.h
+++ b/src/theory/sep/theory_sep_type_rules.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/sets/cardinality_extension.cpp b/src/theory/sets/cardinality_extension.cpp
index f8b5c2e25..228f2cd3f 100644
--- a/src/theory/sets/cardinality_extension.cpp
+++ b/src/theory/sets/cardinality_extension.cpp
@@ -2,10 +2,10 @@
/*! \file cardinality_extension.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Mudathir Mohamed, Mathias Preiner
+ ** Andrew Reynolds, Mudathir Mohamed, Gereon Kremer
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,6 +18,7 @@
#include "expr/emptyset.h"
#include "expr/node_algorithm.h"
#include "options/sets_options.h"
+#include "smt/logic_exception.h"
#include "theory/sets/normal_form.h"
#include "theory/theory_model.h"
#include "theory/valuation.h"
@@ -31,19 +32,15 @@ namespace sets {
CardinalityExtension::CardinalityExtension(SolverState& s,
InferenceManager& im,
- eq::EqualityEngine& e,
- context::Context* c,
- context::UserContext* u)
+ TermRegistry& treg)
: d_state(s),
d_im(im),
- d_ee(e),
- d_card_processed(u),
+ d_treg(treg),
+ d_card_processed(s.getUserContext()),
d_finite_type_constants_processed(false)
{
d_true = NodeManager::currentNM()->mkConst(true);
d_zero = NodeManager::currentNM()->mkConst(Rational(0));
- // we do congruence over cardinality
- d_ee.addFunctionKind(CARD);
}
void CardinalityExtension::reset()
@@ -60,7 +57,7 @@ void CardinalityExtension::registerTerm(Node n)
Assert(n.getKind() == CARD);
TypeNode tnc = n[0].getType().getSetElementType();
d_t_card_enabled[tnc] = true;
- Node r = d_ee.getRepresentative(n[0]);
+ Node r = d_state.getRepresentative(n[0]);
if (d_eqc_to_card_term.find(r) == d_eqc_to_card_term.end())
{
d_eqc_to_card_term[r] = n;
@@ -107,7 +104,7 @@ void CardinalityExtension::checkCardinalityExtended(TypeNode& t)
// here we call getUnivSet instead of getUnivSetEqClass to generate
// a univset term for finite types even if they are not used in the input
- Node univ = d_state.getUnivSet(setType);
+ Node univ = d_treg.getUnivSet(setType);
std::map<Node, Node>::iterator it = d_univProxy.find(univ);
Node proxy;
@@ -115,7 +112,7 @@ void CardinalityExtension::checkCardinalityExtended(TypeNode& t)
if (it == d_univProxy.end())
{
// Force cvc4 to build the cardinality graph for the universe set
- proxy = d_state.getProxy(univ);
+ proxy = d_treg.getProxy(univ);
d_univProxy[univ] = proxy;
}
else
@@ -144,7 +141,7 @@ void CardinalityExtension::checkCardinalityExtended(TypeNode& t)
for (Node& representative : representatives)
{
// the universe set is a subset of itself
- if (representative != d_ee.getRepresentative(univ))
+ if (representative != d_state.getRepresentative(univ))
{
// here we only add representatives with variables to avoid adding
// infinite equivalent generated terms to the cardinality graph
@@ -189,17 +186,17 @@ void CardinalityExtension::check()
{
checkCardinalityExtended();
checkRegister();
- if (d_im.hasProcessed())
+ if (d_im.hasSent())
{
return;
}
checkMinCard();
- if (d_im.hasProcessed())
+ if (d_im.hasSent())
{
return;
}
checkCardCycles();
- if (d_im.hasProcessed())
+ if (d_im.hasSent())
{
return;
}
@@ -214,9 +211,9 @@ void CardinalityExtension::check()
Assert(intro_sets.size() == 1);
Trace("sets-intro") << "Introduce term : " << intro_sets[0] << std::endl;
Trace("sets-intro") << " Actual Intro : ";
- d_state.debugPrintSet(intro_sets[0], "sets-nf");
+ d_treg.debugPrintSet(intro_sets[0], "sets-nf");
Trace("sets-nf") << std::endl;
- Node k = d_state.getProxy(intro_sets[0]);
+ Node k = d_treg.getProxy(intro_sets[0]);
AlwaysAssert(!k.isNull());
}
@@ -280,7 +277,7 @@ void CardinalityExtension::registerCardinalityTerm(Node n)
for (unsigned k = 0, csize = cterms.size(); k < csize; k++)
{
Node nn = cterms[k];
- Node nk = d_state.getProxy(nn);
+ Node nk = d_treg.getProxy(nn);
Node pos_lem = nm->mkNode(GEQ, nm->mkNode(CARD, nk), d_zero);
d_im.assertInference(pos_lem, d_emp_exp, "pcard", 1);
if (nn != nk)
@@ -291,7 +288,7 @@ void CardinalityExtension::registerCardinalityTerm(Node n)
d_im.assertInference(lem, d_emp_exp, "card", 1);
}
}
- d_im.flushPendingLemmas();
+ d_im.doPendingLemmas();
}
void CardinalityExtension::checkCardCycles()
@@ -306,11 +303,14 @@ void CardinalityExtension::checkCardCycles()
std::vector<Node> curr;
std::vector<Node> exp;
checkCardCyclesRec(s, curr, exp);
- if (d_im.hasProcessed())
+ if (d_im.hasSent())
{
return;
}
}
+
+ Trace("sets") << "d_card_parent: " << d_card_parent << std::endl;
+ Trace("sets") << "d_oSetEqc: " << d_oSetEqc << std::endl;
Trace("sets") << "Done check cardinality cycles" << std::endl;
}
@@ -343,7 +343,7 @@ void CardinalityExtension::checkCardCyclesRec(Node eqc,
Trace("sets-cycle-debug")
<< "CYCLE: " << fact << " from " << exp << std::endl;
d_im.assertInference(fact, exp, "card_cycle");
- d_im.flushPendingLemmas();
+ d_im.doPendingLemmas();
}
else
{
@@ -367,7 +367,7 @@ void CardinalityExtension::checkCardCyclesRec(Node eqc,
curr.push_back(eqc);
TypeNode tn = eqc.getType();
bool is_empty = eqc == d_state.getEmptySetEqClass(tn);
- Node emp_set = d_state.getEmptySet(tn);
+ Node emp_set = d_treg.getEmptySet(tn);
for (const Node& n : nvsets)
{
Kind nk = n.getKind();
@@ -399,7 +399,7 @@ void CardinalityExtension::checkCardCyclesRec(Node eqc,
true_sib = 1;
}
Node u = Rewriter::rewrite(nm->mkNode(UNION, n[0], n[1]));
- if (!d_ee.hasTerm(u))
+ if (!d_state.hasTerm(u))
{
u = Node::null();
}
@@ -413,14 +413,14 @@ void CardinalityExtension::checkCardCyclesRec(Node eqc,
// parent equal siblings
for (unsigned e = 0; e < true_sib; e++)
{
- if (d_ee.hasTerm(sib[e]) && !d_state.areEqual(n[e], sib[e]))
+ if (d_state.hasTerm(sib[e]) && !d_state.areEqual(n[e], sib[e]))
{
conc.push_back(n[e].eqNode(sib[e]));
}
}
d_im.assertInference(conc, n.eqNode(emp_set), "cg_emp");
- d_im.flushPendingLemmas();
- if (d_im.hasProcessed())
+ d_im.doPendingLemmas();
+ if (d_im.hasSent())
{
return;
}
@@ -451,8 +451,8 @@ void CardinalityExtension::checkCardCyclesRec(Node eqc,
Trace("sets-debug") << " it is empty..." << std::endl;
Assert(!d_state.areEqual(n, emp_set));
d_im.assertInference(n.eqNode(emp_set), p.eqNode(emp_set), "cg_emppar");
- d_im.flushPendingLemmas();
- if (d_im.hasProcessed())
+ d_im.doPendingLemmas();
+ if (d_im.hasSent())
{
return;
}
@@ -498,8 +498,8 @@ void CardinalityExtension::checkCardCyclesRec(Node eqc,
Trace("sets-debug")
<< "...derived " << conc.size() << " conclusions" << std::endl;
d_im.assertInference(conc, n.eqNode(p), "cg_eqpar");
- d_im.flushPendingLemmas();
- if (d_im.hasProcessed())
+ d_im.doPendingLemmas();
+ if (d_im.hasSent())
{
return;
}
@@ -518,7 +518,7 @@ void CardinalityExtension::checkCardCyclesRec(Node eqc,
for (unsigned k = 0, numcp = card_parents.size(); k < numcp; k++)
{
Node cpk = card_parents[k];
- Node eqcc = d_ee.getRepresentative(cpk);
+ Node eqcc = d_state.getRepresentative(cpk);
Trace("sets-debug") << "Check card parent " << k << "/"
<< card_parents.size() << std::endl;
@@ -550,7 +550,7 @@ void CardinalityExtension::checkCardCyclesRec(Node eqc,
{
Node conc = n.eqNode(cpk);
d_im.assertInference(conc, exps, "cg_par_sing");
- d_im.flushPendingLemmas();
+ d_im.doPendingLemmas();
}
else
{
@@ -558,7 +558,7 @@ void CardinalityExtension::checkCardCyclesRec(Node eqc,
Trace("sets-nf") << "Split empty : " << n << std::endl;
d_im.split(n.eqNode(emp_set), 1);
}
- Assert(d_im.hasProcessed());
+ Assert(d_im.hasSent());
return;
}
else
@@ -605,8 +605,8 @@ void CardinalityExtension::checkCardCyclesRec(Node eqc,
}
}
d_im.assertInference(conc, cpk.eqNode(cpnl), "cg_pareq");
- d_im.flushPendingLemmas();
- if (d_im.hasProcessed())
+ d_im.doPendingLemmas();
+ if (d_im.hasSent())
{
return;
}
@@ -625,7 +625,7 @@ void CardinalityExtension::checkCardCyclesRec(Node eqc,
Trace("sets-cycle-debug")
<< "Traverse card parent " << eqc << " -> " << cpnc << std::endl;
checkCardCyclesRec(cpnc, curr, exp);
- if (d_im.hasProcessed())
+ if (d_im.hasSent())
{
return;
}
@@ -648,7 +648,7 @@ void CardinalityExtension::checkNormalForms(std::vector<Node>& intro_sets)
for (int i = (int)(d_oSetEqc.size() - 1); i >= 0; i--)
{
checkNormalForm(d_oSetEqc[i], intro_sets);
- if (d_im.hasProcessed() || !intro_sets.empty())
+ if (d_im.hasSent() || !intro_sets.empty())
{
return;
}
@@ -689,7 +689,7 @@ void CardinalityExtension::checkNormalForm(Node eqc,
Trace("sets-nf") << " F " << itf.first << " : " << itf.second
<< std::endl;
Trace("sets-nf-debug") << " ...";
- d_state.debugPrintSet(itf.first, "sets-nf-debug");
+ d_treg.debugPrintSet(itf.first, "sets-nf-debug");
Trace("sets-nf-debug") << std::endl;
}
}
@@ -702,7 +702,7 @@ void CardinalityExtension::checkNormalForm(Node eqc,
std::vector<Node>& nfeqc = d_nf[eqc];
NodeManager* nm = NodeManager::currentNM();
bool success = true;
- Node emp_set = d_state.getEmptySet(tn);
+ Node emp_set = d_treg.getEmptySet(tn);
if (!base.isNull())
{
for (unsigned j = 0, csize = comps.size(); j < csize; j++)
@@ -778,7 +778,7 @@ void CardinalityExtension::checkNormalForm(Node eqc,
Node r = e == 2 ? common[l] : only[e][l];
Trace("sets-nf-debug") << "Try split empty : " << r << std::endl;
Trace("sets-nf-debug") << " actual : ";
- d_state.debugPrintSet(r, "sets-nf-debug");
+ d_treg.debugPrintSet(r, "sets-nf-debug");
Trace("sets-nf-debug") << std::endl;
Assert(!d_state.areEqual(r, emp_set));
if (!d_state.areDisequal(r, emp_set) && !d_state.hasMembers(r))
@@ -786,10 +786,10 @@ void CardinalityExtension::checkNormalForm(Node eqc,
// guess that its equal empty if it has no explicit members
Trace("sets-nf") << " Split empty : " << r << std::endl;
Trace("sets-nf") << "Actual Split : ";
- d_state.debugPrintSet(r, "sets-nf");
+ d_treg.debugPrintSet(r, "sets-nf");
Trace("sets-nf") << std::endl;
d_im.split(r.eqNode(emp_set), 1);
- Assert(d_im.hasProcessed());
+ Assert(d_im.hasSent());
return;
}
}
@@ -826,14 +826,14 @@ void CardinalityExtension::checkNormalForm(Node eqc,
{
// simply introduce their intersection
Assert(o0 != o1);
- Node kca = d_state.getProxy(o0);
- Node kcb = d_state.getProxy(o1);
+ Node kca = d_treg.getProxy(o0);
+ Node kcb = d_treg.getProxy(o1);
Node intro =
Rewriter::rewrite(nm->mkNode(INTERSECTION, kca, kcb));
Trace("sets-nf") << " Intro split : " << o0 << " against " << o1
<< ", term is " << intro << std::endl;
intro_sets.push_back(intro);
- Assert(!d_ee.hasTerm(intro));
+ Assert(!d_state.hasTerm(intro));
return;
}
}
@@ -873,7 +873,7 @@ void CardinalityExtension::checkNormalForm(Node eqc,
}
if (!success)
{
- Assert(d_im.hasProcessed());
+ Assert(d_im.hasSent());
return;
}
// Send to parents (a parent is a set that contains a term in this equivalence
@@ -976,7 +976,7 @@ void CardinalityExtension::checkMinCard()
}
}
// flush the lemmas
- d_im.flushPendingLemmas();
+ d_im.doPendingLemmas();
}
bool CardinalityExtension::isModelValueBasic(Node eqc)
@@ -1001,9 +1001,14 @@ void CardinalityExtension::mkModelValueElementsFor(
Node v = val.getModelValue(it->second);
Trace("sets-model") << "Cardinality of " << eqc << " is " << v
<< std::endl;
- Assert(v.getConst<Rational>() <= LONG_MAX)
- << "Exceeded LONG_MAX in sets model";
- unsigned vu = v.getConst<Rational>().getNumerator().toUnsignedInt();
+ if (v.getConst<Rational>() > UINT32_MAX)
+ {
+ std::stringstream ss;
+ ss << "The model for " << eqc << " was computed to have cardinality "
+ << v << ". We only allow sets up to cardinality " << UINT32_MAX;
+ throw LogicException(ss.str());
+ }
+ std::uint32_t vu = v.getConst<Rational>().getNumerator().toUnsignedInt();
Assert(els.size() <= vu);
NodeManager* nm = NodeManager::currentNM();
if (elementType.isInterpretedFinite())
@@ -1026,7 +1031,7 @@ void CardinalityExtension::mkModelValueElementsFor(
// the current members of this finite type.
Node slack = nm->mkSkolem("slack", elementType);
- Node singleton = nm->mkNode(SINGLETON, slack);
+ Node singleton = nm->mkSingleton(elementType, slack);
els.push_back(singleton);
d_finite_type_slack_elements[elementType].push_back(slack);
Trace("sets-model") << "Added slack element " << slack << " to set "
@@ -1035,7 +1040,7 @@ void CardinalityExtension::mkModelValueElementsFor(
else
{
els.push_back(
- nm->mkNode(SINGLETON, nm->mkSkolem("msde", elementType)));
+ nm->mkSingleton(elementType, nm->mkSkolem("msde", elementType)));
}
}
}
diff --git a/src/theory/sets/cardinality_extension.h b/src/theory/sets/cardinality_extension.h
index 570530108..08424d3c4 100644
--- a/src/theory/sets/cardinality_extension.h
+++ b/src/theory/sets/cardinality_extension.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mudathir Mohamed
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,6 +21,7 @@
#include "context/context.h"
#include "theory/sets/inference_manager.h"
#include "theory/sets/solver_state.h"
+#include "theory/sets/term_registry.h"
#include "theory/type_set.h"
#include "theory/uf/equality_engine.h"
@@ -69,9 +70,7 @@ class CardinalityExtension
*/
CardinalityExtension(SolverState& s,
InferenceManager& im,
- eq::EqualityEngine& e,
- context::Context* c,
- context::UserContext* u);
+ TermRegistry& treg);
~CardinalityExtension() {}
/** reset
@@ -164,11 +163,11 @@ class CardinalityExtension
SolverState& d_state;
/** Reference to the inference manager for the theory of sets */
InferenceManager& d_im;
- /** Reference to the equality engine of theory of sets */
- eq::EqualityEngine& d_ee;
+ /** Reference to the term registry */
+ TermRegistry& d_treg;
/** register cardinality term
*
- * This method add lemmas corresponding to the definition of
+ * This method adds lemmas corresponding to the definition of
* the cardinality of set term n. For example, if n is A^B (denoting set
* intersection as ^), then we consider the lemmas card(A^B)>=0,
* card(A) = card(A\B) + card(A^B) and card(B) = card(B\A) + card(A^B).
diff --git a/src/theory/sets/inference_manager.cpp b/src/theory/sets/inference_manager.cpp
index 3b1451e3d..fe4a5875a 100644
--- a/src/theory/sets/inference_manager.cpp
+++ b/src/theory/sets/inference_manager.cpp
@@ -2,10 +2,10 @@
/*! \file inference_manager.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Paul Meng
+ ** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -15,8 +15,6 @@
#include "theory/sets/inference_manager.h"
#include "options/sets_options.h"
-#include "theory/sets/theory_sets.h"
-#include "theory/sets/theory_sets_private.h"
using namespace std;
using namespace CVC4::kind;
@@ -25,28 +23,15 @@ namespace CVC4 {
namespace theory {
namespace sets {
-InferenceManager::InferenceManager(TheorySetsPrivate& p,
+InferenceManager::InferenceManager(Theory& t,
SolverState& s,
- context::Context* c,
- context::UserContext* u)
- : d_parent(p),
- d_state(s),
- d_sentLemma(false),
- d_addedFact(false),
- d_lemmas_produced(u),
- d_keep(c)
+ ProofNodeManager* pnm)
+ : InferenceManagerBuffered(t, s, pnm), d_state(s)
{
d_true = NodeManager::currentNM()->mkConst(true);
d_false = NodeManager::currentNM()->mkConst(false);
}
-void InferenceManager::reset()
-{
- d_sentLemma = false;
- d_addedFact = false;
- d_pendingLemmas.clear();
-}
-
bool InferenceManager::assertFactRec(Node fact, Node exp, int inferType)
{
// should we send this fact out as a lemma?
@@ -61,7 +46,7 @@ bool InferenceManager::assertFactRec(Node fact, Node exp, int inferType)
{
lem = NodeManager::currentNM()->mkNode(IMPLIES, exp, fact);
}
- d_pendingLemmas.push_back(lem);
+ addPendingLemma(lem);
return true;
}
Trace("sets-fact") << "Assert fact rec : " << fact << ", exp = " << exp
@@ -72,7 +57,7 @@ bool InferenceManager::assertFactRec(Node fact, Node exp, int inferType)
if (fact == d_false)
{
Trace("sets-lemma") << "Conflict : " << exp << std::endl;
- d_state.setConflict(exp);
+ conflict(exp);
return true;
}
return false;
@@ -96,18 +81,22 @@ bool InferenceManager::assertFactRec(Node fact, Node exp, int inferType)
}
bool polarity = fact.getKind() != NOT;
TNode atom = polarity ? fact : fact[0];
+ if (d_state.isEntailed(atom, polarity))
+ {
+ return false;
+ }
// things we can assert to equality engine
if (atom.getKind() == MEMBER
|| (atom.getKind() == EQUAL && atom[0].getType().isSet()))
{
// send to equality engine
- if (d_parent.assertFact(fact, exp))
+ if (assertInternalFact(atom, polarity, exp))
{
- d_addedFact = true;
+ // return true if this wasn't redundant
return true;
}
}
- else if (!d_state.isEntailed(fact, true))
+ else
{
// must send as lemma
Node lem = fact;
@@ -115,7 +104,7 @@ bool InferenceManager::assertFactRec(Node fact, Node exp, int inferType)
{
lem = NodeManager::currentNM()->mkNode(IMPLIES, exp, fact);
}
- d_pendingLemmas.push_back(lem);
+ addPendingLemma(lem);
return true;
}
return false;
@@ -125,8 +114,6 @@ void InferenceManager::assertInference(Node fact,
const char* c,
int inferType)
{
- d_keep.insert(exp);
- d_keep.insert(fact);
if (assertFactRec(fact, exp, inferType))
{
Trace("sets-lemma") << "Sets::Lemma : " << fact << " from " << exp << " by "
@@ -176,60 +163,16 @@ void InferenceManager::split(Node n, int reqPol)
{
n = Rewriter::rewrite(n);
Node lem = NodeManager::currentNM()->mkNode(OR, n, n.negate());
- flushLemma(lem);
+ // send the lemma
+ lemma(lem);
Trace("sets-lemma") << "Sets::Lemma split : " << lem << std::endl;
if (reqPol != 0)
{
Trace("sets-lemma") << "Sets::Require phase " << n << " " << (reqPol > 0)
<< std::endl;
- d_parent.getOutputChannel()->requirePhase(n, reqPol > 0);
- }
-}
-void InferenceManager::flushLemmas(std::vector<Node>& lemmas, bool preprocess)
-{
- if (!d_state.isInConflict())
- {
- for (const Node& l : lemmas)
- {
- flushLemma(l, preprocess);
- }
- }
- lemmas.clear();
-}
-
-void InferenceManager::flushLemma(Node lem, bool preprocess)
-{
- if (d_state.isInConflict())
- {
- return;
+ requirePhase(n, reqPol > 0);
}
- if (d_lemmas_produced.find(lem) != d_lemmas_produced.end())
- {
- Trace("sets-lemma-debug") << "Already sent lemma : " << lem << std::endl;
- return;
- }
- Trace("sets-lemma-debug") << "Send lemma : " << lem << std::endl;
- d_lemmas_produced.insert(lem);
- d_parent.getOutputChannel()->lemma(lem, false, preprocess);
- d_sentLemma = true;
-}
-
-void InferenceManager::flushPendingLemmas(bool preprocess)
-{
- flushLemmas(d_pendingLemmas, preprocess);
-}
-
-bool InferenceManager::hasLemmaCached(Node lem) const
-{
- return d_lemmas_produced.find(lem) != d_lemmas_produced.end();
-}
-
-bool InferenceManager::hasProcessed() const
-{
- return d_state.isInConflict() || d_sentLemma || d_addedFact;
}
-bool InferenceManager::hasSentLemma() const { return d_sentLemma; }
-bool InferenceManager::hasAddedFact() const { return d_addedFact; }
} // namespace sets
} // namespace theory
diff --git a/src/theory/sets/inference_manager.h b/src/theory/sets/inference_manager.h
index ba6be9905..c52fcf3d4 100644
--- a/src/theory/sets/inference_manager.h
+++ b/src/theory/sets/inference_manager.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -17,8 +17,8 @@
#ifndef CVC4__THEORY__SETS__INFERENCE_MANAGER_H
#define CVC4__THEORY__SETS__INFERENCE_MANAGER_H
+#include "theory/inference_manager_buffered.h"
#include "theory/sets/solver_state.h"
-#include "theory/uf/equality_engine.h"
namespace CVC4 {
namespace theory {
@@ -33,22 +33,12 @@ class TheorySetsPrivate;
* of theory of sets or internally as literals asserted to the equality engine
* of theory of sets. The latter literals are referred to as "facts".
*/
-class InferenceManager
+class InferenceManager : public InferenceManagerBuffered
{
typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
public:
- InferenceManager(TheorySetsPrivate& p,
- SolverState& s,
- context::Context* c,
- context::UserContext* u);
- /** reset
- *
- * Called at the beginning of a full effort check. Resets the information
- * related to this class regarding whether facts and lemmas have been
- * processed.
- */
- void reset();
+ InferenceManager(Theory& t, SolverState& s, ProofNodeManager* pnm);
/**
* Add facts corresponding to ( exp => fact ) via calls to the assertFact
* method of TheorySetsPrivate.
@@ -80,65 +70,23 @@ class InferenceManager
const char* c,
int inferType = 0);
- /** Flush lemmas
- *
- * This sends lemmas on the output channel of the theory of sets.
- *
- * The argument preprocess indicates whether preprocessing should be applied
- * (by TheoryEngine) on each of lemmas.
- */
- void flushLemmas(std::vector<Node>& lemmas, bool preprocess = false);
- /** singular version of above */
- void flushLemma(Node lem, bool preprocess = false);
- /** Do we have pending lemmas? */
- bool hasPendingLemmas() const { return !d_pendingLemmas.empty(); }
- /** Applies flushLemmas on d_pendingLemmas */
- void flushPendingLemmas(bool preprocess = false);
/** flush the splitting lemma ( n OR (NOT n) )
*
* If reqPol is not 0, then a phase requirement for n is requested with
* polarity ( reqPol>0 ).
*/
void split(Node n, int reqPol = 0);
- /** Have we sent a lemma during the current call to a full effort check? */
- bool hasSentLemma() const;
- /** Have we added a fact during the current call to a full effort check? */
- bool hasAddedFact() const;
- /** Have we processed an inference (fact, lemma, or conflict)? */
- bool hasProcessed() const;
- /** Have we sent lem as a lemma in the current user context? */
- bool hasLemmaCached(Node lem) const;
private:
/** constants */
Node d_true;
Node d_false;
- /** the theory of sets which owns this */
- TheorySetsPrivate& d_parent;
- /** Reference to the state object for the theory of sets */
- SolverState& d_state;
- /** pending lemmas */
- std::vector<Node> d_pendingLemmas;
- /** sent lemma
- *
- * This flag is set to true during a full effort check if this theory
- * called d_out->lemma(...).
- */
- bool d_sentLemma;
- /** added fact
- *
- * This flag is set to true during a full effort check if this theory
- * added an internal fact to its equality engine.
- */
- bool d_addedFact;
- /** A user-context-dependent cache of all lemmas produced */
- NodeSet d_lemmas_produced;
/**
- * A set of nodes to ref-count. Nodes that are facts or are explanations of
- * facts must be added to this set since the equality engine does not
- * ref count nodes.
+ * Reference to the state object for the theory of sets. We store the
+ * (derived) state here, since it has additional methods required in this
+ * class.
*/
- NodeSet d_keep;
+ SolverState& d_state;
/** Assert fact recursive
*
* This is a helper function for assertInference, which calls assertFact
diff --git a/src/theory/sets/kinds b/src/theory/sets/kinds
index 452acfea0..57120e42e 100644
--- a/src/theory/sets/kinds
+++ b/src/theory/sets/kinds
@@ -12,7 +12,7 @@ rewriter ::CVC4::theory::sets::TheorySetsRewriter \
"theory/sets/theory_sets_rewriter.h"
properties parametric
-properties check propagate presolve
+properties check presolve
# constants
constant EMPTYSET \
@@ -35,15 +35,23 @@ enumerator SET_TYPE \
"theory/sets/theory_sets_type_enumerator.h"
# operators
-operator UNION 2 "set union"
-operator INTERSECTION 2 "set intersection"
-operator SETMINUS 2 "set subtraction"
-operator SUBSET 2 "subset predicate; first parameter a subset of second"
-operator MEMBER 2 "set membership predicate; first parameter a member of second"
-operator SINGLETON 1 "the set of the single element given as a parameter"
-operator INSERT 2: "set obtained by inserting elements (first N-1 parameters) into a set (the last parameter)"
-operator CARD 1 "set cardinality operator"
-operator COMPLEMENT 1 "set COMPLEMENT (with respect to finite universe)"
+operator UNION 2 "set union"
+operator INTERSECTION 2 "set intersection"
+operator SETMINUS 2 "set subtraction"
+operator SUBSET 2 "subset predicate; first parameter a subset of second"
+operator MEMBER 2 "set membership predicate; first parameter a member of second"
+
+constant SINGLETON_OP \
+ ::CVC4::SingletonOp \
+ ::CVC4::SingletonOpHashFunction \
+ "theory/sets/singleton_op.h" \
+ "operator for singletons; payload is an instance of the CVC4::SingletonOp class"
+parameterized SINGLETON SINGLETON_OP 1 \
+"constructs a set of a single element. First parameter is a SingletonOp. Second is a term"
+
+operator INSERT 2: "set obtained by inserting elements (first N-1 parameters) into a set (the last parameter)"
+operator CARD 1 "set cardinality operator"
+operator COMPLEMENT 1 "set COMPLEMENT (with respect to finite universe)"
nullaryoperator UNIVERSE_SET "(finite) universe set, all set variables must be interpreted as subsets of it."
# A set comprehension is specified by:
@@ -67,6 +75,9 @@ operator COMPREHENSION 3 "set comprehension specified by a bound variable list,
# If the set has cardinality > 1, then (choose A) will deterministically return an element in A.
operator CHOOSE 1 "return an element in the set given as a parameter"
+# The operator is_singleton returns whether the given set is a singleton
+operator IS_SINGLETON 1 "return whether the given set is a singleton"
+
operator JOIN 2 "set join"
operator PRODUCT 2 "set cartesian product"
operator TRANSPOSE 1 "set transpose"
@@ -79,6 +90,7 @@ typerule INTERSECTION ::CVC4::theory::sets::SetsBinaryOperatorTypeRule
typerule SETMINUS ::CVC4::theory::sets::SetsBinaryOperatorTypeRule
typerule SUBSET ::CVC4::theory::sets::SubsetTypeRule
typerule MEMBER ::CVC4::theory::sets::MemberTypeRule
+typerule SINGLETON_OP "SimpleTypeRule<RBuiltinOperator>"
typerule SINGLETON ::CVC4::theory::sets::SingletonTypeRule
typerule EMPTYSET ::CVC4::theory::sets::EmptySetTypeRule
typerule INSERT ::CVC4::theory::sets::InsertTypeRule
@@ -87,6 +99,7 @@ typerule COMPLEMENT ::CVC4::theory::sets::ComplementTypeRule
typerule UNIVERSE_SET ::CVC4::theory::sets::UniverseSetTypeRule
typerule COMPREHENSION ::CVC4::theory::sets::ComprehensionTypeRule
typerule CHOOSE ::CVC4::theory::sets::ChooseTypeRule
+typerule IS_SINGLETON ::CVC4::theory::sets::IsSingletonTypeRule
typerule JOIN ::CVC4::theory::sets::RelBinaryOperatorTypeRule
typerule PRODUCT ::CVC4::theory::sets::RelBinaryOperatorTypeRule
@@ -96,19 +109,6 @@ typerule JOIN_IMAGE ::CVC4::theory::sets::JoinImageTypeRule
typerule IDEN ::CVC4::theory::sets::RelIdenTypeRule
construle UNION ::CVC4::theory::sets::SetsBinaryOperatorTypeRule
-construle INTERSECTION ::CVC4::theory::sets::SetsBinaryOperatorTypeRule
-construle SETMINUS ::CVC4::theory::sets::SetsBinaryOperatorTypeRule
construle SINGLETON ::CVC4::theory::sets::SingletonTypeRule
-construle INSERT ::CVC4::theory::sets::InsertTypeRule
-construle CARD ::CVC4::theory::sets::CardTypeRule
-construle COMPLEMENT ::CVC4::theory::sets::ComplementTypeRule
-construle CHOOSE ::CVC4::theory::sets::ChooseTypeRule
-
-construle JOIN ::CVC4::theory::sets::RelBinaryOperatorTypeRule
-construle PRODUCT ::CVC4::theory::sets::RelBinaryOperatorTypeRule
-construle TRANSPOSE ::CVC4::theory::sets::RelTransposeTypeRule
-construle TCLOSURE ::CVC4::theory::sets::RelTransClosureTypeRule
-construle JOIN_IMAGE ::CVC4::theory::sets::JoinImageTypeRule
-construle IDEN ::CVC4::theory::sets::RelIdenTypeRule
endtheory
diff --git a/src/theory/sets/normal_form.h b/src/theory/sets/normal_form.h
index 0607a0e6c..2654344f3 100644
--- a/src/theory/sets/normal_form.h
+++ b/src/theory/sets/normal_form.h
@@ -5,7 +5,7 @@
** Kshitij Bansal, Andrew Reynolds, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,6 +25,12 @@ namespace sets {
class NormalForm {
public:
+ /**
+ * Constructs a set of the form:
+ * (union (singleton c1) ... (union (singleton c_{n-1}) (singleton c_n))))
+ * from the set { c1 ... cn }, also handles empty set case, which is why
+ * setType is passed to this method.
+ */
template <bool ref_count>
static Node elementsToSet(const std::set<NodeTemplate<ref_count> >& elements,
TypeNode setType)
@@ -38,16 +44,27 @@ class NormalForm {
}
else
{
+ TypeNode elementType = setType.getSetElementType();
ElementsIterator it = elements.begin();
- Node cur = nm->mkNode(kind::SINGLETON, *it);
+ Node cur = nm->mkSingleton(elementType, *it);
while (++it != elements.end())
{
- cur = nm->mkNode(kind::UNION, cur, nm->mkNode(kind::SINGLETON, *it));
+ Node singleton = nm->mkSingleton(elementType, *it);
+ cur = nm->mkNode(kind::UNION, singleton, cur);
}
return cur;
}
}
+ /**
+ * Returns true if n is considered a to be a (canonical) constant set value.
+ * A canonical set value is one whose AST is:
+ * (union (singleton c1) ... (union (singleton c_{n-1}) (singleton c_n))))
+ * where c1 ... cn are constants and the node identifier of these constants
+ * are such that:
+ * c1 > ... > cn.
+ * Also handles the corner cases of empty set and singleton set.
+ */
static bool checkNormalConstant(TNode n) {
Debug("sets-checknormal") << "[sets-checknormal] checkNormal " << n << " :"
<< std::endl;
@@ -56,46 +73,62 @@ class NormalForm {
} else if (n.getKind() == kind::SINGLETON) {
return n[0].isConst();
} else if (n.getKind() == kind::UNION) {
- // assuming (union ... (union {SmallestNodeID} {BiggerNodeId}) ...
- // {BiggestNodeId})
-
- // store BiggestNodeId in prvs
- if (n[1].getKind() != kind::SINGLETON) return false;
- if (!n[1][0].isConst()) return false;
- Debug("sets-checknormal")
- << "[sets-checknormal] frst element = " << n[1][0] << " "
- << n[1][0].getId() << std::endl;
- TNode prvs = n[1][0];
- n = n[0];
+ // assuming (union {SmallestNodeID} ... (union {BiggerNodeId} ...
+ Node orig = n;
+ TNode prvs;
// check intermediate nodes
- while (n.getKind() == kind::UNION) {
- if (n[1].getKind() != kind::SINGLETON) return false;
- if (!n[1].isConst()) return false;
+ while (n.getKind() == kind::UNION)
+ {
+ if (n[0].getKind() != kind::SINGLETON || !n[0][0].isConst())
+ {
+ // not a constant
+ Trace("sets-isconst") << "sets::isConst: " << orig << " not due to "
+ << n[0] << std::endl;
+ return false;
+ }
Debug("sets-checknormal")
- << "[sets-checknormal] element = " << n[1][0] << " "
- << n[1][0].getId() << std::endl;
- if (n[1][0] >= prvs) return false;
- prvs = n[1][0];
- n = n[0];
+ << "[sets-checknormal] element = " << n[0][0] << " "
+ << n[0][0].getId() << std::endl;
+ if (!prvs.isNull() && n[0][0] >= prvs)
+ {
+ Trace("sets-isconst")
+ << "sets::isConst: " << orig << " not due to compare " << n[0][0]
+ << std::endl;
+ return false;
+ }
+ prvs = n[0][0];
+ n = n[1];
}
// check SmallestNodeID is smallest
- if (n.getKind() != kind::SINGLETON) return false;
- if (!n[0].isConst()) return false;
+ if (n.getKind() != kind::SINGLETON || !n[0].isConst())
+ {
+ Trace("sets-isconst") << "sets::isConst: " << orig
+ << " not due to final " << n << std::endl;
+ return false;
+ }
Debug("sets-checknormal")
<< "[sets-checknormal] lst element = " << n[0] << " "
<< n[0].getId() << std::endl;
- if (n[0] >= prvs) return false;
-
- // we made it
- return true;
-
- } else {
- return false;
+ // compare last ID
+ if (n[0] < prvs)
+ {
+ return true;
+ }
+ Trace("sets-isconst")
+ << "sets::isConst: " << orig << " not due to compare final " << n[0]
+ << std::endl;
}
+ return false;
}
+ /**
+ * Converts a set term to a std::set of its elements. This expects a set of
+ * the form:
+ * (union (singleton c1) ... (union (singleton c_{n-1}) (singleton c_n))))
+ * Also handles the corner cases of empty set and singleton set.
+ */
static std::set<Node> getElementsFromNormalConstant(TNode n) {
Assert(n.isConst());
std::set<Node> ret;
@@ -103,29 +136,15 @@ class NormalForm {
return ret;
}
while (n.getKind() == kind::UNION) {
- Assert(n[1].getKind() == kind::SINGLETON);
- ret.insert(ret.begin(), n[1][0]);
- n = n[0];
+ Assert(n[0].getKind() == kind::SINGLETON);
+ ret.insert(ret.begin(), n[0][0]);
+ n = n[1];
}
Assert(n.getKind() == kind::SINGLETON);
ret.insert(n[0]);
return ret;
}
-
- //AJR
-
- static void getElementsFromBop( Kind k, Node n, std::vector< Node >& els ){
- if( n.getKind()==k ){
- for( unsigned i=0; i<n.getNumChildren(); i++ ){
- getElementsFromBop( k, n[i], els );
- }
- }else{
- if( std::find( els.begin(), els.end(), n )==els.end() ){
- els.push_back( n );
- }
- }
- }
static Node mkBop( Kind k, std::vector< Node >& els, TypeNode tn, unsigned index = 0 ){
if( index>=els.size() ){
return NodeManager::currentNM()->mkConst(EmptySet(tn));
diff --git a/src/theory/sets/rels_utils.h b/src/theory/sets/rels_utils.h
index 007b7ce80..13ee672db 100644
--- a/src/theory/sets/rels_utils.h
+++ b/src/theory/sets/rels_utils.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/sets/singleton_op.cpp b/src/theory/sets/singleton_op.cpp
new file mode 100644
index 000000000..d7f318314
--- /dev/null
+++ b/src/theory/sets/singleton_op.cpp
@@ -0,0 +1,50 @@
+/********************* */
+/*! \file singleton_op.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief a class for singleton operator for sets
+ **/
+
+#include "singleton_op.h"
+
+#include <iostream>
+
+#include "expr/type_node.h"
+
+namespace CVC4 {
+
+std::ostream& operator<<(std::ostream& out, const SingletonOp& op)
+{
+ return out << "(singleton_op " << op.getType() << ')';
+}
+
+size_t SingletonOpHashFunction::operator()(const SingletonOp& op) const
+{
+ return TypeNodeHashFunction()(op.getType());
+}
+
+SingletonOp::SingletonOp(const TypeNode& elementType)
+ : d_type(new TypeNode(elementType))
+{
+}
+
+SingletonOp::SingletonOp(const SingletonOp& op)
+ : d_type(new TypeNode(op.getType()))
+{
+}
+
+const TypeNode& SingletonOp::getType() const { return *d_type; }
+
+bool SingletonOp::operator==(const SingletonOp& op) const
+{
+ return getType() == op.getType();
+}
+
+} // namespace CVC4
diff --git a/src/theory/sets/singleton_op.h b/src/theory/sets/singleton_op.h
new file mode 100644
index 000000000..57118999a
--- /dev/null
+++ b/src/theory/sets/singleton_op.h
@@ -0,0 +1,63 @@
+/********************* */
+/*! \file singleton_op.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief a class for singleton operator for sets
+ **/
+
+#include "cvc4_public.h"
+
+#ifndef CVC4__SINGLETON_OP_H
+#define CVC4__SINGLETON_OP_H
+
+#include <memory>
+
+namespace CVC4 {
+
+class TypeNode;
+
+/**
+ * The class is an operator for kind SINGLETON used to construct singleton sets.
+ * It specifies the type of the single element especially when it is a constant.
+ * e.g. the type of rational 1 is Int, however
+ * (singleton (singleton_op Real) 1) is of type (Set Real), not (Set Int).
+ * Note that the type passed to the constructor is the element's type, not the
+ * set type.
+ */
+class SingletonOp
+{
+ public:
+ SingletonOp(const TypeNode& elementType);
+ SingletonOp(const SingletonOp& op);
+
+ /** return the type of the current object */
+ const TypeNode& getType() const;
+
+ bool operator==(const SingletonOp& op) const;
+
+ private:
+ SingletonOp();
+ /** a pointer to the type of the singleton element */
+ std::unique_ptr<TypeNode> d_type;
+}; /* class Singleton */
+
+std::ostream& operator<<(std::ostream& out, const SingletonOp& op);
+
+/**
+ * Hash function for the SingletonHashFunction objects.
+ */
+struct CVC4_PUBLIC SingletonOpHashFunction
+{
+ size_t operator()(const SingletonOp& op) const;
+}; /* struct SingletonOpHashFunction */
+
+} // namespace CVC4
+
+#endif /* CVC4__SINGLETON_OP_H */
diff --git a/src/theory/sets/skolem_cache.cpp b/src/theory/sets/skolem_cache.cpp
index cf5e8835a..1f6160edc 100644
--- a/src/theory/sets/skolem_cache.cpp
+++ b/src/theory/sets/skolem_cache.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/sets/skolem_cache.h b/src/theory/sets/skolem_cache.h
index 1a8d09c1a..faa4d87bb 100644
--- a/src/theory/sets/skolem_cache.h
+++ b/src/theory/sets/skolem_cache.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/sets/solver_state.cpp b/src/theory/sets/solver_state.cpp
index d3c23454e..1d58945a5 100644
--- a/src/theory/sets/solver_state.cpp
+++ b/src/theory/sets/solver_state.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mudathir Mohamed
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,11 +25,11 @@ namespace CVC4 {
namespace theory {
namespace sets {
-SolverState::SolverState(TheorySetsPrivate& p,
- eq::EqualityEngine& e,
- context::Context* c,
- context::UserContext* u)
- : d_conflict(c), d_parent(p), d_ee(e), d_proxy(u), d_proxy_to_term(u)
+SolverState::SolverState(context::Context* c,
+ context::UserContext* u,
+ Valuation val,
+ SkolemCache& skc)
+ : TheoryState(c, u, val), d_skCache(skc), d_members(c)
{
d_true = NodeManager::currentNM()->mkConst(true);
d_false = NodeManager::currentNM()->mkConst(false);
@@ -69,8 +69,8 @@ void SolverState::registerTerm(Node r, TypeNode tnn, Node n)
{
if (r.isConst())
{
- Node s = d_ee.getRepresentative(n[1]);
- Node x = d_ee.getRepresentative(n[0]);
+ Node s = d_ee->getRepresentative(n[1]);
+ Node x = d_ee->getRepresentative(n[0]);
int pindex = r == d_true ? 0 : (r == d_false ? 1 : -1);
if (pindex != -1)
{
@@ -97,9 +97,7 @@ void SolverState::registerTerm(Node r, TypeNode tnn, Node n)
{
if (nk == SINGLETON)
{
- // singleton lemma
- getProxy(n);
- Node re = d_ee.getRepresentative(n[0]);
+ Node re = d_ee->getRepresentative(n[0]);
if (d_singleton_index.find(re) == d_singleton_index.end())
{
d_singleton_index[re] = n;
@@ -122,8 +120,8 @@ void SolverState::registerTerm(Node r, TypeNode tnn, Node n)
}
else
{
- Node r1 = d_ee.getRepresentative(n[0]);
- Node r2 = d_ee.getRepresentative(n[1]);
+ Node r1 = d_ee->getRepresentative(n[0]);
+ Node r2 = d_ee->getRepresentative(n[1]);
std::map<Node, Node>& binr1 = d_bop_index[nk][r1];
std::map<Node, Node>::iterator itb = binr1.find(r2);
if (itb == binr1.end())
@@ -164,39 +162,6 @@ void SolverState::registerTerm(Node r, TypeNode tnn, Node n)
}
}
-bool SolverState::areEqual(Node a, Node b) const
-{
- if (a == b)
- {
- return true;
- }
- if (d_ee.hasTerm(a) && d_ee.hasTerm(b))
- {
- return d_ee.areEqual(a, b);
- }
- return false;
-}
-
-bool SolverState::areDisequal(Node a, Node b) const
-{
- if (a == b)
- {
- return false;
- }
- else if (d_ee.hasTerm(a) && d_ee.hasTerm(b))
- {
- return d_ee.areDisequal(a, b, false);
- }
- return a.isConst() && b.isConst();
-}
-
-void SolverState::setConflict() { d_conflict = true; }
-void SolverState::setConflict(Node conf)
-{
- d_parent.getOutputChannel()->conflict(conf);
- d_conflict = true;
-}
-
void SolverState::addEqualityToExp(Node a, Node b, std::vector<Node>& exp) const
{
if (a != b)
@@ -218,8 +183,8 @@ Node SolverState::getEmptySetEqClass(TypeNode tn) const
Node SolverState::getUnivSetEqClass(TypeNode tn) const
{
- std::map<TypeNode, Node>::const_iterator it = d_univset.find(tn);
- if (it != d_univset.end())
+ std::map<TypeNode, Node>::const_iterator it = d_eqc_univset.find(tn);
+ if (it != d_eqc_univset.end())
{
return it->second;
}
@@ -279,10 +244,10 @@ bool SolverState::isEntailed(Node n, bool polarity) const
return true;
}
// check members cache
- if (polarity && d_ee.hasTerm(n[1]))
+ if (polarity && d_ee->hasTerm(n[1]))
{
- Node r = d_ee.getRepresentative(n[1]);
- if (d_parent.isMember(n[0], r))
+ Node r = d_ee->getRepresentative(n[1]);
+ if (isMember(n[0], r))
{
return true;
}
@@ -310,8 +275,8 @@ bool SolverState::isEntailed(Node n, bool polarity) const
bool SolverState::isSetDisequalityEntailed(Node r1, Node r2) const
{
- Assert(d_ee.hasTerm(r1) && d_ee.getRepresentative(r1) == r1);
- Assert(d_ee.hasTerm(r2) && d_ee.getRepresentative(r2) == r2);
+ Assert(d_ee->hasTerm(r1) && d_ee->getRepresentative(r1) == r1);
+ Assert(d_ee->hasTerm(r2) && d_ee->getRepresentative(r2) == r2);
TypeNode tn = r1.getType();
Node re = getEmptySetEqClass(tn);
for (unsigned e = 0; e < 2; e++)
@@ -400,40 +365,9 @@ bool SolverState::isSetDisequalityEntailedInternal(Node a,
return false;
}
-Node SolverState::getProxy(Node n)
-{
- Kind nk = n.getKind();
- if (nk != EMPTYSET && nk != SINGLETON && nk != INTERSECTION && nk != SETMINUS
- && nk != UNION && nk != UNIVERSE_SET)
- {
- return n;
- }
- NodeMap::const_iterator it = d_proxy.find(n);
- if (it != d_proxy.end())
- {
- return (*it).second;
- }
- NodeManager* nm = NodeManager::currentNM();
- Node k = d_skCache.mkTypedSkolemCached(
- n.getType(), n, SkolemCache::SK_PURIFY, "sp");
- d_proxy[n] = k;
- d_proxy_to_term[k] = n;
- Node eq = k.eqNode(n);
- Trace("sets-lemma") << "Sets::Lemma : " << eq << " by proxy" << std::endl;
- d_parent.getOutputChannel()->lemma(eq);
- if (nk == SINGLETON)
- {
- Node slem = nm->mkNode(MEMBER, n[0], k);
- Trace("sets-lemma") << "Sets::Lemma : " << slem << " by singleton"
- << std::endl;
- d_parent.getOutputChannel()->lemma(slem);
- }
- return k;
-}
-
Node SolverState::getCongruent(Node n) const
{
- Assert(d_ee.hasTerm(n));
+ Assert(d_ee->hasTerm(n));
std::map<Node, Node>::const_iterator it = d_congruent.find(n);
if (it == d_congruent.end())
{
@@ -445,65 +379,6 @@ bool SolverState::isCongruent(Node n) const
{
return d_congruent.find(n) != d_congruent.end();
}
-
-Node SolverState::getEmptySet(TypeNode tn)
-{
- std::map<TypeNode, Node>::iterator it = d_emptyset.find(tn);
- if (it != d_emptyset.end())
- {
- return it->second;
- }
- Node n = NodeManager::currentNM()->mkConst(EmptySet(tn));
- d_emptyset[tn] = n;
- return n;
-}
-Node SolverState::getUnivSet(TypeNode tn)
-{
- std::map<TypeNode, Node>::iterator it = d_univset.find(tn);
- if (it != d_univset.end())
- {
- return it->second;
- }
- NodeManager* nm = NodeManager::currentNM();
- Node n = nm->mkNullaryOperator(tn, UNIVERSE_SET);
- for (it = d_univset.begin(); it != d_univset.end(); ++it)
- {
- Node n1;
- Node n2;
- if (tn.isSubtypeOf(it->first))
- {
- n1 = n;
- n2 = it->second;
- }
- else if (it->first.isSubtypeOf(tn))
- {
- n1 = it->second;
- n2 = n;
- }
- if (!n1.isNull())
- {
- Node ulem = nm->mkNode(SUBSET, n1, n2);
- Trace("sets-lemma") << "Sets::Lemma : " << ulem << " by univ-type"
- << std::endl;
- d_parent.getOutputChannel()->lemma(ulem);
- }
- }
- d_univset[tn] = n;
- return n;
-}
-
-Node SolverState::getTypeConstraintSkolem(Node n, TypeNode tn)
-{
- std::map<TypeNode, Node>::iterator it = d_tc_skolem[n].find(tn);
- if (it == d_tc_skolem[n].end())
- {
- Node k = NodeManager::currentNM()->mkSkolem("tc_k", tn);
- d_tc_skolem[n][tn] = k;
- return k;
- }
- return it->second;
-}
-
const std::vector<Node>& SolverState::getNonVariableSets(Node r) const
{
std::map<Node, std::vector<Node> >::const_iterator it = d_nvar_sets.find(r);
@@ -569,6 +444,13 @@ SolverState::getBinaryOpIndex() const
{
return d_bop_index;
}
+
+const std::map<Node, std::map<Node, Node>>& SolverState::getBinaryOpIndex(
+ Kind k)
+{
+ return d_bop_index[k];
+}
+
const std::map<Kind, std::vector<Node> >& SolverState::getOperatorList() const
{
return d_op_list;
@@ -579,43 +461,136 @@ const std::vector<Node>& SolverState::getComprehensionSets() const
return d_allCompSets;
}
-void SolverState::debugPrintSet(Node s, const char* c) const
+const vector<Node> SolverState::getSetsEqClasses(const TypeNode& t) const
{
- if (s.getNumChildren() == 0)
+ vector<Node> representatives;
+ for (const Node& eqc : getSetsEqClasses())
{
- NodeMap::const_iterator it = d_proxy_to_term.find(s);
- if (it != d_proxy_to_term.end())
+ if (eqc.getType().getSetElementType() == t)
{
- debugPrintSet((*it).second, c);
+ representatives.push_back(eqc);
}
- else
+ }
+ return representatives;
+}
+
+bool SolverState::isMember(TNode x, TNode s) const
+{
+ Assert(hasTerm(s) && getRepresentative(s) == s);
+ NodeIntMap::const_iterator mem_i = d_members.find(s);
+ if (mem_i != d_members.end())
+ {
+ std::map<Node, std::vector<Node> >::const_iterator itd =
+ d_members_data.find(s);
+ Assert(itd != d_members_data.end());
+ const std::vector<Node>& members = itd->second;
+ Assert((*mem_i).second <= members.size());
+ for (size_t i = 0, nmem = (*mem_i).second; i < nmem; i++)
{
- Trace(c) << s;
+ if (areEqual(members[i][0], x))
+ {
+ return true;
+ }
}
}
+ return false;
+}
+
+void SolverState::addMember(TNode r, TNode atom)
+{
+ NodeIntMap::iterator mem_i = d_members.find(r);
+ size_t n_members = 0;
+ if (mem_i != d_members.end())
+ {
+ n_members = (*mem_i).second;
+ }
+ d_members[r] = n_members + 1;
+ if (n_members < d_members_data[r].size())
+ {
+ d_members_data[r][n_members] = atom;
+ }
else
{
- Trace(c) << "(" << s.getOperator();
- for (const Node& sc : s)
- {
- Trace(c) << " ";
- debugPrintSet(sc, c);
- }
- Trace(c) << ")";
+ d_members_data[r].push_back(atom);
}
}
-const vector<Node> SolverState::getSetsEqClasses(const TypeNode& t) const
+bool SolverState::merge(TNode t1,
+ TNode t2,
+ std::vector<Node>& facts,
+ TNode cset)
{
- vector<Node> representatives;
- for (const Node& eqc : getSetsEqClasses())
+ NodeIntMap::iterator mem_i2 = d_members.find(t2);
+ if (mem_i2 == d_members.end())
{
- if (eqc.getType().getSetElementType() == t)
+ // no members in t2, we are done
+ return true;
+ }
+ NodeIntMap::iterator mem_i1 = d_members.find(t1);
+ size_t n_members = 0;
+ if (mem_i1 != d_members.end())
+ {
+ n_members = (*mem_i1).second;
+ }
+ for (size_t i = 0, nmem2 = (*mem_i2).second; i < nmem2; i++)
+ {
+ Assert(i < d_members_data[t2].size()
+ && d_members_data[t2][i].getKind() == MEMBER);
+ Node m2 = d_members_data[t2][i];
+ // check if redundant
+ bool add = true;
+ for (size_t j = 0; j < n_members; j++)
{
- representatives.push_back(eqc);
+ Assert(j < d_members_data[t1].size()
+ && d_members_data[t1][j].getKind() == MEMBER);
+ if (areEqual(m2[0], d_members_data[t1][j][0]))
+ {
+ add = false;
+ break;
+ }
+ }
+ if (add)
+ {
+ // if there is a concrete set in t1, propagate new facts or conflicts
+ if (!cset.isNull())
+ {
+ NodeManager* nm = NodeManager::currentNM();
+ Assert(areEqual(m2[1], cset));
+ Node exp = nm->mkNode(AND, m2[1].eqNode(cset), m2);
+ if (cset.getKind() == SINGLETON)
+ {
+ if (cset[0] != m2[0])
+ {
+ Node eq = cset[0].eqNode(m2[0]);
+ Trace("sets-prop") << "Propagate eq-mem eq inference : " << exp
+ << " => " << eq << std::endl;
+ Node fact = nm->mkNode(IMPLIES, exp, eq);
+ facts.push_back(fact);
+ }
+ }
+ else
+ {
+ // conflict
+ Assert(facts.empty());
+ Trace("sets-prop")
+ << "Propagate eq-mem conflict : " << exp << std::endl;
+ facts.push_back(exp);
+ return false;
+ }
+ }
+ if (n_members < d_members_data[t1].size())
+ {
+ d_members_data[t1][n_members] = m2;
+ }
+ else
+ {
+ d_members_data[t1].push_back(m2);
+ }
+ n_members++;
}
}
- return representatives;
+ d_members[t1] = n_members;
+ return true;
}
} // namespace sets
diff --git a/src/theory/sets/solver_state.h b/src/theory/sets/solver_state.h
index 0b301dbb7..41d3ac717 100644
--- a/src/theory/sets/solver_state.h
+++ b/src/theory/sets/solver_state.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mudathir Mohamed
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,8 +20,8 @@
#include <map>
#include <vector>
-#include "context/cdhashset.h"
#include "theory/sets/skolem_cache.h"
+#include "theory/theory_state.h"
#include "theory/uf/equality_engine.h"
namespace CVC4 {
@@ -32,46 +32,31 @@ class TheorySetsPrivate;
/** Sets state
*
- * The purpose of this class is to:
- * (1) Maintain information concerning the current set of assertions during a
- * full effort check,
- * (2) Maintain a database of commonly used terms.
+ * The purpose of this class is to maintain information concerning the current
+ * set of assertions during a full effort check.
*
* During a full effort check, the solver for theory of sets should call:
* reset; ( registerEqc | registerTerm )*
* to initialize the information in this class regarding full effort checks.
* Other query calls are then valid for the remainder of the full effort check.
*/
-class SolverState
+class SolverState : public TheoryState
{
- typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeMap;
+ typedef context::CDHashMap<Node, size_t, NodeHashFunction> NodeIntMap;
public:
- SolverState(TheorySetsPrivate& p,
- eq::EqualityEngine& e,
- context::Context* c,
- context::UserContext* u);
- //-------------------------------- initialize
+ SolverState(context::Context* c,
+ context::UserContext* u,
+ Valuation val,
+ SkolemCache& skc);
+ //-------------------------------- initialize per check
/** reset, clears the data structures maintained by this class. */
void reset();
/** register equivalence class whose type is tn */
void registerEqc(TypeNode tn, Node r);
/** register term n of type tnn in the equivalence class of r */
void registerTerm(Node r, TypeNode tnn, Node n);
- //-------------------------------- end initialize
- /** Are we currently in conflict? */
- bool isInConflict() const { return d_conflict; }
- /**
- * Indicate that we are in conflict, without a conflict clause. This is
- * called, for instance, when we have propagated a conflicting literal.
- */
- void setConflict();
- /** Set conf is a conflict node to be sent on the output channel. */
- void setConflict(Node conf);
- /** Is a=b according to equality reasoning in the current context? */
- bool areEqual(Node a, Node b) const;
- /** Is a!=b according to equality reasoning in the current context? */
- bool areDisequal(Node a, Node b) const;
+ //-------------------------------- end initialize per check
/** add equality to explanation
*
* This adds a = b to exp if a and b are syntactically disequal. The equality
@@ -161,6 +146,13 @@ class SolverState
*/
const std::map<Kind, std::map<Node, std::map<Node, Node> > >&
getBinaryOpIndex() const;
+
+ /** Get binary operator index
+ *
+ * This returns the binary operator index of the given kind.
+ * See getBinaryOpIndex() above.
+ */
+ const std::map<Node, std::map<Node, Node> >& getBinaryOpIndex(Kind k);
/** get operator list
*
* This returns a mapping from set kinds to a list of terms of that kind
@@ -171,43 +163,29 @@ class SolverState
/** Get the list of all comprehension sets in the current context */
const std::vector<Node>& getComprehensionSets() const;
- // --------------------------------------- commonly used terms
- /** Get type constraint skolem
- *
- * The sets theory solver outputs equality lemmas of the form:
- * n = d_tc_skolem[n][tn]
- * where the type of d_tc_skolem[n][tn] is tn, and the type
- * of n is not a subtype of tn. This is required to handle benchmarks like
- * test/regress/regress0/sets/sets-of-sets-subtypes.smt2
- * where for s : (Set Int) and t : (Set Real), we have that
- * ( s = t ^ y in t ) implies ( exists k : Int. y = k )
- * The type constraint Skolem for (y, Int) is the skolemization of k above.
+ /**
+ * Is x entailed to be a member of set s in the current context?
*/
- Node getTypeConstraintSkolem(Node n, TypeNode tn);
- /** get the proxy variable for set n
- *
- * Proxy variables are used to communicate information that otherwise would
- * not be possible due to rewriting. For example, the literal
- * card( singleton( 0 ) ) = 1
- * is rewritten to true. Instead, to communicate this fact (e.g. to other
- * theories), we require introducing a proxy variable x for singleton( 0 ).
- * Then:
- * card( x ) = 1 ^ x = singleton( 0 )
- * communicates the equivalent of the above literal.
+ bool isMember(TNode x, TNode s) const;
+ /**
+ * Add member, called when atom is of the form (member x s) where s is in the
+ * equivalence class of r.
*/
- Node getProxy(Node n);
- /** Get the empty set of type tn */
- Node getEmptySet(TypeNode tn);
- /** Get the universe set of type tn if it exists or create a new one */
- Node getUnivSet(TypeNode tn);
+ void addMember(TNode r, TNode atom);
/**
- * Get the skolem cache of this theory, which manages a database of introduced
- * skolem variables used for various inferences.
+ * Called when equivalence classes t1 and t2 merge. This updates the
+ * membership lists, adding members of t2 into t1.
+ *
+ * If cset is non-null, then this is a singleton or empty set in the
+ * equivalence class of t1 where moreover t2 has no singleton or empty sets.
+ * When this is the case, notice that all members of t2 should be made equal
+ * to the element that cset contains, or we are in conflict if cset is the
+ * empty set. These conclusions are added to facts.
+ *
+ * This method returns false if a (single) conflict was added to facts, and
+ * true otherwise.
*/
- SkolemCache& getSkolemCache() { return d_skCache; }
- // --------------------------------------- end commonly used terms
- /** debug print set */
- void debugPrintSet(Node s, const char* c) const;
+ bool merge(TNode t1, TNode t2, std::vector<Node>& facts, TNode cset);
private:
/** constants */
@@ -216,12 +194,8 @@ class SolverState
/** the empty vector and map */
std::vector<Node> d_emptyVec;
std::map<Node, Node> d_emptyMap;
- /** Whether or not we are in conflict. This flag is SAT context dependent. */
- context::CDO<bool> d_conflict;
- /** Reference to the parent theory of sets */
- TheorySetsPrivate& d_parent;
- /** Reference to the equality engine of theory of sets */
- eq::EqualityEngine& d_ee;
+ /** Reference to skolem cache */
+ SkolemCache& d_skCache;
/** The list of all equivalence classes of type set in the current context */
std::vector<Node> d_set_eqc;
/** Maps types to the equivalence class containing empty set of that type */
@@ -245,18 +219,6 @@ class SolverState
* to their negative memberships.
*/
std::map<Node, std::map<Node, Node> > d_pol_mems[2];
- // --------------------------------------- commonly used terms
- /** Map from set terms to their proxy variables */
- NodeMap d_proxy;
- /** Backwards map of above */
- NodeMap d_proxy_to_term;
- /** Cache of type constraint skolems (see getTypeConstraintSkolem) */
- std::map<Node, std::map<TypeNode, Node> > d_tc_skolem;
- /** Map from types to empty set of that type */
- std::map<TypeNode, Node> d_emptyset;
- /** Map from types to universe set of that type */
- std::map<TypeNode, Node> d_univset;
- // --------------------------------------- end commonly used terms
// -------------------------------- term indices
/** Term index for MEMBER
*
@@ -276,9 +238,17 @@ class SolverState
/** A list of comprehension sets */
std::vector<Node> d_allCompSets;
// -------------------------------- end term indices
+ /** List of operators per kind */
std::map<Kind, std::vector<Node> > d_op_list;
- /** the skolem cache */
- SkolemCache d_skCache;
+ //--------------------------------- SAT-context-dependent member list
+ /**
+ * Map from representatives r of set equivalence classes to atoms of the form
+ * (member x s) where s is in the equivalence class of r.
+ */
+ std::map<Node, std::vector<Node> > d_members_data;
+ /** A (SAT-context-dependent) number of members in the above map */
+ NodeIntMap d_members;
+ //--------------------------------- end
/** is set disequality entailed internal
*
* This returns true if disequality between sets a and b is entailed in the
diff --git a/src/theory/sets/term_registry.cpp b/src/theory/sets/term_registry.cpp
new file mode 100644
index 000000000..1e780721d
--- /dev/null
+++ b/src/theory/sets/term_registry.cpp
@@ -0,0 +1,154 @@
+/********************* */
+/*! \file term_registry.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Mudathir Mohamed, Andres Noetzli
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of sets term registry object
+ **/
+
+#include "theory/sets/term_registry.h"
+
+#include "expr/emptyset.h"
+
+using namespace std;
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace sets {
+
+TermRegistry::TermRegistry(SolverState& state,
+ InferenceManager& im,
+ SkolemCache& skc)
+ : d_im(im),
+ d_skCache(skc),
+ d_proxy(state.getUserContext()),
+ d_proxy_to_term(state.getUserContext())
+{
+}
+
+Node TermRegistry::getProxy(Node n)
+{
+ Kind nk = n.getKind();
+ if (nk != EMPTYSET && nk != SINGLETON && nk != INTERSECTION && nk != SETMINUS
+ && nk != UNION && nk != UNIVERSE_SET)
+ {
+ return n;
+ }
+ NodeMap::const_iterator it = d_proxy.find(n);
+ if (it != d_proxy.end())
+ {
+ return (*it).second;
+ }
+ NodeManager* nm = NodeManager::currentNM();
+ Node k = d_skCache.mkTypedSkolemCached(
+ n.getType(), n, SkolemCache::SK_PURIFY, "sp");
+ d_proxy[n] = k;
+ d_proxy_to_term[k] = n;
+ Node eq = k.eqNode(n);
+ Trace("sets-lemma") << "Sets::Lemma : " << eq << " by proxy" << std::endl;
+ d_im.lemma(eq, LemmaProperty::NONE, false);
+ if (nk == SINGLETON)
+ {
+ Node slem = nm->mkNode(MEMBER, n[0], k);
+ Trace("sets-lemma") << "Sets::Lemma : " << slem << " by singleton"
+ << std::endl;
+ d_im.lemma(slem, LemmaProperty::NONE, false);
+ }
+ return k;
+}
+
+Node TermRegistry::getEmptySet(TypeNode tn)
+{
+ std::map<TypeNode, Node>::iterator it = d_emptyset.find(tn);
+ if (it != d_emptyset.end())
+ {
+ return it->second;
+ }
+ Node n = NodeManager::currentNM()->mkConst(EmptySet(tn));
+ d_emptyset[tn] = n;
+ return n;
+}
+
+Node TermRegistry::getUnivSet(TypeNode tn)
+{
+ std::map<TypeNode, Node>::iterator it = d_univset.find(tn);
+ if (it != d_univset.end())
+ {
+ return it->second;
+ }
+ NodeManager* nm = NodeManager::currentNM();
+ Node n = nm->mkNullaryOperator(tn, UNIVERSE_SET);
+ for (it = d_univset.begin(); it != d_univset.end(); ++it)
+ {
+ Node n1;
+ Node n2;
+ if (tn.isSubtypeOf(it->first))
+ {
+ n1 = n;
+ n2 = it->second;
+ }
+ else if (it->first.isSubtypeOf(tn))
+ {
+ n1 = it->second;
+ n2 = n;
+ }
+ if (!n1.isNull())
+ {
+ Node ulem = nm->mkNode(SUBSET, n1, n2);
+ Trace("sets-lemma") << "Sets::Lemma : " << ulem << " by univ-type"
+ << std::endl;
+ d_im.lemma(ulem, LemmaProperty::NONE, false);
+ }
+ }
+ d_univset[tn] = n;
+ return n;
+}
+
+Node TermRegistry::getTypeConstraintSkolem(Node n, TypeNode tn)
+{
+ std::map<TypeNode, Node>::iterator it = d_tc_skolem[n].find(tn);
+ if (it == d_tc_skolem[n].end())
+ {
+ Node k = NodeManager::currentNM()->mkSkolem("tc_k", tn);
+ d_tc_skolem[n][tn] = k;
+ return k;
+ }
+ return it->second;
+}
+
+void TermRegistry::debugPrintSet(Node s, const char* c) const
+{
+ if (s.getNumChildren() == 0)
+ {
+ NodeMap::const_iterator it = d_proxy_to_term.find(s);
+ if (it != d_proxy_to_term.end())
+ {
+ debugPrintSet((*it).second, c);
+ }
+ else
+ {
+ Trace(c) << s;
+ }
+ }
+ else
+ {
+ Trace(c) << "(" << s.getOperator();
+ for (const Node& sc : s)
+ {
+ Trace(c) << " ";
+ debugPrintSet(sc, c);
+ }
+ Trace(c) << ")";
+ }
+}
+
+} // namespace sets
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/sets/term_registry.h b/src/theory/sets/term_registry.h
new file mode 100644
index 000000000..e329ad8de
--- /dev/null
+++ b/src/theory/sets/term_registry.h
@@ -0,0 +1,94 @@
+/********************* */
+/*! \file term_registry.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Mudathir Mohamed
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Sets state object
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__SETS__TERM_REGISTRY_H
+#define CVC4__THEORY__SETS__TERM_REGISTRY_H
+
+#include <map>
+#include <vector>
+
+#include "context/cdhashmap.h"
+#include "theory/sets/inference_manager.h"
+#include "theory/sets/skolem_cache.h"
+#include "theory/sets/solver_state.h"
+
+namespace CVC4 {
+namespace theory {
+namespace sets {
+
+/**
+ * Term registry, the purpose of this class is to maintain a database of
+ * commonly used terms, and mappings from sets to their "proxy variables".
+ */
+class TermRegistry
+{
+ typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeMap;
+
+ public:
+ TermRegistry(SolverState& state, InferenceManager& im, SkolemCache& skc);
+ /** Get type constraint skolem
+ *
+ * The sets theory solver outputs equality lemmas of the form:
+ * n = d_tc_skolem[n][tn]
+ * where the type of d_tc_skolem[n][tn] is tn, and the type
+ * of n is not a subtype of tn. This is required to handle benchmarks like
+ * test/regress/regress0/sets/sets-of-sets-subtypes.smt2
+ * where for s : (Set Int) and t : (Set Real), we have that
+ * ( s = t ^ y in t ) implies ( exists k : Int. y = k )
+ * The type constraint Skolem for (y, Int) is the skolemization of k above.
+ */
+ Node getTypeConstraintSkolem(Node n, TypeNode tn);
+ /** get the proxy variable for set n
+ *
+ * Proxy variables are used to communicate information that otherwise would
+ * not be possible due to rewriting. For example, the literal
+ * card( singleton( 0 ) ) = 1
+ * is rewritten to true. Instead, to communicate this fact (e.g. to other
+ * theories), we require introducing a proxy variable x for singleton( 0 ).
+ * Then:
+ * card( x ) = 1 ^ x = singleton( 0 )
+ * communicates the equivalent of the above literal.
+ */
+ Node getProxy(Node n);
+ /** Get the empty set of type tn */
+ Node getEmptySet(TypeNode tn);
+ /** Get the universe set of type tn if it exists or create a new one */
+ Node getUnivSet(TypeNode tn);
+ /** debug print set */
+ void debugPrintSet(Node s, const char* c) const;
+
+ private:
+ /** The inference manager */
+ InferenceManager& d_im;
+ /** Reference to the skolem cache */
+ SkolemCache& d_skCache;
+ /** Map from set terms to their proxy variables */
+ NodeMap d_proxy;
+ /** Backwards map of above */
+ NodeMap d_proxy_to_term;
+ /** Cache of type constraint skolems (see getTypeConstraintSkolem) */
+ std::map<Node, std::map<TypeNode, Node> > d_tc_skolem;
+ /** Map from types to empty set of that type */
+ std::map<TypeNode, Node> d_emptyset;
+ /** Map from types to universe set of that type */
+ std::map<TypeNode, Node> d_univset;
+}; /* class TheorySetsPrivate */
+
+} // namespace sets
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__SETS__TERM_REGISTRY_H */
diff --git a/src/theory/sets/theory_sets.cpp b/src/theory/sets/theory_sets.cpp
index c4e3e9add..763024d5f 100644
--- a/src/theory/sets/theory_sets.cpp
+++ b/src/theory/sets/theory_sets.cpp
@@ -2,10 +2,10 @@
/*! \file theory_sets.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Kshitij Bansal, Andres Noetzli
+ ** Andrew Reynolds, Mudathir Mohamed, Kshitij Bansal
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -34,17 +34,19 @@ TheorySets::TheorySets(context::Context* c,
const LogicInfo& logicInfo,
ProofNodeManager* pnm)
: Theory(THEORY_SETS, c, u, out, valuation, logicInfo, pnm),
- d_internal(new TheorySetsPrivate(*this, c, u))
+ d_skCache(),
+ d_state(c, u, valuation, d_skCache),
+ d_im(*this, d_state, nullptr),
+ d_internal(new TheorySetsPrivate(*this, d_state, d_im, d_skCache)),
+ d_notify(*d_internal.get(), d_im)
{
- // Do not move me to the header.
- // The constructor + destructor are not in the header as d_internal is a
- // unique_ptr<TheorySetsPrivate> and TheorySetsPrivate is an opaque type in
- // the header (Pimpl). See https://herbsutter.com/gotw/_100/ .
+ // use the official theory state and inference manager objects
+ d_theoryState = &d_state;
+ d_inferManager = &d_im;
}
TheorySets::~TheorySets()
{
- // Do not move me to the header. See explanation in the constructor.
}
TheoryRewriter* TheorySets::getTheoryRewriter()
@@ -52,30 +54,57 @@ TheoryRewriter* TheorySets::getTheoryRewriter()
return d_internal->getTheoryRewriter();
}
-void TheorySets::finishInit()
+bool TheorySets::needsEqualityEngine(EeSetupInfo& esi)
{
- TheoryModel* tm = d_valuation.getModel();
- Assert(tm != nullptr);
- tm->setUnevaluatedKind(COMPREHENSION);
- // choice is used to eliminate witness
- tm->setUnevaluatedKind(WITNESS);
+ esi.d_notify = &d_notify;
+ esi.d_name = "theory::sets::ee";
+ return true;
}
-void TheorySets::addSharedTerm(TNode n) {
- d_internal->addSharedTerm(n);
-}
+void TheorySets::finishInit()
+{
+ Assert(d_equalityEngine != nullptr);
-void TheorySets::check(Effort e) {
- if (done() && e < Theory::EFFORT_FULL) {
- return;
- }
- TimerStat::CodeTimer checkTimer(d_checkTime);
- d_internal->check(e);
+ d_valuation.setUnevaluatedKind(COMPREHENSION);
+ // choice is used to eliminate witness
+ d_valuation.setUnevaluatedKind(WITNESS);
+
+ // functions we are doing congruence over
+ d_equalityEngine->addFunctionKind(SINGLETON);
+ d_equalityEngine->addFunctionKind(UNION);
+ d_equalityEngine->addFunctionKind(INTERSECTION);
+ d_equalityEngine->addFunctionKind(SETMINUS);
+ d_equalityEngine->addFunctionKind(MEMBER);
+ d_equalityEngine->addFunctionKind(SUBSET);
+ // relation operators
+ d_equalityEngine->addFunctionKind(PRODUCT);
+ d_equalityEngine->addFunctionKind(JOIN);
+ d_equalityEngine->addFunctionKind(TRANSPOSE);
+ d_equalityEngine->addFunctionKind(TCLOSURE);
+ d_equalityEngine->addFunctionKind(JOIN_IMAGE);
+ d_equalityEngine->addFunctionKind(IDEN);
+ d_equalityEngine->addFunctionKind(APPLY_CONSTRUCTOR);
+ // we do congruence over cardinality
+ d_equalityEngine->addFunctionKind(CARD);
+
+ // finish initialization internally
+ d_internal->finishInit();
+}
+
+void TheorySets::postCheck(Effort level) { d_internal->postCheck(level); }
+
+void TheorySets::notifyFact(TNode atom,
+ bool polarity,
+ TNode fact,
+ bool isInternal)
+{
+ d_internal->notifyFact(atom, polarity, fact);
}
-bool TheorySets::collectModelInfo(TheoryModel* m)
+bool TheorySets::collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet)
{
- return d_internal->collectModelInfo(m);
+ return d_internal->collectModelValues(m, termSet);
}
void TheorySets::computeCareGraph() {
@@ -88,15 +117,12 @@ TrustNode TheorySets::explain(TNode node)
return TrustNode::mkTrustPropExp(node, exp, nullptr);
}
-EqualityStatus TheorySets::getEqualityStatus(TNode a, TNode b) {
- return d_internal->getEqualityStatus(a, b);
-}
-
Node TheorySets::getModelValue(TNode node) {
return Node::null();
}
-void TheorySets::preRegisterTerm(TNode node) {
+void TheorySets::preRegisterTerm(TNode node)
+{
d_internal->preRegisterTerm(node);
}
@@ -127,12 +153,15 @@ TrustNode TheorySets::expandDefinition(Node n)
return d_internal->expandDefinition(n);
}
-Theory::PPAssertStatus TheorySets::ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
+Theory::PPAssertStatus TheorySets::ppAssert(
+ TrustNode tin, TrustSubstitutionMap& outSubstitutions)
+{
+ TNode in = tin.getNode();
Debug("sets-proc") << "ppAssert : " << in << std::endl;
Theory::PPAssertStatus status = Theory::PP_ASSERT_STATUS_UNSOLVED;
// this is based off of Theory::ppAssert
- if (in.getKind() == kind::EQUAL)
+ if (in.getKind() == EQUAL)
{
if (in[0].isVar() && isLegalElimination(in[0], in[1]))
{
@@ -142,7 +171,7 @@ Theory::PPAssertStatus TheorySets::ppAssert(TNode in, SubstitutionMap& outSubsti
// regress0/sets/pre-proc-univ.smt2
if (!in[0].getType().isSet() || !options::setsExt())
{
- outSubstitutions.addSubstitution(in[0], in[1]);
+ outSubstitutions.addSubstitutionSolved(in[0], in[1], tin);
status = Theory::PP_ASSERT_STATUS_SOLVED;
}
}
@@ -150,7 +179,7 @@ Theory::PPAssertStatus TheorySets::ppAssert(TNode in, SubstitutionMap& outSubsti
{
if (!in[0].getType().isSet() || !options::setsExt())
{
- outSubstitutions.addSubstitution(in[1], in[0]);
+ outSubstitutions.addSubstitutionSolved(in[1], in[0], tin);
status = Theory::PP_ASSERT_STATUS_SOLVED;
}
}
@@ -169,16 +198,32 @@ void TheorySets::presolve() {
d_internal->presolve();
}
-void TheorySets::propagate(Effort e) {
- d_internal->propagate(e);
+bool TheorySets::isEntailed( Node n, bool pol ) {
+ return d_internal->isEntailed( n, pol );
}
-void TheorySets::setMasterEqualityEngine(eq::EqualityEngine* eq) {
- d_internal->setMasterEqualityEngine(eq);
+/**************************** eq::NotifyClass *****************************/
+
+void TheorySets::NotifyClass::eqNotifyNewClass(TNode t)
+{
+ Debug("sets-eq") << "[sets-eq] eqNotifyNewClass:"
+ << " t = " << t << std::endl;
+ d_theory.eqNotifyNewClass(t);
}
-bool TheorySets::isEntailed( Node n, bool pol ) {
- return d_internal->isEntailed( n, pol );
+void TheorySets::NotifyClass::eqNotifyMerge(TNode t1, TNode t2)
+{
+ Debug("sets-eq") << "[sets-eq] eqNotifyMerge:"
+ << " t1 = " << t1 << " t2 = " << t2 << std::endl;
+ d_theory.eqNotifyMerge(t1, t2);
+}
+
+void TheorySets::NotifyClass::eqNotifyDisequal(TNode t1, TNode t2, TNode reason)
+{
+ Debug("sets-eq") << "[sets-eq] eqNotifyDisequal:"
+ << " t1 = " << t1 << " t2 = " << t2 << " reason = " << reason
+ << std::endl;
+ d_theory.eqNotifyDisequal(t1, t2, reason);
}
}/* CVC4::theory::sets namespace */
diff --git a/src/theory/sets/theory_sets.h b/src/theory/sets/theory_sets.h
index e81412ba9..a5f8fa4d8 100644
--- a/src/theory/sets/theory_sets.h
+++ b/src/theory/sets/theory_sets.h
@@ -2,10 +2,10 @@
/*! \file theory_sets.h
** \verbatim
** Top contributors (to current version):
- ** Tim King, Kshitij Bansal, Andrew Reynolds
+ ** Andrew Reynolds, Tim King, Kshitij Bansal
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,7 +21,11 @@
#include <memory>
+#include "theory/sets/inference_manager.h"
+#include "theory/sets/skolem_cache.h"
+#include "theory/sets/solver_state.h"
#include "theory/theory.h"
+#include "theory/theory_eq_notify.h"
#include "theory/uf/equality_engine.h"
namespace CVC4 {
@@ -33,6 +37,8 @@ class TheorySetsScrutinize;
class TheorySets : public Theory
{
+ friend class TheorySetsPrivate;
+ friend class TheorySetsRels;
public:
/** Constructs a new instance of TheorySets w.r.t. the provided contexts. */
TheorySets(context::Context* c,
@@ -43,32 +49,65 @@ class TheorySets : public Theory
ProofNodeManager* pnm);
~TheorySets() override;
+ //--------------------------------- initialization
+ /** get the official theory rewriter of this theory */
TheoryRewriter* getTheoryRewriter() override;
-
+ /**
+ * Returns true if we need an equality engine. If so, we initialize the
+ * information regarding how it should be setup. For details, see the
+ * documentation in Theory::needsEqualityEngine.
+ */
+ bool needsEqualityEngine(EeSetupInfo& esi) override;
/** finish initialization */
void finishInit() override;
- void addSharedTerm(TNode) override;
- void check(Effort) override;
- bool collectModelInfo(TheoryModel* m) override;
+ //--------------------------------- end initialization
+
+ //--------------------------------- standard check
+ /** Post-check, called after the fact queue of the theory is processed. */
+ void postCheck(Effort level) override;
+ /** Notify fact */
+ void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal) override;
+ //--------------------------------- end standard check
+ /** Collect model values in m based on the relevant terms given by termSet */
+ bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet) override;
void computeCareGraph() override;
TrustNode explain(TNode) override;
- EqualityStatus getEqualityStatus(TNode a, TNode b) override;
Node getModelValue(TNode) override;
std::string identify() const override { return "THEORY_SETS"; }
void preRegisterTerm(TNode node) override;
TrustNode expandDefinition(Node n) override;
- PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions) override;
+ PPAssertStatus ppAssert(TrustNode tin,
+ TrustSubstitutionMap& outSubstitutions) override;
void presolve() override;
- void propagate(Effort) override;
- void setMasterEqualityEngine(eq::EqualityEngine* eq) override;
bool isEntailed(Node n, bool pol);
private:
- friend class TheorySetsPrivate;
- friend class TheorySetsScrutinize;
- friend class TheorySetsRels;
-
+ /** Functions to handle callbacks from equality engine */
+ class NotifyClass : public TheoryEqNotifyClass
+ {
+ public:
+ NotifyClass(TheorySetsPrivate& theory, TheoryInferenceManager& im)
+ : TheoryEqNotifyClass(im), d_theory(theory)
+ {
+ }
+ void eqNotifyNewClass(TNode t) override;
+ void eqNotifyMerge(TNode t1, TNode t2) override;
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override;
+
+ private:
+ TheorySetsPrivate& d_theory;
+ };
+ /** The skolem cache */
+ SkolemCache d_skCache;
+ /** The state of the sets solver at full effort */
+ SolverState d_state;
+ /** The inference manager */
+ InferenceManager d_im;
+ /** The internal theory */
std::unique_ptr<TheorySetsPrivate> d_internal;
+ /** Instance of the above class */
+ NotifyClass d_notify;
}; /* class TheorySets */
}/* CVC4::theory::sets namespace */
diff --git a/src/theory/sets/theory_sets_private.cpp b/src/theory/sets/theory_sets_private.cpp
index 0ee623255..d435c641c 100644
--- a/src/theory/sets/theory_sets_private.cpp
+++ b/src/theory/sets/theory_sets_private.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mudathir Mohamed, Kshitij Bansal
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -35,35 +35,25 @@ namespace theory {
namespace sets {
TheorySetsPrivate::TheorySetsPrivate(TheorySets& external,
- context::Context* c,
- context::UserContext* u)
- : d_members(c),
- d_deq(c),
- d_termProcessed(u),
- d_keep(c),
+ SolverState& state,
+ InferenceManager& im,
+ SkolemCache& skc)
+ : d_deq(state.getSatContext()),
+ d_termProcessed(state.getUserContext()),
d_full_check_incomplete(false),
d_external(external),
- d_notify(*this),
- d_equalityEngine(d_notify, c, "theory::sets::ee", true),
- d_state(*this, d_equalityEngine, c, u),
- d_im(*this, d_state, c, u),
- d_rels(new TheorySetsRels(d_state, d_im, d_equalityEngine, u)),
- d_cardSolver(
- new CardinalityExtension(d_state, d_im, d_equalityEngine, c, u)),
+ d_state(state),
+ d_im(im),
+ d_skCache(skc),
+ d_treg(state, im, skc),
+ d_rels(new TheorySetsRels(state, im, skc, d_treg)),
+ d_cardSolver(new CardinalityExtension(state, im, d_treg)),
d_rels_enabled(false),
d_card_enabled(false)
{
d_true = NodeManager::currentNM()->mkConst(true);
d_false = NodeManager::currentNM()->mkConst(false);
d_zero = NodeManager::currentNM()->mkConst(Rational(0));
-
- d_equalityEngine.addFunctionKind(kind::SINGLETON);
- d_equalityEngine.addFunctionKind(kind::UNION);
- d_equalityEngine.addFunctionKind(kind::INTERSECTION);
- d_equalityEngine.addFunctionKind(kind::SETMINUS);
-
- d_equalityEngine.addFunctionKind(kind::MEMBER);
- d_equalityEngine.addFunctionKind(kind::SUBSET);
}
TheorySetsPrivate::~TheorySetsPrivate()
@@ -74,6 +64,12 @@ TheorySetsPrivate::~TheorySetsPrivate()
}
}
+void TheorySetsPrivate::finishInit()
+{
+ d_equalityEngine = d_external.getEqualityEngine();
+ Assert(d_equalityEngine != nullptr);
+}
+
void TheorySetsPrivate::eqNotifyNewClass(TNode t)
{
if (t.getKind() == kind::SINGLETON || t.getKind() == kind::EMPTYSET)
@@ -83,9 +79,7 @@ void TheorySetsPrivate::eqNotifyNewClass(TNode t)
}
}
-void TheorySetsPrivate::eqNotifyPreMerge(TNode t1, TNode t2) {}
-
-void TheorySetsPrivate::eqNotifyPostMerge(TNode t1, TNode t2)
+void TheorySetsPrivate::eqNotifyMerge(TNode t1, TNode t2)
{
if (!d_state.isInConflict())
{
@@ -110,16 +104,14 @@ void TheorySetsPrivate::eqNotifyPostMerge(TNode t1, TNode t2)
// infer equality between elements of singleton
Node exp = s1.eqNode(s2);
Node eq = s1[0].eqNode(s2[0]);
- d_keep.insert(exp);
- d_keep.insert(eq);
- assertFact(eq, exp);
+ d_im.assertInternalFact(eq, true, exp);
}
else
{
// singleton equal to emptyset, conflict
Trace("sets-prop")
<< "Propagate conflict : " << s1 << " == " << s2 << std::endl;
- conflict(s1, s2);
+ d_im.conflictEqConstantMerge(s1, s2);
return;
}
}
@@ -133,73 +125,27 @@ void TheorySetsPrivate::eqNotifyPostMerge(TNode t1, TNode t2)
}
// merge membership list
Trace("sets-prop-debug") << "Copying membership list..." << std::endl;
- NodeIntMap::iterator mem_i2 = d_members.find(t2);
- if (mem_i2 != d_members.end())
+ // if s1 has a singleton or empty set and s2 does not, we may have new
+ // inferences to process.
+ Node checkSingleton = s2.isNull() ? s1 : Node::null();
+ std::vector<Node> facts;
+ // merge the membership list in the state, which may produce facts or
+ // conflicts to propagate
+ if (!d_state.merge(t1, t2, facts, checkSingleton))
{
- NodeIntMap::iterator mem_i1 = d_members.find(t1);
- int n_members = 0;
- if (mem_i1 != d_members.end())
- {
- n_members = (*mem_i1).second;
- }
- for (int i = 0; i < (*mem_i2).second; i++)
- {
- Assert(i < (int)d_members_data[t2].size()
- && d_members_data[t2][i].getKind() == kind::MEMBER);
- Node m2 = d_members_data[t2][i];
- // check if redundant
- bool add = true;
- for (int j = 0; j < n_members; j++)
- {
- Assert(j < (int)d_members_data[t1].size()
- && d_members_data[t1][j].getKind() == kind::MEMBER);
- if (d_state.areEqual(m2[0], d_members_data[t1][j][0]))
- {
- add = false;
- break;
- }
- }
- if (add)
- {
- if (!s1.isNull() && s2.isNull())
- {
- Assert(m2[1].getType().isComparableTo(s1.getType()));
- Assert(d_state.areEqual(m2[1], s1));
- Node exp = NodeManager::currentNM()->mkNode(
- kind::AND, m2[1].eqNode(s1), m2);
- if (s1.getKind() == kind::SINGLETON)
- {
- if (s1[0] != m2[0])
- {
- Node eq = s1[0].eqNode(m2[0]);
- d_keep.insert(exp);
- d_keep.insert(eq);
- Trace("sets-prop") << "Propagate eq-mem eq inference : " << exp
- << " => " << eq << std::endl;
- assertFact(eq, exp);
- }
- }
- else
- {
- // conflict
- Trace("sets-prop")
- << "Propagate eq-mem conflict : " << exp << std::endl;
- d_state.setConflict(exp);
- return;
- }
- }
- if (n_members < (int)d_members_data[t1].size())
- {
- d_members_data[t1][n_members] = m2;
- }
- else
- {
- d_members_data[t1].push_back(m2);
- }
- n_members++;
- }
- }
- d_members[t1] = n_members;
+ // conflict case
+ Assert(facts.size() == 1);
+ Trace("sets-prop") << "Propagate eq-mem conflict : " << facts[0]
+ << std::endl;
+ d_im.conflict(facts[0]);
+ return;
+ }
+ for (const Node& f : facts)
+ {
+ Assert(f.getKind() == kind::IMPLIES);
+ Trace("sets-prop") << "Propagate eq-mem eq inference : " << f[0] << " => "
+ << f[1] << std::endl;
+ d_im.assertInternalFact(f[1], true, f[0]);
}
}
}
@@ -240,13 +186,13 @@ TheorySetsPrivate::EqcInfo* TheorySetsPrivate::getOrMakeEqcInfo(TNode n,
bool TheorySetsPrivate::areCareDisequal(Node a, Node b)
{
- if (d_equalityEngine.isTriggerTerm(a, THEORY_SETS)
- && d_equalityEngine.isTriggerTerm(b, THEORY_SETS))
+ if (d_equalityEngine->isTriggerTerm(a, THEORY_SETS)
+ && d_equalityEngine->isTriggerTerm(b, THEORY_SETS))
{
TNode a_shared =
- d_equalityEngine.getTriggerTermRepresentative(a, THEORY_SETS);
+ d_equalityEngine->getTriggerTermRepresentative(a, THEORY_SETS);
TNode b_shared =
- d_equalityEngine.getTriggerTermRepresentative(b, THEORY_SETS);
+ d_equalityEngine->getTriggerTermRepresentative(b, THEORY_SETS);
EqualityStatus eqStatus =
d_external.d_valuation.getEqualityStatus(a_shared, b_shared);
if (eqStatus == EQUALITY_FALSE_AND_PROPAGATED || eqStatus == EQUALITY_FALSE
@@ -258,103 +204,9 @@ bool TheorySetsPrivate::areCareDisequal(Node a, Node b)
return false;
}
-bool TheorySetsPrivate::isMember(Node x, Node s)
-{
- Assert(d_equalityEngine.hasTerm(s)
- && d_equalityEngine.getRepresentative(s) == s);
- NodeIntMap::iterator mem_i = d_members.find(s);
- if (mem_i != d_members.end())
- {
- for (int i = 0; i < (*mem_i).second; i++)
- {
- if (d_state.areEqual(d_members_data[s][i][0], x))
- {
- return true;
- }
- }
- }
- return false;
-}
-
-bool TheorySetsPrivate::assertFact(Node fact, Node exp)
-{
- Trace("sets-assert") << "TheorySets::assertFact : " << fact
- << ", exp = " << exp << std::endl;
- bool polarity = fact.getKind() != kind::NOT;
- TNode atom = polarity ? fact : fact[0];
- if (!d_state.isEntailed(atom, polarity))
- {
- if (atom.getKind() == kind::EQUAL)
- {
- d_equalityEngine.assertEquality(atom, polarity, exp);
- }
- else
- {
- d_equalityEngine.assertPredicate(atom, polarity, exp);
- }
- if (!d_state.isInConflict())
- {
- if (atom.getKind() == kind::MEMBER && polarity)
- {
- // check if set has a value, if so, we can propagate
- Node r = d_equalityEngine.getRepresentative(atom[1]);
- EqcInfo* e = getOrMakeEqcInfo(r, true);
- if (e)
- {
- Node s = e->d_singleton;
- if (!s.isNull())
- {
- Node pexp = NodeManager::currentNM()->mkNode(
- kind::AND, atom, atom[1].eqNode(s));
- d_keep.insert(pexp);
- if (s.getKind() == kind::SINGLETON)
- {
- if (s[0] != atom[0])
- {
- Trace("sets-prop")
- << "Propagate mem-eq : " << pexp << std::endl;
- Node eq = s[0].eqNode(atom[0]);
- d_keep.insert(eq);
- assertFact(eq, pexp);
- }
- }
- else
- {
- Trace("sets-prop")
- << "Propagate mem-eq conflict : " << pexp << std::endl;
- d_state.setConflict(pexp);
- }
- }
- }
- // add to membership list
- NodeIntMap::iterator mem_i = d_members.find(r);
- int n_members = 0;
- if (mem_i != d_members.end())
- {
- n_members = (*mem_i).second;
- }
- d_members[r] = n_members + 1;
- if (n_members < (int)d_members_data[r].size())
- {
- d_members_data[r][n_members] = atom;
- }
- else
- {
- d_members_data[r].push_back(atom);
- }
- }
- }
- return true;
- }
- else
- {
- return false;
- }
-}
-
void TheorySetsPrivate::fullEffortReset()
{
- Assert(d_equalityEngine.consistent());
+ Assert(d_equalityEngine->consistent());
d_full_check_incomplete = false;
d_most_common_type.clear();
d_most_common_type_term.clear();
@@ -364,6 +216,7 @@ void TheorySetsPrivate::fullEffortReset()
d_state.reset();
// reset the inference manager
d_im.reset();
+ d_im.clearPendingLemmas();
// reset the cardinality solver
d_cardSolver->reset();
}
@@ -373,14 +226,14 @@ void TheorySetsPrivate::fullEffortCheck()
Trace("sets") << "----- Full effort check ------" << std::endl;
do
{
- Assert(!d_im.hasPendingLemmas() || d_im.hasProcessed());
+ Assert(!d_im.hasPendingLemma() || d_im.hasSent());
Trace("sets") << "...iterate full effort check..." << std::endl;
fullEffortReset();
Trace("sets-eqc") << "Equality Engine:" << std::endl;
std::map<TypeNode, unsigned> eqcTypeCount;
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(&d_equalityEngine);
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(d_equalityEngine);
while (!eqcs_i.isFinished())
{
Node eqc = (*eqcs_i);
@@ -398,13 +251,13 @@ void TheorySetsPrivate::fullEffortCheck()
tnct = eqc;
}
Trace("sets-eqc") << "[" << eqc << "] : ";
- eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, &d_equalityEngine);
+ eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, d_equalityEngine);
while (!eqc_i.isFinished())
{
Node n = (*eqc_i);
if (n != eqc)
{
- Trace("sets-eqc") << n << " ";
+ Trace("sets-eqc") << n << " (" << n.isConst() << ") ";
}
TypeNode tnn = n.getType();
if (isSet)
@@ -421,15 +274,21 @@ void TheorySetsPrivate::fullEffortCheck()
}
// register it with the state
d_state.registerTerm(eqc, tnn, n);
- if (n.getKind() == kind::CARD)
+ Kind nk = n.getKind();
+ if (nk == kind::SINGLETON)
+ {
+ // ensure the proxy has been introduced
+ d_treg.getProxy(n);
+ }
+ else if (nk == kind::CARD)
{
d_card_enabled = true;
// register it with the cardinality solver
d_cardSolver->registerTerm(n);
// if we do not handle the kind, set incomplete
- Kind nk = n[0].getKind();
+ Kind nk0 = n[0].getKind();
// some kinds of cardinality we cannot handle
- if (d_rels->isRelationKind(nk))
+ if (d_rels->isRelationKind(nk0))
{
d_full_check_incomplete = true;
Trace("sets-incomplete")
@@ -445,12 +304,9 @@ void TheorySetsPrivate::fullEffortCheck()
// 4- Supporting cardinality for relations (hard)
}
}
- else
+ else if (d_rels->isRelationKind(nk))
{
- if (d_rels->isRelationKind(n.getKind()))
- {
- d_rels_enabled = true;
- }
+ d_rels_enabled = true;
}
++eqc_i;
}
@@ -478,7 +334,7 @@ void TheorySetsPrivate::fullEffortCheck()
// We may have sent lemmas while registering the terms in the loop above,
// e.g. the cardinality solver.
- if (d_im.hasProcessed())
+ if (d_im.hasSent())
{
continue;
}
@@ -505,38 +361,37 @@ void TheorySetsPrivate::fullEffortCheck()
Trace("sets-mem") << std::endl;
}
}
- // check subtypes
- checkSubtypes();
- d_im.flushPendingLemmas(true);
- if (d_im.hasProcessed())
+ d_im.doPendingLemmas();
+ if (d_im.hasSent())
{
continue;
}
// check downwards closure
checkDownwardsClosure();
- d_im.flushPendingLemmas();
- if (d_im.hasProcessed())
+ d_im.doPendingLemmas();
+ if (d_im.hasSent())
{
continue;
}
// check upwards closure
checkUpwardsClosure();
- d_im.flushPendingLemmas();
- if (d_im.hasProcessed())
+ d_im.doPendingLemmas();
+ if (d_im.hasSent())
{
continue;
}
// check disequalities
checkDisequalities();
- d_im.flushPendingLemmas();
- if (d_im.hasProcessed())
+ d_im.doPendingLemmas();
+ if (d_im.hasSent())
{
continue;
}
// check reduce comprehensions
checkReduceComprehensions();
- d_im.flushPendingLemmas();
- if (d_im.hasProcessed())
+
+ d_im.doPendingLemmas();
+ if (d_im.hasSent())
{
continue;
}
@@ -544,7 +399,7 @@ void TheorySetsPrivate::fullEffortCheck()
{
// call the check method of the cardinality solver
d_cardSolver->check();
- if (d_im.hasProcessed())
+ if (d_im.hasSent())
{
continue;
}
@@ -555,56 +410,13 @@ void TheorySetsPrivate::fullEffortCheck()
d_rels->check(Theory::EFFORT_FULL);
}
} while (!d_im.hasSentLemma() && !d_state.isInConflict()
- && d_im.hasAddedFact());
- Assert(!d_im.hasPendingLemmas() || d_im.hasProcessed());
+ && d_im.hasSentFact());
+ Assert(!d_im.hasPendingLemma() || d_im.hasSent());
Trace("sets") << "----- End full effort check, conflict="
<< d_state.isInConflict() << ", lemma=" << d_im.hasSentLemma()
<< std::endl;
}
-void TheorySetsPrivate::checkSubtypes()
-{
- Trace("sets") << "TheorySetsPrivate: check Subtypes..." << std::endl;
- const std::vector<Node>& sec = d_state.getSetsEqClasses();
- for (const Node& s : sec)
- {
- TypeNode mct = d_most_common_type[s];
- Assert(!mct.isNull());
- const std::map<Node, Node>& smems = d_state.getMembers(s);
- if (!smems.empty())
- {
- for (const std::pair<const Node, Node>& it2 : smems)
- {
- Trace("sets") << " check subtype " << it2.first << " " << it2.second
- << std::endl;
- Trace("sets") << " types : " << it2.first.getType() << " " << mct
- << std::endl;
- if (!it2.first.getType().isSubtypeOf(mct))
- {
- Node mctt = d_most_common_type_term[s];
- Assert(!mctt.isNull());
- Trace("sets") << " most common type term is " << mctt << std::endl;
- std::vector<Node> exp;
- exp.push_back(it2.second);
- Assert(d_state.areEqual(mctt, it2.second[1]));
- exp.push_back(mctt.eqNode(it2.second[1]));
- Node tc_k = d_state.getTypeConstraintSkolem(it2.first, mct);
- if (!tc_k.isNull())
- {
- Node etc = tc_k.eqNode(it2.first);
- d_im.assertInference(etc, exp, "subtype-clash");
- if (d_state.isInConflict())
- {
- return;
- }
- }
- }
- }
- }
- }
- Trace("sets") << "TheorySetsPrivate: finished." << std::endl;
-}
-
void TheorySetsPrivate::checkDownwardsClosure()
{
Trace("sets") << "TheorySetsPrivate: check downwards closure..." << std::endl;
@@ -624,7 +436,7 @@ void TheorySetsPrivate::checkDownwardsClosure()
{
Node mem = it2.second;
Node eq_set = nv;
- Assert(d_equalityEngine.areEqual(mem[1], eq_set));
+ Assert(d_equalityEngine->areEqual(mem[1], eq_set));
if (mem[1] != eq_set)
{
Trace("sets-debug") << "Downwards closure based on " << mem
@@ -646,7 +458,7 @@ void TheorySetsPrivate::checkDownwardsClosure()
else
{
// use proxy set
- Node k = d_state.getProxy(eq_set);
+ Node k = d_treg.getProxy(eq_set);
Node pmem =
NodeManager::currentNM()->mkNode(kind::MEMBER, mem[0], k);
Node nmem = NodeManager::currentNM()->mkNode(
@@ -761,10 +573,10 @@ void TheorySetsPrivate::checkUpwardsClosure()
}
if (valid)
{
- Node rr = d_equalityEngine.getRepresentative(term);
- if (!isMember(x, rr))
+ Node rr = d_equalityEngine->getRepresentative(term);
+ if (!d_state.isMember(x, rr))
{
- Node kk = d_state.getProxy(term);
+ Node kk = d_treg.getProxy(term);
Node fact = nm->mkNode(kind::MEMBER, x, kk);
d_im.assertInference(fact, exp, "upc", inferType);
if (d_state.isInConflict())
@@ -785,13 +597,13 @@ void TheorySetsPrivate::checkUpwardsClosure()
for (const std::pair<const Node, Node>& itm2m : r2mem)
{
Node x = itm2m.second[0];
- Node rr = d_equalityEngine.getRepresentative(term);
- if (!isMember(x, rr))
+ Node rr = d_equalityEngine->getRepresentative(term);
+ if (!d_state.isMember(x, rr))
{
std::vector<Node> exp;
exp.push_back(itm2m.second);
d_state.addEqualityToExp(term[1], itm2m.second[1], exp);
- Node r = d_state.getProxy(term);
+ Node r = d_treg.getProxy(term);
Node fact = nm->mkNode(kind::MEMBER, x, r);
d_im.assertInference(fact, exp, "upc2");
if (d_state.isInConflict())
@@ -807,7 +619,7 @@ void TheorySetsPrivate::checkUpwardsClosure()
}
}
}
- if (!d_im.hasProcessed())
+ if (!d_im.hasSent())
{
if (options::setsExt())
{
@@ -837,7 +649,7 @@ void TheorySetsPrivate::checkUpwardsClosure()
// equivalence class
if (s != ueqc)
{
- u = d_state.getUnivSet(tn);
+ u = d_treg.getUnivSet(tn);
}
univ_set[tn] = u;
}
@@ -882,10 +694,10 @@ void TheorySetsPrivate::checkDisequalities()
}
Node deq = (*it).first;
// check if it is already satisfied
- Assert(d_equalityEngine.hasTerm(deq[0])
- && d_equalityEngine.hasTerm(deq[1]));
- Node r1 = d_equalityEngine.getRepresentative(deq[0]);
- Node r2 = d_equalityEngine.getRepresentative(deq[1]);
+ Assert(d_equalityEngine->hasTerm(deq[0])
+ && d_equalityEngine->hasTerm(deq[1]));
+ Node r1 = d_equalityEngine->getRepresentative(deq[0]);
+ Node r2 = d_equalityEngine->getRepresentative(deq[1]);
bool is_sat = d_state.isSetDisequalityEntailed(r1, r2);
Trace("sets-debug") << "Check disequality " << deq
<< ", is_sat = " << is_sat << std::endl;
@@ -906,15 +718,15 @@ void TheorySetsPrivate::checkDisequalities()
d_termProcessed.insert(deq[1].eqNode(deq[0]));
Trace("sets") << "Process Disequality : " << deq.negate() << std::endl;
TypeNode elementType = deq[0].getType().getSetElementType();
- Node x = d_state.getSkolemCache().mkTypedSkolemCached(
+ Node x = d_skCache.mkTypedSkolemCached(
elementType, deq[0], deq[1], SkolemCache::SK_DISEQUAL, "sde");
Node mem1 = nm->mkNode(MEMBER, x, deq[0]);
Node mem2 = nm->mkNode(MEMBER, x, deq[1]);
Node lem = nm->mkNode(OR, deq, nm->mkNode(EQUAL, mem1, mem2).negate());
lem = Rewriter::rewrite(lem);
d_im.assertInference(lem, d_true, "diseq", 1);
- d_im.flushPendingLemmas();
- if (d_im.hasProcessed())
+ d_im.doPendingLemmas();
+ if (d_im.hasSent())
{
return;
}
@@ -952,30 +764,14 @@ void TheorySetsPrivate::checkReduceComprehensions()
nm->mkNode(FORALL, nm->mkNode(BOUND_VAR_LIST, v), body.eqNode(mem));
Trace("sets-comprehension")
<< "Comprehension reduction: " << lem << std::endl;
- d_im.flushLemma(lem);
+ d_im.lemma(lem);
}
}
-/**************************** TheorySetsPrivate *****************************/
-/**************************** TheorySetsPrivate *****************************/
-/**************************** TheorySetsPrivate *****************************/
+//--------------------------------- standard check
-void TheorySetsPrivate::check(Theory::Effort level)
+void TheorySetsPrivate::postCheck(Theory::Effort level)
{
- Trace("sets-check") << "Sets check effort " << level << std::endl;
- if (level == Theory::EFFORT_LAST_CALL)
- {
- return;
- }
- while (!d_external.done() && !d_state.isInConflict())
- {
- // Get all the assertions
- Assertion assertion = d_external.get();
- TNode fact = assertion.d_assertion;
- Trace("sets-assert") << "Assert from input " << fact << std::endl;
- // assert the fact
- assertFact(fact, fact);
- }
Trace("sets-check") << "Sets finished assertions effort " << level
<< std::endl;
// invoke full effort check, relations check
@@ -989,25 +785,60 @@ void TheorySetsPrivate::check(Theory::Effort level)
if (!d_state.isInConflict() && !d_im.hasSentLemma()
&& d_full_check_incomplete)
{
- d_external.d_out->setIncomplete();
+ d_im.setIncomplete();
}
}
}
}
Trace("sets-check") << "Sets finish Check effort " << level << std::endl;
-} /* TheorySetsPrivate::check() */
+}
+
+void TheorySetsPrivate::notifyFact(TNode atom, bool polarity, TNode fact)
+{
+ if (d_state.isInConflict())
+ {
+ return;
+ }
+ if (atom.getKind() == kind::MEMBER && polarity)
+ {
+ // check if set has a value, if so, we can propagate
+ Node r = d_equalityEngine->getRepresentative(atom[1]);
+ EqcInfo* e = getOrMakeEqcInfo(r, true);
+ if (e)
+ {
+ Node s = e->d_singleton;
+ if (!s.isNull())
+ {
+ Node pexp = NodeManager::currentNM()->mkNode(
+ kind::AND, atom, atom[1].eqNode(s));
+ if (s.getKind() == kind::SINGLETON)
+ {
+ if (s[0] != atom[0])
+ {
+ Trace("sets-prop") << "Propagate mem-eq : " << pexp << std::endl;
+ Node eq = s[0].eqNode(atom[0]);
+ // triggers an internal inference
+ d_im.assertInternalFact(eq, true, pexp);
+ }
+ }
+ else
+ {
+ Trace("sets-prop")
+ << "Propagate mem-eq conflict : " << pexp << std::endl;
+ d_im.conflict(pexp);
+ }
+ }
+ }
+ // add to membership list
+ d_state.addMember(r, atom);
+ }
+}
+//--------------------------------- end standard check
/************************ Sharing ************************/
/************************ Sharing ************************/
/************************ Sharing ************************/
-void TheorySetsPrivate::addSharedTerm(TNode n)
-{
- Debug("sets") << "[sets] TheorySetsPrivate::addSharedTerm( " << n << ")"
- << std::endl;
- d_equalityEngine.addTriggerTerm(n, THEORY_SETS);
-}
-
void TheorySetsPrivate::addCarePairs(TNodeTrie* t1,
TNodeTrie* t2,
unsigned arity,
@@ -1020,7 +851,17 @@ void TheorySetsPrivate::addCarePairs(TNodeTrie* t1,
{
Node f1 = t1->getData();
Node f2 = t2->getData();
- if (!d_state.areEqual(f1, f2))
+
+ // Usually when (= (f x) (f y)), we don't care whether (= x y) is true or
+ // not for the shared variables x, y in the care graph.
+ // However, this does not apply to the membership operator since the
+ // equality or disequality between members affects the number of elements
+ // in a set. Therefore we need to split on (= x y) for kind MEMBER.
+ // Example:
+ // Suppose (= (member x S) member( y, S)) is true and there are
+ // no other members in S. We would get S = {x} if (= x y) is true.
+ // Otherwise we would get S = {x, y}.
+ if (f1.getKind() == MEMBER || !d_state.areEqual(f1, f2))
{
Trace("sets-cg") << "Check " << f1 << " and " << f2 << std::endl;
vector<pair<TNode, TNode> > currentPairs;
@@ -1028,21 +869,21 @@ void TheorySetsPrivate::addCarePairs(TNodeTrie* t1,
{
TNode x = f1[k];
TNode y = f2[k];
- Assert(d_equalityEngine.hasTerm(x));
- Assert(d_equalityEngine.hasTerm(y));
+ Assert(d_equalityEngine->hasTerm(x));
+ Assert(d_equalityEngine->hasTerm(y));
Assert(!d_state.areDisequal(x, y));
Assert(!areCareDisequal(x, y));
- if (!d_equalityEngine.areEqual(x, y))
+ if (!d_equalityEngine->areEqual(x, y))
{
Trace("sets-cg")
<< "Arg #" << k << " is " << x << " " << y << std::endl;
- if (d_equalityEngine.isTriggerTerm(x, THEORY_SETS)
- && d_equalityEngine.isTriggerTerm(y, THEORY_SETS))
+ if (d_equalityEngine->isTriggerTerm(x, THEORY_SETS)
+ && d_equalityEngine->isTriggerTerm(y, THEORY_SETS))
{
- TNode x_shared =
- d_equalityEngine.getTriggerTermRepresentative(x, THEORY_SETS);
- TNode y_shared =
- d_equalityEngine.getTriggerTermRepresentative(y, THEORY_SETS);
+ TNode x_shared = d_equalityEngine->getTriggerTermRepresentative(
+ x, THEORY_SETS);
+ TNode y_shared = d_equalityEngine->getTriggerTermRepresentative(
+ y, THEORY_SETS);
currentPairs.push_back(make_pair(x_shared, y_shared));
}
else if (isCareArg(f1, k) && isCareArg(f2, k))
@@ -1092,7 +933,7 @@ void TheorySetsPrivate::addCarePairs(TNodeTrie* t1,
++it2;
for (; it2 != t1->d_data.end(); ++it2)
{
- if (!d_equalityEngine.areDisequal(it->first, it2->first, false))
+ if (!d_equalityEngine->areDisequal(it->first, it2->first, false))
{
if (!areCareDisequal(it->first, it2->first))
{
@@ -1110,7 +951,7 @@ void TheorySetsPrivate::addCarePairs(TNodeTrie* t1,
{
for (std::pair<const TNode, TNodeTrie>& tt2 : t2->d_data)
{
- if (!d_equalityEngine.areDisequal(tt1.first, tt2.first, false))
+ if (!d_equalityEngine->areDisequal(tt1.first, tt2.first, false))
{
if (!areCareDisequal(tt1.first, tt2.first))
{
@@ -1140,9 +981,9 @@ void TheorySetsPrivate::computeCareGraph()
// populate indices
for (TNode f1 : it.second)
{
- Assert(d_equalityEngine.hasTerm(f1));
+ Assert(d_equalityEngine->hasTerm(f1));
Trace("sets-cg-debug") << "...build for " << f1 << std::endl;
- Assert(d_equalityEngine.hasTerm(f1));
+ Assert(d_equalityEngine->hasTerm(f1));
// break into index based on operator, and type of first argument (since
// some operators are parametric)
TypeNode tn = f1[0].getType();
@@ -1150,7 +991,7 @@ void TheorySetsPrivate::computeCareGraph()
bool hasCareArg = false;
for (unsigned j = 0; j < f1.getNumChildren(); j++)
{
- reps.push_back(d_equalityEngine.getRepresentative(f1[j]));
+ reps.push_back(d_equalityEngine->getRepresentative(f1[j]));
if (isCareArg(f1, j))
{
hasCareArg = true;
@@ -1184,7 +1025,7 @@ void TheorySetsPrivate::computeCareGraph()
bool TheorySetsPrivate::isCareArg(Node n, unsigned a)
{
- if (d_equalityEngine.isTriggerTerm(n[a], THEORY_SETS))
+ if (d_equalityEngine->isTriggerTerm(n[a], THEORY_SETS))
{
return true;
}
@@ -1199,37 +1040,6 @@ bool TheorySetsPrivate::isCareArg(Node n, unsigned a)
}
}
-EqualityStatus TheorySetsPrivate::getEqualityStatus(TNode a, TNode b)
-{
- Assert(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;
- /*
- Node aModelValue = d_external.d_valuation.getModelValue(a);
- if(aModelValue.isNull()) { return EQUALITY_UNKNOWN; }
- Node bModelValue = d_external.d_valuation.getModelValue(b);
- if(bModelValue.isNull()) { return EQUALITY_UNKNOWN; }
- if( aModelValue == bModelValue ) {
- // The term are true in current model
- return EQUALITY_TRUE_IN_MODEL;
- } else {
- return EQUALITY_FALSE_IN_MODEL;
- }
- */
- // }
- // //TODO: can we be more precise sometimes?
- // return EQUALITY_UNKNOWN;
-}
-
/******************** Model generation ********************/
/******************** Model generation ********************/
/******************** Model generation ********************/
@@ -1264,18 +1074,10 @@ std::string traceElements(const Node& set)
} // namespace
-bool TheorySetsPrivate::collectModelInfo(TheoryModel* m)
+bool TheorySetsPrivate::collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet)
{
- Trace("sets-model") << "Set collect model info" << std::endl;
- set<Node> termSet;
- // Compute terms appearing in assertions and shared terms
- d_external.computeRelevantTerms(termSet);
-
- // Assert equalities and disequalities to the model
- if (!m->assertEqualityEngine(&d_equalityEngine, &termSet))
- {
- return false;
- }
+ Trace("sets-model") << "Set collect model values" << std::endl;
NodeManager* nm = NodeManager::currentNM();
std::map<Node, Node> mvals;
@@ -1307,9 +1109,13 @@ bool TheorySetsPrivate::collectModelInfo(TheoryModel* m)
const std::map<Node, Node>& emems = d_state.getMembers(eqc);
if (!emems.empty())
{
+ TypeNode elementType = eqc.getType().getSetElementType();
for (const std::pair<const Node, Node>& itmm : emems)
{
- Node t = nm->mkNode(kind::SINGLETON, itmm.first);
+ Trace("sets-model")
+ << "m->getRepresentative(" << itmm.first
+ << ")= " << m->getRepresentative(itmm.first) << std::endl;
+ Node t = nm->mkSingleton(elementType, itmm.first);
els.push_back(t);
}
}
@@ -1320,6 +1126,7 @@ bool TheorySetsPrivate::collectModelInfo(TheoryModel* m)
// cardinality
d_cardSolver->mkModelValueElementsFor(val, eqc, els, mvals, m);
}
+
Node rep = NormalForm::mkBop(kind::UNION, els, eqc.getType());
rep = Rewriter::rewrite(rep);
Trace("sets-model") << "* Assign representative of " << eqc << " to "
@@ -1331,6 +1138,21 @@ bool TheorySetsPrivate::collectModelInfo(TheoryModel* m)
}
m->assertSkeleton(rep);
+ // we add the element terms (singletons) as representatives to tell the
+ // model builder to evaluate them along with their union (rep).
+ // This is needed to account for cases when members and rep are not enough
+ // for the model builder to evaluate set terms.
+ // e.g.
+ // eqc(rep) = [(union (singleton skolem) (singleton 0))]
+ // eqc(skolem) = [0]
+ // The model builder would fail to evaluate rep as (singleton 0)
+ // if (singleton skolem) is not registered as a representative in the
+ // model
+ for (const Node& el : els)
+ {
+ m->assertSkeleton(el);
+ }
+
Trace("sets-model") << "Set " << eqc << " = { " << traceElements(rep)
<< " }" << std::endl;
}
@@ -1399,51 +1221,8 @@ Node mkAnd(const std::vector<TNode>& conjunctions)
return conjunction;
} /* mkAnd() */
-void TheorySetsPrivate::propagate(Theory::Effort effort) {}
-
-bool TheorySetsPrivate::propagate(TNode literal)
-{
- Debug("sets-prop") << " propagate(" << literal << ")" << std::endl;
-
- // If already in conflict, no more propagation
- if (d_state.isInConflict())
- {
- Debug("sets-prop") << "TheoryUF::propagate(" << literal
- << "): already in conflict" << std::endl;
- return false;
- }
-
- // Propagate out
- bool ok = d_external.d_out->propagate(literal);
- if (!ok)
- {
- d_state.setConflict();
- }
-
- return ok;
-} /* TheorySetsPrivate::propagate(TNode) */
-
-OutputChannel* TheorySetsPrivate::getOutputChannel()
-{
- return d_external.d_out;
-}
-
Valuation& TheorySetsPrivate::getValuation() { return d_external.d_valuation; }
-void TheorySetsPrivate::setMasterEqualityEngine(eq::EqualityEngine* eq)
-{
- d_equalityEngine.setMasterEqualityEngine(eq);
-}
-
-void TheorySetsPrivate::conflict(TNode a, TNode b)
-{
- Node conf = explain(a.eqNode(b));
- d_state.setConflict(conf);
- Debug("sets") << "[sets] conflict: " << a << " iff " << b << ", explanation "
- << conf << std::endl;
- Trace("sets-lemma") << "Equality Conflict : " << conf << std::endl;
-}
-
Node TheorySetsPrivate::explain(TNode literal)
{
Debug("sets") << "TheorySetsPrivate::explain(" << literal << ")" << std::endl;
@@ -1454,11 +1233,11 @@ Node TheorySetsPrivate::explain(TNode literal)
if (atom.getKind() == kind::EQUAL)
{
- d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions);
+ d_equalityEngine->explainEquality(atom[0], atom[1], polarity, assumptions);
}
else if (atom.getKind() == kind::MEMBER)
{
- d_equalityEngine.explainPredicate(atom, polarity, assumptions);
+ d_equalityEngine->explainPredicate(atom, polarity, assumptions);
}
else
{
@@ -1476,10 +1255,14 @@ void TheorySetsPrivate::preRegisterTerm(TNode node)
<< std::endl;
switch (node.getKind())
{
- case kind::EQUAL: d_equalityEngine.addTriggerEquality(node); break;
- case kind::MEMBER: d_equalityEngine.addTriggerPredicate(node); break;
- case kind::CARD: d_equalityEngine.addTriggerTerm(node, THEORY_SETS); break;
- default: d_equalityEngine.addTerm(node); break;
+ case kind::EQUAL:
+ case kind::MEMBER:
+ {
+ // add trigger predicate for equality and membership
+ d_equalityEngine->addTriggerPredicate(node);
+ }
+ break;
+ default: d_equalityEngine->addTerm(node); break;
}
}
@@ -1487,143 +1270,110 @@ TrustNode TheorySetsPrivate::expandDefinition(Node node)
{
Debug("sets-proc") << "expandDefinition : " << node << std::endl;
- if (node.getKind() == kind::CHOOSE)
+ switch (node.getKind())
{
- // (choose A) is expanded as
- // (witness ((x elementType))
- // (ite
- // (= A (as emptyset setType))
- // (= x chooseUf(A))
- // (and (member x A) (= x chooseUf(A)))
-
- NodeManager* nm = NodeManager::currentNM();
- Node set = node[0];
- TypeNode setType = set.getType();
- Node chooseSkolem = getChooseFunction(setType);
- Node apply = NodeManager::currentNM()->mkNode(APPLY_UF, chooseSkolem, set);
-
- Node witnessVariable = nm->mkBoundVar(setType.getSetElementType());
-
- Node equal = witnessVariable.eqNode(apply);
- Node emptySet = nm->mkConst(EmptySet(setType));
- Node isEmpty = set.eqNode(emptySet);
- Node member = nm->mkNode(MEMBER, witnessVariable, set);
- Node memberAndEqual = member.andNode(equal);
- Node ite = nm->mkNode(kind::ITE, isEmpty, equal, memberAndEqual);
- Node witnessVariables = nm->mkNode(BOUND_VAR_LIST, witnessVariable);
- Node witness = nm->mkNode(WITNESS, witnessVariables, ite);
- return TrustNode::mkTrustRewrite(node, witness, nullptr);
+ case kind::CHOOSE: return expandChooseOperator(node);
+ case kind::IS_SINGLETON: return expandIsSingletonOperator(node);
+ default: return TrustNode::null();
}
-
- return TrustNode::null();
}
-Node TheorySetsPrivate::getChooseFunction(const TypeNode& setType)
+TrustNode TheorySetsPrivate::expandChooseOperator(const Node& node)
{
- std::map<TypeNode, Node>::iterator it = d_chooseFunctions.find(setType);
- if (it != d_chooseFunctions.end())
+ Assert(node.getKind() == CHOOSE);
+
+ // we call the rewriter here to handle the pattern (choose (singleton x))
+ // because the rewriter is called after expansion
+ Node rewritten = Rewriter::rewrite(node);
+ if (rewritten.getKind() != CHOOSE)
{
- return it->second;
+ return TrustNode::mkTrustRewrite(node, rewritten, nullptr);
}
+ // (choose A) is expanded as
+ // (witness ((x elementType))
+ // (ite
+ // (= A (as emptyset setType))
+ // (= x chooseUf(A))
+ // (and (member x A) (= x chooseUf(A)))
+
NodeManager* nm = NodeManager::currentNM();
- TypeNode chooseUf = nm->mkFunctionType(setType, setType.getSetElementType());
- stringstream stream;
- stream << "chooseUf" << setType.getId();
- string name = stream.str();
- Node chooseSkolem = nm->mkSkolem(
- name, chooseUf, "choose function", NodeManager::SKOLEM_EXACT_NAME);
- d_chooseFunctions[setType] = chooseSkolem;
- return chooseSkolem;
+ Node set = rewritten[0];
+ TypeNode setType = set.getType();
+ Node chooseSkolem = getChooseFunction(setType);
+ Node apply = NodeManager::currentNM()->mkNode(APPLY_UF, chooseSkolem, set);
+
+ Node witnessVariable = nm->mkBoundVar(setType.getSetElementType());
+
+ Node equal = witnessVariable.eqNode(apply);
+ Node emptySet = nm->mkConst(EmptySet(setType));
+ Node isEmpty = set.eqNode(emptySet);
+ Node member = nm->mkNode(MEMBER, witnessVariable, set);
+ Node memberAndEqual = member.andNode(equal);
+ Node ite = nm->mkNode(ITE, isEmpty, equal, memberAndEqual);
+ Node witnessVariables = nm->mkNode(BOUND_VAR_LIST, witnessVariable);
+ Node witness = nm->mkNode(WITNESS, witnessVariables, ite);
+ return TrustNode::mkTrustRewrite(node, witness, nullptr);
}
-void TheorySetsPrivate::presolve() { d_state.reset(); }
-
-/**************************** eq::NotifyClass *****************************/
-/**************************** eq::NotifyClass *****************************/
-/**************************** eq::NotifyClass *****************************/
-
-bool TheorySetsPrivate::NotifyClass::eqNotifyTriggerEquality(TNode equality,
- bool value)
+TrustNode TheorySetsPrivate::expandIsSingletonOperator(const Node& node)
{
- Debug("sets-eq") << "[sets-eq] eqNotifyTriggerEquality: equality = "
- << equality << " value = " << value << std::endl;
- if (value)
- {
- return d_theory.propagate(equality);
- }
- else
- {
- // We use only literal triggers so taking not is safe
- return d_theory.propagate(equality.notNode());
- }
-}
+ Assert(node.getKind() == IS_SINGLETON);
-bool TheorySetsPrivate::NotifyClass::eqNotifyTriggerPredicate(TNode predicate,
- bool value)
-{
- Debug("sets-eq") << "[sets-eq] eqNotifyTriggerPredicate: predicate = "
- << predicate << " value = " << value << std::endl;
- if (value)
+ // we call the rewriter here to handle the pattern
+ // (is_singleton (singleton x)) because the rewriter is called after expansion
+ Node rewritten = Rewriter::rewrite(node);
+ if (rewritten.getKind() != IS_SINGLETON)
{
- return d_theory.propagate(predicate);
+ return TrustNode::mkTrustRewrite(node, rewritten, nullptr);
}
- else
+
+ // (is_singleton A) is expanded as
+ // (exists ((x: T)) (= A (singleton x)))
+ // where T is the sort of elements of A
+
+ NodeManager* nm = NodeManager::currentNM();
+ Node set = rewritten[0];
+
+ std::map<Node, Node>::iterator it = d_isSingletonNodes.find(rewritten);
+
+ if (it != d_isSingletonNodes.end())
{
- return d_theory.propagate(predicate.notNode());
+ return TrustNode::mkTrustRewrite(rewritten, it->second, nullptr);
}
-}
-bool TheorySetsPrivate::NotifyClass::eqNotifyTriggerTermEquality(TheoryId tag,
- TNode t1,
- TNode t2,
- bool value)
-{
- Debug("sets-eq") << "[sets-eq] eqNotifyTriggerTermEquality: tag = " << tag
- << " t1 = " << t1 << " t2 = " << t2 << " value = " << value
- << std::endl;
- d_theory.propagate(value ? t1.eqNode(t2) : t1.eqNode(t2).negate());
- return true;
-}
+ TypeNode setType = set.getType();
+ Node boundVar = nm->mkBoundVar(setType.getSetElementType());
+ Node singleton = nm->mkSingleton(setType.getSetElementType(), boundVar);
+ Node equal = set.eqNode(singleton);
+ std::vector<Node> variables = {boundVar};
+ Node boundVars = nm->mkNode(BOUND_VAR_LIST, variables);
+ Node exists = nm->mkNode(kind::EXISTS, boundVars, equal);
+ d_isSingletonNodes[rewritten] = exists;
-void TheorySetsPrivate::NotifyClass::eqNotifyConstantTermMerge(TNode t1,
- TNode t2)
-{
- Debug("sets-eq") << "[sets-eq] eqNotifyConstantTermMerge "
- << " t1 = " << t1 << " t2 = " << t2 << std::endl;
- d_theory.conflict(t1, t2);
+ return TrustNode::mkTrustRewrite(node, exists, nullptr);
}
-void TheorySetsPrivate::NotifyClass::eqNotifyNewClass(TNode t)
-{
- Debug("sets-eq") << "[sets-eq] eqNotifyNewClass:"
- << " t = " << t << std::endl;
- d_theory.eqNotifyNewClass(t);
-}
-
-void TheorySetsPrivate::NotifyClass::eqNotifyPreMerge(TNode t1, TNode t2)
+Node TheorySetsPrivate::getChooseFunction(const TypeNode& setType)
{
- Debug("sets-eq") << "[sets-eq] eqNotifyPreMerge:"
- << " t1 = " << t1 << " t2 = " << t2 << std::endl;
- d_theory.eqNotifyPreMerge(t1, t2);
-}
+ std::map<TypeNode, Node>::iterator it = d_chooseFunctions.find(setType);
+ if (it != d_chooseFunctions.end())
+ {
+ return it->second;
+ }
-void TheorySetsPrivate::NotifyClass::eqNotifyPostMerge(TNode t1, TNode t2)
-{
- Debug("sets-eq") << "[sets-eq] eqNotifyPostMerge:"
- << " t1 = " << t1 << " t2 = " << t2 << std::endl;
- d_theory.eqNotifyPostMerge(t1, t2);
+ NodeManager* nm = NodeManager::currentNM();
+ TypeNode chooseUf = nm->mkFunctionType(setType, setType.getSetElementType());
+ stringstream stream;
+ stream << "chooseUf" << setType.getId();
+ string name = stream.str();
+ Node chooseSkolem = nm->mkSkolem(
+ name, chooseUf, "choose function", NodeManager::SKOLEM_EXACT_NAME);
+ d_chooseFunctions[setType] = chooseSkolem;
+ return chooseSkolem;
}
-void TheorySetsPrivate::NotifyClass::eqNotifyDisequal(TNode t1,
- TNode t2,
- TNode reason)
-{
- Debug("sets-eq") << "[sets-eq] eqNotifyDisequal:"
- << " t1 = " << t1 << " t2 = " << t2 << " reason = " << reason
- << std::endl;
- d_theory.eqNotifyDisequal(t1, t2, reason);
-}
+void TheorySetsPrivate::presolve() { d_state.reset(); }
} // namespace sets
} // namespace theory
diff --git a/src/theory/sets/theory_sets_private.h b/src/theory/sets/theory_sets_private.h
index c65c86795..8247d4940 100644
--- a/src/theory/sets/theory_sets_private.h
+++ b/src/theory/sets/theory_sets_private.h
@@ -2,10 +2,10 @@
/*! \file theory_sets_private.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Kshitij Bansal, Mathias Preiner
+ ** Andrew Reynolds, Kshitij Bansal, Mudathir Mohamed
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,6 +25,7 @@
#include "theory/sets/cardinality_extension.h"
#include "theory/sets/inference_manager.h"
#include "theory/sets/solver_state.h"
+#include "theory/sets/term_registry.h"
#include "theory/sets/theory_sets_rels.h"
#include "theory/sets/theory_sets_rewriter.h"
#include "theory/theory.h"
@@ -39,26 +40,16 @@ class TheorySets;
class TheorySetsPrivate {
typedef context::CDHashMap< Node, bool, NodeHashFunction> NodeBoolMap;
- typedef context::CDHashMap< Node, int, NodeHashFunction> NodeIntMap;
typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
public:
void eqNotifyNewClass(TNode t);
- void eqNotifyPreMerge(TNode t1, TNode t2);
- void eqNotifyPostMerge(TNode t1, TNode t2);
+ void eqNotifyMerge(TNode t1, TNode t2);
void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
- /** Assert fact holds in the current context with explanation exp.
- *
- * exp should be explainable by the equality engine of this class, and fact
- * should be a literal.
- */
- bool assertFact(Node fact, Node exp);
private:
/** Are a and b trigger terms in the equality engine that may be disequal? */
bool areCareDisequal(Node a, Node b);
- NodeIntMap d_members;
- std::map< Node, std::vector< Node > > d_members_data;
/**
* Invoke the decision procedure for this theory, which is run at
* full effort. This will either send a lemma or conflict on the output
@@ -71,19 +62,6 @@ class TheorySetsPrivate {
*/
void fullEffortReset();
/**
- * This ensures that subtype constraints are met for all set terms. In
- * particular, for a set equivalence class E, let Set(T) be the most
- * common type among the types of terms in that class. In other words,
- * if E contains two terms of Set(Int) and Set(Real), then Set(Int) is the
- * most common type. Then, for each membership x in S where S is a set in
- * this equivalence class, we ensure x has type T by asserting:
- * x = k
- * for a fresh constant k of type T. This is done only if the type of x is not
- * a subtype of Int (e.g. if x is of type Real). We call k the "type
- * constraint skolem for x of type Int".
- */
- void checkSubtypes();
- /**
* This implements an inference schema based on the "downwards closure" of
* set membership. This roughly corresponds to the rules UNION DOWN I and II,
* INTER DOWN I and II from Bansal et al IJCAR 2016, as well as rules for set
@@ -123,7 +101,6 @@ class TheorySetsPrivate {
* context.
*/
NodeSet d_termProcessed;
- NodeSet d_keep;
//propagation
class EqcInfo
@@ -156,27 +133,38 @@ class TheorySetsPrivate {
* contexts.
*/
TheorySetsPrivate(TheorySets& external,
- context::Context* c,
- context::UserContext* u);
+ SolverState& state,
+ InferenceManager& im,
+ SkolemCache& skc);
~TheorySetsPrivate();
TheoryRewriter* getTheoryRewriter() { return &d_rewriter; }
- void setMasterEqualityEngine(eq::EqualityEngine* eq);
+ /** Get the solver state */
+ SolverState* getSolverState() { return &d_state; }
- void addSharedTerm(TNode);
+ /**
+ * Finish initialize, called after the equality engine of theory sets has
+ * been determined.
+ */
+ void finishInit();
- void check(Theory::Effort);
+ //--------------------------------- standard check
+ /** Post-check, called after the fact queue of the theory is processed. */
+ void postCheck(Theory::Effort level);
+ /** Notify new fact */
+ void notifyFact(TNode atom, bool polarity, TNode fact);
+ //--------------------------------- end standard check
- bool collectModelInfo(TheoryModel* m);
+ /** Collect model values in m based on the relevant terms given by termSet */
+ void addSharedTerm(TNode);
+ bool collectModelValues(TheoryModel* m, const std::set<Node>& termSet);
void computeCareGraph();
Node explain(TNode);
- EqualityStatus getEqualityStatus(TNode a, TNode b);
-
void preRegisterTerm(TNode node);
/** expandDefinition
@@ -212,51 +200,27 @@ class TheorySetsPrivate {
void presolve();
- void propagate(Theory::Effort);
-
- /** get default output channel */
- OutputChannel* getOutputChannel();
/** get the valuation */
Valuation& getValuation();
-
private:
TheorySets& d_external;
+ /** The state of the sets solver at full effort */
+ SolverState& d_state;
+ /** The inference manager of the sets solver */
+ InferenceManager& d_im;
+ /** Reference to the skolem cache */
+ SkolemCache& d_skCache;
+ /** The term registry */
+ TermRegistry d_treg;
- /** Functions to handle callbacks from equality engine */
- class NotifyClass : public eq::EqualityEngineNotify {
- TheorySetsPrivate& d_theory;
+ /** Pointer to the equality engine of theory of sets */
+ eq::EqualityEngine* d_equalityEngine;
- public:
- NotifyClass(TheorySetsPrivate& theory): d_theory(theory) {}
- bool eqNotifyTriggerEquality(TNode equality, bool value) override;
- bool eqNotifyTriggerPredicate(TNode predicate, bool value) override;
- bool eqNotifyTriggerTermEquality(TheoryId tag,
- TNode t1,
- TNode t2,
- bool value) override;
- void eqNotifyConstantTermMerge(TNode t1, TNode t2) override;
- void eqNotifyNewClass(TNode t) override;
- void eqNotifyPreMerge(TNode t1, TNode t2) override;
- void eqNotifyPostMerge(TNode t1, TNode t2) override;
- void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override;
- } d_notify;
-
- /** Equality engine */
- eq::EqualityEngine d_equalityEngine;
-
- /** Proagate out to output channel */
- bool propagate(TNode);
-
- /** generate and send out conflict node */
- void conflict(TNode, TNode);
-
bool isCareArg( Node n, unsigned a );
public:
/** Is formula n entailed to have polarity pol in the current context? */
bool isEntailed(Node n, bool pol) { return d_state.isEntailed(n, pol); }
- /** Is x entailed to be a member of set s in the current context? */
- bool isMember(Node x, Node s);
private:
/** get choose function
@@ -265,10 +229,10 @@ class TheorySetsPrivate {
* given set type, or creates a new one if it does not exist.
*/
Node getChooseFunction(const TypeNode& setType);
- /** The state of the sets solver at full effort */
- SolverState d_state;
- /** The inference manager of the sets solver */
- InferenceManager d_im;
+ /** expand the definition of the choose operator */
+ TrustNode expandChooseOperator(const Node& node);
+ /** expand the definition of is_singleton operator */
+ TrustNode expandIsSingletonOperator(const Node& node);
/** subtheory solver for the theory of relations */
std::unique_ptr<TheorySetsRels> d_rels;
/** subtheory solver for the theory of sets with cardinality */
@@ -289,10 +253,12 @@ class TheorySetsPrivate {
/** The theory rewriter for this theory. */
TheorySetsRewriter d_rewriter;
- /*
- * a map that stores the choose functions for set types
- */
+ /** a map that stores the choose functions for set types */
std::map<TypeNode, Node> d_chooseFunctions;
+
+ /** a map that maps each set to an existential quantifier generated for
+ * operator is_singleton */
+ std::map<Node, Node> d_isSingletonNodes;
};/* class TheorySetsPrivate */
diff --git a/src/theory/sets/theory_sets_rels.cpp b/src/theory/sets/theory_sets_rels.cpp
index f4b1d3be9..ebb7f845d 100644
--- a/src/theory/sets/theory_sets_rels.cpp
+++ b/src/theory/sets/theory_sets_rels.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Paul Meng, Piotr Trojanek
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -15,7 +15,6 @@
**/
#include "theory/sets/theory_sets_rels.h"
-#include "expr/datatype.h"
#include "theory/sets/theory_sets_private.h"
#include "theory/sets/theory_sets.h"
@@ -34,19 +33,16 @@ typedef std::map< Node, std::map< Node, std::unordered_set< Node, NodeHashFuncti
TheorySetsRels::TheorySetsRels(SolverState& s,
InferenceManager& im,
- eq::EqualityEngine& e,
- context::UserContext* u)
- : d_state(s), d_im(im), d_ee(e), d_shared_terms(u)
+ SkolemCache& skc,
+ TermRegistry& treg)
+ : d_state(s),
+ d_im(im),
+ d_skCache(skc),
+ d_treg(treg),
+ d_shared_terms(s.getUserContext())
{
d_trueNode = NodeManager::currentNM()->mkConst(true);
d_falseNode = NodeManager::currentNM()->mkConst(false);
- d_ee.addFunctionKind(PRODUCT);
- d_ee.addFunctionKind(JOIN);
- d_ee.addFunctionKind(TRANSPOSE);
- d_ee.addFunctionKind(TCLOSURE);
- d_ee.addFunctionKind(JOIN_IMAGE);
- d_ee.addFunctionKind(IDEN);
- d_ee.addFunctionKind(APPLY_CONSTRUCTOR);
}
TheorySetsRels::~TheorySetsRels() {}
@@ -185,10 +181,11 @@ void TheorySetsRels::check(Theory::Effort level)
void TheorySetsRels::collectRelsInfo() {
Trace("rels") << "[sets-rels] Start collecting relational terms..." << std::endl;
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(&d_ee);
+ eq::EqualityEngine* ee = d_state.getEqualityEngine();
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(ee);
while( !eqcs_i.isFinished() ){
Node eqc_rep = (*eqcs_i);
- eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc_rep, &d_ee);
+ eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc_rep, ee);
TypeNode erType = eqc_rep.getType();
Trace("rels-ee") << "[sets-rels-ee] Eqc term representative: " << eqc_rep << " with type " << eqc_rep.getType() << std::endl;
@@ -250,12 +247,13 @@ void TheorySetsRels::check(Theory::Effort level)
}
else if (erType.isTuple() && !eqc_node.isConst() && !eqc_node.isVar())
{
+ std::vector<TypeNode> tupleTypes = erType.getTupleTypes();
for (unsigned i = 0, tlen = erType.getTupleLength(); i < tlen; i++)
{
- Node element = RelsUtils::nthElementOfTuple( eqc_node, i );
-
- if( !element.isConst() ) {
- makeSharedTerm( element );
+ Node element = RelsUtils::nthElementOfTuple(eqc_node, i);
+ if (!element.isConst())
+ {
+ makeSharedTerm(element, tupleTypes[i]);
}
}
}
@@ -552,17 +550,16 @@ void TheorySetsRels::check(Theory::Effort level)
}
Node fst_element = RelsUtils::nthElementOfTuple( exp[0], 0 );
Node snd_element = RelsUtils::nthElementOfTuple( exp[0], 1 );
- SkolemCache& sc = d_state.getSkolemCache();
- Node sk_1 = sc.mkTypedSkolemCached(fst_element.getType(),
- exp[0],
- tc_rel[0],
- SkolemCache::SK_TCLOSURE_DOWN1,
- "stc1");
- Node sk_2 = sc.mkTypedSkolemCached(fst_element.getType(),
- exp[0],
- tc_rel[0],
- SkolemCache::SK_TCLOSURE_DOWN2,
- "stc2");
+ Node sk_1 = d_skCache.mkTypedSkolemCached(fst_element.getType(),
+ exp[0],
+ tc_rel[0],
+ SkolemCache::SK_TCLOSURE_DOWN1,
+ "stc1");
+ Node sk_2 = d_skCache.mkTypedSkolemCached(fst_element.getType(),
+ exp[0],
+ tc_rel[0],
+ SkolemCache::SK_TCLOSURE_DOWN2,
+ "stc2");
Node mem_of_r = nm->mkNode(MEMBER, exp[0], tc_rel[0]);
Node sk_eq = nm->mkNode(EQUAL, sk_1, sk_2);
Node reason = exp;
@@ -825,7 +822,7 @@ void TheorySetsRels::check(Theory::Effort level)
Node r1_rep = getRepresentative(join_rel[0]);
Node r2_rep = getRepresentative(join_rel[1]);
TypeNode shared_type = r2_rep.getType().getSetElementType().getTupleTypes()[0];
- Node shared_x = d_state.getSkolemCache().mkTypedSkolemCached(
+ Node shared_x = d_skCache.mkTypedSkolemCached(
shared_type, mem, join_rel, SkolemCache::SK_JOIN, "srj");
const DType& dt1 = join_rel[0].getType().getSetElementType().getDType();
unsigned int s1_len = join_rel[0].getType().getSetElementType().getTupleLength();
@@ -867,7 +864,7 @@ void TheorySetsRels::check(Theory::Effort level)
sendInfer(fact, reason, "JOIN-Split-1");
fact = NodeManager::currentNM()->mkNode(kind::MEMBER, mem2, join_rel[1]);
sendInfer(fact, reason, "JOIN-Split-2");
- makeSharedTerm( shared_x );
+ makeSharedTerm(shared_x, shared_type);
}
/*
@@ -1043,8 +1040,14 @@ void TheorySetsRels::check(Theory::Effort level)
Node r2_lmost = RelsUtils::nthElementOfTuple( r2_rep_exps[j][0], 0 );
tuple_elements.push_back(tn.getDType()[0].getConstructor());
- if( (areEqual(r1_rmost, r2_lmost) && rel.getKind() == kind::JOIN) ||
- rel.getKind() == kind::PRODUCT ) {
+ Trace("rels-debug") << "[Theory::Rels] r1_rmost: " << r1_rmost
+ << " of type " << r1_rmost.getType() << std::endl;
+ Trace("rels-debug") << "[Theory::Rels] r2_lmost: " << r2_lmost
+ << " of type " << r2_lmost.getType() << std::endl;
+
+ if (rel.getKind() == kind::PRODUCT
+ || (rel.getKind() == kind::JOIN && areEqual(r1_rmost, r2_lmost)))
+ {
bool isProduct = rel.getKind() == kind::PRODUCT;
unsigned int k = 0;
unsigned int l = 1;
@@ -1111,7 +1114,7 @@ void TheorySetsRels::check(Theory::Effort level)
// if we are still not in conflict, send lemmas
if (!d_state.isInConflict())
{
- d_im.flushPendingLemmas();
+ d_im.doPendingLemmas();
}
}
d_pending.clear();
@@ -1139,24 +1142,17 @@ void TheorySetsRels::check(Theory::Effort level)
}
Node TheorySetsRels::getRepresentative( Node t ) {
- if (d_ee.hasTerm(t))
- {
- return d_ee.getRepresentative(t);
- }
- else
- {
- return t;
- }
+ return d_state.getRepresentative(t);
}
- bool TheorySetsRels::hasTerm(Node a) { return d_ee.hasTerm(a); }
+ bool TheorySetsRels::hasTerm(Node a) { return d_state.hasTerm(a); }
bool TheorySetsRels::areEqual( Node a, Node b ){
Assert(a.getType() == b.getType());
Trace("rels-eq") << "[sets-rels]**** checking equality between " << a << " and " << b << std::endl;
if(a == b) {
return true;
} else if( hasTerm( a ) && hasTerm( b ) ){
- return d_ee.areEqual(a, b);
+ return d_state.areEqual(a, b);
} else if(a.getType().isTuple()) {
bool equal = true;
for(unsigned int i = 0; i < a.getType().getTupleLength(); i++) {
@@ -1164,8 +1160,9 @@ void TheorySetsRels::check(Theory::Effort level)
}
return equal;
} else if(!a.getType().isBoolean()){
- makeSharedTerm(a);
- makeSharedTerm(b);
+ // TODO(project##230): Find a safe type for the singleton operator
+ makeSharedTerm(a, a.getType());
+ makeSharedTerm(b, b.getType());
}
return false;
}
@@ -1194,15 +1191,16 @@ void TheorySetsRels::check(Theory::Effort level)
return false;
}
- void TheorySetsRels::makeSharedTerm( Node n ) {
+ void TheorySetsRels::makeSharedTerm(Node n, TypeNode t)
+ {
if (d_shared_terms.find(n) != d_shared_terms.end())
{
return;
}
Trace("rels-share") << " [sets-rels] making shared term " << n << std::endl;
// force a proxy lemma to be sent for the singleton containing n
- Node ss = NodeManager::currentNM()->mkNode(SINGLETON, n);
- d_state.getProxy(ss);
+ Node ss = NodeManager::currentNM()->mkSingleton(t, n);
+ d_treg.getProxy(ss);
d_shared_terms.insert(n);
}
@@ -1227,9 +1225,11 @@ void TheorySetsRels::check(Theory::Effort level)
Trace("rels-debug") << "[Theory::Rels] Reduce tuple var: " << n[0] << " to a concrete one " << " node = " << n << std::endl;
std::vector<Node> tuple_elements;
tuple_elements.push_back((n[0].getType().getDType())[0].getConstructor());
- for(unsigned int i = 0; i < n[0].getType().getTupleLength(); i++) {
+ std::vector<TypeNode> tupleTypes = n[0].getType().getTupleTypes();
+ for (unsigned int i = 0; i < n[0].getType().getTupleLength(); i++)
+ {
Node element = RelsUtils::nthElementOfTuple(n[0], i);
- makeSharedTerm(element);
+ makeSharedTerm(element, tupleTypes[i]);
tuple_elements.push_back(element);
}
Node tuple_reduct = NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, tuple_elements);
diff --git a/src/theory/sets/theory_sets_rels.h b/src/theory/sets/theory_sets_rels.h
index 0d8ace50f..95a13f4d5 100644
--- a/src/theory/sets/theory_sets_rels.h
+++ b/src/theory/sets/theory_sets_rels.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Paul Meng, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -24,6 +24,7 @@
#include "theory/sets/inference_manager.h"
#include "theory/sets/rels_utils.h"
#include "theory/sets/solver_state.h"
+#include "theory/sets/term_registry.h"
#include "theory/theory.h"
#include "theory/uf/equality_engine.h"
@@ -67,8 +68,8 @@ class TheorySetsRels {
public:
TheorySetsRels(SolverState& s,
InferenceManager& im,
- eq::EqualityEngine& e,
- context::UserContext* u);
+ SkolemCache& skc,
+ TermRegistry& treg);
~TheorySetsRels();
/**
@@ -90,8 +91,10 @@ private:
SolverState& d_state;
/** Reference to the inference manager for the theory of sets */
InferenceManager& d_im;
- /** Reference to the equality engine of theory of sets */
- eq::EqualityEngine& d_ee;
+ /** Reference to the skolem cache */
+ SkolemCache& d_skCache;
+ /** Reference to the term registry */
+ TermRegistry& d_treg;
/** A list of pending inferences to process */
std::vector<Node> d_pending;
NodeSet d_shared_terms;
@@ -173,7 +176,7 @@ private:
/** Helper functions */
bool hasTerm( Node a );
- void makeSharedTerm( Node );
+ void makeSharedTerm(Node, TypeNode t);
void reduceTupleVar( Node );
bool hasMember( Node, Node );
void computeTupleReps( Node );
diff --git a/src/theory/sets/theory_sets_rewriter.cpp b/src/theory/sets/theory_sets_rewriter.cpp
index a7fbc8a38..1e4473d6f 100644
--- a/src/theory/sets/theory_sets_rewriter.cpp
+++ b/src/theory/sets/theory_sets_rewriter.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Kshitij Bansal, Paul Meng
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -27,7 +27,7 @@ namespace CVC4 {
namespace theory {
namespace sets {
-bool checkConstantMembership(TNode elementTerm, TNode setTerm)
+bool TheorySetsRewriter::checkConstantMembership(TNode elementTerm, TNode setTerm)
{
if(setTerm.getKind() == kind::EMPTYSET) {
return false;
@@ -38,12 +38,11 @@ bool checkConstantMembership(TNode elementTerm, TNode setTerm)
}
Assert(setTerm.getKind() == kind::UNION
- && setTerm[1].getKind() == kind::SINGLETON)
+ && setTerm[0].getKind() == kind::SINGLETON)
<< "kind was " << setTerm.getKind() << ", term: " << setTerm;
- return
- elementTerm == setTerm[1][0] ||
- checkConstantMembership(elementTerm, setTerm[0]);
+ return elementTerm == setTerm[0][0]
+ || checkConstantMembership(elementTerm, setTerm[1]);
}
// static
@@ -53,6 +52,8 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) {
Trace("sets-postrewrite") << "Process: " << node << std::endl;
if(node.isConst()) {
+ Trace("sets-rewrite-nf")
+ << "Sets::rewrite: no rewrite (constant) " << node << std::endl;
// Dare you touch the const and mangle it to something else.
return RewriteResponse(REWRITE_DONE, node);
}
@@ -118,32 +119,52 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) {
break;
}
- case kind::SETMINUS: {
- if(node[0] == node[1]) {
+ case kind::SETMINUS:
+ {
+ if (node[0] == node[1])
+ {
Node newNode = nm->mkConst(EmptySet(node[0].getType()));
- Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
+ Trace("sets-postrewrite")
+ << "Sets::postRewrite returning " << newNode << std::endl;
return RewriteResponse(REWRITE_DONE, newNode);
- } else if(node[0].getKind() == kind::EMPTYSET ||
- node[1].getKind() == kind::EMPTYSET) {
- Trace("sets-postrewrite") << "Sets::postRewrite returning " << node[0] << std::endl;
+ }
+ else if (node[0].getKind() == kind::EMPTYSET
+ || node[1].getKind() == kind::EMPTYSET)
+ {
+ Trace("sets-postrewrite")
+ << "Sets::postRewrite returning " << node[0] << std::endl;
return RewriteResponse(REWRITE_AGAIN, node[0]);
- }else if( node[1].getKind() == kind::UNIVERSE_SET ){
+ }
+ else if (node[1].getKind() == kind::SETMINUS && node[1][0] == node[0])
+ {
+ // (setminus A (setminus A B)) = (intersection A B)
+ Node intersection = nm->mkNode(INTERSECTION, node[0], node[1][1]);
+ return RewriteResponse(REWRITE_AGAIN, intersection);
+ }
+ else if (node[1].getKind() == kind::UNIVERSE_SET)
+ {
return RewriteResponse(
REWRITE_AGAIN,
NodeManager::currentNM()->mkConst(EmptySet(node[1].getType())));
- } else if(node[0].isConst() && node[1].isConst()) {
+ }
+ else if (node[0].isConst() && node[1].isConst())
+ {
std::set<Node> left = NormalForm::getElementsFromNormalConstant(node[0]);
std::set<Node> right = NormalForm::getElementsFromNormalConstant(node[1]);
std::set<Node> newSet;
- std::set_difference(left.begin(), left.end(), right.begin(), right.end(),
- std::inserter(newSet, newSet.begin()));
+ std::set_difference(left.begin(),
+ left.end(),
+ right.begin(),
+ right.end(),
+ std::inserter(newSet, newSet.begin()));
Node newNode = NormalForm::elementsToSet(newSet, node.getType());
Assert(newNode.isConst());
- Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
+ Trace("sets-postrewrite")
+ << "Sets::postRewrite returning " << newNode << std::endl;
return RewriteResponse(REWRITE_DONE, newNode);
}
break;
- }//kind::SETMINUS
+ } // kind::SETMINUS
case kind::INTERSECTION: {
if(node[0] == node[1]) {
@@ -160,26 +181,16 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) {
std::set_intersection(left.begin(), left.end(), right.begin(), right.end(),
std::inserter(newSet, newSet.begin()));
Node newNode = NormalForm::elementsToSet(newSet, node.getType());
- Assert(newNode.isConst());
+ Assert(newNode.isConst() && newNode.getType() == node.getType());
Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
return RewriteResponse(REWRITE_DONE, newNode);
- } else {
- std::vector< Node > els;
- NormalForm::getElementsFromBop( kind::INTERSECTION, node, els );
- std::sort( els.begin(), els.end() );
- Node rew = NormalForm::mkBop( kind::INTERSECTION, els, node.getType() );
- if( rew!=node ){
- Trace("sets-rewrite") << "Sets::rewrite " << node << " -> " << rew << std::endl;
- }
- return RewriteResponse(REWRITE_DONE, rew);
}
- /*
- } else if (node[0] > node[1]) {
+ else if (node[0] > node[1])
+ {
Node newNode = nm->mkNode(node.getKind(), node[1], node[0]);
- Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
return RewriteResponse(REWRITE_DONE, newNode);
}
- */
+ // we don't merge non-constant intersections
break;
}//kind::INTERSECION
@@ -200,26 +211,26 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) {
std::inserter(newSet, newSet.begin()));
Node newNode = NormalForm::elementsToSet(newSet, node.getType());
Assert(newNode.isConst());
- Trace("sets-postrewrite") << "Sets::postRewrite returning " << newNode << std::endl;
+ Trace("sets-rewrite")
+ << "Sets::rewrite: UNION_CONSTANT_MERGE: " << newNode << std::endl;
+ return RewriteResponse(REWRITE_DONE, newNode);
+ }
+ else if (node[0] > node[1])
+ {
+ Node newNode = nm->mkNode(node.getKind(), node[1], node[0]);
return RewriteResponse(REWRITE_DONE, newNode);
- } else {
- std::vector< Node > els;
- NormalForm::getElementsFromBop( kind::UNION, node, els );
- std::sort( els.begin(), els.end() );
- Node rew = NormalForm::mkBop( kind::UNION, els, node.getType() );
- if( rew!=node ){
- Trace("sets-rewrite") << "Sets::rewrite " << node << " -> " << rew << std::endl;
- }
- Trace("sets-rewrite") << "...no rewrite." << std::endl;
- return RewriteResponse(REWRITE_DONE, rew);
}
+ // we don't merge non-constant unions
break;
}//kind::UNION
- case kind::COMPLEMENT: {
- Node univ = NodeManager::currentNM()->mkNullaryOperator( node[0].getType(), kind::UNIVERSE_SET );
- return RewriteResponse( REWRITE_AGAIN, NodeManager::currentNM()->mkNode( kind::SETMINUS, univ, node[0] ) );
+ case kind::COMPLEMENT:
+ {
+ Node univ = NodeManager::currentNM()->mkNullaryOperator(node[0].getType(),
+ kind::UNIVERSE_SET);
+ return RewriteResponse(
+ REWRITE_AGAIN,
+ NodeManager::currentNM()->mkNode(kind::SETMINUS, univ, node[0]));
}
- break;
case kind::CARD: {
if(node[0].isConst()) {
std::set<Node> elements = NormalForm::getElementsFromNormalConstant(node[0]);
@@ -240,6 +251,29 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) {
}
break;
}
+
+ case kind::CHOOSE:
+ {
+ if (node[0].getKind() == SINGLETON)
+ {
+ //(= (choose (singleton x)) x) is a tautology
+ // we return x for (choose (singleton x))
+ return RewriteResponse(REWRITE_AGAIN, node[0][0]);
+ }
+ break;
+ } // kind::CHOOSE
+ case kind::IS_SINGLETON:
+ {
+ if (node[0].getKind() == SINGLETON)
+ {
+ //(= (is_singleton (singleton x)) is a tautology
+ // we return true for (is_singleton (singleton x))
+ return RewriteResponse(REWRITE_AGAIN,
+ NodeManager::currentNM()->mkConst(true));
+ }
+ break;
+ } // kind::IS_SINGLETON
+
case kind::TRANSPOSE: {
if(node[0].getKind() == kind::TRANSPOSE) {
return RewriteResponse(REWRITE_AGAIN, node[0][0]);
@@ -468,38 +502,39 @@ RewriteResponse TheorySetsRewriter::postRewrite(TNode node) {
// static
RewriteResponse TheorySetsRewriter::preRewrite(TNode node) {
NodeManager* nm = NodeManager::currentNM();
-
- if(node.getKind() == kind::EQUAL) {
-
+ Kind k = node.getKind();
+ if (k == kind::EQUAL)
+ {
if(node[0] == node[1]) {
return RewriteResponse(REWRITE_DONE, nm->mkConst(true));
}
-
- }//kind::EQUAL
- else if(node.getKind() == kind::INSERT) {
-
- Node insertedElements = nm->mkNode(kind::SINGLETON, node[0]);
+ }
+ else if (k == kind::INSERT)
+ {
size_t setNodeIndex = node.getNumChildren()-1;
- for(size_t i = 1; i < setNodeIndex; ++i) {
- insertedElements = nm->mkNode(kind::UNION,
- insertedElements,
- nm->mkNode(kind::SINGLETON, node[i]));
+ TypeNode elementType = node[setNodeIndex].getType().getSetElementType();
+ Node insertedElements = nm->mkSingleton(elementType, node[0]);
+
+ for (size_t i = 1; i < setNodeIndex; ++i)
+ {
+ Node singleton = nm->mkSingleton(elementType, node[i]);
+ insertedElements = nm->mkNode(kind::UNION, insertedElements, singleton);
}
return RewriteResponse(REWRITE_AGAIN,
nm->mkNode(kind::UNION,
insertedElements,
node[setNodeIndex]));
-
- }//kind::INSERT
- else if(node.getKind() == kind::SUBSET) {
-
+ }
+ else if (k == kind::SUBSET)
+ {
// rewrite (A subset-or-equal B) as (A union B = B)
return RewriteResponse(REWRITE_AGAIN,
nm->mkNode(kind::EQUAL,
nm->mkNode(kind::UNION, node[0], node[1]),
node[1]) );
+ }
- }//kind::SUBSET
+ // could have an efficient normalizer for union here
return RewriteResponse(REWRITE_DONE, node);
}
diff --git a/src/theory/sets/theory_sets_rewriter.h b/src/theory/sets/theory_sets_rewriter.h
index 7d1a6c188..e7d031b6f 100644
--- a/src/theory/sets/theory_sets_rewriter.h
+++ b/src/theory/sets/theory_sets_rewriter.h
@@ -5,7 +5,7 @@
** Kshitij Bansal, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -70,7 +70,11 @@ class TheorySetsRewriter : public TheoryRewriter
// often this will suffice
return postRewrite(equality).d_node;
}
-
+private:
+ /**
+ * Returns true if elementTerm is in setTerm, where both terms are constants.
+ */
+ bool checkConstantMembership(TNode elementTerm, TNode setTerm);
}; /* class TheorySetsRewriter */
}/* CVC4::theory::sets namespace */
diff --git a/src/theory/sets/theory_sets_type_enumerator.cpp b/src/theory/sets/theory_sets_type_enumerator.cpp
index 7f5628c66..1d932b590 100644
--- a/src/theory/sets/theory_sets_type_enumerator.cpp
+++ b/src/theory/sets/theory_sets_type_enumerator.cpp
@@ -2,10 +2,10 @@
/*! \file theory_sets_type_enumerator.cpp
** \verbatim
** Top contributors (to current version):
- ** Mudathir Mohamed
+ ** Mudathir Mohamed, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -89,7 +89,8 @@ SetEnumerator& SetEnumerator::operator++()
// get a new element and return it as a singleton set
Node element = *d_elementEnumerator;
d_elementsSoFar.push_back(element);
- d_currentSet = d_nodeManager->mkNode(kind::SINGLETON, element);
+ TypeNode elementType = d_elementEnumerator.getType();
+ d_currentSet = d_nodeManager->mkSingleton(elementType, element);
d_elementEnumerator++;
}
else
diff --git a/src/theory/sets/theory_sets_type_enumerator.h b/src/theory/sets/theory_sets_type_enumerator.h
index fc6faa337..1bc6e5e43 100644
--- a/src/theory/sets/theory_sets_type_enumerator.h
+++ b/src/theory/sets/theory_sets_type_enumerator.h
@@ -5,7 +5,7 @@
** Mudathir Mohamed, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/sets/theory_sets_type_rules.h b/src/theory/sets/theory_sets_type_rules.h
index 5d01a966a..c5e86f10c 100644
--- a/src/theory/sets/theory_sets_type_rules.h
+++ b/src/theory/sets/theory_sets_type_rules.h
@@ -2,10 +2,10 @@
/*! \file theory_sets_type_rules.h
** \verbatim
** Top contributors (to current version):
- ** Kshitij Bansal, Andrew Reynolds, Paul Meng
+ ** Andrew Reynolds, Kshitij Bansal, Paul Meng
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,42 +25,44 @@ namespace CVC4 {
namespace theory {
namespace sets {
-struct SetsBinaryOperatorTypeRule {
- inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+struct SetsBinaryOperatorTypeRule
+{
+ inline static TypeNode computeType(NodeManager* nodeManager,
+ TNode n,
+ bool check)
{
Assert(n.getKind() == kind::UNION || n.getKind() == kind::INTERSECTION
|| n.getKind() == kind::SETMINUS);
TypeNode setType = n[0].getType(check);
- if( check ) {
- if(!setType.isSet()) {
- throw TypeCheckingExceptionPrivate(n, "operator expects a set, first argument is not");
+ if (check)
+ {
+ if (!setType.isSet())
+ {
+ throw TypeCheckingExceptionPrivate(
+ n, "operator expects a set, first argument is not");
}
TypeNode secondSetType = n[1].getType(check);
- if(secondSetType != setType) {
- if( n.getKind() == kind::INTERSECTION ){
- setType = TypeNode::mostCommonTypeNode( secondSetType, setType );
- }else{
- setType = TypeNode::leastCommonTypeNode( secondSetType, setType );
- }
- if( setType.isNull() ){
- throw TypeCheckingExceptionPrivate(n, "operator expects two sets of comparable types");
- }
-
+ if (secondSetType != setType)
+ {
+ std::stringstream ss;
+ ss << "Operator " << n.getKind()
+ << " expects two sets of the same type. Found types '" << setType
+ << "' and '" << secondSetType << "'.";
+ throw TypeCheckingExceptionPrivate(n, ss.str());
}
}
return setType;
}
- inline static bool computeIsConst(NodeManager* nodeManager, TNode n) {
- Assert(n.getKind() == kind::UNION || n.getKind() == kind::INTERSECTION
- || n.getKind() == kind::SETMINUS);
- if(n.getKind() == kind::UNION) {
- return NormalForm::checkNormalConstant(n);
- } else {
- return false;
- }
+ inline static bool computeIsConst(NodeManager* nodeManager, TNode n)
+ {
+ // only UNION has a const rule in kinds.
+ // INTERSECTION and SETMINUS are not used in the canonical representation of
+ // sets and therefore they do not have const rules in kinds
+ Assert(n.getKind() == kind::UNION);
+ return NormalForm::checkNormalConstant(n);
}
-};/* struct SetUnionTypeRule */
+}; /* struct SetsBinaryOperatorTypeRule */
struct SubsetTypeRule {
inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
@@ -82,33 +84,26 @@ struct SubsetTypeRule {
}
};/* struct SetSubsetTypeRule */
-struct MemberTypeRule {
- inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+struct MemberTypeRule
+{
+ inline static TypeNode computeType(NodeManager* nodeManager,
+ TNode n,
+ bool check)
{
Assert(n.getKind() == kind::MEMBER);
TypeNode setType = n[1].getType(check);
- if( check ) {
- if(!setType.isSet()) {
- throw TypeCheckingExceptionPrivate(n, "checking for membership in a non-set");
+ if (check)
+ {
+ if (!setType.isSet())
+ {
+ throw TypeCheckingExceptionPrivate(
+ n, "checking for membership in a non-set");
}
TypeNode elementType = n[0].getType(check);
- // TODO : still need to be flexible here due to situations like:
- //
- // T : (Set Int)
- // S : (Set Real)
- // (= (as T (Set Real)) S)
- // (member 0.5 S)
- // ...where (member 0.5 T) is inferred
- //
- // or
- //
- // S : (Set Real)
- // (not (member 0.5 s))
- // (member 0.0 s)
- // ...find model M where M( s ) = { 0 }, check model will generate (not (member 0.5 (singleton 0)))
- //
- if(!elementType.isComparableTo(setType.getSetElementType())) {
- //if(!elementType.isSubtypeOf(setType.getSetElementType())) { //FIXME:typing
+ // e.g. (member 1 (singleton 1.0)) is true whereas
+ // (member 1.0 (singleton 1)) throws a typing error
+ if (!elementType.isSubtypeOf(setType.getSetElementType()))
+ {
std::stringstream ss;
ss << "member operating on sets of different types:\n"
<< "child type: " << elementType << "\n"
@@ -119,20 +114,42 @@ struct MemberTypeRule {
}
return nodeManager->booleanType();
}
-};/* struct MemberTypeRule */
+}; /* struct MemberTypeRule */
-struct SingletonTypeRule {
- inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+struct SingletonTypeRule
+{
+ inline static TypeNode computeType(NodeManager* nodeManager,
+ TNode n,
+ bool check)
{
- Assert(n.getKind() == kind::SINGLETON);
- return nodeManager->mkSetType(n[0].getType(check));
+ Assert(n.getKind() == kind::SINGLETON && n.hasOperator()
+ && n.getOperator().getKind() == kind::SINGLETON_OP);
+
+ SingletonOp op = n.getOperator().getConst<SingletonOp>();
+ TypeNode type1 = op.getType();
+ if (check)
+ {
+ TypeNode type2 = n[0].getType(check);
+ TypeNode leastCommonType = TypeNode::leastCommonTypeNode(type1, type2);
+ // the type of the element should be a subtype of the type of the operator
+ // e.g. (singleton (singleton_op Real) 1) where 1 is an Int
+ if (leastCommonType.isNull() || leastCommonType != type1)
+ {
+ std::stringstream ss;
+ ss << "The type '" << type2 << "' of the element is not a subtype of '"
+ << type1 << "' in term : " << n;
+ throw TypeCheckingExceptionPrivate(n, ss.str());
+ }
+ }
+ return nodeManager->mkSetType(type1);
}
- inline static bool computeIsConst(NodeManager* nodeManager, TNode n) {
+ inline static bool computeIsConst(NodeManager* nodeManager, TNode n)
+ {
Assert(n.getKind() == kind::SINGLETON);
return n[0].isConst();
}
-};/* struct SingletonTypeRule */
+}; /* struct SingletonTypeRule */
struct EmptySetTypeRule {
inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
@@ -155,11 +172,6 @@ struct CardTypeRule {
}
return nodeManager->integerType();
}
-
- inline static bool computeIsConst(NodeManager* nodeManager, TNode n) {
- Assert(n.getKind() == kind::CARD);
- return false;
- }
};/* struct CardTypeRule */
struct ComplementTypeRule {
@@ -174,11 +186,6 @@ struct ComplementTypeRule {
}
return setType;
}
-
- inline static bool computeIsConst(NodeManager* nodeManager, TNode n) {
- Assert(n.getKind() == kind::COMPLEMENT);
- return false;
- }
};/* struct ComplementTypeRule */
struct UniverseSetTypeRule {
@@ -235,13 +242,27 @@ struct ChooseTypeRule
}
return setType.getSetElementType();
}
- inline static bool computeIsConst(NodeManager* nodeManager, TNode n)
+}; /* struct ChooseTypeRule */
+
+struct IsSingletonTypeRule
+{
+ inline static TypeNode computeType(NodeManager* nodeManager,
+ TNode n,
+ bool check)
{
- Assert(n.getKind() == kind::CHOOSE);
- // choose nodes should be expanded
- return false;
+ Assert(n.getKind() == kind::IS_SINGLETON);
+ TypeNode setType = n[0].getType(check);
+ if (check)
+ {
+ if (!setType.isSet())
+ {
+ throw TypeCheckingExceptionPrivate(
+ n, "IS_SINGLETON operator expects a set, a non-set is found");
+ }
+ }
+ return nodeManager->booleanType();
}
-}; /* struct ChooseTypeRule */
+}; /* struct IsSingletonTypeRule */
struct InsertTypeRule {
inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
@@ -264,11 +285,6 @@ struct InsertTypeRule {
}
return setType;
}
-
- inline static bool computeIsConst(NodeManager* nodeManager, TNode n) {
- Assert(n.getKind() == kind::INSERT);
- return false;
- }
};/* struct InsertTypeRule */
struct RelBinaryOperatorTypeRule {
@@ -308,11 +324,6 @@ struct RelBinaryOperatorTypeRule {
return resultType;
}
-
- inline static bool computeIsConst(NodeManager* nodeManager, TNode n) {
- Assert(n.getKind() == kind::JOIN || n.getKind() == kind::PRODUCT);
- return false;
- }
};/* struct RelBinaryOperatorTypeRule */
struct RelTransposeTypeRule {
@@ -327,10 +338,6 @@ struct RelTransposeTypeRule {
std::reverse(tupleTypes.begin(), tupleTypes.end());
return nodeManager->mkSetType(nodeManager->mkTupleType(tupleTypes));
}
-
- inline static bool computeIsConst(NodeManager* nodeManager, TNode n) {
- return false;
- }
};/* struct RelTransposeTypeRule */
struct RelTransClosureTypeRule {
@@ -352,11 +359,6 @@ struct RelTransClosureTypeRule {
}
return setType;
}
-
- inline static bool computeIsConst(NodeManager* nodeManager, TNode n) {
- Assert(n.getKind() == kind::TCLOSURE);
- return false;
- }
};/* struct RelTransClosureTypeRule */
struct JoinImageTypeRule {
@@ -399,11 +401,6 @@ struct JoinImageTypeRule {
newTupleTypes.push_back(tupleTypes[0]);
return nodeManager->mkSetType(nodeManager->mkTupleType(newTupleTypes));
}
-
- inline static bool computeIsConst(NodeManager* nodeManager, TNode n) {
- Assert(n.getKind() == kind::JOIN_IMAGE);
- return false;
- }
};/* struct JoinImageTypeRule */
struct RelIdenTypeRule {
@@ -423,10 +420,6 @@ struct RelIdenTypeRule {
tupleTypes.push_back(tupleTypes[0]);
return nodeManager->mkSetType(nodeManager->mkTupleType(tupleTypes));
}
-
- inline static bool computeIsConst(NodeManager* nodeManager, TNode n) {
- return false;
- }
};/* struct RelIdenTypeRule */
struct SetsProperties {
diff --git a/src/theory/shared_solver.cpp b/src/theory/shared_solver.cpp
new file mode 100644
index 000000000..24d7d29cf
--- /dev/null
+++ b/src/theory/shared_solver.cpp
@@ -0,0 +1,116 @@
+/********************* */
+/*! \file shared_solver.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The shared solver base class
+ **/
+
+#include "theory/shared_solver.h"
+
+#include "expr/node_visitor.h"
+#include "theory/theory_engine.h"
+
+namespace CVC4 {
+namespace theory {
+
+// Always creates shared terms database. In all cases, shared terms
+// database is used as a way of tracking which calls to Theory::addSharedTerm
+// we need to make in preNotifySharedFact.
+// In distributed equality engine management, shared terms database also
+// maintains an equality engine. In central equality engine management,
+// it does not.
+SharedSolver::SharedSolver(TheoryEngine& te, ProofNodeManager* pnm)
+ : d_te(te),
+ d_logicInfo(te.getLogicInfo()),
+ d_sharedTerms(&d_te, d_te.getSatContext(), d_te.getUserContext(), pnm),
+ d_sharedTermsVisitor(d_sharedTerms)
+{
+}
+
+bool SharedSolver::needsEqualityEngine(theory::EeSetupInfo& esi)
+{
+ return false;
+}
+
+void SharedSolver::preRegisterShared(TNode t, bool multipleTheories)
+{
+ // register it with the equality engine manager if sharing is enabled
+ if (d_logicInfo.isSharingEnabled())
+ {
+ preRegisterSharedInternal(t);
+ }
+ // if multiple theories are present in t
+ if (multipleTheories)
+ {
+ // Collect the shared terms if there are multiple theories
+ // This calls Theory::addSharedTerm, possibly multiple times
+ NodeVisitor<SharedTermsVisitor>::run(d_sharedTermsVisitor, t);
+ }
+}
+
+void SharedSolver::preNotifySharedFact(TNode atom)
+{
+ if (d_sharedTerms.hasSharedTerms(atom))
+ {
+ // Always notify the theories of the shared terms, which is independent of
+ // the architecture currently.
+ SharedTermsDatabase::shared_terms_iterator it = d_sharedTerms.begin(atom);
+ SharedTermsDatabase::shared_terms_iterator it_end = d_sharedTerms.end(atom);
+ for (; it != it_end; ++it)
+ {
+ TNode term = *it;
+ TheoryIdSet theories = d_sharedTerms.getTheoriesToNotify(atom, term);
+ for (TheoryId id = THEORY_FIRST; id != THEORY_LAST; ++id)
+ {
+ if (TheoryIdSetUtil::setContains(id, theories))
+ {
+ Theory* t = d_te.theoryOf(id);
+ // call the add shared term method
+ t->addSharedTerm(term);
+ }
+ }
+ d_sharedTerms.markNotified(term, theories);
+ }
+ }
+}
+
+EqualityStatus SharedSolver::getEqualityStatus(TNode a, TNode b)
+{
+ return EQUALITY_UNKNOWN;
+}
+
+void SharedSolver::sendLemma(TrustNode trn, TheoryId atomsTo)
+{
+ d_te.lemma(trn, LemmaProperty::NONE, atomsTo);
+}
+
+bool SharedSolver::propagateSharedEquality(theory::TheoryId theory,
+ TNode a,
+ TNode b,
+ bool value)
+{
+ // Propagate equality between shared terms to the one who asked for it
+ Node equality = a.eqNode(b);
+ if (value)
+ {
+ d_te.assertToTheory(equality, equality, theory, THEORY_BUILTIN);
+ }
+ else
+ {
+ d_te.assertToTheory(
+ equality.notNode(), equality.notNode(), theory, THEORY_BUILTIN);
+ }
+ return true;
+}
+
+bool SharedSolver::isShared(TNode t) const { return d_sharedTerms.isShared(t); }
+
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/shared_solver.h b/src/theory/shared_solver.h
new file mode 100644
index 000000000..c3d95f3c4
--- /dev/null
+++ b/src/theory/shared_solver.h
@@ -0,0 +1,134 @@
+/********************* */
+/*! \file shared_solver.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Base class for shared solver
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__SHARED_SOLVER__H
+#define CVC4__THEORY__SHARED_SOLVER__H
+
+#include "expr/node.h"
+#include "expr/proof_node_manager.h"
+#include "theory/ee_setup_info.h"
+#include "theory/logic_info.h"
+#include "theory/shared_terms_database.h"
+#include "theory/term_registration_visitor.h"
+#include "theory/valuation.h"
+
+namespace CVC4 {
+
+class TheoryEngine;
+
+namespace theory {
+
+/**
+ * A base class for shared solver. The shared solver is the component of theory
+ * engine that behaves like a theory solver, and whose purpose is to ensure the
+ * main theory combination method can be performed in CombinationEngine.
+ * Its role is to:
+ * (1) Notify the individual theories of shared terms via addSharedTerms,
+ * (2) Be the official interface for equality statuses,
+ * (3) Propagate equalities to TheoryEngine when necessary and explain them.
+ */
+class SharedSolver
+{
+ public:
+ SharedSolver(TheoryEngine& te, ProofNodeManager* pnm);
+ virtual ~SharedSolver() {}
+ //------------------------------------- initialization
+ /**
+ * Returns true if we need an equality engine, this has the same contract
+ * as Theory::needsEqualityEngine.
+ */
+ virtual bool needsEqualityEngine(theory::EeSetupInfo& esi);
+ /**
+ * Set the equality engine. This should be called by equality engine manager
+ * during EqEngineManager::initializeTheories.
+ */
+ virtual void setEqualityEngine(eq::EqualityEngine* ee) = 0;
+ //------------------------------------- end initialization
+ /**
+ * Called when the given term t is pre-registered in TheoryEngine.
+ *
+ * This adds t as an equality to propagate in the shared terms database
+ * if it is an equality, or adds its shared terms if it involves multiple
+ * theories.
+ *
+ * @param t The term to preregister
+ * @param multipleTheories Whether multiple theories are present in t.
+ */
+ void preRegisterShared(TNode t, bool multipleTheories);
+ /**
+ * Pre-notify assertion fact with the given atom. This is called when any
+ * fact is asserted in TheoryEngine, just before it is dispatched to the
+ * appropriate theory.
+ *
+ * This calls Theory::notifySharedTerm for the shared terms of the atom.
+ */
+ void preNotifySharedFact(TNode atom);
+ /**
+ * Get the equality status of a and b.
+ *
+ * This method is used by theories via Valuation mostly for determining their
+ * care graph.
+ */
+ virtual EqualityStatus getEqualityStatus(TNode a, TNode b);
+ /**
+ * Explain literal, which returns a conjunction of literals that entail
+ * the given one.
+ */
+ virtual TrustNode explain(TNode literal, TheoryId id) = 0;
+ /**
+ * Assert equality to the shared terms database.
+ *
+ * This method is called by TheoryEngine when a fact has been marked to
+ * send to THEORY_BUILTIN, meaning that shared terms database should
+ * maintain this fact. This is the case when either an equality is
+ * asserted from the SAT solver or a theory propagates an equality between
+ * shared terms.
+ */
+ virtual void assertSharedEquality(TNode equality,
+ bool polarity,
+ TNode reason) = 0;
+ /** Is term t a shared term? */
+ virtual bool isShared(TNode t) const;
+
+ /**
+ * Method called by equalityEngine when a becomes (dis-)equal to b and a and b
+ * are shared with the theory. Returns false if there is a direct conflict
+ * (via rewrite for example).
+ */
+ bool propagateSharedEquality(theory::TheoryId theory,
+ TNode a,
+ TNode b,
+ bool value);
+ /** Send lemma to the theory engine, atomsTo is the theory to send atoms to */
+ void sendLemma(TrustNode trn, TheoryId atomsTo);
+
+ protected:
+ /** Solver-specific pre-register shared */
+ virtual void preRegisterSharedInternal(TNode t) = 0;
+ /** Reference to the theory engine */
+ TheoryEngine& d_te;
+ /** Logic info of theory engine (cached) */
+ const LogicInfo& d_logicInfo;
+ /** The database of shared terms.*/
+ SharedTermsDatabase d_sharedTerms;
+ /** Visitor for collecting shared terms */
+ SharedTermsVisitor d_sharedTermsVisitor;
+};
+
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__SHARED_SOLVER__H */
diff --git a/src/theory/shared_solver_distributed.cpp b/src/theory/shared_solver_distributed.cpp
new file mode 100644
index 000000000..c868ed206
--- /dev/null
+++ b/src/theory/shared_solver_distributed.cpp
@@ -0,0 +1,96 @@
+/********************* */
+/*! \file shared_solver_distributed.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Shared solver in the distributed architecture
+ **/
+
+#include "theory/shared_solver_distributed.h"
+
+#include "theory/theory_engine.h"
+
+namespace CVC4 {
+namespace theory {
+
+SharedSolverDistributed::SharedSolverDistributed(TheoryEngine& te,
+ ProofNodeManager* pnm)
+ : SharedSolver(te, pnm)
+{
+}
+
+bool SharedSolverDistributed::needsEqualityEngine(theory::EeSetupInfo& esi)
+{
+ return d_sharedTerms.needsEqualityEngine(esi);
+}
+
+void SharedSolverDistributed::setEqualityEngine(eq::EqualityEngine* ee)
+{
+ d_sharedTerms.setEqualityEngine(ee);
+}
+
+void SharedSolverDistributed::preRegisterSharedInternal(TNode t)
+{
+ if (t.getKind() == kind::EQUAL)
+ {
+ // When sharing is enabled, we propagate from the shared terms manager also
+ d_sharedTerms.addEqualityToPropagate(t);
+ }
+}
+
+EqualityStatus SharedSolverDistributed::getEqualityStatus(TNode a, TNode b)
+{
+ // if we're using a shared terms database, ask its status if a and b are
+ // shared.
+ if (d_sharedTerms.isShared(a) && d_sharedTerms.isShared(b))
+ {
+ if (d_sharedTerms.areEqual(a, b))
+ {
+ return EQUALITY_TRUE_AND_PROPAGATED;
+ }
+ else if (d_sharedTerms.areDisequal(a, b))
+ {
+ return EQUALITY_FALSE_AND_PROPAGATED;
+ }
+ }
+ // otherwise, ask the theory
+ return d_te.theoryOf(Theory::theoryOf(a.getType()))->getEqualityStatus(a, b);
+}
+
+TrustNode SharedSolverDistributed::explain(TNode literal, TheoryId id)
+{
+ TrustNode texp;
+ if (id == THEORY_BUILTIN)
+ {
+ // explanation using the shared terms database
+ texp = d_sharedTerms.explain(literal);
+ Trace("shared-solver")
+ << "\tTerm was propagated by THEORY_BUILTIN. Explanation: "
+ << texp.getNode() << std::endl;
+ }
+ else
+ {
+ // By default, we ask the individual theory for the explanation.
+ // It is possible that a centralized approach could preempt this.
+ texp = d_te.theoryOf(id)->explain(literal);
+ Trace("shared-solver") << "\tTerm was propagated by owner theory: " << id
+ << ". Explanation: " << texp.getNode() << std::endl;
+ }
+ return texp;
+}
+
+void SharedSolverDistributed::assertSharedEquality(TNode equality,
+ bool polarity,
+ TNode reason)
+{
+ d_sharedTerms.assertEquality(equality, polarity, reason);
+}
+
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/shared_solver_distributed.h b/src/theory/shared_solver_distributed.h
new file mode 100644
index 000000000..de6e29743
--- /dev/null
+++ b/src/theory/shared_solver_distributed.h
@@ -0,0 +1,64 @@
+/********************* */
+/*! \file shared_solver_distributed.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Shared solver in the distributed architecture.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__SHARED_SOLVER_DISTRIBUTED__H
+#define CVC4__THEORY__SHARED_SOLVER_DISTRIBUTED__H
+
+#include "expr/node.h"
+#include "theory/shared_solver.h"
+
+namespace CVC4 {
+namespace theory {
+
+/**
+ * The shared solver in the distributed architecture. This class uses the
+ * SharedTermsDatabase for implementing the core methods of a shared solver.
+ */
+class SharedSolverDistributed : public SharedSolver
+{
+ public:
+ SharedSolverDistributed(TheoryEngine& te, ProofNodeManager* pnm);
+ virtual ~SharedSolverDistributed() {}
+ //------------------------------------- initialization
+ /**
+ * Returns true if we need an equality engine, this has the same contract
+ * as Theory::needsEqualityEngine.
+ */
+ bool needsEqualityEngine(theory::EeSetupInfo& esi) override;
+ /** Set equality engine in the shared terms database */
+ void setEqualityEngine(eq::EqualityEngine* ee) override;
+ //------------------------------------- end initialization
+ /** Assert equality to the shared terms database. */
+ void assertSharedEquality(TNode equality,
+ bool polarity,
+ TNode reason) override;
+ /**
+ * Get equality status based on the equality engine of shared terms database
+ */
+ EqualityStatus getEqualityStatus(TNode a, TNode b) override;
+ /** Explain literal that was propagated by a theory or using shared terms
+ * database */
+ TrustNode explain(TNode literal, TheoryId id) override;
+
+ protected:
+ /** If t is an equality, add it as one that may be propagated */
+ void preRegisterSharedInternal(TNode t) override;
+};
+
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__SHARED_SOLVER_DISTRIBUTED__H */
diff --git a/src/theory/shared_terms_database.cpp b/src/theory/shared_terms_database.cpp
index 52ce34756..edf512e4b 100644
--- a/src/theory/shared_terms_database.cpp
+++ b/src/theory/shared_terms_database.cpp
@@ -2,10 +2,10 @@
/*! \file shared_terms_database.cpp
** \verbatim
** Top contributors (to current version):
- ** Dejan Jovanovic, Morgan Deters, Tim King
+ ** Dejan Jovanovic, Andrew Reynolds, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -24,7 +24,9 @@ using namespace CVC4::theory;
namespace CVC4 {
SharedTermsDatabase::SharedTermsDatabase(TheoryEngine* theoryEngine,
- context::Context* context)
+ context::Context* context,
+ context::UserContext* userContext,
+ ProofNodeManager* pnm)
: ContextNotifyObj(context),
d_statSharedTerms("theory::shared_terms", 0),
d_addedSharedTermsSize(context, 0),
@@ -32,10 +34,15 @@ SharedTermsDatabase::SharedTermsDatabase(TheoryEngine* theoryEngine,
d_alreadyNotifiedMap(context),
d_registeredEqualities(context),
d_EENotify(*this),
- d_equalityEngine(d_EENotify, context, "SharedTermsDatabase", true),
d_theoryEngine(theoryEngine),
d_inConflict(context, false),
- d_conflictPolarity() {
+ d_conflictPolarity(),
+ d_satContext(context),
+ d_userContext(userContext),
+ d_equalityEngine(nullptr),
+ d_pfee(nullptr),
+ d_pnm(pnm)
+{
smtStatisticsRegistry()->registerStat(&d_statSharedTerms);
}
@@ -44,15 +51,39 @@ SharedTermsDatabase::~SharedTermsDatabase()
smtStatisticsRegistry()->unregisterStat(&d_statSharedTerms);
}
+void SharedTermsDatabase::setEqualityEngine(eq::EqualityEngine* ee)
+{
+ Assert(ee != nullptr);
+ d_equalityEngine = ee;
+ // if proofs are enabled, make the proof equality engine
+ if (d_pnm != nullptr)
+ {
+ d_pfee.reset(
+ new eq::ProofEqEngine(d_satContext, d_userContext, *ee, d_pnm));
+ }
+}
+
+bool SharedTermsDatabase::needsEqualityEngine(EeSetupInfo& esi)
+{
+ esi.d_notify = &d_EENotify;
+ esi.d_name = "SharedTermsDatabase";
+ return true;
+}
+
void SharedTermsDatabase::addEqualityToPropagate(TNode equality) {
+ Assert(d_equalityEngine != nullptr);
d_registeredEqualities.insert(equality);
- d_equalityEngine.addTriggerEquality(equality);
+ d_equalityEngine->addTriggerPredicate(equality);
checkForConflict();
}
-
-void SharedTermsDatabase::addSharedTerm(TNode atom, TNode term, Theory::Set theories) {
- Debug("register") << "SharedTermsDatabase::addSharedTerm(" << atom << ", " << term << ", " << Theory::setToString(theories) << ")" << std::endl;
+void SharedTermsDatabase::addSharedTerm(TNode atom,
+ TNode term,
+ TheoryIdSet theories)
+{
+ Debug("register") << "SharedTermsDatabase::addSharedTerm(" << atom << ", "
+ << term << ", " << TheoryIdSetUtil::setToString(theories)
+ << ")" << std::endl;
std::pair<TNode, TNode> search_pair(atom, term);
SharedTermsTheoriesMap::iterator find = d_termsToTheories.find(search_pair);
@@ -64,7 +95,8 @@ void SharedTermsDatabase::addSharedTerm(TNode atom, TNode term, Theory::Set theo
d_termsToTheories[search_pair] = theories;
} else {
Assert(theories != (*find).second);
- d_termsToTheories[search_pair] = Theory::setUnion(theories, (*find).second);
+ d_termsToTheories[search_pair] =
+ TheoryIdSetUtil::setUnion(theories, (*find).second);
}
}
@@ -94,25 +126,27 @@ void SharedTermsDatabase::backtrack() {
d_addedSharedTerms.resize(d_addedSharedTermsSize);
}
-Theory::Set SharedTermsDatabase::getTheoriesToNotify(TNode atom, TNode term) const {
+TheoryIdSet SharedTermsDatabase::getTheoriesToNotify(TNode atom,
+ TNode term) const
+{
// Get the theories that share this term from this atom
std::pair<TNode, TNode> search_pair(atom, term);
SharedTermsTheoriesMap::iterator find = d_termsToTheories.find(search_pair);
Assert(find != d_termsToTheories.end());
// Get the theories that were already notified
- Theory::Set alreadyNotified = 0;
+ TheoryIdSet alreadyNotified = 0;
AlreadyNotifiedMap::iterator theoriesFind = d_alreadyNotifiedMap.find(term);
if (theoriesFind != d_alreadyNotifiedMap.end()) {
alreadyNotified = (*theoriesFind).second;
}
// Return the ones that haven't been notified yet
- return Theory::setDifference((*find).second, alreadyNotified);
+ return TheoryIdSetUtil::setDifference((*find).second, alreadyNotified);
}
-
-Theory::Set SharedTermsDatabase::getNotifiedTheories(TNode term) const {
+TheoryIdSet SharedTermsDatabase::getNotifiedTheories(TNode term) const
+{
// Get the theories that were already notified
AlreadyNotifiedMap::iterator theoriesFind = d_alreadyNotifiedMap.find(term);
if (theoriesFind != d_alreadyNotifiedMap.end()) {
@@ -142,15 +176,16 @@ bool SharedTermsDatabase::propagateSharedEquality(TheoryId theory, TNode a, TNod
return true;
}
-void SharedTermsDatabase::markNotified(TNode term, Theory::Set theories) {
-
+void SharedTermsDatabase::markNotified(TNode term, TheoryIdSet theories)
+{
// Find out if there are any new theories that were notified about this term
- Theory::Set alreadyNotified = 0;
+ TheoryIdSet alreadyNotified = 0;
AlreadyNotifiedMap::iterator theoriesFind = d_alreadyNotifiedMap.find(term);
if (theoriesFind != d_alreadyNotifiedMap.end()) {
alreadyNotified = (*theoriesFind).second;
}
- Theory::Set newlyNotified = Theory::setDifference(theories, alreadyNotified);
+ TheoryIdSet newlyNotified =
+ TheoryIdSetUtil::setDifference(theories, alreadyNotified);
// If no new theories were notified, we are done
if (newlyNotified == 0) {
@@ -160,12 +195,21 @@ void SharedTermsDatabase::markNotified(TNode term, Theory::Set theories) {
Debug("shared-terms-database") << "SharedTermsDatabase::markNotified(" << term << ")" << endl;
// First update the set of notified theories for this term
- d_alreadyNotifiedMap[term] = Theory::setUnion(newlyNotified, alreadyNotified);
+ d_alreadyNotifiedMap[term] =
+ TheoryIdSetUtil::setUnion(newlyNotified, alreadyNotified);
+
+ if (d_equalityEngine == nullptr)
+ {
+ // if we are not assigned an equality engine, there is nothing to do
+ return;
+ }
// Mark the shared terms in the equality engine
theory::TheoryId currentTheory;
- while ((currentTheory = Theory::setPop(newlyNotified)) != THEORY_LAST) {
- d_equalityEngine.addTriggerTerm(term, currentTheory);
+ while ((currentTheory = TheoryIdSetUtil::setPop(newlyNotified))
+ != THEORY_LAST)
+ {
+ d_equalityEngine->addTriggerTerm(term, currentTheory);
}
// Check for any conflits
@@ -173,32 +217,42 @@ void SharedTermsDatabase::markNotified(TNode term, Theory::Set theories) {
}
bool SharedTermsDatabase::areEqual(TNode a, TNode b) const {
- if (d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b)) {
- return d_equalityEngine.areEqual(a,b);
+ Assert(d_equalityEngine != nullptr);
+ if (d_equalityEngine->hasTerm(a) && d_equalityEngine->hasTerm(b))
+ {
+ return d_equalityEngine->areEqual(a, b);
} else {
- Assert(d_equalityEngine.hasTerm(a) || a.isConst());
- Assert(d_equalityEngine.hasTerm(b) || b.isConst());
+ Assert(d_equalityEngine->hasTerm(a) || a.isConst());
+ Assert(d_equalityEngine->hasTerm(b) || b.isConst());
// since one (or both) of them is a constant, and the other is in the equality engine, they are not same
return false;
}
}
bool SharedTermsDatabase::areDisequal(TNode a, TNode b) const {
- if (d_equalityEngine.hasTerm(a) && d_equalityEngine.hasTerm(b)) {
- return d_equalityEngine.areDisequal(a,b,false);
+ Assert(d_equalityEngine != nullptr);
+ if (d_equalityEngine->hasTerm(a) && d_equalityEngine->hasTerm(b))
+ {
+ return d_equalityEngine->areDisequal(a, b, false);
} else {
- Assert(d_equalityEngine.hasTerm(a) || a.isConst());
- Assert(d_equalityEngine.hasTerm(b) || b.isConst());
+ Assert(d_equalityEngine->hasTerm(a) || a.isConst());
+ Assert(d_equalityEngine->hasTerm(b) || b.isConst());
// one (or both) are in the equality engine
return false;
}
}
+theory::eq::EqualityEngine* SharedTermsDatabase::getEqualityEngine()
+{
+ return d_equalityEngine;
+}
+
void SharedTermsDatabase::assertEquality(TNode equality, bool polarity, TNode reason)
{
+ Assert(d_equalityEngine != nullptr);
Debug("shared-terms-database::assert") << "SharedTermsDatabase::assertEquality(" << equality << ", " << (polarity ? "true" : "false") << ", " << reason << ")" << endl;
// Add it to the equality engine
- d_equalityEngine.assertEquality(equality, polarity, reason);
+ d_equalityEngine->assertEquality(equality, polarity, reason);
// Check for conflict
checkForConflict();
}
@@ -212,56 +266,55 @@ bool SharedTermsDatabase::propagateEquality(TNode equality, bool polarity) {
return true;
}
-static Node mkAnd(const std::vector<TNode>& conjunctions) {
- Assert(conjunctions.size() > 0);
-
- std::set<TNode> all;
- all.insert(conjunctions.begin(), conjunctions.end());
-
- if (all.size() == 1) {
- // All the same, or just one
- return conjunctions[0];
+void SharedTermsDatabase::checkForConflict()
+{
+ if (!d_inConflict)
+ {
+ return;
}
-
- NodeBuilder<> conjunction(kind::AND);
- std::set<TNode>::const_iterator it = all.begin();
- std::set<TNode>::const_iterator it_end = all.end();
- while (it != it_end) {
- conjunction << *it;
- ++ it;
+ d_inConflict = false;
+ TrustNode trnc;
+ if (d_pfee != nullptr)
+ {
+ Node conflict = d_conflictLHS.eqNode(d_conflictRHS);
+ conflict = d_conflictPolarity ? conflict : conflict.notNode();
+ trnc = d_pfee->assertConflict(conflict);
}
-
- return conjunction;
-}
-
-void SharedTermsDatabase::checkForConflict() {
- if (d_inConflict) {
- d_inConflict = false;
+ else
+ {
+ // standard explain
std::vector<TNode> assumptions;
- d_equalityEngine.explainEquality(d_conflictLHS, d_conflictRHS, d_conflictPolarity, assumptions);
- Node conflict = mkAnd(assumptions);
- d_theoryEngine->conflict(conflict, THEORY_BUILTIN);
- d_conflictLHS = d_conflictRHS = Node::null();
+ d_equalityEngine->explainEquality(
+ d_conflictLHS, d_conflictRHS, d_conflictPolarity, assumptions);
+ Node conflictNode = NodeManager::currentNM()->mkAnd(assumptions);
+ trnc = TrustNode::mkTrustConflict(conflictNode, nullptr);
}
+ d_theoryEngine->conflict(trnc, THEORY_BUILTIN);
+ d_conflictLHS = d_conflictRHS = Node::null();
}
bool SharedTermsDatabase::isKnown(TNode literal) const {
+ Assert(d_equalityEngine != nullptr);
bool polarity = literal.getKind() != kind::NOT;
TNode equality = polarity ? literal : literal[0];
if (polarity) {
- return d_equalityEngine.areEqual(equality[0], equality[1]);
+ return d_equalityEngine->areEqual(equality[0], equality[1]);
} else {
- return d_equalityEngine.areDisequal(equality[0], equality[1], false);
+ return d_equalityEngine->areDisequal(equality[0], equality[1], false);
}
}
-Node SharedTermsDatabase::explain(TNode literal) const {
- bool polarity = literal.getKind() != kind::NOT;
- TNode atom = polarity ? literal : literal[0];
- Assert(atom.getKind() == kind::EQUAL);
- std::vector<TNode> assumptions;
- d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions);
- return mkAnd(assumptions);
+theory::TrustNode SharedTermsDatabase::explain(TNode literal) const
+{
+ if (d_pfee != nullptr)
+ {
+ // use the proof equality engine if it exists
+ return d_pfee->explain(literal);
+ }
+ // otherwise, explain without proofs
+ Node exp = d_equalityEngine->mkExplainLit(literal);
+ // no proof generator
+ return TrustNode::mkTrustPropExp(literal, exp, nullptr);
}
} /* namespace CVC4 */
diff --git a/src/theory/shared_terms_database.h b/src/theory/shared_terms_database.h
index 0bfd8e094..693e93228 100644
--- a/src/theory/shared_terms_database.h
+++ b/src/theory/shared_terms_database.h
@@ -2,10 +2,10 @@
/*! \file shared_terms_database.h
** \verbatim
** Top contributors (to current version):
- ** Dejan Jovanovic, Mathias Preiner, Morgan Deters
+ ** Dejan Jovanovic, Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,8 +21,12 @@
#include "context/cdhashset.h"
#include "expr/node.h"
-#include "theory/theory.h"
+#include "expr/proof_node_manager.h"
+#include "theory/ee_setup_info.h"
+#include "theory/theory_id.h"
+#include "theory/trust_node.h"
#include "theory/uf/equality_engine.h"
+#include "theory/uf/proof_equality_engine.h"
#include "util/statistics_registry.h"
namespace CVC4 {
@@ -30,17 +34,14 @@ namespace CVC4 {
class TheoryEngine;
class SharedTermsDatabase : public context::ContextNotifyObj {
-
-public:
-
+ public:
/** A container for a list of shared terms */
typedef std::vector<TNode> shared_terms_list;
/** The iterator to go through the shared terms list */
typedef shared_terms_list::const_iterator shared_terms_iterator;
-private:
-
+ private:
/** Some statistics */
IntStat d_statSharedTerms;
@@ -57,19 +58,22 @@ private:
context::CDO<unsigned> d_addedSharedTermsSize;
/** A map from atoms and subterms to the theories that use it */
- typedef context::CDHashMap<std::pair<Node, TNode>, theory::Theory::Set, TNodePairHashFunction> SharedTermsTheoriesMap;
+ typedef context::CDHashMap<std::pair<Node, TNode>,
+ theory::TheoryIdSet,
+ TNodePairHashFunction>
+ SharedTermsTheoriesMap;
SharedTermsTheoriesMap d_termsToTheories;
/** Map from term to theories that have already been notified about the shared term */
- typedef context::CDHashMap<TNode, theory::Theory::Set, TNodeHashFunction> AlreadyNotifiedMap;
+ typedef context::CDHashMap<TNode, theory::TheoryIdSet, TNodeHashFunction>
+ AlreadyNotifiedMap;
AlreadyNotifiedMap d_alreadyNotifiedMap;
/** The registered equalities for propagation */
typedef context::CDHashSet<Node, NodeHashFunction> RegisteredEqualitiesSet;
RegisteredEqualitiesSet d_registeredEqualities;
-private:
-
+ private:
/** This method removes all the un-necessary stuff from the maps */
void backtrack();
@@ -78,15 +82,10 @@ private:
SharedTermsDatabase& d_sharedTerms;
public:
EENotifyClass(SharedTermsDatabase& shared): d_sharedTerms(shared) {}
- bool eqNotifyTriggerEquality(TNode equality, bool value) override
- {
- d_sharedTerms.propagateEquality(equality, value);
- return true;
- }
-
bool eqNotifyTriggerPredicate(TNode predicate, bool value) override
{
- Unreachable();
+ Assert(predicate.getKind() == kind::EQUAL);
+ d_sharedTerms.propagateEquality(predicate, value);
return true;
}
@@ -104,17 +103,13 @@ private:
}
void eqNotifyNewClass(TNode t) override {}
- void eqNotifyPreMerge(TNode t1, TNode t2) override {}
- void eqNotifyPostMerge(TNode t1, TNode t2) override {}
+ void eqNotifyMerge(TNode t1, TNode t2) override {}
void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override {}
};
/** The notify class for d_equalityEngine */
EENotifyClass d_EENotify;
- /** Equality engine */
- theory::eq::EqualityEngine d_equalityEngine;
-
/**
* Method called by equalityEngine when a becomes (dis-)equal to b and a and b are shared with
* the theory. Returns false if there is a direct conflict (via rewrite for example).
@@ -155,11 +150,30 @@ private:
*/
void checkForConflict();
-public:
-
- SharedTermsDatabase(TheoryEngine* theoryEngine, context::Context* context);
+ public:
+ /**
+ * @param theoryEngine The parent theory engine
+ * @param context The SAT context
+ * @param userContext The user context
+ * @param pnm The proof node manager to use, which is non-null if proofs
+ * are enabled.
+ */
+ SharedTermsDatabase(TheoryEngine* theoryEngine,
+ context::Context* context,
+ context::UserContext* userContext,
+ ProofNodeManager* pnm);
~SharedTermsDatabase();
+ //-------------------------------------------- initialization
+ /** Called to set the equality engine. */
+ void setEqualityEngine(theory::eq::EqualityEngine* ee);
+ /**
+ * Returns true if we need an equality engine, this has the same contract
+ * as Theory::needsEqualityEngine.
+ */
+ bool needsEqualityEngine(theory::EeSetupInfo& esi);
+ //-------------------------------------------- end initialization
+
/**
* Asserts the equality to the shared terms database,
*/
@@ -173,7 +187,7 @@ public:
/**
* Returns an explanation of the propagation that came from the database.
*/
- Node explain(TNode literal) const;
+ theory::TrustNode explain(TNode literal) const;
/**
* Add an equality to propagate.
@@ -184,12 +198,12 @@ public:
* Add a shared term to the database. The shared term is a subterm of the atom and
* should be associated with the given theory.
*/
- void addSharedTerm(TNode atom, TNode term, theory::Theory::Set theories);
+ void addSharedTerm(TNode atom, TNode term, theory::TheoryIdSet theories);
/**
* Mark that the given theories have been notified of the given shared term.
*/
- void markNotified(TNode term, theory::Theory::Set theories);
+ void markNotified(TNode term, theory::TheoryIdSet theories);
/**
* Returns true if the atom contains any shared terms, false otherwise.
@@ -209,12 +223,12 @@ public:
/**
* Get the theories that share the term in a given atom (and have not yet been notified).
*/
- theory::Theory::Set getTheoriesToNotify(TNode atom, TNode term) const;
+ theory::TheoryIdSet getTheoriesToNotify(TNode atom, TNode term) const;
/**
* Get the theories that share the term and have been notified already.
*/
- theory::Theory::Set getNotifiedTheories(TNode term) const;
+ theory::TheoryIdSet getNotifiedTheories(TNode term) const;
/**
* Returns true if the term is currently registered as shared with some theory.
@@ -245,14 +259,23 @@ public:
/**
* get equality engine
*/
- theory::eq::EqualityEngine* getEqualityEngine() { return &d_equalityEngine; }
-
-protected:
+ theory::eq::EqualityEngine* getEqualityEngine();
+ protected:
/**
* This method gets called on backtracks from the context manager.
*/
- void contextNotifyPop() override { backtrack(); }
+ void contextNotifyPop() override { backtrack(); }
+ /** The SAT search context. */
+ context::Context* d_satContext;
+ /** The user level assertion context. */
+ context::UserContext* d_userContext;
+ /** Equality engine */
+ theory::eq::EqualityEngine* d_equalityEngine;
+ /** Proof equality engine */
+ std::unique_ptr<theory::eq::ProofEqEngine> d_pfee;
+ /** The proof node manager */
+ ProofNodeManager* d_pnm;
};
}
diff --git a/src/theory/smt_engine_subsolver.cpp b/src/theory/smt_engine_subsolver.cpp
index 41526c30d..ed10e85ae 100644
--- a/src/theory/smt_engine_subsolver.cpp
+++ b/src/theory/smt_engine_subsolver.cpp
@@ -2,10 +2,10 @@
/*! \file smt_engine_subsolver.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Haniel Barbosa
+ ** Andrew Reynolds, Andres Noetzli, Gereon Kremer
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -51,11 +51,11 @@ void initializeSubsolver(std::unique_ptr<SmtEngine>& smte,
smte.reset(new SmtEngine(nm->toExprManager(), &smtCurr->getOptions()));
smte->setIsInternalSubsolver();
smte->setLogic(smtCurr->getLogicInfo());
+ // set the options
if (needsTimeout)
{
- smte->setTimeLimit(timeout, true);
+ smte->setTimeLimit(timeout);
}
- smte->setLogic(smt::currentSmtEngine()->getLogicInfo());
}
Result checkWithSubsolver(std::unique_ptr<SmtEngine>& smte,
@@ -112,8 +112,8 @@ Result checkWithSubsolver(Node query,
{
for (const Node& v : vars)
{
- Expr val = smte->getValue(v.toExpr());
- modelVals.push_back(Node::fromExpr(val));
+ Node val = smte->getValue(v);
+ modelVals.push_back(val);
}
}
return r;
diff --git a/src/theory/smt_engine_subsolver.h b/src/theory/smt_engine_subsolver.h
index cbc871cce..f68900ccc 100644
--- a/src/theory/smt_engine_subsolver.h
+++ b/src/theory/smt_engine_subsolver.h
@@ -2,10 +2,10 @@
/*! \file smt_engine_subsolver.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Haniel Barbosa
+ ** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -24,7 +24,6 @@
#include "expr/expr_manager.h"
#include "expr/node.h"
-#include "expr/variable_type_map.h"
#include "smt/smt_engine.h"
namespace CVC4 {
@@ -32,7 +31,16 @@ namespace theory {
/**
* This function initializes the smt engine smte to check the satisfiability
- * of the argument "query".
+ * of the argument "query". It takes the logic and options of the current
+ * SMT engine in scope.
+ *
+ * Notice this method intentionally does not fully initialize smte. This means
+ * that the options of smte can still be modified after it is returned by
+ * this method.
+ *
+ * Notice that some aspects of subsolvers are not incoporated by this call.
+ * For example, the type of separation logic heaps is not set on smte, even
+ * if the current SMT engine has declared a separation logic heap.
*
* @param smte The smt engine pointer to initialize
* @param needsTimeout Whether we would like to set a timeout
diff --git a/src/theory/sort_inference.cpp b/src/theory/sort_inference.cpp
index 144f5b54d..9fa216e67 100644
--- a/src/theory/sort_inference.cpp
+++ b/src/theory/sort_inference.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Paul Meng, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -24,7 +24,6 @@
#include "options/quantifiers_options.h"
#include "options/smt_options.h"
#include "options/uf_options.h"
-#include "proof/proof_manager.h"
#include "theory/rewriter.h"
#include "theory/quantifiers/quant_util.h"
diff --git a/src/theory/sort_inference.h b/src/theory/sort_inference.h
index 07a0901f0..059dc5582 100644
--- a/src/theory/sort_inference.h
+++ b/src/theory/sort_inference.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Paul Meng, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/arith_entail.cpp b/src/theory/strings/arith_entail.cpp
index adcbe590e..3c58767b3 100644
--- a/src/theory/strings/arith_entail.cpp
+++ b/src/theory/strings/arith_entail.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -15,6 +15,7 @@
#include "theory/strings/arith_entail.h"
#include "expr/attribute.h"
+#include "expr/node_algorithm.h"
#include "theory/arith/arith_msum.h"
#include "theory/rewriter.h"
#include "theory/strings/theory_strings_utils.h"
@@ -555,6 +556,8 @@ bool ArithEntail::checkWithEqAssumption(Node assumption, Node a, bool strict)
{
Assert(assumption.getKind() == kind::EQUAL);
Assert(Rewriter::rewrite(assumption) == assumption);
+ Trace("strings-entail") << "checkWithEqAssumption: " << assumption << " " << a
+ << ", strict=" << strict << std::endl;
// Find candidates variables to compute substitutions for
std::unordered_set<Node, NodeHashFunction> candVars;
@@ -615,8 +618,11 @@ bool ArithEntail::checkWithEqAssumption(Node assumption, Node a, bool strict)
// Could not solve for v
return false;
}
+ Trace("strings-entail") << "checkWithEqAssumption: subs " << v << " -> "
+ << solution << std::endl;
- a = a.substitute(TNode(v), TNode(solution));
+ // use capture avoiding substitution
+ a = expr::substituteCaptureAvoiding(a, v, solution);
return check(a, strict);
}
diff --git a/src/theory/strings/arith_entail.h b/src/theory/strings/arith_entail.h
index e3dd7e2e5..a0117a456 100644
--- a/src/theory/strings/arith_entail.h
+++ b/src/theory/strings/arith_entail.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/base_solver.cpp b/src/theory/strings/base_solver.cpp
index 00658d08b..451c01f8c 100644
--- a/src/theory/strings/base_solver.cpp
+++ b/src/theory/strings/base_solver.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -638,9 +638,8 @@ void BaseSolver::checkCardinalityType(TypeNode tn,
ei->d_cardinalityLemK.set(int_k + 1);
if (!cons.isConst() || !cons.getConst<bool>())
{
- std::vector<Node> emptyVec;
d_im.sendInference(
- emptyVec, expn, cons, Inference::CARDINALITY, true);
+ expn, expn, cons, Inference::CARDINALITY, false, true);
return;
}
}
@@ -675,7 +674,7 @@ Node BaseSolver::explainConstantEqc(Node n, Node eqc, std::vector<Node>& exp)
}
if (!bei.d_exp.isNull())
{
- exp.push_back(bei.d_exp);
+ utils::flattenOp(AND, bei.d_exp, exp);
}
if (!bei.d_base.isNull())
{
@@ -695,7 +694,7 @@ Node BaseSolver::explainBestContentEqc(Node n, Node eqc, std::vector<Node>& exp)
Assert(!bei.d_bestContent.isNull());
if (!bei.d_exp.isNull())
{
- exp.push_back(bei.d_exp);
+ utils::flattenOp(AND, bei.d_exp, exp);
}
if (!bei.d_base.isNull())
{
diff --git a/src/theory/strings/base_solver.h b/src/theory/strings/base_solver.h
index 5dcb75560..87f136dd0 100644
--- a/src/theory/strings/base_solver.h
+++ b/src/theory/strings/base_solver.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/core_solver.cpp b/src/theory/strings/core_solver.cpp
index 89a286a06..48116bc24 100644
--- a/src/theory/strings/core_solver.cpp
+++ b/src/theory/strings/core_solver.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -32,13 +32,15 @@ namespace strings {
CoreInferInfo::CoreInferInfo() : d_index(0), d_rev(false) {}
-CoreSolver::CoreSolver(context::Context* c,
- context::UserContext* u,
- SolverState& s,
+CoreSolver::CoreSolver(SolverState& s,
InferenceManager& im,
TermRegistry& tr,
BaseSolver& bs)
- : d_state(s), d_im(im), d_termReg(tr), d_bsolver(bs), d_nfPairs(c)
+ : d_state(s),
+ d_im(im),
+ d_termReg(tr),
+ d_bsolver(bs),
+ d_nfPairs(s.getSatContext())
{
d_zero = NodeManager::currentNM()->mkConst( Rational( 0 ) );
d_one = NodeManager::currentNM()->mkConst( Rational( 1 ) );
@@ -171,7 +173,6 @@ void CoreSolver::checkFlatForms()
// conflict, explanation is n = base ^ base = c ^ relevant portion
// of ( n = f[n] )
std::vector<Node> exp;
- d_bsolver.explainConstantEqc(n,eqc,exp);
for (int e = firstc; e <= lastc; e++)
{
if (d_flat_form[n][e].isConst())
@@ -180,9 +181,10 @@ void CoreSolver::checkFlatForms()
Assert(d_flat_form_index[n][e] >= 0
&& d_flat_form_index[n][e] < (int)n.getNumChildren());
d_im.addToExplanation(
- d_flat_form[n][e], n[d_flat_form_index[n][e]], exp);
+ n[d_flat_form_index[n][e]], d_flat_form[n][e], exp);
}
}
+ d_bsolver.explainConstantEqc(n, eqc, exp);
Node conc = d_false;
d_im.sendInference(exp, conc, Inference::F_NCTN);
return;
@@ -239,6 +241,8 @@ void CoreSolver::checkFlatForm(std::vector<Node>& eqc,
<< "Check flat form for a = " << a << ", whose flat form is "
<< d_flat_form[a] << ")" << std::endl;
Node b;
+ // the length explanation
+ Node lant;
do
{
std::vector<Node> exp;
@@ -370,10 +374,11 @@ void CoreSolver::checkFlatForm(std::vector<Node>& eqc,
Trace("strings-ff-debug") << lexp2[j] << std::endl;
}
}
-
- exp.insert(exp.end(), lexp.begin(), lexp.end());
- exp.insert(exp.end(), lexp2.begin(), lexp2.end());
- d_im.addToExplanation(lcurr, lcc, exp);
+ std::vector<Node> lexpc;
+ lexpc.insert(lexpc.end(), lexp.begin(), lexp.end());
+ lexpc.insert(lexpc.end(), lexp2.begin(), lexp2.end());
+ d_im.addToExplanation(lcurr, lcc, lexpc);
+ lant = utils::mkAnd(lexpc);
conc = ac.eqNode(bc);
infType = Inference::F_UNIFY;
break;
@@ -388,7 +393,6 @@ void CoreSolver::checkFlatForm(std::vector<Node>& eqc,
Trace("strings-ff-debug") << "Found inference (" << infType
<< "): " << conc << " based on equality " << a
<< " == " << b << ", " << isRev << std::endl;
- d_im.addToExplanation(a, b, exp);
// explain why prefixes up to now were the same
for (size_t j = 0; j < count; j++)
{
@@ -425,12 +429,18 @@ void CoreSolver::checkFlatForm(std::vector<Node>& eqc,
}
}
}
+ d_im.addToExplanation(a, b, exp);
+ if (!lant.isNull())
+ {
+ // add the length explanation
+ exp.push_back(lant);
+ }
// Notice that F_EndpointEmp is not typically applied, since
// strict prefix equality ( a.b = a ) where a,b non-empty
// is conflicting by arithmetic len(a.b)=len(a)+len(b)!=len(a)
// when len(b)!=0. Although if we do not infer this conflict eagerly,
// it may be applied (see #3272).
- d_im.sendInference(exp, conc, infType);
+ d_im.sendInference(exp, conc, infType, isRev);
if (d_state.isInConflict())
{
return;
@@ -549,9 +559,12 @@ void CoreSolver::checkNormalFormsEq()
{
NormalForm& nfe_eq = getNormalForm(itn->second);
// two equivalence classes have same normal form, merge
- std::vector<Node> nf_exp;
- nf_exp.push_back(utils::mkAnd(nfe.d_exp));
- nf_exp.push_back(eqc_to_exp[itn->second]);
+ std::vector<Node> nf_exp(nfe.d_exp.begin(), nfe.d_exp.end());
+ Node eexp = eqc_to_exp[itn->second];
+ if (eexp != d_true)
+ {
+ nf_exp.push_back(eexp);
+ }
Node eq = nfe.d_base.eqNode(nfe_eq.d_base);
d_im.sendInference(nf_exp, eq, Inference::NORMAL_FORM);
if (d_im.hasProcessed())
@@ -693,6 +706,162 @@ Node CoreSolver::getNormalString(Node x, std::vector<Node>& nf_exp)
return x;
}
+Node CoreSolver::getConclusion(Node x,
+ Node y,
+ PfRule rule,
+ bool isRev,
+ SkolemCache* skc,
+ std::vector<Node>& newSkolems)
+{
+ Trace("strings-csolver") << "CoreSolver::getConclusion: " << x << " " << y
+ << " " << rule << " " << isRev << std::endl;
+ NodeManager* nm = NodeManager::currentNM();
+ Node conc;
+ if (rule == PfRule::CONCAT_SPLIT || rule == PfRule::CONCAT_LPROP)
+ {
+ Node sk1;
+ Node sk2;
+ if (options::stringUnifiedVSpt())
+ {
+ // must compare so that we are agnostic to order of x/y
+ Node ux = x < y ? x : y;
+ Node uy = x < y ? y : x;
+ Node sk = skc->mkSkolemCached(ux,
+ uy,
+ isRev ? SkolemCache::SK_ID_V_UNIFIED_SPT_REV
+ : SkolemCache::SK_ID_V_UNIFIED_SPT,
+ "v_spt");
+ newSkolems.push_back(sk);
+ sk1 = sk;
+ sk2 = sk;
+ }
+ else
+ {
+ sk1 = skc->mkSkolemCached(
+ x,
+ y,
+ isRev ? SkolemCache::SK_ID_V_SPT_REV : SkolemCache::SK_ID_V_SPT,
+ "v_spt1");
+ sk2 = skc->mkSkolemCached(
+ y,
+ x,
+ isRev ? SkolemCache::SK_ID_V_SPT_REV : SkolemCache::SK_ID_V_SPT,
+ "v_spt2");
+ newSkolems.push_back(sk1);
+ newSkolems.push_back(sk2);
+ }
+ Node eq1 = x.eqNode(isRev ? nm->mkNode(STRING_CONCAT, sk1, y)
+ : nm->mkNode(STRING_CONCAT, y, sk1));
+
+ if (rule == PfRule::CONCAT_LPROP)
+ {
+ conc = eq1;
+ }
+ else
+ {
+ Node eq2 = y.eqNode(isRev ? nm->mkNode(STRING_CONCAT, sk2, x)
+ : nm->mkNode(STRING_CONCAT, x, sk2));
+ // make agnostic to x/y
+ conc = x < y ? nm->mkNode(OR, eq1, eq2) : nm->mkNode(OR, eq2, eq1);
+ }
+ if (options::stringUnifiedVSpt() && options::stringLenConc())
+ {
+ // we can assume its length is greater than zero
+ Node emp = Word::mkEmptyWord(sk1.getType());
+ conc = nm->mkNode(
+ AND,
+ conc,
+ sk1.eqNode(emp).negate(),
+ nm->mkNode(
+ GT, nm->mkNode(STRING_LENGTH, sk1), nm->mkConst(Rational(0))));
+ }
+ }
+ else if (rule == PfRule::CONCAT_CSPLIT)
+ {
+ Assert(y.isConst());
+ size_t yLen = Word::getLength(y);
+ Node firstChar =
+ yLen == 1 ? y : (isRev ? Word::suffix(y, 1) : Word::prefix(y, 1));
+ Node sk = skc->mkSkolemCached(
+ x,
+ isRev ? SkolemCache::SK_ID_VC_SPT_REV : SkolemCache::SK_ID_VC_SPT,
+ "c_spt");
+ newSkolems.push_back(sk);
+ conc = x.eqNode(isRev ? nm->mkNode(STRING_CONCAT, sk, firstChar)
+ : nm->mkNode(STRING_CONCAT, firstChar, sk));
+ }
+ else if (rule == PfRule::CONCAT_CPROP)
+ {
+ // expect (str.++ z d) and c
+ Assert(x.getKind() == STRING_CONCAT && x.getNumChildren() == 2);
+ Node z = x[isRev ? 1 : 0];
+ Node d = x[isRev ? 0 : 1];
+ Assert(d.isConst());
+ Node c = y;
+ Assert(c.isConst());
+ size_t cLen = Word::getLength(c);
+ size_t p = getSufficientNonEmptyOverlap(c, d, isRev);
+ Node preC =
+ p == cLen ? c : (isRev ? Word::suffix(c, p) : Word::prefix(c, p));
+ Node sk = skc->mkSkolemCached(
+ z,
+ preC,
+ isRev ? SkolemCache::SK_ID_C_SPT_REV : SkolemCache::SK_ID_C_SPT,
+ "c_spt");
+ newSkolems.push_back(sk);
+ conc = z.eqNode(isRev ? nm->mkNode(STRING_CONCAT, sk, preC)
+ : nm->mkNode(STRING_CONCAT, preC, sk));
+ }
+
+ return conc;
+}
+
+size_t CoreSolver::getSufficientNonEmptyOverlap(Node c, Node d, bool isRev)
+{
+ Assert(c.isConst() && c.getType().isStringLike());
+ Assert(d.isConst() && d.getType().isStringLike());
+ size_t p;
+ size_t p2;
+ size_t cLen = Word::getLength(c);
+ if (isRev)
+ {
+ // Since non-empty, we start with character 1
+ Node c1 = Word::prefix(c, cLen - 1);
+ p = cLen - Word::roverlap(c1, d);
+ p2 = Word::rfind(c1, d);
+ }
+ else
+ {
+ Node c1 = Word::substr(c, 1);
+ p = cLen - Word::overlap(c1, d);
+ p2 = Word::find(c1, d);
+ }
+ return p2 == std::string::npos ? p : (p > p2 + 1 ? p2 + 1 : p);
+}
+
+Node CoreSolver::getDecomposeConclusion(Node x,
+ Node l,
+ bool isRev,
+ bool addLenConc,
+ SkolemCache* skc,
+ std::vector<Node>& newSkolems)
+{
+ Assert(l.getType().isInteger());
+ NodeManager* nm = NodeManager::currentNM();
+ Node n = isRev ? nm->mkNode(MINUS, nm->mkNode(STRING_LENGTH, x), l) : l;
+ Node sk1 = skc->mkSkolemCached(x, n, SkolemCache::SK_PREFIX, "dc_spt1");
+ newSkolems.push_back(sk1);
+ Node sk2 = skc->mkSkolemCached(x, n, SkolemCache::SK_SUFFIX_REM, "dc_spt2");
+ newSkolems.push_back(sk2);
+ Node conc = x.eqNode(nm->mkNode(STRING_CONCAT, sk1, sk2));
+ if (addLenConc)
+ {
+ Node lc = nm->mkNode(STRING_LENGTH, isRev ? sk2 : sk1).eqNode(l);
+ conc = nm->mkNode(AND, conc, lc);
+ }
+ return conc;
+}
+
void CoreSolver::getNormalForms(Node eqc,
std::vector<NormalForm>& normal_forms,
std::map<Node, unsigned>& term_to_nf_index,
@@ -920,16 +1089,16 @@ void CoreSolver::processNEqc(Node eqc,
if (!StringsEntail::canConstantContainList(c, nfi.d_nf, firstc, lastc))
{
Node n = nfi.d_base;
+ std::vector<Node> exp(nfi.d_exp.begin(), nfi.d_exp.end());
//conflict
Trace("strings-solve") << "Normal form for " << n << " cannot be contained in constant " << c << std::endl;
// conflict, explanation is:
// n = base ^ base = c ^ relevant porition of ( n = N[n] )
- std::vector< Node > exp;
- d_bsolver.explainConstantEqc(n,eqc,exp);
// Notice although not implemented, this can be minimized based on
// firstc/lastc, normal_forms_exp_depend.
- exp.insert(exp.end(), nfi.d_exp.begin(), nfi.d_exp.end());
+ d_bsolver.explainConstantEqc(n, eqc, exp);
d_im.sendInference(exp, d_false, Inference::N_NCTN);
+ // conflict, finished
return;
}
}
@@ -1023,6 +1192,10 @@ void CoreSolver::processNEqc(Node eqc,
return;
}
}
+ if (d_im.hasProcessed())
+ {
+ break;
+ }
}
if (d_im.hasProcessed() || pinfer.empty())
{
@@ -1096,7 +1269,7 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
// can infer that this string must be empty
Node eq = nfkv[index_k].eqNode(emp);
Assert(!d_state.areEqual(emp, nfkv[index_k]));
- d_im.sendInference(curr_exp, eq, Inference::N_ENDPOINT_EMP);
+ d_im.sendInference(curr_exp, eq, Inference::N_ENDPOINT_EMP, isRev);
index_k++;
}
break;
@@ -1134,6 +1307,14 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
if (d_state.areEqual(xLenTerm, yLenTerm))
{
+ std::vector<Node> ant;
+ NormalForm::getExplanationForPrefixEq(nfi, nfj, index, index, ant);
+ if (x.isConst() && y.isConst())
+ {
+ // if both are constant, it's just a constant conflict
+ d_im.sendInference(ant, d_false, Inference::N_CONST, isRev, true);
+ return;
+ }
// `x` and `y` have the same length. We infer that the two components
// have to be the same.
//
@@ -1142,9 +1323,11 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
<< "Simple Case 2 : string lengths are equal" << std::endl;
Node eq = x.eqNode(y);
Node leneq = xLenTerm.eqNode(yLenTerm);
- NormalForm::getExplanationForPrefixEq(nfi, nfj, index, index, lenExp);
lenExp.push_back(leneq);
- d_im.sendInference(lenExp, eq, Inference::N_UNIFY);
+ // set the explanation for length
+ Node lant = utils::mkAnd(lenExp);
+ ant.push_back(lant);
+ d_im.sendInference(ant, eq, Inference::N_UNIFY, isRev);
break;
}
else if ((!x.isConst() && index == nfiv.size() - rproc - 1)
@@ -1180,8 +1363,11 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
{
std::vector<Node> antec;
NormalForm::getExplanationForPrefixEq(nfi, nfj, -1, -1, antec);
- d_im.sendInference(
- antec, eqn[0].eqNode(eqn[1]), Inference::N_ENDPOINT_EQ, true);
+ d_im.sendInference(antec,
+ eqn[0].eqNode(eqn[1]),
+ Inference::N_ENDPOINT_EQ,
+ isRev,
+ true);
}
else
{
@@ -1241,7 +1427,7 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
// E.g. "abc" ++ ... = "bc" ++ ... ---> conflict
std::vector<Node> antec;
NormalForm::getExplanationForPrefixEq(nfi, nfj, index, index, antec);
- d_im.sendInference(antec, d_false, Inference::N_CONST, true);
+ d_im.sendInference(antec, d_false, Inference::N_CONST, isRev, true);
break;
}
}
@@ -1283,8 +1469,11 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
if (detectLoop(nfi, nfj, index, lhsLoopIdx, rhsLoopIdx, rproc))
{
// We are dealing with a looping word equation.
+ // Note we could make this code also run in the reverse direction, but
+ // this is not implemented currently.
if (!isRev)
- { // FIXME
+ {
+ // add temporarily to the antecedant of iinfo.
NormalForm::getExplanationForPrefixEq(nfi, nfj, -1, -1, iinfo.d_ant);
ProcessLoopResult plr =
processLoop(lhsLoopIdx != -1 ? nfi : nfj,
@@ -1302,6 +1491,8 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
break;
}
Assert(plr == ProcessLoopResult::SKIPPED);
+ // not processing an inference here, undo changes to ant
+ iinfo.d_ant.clear();
}
}
@@ -1356,9 +1547,9 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
break;
}
- // At this point, we know that `nc` is non-empty, so we add that to our
- // explanation.
- iinfo.d_ant.push_back(expNonEmpty);
+ // At this point, we know that `nc` is non-empty, so we add expNonEmpty
+ // to our explanation below. We do this after adding other parts of the
+ // explanation for consistency with other inferences.
size_t ncIndex = index + 1;
Node nextConstStr = nfnc.collectConstantStringAt(ncIndex);
@@ -1370,35 +1561,11 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
// E.g. "abc" ++ ... = nc ++ "b" ++ ... ---> nc = "a" ++ k
size_t cIndex = index;
Node stra = nfc.collectConstantStringAt(cIndex);
- size_t straLen = Word::getLength(stra);
Assert(!stra.isNull());
Node strb = nextConstStr;
- // Since `nc` is non-empty, we start with character 1
- size_t p;
- if (isRev)
- {
- Node stra1 = Word::prefix(stra, straLen - 1);
- p = straLen - Word::roverlap(stra1, strb);
- Trace("strings-csp-debug")
- << "Compute roverlap : " << stra1 << " " << strb << std::endl;
- size_t p2 = Word::rfind(stra1, strb);
- p = p2 == std::string::npos ? p : (p > p2 + 1 ? p2 + 1 : p);
- Trace("strings-csp-debug")
- << "roverlap : " << stra1 << " " << strb << " returned " << p
- << " " << p2 << " " << (p2 == std::string::npos) << std::endl;
- }
- else
- {
- Node stra1 = Word::substr(stra, 1);
- p = straLen - Word::overlap(stra1, strb);
- Trace("strings-csp-debug")
- << "Compute overlap : " << stra1 << " " << strb << std::endl;
- size_t p2 = Word::find(stra1, strb);
- p = p2 == std::string::npos ? p : (p > p2 + 1 ? p2 + 1 : p);
- Trace("strings-csp-debug")
- << "overlap : " << stra1 << " " << strb << " returned " << p
- << " " << p2 << " " << (p2 == std::string::npos) << std::endl;
- }
+
+ // Since `nc` is non-empty, we use the non-empty overlap
+ size_t p = getSufficientNonEmptyOverlap(stra, strb, isRev);
// If we can't split off more than a single character from the
// constant, we might as well do regular constant/non-constant
@@ -1407,22 +1574,18 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
{
NormalForm::getExplanationForPrefixEq(
nfc, nfnc, cIndex, ncIndex, iinfo.d_ant);
- Node prea = p == straLen ? stra
- : (isRev ? Word::suffix(stra, p)
- : Word::prefix(stra, p));
+ iinfo.d_ant.push_back(expNonEmpty);
+ // make the conclusion
SkolemCache* skc = d_termReg.getSkolemCache();
- Node sk = skc->mkSkolemCached(
- nc,
- prea,
- isRev ? SkolemCache::SK_ID_C_SPT_REV : SkolemCache::SK_ID_C_SPT,
- "c_spt");
- Trace("strings-csp")
- << "Const Split: " << prea << " is removed from " << stra
- << " due to " << strb << ", p=" << p << std::endl;
- iinfo.d_conc = nc.eqNode(isRev ? utils::mkNConcat(sk, prea)
- : utils::mkNConcat(prea, sk));
- iinfo.d_new_skolem[LENGTH_SPLIT].push_back(sk);
+ Node xcv =
+ nm->mkNode(STRING_CONCAT, isRev ? strb : nc, isRev ? nc : strb);
+ std::vector<Node> newSkolems;
+ iinfo.d_conc = getConclusion(
+ xcv, stra, PfRule::CONCAT_CPROP, isRev, skc, newSkolems);
+ Assert(newSkolems.size() == 1);
+ iinfo.d_new_skolem[LENGTH_SPLIT].push_back(newSkolems[0]);
iinfo.d_id = Inference::SSPLIT_CST_PROP;
+ iinfo.d_idRev = isRev;
pinfer.push_back(info);
break;
}
@@ -1432,25 +1595,17 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
// to start with the first character of the constant.
//
// E.g. "abc" ++ ... = nc ++ ... ---> nc = "a" ++ k
- Node stra = nfcv[index];
- size_t straLen = Word::getLength(stra);
- Node firstChar = straLen == 1 ? stra
- : (isRev ? Word::suffix(stra, 1)
- : Word::prefix(stra, 1));
SkolemCache* skc = d_termReg.getSkolemCache();
- Node sk = skc->mkSkolemCached(
- nc,
- isRev ? SkolemCache::SK_ID_VC_SPT_REV : SkolemCache::SK_ID_VC_SPT,
- "c_spt");
- Trace("strings-csp") << "Const Split: " << firstChar
- << " is removed from " << stra << " (serial) "
- << std::endl;
+ std::vector<Node> newSkolems;
+ iinfo.d_conc = getConclusion(
+ nc, nfcv[index], PfRule::CONCAT_CSPLIT, isRev, skc, newSkolems);
NormalForm::getExplanationForPrefixEq(
nfi, nfj, index, index, iinfo.d_ant);
- iinfo.d_conc = nc.eqNode(isRev ? utils::mkNConcat(sk, firstChar)
- : utils::mkNConcat(firstChar, sk));
- iinfo.d_new_skolem[LENGTH_SPLIT].push_back(sk);
+ iinfo.d_ant.push_back(expNonEmpty);
+ Assert(newSkolems.size() == 1);
+ iinfo.d_new_skolem[LENGTH_SPLIT].push_back(newSkolems[0]);
iinfo.d_id = Inference::SSPLIT_CST;
+ iinfo.d_idRev = isRev;
pinfer.push_back(info);
break;
}
@@ -1465,7 +1620,7 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
Assert(!y.isConst());
int32_t lentTestSuccess = -1;
- Node lentTestExp;
+ Node lenConstraint;
if (options::stringCheckEntailLen())
{
// If length entailment checks are enabled, we can save the case split by
@@ -1489,54 +1644,81 @@ void CoreSolver::processSimpleNEq(NormalForm& nfi,
Trace("strings-entail")
<< " explanation was : " << et.second << std::endl;
lentTestSuccess = e;
- lentTestExp = et.second;
+ lenConstraint = entLit;
+ // Its not explained by the equality engine of this class, so its
+ // marked as not being explained. The length constraint is
+ // additionally being saved and added to the length constraint
+ // vector lcVec below, which is added to iinfo.d_ant below. Length
+ // constraints are being added as the last antecedant for the sake
+ // of proof reconstruction, which expect length constraints to come
+ // last.
+ iinfo.d_noExplain.push_back(lenConstraint);
break;
}
}
}
}
+ // lcVec stores the length constraint portion of the antecedant.
+ std::vector<Node> lcVec;
+ if (lenConstraint.isNull())
+ {
+ // will do split on length
+ lenConstraint = nm->mkNode(EQUAL, xLenTerm, yLenTerm).negate();
+ lcVec.push_back(lenConstraint);
+ }
+ else
+ {
+ utils::flattenOp(AND, lenConstraint, lcVec);
+ }
NormalForm::getExplanationForPrefixEq(nfi, nfj, index, index, iinfo.d_ant);
// Add premises for x != "" ^ y != ""
for (unsigned xory = 0; xory < 2; xory++)
{
Node t = xory == 0 ? x : y;
- Node tnz = d_state.explainNonEmpty(x);
+ Node tnz = d_state.explainNonEmpty(t);
if (!tnz.isNull())
{
- iinfo.d_ant.push_back(tnz);
+ lcVec.push_back(tnz);
}
else
{
tnz = x.eqNode(emp).negate();
- iinfo.d_antn.push_back(tnz);
+ lcVec.push_back(tnz);
+ iinfo.d_noExplain.push_back(tnz);
}
}
SkolemCache* skc = d_termReg.getSkolemCache();
- Node sk = skc->mkSkolemCached(x,
- y,
- isRev ? SkolemCache::SK_ID_V_UNIFIED_SPT_REV
- : SkolemCache::SK_ID_V_UNIFIED_SPT,
- "v_spt");
- iinfo.d_new_skolem[LENGTH_GEQ_ONE].push_back(sk);
- Node eq1 =
- x.eqNode(isRev ? utils::mkNConcat(sk, y) : utils::mkNConcat(y, sk));
- Node eq2 =
- y.eqNode(isRev ? utils::mkNConcat(sk, x) : utils::mkNConcat(x, sk));
-
- if (lentTestSuccess != -1)
- {
- iinfo.d_antn.push_back(lentTestExp);
- iinfo.d_conc = lentTestSuccess == 0 ? eq1 : eq2;
+ std::vector<Node> newSkolems;
+ // make the conclusion
+ if (lentTestSuccess == -1)
+ {
+ iinfo.d_id = Inference::SSPLIT_VAR;
+ iinfo.d_conc =
+ getConclusion(x, y, PfRule::CONCAT_SPLIT, isRev, skc, newSkolems);
+ if (options::stringUnifiedVSpt() && !options::stringLenConc())
+ {
+ Assert(newSkolems.size() == 1);
+ iinfo.d_new_skolem[LENGTH_GEQ_ONE].push_back(newSkolems[0]);
+ }
+ }
+ else if (lentTestSuccess == 0)
+ {
iinfo.d_id = Inference::SSPLIT_VAR_PROP;
+ iinfo.d_conc =
+ getConclusion(x, y, PfRule::CONCAT_LPROP, isRev, skc, newSkolems);
}
else
{
- Node ldeq = nm->mkNode(EQUAL, xLenTerm, yLenTerm).negate();
- iinfo.d_ant.push_back(ldeq);
- iinfo.d_conc = nm->mkNode(OR, eq1, eq2);
- iinfo.d_id = Inference::SSPLIT_VAR;
+ Assert(lentTestSuccess == 1);
+ iinfo.d_id = Inference::SSPLIT_VAR_PROP;
+ iinfo.d_conc =
+ getConclusion(y, x, PfRule::CONCAT_LPROP, isRev, skc, newSkolems);
}
+ // add the length constraint(s) as the last antecedant
+ Node lc = utils::mkAnd(lcVec);
+ iinfo.d_ant.push_back(lc);
+ iinfo.d_idRev = isRev;
pinfer.push_back(info);
break;
}
@@ -1642,7 +1824,8 @@ CoreSolver::ProcessLoopResult CoreSolver::processLoop(NormalForm& nfi,
{
Trace("strings-loop") << "Strings::Loop: tails are different."
<< std::endl;
- d_im.sendInference(iinfo.d_ant, conc, Inference::FLOOP_CONFLICT, true);
+ d_im.sendInference(
+ iinfo.d_ant, conc, Inference::FLOOP_CONFLICT, false, true);
return ProcessLoopResult::CONFLICT;
}
}
@@ -1659,6 +1842,8 @@ CoreSolver::ProcessLoopResult CoreSolver::processLoop(NormalForm& nfi,
Node expNonEmpty = d_state.explainNonEmpty(t);
if (expNonEmpty.isNull())
{
+ // no antecedants necessary
+ iinfo.d_ant.clear();
// try to make t equal to empty to avoid loop
iinfo.d_conc = nm->mkNode(kind::OR, split_eq, split_eq.negate());
iinfo.d_id = Inference::LEN_SPLIT_EMP;
@@ -1675,10 +1860,6 @@ CoreSolver::ProcessLoopResult CoreSolver::processLoop(NormalForm& nfi,
}
}
- Node ant = d_im.mkExplain(iinfo.d_ant);
- iinfo.d_ant.clear();
- iinfo.d_antn.push_back(ant);
-
Node str_in_re;
if (s_zy == t_yz && r == emp && s_zy.isConst()
&& s_zy.getConst<String>().isRepeated())
@@ -1922,32 +2103,30 @@ void CoreSolver::processDeq(Node ni, Node nj)
{
// Either `x` or `y` is a constant and it is not know whether the
// non-empty non-constant is of length one. We split the non-constant
- // into a string of length one and the remainder and split on whether
- // the first character of the constant and the non-constant are
- // equal.
+ // into a string of length one and the remainder.
//
- // E.g. x ++ x' ++ ... != "abc" ++ y' ++ ... ^ len(x) != "" --->
- // x = k1 ++ k2 ^ len(k1) = 1 ^ (k1 != "a" v x = "a" ++ k2)
+ // len(x)>=1 => x = k1 ++ k2 ^ len(k1) = 1
SkolemCache* skc = d_termReg.getSkolemCache();
- Node sk =
- skc->mkSkolemCached(nck, SkolemCache::SK_ID_DC_SPT, "dc_spt");
- d_termReg.registerTermAtomic(sk, LENGTH_ONE);
- Node skr = skc->mkSkolemCached(
- nck, SkolemCache::SK_ID_DC_SPT_REM, "dc_spt_rem");
- Node eq1 = nck.eqNode(nm->mkNode(kind::STRING_CONCAT, sk, skr));
- eq1 = Rewriter::rewrite(eq1);
- Node eq2 =
- nck.eqNode(nm->mkNode(kind::STRING_CONCAT, firstChar, skr));
- std::vector<Node> antec(nfni.d_exp.begin(), nfni.d_exp.end());
- antec.insert(antec.end(), nfnj.d_exp.begin(), nfnj.d_exp.end());
- antec.push_back(expNonEmpty);
- d_im.sendInference(
- antec,
- nm->mkNode(
- OR, nm->mkNode(AND, eq1, sk.eqNode(firstChar).negate()), eq2),
- Inference::DEQ_DISL_FIRST_CHAR_STRING_SPLIT,
- true);
- d_im.sendPhaseRequirement(eq1, true);
+ std::vector<Node> newSkolems;
+ Node conc = getDecomposeConclusion(
+ nck, d_one, false, options::stringLenConc(), skc, newSkolems);
+ Assert(newSkolems.size() == 2);
+ if (options::stringLenConc())
+ {
+ d_termReg.registerTermAtomic(newSkolems[0], LENGTH_IGNORE);
+ }
+ else
+ {
+ d_termReg.registerTermAtomic(newSkolems[0], LENGTH_ONE);
+ }
+ std::vector<Node> antecLen;
+ antecLen.push_back(nm->mkNode(GEQ, nckLenTerm, d_one));
+ d_im.sendInference(antecLen,
+ antecLen,
+ conc,
+ Inference::DEQ_DISL_FIRST_CHAR_STRING_SPLIT,
+ false,
+ true);
return;
}
}
@@ -1957,47 +2136,44 @@ void CoreSolver::processDeq(Node ni, Node nj)
// are both non-constants. We split them into parts that have the same
// lengths.
//
- // E.g. x ++ x' ++ ... != y ++ y' ++ ... ^ len(x) != len(y) --->
- // len(k1) = len(x) ^ len(k2) = len(y) ^
- // (y = k1 ++ k3 v x = k1 ++ k2)
- Trace("strings-solve") << "Non-Simple Case 1 : add lemma " << std::endl;
- std::vector<Node> antec(nfni.d_exp.begin(), nfni.d_exp.end());
- antec.insert(antec.end(), nfnj.d_exp.begin(), nfnj.d_exp.end());
- std::vector<Node> antecNewLits;
-
- if (d_state.areDisequal(ni, nj))
- {
- antec.push_back(ni.eqNode(nj).negate());
- }
- else
+ // len(x) > len(y) => x = k1 ++ k2 ^ len(k1) = len(y)
+ // len(y) > len(x) => y = k3 ++ k4 ^ len(k3) = len(x)
+ Trace("strings-solve")
+ << "Non-Simple Case 1 : add lemmas " << std::endl;
+ SkolemCache* skc = d_termReg.getSkolemCache();
+
+ for (unsigned r = 0; r < 2; r++)
{
- antecNewLits.push_back(ni.eqNode(nj).negate());
+ Node ux = r == 0 ? x : y;
+ Node uy = r == 0 ? y : x;
+ Node uxLen = nm->mkNode(STRING_LENGTH, ux);
+ Node uyLen = nm->mkNode(STRING_LENGTH, uy);
+ // We always request the length constraint in the conclusion here
+ // because the skolem needs to have length `uyLen`. If we only assert
+ // that the skolem's length is greater or equal to one, we can end up
+ // in a loop:
+ //
+ // 1. Split: x = k1 ++ k2 ^ len(k1) >= 1
+ // 2. Assume: k2 = ""
+ // 3. Deduce: x = k1
+ //
+ // After step 3, `k1` is marked congruent because `x` is the older
+ // variable. So we get `x` in the normal form again.
+ std::vector<Node> newSkolems;
+ Node conc =
+ getDecomposeConclusion(ux, uyLen, false, true, skc, newSkolems);
+ Assert(newSkolems.size() == 2);
+ d_termReg.registerTermAtomic(newSkolems[1], LENGTH_GEQ_ONE);
+ std::vector<Node> antecLen;
+ antecLen.push_back(nm->mkNode(GT, uxLen, uyLen));
+ d_im.sendInference(antecLen,
+ antecLen,
+ conc,
+ Inference::DEQ_DISL_STRINGS_SPLIT,
+ false,
+ true);
}
- antecNewLits.push_back(xLenTerm.eqNode(yLenTerm).negate());
- std::vector<Node> conc;
- SkolemCache* skc = d_termReg.getSkolemCache();
- Node sk1 =
- skc->mkSkolemCached(x, y, SkolemCache::SK_ID_DEQ_X, "x_dsplit");
- Node sk2 =
- skc->mkSkolemCached(x, y, SkolemCache::SK_ID_DEQ_Y, "y_dsplit");
- Node sk3 =
- skc->mkSkolemCached(y, x, SkolemCache::SK_ID_V_SPT, "z_dsplit");
- Node sk4 =
- skc->mkSkolemCached(x, y, SkolemCache::SK_ID_V_SPT, "w_dsplit");
- d_termReg.registerTermAtomic(sk3, LENGTH_GEQ_ONE);
- Node sk1Len = utils::mkNLength(sk1);
- conc.push_back(sk1Len.eqNode(xLenTerm));
- Node sk2Len = utils::mkNLength(sk2);
- conc.push_back(sk2Len.eqNode(yLenTerm));
- conc.push_back(nm->mkNode(OR,
- y.eqNode(utils::mkNConcat(sk1, sk3)),
- x.eqNode(utils::mkNConcat(sk2, sk4))));
- d_im.sendInference(antec,
- antecNewLits,
- nm->mkNode(AND, conc),
- Inference::DEQ_DISL_STRINGS_SPLIT,
- true);
return;
}
}
@@ -2090,7 +2266,7 @@ bool CoreSolver::processSimpleDeq(std::vector<Node>& nfi,
Node conc = cc.size() == 1
? cc[0]
: NodeManager::currentNM()->mkNode(kind::AND, cc);
- d_im.sendInference(ant, conc, Inference::DEQ_NORM_EMP, true);
+ d_im.sendInference(ant, conc, Inference::DEQ_NORM_EMP, isRev, true);
return true;
}
@@ -2366,16 +2542,16 @@ void CoreSolver::checkLengthsEqc() {
// if not, add the lemma
std::vector<Node> ant;
ant.insert(ant.end(), nfi.d_exp.begin(), nfi.d_exp.end());
- ant.push_back(nfi.d_base.eqNode(lt));
+ ant.push_back(lt.eqNode(nfi.d_base));
Node lc = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, nf);
Node lcr = Rewriter::rewrite(lc);
Trace("strings-process-debug")
<< "Rewrote length " << lc << " to " << lcr << std::endl;
if (!d_state.areEqual(llt, lcr))
{
- Node eq = llt.eqNode(lcr);
+ Node eq = llt.eqNode(lc);
ei->d_normalizedLength.set(eq);
- d_im.sendInference(ant, eq, Inference::LEN_NORM, true);
+ d_im.sendInference(ant, eq, Inference::LEN_NORM, false, true);
}
}
}
@@ -2385,9 +2561,9 @@ bool CoreSolver::processInferInfo(CoreInferInfo& cii)
{
InferInfo& ii = cii.d_infer;
// rewrite the conclusion, ensure non-trivial
- ii.d_conc = Rewriter::rewrite(ii.d_conc);
+ Node concr = Rewriter::rewrite(ii.d_conc);
- if (ii.isTrivial())
+ if (concr == d_true)
{
// conclusion rewrote to true
return false;
@@ -2401,7 +2577,8 @@ bool CoreSolver::processInferInfo(CoreInferInfo& cii)
// send phase requirements
for (const std::pair<const Node, bool>& pp : cii.d_pendingPhase)
{
- d_im.sendPhaseRequirement(pp.first, pp.second);
+ Node ppr = Rewriter::rewrite(pp.first);
+ d_im.addPendingPhaseRequirement(ppr, pp.second);
}
// send the inference, which is a lemma
diff --git a/src/theory/strings/core_solver.h b/src/theory/strings/core_solver.h
index db1f5ecf6..b1c302935 100644
--- a/src/theory/strings/core_solver.h
+++ b/src/theory/strings/core_solver.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -81,9 +81,7 @@ class CoreSolver
typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
public:
- CoreSolver(context::Context* c,
- context::UserContext* u,
- SolverState& s,
+ CoreSolver(SolverState& s,
InferenceManager& im,
TermRegistry& tr,
BaseSolver& bs);
@@ -219,6 +217,67 @@ class CoreSolver
*/
Node getNormalString(Node x, std::vector<Node>& nf_exp);
//-------------------------- end query functions
+
+ /**
+ * This returns the conclusion of the proof rule corresponding to splitting
+ * on the arrangement of terms x and y appearing in an equation of the form
+ * x ++ x' = y ++ y' or x' ++ x = y' ++ y
+ * where we are in the second case if isRev is true. This method is called
+ * both by the core solver and by the strings proof checker.
+ *
+ * @param x The first term
+ * @param y The second term
+ * @param rule The proof rule whose conclusion we are asking for
+ * @param isRev Whether the equation is in a reverse direction
+ * @param skc The skolem cache (to allocate fresh variables if necessary)
+ * @param newSkolems The vector to add new variables to
+ * @return The conclusion of the inference.
+ */
+ static Node getConclusion(Node x,
+ Node y,
+ PfRule rule,
+ bool isRev,
+ SkolemCache* skc,
+ std::vector<Node>& newSkolems);
+ /**
+ * Get sufficient non-empty overlap of string constants c and d.
+ *
+ * This is called when handling equations of the form:
+ * x ++ d ++ ... = c ++ ...
+ * when x is non-empty and non-constant.
+ *
+ * This returns the maximal index in c which x must have as a prefix, which
+ * notice is an integer >= 1 since x is non-empty.
+ *
+ * @param c The first constant
+ * @param d The second constant
+ * @param isRev Whether the equation is in the reverse direction
+ * @return The position in c.
+ */
+ static size_t getSufficientNonEmptyOverlap(Node c, Node d, bool isRev);
+ /**
+ * This returns the conclusion of the decompose proof rule. This returns
+ * a conjunction of splitting string x into pieces based on length l, e.g.:
+ * x = k_1 ++ k_2
+ * where k_1 (resp. k_2) is a skolem corresponding to a substring of x of
+ * length l if isRev is false (resp. true). The function optionally adds a
+ * length constraint len(k_1) = l (resp. len(k_2) = l).
+ *
+ * @param x The string term
+ * @param l The length term
+ * @param isRev Whether the equation is in a reverse direction
+ * @param addLenConc Whether to add the length constraint
+ * @param skc The skolem cache (to allocate fresh variables if necessary)
+ * @param newSkolems The vector to add new variables to
+ * @return The conclusion of the inference.
+ */
+ static Node getDecomposeConclusion(Node x,
+ Node l,
+ bool isRev,
+ bool addLenConc,
+ SkolemCache* skc,
+ std::vector<Node>& newSkolems);
+
private:
/**
* This processes the infer info ii as an inference. In more detail, it calls
diff --git a/src/theory/strings/eqc_info.cpp b/src/theory/strings/eqc_info.cpp
index 31d7f8b01..45062c59a 100644
--- a/src/theory/strings/eqc_info.cpp
+++ b/src/theory/strings/eqc_info.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/eqc_info.h b/src/theory/strings/eqc_info.h
index 108264969..c76102cbc 100644
--- a/src/theory/strings/eqc_info.h
+++ b/src/theory/strings/eqc_info.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/extf_solver.cpp b/src/theory/strings/extf_solver.cpp
index 9b1b0e6dd..7e416d132 100644
--- a/src/theory/strings/extf_solver.cpp
+++ b/src/theory/strings/extf_solver.cpp
@@ -2,10 +2,10 @@
/*! \file extf_solver.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Andres Noetzli, Tianyi Liang
+ ** Andrew Reynolds, Tianyi Liang, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -27,9 +27,7 @@ namespace CVC4 {
namespace theory {
namespace strings {
-ExtfSolver::ExtfSolver(context::Context* c,
- context::UserContext* u,
- SolverState& s,
+ExtfSolver::ExtfSolver(SolverState& s,
InferenceManager& im,
TermRegistry& tr,
StringsRewriter& rewriter,
@@ -45,10 +43,10 @@ ExtfSolver::ExtfSolver(context::Context* c,
d_csolver(cs),
d_extt(et),
d_statistics(statistics),
- d_preproc(d_termReg.getSkolemCache(), u, statistics),
- d_hasExtf(c, false),
- d_extfInferCache(c),
- d_reduced(u)
+ d_preproc(d_termReg.getSkolemCache(), s.getUserContext(), statistics),
+ d_hasExtf(s.getSatContext(), false),
+ d_extfInferCache(s.getSatContext()),
+ d_reduced(s.getUserContext())
{
d_extt.addFunctionKind(kind::STRING_SUBSTR);
d_extt.addFunctionKind(kind::STRING_UPDATE);
@@ -67,6 +65,7 @@ ExtfSolver::ExtfSolver(context::Context* c,
d_extt.addFunctionKind(kind::STRING_TOUPPER);
d_extt.addFunctionKind(kind::STRING_REV);
d_extt.addFunctionKind(kind::SEQ_UNIT);
+ d_extt.addFunctionKind(kind::SEQ_NTH);
d_true = NodeManager::currentNM()->mkConst(true);
d_false = NodeManager::currentNM()->mkConst(false);
@@ -74,17 +73,21 @@ ExtfSolver::ExtfSolver(context::Context* c,
ExtfSolver::~ExtfSolver() {}
+void ExtfSolver::addSharedTerm(TNode n) { d_extt.registerTermRec(n); }
+
bool ExtfSolver::doReduction(int effort, Node n)
{
Assert(d_extfInfoTmp.find(n) != d_extfInfoTmp.end());
if (!d_extfInfoTmp[n].d_modelActive)
{
// n is not active in the model, no need to reduce
+ Trace("strings-extf-debug") << "...skip due to model active" << std::endl;
return false;
}
if (d_reduced.find(n)!=d_reduced.end())
{
// already sent a reduction lemma
+ Trace("strings-extf-debug") << "...skip due to reduced" << std::endl;
return false;
}
// determine the effort level to process the extf at
@@ -126,7 +129,8 @@ bool ExtfSolver::doReduction(int effort, Node n)
lexp.push_back(lenx.eqNode(lens));
lexp.push_back(n.negate());
Node xneqs = x.eqNode(s).negate();
- d_im.sendInference(lexp, xneqs, Inference::CTN_NEG_EQUAL, true);
+ d_im.sendInference(
+ lexp, xneqs, Inference::CTN_NEG_EQUAL, false, true);
}
// this depends on the current assertions, so this
// inference is context-dependent
@@ -155,6 +159,8 @@ bool ExtfSolver::doReduction(int effort, Node n)
}
if (effort != r_effort)
{
+
+ Trace("strings-extf-debug") << "...skip due to effort" << std::endl;
// not the right effort level to reduce
return false;
}
@@ -167,12 +173,13 @@ bool ExtfSolver::doReduction(int effort, Node n)
Node s = n[1];
// positive contains reduces to a equality
SkolemCache* skc = d_termReg.getSkolemCache();
- Node sk1 = skc->mkSkolemCached(x, s, SkolemCache::SK_FIRST_CTN_PRE, "sc1");
- Node sk2 = skc->mkSkolemCached(x, s, SkolemCache::SK_FIRST_CTN_POST, "sc2");
- Node eq = Rewriter::rewrite(x.eqNode(utils::mkNConcat(sk1, s, sk2)));
- std::vector<Node> exp_vec;
- exp_vec.push_back(n);
- d_im.sendInference(d_emptyVec, exp_vec, eq, Inference::CTN_POS, true);
+ Node eq = d_termReg.eagerReduce(n, skc);
+ Assert(!eq.isNull());
+ Assert(eq.getKind() == ITE && eq[0] == n);
+ eq = eq[1];
+ std::vector<Node> expn;
+ expn.push_back(n);
+ d_im.sendInference(expn, expn, eq, Inference::CTN_POS, false, true);
Trace("strings-extf-debug")
<< " resolve extf : " << n << " based on positive contain reduction."
<< std::endl;
@@ -186,21 +193,22 @@ bool ExtfSolver::doReduction(int effort, Node n)
NodeManager* nm = NodeManager::currentNM();
Assert(k == STRING_SUBSTR || k == STRING_UPDATE || k == STRING_STRCTN
|| k == STRING_STRIDOF || k == STRING_ITOS || k == STRING_STOI
- || k == STRING_STRREPL || k == STRING_STRREPLALL
+ || k == STRING_STRREPL || k == STRING_STRREPLALL || k == SEQ_NTH
|| k == STRING_REPLACE_RE || k == STRING_REPLACE_RE_ALL
|| k == STRING_LEQ || k == STRING_TOLOWER || k == STRING_TOUPPER
|| k == STRING_REV);
std::vector<Node> new_nodes;
Node res = d_preproc.simplify(n, new_nodes);
Assert(res != n);
- new_nodes.push_back(res.eqNode(n));
+ new_nodes.push_back(n.eqNode(res));
Node nnlem =
new_nodes.size() == 1 ? new_nodes[0] : nm->mkNode(AND, new_nodes);
- nnlem = Rewriter::rewrite(nnlem);
Trace("strings-red-lemma")
<< "Reduction_" << effort << " lemma : " << nnlem << std::endl;
Trace("strings-red-lemma") << "...from " << n << std::endl;
- d_im.sendInference(d_emptyVec, nnlem, Inference::REDUCTION, true);
+ Trace("strings-red-lemma")
+ << "Reduction_" << effort << " rewritten : " << Rewriter::rewrite(nnlem) << std::endl;
+ d_im.sendInference(d_emptyVec, nnlem, Inference::REDUCTION, false, true);
Trace("strings-extf-debug")
<< " resolve extf : " << n << " based on reduction." << std::endl;
// add as reduction lemma
@@ -275,7 +283,8 @@ void ExtfSolver::checkExtfEval(int effort)
}
// If there is information involving the children, attempt to do an
// inference and/or mark n as reduced.
- Node to_reduce;
+ bool reduced = false;
+ Node to_reduce = n;
if (schanged)
{
Node sn = nm->mkNode(n.getKind(), schildren);
@@ -381,13 +390,8 @@ void ExtfSolver::checkExtfEval(int effort)
Trace("strings-extf")
<< " resolve extf : " << sn << " -> " << nrc << std::endl;
Inference inf = effort == 0 ? Inference::EXTF : Inference::EXTF_N;
- d_im.sendInference(einfo.d_exp, conc, inf, true);
+ d_im.sendInference(einfo.d_exp, conc, inf, false, true);
d_statistics.d_cdSimplifications << n.getKind();
- if (d_state.isInConflict())
- {
- Trace("strings-extf-debug") << " conflict, return." << std::endl;
- return;
- }
}
}
else
@@ -402,6 +406,7 @@ void ExtfSolver::checkExtfEval(int effort)
einfo.d_modelActive = false;
}
}
+ reduced = true;
}
else
{
@@ -425,28 +430,26 @@ void ExtfSolver::checkExtfEval(int effort)
effort == 0 ? Inference::EXTF_D : Inference::EXTF_D_N;
d_im.sendInternalInference(einfo.d_exp, nrcAssert, infer);
}
- // We must use the original n here to avoid circular justifications for
- // why extended functions are reduced below. In particular, to_reduce
- // should never be a duplicate of another term considered in the block
- // of code for checkExtfInference below.
- to_reduce = n;
+ to_reduce = nrc;
}
}
- else
- {
- to_reduce = n;
- }
+ // We must use the original n here to avoid circular justifications for
+ // why extended functions are reduced. In particular, n should never be a
+ // duplicate of another term considered in the block of code for
+ // checkExtfInference below.
// if not reduced and not processed
- if (!to_reduce.isNull()
- && inferProcessed.find(to_reduce) == inferProcessed.end())
+ if (!reduced && !n.isNull()
+ && inferProcessed.find(n) == inferProcessed.end())
{
- inferProcessed.insert(to_reduce);
+ inferProcessed.insert(n);
Assert(effort < 3);
if (effort == 1)
{
Trace("strings-extf")
<< " cannot rewrite extf : " << to_reduce << std::endl;
}
+ // we take to_reduce to be the (partially) reduced version of n, which
+ // is justified by the explanation in einfo.
checkExtfInference(n, to_reduce, einfo, effort);
if (Trace.isOn("strings-extf-list"))
{
@@ -466,6 +469,11 @@ void ExtfSolver::checkExtfEval(int effort)
has_nreduce = true;
}
}
+ if (d_state.isInConflict())
+ {
+ Trace("strings-extf-debug") << " conflict, return." << std::endl;
+ return;
+ }
}
d_hasExtf = has_nreduce;
}
@@ -623,13 +631,13 @@ void ExtfSolver::checkExtfInference(Node n,
}
else
{
- // If we already know that s (does not) contain t, then n is redundant.
- // For example, if str.contains( x, y ), str.contains( z, y ), and x=z
- // are asserted in the current context, then str.contains( z, y ) is
- // satisfied by all models of str.contains( x, y ) ^ x=z and thus can
- // be ignored.
+ // If we already know that s (does not) contain t, then n may be
+ // redundant. However, we do not mark n as reduced here, since strings
+ // reductions may require dependencies between extended functions.
+ // Marking reduced here could lead to incorrect models if an
+ // extended function is marked reduced based on an assignment to
+ // something that depends on n.
Trace("strings-extf-debug") << " redundant." << std::endl;
- d_extt.markReduced(n);
}
}
return;
@@ -699,6 +707,23 @@ std::vector<Node> ExtfSolver::getActive(Kind k) const
return d_extt.getActive(k);
}
+bool StringsExtfCallback::getCurrentSubstitution(
+ int effort,
+ const std::vector<Node>& vars,
+ std::vector<Node>& subs,
+ std::map<Node, std::vector<Node> >& exp)
+{
+ Trace("strings-subs") << "getCurrentSubstitution, effort = " << effort
+ << std::endl;
+ for (const Node& v : vars)
+ {
+ Trace("strings-subs") << " get subs for " << v << "..." << std::endl;
+ Node s = d_esolver->getCurrentSubstitutionFor(effort, v, exp[v]);
+ subs.push_back(s);
+ }
+ return true;
+}
+
} // namespace strings
} // namespace theory
} // namespace CVC4
diff --git a/src/theory/strings/extf_solver.h b/src/theory/strings/extf_solver.h
index d99a881f6..df0a7ccb5 100644
--- a/src/theory/strings/extf_solver.h
+++ b/src/theory/strings/extf_solver.h
@@ -2,10 +2,10 @@
/*! \file extf_solver.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Andres Noetzli
+ ** Andrew Reynolds, Andres Noetzli, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -83,9 +83,7 @@ class ExtfSolver
typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
public:
- ExtfSolver(context::Context* c,
- context::UserContext* u,
- SolverState& s,
+ ExtfSolver(SolverState& s,
InferenceManager& im,
TermRegistry& tr,
StringsRewriter& rewriter,
@@ -95,6 +93,11 @@ class ExtfSolver
SequencesStatistics& statistics);
~ExtfSolver();
+ /**
+ * Called when a shared term is added to theory of strings, this registers
+ * n with the extended theory utility for context-depdendent simplification.
+ */
+ void addSharedTerm(TNode n);
/** check extended functions evaluation
*
* This applies "context-dependent simplification" for all active extended
@@ -211,6 +214,23 @@ class ExtfSolver
NodeSet d_reduced;
};
+/** An extended theory callback */
+class StringsExtfCallback : public ExtTheoryCallback
+{
+ public:
+ StringsExtfCallback() : d_esolver(nullptr) {}
+ /**
+ * Get current substitution based on the underlying extended function
+ * solver.
+ */
+ bool getCurrentSubstitution(int effort,
+ const std::vector<Node>& vars,
+ std::vector<Node>& subs,
+ std::map<Node, std::vector<Node> >& exp) override;
+ /** The extended function solver */
+ ExtfSolver* d_esolver;
+};
+
} // namespace strings
} // namespace theory
} // namespace CVC4
diff --git a/src/theory/strings/infer_info.cpp b/src/theory/strings/infer_info.cpp
index c75e03440..0d2f94f91 100644
--- a/src/theory/strings/infer_info.cpp
+++ b/src/theory/strings/infer_info.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,6 +14,9 @@
#include "theory/strings/infer_info.h"
+#include "theory/strings/inference_manager.h"
+#include "theory/strings/theory_strings_utils.h"
+
namespace CVC4 {
namespace theory {
namespace strings {
@@ -85,6 +88,7 @@ const char* toString(Inference i)
case Inference::CTN_NEG_EQUAL: return "CTN_NEG_EQUAL";
case Inference::CTN_POS: return "CTN_POS";
case Inference::REDUCTION: return "REDUCTION";
+ case Inference::PREFIX_CONFLICT: return "PREFIX_CONFLICT";
default: return "?";
}
}
@@ -95,7 +99,18 @@ std::ostream& operator<<(std::ostream& out, Inference i)
return out;
}
-InferInfo::InferInfo() : d_id(Inference::NONE) {}
+InferInfo::InferInfo() : d_sim(nullptr), d_id(Inference::NONE), d_idRev(false)
+{
+}
+
+bool InferInfo::process(TheoryInferenceManager* im, bool asLemma)
+{
+ if (asLemma)
+ {
+ return d_sim->processLemma(*this);
+ }
+ return d_sim->processFact(*this);
+}
bool InferInfo::isTrivial() const
{
@@ -106,26 +121,36 @@ bool InferInfo::isTrivial() const
bool InferInfo::isConflict() const
{
Assert(!d_conc.isNull());
- return d_conc.isConst() && !d_conc.getConst<bool>() && d_antn.empty();
+ return d_conc.isConst() && !d_conc.getConst<bool>() && d_noExplain.empty();
}
bool InferInfo::isFact() const
{
Assert(!d_conc.isNull());
TNode atom = d_conc.getKind() == kind::NOT ? d_conc[0] : d_conc;
- return !atom.isConst() && atom.getKind() != kind::OR && d_antn.empty();
+ return !atom.isConst() && atom.getKind() != kind::OR && d_noExplain.empty();
+}
+
+Node InferInfo::getAntecedant() const
+{
+ // d_noExplain is a subset of d_ant
+ return utils::mkAnd(d_ant);
}
std::ostream& operator<<(std::ostream& out, const InferInfo& ii)
{
out << "(infer " << ii.d_id << " " << ii.d_conc;
+ if (ii.d_idRev)
+ {
+ out << " :rev";
+ }
if (!ii.d_ant.empty())
{
out << " :ant (" << ii.d_ant << ")";
}
- if (!ii.d_antn.empty())
+ if (!ii.d_noExplain.empty())
{
- out << " :antn (" << ii.d_antn << ")";
+ out << " :no-explain (" << ii.d_noExplain << ")";
}
out << ")";
return out;
diff --git a/src/theory/strings/infer_info.h b/src/theory/strings/infer_info.h
index 2a42b9fab..4c5674d2b 100644
--- a/src/theory/strings/infer_info.h
+++ b/src/theory/strings/infer_info.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,6 +21,7 @@
#include <vector>
#include "expr/node.h"
+#include "theory/theory_inference.h"
#include "util/safe_print.h"
namespace CVC4 {
@@ -35,9 +36,17 @@ namespace strings {
* Note: The order in this enum matters in certain cases (e.g. inferences
* related to normal forms), inferences that come first are generally
* preferred.
+ *
+ * Notice that an inference is intentionally distinct from PfRule. An
+ * inference captures *why* we performed a reasoning step, and a PfRule
+ * rule captures *what* reasoning step was used. For instance, the inference
+ * LEN_SPLIT translates to PfRule::SPLIT. The use of stats on inferences allows
+ * us to know that we performed N splits (PfRule::SPLIT) because we wanted
+ * to split on lengths for string equalities (Inference::LEN_SPLIT).
*/
enum class Inference : uint32_t
{
+ BEGIN,
//-------------------------------------- base solver
// initial normalize singular
// x1 = "" ^ ... ^ x_{i-1} = "" ^ x_{i+1} = "" ^ ... ^ xn = "" =>
@@ -295,6 +304,10 @@ enum class Inference : uint32_t
// (see theory_strings_preprocess).
REDUCTION,
//-------------------------------------- end extended function solver
+ //-------------------------------------- prefix conflict
+ // prefix conflict (coarse-grained)
+ PREFIX_CONFLICT,
+ //-------------------------------------- end prefix conflict
NONE,
};
@@ -335,18 +348,42 @@ enum LengthStatus
LENGTH_GEQ_ONE
};
+class InferenceManager;
+
/**
* An inference. This is a class to track an unprocessed call to either
* send a fact, lemma, or conflict that is waiting to be asserted to the
* equality engine or sent on the output channel.
+ *
+ * For the sake of proofs, the antecedants in InferInfo have a particular
+ * ordering for many of the core strings rules, which is expected by
+ * InferProofCons for constructing proofs of F_CONST, F_UNIFY, N_CONST, etc.
+ * which apply to a pair of string terms t and s. At a high level, the ordering
+ * expected in d_ant is:
+ * (1) (multiple) literals that explain why t and s have the same prefix/suffix,
+ * (2) t = s,
+ * (3) (optionally) a length constraint.
+ * For example, say we have:
+ * { x ++ y ++ v1 = z ++ w ++ v2, x = z ++ u, u = "", len(y) = len(w) }
+ * We can conclude y = w by the N_UNIFY rule from the left side. The antecedant
+ * has the following form:
+ * - (prefix up to y/w equal) x = z ++ u, u = "",
+ * - (main equality) x ++ y ++ v1 = z ++ w ++ v2,
+ * - (length constraint) len(y) = len(w).
*/
-class InferInfo
+class InferInfo : public TheoryInference
{
public:
InferInfo();
~InferInfo() {}
+ /** Process this inference */
+ bool process(TheoryInferenceManager* im, bool asLemma) override;
+ /** Pointer to the class used for processing this info */
+ InferenceManager* d_sim;
/** The inference identifier */
Inference d_id;
+ /** Whether it is the reverse form of the above id */
+ bool d_idRev;
/** The conclusion */
Node d_conc;
/**
@@ -357,9 +394,11 @@ class InferInfo
/**
* The "new literal" antecedant(s) of the inference, interpreted
* conjunctively. These are literals that were needed to show the conclusion
- * but do not currently hold in the equality engine.
+ * but do not currently hold in the equality engine. These should be a subset
+ * of d_ant. In other words, antecedants that are not explained are stored
+ * in *both* d_ant and d_noExplain.
*/
- std::vector<Node> d_antn;
+ std::vector<Node> d_noExplain;
/**
* A list of new skolems introduced as a result of this inference. They
* are mapped to by a length status, indicating the length constraint that
@@ -370,15 +409,17 @@ class InferInfo
bool isTrivial() const;
/**
* Does this infer info correspond to a conflict? True if d_conc is false
- * and it has no new antecedants (d_antn).
+ * and it has no new antecedants (d_noExplain).
*/
bool isConflict() const;
/**
* Does this infer info correspond to a "fact". A fact is an inference whose
* conclusion should be added as an equality or predicate to the equality
- * engine with no new external antecedants (d_antn).
+ * engine with no new external antecedants (d_noExplain).
*/
bool isFact() const;
+ /** Get antecedant */
+ Node getAntecedant() const;
};
/**
diff --git a/src/theory/strings/infer_proof_cons.cpp b/src/theory/strings/infer_proof_cons.cpp
new file mode 100644
index 000000000..66f71bf14
--- /dev/null
+++ b/src/theory/strings/infer_proof_cons.cpp
@@ -0,0 +1,1016 @@
+/********************* */
+/*! \file infer_proof_cons.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of inference to proof conversion
+ **/
+
+#include "theory/strings/infer_proof_cons.h"
+
+#include "expr/skolem_manager.h"
+#include "options/smt_options.h"
+#include "options/strings_options.h"
+#include "theory/builtin/proof_checker.h"
+#include "theory/rewriter.h"
+#include "theory/strings/regexp_operation.h"
+#include "theory/strings/theory_strings_utils.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+InferProofCons::InferProofCons(context::Context* c,
+ ProofNodeManager* pnm,
+ SequencesStatistics& statistics)
+ : d_pnm(pnm), d_lazyFactMap(c), d_statistics(statistics)
+{
+ Assert(d_pnm != nullptr);
+}
+
+void InferProofCons::notifyFact(const InferInfo& ii)
+{
+ Node fact = ii.d_conc;
+ Trace("strings-ipc-debug")
+ << "InferProofCons::notifyFact: " << ii << std::endl;
+ if (d_lazyFactMap.find(fact) != d_lazyFactMap.end())
+ {
+ Trace("strings-ipc-debug") << "...duplicate!" << std::endl;
+ return;
+ }
+ Node symFact = CDProof::getSymmFact(fact);
+ if (!symFact.isNull() && d_lazyFactMap.find(symFact) != d_lazyFactMap.end())
+ {
+ Trace("strings-ipc-debug") << "...duplicate (sym)!" << std::endl;
+ return;
+ }
+ std::shared_ptr<InferInfo> iic = std::make_shared<InferInfo>(ii);
+ d_lazyFactMap.insert(ii.d_conc, iic);
+}
+
+void InferProofCons::convert(Inference infer,
+ bool isRev,
+ Node conc,
+ const std::vector<Node>& exp,
+ ProofStep& ps,
+ TheoryProofStepBuffer& psb,
+ bool& useBuffer)
+{
+ // by default, don't use the buffer
+ useBuffer = false;
+ // Must flatten children with respect to AND to be ready to explain.
+ // We store the index where each flattened vector begins, since some
+ // explanations are grouped together using AND.
+ std::vector<size_t> startExpIndex;
+ for (const Node& ec : exp)
+ {
+ // store the index in the flattened vector
+ startExpIndex.push_back(ps.d_children.size());
+ utils::flattenOp(AND, ec, ps.d_children);
+ }
+ // debug print
+ if (Trace.isOn("strings-ipc-debug"))
+ {
+ Trace("strings-ipc-debug") << "InferProofCons::convert: " << infer
+ << (isRev ? " :rev " : " ") << conc << std::endl;
+ for (const Node& ec : exp)
+ {
+ Trace("strings-ipc-debug") << " e: " << ec << std::endl;
+ }
+ }
+ // try to find a set of proof steps to incorporate into the buffer
+ psb.clear();
+ NodeManager* nm = NodeManager::currentNM();
+ Node nodeIsRev = nm->mkConst(isRev);
+ switch (infer)
+ {
+ // ========================== equal by substitution+rewriting
+ case Inference::I_NORM_S:
+ case Inference::I_CONST_MERGE:
+ case Inference::I_NORM:
+ case Inference::LEN_NORM:
+ case Inference::NORMAL_FORM:
+ case Inference::CODE_PROXY:
+ {
+ ps.d_args.push_back(conc);
+ // will attempt this rule
+ ps.d_rule = PfRule::MACRO_SR_PRED_INTRO;
+ }
+ break;
+ // ========================== substitution + rewriting
+ case Inference::RE_NF_CONFLICT:
+ case Inference::EXTF:
+ case Inference::EXTF_N:
+ case Inference::EXTF_D:
+ case Inference::EXTF_D_N:
+ case Inference::I_CONST_CONFLICT:
+ case Inference::UNIT_CONST_CONFLICT:
+ {
+ if (!ps.d_children.empty())
+ {
+ std::vector<Node> exps(ps.d_children.begin(), ps.d_children.end() - 1);
+ Node src = ps.d_children[ps.d_children.size() - 1];
+ if (psb.applyPredTransform(src, conc, exps))
+ {
+ useBuffer = true;
+ }
+ }
+ if (!useBuffer)
+ {
+ // use the predicate version?
+ ps.d_args.push_back(conc);
+ ps.d_rule = PfRule::MACRO_SR_PRED_INTRO;
+ }
+ }
+ break;
+ // ========================== rewrite pred
+ case Inference::EXTF_EQ_REW:
+ case Inference::INFER_EMP:
+ {
+ // the last child is the predicate we are operating on, move to front
+ Node src = ps.d_children[ps.d_children.size() - 1];
+ std::vector<Node> expe(ps.d_children.begin(), ps.d_children.end() - 1);
+ // start with a default rewrite
+ Node mainEqSRew = psb.applyPredElim(src, expe);
+ if (mainEqSRew == conc)
+ {
+ useBuffer = true;
+ break;
+ }
+ // may need the "extended equality rewrite"
+ Node mainEqSRew2 = psb.applyPredElim(
+ mainEqSRew, {}, MethodId::SB_DEFAULT, MethodId::RW_REWRITE_EQ_EXT);
+ if (mainEqSRew2 == conc)
+ {
+ useBuffer = true;
+ break;
+ }
+ // rewrite again with default rewriter
+ Node mainEqSRew3 = psb.applyPredElim(mainEqSRew2, {});
+ useBuffer = (mainEqSRew3 == conc);
+ }
+ break;
+ // ========================== substitution+rewriting, CONCAT_EQ, ...
+ case Inference::F_CONST:
+ case Inference::F_UNIFY:
+ case Inference::F_ENDPOINT_EMP:
+ case Inference::F_ENDPOINT_EQ:
+ case Inference::F_NCTN:
+ case Inference::N_EQ_CONF:
+ case Inference::N_CONST:
+ case Inference::N_UNIFY:
+ case Inference::N_ENDPOINT_EMP:
+ case Inference::N_ENDPOINT_EQ:
+ case Inference::N_NCTN:
+ case Inference::SSPLIT_CST_PROP:
+ case Inference::SSPLIT_VAR_PROP:
+ case Inference::SSPLIT_CST:
+ case Inference::SSPLIT_VAR:
+ {
+ Trace("strings-ipc-core") << "Generate core rule for " << infer
+ << " (rev=" << isRev << ")" << std::endl;
+ // All of the above inferences have the form:
+ // (explanation for why t and s have the same prefix/suffix) ^
+ // t = s ^
+ // (length constraint)?
+ // We call t=s the "main equality" below. The length constraint is
+ // optional, which we split on below.
+ size_t nchild = ps.d_children.size();
+ size_t mainEqIndex = 0;
+ bool mainEqIndexSet = false;
+ // the length constraint
+ std::vector<Node> lenConstraint;
+ // these inferences have a length constraint as the last explain
+ if (infer == Inference::N_UNIFY || infer == Inference::F_UNIFY
+ || infer == Inference::SSPLIT_CST || infer == Inference::SSPLIT_VAR
+ || infer == Inference::SSPLIT_VAR_PROP
+ || infer == Inference::SSPLIT_CST_PROP)
+ {
+ if (exp.size() >= 2)
+ {
+ Assert(exp.size() <= startExpIndex.size());
+ // The index of the "main" equality is the last equality before
+ // the length explanation.
+ mainEqIndex = startExpIndex[exp.size() - 1] - 1;
+ mainEqIndexSet = true;
+ // the remainder is the length constraint
+ lenConstraint.insert(lenConstraint.end(),
+ ps.d_children.begin() + mainEqIndex + 1,
+ ps.d_children.end());
+ }
+ }
+ else if (nchild >= 1)
+ {
+ // The index of the main equality is the last child.
+ mainEqIndex = nchild - 1;
+ mainEqIndexSet = true;
+ }
+ Node mainEq;
+ if (mainEqIndexSet)
+ {
+ mainEq = ps.d_children[mainEqIndex];
+ Trace("strings-ipc-core") << "Main equality " << mainEq << " at index "
+ << mainEqIndex << std::endl;
+ }
+ if (mainEq.isNull() || mainEq.getKind() != EQUAL)
+ {
+ Trace("strings-ipc-core")
+ << "...failed to find main equality" << std::endl;
+ break;
+ }
+ // apply MACRO_SR_PRED_ELIM using equalities up to the main eq
+ std::vector<Node> childrenSRew;
+ childrenSRew.push_back(mainEq);
+ childrenSRew.insert(childrenSRew.end(),
+ ps.d_children.begin(),
+ ps.d_children.begin() + mainEqIndex);
+ Node mainEqSRew =
+ psb.tryStep(PfRule::MACRO_SR_PRED_ELIM, childrenSRew, {});
+ if (CDProof::isSame(mainEqSRew, mainEq))
+ {
+ Trace("strings-ipc-core") << "...undo step" << std::endl;
+ // the rule added above was not necessary
+ psb.popStep();
+ }
+ else if (mainEqSRew == conc)
+ {
+ Trace("strings-ipc-core") << "...success after rewrite!" << std::endl;
+ useBuffer = true;
+ break;
+ }
+ Trace("strings-ipc-core")
+ << "Main equality after subs+rewrite " << mainEqSRew << std::endl;
+ // now, apply CONCAT_EQ to get the remainder
+ std::vector<Node> childrenCeq;
+ childrenCeq.push_back(mainEqSRew);
+ std::vector<Node> argsCeq;
+ argsCeq.push_back(nodeIsRev);
+ Node mainEqCeq = psb.tryStep(PfRule::CONCAT_EQ, childrenCeq, argsCeq);
+ Trace("strings-ipc-core")
+ << "Main equality after CONCAT_EQ " << mainEqCeq << std::endl;
+ if (mainEqCeq.isNull() || mainEqCeq.getKind() != EQUAL)
+ {
+ // fail
+ break;
+ }
+ else if (mainEqCeq == mainEqSRew)
+ {
+ Trace("strings-ipc-core") << "...undo step" << std::endl;
+ // not necessary, probably first component of equality
+ psb.popStep();
+ }
+ // Now, mainEqCeq is an equality t ++ ... == s ++ ... where the
+ // inference involved t and s.
+ if (infer == Inference::N_ENDPOINT_EQ
+ || infer == Inference::N_ENDPOINT_EMP
+ || infer == Inference::F_ENDPOINT_EQ
+ || infer == Inference::F_ENDPOINT_EMP)
+ {
+ // Should be equal to conclusion already, or rewrite to it.
+ // Notice that this step is necessary to handle the "rproc"
+ // optimization in processSimpleNEq. Alternatively, this could
+ // possibly be done by CONCAT_EQ with !isRev.
+ std::vector<Node> cexp;
+ if (psb.applyPredTransform(mainEqCeq,
+ conc,
+ cexp,
+ MethodId::SB_DEFAULT,
+ MethodId::RW_REWRITE_EQ_EXT))
+ {
+ Trace("strings-ipc-core") << "Transformed to " << conc
+ << " via pred transform" << std::endl;
+ // success
+ useBuffer = true;
+ Trace("strings-ipc-core") << "...success!" << std::endl;
+ }
+ // Otherwise, note that EMP rules conclude ti = "" where
+ // t1 ++ ... ++ tn == "". However, these are very rarely applied, let
+ // alone for 2+ children. This case is intentionally unhandled here.
+ }
+ else if (infer == Inference::N_CONST || infer == Inference::F_CONST
+ || infer == Inference::N_EQ_CONF)
+ {
+ // should be a constant conflict
+ std::vector<Node> childrenC;
+ childrenC.push_back(mainEqCeq);
+ std::vector<Node> argsC;
+ argsC.push_back(nodeIsRev);
+ Node mainEqC = psb.tryStep(PfRule::CONCAT_CONFLICT, childrenC, argsC);
+ if (mainEqC == conc)
+ {
+ useBuffer = true;
+ Trace("strings-ipc-core") << "...success!" << std::endl;
+ }
+ }
+ else
+ {
+ std::vector<Node> tvec;
+ std::vector<Node> svec;
+ utils::getConcat(mainEqCeq[0], tvec);
+ utils::getConcat(mainEqCeq[1], svec);
+ Node t0 = tvec[isRev ? tvec.size() - 1 : 0];
+ Node s0 = svec[isRev ? svec.size() - 1 : 0];
+ bool applySym = false;
+ // may need to apply symmetry
+ if ((infer == Inference::SSPLIT_CST
+ || infer == Inference::SSPLIT_CST_PROP)
+ && t0.isConst())
+ {
+ Assert(!s0.isConst());
+ applySym = true;
+ std::swap(t0, s0);
+ }
+ if (infer == Inference::N_UNIFY || infer == Inference::F_UNIFY)
+ {
+ if (conc.getKind() != EQUAL)
+ {
+ break;
+ }
+ // one side should match, the other side could be a split constant
+ if (conc[0] != t0 && conc[1] != s0)
+ {
+ applySym = true;
+ std::swap(t0, s0);
+ }
+ Assert(conc[0].isConst() == t0.isConst());
+ Assert(conc[1].isConst() == s0.isConst());
+ }
+ PfRule rule = PfRule::UNKNOWN;
+ // the form of the required length constraint expected by the proof
+ Node lenReq;
+ bool lenSuccess = false;
+ if (infer == Inference::N_UNIFY || infer == Inference::F_UNIFY)
+ {
+ // the required premise for unify is always len(x) = len(y),
+ // however the explanation may not be literally this. Thus, we
+ // need to reconstruct a proof from the given explanation.
+ // it should be the case that lenConstraint => lenReq.
+ // We use terms in the conclusion equality, not t0, s0 here.
+ lenReq = nm->mkNode(STRING_LENGTH, conc[0])
+ .eqNode(nm->mkNode(STRING_LENGTH, conc[1]));
+ lenSuccess = convertLengthPf(lenReq, lenConstraint, psb);
+ rule = PfRule::CONCAT_UNIFY;
+ }
+ else if (infer == Inference::SSPLIT_VAR)
+ {
+ // it should be the case that lenConstraint => lenReq
+ lenReq = nm->mkNode(STRING_LENGTH, t0)
+ .eqNode(nm->mkNode(STRING_LENGTH, s0))
+ .notNode();
+ lenSuccess = convertLengthPf(lenReq, lenConstraint, psb);
+ rule = PfRule::CONCAT_SPLIT;
+ }
+ else if (infer == Inference::SSPLIT_CST)
+ {
+ // it should be the case that lenConstraint => lenReq
+ lenReq = nm->mkNode(STRING_LENGTH, t0)
+ .eqNode(nm->mkConst(Rational(0)))
+ .notNode();
+ lenSuccess = convertLengthPf(lenReq, lenConstraint, psb);
+ rule = PfRule::CONCAT_CSPLIT;
+ }
+ else if (infer == Inference::SSPLIT_VAR_PROP)
+ {
+ // it should be the case that lenConstraint => lenReq
+ for (unsigned r = 0; r < 2; r++)
+ {
+ lenReq = nm->mkNode(GT,
+ nm->mkNode(STRING_LENGTH, t0),
+ nm->mkNode(STRING_LENGTH, s0));
+ if (convertLengthPf(lenReq, lenConstraint, psb))
+ {
+ lenSuccess = true;
+ break;
+ }
+ if (r == 0)
+ {
+ // may be the other direction
+ applySym = true;
+ std::swap(t0, s0);
+ }
+ }
+ rule = PfRule::CONCAT_LPROP;
+ }
+ else if (infer == Inference::SSPLIT_CST_PROP)
+ {
+ // it should be the case that lenConstraint => lenReq
+ lenReq = nm->mkNode(STRING_LENGTH, t0)
+ .eqNode(nm->mkConst(Rational(0)))
+ .notNode();
+ lenSuccess = convertLengthPf(lenReq, lenConstraint, psb);
+ rule = PfRule::CONCAT_CPROP;
+ }
+ if (!lenSuccess)
+ {
+ Trace("strings-ipc-core")
+ << "...failed due to length constraint" << std::endl;
+ break;
+ }
+ // apply symmetry if necessary
+ if (applySym)
+ {
+ std::vector<Node> childrenSymm;
+ childrenSymm.push_back(mainEqCeq);
+ // note this explicit step may not be necessary
+ mainEqCeq = psb.tryStep(PfRule::SYMM, childrenSymm, {});
+ Trace("strings-ipc-core")
+ << "Main equality after SYMM " << mainEqCeq << std::endl;
+ }
+ if (rule != PfRule::UNKNOWN)
+ {
+ Trace("strings-ipc-core")
+ << "Core rule length requirement is " << lenReq << std::endl;
+ // apply the given rule
+ std::vector<Node> childrenMain;
+ childrenMain.push_back(mainEqCeq);
+ childrenMain.push_back(lenReq);
+ std::vector<Node> argsMain;
+ argsMain.push_back(nodeIsRev);
+ Node mainEqMain = psb.tryStep(rule, childrenMain, argsMain);
+ Trace("strings-ipc-core") << "Main equality after " << rule << " "
+ << mainEqMain << std::endl;
+ if (mainEqMain == mainEqCeq)
+ {
+ Trace("strings-ipc-core") << "...undo step" << std::endl;
+ // not necessary, probably first component of equality
+ psb.popStep();
+ }
+ // either equal or rewrites to it
+ std::vector<Node> cexp;
+ if (psb.applyPredTransform(mainEqMain, conc, cexp))
+ {
+ // requires that length success is also true
+ useBuffer = true;
+ Trace("strings-ipc-core") << "...success" << std::endl;
+ }
+ else
+ {
+ Trace("strings-ipc-core") << "...fail" << std::endl;
+ }
+ }
+ else
+ {
+ // should always have given a rule to try above
+ Assert(false) << "No reconstruction rule given for " << infer;
+ }
+ }
+ }
+ break;
+ // ========================== Disequalities
+ case Inference::DEQ_DISL_FIRST_CHAR_STRING_SPLIT:
+ case Inference::DEQ_DISL_STRINGS_SPLIT:
+ {
+ if (conc.getKind() != AND || conc.getNumChildren() != 2
+ || conc[0].getKind() != EQUAL || !conc[0][0].getType().isStringLike()
+ || conc[1].getKind() != EQUAL
+ || conc[1][0].getKind() != STRING_LENGTH)
+ {
+ Trace("strings-ipc-deq") << "malformed application" << std::endl;
+ Assert(false) << "unexpected conclusion " << conc << " for " << infer;
+ }
+ else
+ {
+ Node lenReq =
+ nm->mkNode(GEQ, nm->mkNode(STRING_LENGTH, conc[0][0]), conc[1][1]);
+ Trace("strings-ipc-deq")
+ << "length requirement is " << lenReq << std::endl;
+ if (convertLengthPf(lenReq, ps.d_children, psb))
+ {
+ Trace("strings-ipc-deq") << "...success length" << std::endl;
+ // make the proof
+ std::vector<Node> childrenMain;
+ childrenMain.push_back(lenReq);
+ std::vector<Node> argsMain;
+ argsMain.push_back(nodeIsRev);
+ Node mainConc =
+ psb.tryStep(PfRule::STRING_DECOMPOSE, childrenMain, argsMain);
+ Trace("strings-ipc-deq")
+ << "...main conclusion is " << mainConc << std::endl;
+ useBuffer = (mainConc == conc);
+ Trace("strings-ipc-deq")
+ << "...success is " << useBuffer << std::endl;
+ }
+ else
+ {
+ Trace("strings-ipc-deq") << "...fail length" << std::endl;
+ }
+ }
+ }
+ break;
+ // ========================== Boolean split
+ case Inference::CARD_SP:
+ case Inference::LEN_SPLIT:
+ case Inference::LEN_SPLIT_EMP:
+ case Inference::DEQ_DISL_EMP_SPLIT:
+ case Inference::DEQ_DISL_FIRST_CHAR_EQ_SPLIT:
+ case Inference::DEQ_STRINGS_EQ:
+ case Inference::DEQ_LENS_EQ:
+ case Inference::DEQ_LENGTH_SP:
+ {
+ if (conc.getKind() != OR)
+ {
+ // This should never happen. If it does, we resort to using
+ // STRING_TRUST below (in production mode).
+ Assert(false) << "Expected OR conclusion for " << infer;
+ }
+ else
+ {
+ ps.d_rule = PfRule::SPLIT;
+ Assert(ps.d_children.empty());
+ ps.d_args.push_back(conc[0]);
+ }
+ }
+ break;
+ // ========================== Regular expression unfolding
+ case Inference::RE_UNFOLD_POS:
+ case Inference::RE_UNFOLD_NEG:
+ {
+ if (infer == Inference::RE_UNFOLD_POS)
+ {
+ ps.d_rule = PfRule::RE_UNFOLD_POS;
+ }
+ else
+ {
+ ps.d_rule = PfRule::RE_UNFOLD_NEG;
+ // it may be an optimized form of concat simplification
+ Assert(ps.d_children.size() == 1);
+ Node mem = ps.d_children[0];
+ Assert(mem.getKind() == NOT && mem[0].getKind() == STRING_IN_REGEXP);
+ if (mem[0][1].getKind() == REGEXP_CONCAT)
+ {
+ size_t index;
+ Node reLen = RegExpOpr::getRegExpConcatFixed(mem[0][1], index);
+ // if we can find a fixed length for a component, use the optimized
+ // version
+ if (!reLen.isNull())
+ {
+ ps.d_rule = PfRule::RE_UNFOLD_NEG_CONCAT_FIXED;
+ }
+ }
+ }
+ }
+ break;
+ // ========================== Reduction
+ case Inference::CTN_POS:
+ case Inference::CTN_NEG_EQUAL:
+ {
+ if (ps.d_children.size() != 1)
+ {
+ break;
+ }
+ bool polarity = ps.d_children[0].getKind() != NOT;
+ Node atom = polarity ? ps.d_children[0] : ps.d_children[0][0];
+ std::vector<Node> args;
+ args.push_back(atom);
+ Node res = psb.tryStep(PfRule::STRING_EAGER_REDUCTION, {}, args);
+ if (res.isNull())
+ {
+ break;
+ }
+ // ite( contains(x,t), x = k1 ++ t ++ k2, x != t )
+ std::vector<Node> tiChildren;
+ tiChildren.push_back(ps.d_children[0]);
+ Node ctnt = psb.tryStep(
+ polarity ? PfRule::TRUE_INTRO : PfRule::FALSE_INTRO, tiChildren, {});
+ if (ctnt.isNull() || ctnt.getKind() != EQUAL)
+ {
+ break;
+ }
+ std::vector<Node> tchildren;
+ tchildren.push_back(ctnt);
+ // apply substitution { contains(x,t) -> true|false } and rewrite to get
+ // conclusion x = k1 ++ t ++ k2 or x != t.
+ if (psb.applyPredTransform(res, conc, tchildren))
+ {
+ useBuffer = true;
+ }
+ }
+ break;
+
+ case Inference::REDUCTION:
+ {
+ size_t nchild = conc.getNumChildren();
+ Node mainEq;
+ if (conc.getKind() == EQUAL)
+ {
+ mainEq = conc;
+ }
+ else if (conc.getKind() == AND && conc[nchild - 1].getKind() == EQUAL)
+ {
+ mainEq = conc[nchild - 1];
+ }
+ if (mainEq.isNull())
+ {
+ Trace("strings-ipc-red") << "Bad Reduction: " << conc << std::endl;
+ Assert(false) << "Unexpected reduction " << conc;
+ break;
+ }
+ std::vector<Node> argsRed;
+ // the left hand side of the last conjunct is the term we are reducing
+ argsRed.push_back(mainEq[0]);
+ Node red = psb.tryStep(PfRule::STRING_REDUCTION, {}, argsRed);
+ Trace("strings-ipc-red") << "Reduction : " << red << std::endl;
+ if (!red.isNull())
+ {
+ // either equal or rewrites to it
+ std::vector<Node> cexp;
+ if (psb.applyPredTransform(red, conc, cexp))
+ {
+ Trace("strings-ipc-red") << "...success!" << std::endl;
+ useBuffer = true;
+ }
+ else
+ {
+ Trace("strings-ipc-red") << "...failed to reduce" << std::endl;
+ }
+ }
+ }
+ break;
+ // ========================== code injectivity
+ case Inference::CODE_INJ:
+ {
+ ps.d_rule = PfRule::STRING_CODE_INJ;
+ Assert(conc.getKind() == OR && conc.getNumChildren() == 3
+ && conc[2].getKind() == EQUAL);
+ ps.d_args.push_back(conc[2][0]);
+ ps.d_args.push_back(conc[2][1]);
+ }
+ break;
+ // ========================== unit injectivity
+ case Inference::UNIT_INJ: { ps.d_rule = PfRule::STRING_SEQ_UNIT_INJ;
+ }
+ break;
+ // ========================== prefix conflict
+ case Inference::PREFIX_CONFLICT:
+ {
+ Trace("strings-ipc-prefix") << "Prefix conflict..." << std::endl;
+ std::vector<Node> eqs;
+ for (const Node& e : ps.d_children)
+ {
+ Kind ek = e.getKind();
+ if (ek == EQUAL)
+ {
+ Trace("strings-ipc-prefix") << "- equality : " << e << std::endl;
+ eqs.push_back(e);
+ }
+ else if (ek == STRING_IN_REGEXP)
+ {
+ // unfold it and extract the equality
+ std::vector<Node> children;
+ children.push_back(e);
+ std::vector<Node> args;
+ Node eunf = psb.tryStep(PfRule::RE_UNFOLD_POS, children, args);
+ Trace("strings-ipc-prefix")
+ << "--- " << e << " unfolds to " << eunf << std::endl;
+ if (eunf.isNull())
+ {
+ continue;
+ }
+ else if (eunf.getKind() == AND)
+ {
+ // equality is the last conjunct
+ std::vector<Node> childrenAE;
+ childrenAE.push_back(eunf);
+ std::vector<Node> argsAE;
+ argsAE.push_back(nm->mkConst(Rational(eunf.getNumChildren() - 1)));
+ Node eunfAE = psb.tryStep(PfRule::AND_ELIM, childrenAE, argsAE);
+ Trace("strings-ipc-prefix")
+ << "--- and elim to " << eunfAE << std::endl;
+ if (eunfAE.isNull() || eunfAE.getKind() != EQUAL)
+ {
+ Assert(false)
+ << "Unexpected unfolded premise " << eunf << " for " << infer;
+ continue;
+ }
+ Trace("strings-ipc-prefix")
+ << "- equality : " << eunfAE << std::endl;
+ eqs.push_back(eunfAE);
+ }
+ else if (eunf.getKind() == EQUAL)
+ {
+ Trace("strings-ipc-prefix") << "- equality : " << eunf << std::endl;
+ eqs.push_back(eunf);
+ }
+ }
+ else
+ {
+ // not sure how to use this assumption
+ Assert(false) << "Unexpected premise " << e << " for " << infer;
+ }
+ }
+ if (eqs.empty())
+ {
+ break;
+ }
+ // connect via transitivity
+ Node curr = eqs[0];
+ for (size_t i = 1, esize = eqs.size(); i < esize; i++)
+ {
+ Node prev = curr;
+ curr = convertTrans(curr, eqs[1], psb);
+ if (curr.isNull())
+ {
+ break;
+ }
+ Trace("strings-ipc-prefix") << "- Via trans: " << curr << std::endl;
+ }
+ if (curr.isNull())
+ {
+ break;
+ }
+ Trace("strings-ipc-prefix")
+ << "- Possible conflicting equality : " << curr << std::endl;
+ std::vector<Node> emp;
+ Node concE = psb.applyPredElim(curr, emp);
+ Trace("strings-ipc-prefix")
+ << "- After pred elim: " << concE << std::endl;
+ if (concE == conc)
+ {
+ Trace("strings-ipc-prefix") << "...success!" << std::endl;
+ useBuffer = true;
+ }
+ }
+ break;
+ // ========================== regular expressions
+ case Inference::RE_INTER_INCLUDE:
+ case Inference::RE_INTER_CONF:
+ case Inference::RE_INTER_INFER:
+ {
+ std::vector<Node> reiExp;
+ std::vector<Node> reis;
+ std::vector<Node> reiChildren;
+ std::vector<Node> reiChildrenOrig;
+ Node x;
+ // make the regular expression intersection that summarizes all
+ // memberships in the explanation
+ for (const Node& c : ps.d_children)
+ {
+ bool polarity = c.getKind() != NOT;
+ Node catom = polarity ? c : c[0];
+ if (catom.getKind() != STRING_IN_REGEXP)
+ {
+ Assert(c.getKind() == EQUAL);
+ if (c.getKind() == EQUAL)
+ {
+ reiExp.push_back(c);
+ }
+ continue;
+ }
+ if (x.isNull())
+ {
+ // just take the first LHS; others should be equated to it by exp
+ x = catom[0];
+ }
+ Node rcurr =
+ polarity ? catom[1] : nm->mkNode(REGEXP_COMPLEMENT, catom[1]);
+ reis.push_back(rcurr);
+ Node mem = nm->mkNode(STRING_IN_REGEXP, catom[0], rcurr);
+ reiChildren.push_back(mem);
+ reiChildrenOrig.push_back(c);
+ }
+ // go back and justify each premise
+ bool successChildren = true;
+ for (size_t i = 0, nchild = reiChildren.size(); i < nchild; i++)
+ {
+ if (!psb.applyPredTransform(reiChildrenOrig[i], reiChildren[i], reiExp))
+ {
+ Trace("strings-ipc-re")
+ << "... failed to justify child " << reiChildren[i] << " from "
+ << reiChildrenOrig[i] << std::endl;
+ successChildren = false;
+ break;
+ }
+ }
+ if (!successChildren)
+ {
+ break;
+ }
+ Node mem = psb.tryStep(PfRule::RE_INTER, reiChildren, {});
+ Trace("strings-ipc-re")
+ << "Regular expression summary: " << mem << std::endl;
+ // the conclusion is rewritable to the premises via rewriting?
+ if (psb.applyPredTransform(mem, conc, {}))
+ {
+ Trace("strings-ipc-re") << "... success!" << std::endl;
+ useBuffer = true;
+ }
+ else
+ {
+ Trace("strings-ipc-re")
+ << "...failed to rewrite to conclusion" << std::endl;
+ }
+ }
+ break;
+ // ========================== unknown and currently unsupported
+ case Inference::CARDINALITY:
+ case Inference::I_CYCLE_E:
+ case Inference::I_CYCLE:
+ case Inference::RE_DELTA:
+ case Inference::RE_DELTA_CONF:
+ case Inference::RE_DERIVE:
+ case Inference::FLOOP:
+ case Inference::FLOOP_CONFLICT:
+ case Inference::DEQ_NORM_EMP:
+ case Inference::CTN_TRANS:
+ case Inference::CTN_DECOMPOSE:
+ default:
+ // do nothing, these will be converted to STRING_TRUST below since the
+ // rule is unknown.
+ break;
+ }
+
+ // now see if we would succeed with the checker-to-try
+ bool success = false;
+ if (ps.d_rule != PfRule::UNKNOWN)
+ {
+ Trace("strings-ipc") << "For " << infer << ", try proof rule " << ps.d_rule
+ << "...";
+ Assert(ps.d_rule != PfRule::UNKNOWN);
+ Node pconc = psb.tryStep(ps.d_rule, ps.d_children, ps.d_args);
+ if (pconc.isNull() || pconc != conc)
+ {
+ Trace("strings-ipc") << "failed, pconc is " << pconc << " (expected "
+ << conc << ")" << std::endl;
+ ps.d_rule = PfRule::UNKNOWN;
+ }
+ else
+ {
+ // successfully set up a single step proof in ps
+ success = true;
+ Trace("strings-ipc") << "success!" << std::endl;
+ }
+ }
+ else if (useBuffer)
+ {
+ // successfully set up a multi step proof in psb
+ success = true;
+ }
+ else
+ {
+ Trace("strings-ipc") << "For " << infer << " " << conc
+ << ", no proof rule, failed" << std::endl;
+ }
+ if (!success)
+ {
+ // debug print
+ if (Trace.isOn("strings-ipc-fail"))
+ {
+ Trace("strings-ipc-fail")
+ << "InferProofCons::convert: Failed " << infer
+ << (isRev ? " :rev " : " ") << conc << std::endl;
+ for (const Node& ec : exp)
+ {
+ Trace("strings-ipc-fail") << " e: " << ec << std::endl;
+ }
+ }
+ // untrustworthy conversion, the argument of STRING_TRUST is its conclusion
+ ps.d_args.clear();
+ ps.d_args.push_back(conc);
+ // use the trust rule
+ ps.d_rule = PfRule::STRING_TRUST;
+ // add to stats
+ d_statistics.d_inferencesNoPf << infer;
+ }
+ if (Trace.isOn("strings-ipc-debug"))
+ {
+ if (useBuffer)
+ {
+ Trace("strings-ipc-debug")
+ << "InferProofCons::convert returned buffer with "
+ << psb.getNumSteps() << " steps:" << std::endl;
+ const std::vector<std::pair<Node, ProofStep>>& steps = psb.getSteps();
+ for (const std::pair<Node, ProofStep>& step : steps)
+ {
+ Trace("strings-ipc-debug")
+ << "- " << step.first << " via " << step.second << std::endl;
+ }
+ }
+ else
+ {
+ Trace("strings-ipc-debug")
+ << "InferProofCons::convert returned " << ps << std::endl;
+ }
+ }
+}
+
+bool InferProofCons::convertLengthPf(Node lenReq,
+ const std::vector<Node>& lenExp,
+ TheoryProofStepBuffer& psb)
+{
+ for (const Node& le : lenExp)
+ {
+ if (lenReq == le)
+ {
+ return true;
+ }
+ }
+ Trace("strings-ipc-len") << "Must explain " << lenReq << " by " << lenExp
+ << std::endl;
+ for (const Node& le : lenExp)
+ {
+ // probably rewrites to it?
+ std::vector<Node> exp;
+ if (psb.applyPredTransform(le, lenReq, exp))
+ {
+ Trace("strings-ipc-len") << "...success by rewrite" << std::endl;
+ return true;
+ }
+ // maybe x != "" => len(x) != 0
+ std::vector<Node> children;
+ children.push_back(le);
+ std::vector<Node> args;
+ Node res = psb.tryStep(PfRule::STRING_LENGTH_NON_EMPTY, children, args);
+ if (res == lenReq)
+ {
+ Trace("strings-ipc-len") << "...success by LENGTH_NON_EMPTY" << std::endl;
+ return true;
+ }
+ }
+ Trace("strings-ipc-len") << "...failed" << std::endl;
+ return false;
+}
+
+Node InferProofCons::convertTrans(Node eqa,
+ Node eqb,
+ TheoryProofStepBuffer& psb)
+{
+ if (eqa.getKind() != EQUAL || eqb.getKind() != EQUAL)
+ {
+ return Node::null();
+ }
+ for (uint32_t i = 0; i < 2; i++)
+ {
+ Node eqaSym = i == 0 ? eqa[1].eqNode(eqa[0]) : eqa;
+ for (uint32_t j = 0; j < 2; j++)
+ {
+ Node eqbSym = j == 0 ? eqb : eqb[1].eqNode(eqb[1]);
+ if (eqa[i] == eqb[j])
+ {
+ std::vector<Node> children;
+ children.push_back(eqaSym);
+ children.push_back(eqbSym);
+ return psb.tryStep(PfRule::TRANS, children, {});
+ }
+ }
+ }
+ return Node::null();
+}
+
+std::shared_ptr<ProofNode> InferProofCons::getProofFor(Node fact)
+{
+ // temporary proof
+ CDProof pf(d_pnm);
+ // get the inference
+ NodeInferInfoMap::iterator it = d_lazyFactMap.find(fact);
+ if (it == d_lazyFactMap.end())
+ {
+ Node factSym = CDProof::getSymmFact(fact);
+ if (!factSym.isNull())
+ {
+ // Use the symmetric fact. There is no need to explictly make a
+ // SYMM proof, as this is handled by CDProof::getProofFor below.
+ it = d_lazyFactMap.find(factSym);
+ }
+ }
+ AlwaysAssert(it != d_lazyFactMap.end());
+ // now go back and convert it to proof steps and add to proof
+ bool useBuffer = false;
+ ProofStep ps;
+ TheoryProofStepBuffer psb(d_pnm->getChecker());
+ std::shared_ptr<InferInfo> ii = (*it).second;
+ // run the conversion
+ convert(ii->d_id, ii->d_idRev, ii->d_conc, ii->d_ant, ps, psb, useBuffer);
+ // make the proof based on the step or the buffer
+ if (useBuffer)
+ {
+ if (!pf.addSteps(psb))
+ {
+ return nullptr;
+ }
+ }
+ else
+ {
+ if (!pf.addStep(fact, ps))
+ {
+ return nullptr;
+ }
+ }
+ return pf.getProofFor(fact);
+}
+
+std::string InferProofCons::identify() const
+{
+ return "strings::InferProofCons";
+}
+
+} // namespace strings
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/strings/infer_proof_cons.h b/src/theory/strings/infer_proof_cons.h
new file mode 100644
index 000000000..63e341dfe
--- /dev/null
+++ b/src/theory/strings/infer_proof_cons.h
@@ -0,0 +1,135 @@
+/********************* */
+/*! \file infer_proof_cons.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Inference to proof conversion
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__STRINGS__INFER_PROOF_CONS_H
+#define CVC4__THEORY__STRINGS__INFER_PROOF_CONS_H
+
+#include <vector>
+
+#include "expr/node.h"
+#include "expr/proof_checker.h"
+#include "expr/proof_rule.h"
+#include "theory/builtin/proof_checker.h"
+#include "theory/strings/infer_info.h"
+#include "theory/strings/sequences_stats.h"
+#include "theory/theory_proof_step_buffer.h"
+#include "theory/uf/proof_equality_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+/**
+ * Converts between the strings-specific (untrustworthy) InferInfo class and
+ * information about how to construct a trustworthy proof step
+ * (PfRule, children, args). It acts as a (lazy) proof generator where the
+ * former is registered via notifyFact and the latter is asked for in
+ * getProofFor, typically by the proof equality engine.
+ *
+ * The main (private) method of this class is convert below, which is
+ * called when we need to construct a proof node from an InferInfo.
+ */
+class InferProofCons : public ProofGenerator
+{
+ typedef context::CDHashMap<Node, std::shared_ptr<InferInfo>, NodeHashFunction>
+ NodeInferInfoMap;
+
+ public:
+ InferProofCons(context::Context* c,
+ ProofNodeManager* pnm,
+ SequencesStatistics& statistics);
+ ~InferProofCons() {}
+ /**
+ * This is called to notify that ii is an inference that may need a proof
+ * in the future.
+ *
+ * In detail, this class should be prepared to respond to a call to:
+ * getProofFor(ii.d_conc)
+ * in the remainder of the SAT context. This method copies ii and stores it
+ * in the context-dependent map d_lazyFactMap below.
+ *
+ * This is used for lazy proof construction, where proofs are constructed
+ * only for facts that are explained.
+ */
+ void notifyFact(const InferInfo& ii);
+
+ /**
+ * This returns the proof for fact. This is required for using this class as
+ * a lazy proof generator.
+ *
+ * It should be the case that a call was made to notifyFact(ii) where
+ * ii.d_conc is fact in this SAT context.
+ */
+ std::shared_ptr<ProofNode> getProofFor(Node fact) override;
+ /** Identify this generator (for debugging, etc..) */
+ virtual std::string identify() const override;
+
+ private:
+ /** convert
+ *
+ * This method is called when the theory of strings makes an inference
+ * described by an InferInfo, whose fields are given by the first four
+ * arguments of this method.
+ *
+ * This method converts this call to instructions on what the proof rule
+ * step(s) are for concluding the conclusion of the inference. This
+ * information is either:
+ *
+ * (A) stored in the argument ps, which consists of:
+ * - A proof rule identifier (ProofStep::d_rule).
+ * - The premises of the proof step (ProofStep::d_children).
+ * - Arguments to the proof step (ProofStep::d_args).
+ *
+ * (B) If the proof for the inference cannot be captured by a single
+ * step, then the d_rule field of ps is not set, and useBuffer is set to
+ * true. In this case, the argument psb is updated to contain (possibly
+ * multiple) proof steps for how to construct a proof for the given inference.
+ * In particular, psb will contain a set of steps that form a proof
+ * whose conclusion is ii.d_conc and whose free assumptions are ii.d_ant.
+ */
+ void convert(Inference infer,
+ bool isRev,
+ Node conc,
+ const std::vector<Node>& exp,
+ ProofStep& ps,
+ TheoryProofStepBuffer& psb,
+ bool& useBuffer);
+ /**
+ * Convert length proof. If this method returns true, it adds proof step(s)
+ * to the buffer psb that conclude lenReq from premises lenExp.
+ */
+ bool convertLengthPf(Node lenReq,
+ const std::vector<Node>& lenExp,
+ TheoryProofStepBuffer& psb);
+ /**
+ * Helper method, adds the proof of (TRANS eqa eqb) into the proof step
+ * buffer psb, where eqa and eqb are flipped as needed. Returns the
+ * conclusion, or null if we were not able to construct a TRANS step.
+ */
+ Node convertTrans(Node eqa, Node eqb, TheoryProofStepBuffer& psb);
+ /** the proof node manager */
+ ProofNodeManager* d_pnm;
+ /** The lazy fact map */
+ NodeInferInfoMap d_lazyFactMap;
+ /** Reference to the statistics for the theory of strings/sequences. */
+ SequencesStatistics& d_statistics;
+};
+
+} // namespace strings
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__STRINGS__INFER_PROOF_CONS_H */
diff --git a/src/theory/strings/inference_manager.cpp b/src/theory/strings/inference_manager.cpp
index 6d33c8627..e324689f5 100644
--- a/src/theory/strings/inference_manager.cpp
+++ b/src/theory/strings/inference_manager.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -28,19 +28,19 @@ namespace CVC4 {
namespace theory {
namespace strings {
-InferenceManager::InferenceManager(context::Context* c,
- context::UserContext* u,
+InferenceManager::InferenceManager(Theory& t,
SolverState& s,
TermRegistry& tr,
ExtTheory& e,
- OutputChannel& out,
- SequencesStatistics& statistics)
- : d_state(s),
+ SequencesStatistics& statistics,
+ ProofNodeManager* pnm)
+ : InferenceManagerBuffered(t, s, pnm),
+ d_state(s),
d_termReg(tr),
d_extt(e),
- d_out(out),
d_statistics(statistics),
- d_keep(c)
+ d_ipc(pnm ? new InferProofCons(d_state.getSatContext(), pnm, d_statistics)
+ : nullptr)
{
NodeManager* nm = NodeManager::currentNM();
d_zero = nm->mkConst(Rational(0));
@@ -49,12 +49,18 @@ InferenceManager::InferenceManager(context::Context* c,
d_false = nm->mkConst(false);
}
-void InferenceManager::sendAssumption(TNode lit)
+void InferenceManager::doPending()
{
- bool polarity = lit.getKind() != kind::NOT;
- TNode atom = polarity ? lit : lit[0];
- // assert pending fact
- assertPendingFact(atom, polarity, lit);
+ doPendingFacts();
+ if (d_state.isInConflict())
+ {
+ // just clear the pending vectors, nothing else to do
+ clearPendingLemmas();
+ clearPendingPhaseRequirements();
+ return;
+ }
+ doPendingLemmas();
+ doPendingPhaseRequirements();
}
bool InferenceManager::sendInternalInference(std::vector<Node>& exp,
@@ -116,63 +122,67 @@ bool InferenceManager::sendInternalInference(std::vector<Node>& exp,
return true;
}
-void InferenceManager::sendInference(const std::vector<Node>& exp,
- const std::vector<Node>& expn,
+bool InferenceManager::sendInference(const std::vector<Node>& exp,
+ const std::vector<Node>& noExplain,
Node eq,
Inference infer,
+ bool isRev,
bool asLemma)
{
- eq = eq.isNull() ? d_false : Rewriter::rewrite(eq);
- if (eq == d_true)
+ if (eq.isNull())
{
- return;
+ eq = d_false;
+ }
+ else if (Rewriter::rewrite(eq) == d_true)
+ {
+ // if trivial, return
+ return false;
}
// wrap in infer info and send below
InferInfo ii;
ii.d_id = infer;
+ ii.d_idRev = isRev;
ii.d_conc = eq;
ii.d_ant = exp;
- ii.d_antn = expn;
+ ii.d_noExplain = noExplain;
sendInference(ii, asLemma);
+ return true;
}
-void InferenceManager::sendInference(const std::vector<Node>& exp,
+bool InferenceManager::sendInference(const std::vector<Node>& exp,
Node eq,
Inference infer,
+ bool isRev,
bool asLemma)
{
- std::vector<Node> expn;
- sendInference(exp, expn, eq, infer, asLemma);
+ std::vector<Node> noExplain;
+ return sendInference(exp, noExplain, eq, infer, isRev, asLemma);
}
-void InferenceManager::sendInference(const InferInfo& ii, bool asLemma)
+void InferenceManager::sendInference(InferInfo& ii, bool asLemma)
{
Assert(!ii.isTrivial());
+ // set that this inference manager will be processing this inference
+ ii.d_sim = this;
Trace("strings-infer-debug")
<< "sendInference: " << ii << ", asLemma = " << asLemma << std::endl;
// check if we should send a conflict, lemma or a fact
- if (asLemma || options::stringInferAsLemmas() || !ii.isFact())
+ if (ii.isConflict())
+ {
+ Trace("strings-infer-debug") << "...as conflict" << std::endl;
+ Trace("strings-lemma") << "Strings::Conflict: " << ii.d_ant << " by "
+ << ii.d_id << std::endl;
+ Trace("strings-conflict") << "CONFLICT: inference conflict " << ii.d_ant
+ << " by " << ii.d_id << std::endl;
+ ++(d_statistics.d_conflictsInfer);
+ // process the conflict immediately
+ processConflict(ii);
+ return;
+ }
+ else if (asLemma || options::stringInferAsLemmas() || !ii.isFact())
{
- if (ii.isConflict())
- {
- Trace("strings-infer-debug") << "...as conflict" << std::endl;
- Trace("strings-lemma") << "Strings::Conflict: " << ii.d_ant << " by "
- << ii.d_id << std::endl;
- Trace("strings-conflict") << "CONFLICT: inference conflict " << ii.d_ant
- << " by " << ii.d_id << std::endl;
- // we must fully explain it
- Node conf = mkExplain(ii.d_ant);
- Trace("strings-assert") << "(assert (not " << conf << ")) ; conflict "
- << ii.d_id << std::endl;
- ++(d_statistics.d_conflictsInfer);
- // only keep stats if we process it here
- d_statistics.d_inferences << ii.d_id;
- d_out.conflict(conf);
- d_state.setConflict();
- return;
- }
Trace("strings-infer-debug") << "...as lemma" << std::endl;
- d_pendingLem.push_back(ii);
+ addPendingLemma(std::unique_ptr<InferInfo>(new InferInfo(ii)));
return;
}
if (options::stringInferSym())
@@ -189,6 +199,7 @@ void InferenceManager::sendInference(const InferInfo& ii, bool asLemma)
Node eqs = ii.d_conc.substitute(
vars.begin(), vars.end(), subs.begin(), subs.end());
InferInfo iiSubsLem;
+ iiSubsLem.d_sim = this;
// keep the same id for now, since we are transforming the form of the
// inference, not the root reason.
iiSubsLem.d_id = ii.d_id;
@@ -206,7 +217,7 @@ void InferenceManager::sendInference(const InferInfo& ii, bool asLemma)
}
}
Trace("strings-infer-debug") << "...as symbolic lemma" << std::endl;
- d_pendingLem.push_back(iiSubsLem);
+ addPendingLemma(std::unique_ptr<InferInfo>(new InferInfo(iiSubsLem)));
return;
}
if (Trace.isOn("strings-lemma-debug"))
@@ -214,13 +225,13 @@ void InferenceManager::sendInference(const InferInfo& ii, bool asLemma)
for (const Node& u : unproc)
{
Trace("strings-lemma-debug")
- << " non-trivial exp : " << u << std::endl;
+ << " non-trivial explanation : " << u << std::endl;
}
}
}
Trace("strings-infer-debug") << "...as fact" << std::endl;
- // add to pending, to be processed as a fact
- d_pending.push_back(ii);
+ // add to pending to be processed as a fact
+ addPendingFact(std::unique_ptr<InferInfo>(new InferInfo(ii)));
}
bool InferenceManager::sendSplit(Node a, Node b, Inference infer, bool preq)
@@ -233,19 +244,15 @@ bool InferenceManager::sendSplit(Node a, Node b, Inference infer, bool preq)
}
NodeManager* nm = NodeManager::currentNM();
InferInfo iiSplit;
+ iiSplit.d_sim = this;
iiSplit.d_id = infer;
iiSplit.d_conc = nm->mkNode(OR, eq, nm->mkNode(NOT, eq));
- sendPhaseRequirement(eq, preq);
- d_pendingLem.push_back(iiSplit);
+ eq = Rewriter::rewrite(eq);
+ addPendingPhaseRequirement(eq, preq);
+ addPendingLemma(std::unique_ptr<InferInfo>(new InferInfo(iiSplit)));
return true;
}
-void InferenceManager::sendPhaseRequirement(Node lit, bool pol)
-{
- lit = Rewriter::rewrite(lit);
- d_pendingReqPhase[lit] = pol;
-}
-
void InferenceManager::setIncomplete() { d_out.setIncomplete(); }
void InferenceManager::addToExplanation(Node a,
@@ -265,304 +272,167 @@ void InferenceManager::addToExplanation(Node lit, std::vector<Node>& exp) const
{
if (!lit.isNull())
{
+ Assert(!lit.isConst());
exp.push_back(lit);
}
}
-void InferenceManager::doPendingFacts()
+bool InferenceManager::hasProcessed() const
{
- size_t i = 0;
- while (!d_state.isInConflict() && i < d_pending.size())
- {
- InferInfo& ii = d_pending[i];
- // At this point, ii should be a "fact", i.e. something whose conclusion
- // should be added as a normal equality or predicate to the equality engine
- // with no new external assumptions (ii.d_antn).
- Assert(ii.isFact());
- Node facts = ii.d_conc;
- Node exp = utils::mkAnd(ii.d_ant);
- Trace("strings-assert") << "(assert (=> " << exp << " " << facts
- << ")) ; fact " << ii.d_id << std::endl;
- // only keep stats if we process it here
- Trace("strings-lemma") << "Strings::Fact: " << facts << " from " << exp
- << " by " << ii.d_id << std::endl;
- d_statistics.d_inferences << ii.d_id;
- // assert it as a pending fact
- if (facts.getKind() == AND)
- {
- for (const Node& fact : facts)
- {
- bool polarity = fact.getKind() != NOT;
- TNode atom = polarity ? fact : fact[0];
- // no double negation or double (conjunctive) conclusions
- Assert(atom.getKind() != NOT && atom.getKind() != AND);
- assertPendingFact(atom, polarity, exp);
- }
- }
- else
- {
- bool polarity = facts.getKind() != NOT;
- TNode atom = polarity ? facts : facts[0];
- // no double negation or double (conjunctive) conclusions
- Assert(atom.getKind() != NOT && atom.getKind() != AND);
- assertPendingFact(atom, polarity, exp);
- }
- // Must reference count the equality and its explanation, which is not done
- // by the equality engine. Notice that we do not need to do this for
- // external assertions, which enter as facts through sendAssumption.
- d_keep.insert(facts);
- d_keep.insert(exp);
- i++;
- }
- d_pending.clear();
+ return d_state.isInConflict() || hasPending();
}
-void InferenceManager::doPendingLemmas()
+void InferenceManager::markCongruent(Node a, Node b)
{
- if (d_state.isInConflict())
+ Assert(a.getKind() == b.getKind());
+ if (d_extt.hasFunctionKind(a.getKind()))
{
- // just clear the pending vectors, nothing else to do
- d_pendingLem.clear();
- d_pendingReqPhase.clear();
- return;
+ d_extt.markCongruent(a, b);
}
- NodeManager* nm = NodeManager::currentNM();
- for (unsigned i = 0, psize = d_pendingLem.size(); i < psize; i++)
- {
- InferInfo& ii = d_pendingLem[i];
- Assert(!ii.isTrivial());
- Assert(!ii.isConflict());
- // get the explanation
- Node eqExp;
- if (options::stringRExplainLemmas())
- {
- eqExp = mkExplain(ii.d_ant, ii.d_antn);
- }
- else
- {
- std::vector<Node> ev;
- ev.insert(ev.end(), ii.d_ant.begin(), ii.d_ant.end());
- ev.insert(ev.end(), ii.d_antn.begin(), ii.d_antn.end());
- eqExp = utils::mkAnd(ev);
- }
- // make the lemma node
- Node lem = ii.d_conc;
- if (eqExp != d_true)
- {
- lem = nm->mkNode(IMPLIES, eqExp, lem);
- }
- Trace("strings-pending") << "Process pending lemma : " << lem << std::endl;
- Trace("strings-assert")
- << "(assert " << lem << ") ; lemma " << ii.d_id << std::endl;
- Trace("strings-lemma") << "Strings::Lemma: " << lem << " by " << ii.d_id
- << std::endl;
- // only keep stats if we process it here
- d_statistics.d_inferences << ii.d_id;
- ++(d_statistics.d_lemmasInfer);
+}
- // Process the side effects of the inference info.
- // Register the new skolems from this inference. We register them here
- // (lazily), since this is the moment when we have decided to process the
- // inference.
- for (const std::pair<const LengthStatus, std::vector<Node> >& sks :
- ii.d_new_skolem)
- {
- for (const Node& n : sks.second)
- {
- d_termReg.registerTermAtomic(n, sks.first);
- }
- }
+void InferenceManager::markReduced(Node n, bool contextDepend)
+{
+ d_extt.markReduced(n, contextDepend);
+}
- d_out.lemma(lem);
- }
- // process the pending require phase calls
- for (const std::pair<const Node, bool>& prp : d_pendingReqPhase)
+void InferenceManager::processConflict(const InferInfo& ii)
+{
+ Assert(!d_state.isInConflict());
+ // setup the fact to reproduce the proof in the call below
+ d_statistics.d_inferences << ii.d_id;
+ if (d_ipc != nullptr)
{
- Trace("strings-pending") << "Require phase : " << prp.first
- << ", polarity = " << prp.second << std::endl;
- d_out.requirePhase(prp.first, prp.second);
+ d_ipc->notifyFact(ii);
}
- d_pendingLem.clear();
- d_pendingReqPhase.clear();
+ // make the trust node
+ TrustNode tconf = mkConflictExp(ii.d_ant, d_ipc.get());
+ Assert(tconf.getKind() == TrustNodeKind::CONFLICT);
+ Trace("strings-assert") << "(assert (not " << tconf.getNode()
+ << ")) ; conflict " << ii.d_id << std::endl;
+ // send the trusted conflict
+ trustedConflict(tconf);
}
-void InferenceManager::assertPendingFact(Node atom, bool polarity, Node exp)
+bool InferenceManager::processFact(InferInfo& ii)
{
- eq::EqualityEngine* ee = d_state.getEqualityEngine();
- Trace("strings-pending") << "Assert pending fact : " << atom << " "
- << polarity << " from " << exp << std::endl;
- Assert(atom.getKind() != OR) << "Infer error: a split.";
- if (atom.getKind() == EQUAL)
+ // Get the fact(s). There are multiple facts if the conclusion is an AND
+ std::vector<Node> facts;
+ if (ii.d_conc.getKind() == AND)
{
- // we must ensure these terms are registered
- Trace("strings-pending-debug") << " Register term" << std::endl;
- for (const Node& t : atom)
+ for (const Node& cc : ii.d_conc)
{
- // terms in the equality engine are already registered, hence skip
- // currently done for only string-like terms, but this could potentially
- // be avoided.
- if (!ee->hasTerm(t) && t.getType().isStringLike())
- {
- d_termReg.registerTerm(t, 0);
- }
+ facts.push_back(cc);
}
- Trace("strings-pending-debug") << " Now assert equality" << std::endl;
- ee->assertEquality(atom, polarity, exp);
- Trace("strings-pending-debug") << " Finished assert equality" << std::endl;
}
else
{
- ee->assertPredicate(atom, polarity, exp);
- if (atom.getKind() == STRING_IN_REGEXP)
- {
- if (polarity && atom[1].getKind() == REGEXP_CONCAT)
- {
- Node eqc = ee->getRepresentative(atom[0]);
- d_state.addEndpointsToEqcInfo(atom, atom[1], eqc);
- }
- }
- }
- // process the conflict
- if (!d_state.isInConflict())
- {
- Node pc = d_state.getPendingConflict();
- if (!pc.isNull())
- {
- std::vector<Node> a;
- a.push_back(pc);
- Trace("strings-pending")
- << "Process pending conflict " << pc << std::endl;
- Node conflictNode = mkExplain(a);
- d_state.setConflict();
- Trace("strings-conflict")
- << "CONFLICT: Eager prefix : " << conflictNode << std::endl;
- ++(d_statistics.d_conflictsEagerPrefix);
- d_out.conflict(conflictNode);
- }
+ facts.push_back(ii.d_conc);
}
- Trace("strings-pending-debug") << " Now collect terms" << std::endl;
- // Collect extended function terms in the atom. Notice that we must register
- // all extended functions occurring in assertions and shared terms. We
- // make a similar call to registerTermRec in TheoryStrings::addSharedTerm.
- d_extt.registerTermRec(atom);
- Trace("strings-pending-debug") << " Finished collect terms" << std::endl;
-}
-
-bool InferenceManager::hasProcessed() const
-{
- return d_state.isInConflict() || !d_pendingLem.empty() || !d_pending.empty();
-}
-
-Node InferenceManager::mkExplain(const std::vector<Node>& a) const
-{
- std::vector<Node> an;
- return mkExplain(a, an);
-}
-
-Node InferenceManager::mkExplain(const std::vector<Node>& a,
- const std::vector<Node>& an) const
-{
- std::vector<TNode> antec_exp;
- // copy to processing vector
- std::vector<Node> aconj;
- for (const Node& ac : a)
+ Trace("strings-assert") << "(assert (=> " << ii.getAntecedant() << " "
+ << ii.d_conc << ")) ; fact " << ii.d_id << std::endl;
+ Trace("strings-lemma") << "Strings::Fact: " << ii.d_conc << " from "
+ << ii.getAntecedant() << " by " << ii.d_id
+ << std::endl;
+ std::vector<Node> exp;
+ for (const Node& ec : ii.d_ant)
{
- utils::flattenOp(AND, ac, aconj);
+ utils::flattenOp(AND, ec, exp);
}
- eq::EqualityEngine* ee = d_state.getEqualityEngine();
- for (const Node& apc : aconj)
+ bool ret = false;
+ // convert for each fact
+ for (const Node& fact : facts)
{
- Assert(apc.getKind() != AND);
- Debug("strings-explain") << "Add to explanation " << apc << std::endl;
- if (apc.getKind() == NOT && apc[0].getKind() == EQUAL)
+ ii.d_conc = fact;
+ d_statistics.d_inferences << ii.d_id;
+ bool polarity = fact.getKind() != NOT;
+ TNode atom = polarity ? fact : fact[0];
+ bool curRet = false;
+ if (d_ipc != nullptr)
{
- Assert(ee->hasTerm(apc[0][0]));
- Assert(ee->hasTerm(apc[0][1]));
- // ensure that we are ready to explain the disequality
- AlwaysAssert(ee->areDisequal(apc[0][0], apc[0][1], true));
+ // ensure the proof generator is ready to explain this fact in the
+ // current SAT context
+ d_ipc->notifyFact(ii);
+ // now, assert the internal fact with d_ipc as proof generator
+ curRet = assertInternalFact(atom, polarity, exp, d_ipc.get());
}
- Assert(apc.getKind() != EQUAL || ee->areEqual(apc[0], apc[1]));
- // now, explain
- explain(apc, antec_exp);
- }
- for (const Node& anc : an)
- {
- if (std::find(antec_exp.begin(), antec_exp.end(), anc) == antec_exp.end())
+ else
{
- Debug("strings-explain")
- << "Add to explanation (new literal) " << anc << std::endl;
- antec_exp.push_back(anc);
+ Node cexp = utils::mkAnd(exp);
+ // without proof generator
+ curRet = assertInternalFact(atom, polarity, cexp);
+ }
+ ret = ret || curRet;
+ // may be in conflict
+ if (d_state.isInConflict())
+ {
+ break;
}
}
- Node ant;
- if (antec_exp.empty())
- {
- ant = d_true;
- }
- else if (antec_exp.size() == 1)
- {
- ant = antec_exp[0];
- }
- else
- {
- ant = NodeManager::currentNM()->mkNode(AND, antec_exp);
- }
- return ant;
+ return ret;
}
-void InferenceManager::explain(TNode literal,
- std::vector<TNode>& assumptions) const
+bool InferenceManager::processLemma(InferInfo& ii)
{
- Debug("strings-explain") << "Explain " << literal << " "
- << d_state.isInConflict() << std::endl;
- eq::EqualityEngine* ee = d_state.getEqualityEngine();
- bool polarity = literal.getKind() != NOT;
- TNode atom = polarity ? literal : literal[0];
- std::vector<TNode> tassumptions;
- if (atom.getKind() == EQUAL)
+ Assert(!ii.isTrivial());
+ Assert(!ii.isConflict());
+ // set up the explanation and no-explanation
+ std::vector<Node> exp;
+ for (const Node& ec : ii.d_ant)
{
- if (atom[0] != atom[1])
- {
- Assert(ee->hasTerm(atom[0]));
- Assert(ee->hasTerm(atom[1]));
- ee->explainEquality(atom[0], atom[1], polarity, tassumptions);
- }
+ utils::flattenOp(AND, ec, exp);
}
- else
+ std::vector<Node> noExplain;
+ if (!options::stringRExplainLemmas())
{
- ee->explainPredicate(atom, polarity, tassumptions);
+ // if we aren't regressing the explanation, we add all literals to
+ // noExplain and ignore ii.d_ant.
+ noExplain.insert(noExplain.end(), exp.begin(), exp.end());
}
- for (const TNode& a : tassumptions)
+ else
{
- if (std::find(assumptions.begin(), assumptions.end(), a)
- == assumptions.end())
+ // otherwise, the no-explain literals are those provided
+ for (const Node& ecn : ii.d_noExplain)
{
- assumptions.push_back(a);
+ utils::flattenOp(AND, ecn, noExplain);
}
}
- if (Debug.isOn("strings-explain-debug"))
+ // ensure that the proof generator is ready to explain the final conclusion
+ // of the lemma (ii.d_conc).
+ d_statistics.d_inferences << ii.d_id;
+ if (d_ipc != nullptr)
+ {
+ d_ipc->notifyFact(ii);
+ }
+ TrustNode tlem = mkLemmaExp(ii.d_conc, exp, noExplain, d_ipc.get());
+ Trace("strings-pending") << "Process pending lemma : " << tlem.getNode()
+ << std::endl;
+
+ // Process the side effects of the inference info.
+ // Register the new skolems from this inference. We register them here
+ // (lazily), since this is the moment when we have decided to process the
+ // inference.
+ for (const std::pair<const LengthStatus, std::vector<Node> >& sks :
+ ii.d_new_skolem)
{
- Debug("strings-explain-debug")
- << "Explanation for " << literal << " was " << std::endl;
- for (const TNode& a : tassumptions)
+ for (const Node& n : sks.second)
{
- Debug("strings-explain-debug") << " " << a << std::endl;
+ d_termReg.registerTermAtomic(n, sks.first);
}
}
-}
-
-void InferenceManager::markCongruent(Node a, Node b)
-{
- Assert(a.getKind() == b.getKind());
- if (d_extt.hasFunctionKind(a.getKind()))
+ LemmaProperty p = LemmaProperty::NONE;
+ if (ii.d_id == Inference::REDUCTION)
{
- d_extt.markCongruent(a, b);
+ p |= LemmaProperty::NEEDS_JUSTIFY;
}
-}
+ Trace("strings-assert") << "(assert " << tlem.getNode() << ") ; lemma "
+ << ii.d_id << std::endl;
+ Trace("strings-lemma") << "Strings::Lemma: " << tlem.getNode() << " by "
+ << ii.d_id << std::endl;
+ ++(d_statistics.d_lemmasInfer);
-void InferenceManager::markReduced(Node n, bool contextDepend)
-{
- d_extt.markReduced(n, contextDepend);
+ // call the trusted lemma, without caching
+ return trustedLemma(tlem, p, false);
}
} // namespace strings
diff --git a/src/theory/strings/inference_manager.h b/src/theory/strings/inference_manager.h
index 4e50a6cb7..3280281bd 100644
--- a/src/theory/strings/inference_manager.h
+++ b/src/theory/strings/inference_manager.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -23,12 +23,16 @@
#include "context/cdhashset.h"
#include "context/context.h"
#include "expr/node.h"
+#include "expr/proof_node_manager.h"
#include "theory/ext_theory.h"
+#include "theory/inference_manager_buffered.h"
#include "theory/output_channel.h"
#include "theory/strings/infer_info.h"
+#include "theory/strings/infer_proof_cons.h"
#include "theory/strings/sequences_stats.h"
#include "theory/strings/solver_state.h"
#include "theory/strings/term_registry.h"
+#include "theory/theory_inference_manager.h"
#include "theory/uf/equality_engine.h"
namespace CVC4 {
@@ -65,27 +69,29 @@ namespace strings {
* theory of strings, e.g. sendPhaseRequirement, setIncomplete, and
* with the extended theory object e.g. markCongruent.
*/
-class InferenceManager
+class InferenceManager : public InferenceManagerBuffered
{
typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
+ friend class InferInfo;
public:
- InferenceManager(context::Context* c,
- context::UserContext* u,
+ InferenceManager(Theory& t,
SolverState& s,
TermRegistry& tr,
ExtTheory& e,
- OutputChannel& out,
- SequencesStatistics& statistics);
+ SequencesStatistics& statistics,
+ ProofNodeManager* pnm);
~InferenceManager() {}
- /** send assumption
- *
- * This is called when a fact is asserted to TheoryStrings. It adds lit
- * to the equality engine maintained by this class immediately.
+ /**
+ * Do pending method. This processes all pending facts, lemmas and pending
+ * phase requests based on the policy of this manager. This means that
+ * we process the pending facts first and abort if in conflict. Otherwise, we
+ * process the pending lemmas and then the pending phase requirements.
+ * Notice that we process the pending lemmas even if there were facts.
*/
- void sendAssumption(TNode lit);
+ void doPending();
/** send internal inferences
*
@@ -109,26 +115,27 @@ class InferenceManager
bool sendInternalInference(std::vector<Node>& exp,
Node conc,
Inference infer);
+
/** send inference
*
- * This function should be called when ( exp ^ exp_n ) => eq. The set exp
+ * This function should be called when exp => eq. The set exp
* contains literals that are explainable, i.e. those that hold in the
* equality engine of the theory of strings. On the other hand, the set
- * exp_n ("explanations new") contain nodes that are not explainable by the
- * theory of strings. This method may call sendLemma or otherwise add a
- * InferInfo to d_pending, indicating a fact should be asserted to the
- * equality engine. Overall, the result of this method is one of the
- * following:
+ * noExplain contains nodes that are not explainable by the theory of strings.
+ * This method may call sendLemma or otherwise add a InferInfo to d_pending,
+ * indicating a fact should be asserted to the equality engine. Overall, the
+ * result of this method is one of the following:
*
- * [1] (No-op) Do nothing if eq is true,
+ * [1] (No-op) Do nothing if eq is equivalent to true,
*
* [2] (Infer) Indicate that eq should be added to the equality engine of this
* class with explanation exp, where exp is a set of literals that currently
* hold in the equality engine. We add this to the pending vector d_pending.
*
- * [3] (Lemma) Indicate that the lemma ( EXPLAIN(exp) ^ exp_n ) => eq should
- * be sent on the output channel of the theory of strings, where EXPLAIN
- * returns the explanation of the node in exp in terms of the literals
+ * [3] (Lemma) Indicate that the lemma
+ * ( EXPLAIN(exp \ noExplain) ^ noExplain ) => eq
+ * should be sent on the output channel of the theory of strings, where
+ * EXPLAIN returns the explanation of the node in exp in terms of the literals
* asserted to the theory of strings, as computed by the equality engine.
* This is also added to a pending vector, d_pendingLem.
*
@@ -136,25 +143,35 @@ class InferenceManager
* channel of the theory of strings.
*
* Determining which case to apply depends on the form of eq and whether
- * exp_n is empty. In particular, lemmas must be used whenever exp_n is
- * non-empty, conflicts are used when exp_n is empty and eq is false.
+ * noExplain is empty. In particular, lemmas must be used whenever noExplain
+ * is non-empty, conflicts are used when noExplain is empty and eq is false.
*
- * The argument infer identifies the reason for inference, used for
+ * @param exp The explanation of eq.
+ * @param noExplain The subset of exp that cannot be explained by the
+ * equality engine. This may impact whether we are processing this call as a
+ * fact or as a lemma.
+ * @param eq The conclusion.
+ * @param infer Identifies the reason for inference, used for
* debugging. This updates the statistics about the number of inferences made
* of each type.
- *
- * If the flag asLemma is true, then this method will send a lemma instead
+ * @param isRev Whether this is the "reverse variant" of the inference, which
+ * is used as a hint for proof reconstruction.
+ * @param asLemma If true, then this method will send a lemma instead
* of a fact whenever applicable.
+ * @return true if the inference was not trivial (e.g. its conclusion did
+ * not rewrite to true).
*/
- void sendInference(const std::vector<Node>& exp,
- const std::vector<Node>& exp_n,
+ bool sendInference(const std::vector<Node>& exp,
+ const std::vector<Node>& noExplain,
Node eq,
Inference infer,
+ bool isRev = false,
bool asLemma = false);
- /** same as above, but where exp_n is empty */
- void sendInference(const std::vector<Node>& exp,
+ /** same as above, but where noExplain is empty */
+ bool sendInference(const std::vector<Node>& exp,
Node eq,
Inference infer,
+ bool isRev = false,
bool asLemma = false);
/** Send inference
@@ -169,7 +186,7 @@ class InferenceManager
* If the flag asLemma is true, then this method will send a lemma instead
* of a fact whenever applicable.
*/
- void sendInference(const InferInfo& ii, bool asLemma = false);
+ void sendInference(InferInfo& ii, bool asLemma = false);
/** Send split
*
* This requests that ( a = b V a != b ) is sent on the output channel as a
@@ -184,17 +201,6 @@ class InferenceManager
* otherwise. A split is trivial if a=b rewrites to a constant.
*/
bool sendSplit(Node a, Node b, Inference infer, bool preq = true);
-
- /** Send phase requirement
- *
- * This method is called to indicate this class should send a phase
- * requirement request to the output channel for literal lit to be
- * decided with polarity pol. This requirement is processed at the same time
- * lemmas are sent on the output channel of this class during this call to
- * check. This means if the current lemmas of this class are abandoned (due
- * to a conflict), the phase requirement is not processed.
- */
- void sendPhaseRequirement(Node lit, bool pol);
/**
* Set that we are incomplete for the current set of assertions (in other
* words, we must answer "unknown" instead of "sat"); this calls the output
@@ -211,60 +217,13 @@ class InferenceManager
/** Adds lit to the vector exp if it is non-null */
void addToExplanation(Node lit, std::vector<Node>& exp) const;
//----------------------------end constructing antecedants
- /** Do pending facts
- *
- * This method asserts pending facts (d_pending) with explanations
- * (d_pendingExp) to the equality engine of the theory of strings via calls
- * to assertPendingFact.
- *
- * It terminates early if a conflict is encountered, for instance, by
- * equality reasoning within the equality engine.
- *
- * Regardless of whether a conflict is encountered, the vector d_pending
- * and map d_pendingExp are cleared.
- */
- void doPendingFacts();
- /** Do pending lemmas
- *
- * This method flushes all pending lemmas (d_pending_lem) to the output
- * channel of theory of strings.
- *
- * Like doPendingFacts, this function will terminate early if a conflict
- * has already been encountered by the theory of strings. The vector
- * d_pending_lem is cleared regardless of whether a conflict is discovered.
- *
- * Notice that as a result of the above design, some lemmas may be "dropped"
- * if a conflict is discovered in between when a lemma is added to the
- * pending vector of this class (via a sendInference call). Lemmas
- * e.g. those that are required for initialization should not be sent via
- * this class, since they should never be dropped.
- */
- void doPendingLemmas();
/**
* Have we processed an inference during this call to check? In particular,
* this returns true if we have a pending fact or lemma, or have encountered
* a conflict.
*/
bool hasProcessed() const;
- /** Do we have a pending fact to add to the equality engine? */
- bool hasPendingFact() const { return !d_pending.empty(); }
- /** Do we have a pending lemma to send on the output channel? */
- bool hasPendingLemma() const { return !d_pendingLem.empty(); }
- /** make explanation
- *
- * This returns a node corresponding to the explanation of formulas in a,
- * interpreted conjunctively. The returned node is a conjunction of literals
- * that have been asserted to the equality engine.
- */
- Node mkExplain(const std::vector<Node>& a) const;
- /** Same as above, but the new literals an are append to the result */
- Node mkExplain(const std::vector<Node>& a, const std::vector<Node>& an) const;
- /**
- * Explain literal l, add conjuncts to assumptions vector instead of making
- * the node corresponding to their conjunction.
- */
- void explain(TNode literal, std::vector<TNode>& assumptions) const;
// ------------------------------------------------- extended theory
/**
* Mark that terms a and b are congruent in the current context.
@@ -281,48 +240,33 @@ class InferenceManager
void markReduced(Node n, bool contextDepend = true);
// ------------------------------------------------- end extended theory
- private:
- /** assert pending fact
- *
- * This asserts atom with polarity to the equality engine of this class,
- * where exp is the explanation of why (~) atom holds.
- *
- * This call may trigger further initialization steps involving the terms
- * of atom, including calls to registerTerm.
+ /**
+ * Called when ii is ready to be processed as a conflict. This makes a
+ * trusted node whose generator is the underlying proof equality engine
+ * (if it exists), and sends it on the output channel.
*/
- void assertPendingFact(Node atom, bool polarity, Node exp);
+ void processConflict(const InferInfo& ii);
+
+ private:
+ /** Called when ii is ready to be processed as a fact */
+ bool processFact(InferInfo& ii);
+ /** Called when ii is ready to be processed as a lemma */
+ bool processLemma(InferInfo& ii);
/** Reference to the solver state of the theory of strings. */
SolverState& d_state;
/** Reference to the term registry of theory of strings */
TermRegistry& d_termReg;
/** the extended theory object for the theory of strings */
ExtTheory& d_extt;
- /** A reference to the output channel of the theory of strings. */
- OutputChannel& d_out;
/** Reference to the statistics for the theory of strings/sequences. */
SequencesStatistics& d_statistics;
-
+ /** Conversion from inferences to proofs */
+ std::unique_ptr<InferProofCons> d_ipc;
/** Common constants */
Node d_true;
Node d_false;
Node d_zero;
Node d_one;
- /**
- * The list of pending literals to assert to the equality engine along with
- * their explanation.
- */
- std::vector<InferInfo> d_pending;
- /** A map from literals to their pending phase requirement */
- std::map<Node, bool> d_pendingReqPhase;
- /** A list of pending lemmas to be sent on the output channel. */
- std::vector<InferInfo> d_pendingLem;
- /**
- * The keep set of this class. This set is maintained to ensure that
- * facts and their explanations are ref-counted. Since facts and their
- * explanations are SAT-context-dependent, this set is also
- * SAT-context-dependent.
- */
- NodeSet d_keep;
};
} // namespace strings
diff --git a/src/theory/strings/kinds b/src/theory/strings/kinds
index 226dcbd17..020cedb30 100644
--- a/src/theory/strings/kinds
+++ b/src/theory/strings/kinds
@@ -6,7 +6,7 @@
theory THEORY_STRINGS ::CVC4::theory::strings::TheoryStrings "theory/strings/theory_strings.h"
-properties check parametric propagate presolve
+properties check parametric presolve
rewriter ::CVC4::theory::strings::SequencesRewriter "theory/strings/sequences_rewriter.h"
@@ -83,13 +83,14 @@ constant CONST_SEQUENCE \
"a sequence of characters"
operator SEQ_UNIT 1 "a sequence of length one"
+operator SEQ_NTH 2 "The nth element of a sequence"
# equal equal / less than / output
operator STRING_TO_REGEXP 1 "convert string to regexp"
operator REGEXP_CONCAT 2: "regexp concat"
operator REGEXP_UNION 2: "regexp union"
operator REGEXP_INTER 2: "regexp intersection"
-operator REGEXP_DIFF 2: "regexp difference"
+operator REGEXP_DIFF 2 "regexp difference"
operator REGEXP_STAR 1 "regexp *"
operator REGEXP_PLUS 1 "regexp +"
operator REGEXP_OPT 1 "regexp ?"
@@ -169,5 +170,6 @@ typerule STRING_TOLOWER "SimpleTypeRule<RString, AString>"
typerule CONST_SEQUENCE ::CVC4::theory::strings::ConstSequenceTypeRule
typerule SEQ_UNIT ::CVC4::theory::strings::SeqUnitTypeRule
+typerule SEQ_NTH ::CVC4::theory::strings::SeqNthTypeRule
endtheory
diff --git a/src/theory/strings/normal_form.cpp b/src/theory/strings/normal_form.cpp
index 02af4904a..7fdf3ff76 100644
--- a/src/theory/strings/normal_form.cpp
+++ b/src/theory/strings/normal_form.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -83,6 +83,7 @@ void NormalForm::addToExplanation(Node exp,
unsigned new_val,
unsigned new_rev_val)
{
+ Assert(!exp.isConst());
if (std::find(d_exp.begin(), d_exp.end(), exp) == d_exp.end())
{
d_exp.push_back(exp);
@@ -177,11 +178,9 @@ void NormalForm::getExplanationForPrefixEq(NormalForm& nfi,
Trace("strings-explain-prefix")
<< "Included " << curr_exp.size() << " / "
<< (nfi.d_exp.size() + nfj.d_exp.size()) << std::endl;
- if (nfi.d_base != nfj.d_base)
- {
- Node eq = nfi.d_base.eqNode(nfj.d_base);
- curr_exp.push_back(eq);
- }
+ // add explanation for why they are equal
+ Node eq = nfi.d_base.eqNode(nfj.d_base);
+ curr_exp.push_back(eq);
}
} // namespace strings
diff --git a/src/theory/strings/normal_form.h b/src/theory/strings/normal_form.h
index bd60b0252..568b83319 100644
--- a/src/theory/strings/normal_form.h
+++ b/src/theory/strings/normal_form.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/proof_checker.cpp b/src/theory/strings/proof_checker.cpp
new file mode 100644
index 000000000..0b6cf6652
--- /dev/null
+++ b/src/theory/strings/proof_checker.cpp
@@ -0,0 +1,509 @@
+/********************* */
+/*! \file proof_checker.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of strings proof checker
+ **/
+
+#include "theory/strings/proof_checker.h"
+
+#include "expr/sequence.h"
+#include "options/strings_options.h"
+#include "theory/rewriter.h"
+#include "theory/strings/core_solver.h"
+#include "theory/strings/regexp_elim.h"
+#include "theory/strings/regexp_operation.h"
+#include "theory/strings/term_registry.h"
+#include "theory/strings/theory_strings_preprocess.h"
+#include "theory/strings/theory_strings_utils.h"
+#include "theory/strings/word.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+void StringProofRuleChecker::registerTo(ProofChecker* pc)
+{
+ pc->registerChecker(PfRule::CONCAT_EQ, this);
+ pc->registerChecker(PfRule::CONCAT_UNIFY, this);
+ pc->registerChecker(PfRule::CONCAT_CONFLICT, this);
+ pc->registerChecker(PfRule::CONCAT_SPLIT, this);
+ pc->registerChecker(PfRule::CONCAT_CSPLIT, this);
+ pc->registerChecker(PfRule::CONCAT_LPROP, this);
+ pc->registerChecker(PfRule::CONCAT_CPROP, this);
+ pc->registerChecker(PfRule::STRING_DECOMPOSE, this);
+ pc->registerChecker(PfRule::STRING_LENGTH_POS, this);
+ pc->registerChecker(PfRule::STRING_LENGTH_NON_EMPTY, this);
+ pc->registerChecker(PfRule::STRING_REDUCTION, this);
+ pc->registerChecker(PfRule::STRING_EAGER_REDUCTION, this);
+ pc->registerChecker(PfRule::RE_INTER, this);
+ pc->registerChecker(PfRule::RE_UNFOLD_POS, this);
+ pc->registerChecker(PfRule::RE_UNFOLD_NEG, this);
+ pc->registerChecker(PfRule::RE_UNFOLD_NEG_CONCAT_FIXED, this);
+ pc->registerChecker(PfRule::RE_ELIM, this);
+ pc->registerChecker(PfRule::STRING_CODE_INJ, this);
+ pc->registerChecker(PfRule::STRING_SEQ_UNIT_INJ, this);
+ // trusted rules
+ pc->registerTrustedChecker(PfRule::STRING_TRUST, this, 2);
+}
+
+Node StringProofRuleChecker::checkInternal(PfRule id,
+ const std::vector<Node>& children,
+ const std::vector<Node>& args)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ // core rules for word equations
+ if (id == PfRule::CONCAT_EQ || id == PfRule::CONCAT_UNIFY
+ || id == PfRule::CONCAT_CONFLICT || id == PfRule::CONCAT_SPLIT
+ || id == PfRule::CONCAT_CSPLIT || id == PfRule::CONCAT_LPROP
+ || id == PfRule::CONCAT_CPROP)
+ {
+ Trace("strings-pfcheck") << "Checking id " << id << std::endl;
+ Assert(children.size() >= 1);
+ Assert(args.size() == 1);
+ // all rules have an equality
+ if (children[0].getKind() != EQUAL)
+ {
+ return Node::null();
+ }
+ // convert to concatenation form
+ std::vector<Node> tvec;
+ std::vector<Node> svec;
+ utils::getConcat(children[0][0], tvec);
+ utils::getConcat(children[0][1], svec);
+ size_t nchildt = tvec.size();
+ size_t nchilds = svec.size();
+ TypeNode stringType = children[0][0].getType();
+ // extract the Boolean corresponding to whether the rule is reversed
+ bool isRev;
+ if (!getBool(args[0], isRev))
+ {
+ return Node::null();
+ }
+ if (id == PfRule::CONCAT_EQ)
+ {
+ Assert(children.size() == 1);
+ size_t index = 0;
+ std::vector<Node> tremVec;
+ std::vector<Node> sremVec;
+ // scan the concatenation until we exhaust child proofs
+ while (index < nchilds && index < nchildt)
+ {
+ Node currT = tvec[isRev ? (nchildt - 1 - index) : index];
+ Node currS = svec[isRev ? (nchilds - 1 - index) : index];
+ if (currT != currS)
+ {
+ if (currT.isConst() && currS.isConst())
+ {
+ size_t sindex;
+ // get the equal prefix/suffix, strip and add the remainders
+ Node currR = Word::splitConstant(currT, currS, sindex, isRev);
+ if (!currR.isNull())
+ {
+ // add the constant to remainder vec
+ std::vector<Node>& rem = sindex == 0 ? tremVec : sremVec;
+ rem.push_back(currR);
+ // ignore the current component
+ index++;
+ // In other words, if we have (currS,currT) = ("ab","abc"), then
+ // we proceed to the next component and add currR = "c" to
+ // tremVec.
+ }
+ // otherwise if we are not the same prefix, then both will be added
+ // Notice that we do not add maximal prefixes, in other words,
+ // ("abc", "abd") may be added to the remainder vectors, and not
+ // ("c", "d").
+ }
+ break;
+ }
+ index++;
+ }
+ Assert(index <= nchildt);
+ Assert(index <= nchilds);
+ // the remainders are equal
+ tremVec.insert(isRev ? tremVec.begin() : tremVec.end(),
+ tvec.begin() + (isRev ? 0 : index),
+ tvec.begin() + nchildt - (isRev ? index : 0));
+ sremVec.insert(isRev ? sremVec.begin() : sremVec.end(),
+ svec.begin() + (isRev ? 0 : index),
+ svec.begin() + nchilds - (isRev ? index : 0));
+ // convert back to node
+ Node trem = utils::mkConcat(tremVec, stringType);
+ Node srem = utils::mkConcat(sremVec, stringType);
+ return trem.eqNode(srem);
+ }
+ // all remaining rules do something with the first child of each side
+ Node t0 = tvec[isRev ? nchildt - 1 : 0];
+ Node s0 = svec[isRev ? nchilds - 1 : 0];
+ if (id == PfRule::CONCAT_UNIFY)
+ {
+ Assert(children.size() == 2);
+ if (children[1].getKind() != EQUAL)
+ {
+ return Node::null();
+ }
+ for (size_t i = 0; i < 2; i++)
+ {
+ Node l = children[1][i];
+ if (l.getKind() != STRING_LENGTH)
+ {
+ return Node::null();
+ }
+ Node term = i == 0 ? t0 : s0;
+ if (l[0] == term)
+ {
+ continue;
+ }
+ // could be a spliced constant
+ bool success = false;
+ if (term.isConst() && l[0].isConst())
+ {
+ size_t lenL = Word::getLength(l[0]);
+ success = (isRev && l[0] == Word::suffix(term, lenL))
+ || (!isRev && l[0] == Word::prefix(term, lenL));
+ }
+ if (!success)
+ {
+ return Node::null();
+ }
+ }
+ return children[1][0][0].eqNode(children[1][1][0]);
+ }
+ else if (id == PfRule::CONCAT_CONFLICT)
+ {
+ Assert(children.size() == 1);
+ if (!t0.isConst() || !s0.isConst())
+ {
+ // not constants
+ return Node::null();
+ }
+ size_t sindex;
+ Node r0 = Word::splitConstant(t0, s0, sindex, isRev);
+ if (!r0.isNull())
+ {
+ // Not a conflict due to constants, i.e. s0 is a prefix of t0 or vice
+ // versa.
+ return Node::null();
+ }
+ return nm->mkConst(false);
+ }
+ else if (id == PfRule::CONCAT_SPLIT)
+ {
+ Assert(children.size() == 2);
+ if (children[1].getKind() != NOT || children[1][0].getKind() != EQUAL
+ || children[1][0][0].getKind() != STRING_LENGTH
+ || children[1][0][0][0] != t0
+ || children[1][0][1].getKind() != STRING_LENGTH
+ || children[1][0][1][0] != s0)
+ {
+ return Node::null();
+ }
+ }
+ else if (id == PfRule::CONCAT_CSPLIT)
+ {
+ Assert(children.size() == 2);
+ Node zero = nm->mkConst(Rational(0));
+ Node one = nm->mkConst(Rational(1));
+ if (children[1].getKind() != NOT || children[1][0].getKind() != EQUAL
+ || children[1][0][0].getKind() != STRING_LENGTH
+ || children[1][0][0][0] != t0 || children[1][0][1] != zero)
+ {
+ return Node::null();
+ }
+ if (!s0.isConst() || !s0.getType().isStringLike() || Word::isEmpty(s0))
+ {
+ return Node::null();
+ }
+ }
+ else if (id == PfRule::CONCAT_LPROP)
+ {
+ Assert(children.size() == 2);
+ if (children[1].getKind() != GT
+ || children[1][0].getKind() != STRING_LENGTH
+ || children[1][0][0] != t0
+ || children[1][1].getKind() != STRING_LENGTH
+ || children[1][1][0] != s0)
+ {
+ return Node::null();
+ }
+ }
+ else if (id == PfRule::CONCAT_CPROP)
+ {
+ Assert(children.size() == 2);
+ Node zero = nm->mkConst(Rational(0));
+
+ Trace("pfcheck-strings-cprop")
+ << "CONCAT_PROP, isRev=" << isRev << std::endl;
+ if (children[1].getKind() != NOT || children[1][0].getKind() != EQUAL
+ || children[1][0][0].getKind() != STRING_LENGTH
+ || children[1][0][0][0] != t0 || children[1][0][1] != zero)
+ {
+ Trace("pfcheck-strings-cprop")
+ << "...failed pattern match" << std::endl;
+ return Node::null();
+ }
+ if (tvec.size() <= 1)
+ {
+ Trace("pfcheck-strings-cprop")
+ << "...failed adjacent constant" << std::endl;
+ return Node::null();
+ }
+ Node w1 = tvec[isRev ? nchildt - 2 : 1];
+ if (!w1.isConst() || !w1.getType().isStringLike() || Word::isEmpty(w1))
+ {
+ Trace("pfcheck-strings-cprop")
+ << "...failed adjacent constant content" << std::endl;
+ return Node::null();
+ }
+ Node w2 = s0;
+ if (!w2.isConst() || !w2.getType().isStringLike() || Word::isEmpty(w2))
+ {
+ Trace("pfcheck-strings-cprop") << "...failed constant" << std::endl;
+ return Node::null();
+ }
+ // getConclusion expects the adjacent constant to be included
+ t0 = nm->mkNode(STRING_CONCAT, isRev ? w1 : t0, isRev ? t0 : w1);
+ }
+ // use skolem cache
+ SkolemCache skc(false);
+ std::vector<Node> newSkolems;
+ Node conc = CoreSolver::getConclusion(t0, s0, id, isRev, &skc, newSkolems);
+ return conc;
+ }
+ else if (id == PfRule::STRING_DECOMPOSE)
+ {
+ Assert(children.size() == 1);
+ Assert(args.size() == 1);
+ bool isRev;
+ if (!getBool(args[0], isRev))
+ {
+ return Node::null();
+ }
+ Node atom = children[0];
+ if (atom.getKind() != GEQ || atom[0].getKind() != STRING_LENGTH)
+ {
+ return Node::null();
+ }
+ SkolemCache sc(false);
+ std::vector<Node> newSkolems;
+ Node conc = CoreSolver::getConclusion(
+ atom[0][0], atom[1], id, isRev, &sc, newSkolems);
+ return conc;
+ }
+ else if (id == PfRule::STRING_REDUCTION
+ || id == PfRule::STRING_EAGER_REDUCTION
+ || id == PfRule::STRING_LENGTH_POS)
+ {
+ Assert(children.empty());
+ Assert(args.size() >= 1);
+ // These rules are based on calling a C++ method for returning a valid
+ // lemma involving a single argument term.
+ // Must convert to skolem form.
+ Node t = args[0];
+ Node ret;
+ if (id == PfRule::STRING_REDUCTION)
+ {
+ Assert(args.size() == 1);
+ // we do not use optimizations
+ SkolemCache skc(false);
+ std::vector<Node> conj;
+ ret = StringsPreprocess::reduce(t, conj, &skc);
+ conj.push_back(t.eqNode(ret));
+ ret = nm->mkAnd(conj);
+ }
+ else if (id == PfRule::STRING_EAGER_REDUCTION)
+ {
+ Assert(args.size() == 1);
+ SkolemCache skc(false);
+ ret = TermRegistry::eagerReduce(t, &skc);
+ }
+ else if (id == PfRule::STRING_LENGTH_POS)
+ {
+ Assert(args.size() == 1);
+ ret = TermRegistry::lengthPositive(t);
+ }
+ if (ret.isNull())
+ {
+ return Node::null();
+ }
+ return ret;
+ }
+ else if (id == PfRule::STRING_LENGTH_NON_EMPTY)
+ {
+ Assert(children.size() == 1);
+ Assert(args.empty());
+ Node nemp = children[0];
+ if (nemp.getKind() != NOT || nemp[0].getKind() != EQUAL
+ || !nemp[0][1].isConst() || !nemp[0][1].getType().isStringLike())
+ {
+ return Node::null();
+ }
+ if (!Word::isEmpty(nemp[0][1]))
+ {
+ return Node::null();
+ }
+ Node zero = nm->mkConst(Rational(0));
+ Node clen = nm->mkNode(STRING_LENGTH, nemp[0][0]);
+ return clen.eqNode(zero).notNode();
+ }
+ else if (id == PfRule::RE_INTER)
+ {
+ Assert(children.size() >= 1);
+ Assert(args.empty());
+ std::vector<Node> reis;
+ Node x;
+ // make the regular expression intersection that summarizes all
+ // memberships in the explanation
+ for (const Node& c : children)
+ {
+ bool polarity = c.getKind() != NOT;
+ Node catom = polarity ? c : c[0];
+ if (catom.getKind() != STRING_IN_REGEXP)
+ {
+ return Node::null();
+ }
+ if (x.isNull())
+ {
+ x = catom[0];
+ }
+ else if (x != catom[0])
+ {
+ // different LHS
+ return Node::null();
+ }
+ Node xcurr = catom[0];
+ Node rcurr =
+ polarity ? catom[1] : nm->mkNode(REGEXP_COMPLEMENT, catom[1]);
+ reis.push_back(rcurr);
+ }
+ Node rei = reis.size() == 1 ? reis[0] : nm->mkNode(REGEXP_INTER, reis);
+ return nm->mkNode(STRING_IN_REGEXP, x, rei);
+ }
+ else if (id == PfRule::RE_UNFOLD_POS || id == PfRule::RE_UNFOLD_NEG
+ || id == PfRule::RE_UNFOLD_NEG_CONCAT_FIXED)
+ {
+ Assert(children.size() == 1);
+ Assert(args.empty());
+ Node skChild = children[0];
+ if (id == PfRule::RE_UNFOLD_NEG || id == PfRule::RE_UNFOLD_NEG_CONCAT_FIXED)
+ {
+ if (skChild.getKind() != NOT || skChild[0].getKind() != STRING_IN_REGEXP)
+ {
+ Trace("strings-pfcheck") << "...fail, non-neg member" << std::endl;
+ return Node::null();
+ }
+ }
+ else if (skChild.getKind() != STRING_IN_REGEXP)
+ {
+ Trace("strings-pfcheck") << "...fail, non-pos member" << std::endl;
+ return Node::null();
+ }
+ Node conc;
+ if (id == PfRule::RE_UNFOLD_POS)
+ {
+ std::vector<Node> newSkolems;
+ SkolemCache sc;
+ conc = RegExpOpr::reduceRegExpPos(skChild, &sc, newSkolems);
+ }
+ else if (id == PfRule::RE_UNFOLD_NEG)
+ {
+ conc = RegExpOpr::reduceRegExpNeg(skChild);
+ }
+ else if (id == PfRule::RE_UNFOLD_NEG_CONCAT_FIXED)
+ {
+ if (skChild[0][1].getKind() != REGEXP_CONCAT)
+ {
+ Trace("strings-pfcheck") << "...fail, no concat regexp" << std::endl;
+ return Node::null();
+ }
+ size_t index;
+ Node reLen = RegExpOpr::getRegExpConcatFixed(skChild[0][1], index);
+ if (reLen.isNull())
+ {
+ Trace("strings-pfcheck") << "...fail, non-fixed lengths" << std::endl;
+ return Node::null();
+ }
+ conc = RegExpOpr::reduceRegExpNegConcatFixed(skChild, reLen, index);
+ }
+ return conc;
+ }
+ else if (id == PfRule::RE_ELIM)
+ {
+ Assert(children.size() == 1);
+ Assert(args.empty());
+ return RegExpElimination::eliminate(children[0]);
+ }
+ else if (id == PfRule::STRING_CODE_INJ)
+ {
+ Assert(children.empty());
+ Assert(args.size() == 2);
+ Assert(args[0].getType().isStringLike()
+ && args[1].getType().isStringLike());
+ Node c1 = nm->mkNode(STRING_TO_CODE, args[0]);
+ Node c2 = nm->mkNode(STRING_TO_CODE, args[1]);
+ Node eqNegOne = c1.eqNode(nm->mkConst(Rational(-1)));
+ Node deq = c1.eqNode(c2).negate();
+ Node eqn = args[0].eqNode(args[1]);
+ return nm->mkNode(kind::OR, eqNegOne, deq, eqn);
+ }
+ else if (id == PfRule::STRING_SEQ_UNIT_INJ)
+ {
+ Assert(children.size() == 1);
+ Assert(args.empty());
+ if (children[0].getKind() != EQUAL)
+ {
+ return Node::null();
+ }
+ Node t[2];
+ for (size_t i = 0; i < 2; i++)
+ {
+ if (children[0][i].getKind() == SEQ_UNIT)
+ {
+ t[i] = children[0][i][0];
+ }
+ else if (children[0][i].isConst())
+ {
+ // notice that Word::getChars is not the right call here, since it
+ // gets a vector of sequences of length one. We actually need to
+ // extract the character, which is a sequence-specific operation.
+ const Sequence& sx = children[0][i].getConst<Sequence>();
+ const std::vector<Node>& vec = sx.getVec();
+ if (vec.size() == 1)
+ {
+ // the character of the single character sequence
+ t[i] = vec[0];
+ }
+ }
+ if (t[i].isNull())
+ {
+ return Node::null();
+ }
+ }
+ Trace("strings-pfcheck-debug")
+ << "STRING_SEQ_UNIT_INJ: " << children[0] << " => " << t[0]
+ << " == " << t[1] << std::endl;
+ AlwaysAssert(t[0].getType() == t[1].getType());
+ return t[0].eqNode(t[1]);
+ }
+ else if (id == PfRule::STRING_TRUST)
+ {
+ // "trusted" rules
+ Assert(!args.empty());
+ Assert(args[0].getType().isBoolean());
+ return args[0];
+ }
+ return Node::null();
+}
+
+} // namespace strings
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/strings/proof_checker.h b/src/theory/strings/proof_checker.h
new file mode 100644
index 000000000..a6dcd9df2
--- /dev/null
+++ b/src/theory/strings/proof_checker.h
@@ -0,0 +1,49 @@
+/********************* */
+/*! \file proof_checker.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Strings proof checker utility
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__STRINGS__PROOF_CHECKER_H
+#define CVC4__THEORY__STRINGS__PROOF_CHECKER_H
+
+#include "expr/node.h"
+#include "expr/proof_checker.h"
+#include "expr/proof_node.h"
+
+namespace CVC4 {
+namespace theory {
+namespace strings {
+
+/** A checker for strings proofs */
+class StringProofRuleChecker : public ProofRuleChecker
+{
+ public:
+ StringProofRuleChecker() {}
+ ~StringProofRuleChecker() {}
+
+ /** Register all rules owned by this rule checker in pc. */
+ void registerTo(ProofChecker* pc) override;
+
+ protected:
+ /** Return the conclusion of the given proof step, or null if it is invalid */
+ Node checkInternal(PfRule id,
+ const std::vector<Node>& children,
+ const std::vector<Node>& args) override;
+};
+
+} // namespace strings
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__STRINGS__PROOF_CHECKER_H */
diff --git a/src/theory/strings/regexp_elim.cpp b/src/theory/strings/regexp_elim.cpp
index 37920d248..1d0db0e4d 100644
--- a/src/theory/strings/regexp_elim.cpp
+++ b/src/theory/strings/regexp_elim.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tianyi Liang, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/regexp_elim.h b/src/theory/strings/regexp_elim.h
index e5f2fa854..0c1acd29d 100644
--- a/src/theory/strings/regexp_elim.h
+++ b/src/theory/strings/regexp_elim.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/regexp_entail.cpp b/src/theory/strings/regexp_entail.cpp
index 7e1f42f37..0ab634c88 100644
--- a/src/theory/strings/regexp_entail.cpp
+++ b/src/theory/strings/regexp_entail.cpp
@@ -2,10 +2,10 @@
/*! \file regexp_entail.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Andres Noetzli, Mathias Preiner
+ ** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/regexp_entail.h b/src/theory/strings/regexp_entail.h
index 9fb797c45..2fe9961de 100644
--- a/src/theory/strings/regexp_entail.h
+++ b/src/theory/strings/regexp_entail.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/regexp_operation.cpp b/src/theory/strings/regexp_operation.cpp
index a91210a7b..24d2e00bd 100644
--- a/src/theory/strings/regexp_operation.cpp
+++ b/src/theory/strings/regexp_operation.cpp
@@ -2,10 +2,10 @@
/*! \file regexp_operation.cpp
** \verbatim
** Top contributors (to current version):
- ** Tianyi Liang, Andrew Reynolds, Andres Noetzli
+ ** Tianyi Liang, Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,20 +16,20 @@
#include "theory/strings/regexp_operation.h"
-#include "expr/kind.h"
+#include "expr/node_algorithm.h"
#include "options/strings_options.h"
+#include "theory/rewriter.h"
#include "theory/strings/regexp_entail.h"
#include "theory/strings/theory_strings_utils.h"
#include "theory/strings/word.h"
-using namespace CVC4;
using namespace CVC4::kind;
namespace CVC4 {
namespace theory {
namespace strings {
-RegExpOpr::RegExpOpr()
+RegExpOpr::RegExpOpr(SkolemCache* sc)
: d_true(NodeManager::currentNM()->mkConst(true)),
d_false(NodeManager::currentNM()->mkConst(false)),
d_emptyRegexp(NodeManager::currentNM()->mkNode(kind::REGEXP_EMPTY,
@@ -38,7 +38,9 @@ RegExpOpr::RegExpOpr()
d_one(NodeManager::currentNM()->mkConst(::CVC4::Rational(1))),
d_sigma(NodeManager::currentNM()->mkNode(kind::REGEXP_SIGMA,
std::vector<Node>{})),
- d_sigma_star(NodeManager::currentNM()->mkNode(kind::REGEXP_STAR, d_sigma))
+ d_sigma_star(
+ NodeManager::currentNM()->mkNode(kind::REGEXP_STAR, d_sigma)),
+ d_sc(sc)
{
d_emptyString = Word::mkEmptyWord(NodeManager::currentNM()->stringType());
@@ -117,161 +119,147 @@ RegExpConstType RegExpOpr::getRegExpConstType(Node r)
// 0-unknown, 1-yes, 2-no
int RegExpOpr::delta( Node r, Node &exp ) {
- Trace("regexp-delta") << "RegExp-Delta starts with /" << mkString( r ) << "/" << std::endl;
+ std::map<Node, std::pair<int, Node> >::const_iterator itd =
+ d_delta_cache.find(r);
+ if (itd != d_delta_cache.end())
+ {
+ // already computed
+ exp = itd->second.second;
+ return itd->second.first;
+ }
+ Trace("regexp-delta") << "RegExpOpr::delta: " << r << std::endl;
int ret = 0;
- if( d_delta_cache.find( r ) != d_delta_cache.end() ) {
- ret = d_delta_cache[r].first;
- exp = d_delta_cache[r].second;
- } else {
- Kind k = r.getKind();
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- ret = 2;
- break;
- }
- case kind::REGEXP_SIGMA: {
- ret = 2;
- break;
- }
- case kind::STRING_TO_REGEXP: {
- Node tmp = Rewriter::rewrite(r[0]);
- if(tmp.isConst()) {
- if(tmp == d_emptyString) {
- ret = 1;
- } else {
- ret = 2;
- }
+ NodeManager* nm = NodeManager::currentNM();
+ Kind k = r.getKind();
+ switch (k)
+ {
+ case REGEXP_EMPTY:
+ case REGEXP_SIGMA:
+ case REGEXP_RANGE:
+ {
+ // does not contain empty string
+ ret = 2;
+ break;
+ }
+ case STRING_TO_REGEXP:
+ {
+ Node tmp = Rewriter::rewrite(r[0]);
+ if (tmp.isConst())
+ {
+ if (tmp == d_emptyString)
+ {
+ ret = 1;
} else {
- ret = 0;
- if(tmp.getKind() == kind::STRING_CONCAT) {
- for(unsigned i=0; i<tmp.getNumChildren(); i++) {
- if(tmp[i].isConst()) {
- ret = 2; break;
- }
- }
-
- }
- if(ret == 0) {
- exp = r[0].eqNode(d_emptyString);
- }
- }
- break;
- }
- case kind::REGEXP_CONCAT: {
- bool flag = false;
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node exp2;
- int tmp = delta( r[i], exp2 );
- if(tmp == 2) {
- ret = 2;
- break;
- } else if(tmp == 0) {
- vec_nodes.push_back( exp2 );
- flag = true;
- }
- }
- if(ret != 2) {
- if(!flag) {
- ret = 1;
- } else {
- exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::AND, vec_nodes);
- }
+ ret = 2;
}
- break;
}
- case kind::REGEXP_UNION: {
- bool flag = false;
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node exp2;
- int tmp = delta( r[i], exp2 );
- if(tmp == 1) {
- ret = 1;
- break;
- } else if(tmp == 0) {
- vec_nodes.push_back( exp2 );
- flag = true;
+ else
+ {
+ ret = 0;
+ if (tmp.getKind() == STRING_CONCAT)
+ {
+ for (const Node& tmpc : tmp)
+ {
+ if (tmpc.isConst())
+ {
+ ret = 2;
+ break;
+ }
}
}
- if(ret != 1) {
- if(!flag) {
- ret = 2;
- } else {
- exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::OR, vec_nodes);
- }
+ if (ret == 0)
+ {
+ exp = r[0].eqNode(d_emptyString);
}
- break;
}
- case kind::REGEXP_INTER: {
- bool flag = false;
- std::vector< Node > vec_nodes;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- Node exp2;
- int tmp = delta( r[i], exp2 );
- if(tmp == 2) {
- ret = 2;
- break;
- } else if(tmp == 0) {
- vec_nodes.push_back( exp2 );
- flag = true;
- }
+ break;
+ }
+ case REGEXP_CONCAT:
+ case REGEXP_UNION:
+ case REGEXP_INTER:
+ {
+ // has there been an unknown child?
+ bool hasUnknownChild = false;
+ std::vector<Node> vec;
+ int checkTmp = k == REGEXP_UNION ? 1 : 2;
+ int retTmp = k == REGEXP_UNION ? 2 : 1;
+ for (const Node& rc : r)
+ {
+ Node exp2;
+ int tmp = delta(rc, exp2);
+ if (tmp == checkTmp)
+ {
+ // return is implied by the child's return value
+ ret = checkTmp;
+ break;
}
- if(ret != 2) {
- if(!flag) {
- ret = 1;
- } else {
- exp = vec_nodes.size()==1 ? vec_nodes[0] : NodeManager::currentNM()->mkNode(kind::AND, vec_nodes);
- }
+ else if (tmp == 0)
+ {
+ // unknown if child contains empty string
+ Assert(!exp2.isNull());
+ vec.push_back(exp2);
+ hasUnknownChild = true;
}
- break;
- }
- case kind::REGEXP_STAR: {
- ret = 1;
- break;
- }
- case kind::REGEXP_PLUS: {
- ret = delta( r[0], exp );
- break;
- }
- case kind::REGEXP_OPT: {
- ret = 1;
- break;
- }
- case kind::REGEXP_RANGE: {
- ret = 2;
- break;
}
- case kind::REGEXP_LOOP: {
- uint32_t lo = utils::getLoopMinOccurrences(r);
- if (lo == 0)
+ if (ret != checkTmp)
+ {
+ if (!hasUnknownChild)
{
- ret = 1;
+ ret = retTmp;
} else {
- ret = delta(r[0], exp);
+ Kind kr = k == REGEXP_UNION ? OR : AND;
+ exp = vec.size() == 1 ? vec[0] : nm->mkNode(kr, vec);
}
- break;
}
- case kind::REGEXP_COMPLEMENT:
+ break;
+ }
+ case REGEXP_STAR:
+ case REGEXP_OPT:
+ {
+ // contains empty string
+ ret = 1;
+ break;
+ }
+ case REGEXP_PLUS:
+ {
+ ret = delta(r[0], exp);
+ break;
+ }
+ case REGEXP_LOOP:
+ {
+ uint32_t lo = utils::getLoopMinOccurrences(r);
+ if (lo == 0)
{
- int tmp = delta(r[0], exp);
- // flip the result if known
- tmp = tmp == 0 ? 0 : (3 - tmp);
- exp = exp.isNull() ? exp : exp.negate();
- break;
+ ret = 1;
}
- default: {
- Assert(!utils::isRegExpKind(k));
- break;
+ else
+ {
+ ret = delta(r[0], exp);
}
+ break;
+ }
+ case REGEXP_COMPLEMENT:
+ {
+ int tmp = delta(r[0], exp);
+ // flip the result if known
+ ret = tmp == 0 ? 0 : (3 - tmp);
+ exp = exp.isNull() ? exp : exp.negate();
+ break;
}
- if(!exp.isNull()) {
- exp = Rewriter::rewrite(exp);
+ default:
+ {
+ Assert(!utils::isRegExpKind(k));
+ break;
}
- std::pair< int, Node > p(ret, exp);
- d_delta_cache[r] = p;
}
- Trace("regexp-delta") << "RegExp-Delta returns : " << ret << std::endl;
+ if (!exp.isNull())
+ {
+ exp = Rewriter::rewrite(exp);
+ }
+ std::pair<int, Node> p(ret, exp);
+ d_delta_cache[r] = p;
+ Trace("regexp-delta") << "RegExpOpr::delta returns " << ret << " for " << r
+ << ", expr = " << exp << std::endl;
return ret;
}
@@ -835,444 +823,265 @@ void RegExpOpr::firstChars(Node r, std::set<unsigned> &pcset, SetNodes &pvset)
}
}
-//simplify
-void RegExpOpr::simplify(Node t, std::vector< Node > &new_nodes, bool polarity) {
- Trace("strings-regexp-simpl") << "RegExp-Simpl starts with " << t << ", polarity=" << polarity << std::endl;
+Node RegExpOpr::simplify(Node t, bool polarity)
+{
+ Trace("strings-regexp-simpl")
+ << "RegExpOpr::simplify: " << t << ", polarity=" << polarity << std::endl;
Assert(t.getKind() == kind::STRING_IN_REGEXP);
- Node str = t[0];
- Node re = t[1];
- if(polarity) {
- simplifyPRegExp( str, re, new_nodes );
- } else {
- simplifyNRegExp( str, re, new_nodes );
+ Node tlit = polarity ? t : t.notNode();
+ Node conc;
+ std::map<Node, Node>::const_iterator itr = d_simpCache.find(tlit);
+ if (itr != d_simpCache.end())
+ {
+ return itr->second;
}
- Trace("strings-regexp-simpl") << "RegExp-Simpl returns (" << new_nodes.size() << "):\n";
- for(unsigned i=0; i<new_nodes.size(); i++) {
- Trace("strings-regexp-simpl") << "\t" << new_nodes[i] << std::endl;
+ if (polarity)
+ {
+ std::vector<Node> newSkolems;
+ conc = reduceRegExpPos(tlit, d_sc, newSkolems);
}
-}
-void RegExpOpr::simplifyNRegExp( Node s, Node r, std::vector< Node > &new_nodes ) {
- std::pair < Node, Node > p(s, r);
- NodeManager *nm = NodeManager::currentNM();
- std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_simpl_neg_cache.find(p);
- if(itr != d_simpl_neg_cache.end()) {
- new_nodes.push_back( itr->second );
- } else {
- Kind k = r.getKind();
- Node conc;
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- conc = d_true;
- break;
- }
- case kind::REGEXP_SIGMA: {
- conc = d_one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s)).negate();
- break;
- }
- case kind::REGEXP_RANGE: {
- std::vector< Node > vec;
- unsigned a = r[0].getConst<String>().front();
- unsigned b = r[1].getConst<String>().front();
- for (unsigned c = a; c <= b; c++)
- {
- std::vector<unsigned> tmpVec;
- tmpVec.push_back(c);
- Node tmp = s.eqNode(nm->mkConst(String(tmpVec))).negate();
- vec.push_back( tmp );
- }
- conc = vec.size()==1? vec[0] : NodeManager::currentNM()->mkNode(kind::AND, vec);
- break;
- }
- case kind::STRING_TO_REGEXP: {
- conc = s.eqNode(r[0]).negate();
- break;
- }
- case kind::REGEXP_CONCAT: {
- // The following simplification states that
- // ~( s in R1 ++ R2 )
- // is equivalent to
- // forall x.
- // 0 <= x <= len(s) =>
- // ~( substr(s,0,x) in R1 ) OR ~( substr(s,x,len(s)-x) in R2)
- Node lens = nm->mkNode(STRING_LENGTH, s);
- // the index we are removing from the RE concatenation
- unsigned indexRm = 0;
- Node b1;
- Node b1v;
- // As an optimization to the above reduction, if we can determine that
- // all strings in the language of R1 have the same length, say n,
- // then the conclusion of the reduction is quantifier-free:
- // ~( substr(s,0,n) in R1 ) OR ~( substr(s,n,len(s)-n) in R2)
- Node reLength = RegExpEntail::getFixedLengthForRegexp(r[0]);
- if (reLength.isNull())
- {
- // try from the opposite end
- unsigned indexE = r.getNumChildren() - 1;
- reLength = RegExpEntail::getFixedLengthForRegexp(r[indexE]);
- if (!reLength.isNull())
- {
- indexRm = indexE;
- }
- }
- Node guard;
- if (reLength.isNull())
- {
- b1 = nm->mkBoundVar(nm->integerType());
- b1v = nm->mkNode(BOUND_VAR_LIST, b1);
- guard = nm->mkNode(AND,
- nm->mkNode(GEQ, b1, d_zero),
- nm->mkNode(GEQ, nm->mkNode(STRING_LENGTH, s), b1));
- }
- else
- {
- b1 = reLength;
- }
- Node s1;
- Node s2;
- if (indexRm == 0)
- {
- s1 = nm->mkNode(STRING_SUBSTR, s, d_zero, b1);
- s2 = nm->mkNode(STRING_SUBSTR, s, b1, nm->mkNode(MINUS, lens, b1));
- }
- else
- {
- s1 = nm->mkNode(STRING_SUBSTR, s, nm->mkNode(MINUS, lens, b1), b1);
- s2 =
- nm->mkNode(STRING_SUBSTR, s, d_zero, nm->mkNode(MINUS, lens, b1));
- }
- Node s1r1 = nm->mkNode(STRING_IN_REGEXP, s1, r[indexRm]).negate();
- std::vector<Node> nvec;
- for (unsigned i = 0, nchild = r.getNumChildren(); i < nchild; i++)
- {
- if (i != indexRm)
- {
- nvec.push_back( r[i] );
- }
- }
- Node r2 = nvec.size() == 1 ? nvec[0] : nm->mkNode(REGEXP_CONCAT, nvec);
- r2 = Rewriter::rewrite(r2);
- Node s2r2 = nm->mkNode(STRING_IN_REGEXP, s2, r2).negate();
- conc = nm->mkNode(OR, s1r1, s2r2);
- if (!b1v.isNull())
- {
- conc = nm->mkNode(OR, guard.negate(), conc);
- conc = nm->mkNode(FORALL, b1v, conc);
- }
- break;
- }
- case kind::REGEXP_UNION: {
- std::vector< Node > c_and;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {
- c_and.push_back( r[i][0].eqNode(s).negate() );
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
- continue;
- } else {
- c_and.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]).negate());
- }
- }
- conc = c_and.size() == 0 ? d_true :
- c_and.size() == 1 ? c_and[0] : NodeManager::currentNM()->mkNode(kind::AND, c_and);
- break;
- }
- case kind::REGEXP_INTER: {
- bool emptyflag = false;
- std::vector< Node > c_or;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {
- c_or.push_back( r[i][0].eqNode(s).negate() );
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
- emptyflag = true;
- break;
- } else {
- c_or.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]).negate());
- }
- }
- if(emptyflag) {
- conc = d_true;
- } else {
- conc = c_or.size() == 1 ? c_or[0] : NodeManager::currentNM()->mkNode(kind::OR, c_or);
- }
- break;
- }
- case kind::REGEXP_STAR: {
- if(s == d_emptyString) {
- conc = d_false;
- } else if(r[0].getKind() == kind::REGEXP_EMPTY) {
- conc = s.eqNode(d_emptyString).negate();
- } else if(r[0].getKind() == kind::REGEXP_SIGMA) {
- conc = d_false;
- } else {
- Node lens = NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s);
- Node sne = s.eqNode(d_emptyString).negate();
- Node b1 = NodeManager::currentNM()->mkBoundVar(NodeManager::currentNM()->integerType());
- Node b1v = NodeManager::currentNM()->mkNode(kind::BOUND_VAR_LIST, b1);
- Node g1 = NodeManager::currentNM()->mkNode( kind::AND, NodeManager::currentNM()->mkNode(kind::GEQ, b1, d_one),
- NodeManager::currentNM()->mkNode( kind::GEQ, lens, b1 ) );
- //internal
- Node s1 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR, s, d_zero, b1);
- Node s2 = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR, s, b1, NodeManager::currentNM()->mkNode(kind::MINUS, lens, b1));
- Node s1r1 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s1, r[0]).negate();
- Node s2r2 = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s2, r).negate();
-
- conc = NodeManager::currentNM()->mkNode(kind::OR, s1r1, s2r2);
- conc = NodeManager::currentNM()->mkNode(kind::IMPLIES, g1, conc);
- conc = NodeManager::currentNM()->mkNode(kind::FORALL, b1v, conc);
- conc = NodeManager::currentNM()->mkNode(kind::AND, sne, conc);
- }
- break;
- }
- case kind::REGEXP_LOOP: {
- Assert(r.getNumChildren() == 3);
- if(r[1] == r[2]) {
- if(r[1] == d_zero) {
- conc = s.eqNode(d_emptyString).negate();
- } else if(r[1] == d_one) {
- conc = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[0]).negate();
- } else {
- //unroll for now
- unsigned l = r[1].getConst<Rational>().getNumerator().toUnsignedInt();
- std::vector<Node> vec;
- for(unsigned i=0; i<l; i++) {
- vec.push_back(r[0]);
- }
- Node r2 = NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec);
- conc = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r2).negate();
- }
- } else {
- Assert(r[1] == d_zero);
- //unroll for now
- unsigned u = r[2].getConst<Rational>().getNumerator().toUnsignedInt();
- std::vector<Node> vec;
- vec.push_back(d_emptySingleton);
- std::vector<Node> vec2;
- for(unsigned i=1; i<=u; i++) {
- vec2.push_back(r[0]);
- Node r2 = i==1? r[0] : NodeManager::currentNM()->mkNode(kind::REGEXP_CONCAT, vec);
- vec.push_back(r2);
- }
- Node r3 = NodeManager::currentNM()->mkNode(kind::REGEXP_UNION, vec);
- conc = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r3).negate();
- }
- break;
- }
- case kind::REGEXP_COMPLEMENT:
+ else
+ {
+ // see if we can use an optimized version of the reduction for re.++.
+ Node r = t[1];
+ if (r.getKind() == REGEXP_CONCAT)
+ {
+ // the index we are removing from the RE concatenation
+ size_t index = 0;
+ // As an optimization to the reduction, if we can determine that
+ // all strings in the language of R1 have the same length, say n,
+ // then the conclusion of the reduction is quantifier-free:
+ // ~( substr(s,0,n) in R1 ) OR ~( substr(s,n,len(s)-n) in R2)
+ Node reLen = getRegExpConcatFixed(r, index);
+ if (!reLen.isNull())
{
- // ~( s in complement(R) ) ---> s in R
- conc = nm->mkNode(STRING_IN_REGEXP, s, r[0]);
- break;
- }
- default: {
- Assert(!utils::isRegExpKind(k));
- break;
+ conc = reduceRegExpNegConcatFixed(tlit, reLen, index);
}
}
- if (!conc.isNull())
+ if (conc.isNull())
{
- conc = Rewriter::rewrite(conc);
- new_nodes.push_back(conc);
- d_simpl_neg_cache[p] = conc;
+ conc = reduceRegExpNeg(tlit);
}
}
+ d_simpCache[tlit] = conc;
+ Trace("strings-regexp-simpl")
+ << "RegExpOpr::simplify: returns " << conc << std::endl;
+ return conc;
}
-void RegExpOpr::simplifyPRegExp( Node s, Node r, std::vector< Node > &new_nodes ) {
- std::pair < Node, Node > p(s, r);
- NodeManager *nm = NodeManager::currentNM();
- std::map < std::pair< Node, Node >, Node >::const_iterator itr = d_simpl_cache.find(p);
- if(itr != d_simpl_cache.end()) {
- new_nodes.push_back( itr->second );
- } else {
- Kind k = r.getKind();
- Node conc;
- switch( k ) {
- case kind::REGEXP_EMPTY: {
- conc = d_false;
- break;
- }
- case kind::REGEXP_SIGMA: {
- conc = d_one.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_LENGTH, s));
- break;
- }
- case kind::REGEXP_RANGE: {
- conc = s.eqNode( r[0] );
- if(r[0] != r[1]) {
- unsigned a = r[0].getConst<String>().front();
- unsigned b = r[1].getConst<String>().front();
- a += 1;
- std::vector<unsigned> anvec;
- anvec.push_back(a);
- Node an = nm->mkConst(String(anvec));
- Node tmp = a != b
- ? nm->mkNode(kind::STRING_IN_REGEXP,
- s,
- nm->mkNode(kind::REGEXP_RANGE, an, r[1]))
- : s.eqNode(r[1]);
- conc = NodeManager::currentNM()->mkNode(kind::OR, conc, tmp);
- }
- break;
- }
- case kind::STRING_TO_REGEXP: {
- conc = s.eqNode(r[0]);
- break;
- }
- case kind::REGEXP_CONCAT: {
- std::vector< Node > nvec;
- std::vector< Node > cc;
- bool emptyflag = false;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {
- cc.push_back( r[i][0] );
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
- emptyflag = true;
- break;
- } else {
- Node sk = NodeManager::currentNM()->mkSkolem( "rc", s.getType(), "created for regular expression concat" );
- Node lem = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk, r[i]);
- nvec.push_back(lem);
- cc.push_back(sk);
- }
- }
- if(emptyflag) {
- conc = d_false;
- } else {
- Node lem = s.eqNode( NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, cc) );
- nvec.push_back(lem);
- conc = nvec.size() == 1 ? nvec[0] : NodeManager::currentNM()->mkNode(kind::AND, nvec);
- }
- break;
- }
- case kind::REGEXP_UNION: {
- std::vector< Node > c_or;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {
- c_or.push_back( r[i][0].eqNode(s) );
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
- continue;
- } else {
- c_or.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]));
- }
- }
- conc = c_or.size() == 0 ? d_false :
- c_or.size() == 1 ? c_or[0] : NodeManager::currentNM()->mkNode(kind::OR, c_or);
- break;
- }
- case kind::REGEXP_INTER: {
- std::vector< Node > c_and;
- bool emptyflag = false;
- for(unsigned i=0; i<r.getNumChildren(); ++i) {
- if(r[i].getKind() == kind::STRING_TO_REGEXP) {
- c_and.push_back( r[i][0].eqNode(s) );
- } else if(r[i].getKind() == kind::REGEXP_EMPTY) {
- emptyflag = true;
- break;
- } else {
- c_and.push_back(NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, s, r[i]));
- }
- }
- if(emptyflag) {
- conc = d_false;
- } else {
- conc = c_and.size() == 1 ? c_and[0] : NodeManager::currentNM()->mkNode(kind::AND, c_and);
- }
- break;
- }
- case kind::REGEXP_STAR: {
- if(s == d_emptyString) {
- conc = d_true;
- } else if(r[0].getKind() == kind::REGEXP_EMPTY) {
- conc = s.eqNode(d_emptyString);
- } else if(r[0].getKind() == kind::REGEXP_SIGMA) {
- conc = d_true;
- } else {
- Node se = s.eqNode(d_emptyString);
- Node sinr = nm->mkNode(kind::STRING_IN_REGEXP, s, r[0]);
- Node sk1 = nm->mkSkolem(
- "rs", s.getType(), "created for regular expression star");
- Node sk2 = nm->mkSkolem(
- "rs", s.getType(), "created for regular expression star");
- Node sk3 = nm->mkSkolem(
- "rs", s.getType(), "created for regular expression star");
- NodeBuilder<> nb(kind::AND);
- nb << sk1.eqNode(d_emptyString).negate();
- nb << sk3.eqNode(d_emptyString).negate();
- nb << nm->mkNode(kind::STRING_IN_REGEXP, sk1, r[0]);
- nb << nm->mkNode(kind::STRING_IN_REGEXP, sk2, r);
- nb << nm->mkNode(kind::STRING_IN_REGEXP, sk3, r[0]);
- nb << s.eqNode(nm->mkNode(kind::STRING_CONCAT, sk1, sk2, sk3));
- conc = nb;
+Node RegExpOpr::getRegExpConcatFixed(Node r, size_t& index)
+{
+ Assert(r.getKind() == REGEXP_CONCAT);
+ index = 0;
+ Node reLen = RegExpEntail::getFixedLengthForRegexp(r[0]);
+ if (!reLen.isNull())
+ {
+ return reLen;
+ }
+ // try from the opposite end
+ size_t indexE = r.getNumChildren() - 1;
+ reLen = RegExpEntail::getFixedLengthForRegexp(r[indexE]);
+ if (!reLen.isNull())
+ {
+ index = indexE;
+ return reLen;
+ }
+ return Node::null();
+}
- // We unfold `x in R*` by considering three cases: `x` is empty, `x`
- // is matched by `R`, or `x` is matched by two or more `R`s. For the
- // last case, we break `x` into three pieces, making the beginning
- // and the end each match `R` and the middle match `R*`. Matching the
- // beginning and the end with `R` allows us to reason about the
- // beginning and the end of `x` simultaneously.
- //
- // x in R* ---> (x = "") v (x in R) v
- // (x = x1 ++ x2 ++ x3 ^ x1 != "" ^ x3 != "" ^
- // x1 in R ^ x2 in R* ^ x3 in R)
- conc = nm->mkNode(kind::OR, se, sinr, conc);
- }
- break;
- }
- case kind::REGEXP_LOOP: {
- Assert(r.getNumChildren() == 3);
- if(r[1] == d_zero) {
- if(r[2] == d_zero) {
- conc = s.eqNode( d_emptyString );
- } else {
- //R{0,n}
- if(s != d_emptyString) {
- Node sk1 = NodeManager::currentNM()->mkSkolem( "lps", s.getType(), "created for regular expression loop" );
- Node sk2 = NodeManager::currentNM()->mkSkolem( "lps", s.getType(), "created for regular expression loop" );
- Node seq12 = s.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, sk1, sk2));
- Node sk1ne = sk1.eqNode(d_emptyString).negate();
- Node sk1inr = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk1, r[0]);
- unsigned u = r[2].getConst<Rational>().getNumerator().toUnsignedInt();
- Node u1 = NodeManager::currentNM()->mkConst(CVC4::Rational(u - 1));
- Node sk2inru = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk2,
- NodeManager::currentNM()->mkNode(kind::REGEXP_LOOP, r[0], d_zero, u1));
- conc = NodeManager::currentNM()->mkNode(kind::AND, seq12, sk1ne, sk1inr, sk2inru);
- conc = NodeManager::currentNM()->mkNode(kind::OR,
- s.eqNode(d_emptyString), conc);
- } else {
- conc = d_true;
- }
- }
- } else {
- //R^n
- Node sk1 = NodeManager::currentNM()->mkSkolem( "lps", s.getType(), "created for regular expression loop" );
- Node sk2 = NodeManager::currentNM()->mkSkolem( "lps", s.getType(), "created for regular expression loop" );
- Node seq12 = s.eqNode(NodeManager::currentNM()->mkNode(kind::STRING_CONCAT, sk1, sk2));
- Node sk1ne = sk1.eqNode(d_emptyString).negate();
- Node sk1inr = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk1, r[0]);
- unsigned u = r[2].getConst<Rational>().getNumerator().toUnsignedInt();
- Node u1 = NodeManager::currentNM()->mkConst(CVC4::Rational(u - 1));
- Node sk2inru = NodeManager::currentNM()->mkNode(kind::STRING_IN_REGEXP, sk2,
- NodeManager::currentNM()->mkNode(kind::REGEXP_LOOP, r[0], u1, u1));
- conc = NodeManager::currentNM()->mkNode(kind::AND, seq12, sk1ne, sk1inr, sk2inru);
- }
- break;
- }
- case kind::REGEXP_COMPLEMENT:
+Node RegExpOpr::reduceRegExpNeg(Node mem)
+{
+ Assert(mem.getKind() == NOT && mem[0].getKind() == STRING_IN_REGEXP);
+ Node s = mem[0][0];
+ Node r = mem[0][1];
+ NodeManager* nm = NodeManager::currentNM();
+ Kind k = r.getKind();
+ Node zero = nm->mkConst(Rational(0));
+ Node conc;
+ if (k == REGEXP_CONCAT)
+ {
+ // do not use length entailment, call regular expression concat
+ Node reLen;
+ size_t i = 0;
+ conc = reduceRegExpNegConcatFixed(mem, reLen, i);
+ }
+ else if (k == REGEXP_STAR)
+ {
+ Node emp = Word::mkEmptyWord(s.getType());
+ Node lens = nm->mkNode(STRING_LENGTH, s);
+ Node sne = s.eqNode(emp).negate();
+ Node b1 = nm->mkBoundVar(nm->integerType());
+ Node b1v = nm->mkNode(BOUND_VAR_LIST, b1);
+ Node g1 =
+ nm->mkNode(AND, nm->mkNode(GT, b1, zero), nm->mkNode(GEQ, lens, b1));
+ // internal
+ Node s1 = nm->mkNode(STRING_SUBSTR, s, zero, b1);
+ Node s2 = nm->mkNode(STRING_SUBSTR, s, b1, nm->mkNode(MINUS, lens, b1));
+ Node s1r1 = nm->mkNode(STRING_IN_REGEXP, s1, r[0]).negate();
+ Node s2r2 = nm->mkNode(STRING_IN_REGEXP, s2, r).negate();
+
+ conc = nm->mkNode(OR, s1r1, s2r2);
+ conc = nm->mkNode(IMPLIES, g1, conc);
+ conc = nm->mkNode(FORALL, b1v, conc);
+ conc = nm->mkNode(AND, sne, conc);
+ }
+ else
+ {
+ Assert(!utils::isRegExpKind(k));
+ }
+ return conc;
+}
+
+Node RegExpOpr::reduceRegExpNegConcatFixed(Node mem, Node reLen, size_t index)
+{
+ Assert(mem.getKind() == NOT && mem[0].getKind() == STRING_IN_REGEXP);
+ Node s = mem[0][0];
+ Node r = mem[0][1];
+ NodeManager* nm = NodeManager::currentNM();
+ Assert(r.getKind() == REGEXP_CONCAT);
+ Node zero = nm->mkConst(Rational(0));
+ // The following simplification states that
+ // ~( s in R1 ++ R2 ++... ++ Rn )
+ // is equivalent to
+ // forall x.
+ // 0 <= x <= len(s) =>
+ // ~(substr(s,0,x) in R1) OR ~(substr(s,x,len(s)-x) in R2 ++ ... ++ Rn)
+ // Index is the child index of r that we are stripping off, which is either
+ // from the beginning or the end.
+ Assert(index == 0 || index == r.getNumChildren() - 1);
+ Node lens = nm->mkNode(STRING_LENGTH, s);
+ Node b1;
+ Node b1v;
+ Node guard;
+ if (reLen.isNull())
+ {
+ b1 = SkolemCache::mkIndexVar(mem);
+ b1v = nm->mkNode(BOUND_VAR_LIST, b1);
+ guard = nm->mkNode(AND,
+ nm->mkNode(GEQ, b1, zero),
+ nm->mkNode(GEQ, nm->mkNode(STRING_LENGTH, s), b1));
+ }
+ else
+ {
+ b1 = reLen;
+ }
+ Node s1;
+ Node s2;
+ if (index == 0)
+ {
+ s1 = nm->mkNode(STRING_SUBSTR, s, zero, b1);
+ s2 = nm->mkNode(STRING_SUBSTR, s, b1, nm->mkNode(MINUS, lens, b1));
+ }
+ else
+ {
+ s1 = nm->mkNode(STRING_SUBSTR, s, nm->mkNode(MINUS, lens, b1), b1);
+ s2 = nm->mkNode(STRING_SUBSTR, s, zero, nm->mkNode(MINUS, lens, b1));
+ }
+ Node s1r1 = nm->mkNode(STRING_IN_REGEXP, s1, r[index]).negate();
+ std::vector<Node> nvec;
+ for (unsigned i = 0, nchild = r.getNumChildren(); i < nchild; i++)
+ {
+ if (i != index)
+ {
+ nvec.push_back(r[i]);
+ }
+ }
+ Node r2 = nvec.size() == 1 ? nvec[0] : nm->mkNode(REGEXP_CONCAT, nvec);
+ r2 = Rewriter::rewrite(r2);
+ Node s2r2 = nm->mkNode(STRING_IN_REGEXP, s2, r2).negate();
+ Node conc = nm->mkNode(OR, s1r1, s2r2);
+ if (!b1v.isNull())
+ {
+ conc = nm->mkNode(OR, guard.negate(), conc);
+ conc = nm->mkNode(FORALL, b1v, conc);
+ }
+ return conc;
+}
+
+Node RegExpOpr::reduceRegExpPos(Node mem,
+ SkolemCache* sc,
+ std::vector<Node>& newSkolems)
+{
+ Assert(mem.getKind() == STRING_IN_REGEXP);
+ Node s = mem[0];
+ Node r = mem[1];
+ NodeManager* nm = NodeManager::currentNM();
+ Kind k = r.getKind();
+ Node conc;
+ if (k == REGEXP_CONCAT)
+ {
+ std::vector<Node> nvec;
+ std::vector<Node> cc;
+ // get the (valid) existential for this membership
+ Node eform = getExistsForRegExpConcatMem(mem);
+ SkolemManager* sm = nm->getSkolemManager();
+ // Notice that this rule does not introduce witness terms, instead it
+ // uses skolems in the conclusion of the proof rule directly. Thus,
+ // the existential eform does not need to be explicitly justified by a
+ // proof here, since it is only being used as an intermediate formula in
+ // this inference. Hence we do not pass a proof generator to mkSkolemize.
+ sm->mkSkolemize(eform, newSkolems, "rc", "regexp concat skolem");
+ Assert(newSkolems.size() == r.getNumChildren());
+ // Look up skolems for each of the components. If sc has optimizations
+ // enabled, this will return arguments of str.to_re.
+ for (unsigned i = 0, nchild = r.getNumChildren(); i < nchild; ++i)
+ {
+ if (r[i].getKind() == STRING_TO_REGEXP)
{
- // s in complement(R) ---> ~( s in R )
- conc = nm->mkNode(STRING_IN_REGEXP, s, r[0]).negate();
- break;
+ // optimization, just take the body
+ newSkolems[i] = r[i][0];
}
- default: {
- Assert(!utils::isRegExpKind(k));
- break;
+ else
+ {
+ nvec.push_back(nm->mkNode(STRING_IN_REGEXP, newSkolems[i], r[i]));
}
}
- if (!conc.isNull())
- {
- conc = Rewriter::rewrite(conc);
- new_nodes.push_back(conc);
- d_simpl_cache[p] = conc;
- }
+ // (str.in_re x (re.++ R1 .... Rn)) =>
+ // (and (str.in_re k1 R1) ... (str.in_re kn Rn) (= x (str.++ k1 ... kn)))
+ Node lem = s.eqNode(nm->mkNode(STRING_CONCAT, newSkolems));
+ nvec.push_back(lem);
+ conc = nvec.size() == 1 ? nvec[0] : nm->mkNode(AND, nvec);
+ }
+ else if (k == REGEXP_STAR)
+ {
+ Node emp = Word::mkEmptyWord(s.getType());
+ Node se = s.eqNode(emp);
+ Node sinr = nm->mkNode(STRING_IN_REGEXP, s, r[0]);
+ Node reExpand = nm->mkNode(REGEXP_CONCAT, r[0], r, r[0]);
+ Node sinRExp = nm->mkNode(STRING_IN_REGEXP, s, reExpand);
+ // We unfold `x in R*` by considering three cases: `x` is empty, `x`
+ // is matched by `R`, or `x` is matched by two or more `R`s. For the
+ // last case, `x` will break into three pieces, making the beginning
+ // and the end each match `R` and the middle match `R*`. Matching the
+ // beginning and the end with `R` allows us to reason about the
+ // beginning and the end of `x` simultaneously.
+ //
+ // x in R* ---> (x = "") v (x in R) v (x in (re.++ R (re.* R) R))
+
+ // We also immediately unfold the last disjunct for re.*. The advantage
+ // of doing this is that we use the same scheme for skolems above.
+ std::vector<Node> newSkolemsC;
+ sinRExp = reduceRegExpPos(sinRExp, sc, newSkolemsC);
+ Assert(newSkolemsC.size() == 3);
+ // make the return lemma
+ // can also assume the component match the first and last R are non-empty.
+ // This means that the overall conclusion is:
+ // (x = "") v (x in R) v (x = (str.++ k1 k2 k3) ^
+ // k1 in R ^ k2 in (re.* R) ^ k3 in R ^
+ // k1 != "" ^ k3 != "")
+ conc = nm->mkNode(OR,
+ se,
+ sinr,
+ nm->mkNode(AND,
+ sinRExp,
+ newSkolemsC[0].eqNode(emp).negate(),
+ newSkolemsC[2].eqNode(emp).negate()));
+ }
+ else
+ {
+ Assert(!utils::isRegExpKind(k));
}
+ return conc;
}
bool RegExpOpr::isPairNodesInSet(std::set< PairNodes > &s, Node n1, Node n2) {
@@ -1398,24 +1207,6 @@ void RegExpOpr::convert2(unsigned cnt, Node n, Node &r1, Node &r2) {
}
}
-bool RegExpOpr::testNoRV(Node r) {
- std::map< Node, bool >::const_iterator itr = d_norv_cache.find(r);
- if(itr != d_norv_cache.end()) {
- return itr->second;
- } else {
- if(r.getKind() == kind::REGEXP_RV) {
- return false;
- } else if(r.getNumChildren() > 1) {
- for(unsigned int i=0; i<r.getNumChildren(); i++) {
- if(!testNoRV(r[i])) {
- return false;
- }
- }
- }
- return true;
- }
-}
-
Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< PairNodes, Node > cache, unsigned cnt ) {
//Assert(checkConstRegExp(r1) && checkConstRegExp(r2));
if(r1 > r2) {
@@ -1424,13 +1215,6 @@ Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< PairNodes, Node >
r2 = tmpNode;
}
Trace("regexp-int") << "Starting INTERSECT(" << cnt << "):\n "<< mkString(r1) << ",\n " << mkString(r2) << std::endl;
- //if(Trace.isOn("regexp-debug")) {
- // Trace("regexp-debug") << "... with cache:\n";
- // for(std::map< PairNodes, Node >::const_iterator itr=cache.begin();
- // itr!=cache.end();itr++) {
- // Trace("regexp-debug") << "(" << itr->first.first << "," << itr->first.second << ")->" << itr->second << std::endl;
- // }
- //}
std::pair < Node, Node > p(r1, r2);
std::map < PairNodes, Node >::const_iterator itr = d_inter_cache.find(p);
Node rNode;
@@ -1542,7 +1326,8 @@ Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< PairNodes, Node >
}
}
Trace("regexp-int-debug") << " ... try testing no RV of " << mkString(rNode) << std::endl;
- if(testNoRV(rNode)) {
+ if (!expr::hasSubtermKind(REGEXP_RV, rNode))
+ {
d_inter_cache[p] = rNode;
}
}
@@ -1552,80 +1337,103 @@ Node RegExpOpr::intersectInternal( Node r1, Node r2, std::map< PairNodes, Node >
Node RegExpOpr::removeIntersection(Node r) {
Assert(checkConstRegExp(r));
- std::map < Node, Node >::const_iterator itr = d_rm_inter_cache.find(r);
- if(itr != d_rm_inter_cache.end()) {
- return itr->second;
- }
- Node retNode;
- Kind rk = r.getKind();
- switch (rk)
+ NodeManager* nm = NodeManager::currentNM();
+ std::unordered_map<TNode, Node, TNodeHashFunction> visited;
+ std::unordered_map<TNode, Node, TNodeHashFunction>::iterator it;
+ std::vector<TNode> visit;
+ TNode cur;
+ visit.push_back(r);
+ do
{
- case REGEXP_EMPTY:
- case REGEXP_SIGMA:
- case REGEXP_RANGE:
- case STRING_TO_REGEXP:
- {
- retNode = r;
- break;
- }
- case REGEXP_CONCAT:
- case REGEXP_UNION:
- case REGEXP_STAR:
- case REGEXP_COMPLEMENT:
+ cur = visit.back();
+ visit.pop_back();
+ it = visited.find(cur);
+
+ if (it == visited.end())
{
- NodeBuilder<> nb(rk);
- for (const Node& rc : r)
+ visited[cur] = Node::null();
+ visit.push_back(cur);
+ for (const Node& cn : cur)
{
- nb << removeIntersection(rc);
+ visit.push_back(cn);
}
- retNode = Rewriter::rewrite(nb.constructNode());
- break;
}
-
- case REGEXP_INTER:
+ else if (it->second.isNull())
{
- retNode = removeIntersection(r[0]);
- for (size_t i = 1, nchild = r.getNumChildren(); i < nchild; i++)
+ Kind ck = cur.getKind();
+ Node ret;
+ bool childChanged = false;
+ std::vector<Node> children;
+ if (cur.getMetaKind() == metakind::PARAMETERIZED)
{
- bool spflag = false;
- Node tmpNode = removeIntersection(r[i]);
- retNode = intersect(retNode, tmpNode, spflag);
+ children.push_back(cur.getOperator());
}
- break;
- }
- case REGEXP_LOOP:
- {
- retNode = removeIntersection(r[0]);
- retNode = Rewriter::rewrite(
- NodeManager::currentNM()->mkNode(REGEXP_LOOP, retNode, r[1], r[2]));
- break;
- }
- default:
- {
- Unreachable();
+ for (const Node& cn : cur)
+ {
+ it = visited.find(cn);
+ Assert(it != visited.end());
+ Assert(!it->second.isNull());
+ if (ck == REGEXP_INTER)
+ {
+ if (ret.isNull())
+ {
+ ret = it->second;
+ }
+ else
+ {
+ ret = intersect(ret, it->second);
+ }
+ }
+ else
+ {
+ // will construct below
+ childChanged = childChanged || cn != it->second;
+ children.push_back(it->second);
+ }
+ }
+ if (ck != REGEXP_INTER)
+ {
+ if (childChanged)
+ {
+ ret = nm->mkNode(cur.getKind(), children);
+ }
+ else
+ {
+ ret = cur;
+ }
+ }
+ visited[cur] = ret;
}
+ } while (!visit.empty());
+ Assert(visited.find(r) != visited.end());
+ Assert(!visited.find(r)->second.isNull());
+ if (Trace.isOn("regexp-intersect"))
+ {
+ Trace("regexp-intersect") << "Remove INTERSECTION( " << mkString(r)
+ << " ) = " << mkString(visited[r]) << std::endl;
}
- d_rm_inter_cache[r] = retNode;
- Trace("regexp-intersect") << "Remove INTERSECTION( " << mkString(r) << " ) = " << mkString(retNode) << std::endl;
- return retNode;
+ return visited[r];
}
-Node RegExpOpr::intersect(Node r1, Node r2, bool &spflag) {
- if(checkConstRegExp(r1) && checkConstRegExp(r2)) {
- Node rr1 = removeIntersection(r1);
- Node rr2 = removeIntersection(r2);
- std::map< PairNodes, Node > cache;
- Trace("regexp-intersect-node") << "Intersect (1): " << rr1 << std::endl;
- Trace("regexp-intersect-node") << "Intersect (2): " << rr2 << std::endl;
- Trace("regexp-intersect") << "Start INTERSECTION(\n\t" << mkString(r1) << ",\n\t"<< mkString(r2) << ")" << std::endl;
- Node retNode = intersectInternal(rr1, rr2, cache, 1);
- Trace("regexp-intersect") << "End INTERSECTION(\n\t" << mkString(r1) << ",\n\t"<< mkString(r2) << ") =\n\t" << mkString(retNode) << std::endl;
- Trace("regexp-intersect-node") << "Intersect finished." << std::endl;
- return retNode;
- } else {
- spflag = true;
+Node RegExpOpr::intersect(Node r1, Node r2)
+{
+ if (!checkConstRegExp(r1) || !checkConstRegExp(r2))
+ {
return Node::null();
}
+ Node rr1 = removeIntersection(r1);
+ Node rr2 = removeIntersection(r2);
+ std::map<PairNodes, Node> cache;
+ Trace("regexp-intersect-node") << "Intersect (1): " << rr1 << std::endl;
+ Trace("regexp-intersect-node") << "Intersect (2): " << rr2 << std::endl;
+ Trace("regexp-intersect") << "Start INTERSECTION(\n\t" << mkString(r1)
+ << ",\n\t" << mkString(r2) << ")" << std::endl;
+ Node retNode = intersectInternal(rr1, rr2, cache, 1);
+ Trace("regexp-intersect")
+ << "End INTERSECTION(\n\t" << mkString(r1) << ",\n\t" << mkString(r2)
+ << ") =\n\t" << mkString(retNode) << std::endl;
+ Trace("regexp-intersect-node") << "Intersect finished." << std::endl;
+ return retNode;
}
//printing
@@ -1709,16 +1517,15 @@ std::string RegExpOpr::mkString( Node r ) {
break;
}
case kind::REGEXP_LOOP: {
- retStr += "(";
- retStr += mkString(r[0]);
- retStr += ")";
- retStr += "{";
- retStr += r[1].getConst<Rational>().toString();
- retStr += ",";
+ uint32_t l = utils::getLoopMinOccurrences(r);
+ std::stringstream ss;
+ ss << "(" << mkString(r[0]) << "){" << l << ",";
if(r.getNumChildren() == 3) {
- retStr += r[2].getConst<Rational>().toString();
+ uint32_t u = utils::getLoopMaxOccurrences(r);
+ ss << u;
}
- retStr += "}";
+ ss << "}";
+ retStr += ss.str();
break;
}
case kind::REGEXP_RV: {
@@ -1760,6 +1567,50 @@ bool RegExpOpr::regExpIncludes(Node r1, Node r2)
return result;
}
+/**
+ * Associating formulas with their "exists form", or an existentially
+ * quantified formula that is equivalent to it. This is currently used
+ * for regular expression memberships in the method below.
+ */
+struct ExistsFormAttributeId
+{
+};
+typedef expr::Attribute<ExistsFormAttributeId, Node> ExistsFormAttribute;
+
+Node RegExpOpr::getExistsForRegExpConcatMem(Node mem)
+{
+ // get or make the exists form of the membership
+ ExistsFormAttribute efa;
+ if (mem.hasAttribute(efa))
+ {
+ // already computed
+ return mem.getAttribute(efa);
+ }
+ Assert(mem.getKind() == STRING_IN_REGEXP);
+ Node x = mem[0];
+ Node r = mem[1];
+ Assert(r.getKind() == REGEXP_CONCAT);
+ NodeManager* nm = NodeManager::currentNM();
+ TypeNode xtn = x.getType();
+ std::vector<Node> vars;
+ std::vector<Node> mems;
+ for (const Node& rc : r)
+ {
+ Node v = nm->mkBoundVar(xtn);
+ vars.push_back(v);
+ mems.push_back(nm->mkNode(STRING_IN_REGEXP, v, rc));
+ }
+ Node sconcat = nm->mkNode(STRING_CONCAT, vars);
+ Node eq = x.eqNode(sconcat);
+ mems.insert(mems.begin(), eq);
+ Node bvl = nm->mkNode(BOUND_VAR_LIST, vars);
+ Node ebody = nm->mkNode(AND, mems);
+ Node eform = nm->mkNode(EXISTS, bvl, ebody);
+ mem.setAttribute(efa, eform);
+ Trace("regexp-opr") << "Exists form " << mem << " : " << eform << std::endl;
+ return eform;
+}
+
}/* CVC4::theory::strings namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/strings/regexp_operation.h b/src/theory/strings/regexp_operation.h
index d0b0755eb..b9834e987 100644
--- a/src/theory/strings/regexp_operation.h
+++ b/src/theory/strings/regexp_operation.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tianyi Liang, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,14 +19,14 @@
#ifndef CVC4__THEORY__STRINGS__REGEXP__OPERATION_H
#define CVC4__THEORY__STRINGS__REGEXP__OPERATION_H
-#include <vector>
+#include <map>
#include <set>
-#include <algorithm>
-#include <climits>
-#include "util/hash.h"
+#include <unordered_map>
+#include <vector>
+
+#include "expr/node.h"
+#include "theory/strings/skolem_cache.h"
#include "util/string.h"
-#include "theory/theory.h"
-#include "theory/rewriter.h"
namespace CVC4 {
namespace theory {
@@ -73,23 +73,17 @@ class RegExpOpr {
Node d_sigma;
Node d_sigma_star;
- std::map<PairNodes, Node> d_simpl_cache;
- std::map<PairNodes, Node> d_simpl_neg_cache;
+ /** A cache for simplify */
+ std::map<Node, Node> d_simpCache;
std::map<Node, std::pair<int, Node> > d_delta_cache;
std::map<PairNodeStr, Node> d_dv_cache;
std::map<PairNodeStr, std::pair<Node, int> > d_deriv_cache;
- std::map<Node, std::pair<Node, int> > d_compl_cache;
/** cache mapping regular expressions to whether they contain constants */
std::unordered_map<Node, RegExpConstType, NodeHashFunction> d_constCache;
- std::map<Node, std::pair<std::set<unsigned>, std::set<Node> > > d_cset_cache;
std::map<Node, std::pair<std::set<unsigned>, std::set<Node> > > d_fset_cache;
std::map<PairNodes, Node> d_inter_cache;
- std::map<Node, Node> d_rm_inter_cache;
- std::map<Node, bool> d_norv_cache;
std::map<Node, std::vector<PairNodes> > d_split_cache;
std::map<PairNodes, bool> d_inclusionCache;
- void simplifyPRegExp(Node s, Node r, std::vector<Node> &new_nodes);
- void simplifyNRegExp(Node s, Node r, std::vector<Node> &new_nodes);
/**
* Helper function for mkString, pretty prints constant or variable regular
* expression r.
@@ -101,16 +95,19 @@ class RegExpOpr {
bool containC2(unsigned cnt, Node n);
Node convert1(unsigned cnt, Node n);
void convert2(unsigned cnt, Node n, Node &r1, Node &r2);
- bool testNoRV(Node r);
Node intersectInternal(Node r1,
Node r2,
std::map<PairNodes, Node> cache,
unsigned cnt);
+ /**
+ * Given a regular expression r, this returns an equivalent regular expression
+ * that contains no applications of intersection.
+ */
Node removeIntersection(Node r);
void firstChars(Node r, std::set<unsigned> &pcset, SetNodes &pvset);
public:
- RegExpOpr();
+ RegExpOpr(SkolemCache* sc);
~RegExpOpr();
/**
@@ -121,7 +118,44 @@ class RegExpOpr {
bool checkConstRegExp( Node r );
/** get the constant type for regular expression r */
RegExpConstType getRegExpConstType(Node r);
- void simplify(Node t, std::vector< Node > &new_nodes, bool polarity);
+ /** Simplify
+ *
+ * This is the main method to simplify (unfold) a regular expression
+ * membership. It is called where t is of the form (str.in_re s r),
+ * and t (or (not t), when polarity=false) holds in the current context.
+ * It returns the unfolded form of t.
+ */
+ Node simplify(Node t, bool polarity);
+ /**
+ * Given regular expression of the form
+ * (re.++ r_0 ... r_{n-1})
+ * This returns a non-null node reLen and updates index such that
+ * RegExpEntail::getFixedLengthForRegexp(r_index) = reLen
+ * where index is set to either 0 or n-1.
+ */
+ static Node getRegExpConcatFixed(Node r, size_t& index);
+ //------------------------ trusted reductions
+ /**
+ * Return the unfolded form of mem of the form (str.in_re s r).
+ */
+ static Node reduceRegExpPos(Node mem,
+ SkolemCache* sc,
+ std::vector<Node>& newSkolems);
+ /**
+ * Return the unfolded form of mem of the form (not (str.in_re s r)).
+ */
+ static Node reduceRegExpNeg(Node mem);
+ /**
+ * Return the unfolded form of mem of the form
+ * (not (str.in_re s (re.++ r_0 ... r_{n-1})))
+ * Called when RegExpEntail::getFixedLengthForRegexp(r_index) = reLen
+ * where index is either 0 or n-1.
+ *
+ * This uses reLen as an optimization to improve the reduction. If reLen
+ * is null, then this optimization is not applied.
+ */
+ static Node reduceRegExpNegConcatFixed(Node mem, Node reLen, size_t index);
+ //------------------------ end trusted reductions
/**
* This method returns 1 if the empty string is in r, 2 if the empty string
* is not in r, or 0 if it is unknown whether the empty string is in r.
@@ -141,9 +175,9 @@ class RegExpOpr {
Node derivativeSingle( Node r, CVC4::String c );
/**
* Returns the regular expression intersection of r1 and r2. If r1 or r2 is
- * not constant, then this method returns null and sets spflag to true.
+ * not constant, then this method returns null.
*/
- Node intersect(Node r1, Node r2, bool &spflag);
+ Node intersect(Node r1, Node r2);
/** Get the pretty printed version of the regular expression r */
static std::string mkString(Node r);
@@ -155,6 +189,22 @@ class RegExpOpr {
* for performance reasons.
*/
bool regExpIncludes(Node r1, Node r2);
+
+ private:
+ /**
+ * Given a regular expression membership of the form:
+ * (str.in_re x (re.++ R1 ... Rn))
+ * This returns the valid existentially quantified formula:
+ * (exists ((x1 String) ... (xn String))
+ * (=> (str.in_re x (re.++ R1 ... Rn))
+ * (and (= x (str.++ x1 ... xn))
+ * (str.in_re x1 R1) ... (str.in_re xn Rn))))
+ * Moreover, this formula is cached per regular expression membership via
+ * an attribute, meaning it is always the same for a given membership mem.
+ */
+ static Node getExistsForRegExpConcatMem(Node mem);
+ /** pointer to the skolem cache used by this class */
+ SkolemCache* d_sc;
};
}/* CVC4::theory::strings namespace */
diff --git a/src/theory/strings/regexp_solver.cpp b/src/theory/strings/regexp_solver.cpp
index 53c6c9acc..3f419c66d 100644
--- a/src/theory/strings/regexp_solver.cpp
+++ b/src/theory/strings/regexp_solver.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -33,19 +33,19 @@ namespace strings {
RegExpSolver::RegExpSolver(SolverState& s,
InferenceManager& im,
+ SkolemCache* skc,
CoreSolver& cs,
ExtfSolver& es,
- SequencesStatistics& stats,
- context::Context* c,
- context::UserContext* u)
+ SequencesStatistics& stats)
: d_state(s),
d_im(im),
d_csolver(cs),
d_esolver(es),
d_statistics(stats),
- d_regexp_ucached(u),
- d_regexp_ccached(c),
- d_processed_memberships(c)
+ d_regexp_ucached(s.getUserContext()),
+ d_regexp_ccached(s.getSatContext()),
+ d_processed_memberships(s.getSatContext()),
+ d_regexp_opr(skc)
{
d_emptyString = NodeManager::currentNM()->mkConst(::CVC4::String(""));
std::vector<Node> nvec;
@@ -221,10 +221,13 @@ void RegExpSolver::check(const std::map<Node, std::vector<Node> >& mems)
else
{
// we have a conflict
- std::vector<Node> exp_n;
- exp_n.push_back(assertion);
+ std::vector<Node> iexp = nfexp;
+ std::vector<Node> noExplain;
+ iexp.push_back(assertion);
+ noExplain.push_back(assertion);
Node conc = Node::null();
- d_im.sendInference(nfexp, exp_n, conc, Inference::RE_NF_CONFLICT);
+ d_im.sendInference(
+ iexp, noExplain, conc, Inference::RE_NF_CONFLICT);
addedLemma = true;
break;
}
@@ -260,16 +263,16 @@ void RegExpSolver::check(const std::map<Node, std::vector<Node> >& mems)
<< "Unroll/simplify membership of atomic term " << rep
<< std::endl;
// if so, do simple unrolling
- std::vector<Node> nvec;
Trace("strings-regexp") << "Simplify on " << atom << std::endl;
- d_regexp_opr.simplify(atom, nvec, polarity);
+ Node conc = d_regexp_opr.simplify(atom, polarity);
Trace("strings-regexp") << "...finished" << std::endl;
// if simplifying successfully generated a lemma
- if (!nvec.empty())
+ if (!conc.isNull())
{
- std::vector<Node> exp_n;
- exp_n.push_back(assertion);
- Node conc = nvec.size() == 1 ? nvec[0] : nm->mkNode(AND, nvec);
+ std::vector<Node> iexp = rnfexp;
+ std::vector<Node> noExplain;
+ iexp.push_back(assertion);
+ noExplain.push_back(assertion);
Assert(atom.getKind() == STRING_IN_REGEXP);
if (polarity)
{
@@ -281,7 +284,7 @@ void RegExpSolver::check(const std::map<Node, std::vector<Node> >& mems)
}
Inference inf =
polarity ? Inference::RE_UNFOLD_POS : Inference::RE_UNFOLD_NEG;
- d_im.sendInference(rnfexp, exp_n, conc, inf);
+ d_im.sendInference(iexp, noExplain, conc, inf);
addedLemma = true;
if (changed)
{
@@ -401,7 +404,7 @@ bool RegExpSolver::checkEqcInclusion(std::vector<Node>& mems)
Node conc;
d_im.sendInference(
- vec_nodes, conc, Inference::RE_INTER_INCLUDE, true);
+ vec_nodes, conc, Inference::RE_INTER_INCLUDE, false, true);
return false;
}
}
@@ -468,11 +471,9 @@ bool RegExpSolver::checkEqcIntersect(const std::vector<Node>& mems)
rcti = rct;
continue;
}
- bool spflag = false;
- Node resR = d_regexp_opr.intersect(mi[1], m[1], spflag);
+ Node resR = d_regexp_opr.intersect(mi[1], m[1]);
// intersection should be computable
Assert(!resR.isNull());
- Assert(!spflag);
if (resR == d_emptyRegexp)
{
// conflict, explain
@@ -484,19 +485,21 @@ bool RegExpSolver::checkEqcIntersect(const std::vector<Node>& mems)
vec_nodes.push_back(mi[0].eqNode(m[0]));
}
Node conc;
- d_im.sendInference(vec_nodes, conc, Inference::RE_INTER_CONF, true);
+ d_im.sendInference(
+ vec_nodes, conc, Inference::RE_INTER_CONF, false, true);
// conflict, return
return false;
}
// rewrite to ensure the equality checks below are precise
- Node mres = Rewriter::rewrite(nm->mkNode(STRING_IN_REGEXP, mi[0], resR));
- if (mres == mi)
+ Node mres = nm->mkNode(STRING_IN_REGEXP, mi[0], resR);
+ Node mresr = Rewriter::rewrite(mres);
+ if (mresr == mi)
{
// if R1 = intersect( R1, R2 ), then x in R1 ^ x in R2 is equivalent
// to x in R1, hence x in R2 can be marked redundant.
d_im.markReduced(m);
}
- else if (mres == m)
+ else if (mresr == m)
{
// same as above, opposite direction
d_im.markReduced(mi);
@@ -512,7 +515,8 @@ bool RegExpSolver::checkEqcIntersect(const std::vector<Node>& mems)
{
vec_nodes.push_back(mi[0].eqNode(m[0]));
}
- d_im.sendInference(vec_nodes, mres, Inference::RE_INTER_INFER, true);
+ d_im.sendInference(
+ vec_nodes, mres, Inference::RE_INTER_INFER, false, true);
// both are reduced
d_im.markReduced(m);
d_im.markReduced(mi);
@@ -533,10 +537,12 @@ bool RegExpSolver::checkPDerivative(
{
case 0:
{
- std::vector<Node> exp_n;
- exp_n.push_back(atom);
- exp_n.push_back(x.eqNode(d_emptyString));
- d_im.sendInference(nf_exp, exp_n, exp, Inference::RE_DELTA);
+ std::vector<Node> noExplain;
+ noExplain.push_back(atom);
+ noExplain.push_back(x.eqNode(d_emptyString));
+ std::vector<Node> iexp = nf_exp;
+ iexp.insert(iexp.end(), noExplain.begin(), noExplain.end());
+ d_im.sendInference(iexp, noExplain, exp, Inference::RE_DELTA);
addedLemma = true;
d_regexp_ccached.insert(atom);
return false;
@@ -548,11 +554,12 @@ bool RegExpSolver::checkPDerivative(
}
case 2:
{
- std::vector<Node> exp_n;
- exp_n.push_back(atom);
- exp_n.push_back(x.eqNode(d_emptyString));
- Node conc;
- d_im.sendInference(nf_exp, exp_n, conc, Inference::RE_DELTA_CONF);
+ std::vector<Node> noExplain;
+ noExplain.push_back(atom);
+ noExplain.push_back(x.eqNode(d_emptyString));
+ std::vector<Node> iexp = nf_exp;
+ iexp.insert(iexp.end(), noExplain.begin(), noExplain.end());
+ d_im.sendInference(iexp, noExplain, d_false, Inference::RE_DELTA_CONF);
addedLemma = true;
d_regexp_ccached.insert(atom);
return false;
@@ -641,9 +648,11 @@ bool RegExpSolver::deriveRegExp(Node x,
conc = NodeManager::currentNM()->mkNode(STRING_IN_REGEXP, left, dc);
}
}
- std::vector<Node> exp_n;
- exp_n.push_back(atom);
- d_im.sendInference(ant, exp_n, conc, Inference::RE_DERIVE);
+ std::vector<Node> iexp = ant;
+ std::vector<Node> noExplain;
+ noExplain.push_back(atom);
+ iexp.push_back(atom);
+ d_im.sendInference(iexp, noExplain, conc, Inference::RE_DERIVE);
return true;
}
return false;
diff --git a/src/theory/strings/regexp_solver.h b/src/theory/strings/regexp_solver.h
index 9e9ba5845..92f2b1bac 100644
--- a/src/theory/strings/regexp_solver.h
+++ b/src/theory/strings/regexp_solver.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tianyi Liang, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,6 +25,7 @@
#include "expr/node.h"
#include "theory/strings/extf_solver.h"
#include "theory/strings/inference_manager.h"
+#include "theory/strings/skolem_cache.h"
#include "theory/strings/regexp_operation.h"
#include "theory/strings/sequences_stats.h"
#include "theory/strings/solver_state.h"
@@ -46,11 +47,10 @@ class RegExpSolver
public:
RegExpSolver(SolverState& s,
InferenceManager& im,
+ SkolemCache* skc,
CoreSolver& cs,
ExtfSolver& es,
- SequencesStatistics& stats,
- context::Context* c,
- context::UserContext* u);
+ SequencesStatistics& stats);
~RegExpSolver() {}
/** check regular expression memberships
diff --git a/src/theory/strings/rewrites.cpp b/src/theory/strings/rewrites.cpp
index 6ea467ae9..a32e5bc9e 100644
--- a/src/theory/strings/rewrites.cpp
+++ b/src/theory/strings/rewrites.cpp
@@ -2,10 +2,10 @@
/*! \file rewrites.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Andres Noetzli
+ ** Andrew Reynolds, Andres Noetzli, Yoni Zohar
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -210,6 +210,7 @@ const char* toString(Rewrite r)
case Rewrite::LEN_SEQ_UNIT: return "LEN_SEQ_UNIT";
case Rewrite::CHARAT_ELIM: return "CHARAT_ELIM";
case Rewrite::SEQ_UNIT_EVAL: return "SEQ_UNIT_EVAL";
+ case Rewrite::SEQ_NTH_EVAL: return "SEQ_NTH_EVAL";
default: return "?";
}
}
diff --git a/src/theory/strings/rewrites.h b/src/theory/strings/rewrites.h
index bc5de3a8a..f9824405b 100644
--- a/src/theory/strings/rewrites.h
+++ b/src/theory/strings/rewrites.h
@@ -2,10 +2,10 @@
/*! \file rewrites.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Andres Noetzli
+ ** Andrew Reynolds, Andres Noetzli, Yoni Zohar
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -212,7 +212,8 @@ enum class Rewrite : uint32_t
LEN_CONV_INV,
LEN_SEQ_UNIT,
CHARAT_ELIM,
- SEQ_UNIT_EVAL
+ SEQ_UNIT_EVAL,
+ SEQ_NTH_EVAL
};
/**
diff --git a/src/theory/strings/sequences_rewriter.cpp b/src/theory/strings/sequences_rewriter.cpp
index 292960e6a..2cefe6b09 100644
--- a/src/theory/strings/sequences_rewriter.cpp
+++ b/src/theory/strings/sequences_rewriter.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,6 +18,7 @@
#include "expr/attribute.h"
#include "expr/node_builder.h"
+#include "expr/sequence.h"
#include "theory/rewriter.h"
#include "theory/strings/arith_entail.h"
#include "theory/strings/regexp_entail.h"
@@ -463,7 +464,8 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
// (= (str.++ "A" x y) (str.++ x "AB" z)) --->
// (and (= (str.++ "A" x) (str.++ x "A")) (= y (str.++ "B" z)))
std::vector<Node> rpfxv1;
- if (StringsEntail::stripSymbolicLength(pfxv1, rpfxv1, 1, lenPfx0))
+ if (StringsEntail::stripSymbolicLength(
+ pfxv1, rpfxv1, 1, lenPfx0, true))
{
std::vector<Node> sfxv0(v0.begin() + i, v0.end());
pfxv1.insert(pfxv1.end(), v1.begin() + j, v1.end());
@@ -490,7 +492,8 @@ Node SequencesRewriter::rewriteStrEqualityExt(Node node)
// (= (str.++ x "AB" z) (str.++ "A" x y)) --->
// (and (= (str.++ x "A") (str.++ "A" x)) (= (str.++ "B" z) y))
std::vector<Node> rpfxv0;
- if (StringsEntail::stripSymbolicLength(pfxv0, rpfxv0, 1, lenPfx1))
+ if (StringsEntail::stripSymbolicLength(
+ pfxv0, rpfxv0, 1, lenPfx1, true))
{
pfxv0.insert(pfxv0.end(), v0.begin() + i, v0.end());
std::vector<Node> sfxv1(v1.begin() + j, v1.end());
@@ -1488,6 +1491,10 @@ RewriteResponse SequencesRewriter::postRewrite(TNode node)
{
retNode = rewriteSeqUnit(node);
}
+ else if (nk == SEQ_NTH)
+ {
+ retNode = rewriteSeqNth(node);
+ }
Trace("sequences-postrewrite")
<< "Strings::SequencesRewriter::postRewrite returning " << retNode
@@ -1507,6 +1514,33 @@ RewriteResponse SequencesRewriter::preRewrite(TNode node)
return RewriteResponse(REWRITE_DONE, node);
}
+Node SequencesRewriter::rewriteSeqNth(Node node)
+{
+ Assert(node.getKind() == SEQ_NTH);
+ Node ret;
+ Node s = node[0];
+ Node i = node[1];
+ if (s.isConst() && i.isConst())
+ {
+ size_t len = Word::getLength(s);
+ size_t pos = i.getConst<Rational>().getNumerator().toUnsignedInt();
+ if (pos < len)
+ {
+ std::vector<Node> elements = s.getConst<Sequence>().getVec();
+ ret = elements[pos];
+ return returnRewrite(node, ret, Rewrite::SEQ_NTH_EVAL);
+ }
+ else
+ {
+ return node;
+ }
+ }
+ else
+ {
+ return node;
+ }
+}
+
Node SequencesRewriter::rewriteCharAt(Node node)
{
Assert(node.getKind() == STRING_CHARAT);
@@ -2990,31 +3024,34 @@ Node SequencesRewriter::rewriteReplaceRe(Node node)
Node y = node[1];
Node z = node[2];
- if (x.isConst())
+ if (RegExpEntail::isConstRegExp(y))
{
- // str.replace_re("ZABCZ", re.++("A", _*, "C"), y) ---> "Z" ++ y ++ "Z"
- std::pair<size_t, size_t> match = firstMatch(x, y);
- if (match.first != string::npos)
+ if (x.isConst())
{
- String s = x.getConst<String>();
- Node ret = nm->mkNode(STRING_CONCAT,
- nm->mkConst(s.substr(0, match.first)),
- z,
- nm->mkConst(s.substr(match.second)));
- return returnRewrite(node, ret, Rewrite::REPLACE_RE_EVAL);
+ // str.replace_re("ZABCZ", re.++("A", _*, "C"), y) ---> "Z" ++ y ++ "Z"
+ std::pair<size_t, size_t> match = firstMatch(x, y);
+ if (match.first != string::npos)
+ {
+ String s = x.getConst<String>();
+ Node ret = nm->mkNode(STRING_CONCAT,
+ nm->mkConst(s.substr(0, match.first)),
+ z,
+ nm->mkConst(s.substr(match.second)));
+ return returnRewrite(node, ret, Rewrite::REPLACE_RE_EVAL);
+ }
+ else
+ {
+ return returnRewrite(node, x, Rewrite::REPLACE_RE_EVAL);
+ }
}
- else
+ // str.replace_re( x, y, z ) ---> z ++ x if "" in y ---> true
+ String emptyStr("");
+ if (RegExpEntail::testConstStringInRegExp(emptyStr, 0, y))
{
- return returnRewrite(node, x, Rewrite::REPLACE_RE_EVAL);
+ Node ret = nm->mkNode(STRING_CONCAT, z, x);
+ return returnRewrite(node, ret, Rewrite::REPLACE_RE_EMP_RE);
}
}
- // str.replace_re( x, y, z ) ---> z ++ x if "" in y ---> true
- String emptyStr("");
- if (RegExpEntail::testConstStringInRegExp(emptyStr, 0, y))
- {
- Node ret = nm->mkNode(STRING_CONCAT, z, x);
- return returnRewrite(node, ret, Rewrite::REPLACE_RE_EMP_RE);
- }
return node;
}
@@ -3026,31 +3063,34 @@ Node SequencesRewriter::rewriteReplaceReAll(Node node)
Node y = node[1];
Node z = node[2];
- if (x.isConst())
+ if (RegExpEntail::isConstRegExp(y))
{
- // str.replace_re_all("ZABCZAB", re.++("A", _*, "C"), y) --->
- // "Z" ++ y ++ "Z" ++ y
- TypeNode t = x.getType();
- Node emp = Word::mkEmptyWord(t);
- Node yp = Rewriter::rewrite(
- nm->mkNode(REGEXP_DIFF, y, nm->mkNode(STRING_TO_REGEXP, emp)));
- std::vector<Node> res;
- String rem = x.getConst<String>();
- std::pair<size_t, size_t> match(0, 0);
- while (rem.size() >= 0)
+ if (x.isConst())
{
- match = firstMatch(nm->mkConst(rem), yp);
- if (match.first == string::npos)
- {
- break;
+ // str.replace_re_all("ZABCZAB", re.++("A", _*, "C"), y) --->
+ // "Z" ++ y ++ "Z" ++ y
+ TypeNode t = x.getType();
+ Node emp = Word::mkEmptyWord(t);
+ Node yp = Rewriter::rewrite(
+ nm->mkNode(REGEXP_DIFF, y, nm->mkNode(STRING_TO_REGEXP, emp)));
+ std::vector<Node> res;
+ String rem = x.getConst<String>();
+ std::pair<size_t, size_t> match(0, 0);
+ while (rem.size() >= 0)
+ {
+ match = firstMatch(nm->mkConst(rem), yp);
+ if (match.first == string::npos)
+ {
+ break;
+ }
+ res.push_back(nm->mkConst(rem.substr(0, match.first)));
+ res.push_back(z);
+ rem = rem.substr(match.second);
}
- res.push_back(nm->mkConst(rem.substr(0, match.first)));
- res.push_back(z);
- rem = rem.substr(match.second);
+ res.push_back(nm->mkConst(rem));
+ Node ret = utils::mkConcat(res, t);
+ return returnRewrite(node, ret, Rewrite::REPLACE_RE_ALL_EVAL);
}
- res.push_back(nm->mkConst(rem));
- Node ret = utils::mkConcat(res, t);
- return returnRewrite(node, ret, Rewrite::REPLACE_RE_ALL_EVAL);
}
return node;
diff --git a/src/theory/strings/sequences_rewriter.h b/src/theory/strings/sequences_rewriter.h
index 47a20a7ca..105bfc105 100644
--- a/src/theory/strings/sequences_rewriter.h
+++ b/src/theory/strings/sequences_rewriter.h
@@ -2,10 +2,10 @@
/*! \file sequences_rewriter.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Andres Noetzli
+ ** Andrew Reynolds, Andres Noetzli, Yoni Zohar
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -264,6 +264,13 @@ class SequencesRewriter : public TheoryRewriter
*/
Node rewriteSeqUnit(Node node);
+ /** rewrite seq.nth
+ * This is the entry point for post-rewriting terms n of the form
+ * seq.nth(s, i)
+ * Returns the rewritten form of node.
+ */
+ Node rewriteSeqNth(Node node);
+
/** length preserving rewrite
*
* Given input n, this returns a string n' whose length is equivalent to n.
diff --git a/src/theory/strings/sequences_stats.cpp b/src/theory/strings/sequences_stats.cpp
index 502d05353..fe6bc548e 100644
--- a/src/theory/strings/sequences_stats.cpp
+++ b/src/theory/strings/sequences_stats.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,13 +25,14 @@ SequencesStatistics::SequencesStatistics()
: d_checkRuns("theory::strings::checkRuns", 0),
d_strategyRuns("theory::strings::strategyRuns", 0),
d_inferences("theory::strings::inferences"),
+ d_inferencesNoPf("theory::strings::inferencesNoPf"),
d_cdSimplifications("theory::strings::cdSimplifications"),
d_reductions("theory::strings::reductions"),
d_regexpUnfoldingsPos("theory::strings::regexpUnfoldingsPos"),
d_regexpUnfoldingsNeg("theory::strings::regexpUnfoldingsNeg"),
d_rewrites("theory::strings::rewrites"),
d_conflictsEqEngine("theory::strings::conflictsEqEngine", 0),
- d_conflictsEagerPrefix("theory::strings::conflictsEagerPrefix", 0),
+ d_conflictsEager("theory::strings::conflictsEager", 0),
d_conflictsInfer("theory::strings::conflictsInfer", 0),
d_lemmasEagerPreproc("theory::strings::lemmasEagerPreproc", 0),
d_lemmasCmiSplit("theory::strings::lemmasCmiSplit", 0),
@@ -43,13 +44,14 @@ SequencesStatistics::SequencesStatistics()
smtStatisticsRegistry()->registerStat(&d_checkRuns);
smtStatisticsRegistry()->registerStat(&d_strategyRuns);
smtStatisticsRegistry()->registerStat(&d_inferences);
+ smtStatisticsRegistry()->registerStat(&d_inferencesNoPf);
smtStatisticsRegistry()->registerStat(&d_cdSimplifications);
smtStatisticsRegistry()->registerStat(&d_reductions);
smtStatisticsRegistry()->registerStat(&d_regexpUnfoldingsPos);
smtStatisticsRegistry()->registerStat(&d_regexpUnfoldingsNeg);
smtStatisticsRegistry()->registerStat(&d_rewrites);
smtStatisticsRegistry()->registerStat(&d_conflictsEqEngine);
- smtStatisticsRegistry()->registerStat(&d_conflictsEagerPrefix);
+ smtStatisticsRegistry()->registerStat(&d_conflictsEager);
smtStatisticsRegistry()->registerStat(&d_conflictsInfer);
smtStatisticsRegistry()->registerStat(&d_lemmasEagerPreproc);
smtStatisticsRegistry()->registerStat(&d_lemmasCmiSplit);
@@ -63,13 +65,14 @@ SequencesStatistics::~SequencesStatistics()
smtStatisticsRegistry()->unregisterStat(&d_checkRuns);
smtStatisticsRegistry()->unregisterStat(&d_strategyRuns);
smtStatisticsRegistry()->unregisterStat(&d_inferences);
+ smtStatisticsRegistry()->unregisterStat(&d_inferencesNoPf);
smtStatisticsRegistry()->unregisterStat(&d_cdSimplifications);
smtStatisticsRegistry()->unregisterStat(&d_reductions);
smtStatisticsRegistry()->unregisterStat(&d_regexpUnfoldingsPos);
smtStatisticsRegistry()->unregisterStat(&d_regexpUnfoldingsNeg);
smtStatisticsRegistry()->unregisterStat(&d_rewrites);
smtStatisticsRegistry()->unregisterStat(&d_conflictsEqEngine);
- smtStatisticsRegistry()->unregisterStat(&d_conflictsEagerPrefix);
+ smtStatisticsRegistry()->unregisterStat(&d_conflictsEager);
smtStatisticsRegistry()->unregisterStat(&d_conflictsInfer);
smtStatisticsRegistry()->unregisterStat(&d_lemmasEagerPreproc);
smtStatisticsRegistry()->unregisterStat(&d_lemmasCmiSplit);
diff --git a/src/theory/strings/sequences_stats.h b/src/theory/strings/sequences_stats.h
index 85f830fa2..e35d951f7 100644
--- a/src/theory/strings/sequences_stats.h
+++ b/src/theory/strings/sequences_stats.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -63,6 +63,11 @@ class SequencesStatistics
/** Counts the number of applications of each type of inference */
HistogramStat<Inference> d_inferences;
/**
+ * Counts the number of applications of each type of inference that were not
+ * processed as a proof step. This is a subset of d_inferences.
+ */
+ HistogramStat<Inference> d_inferencesNoPf;
+ /**
* Counts the number of applications of each type of context-dependent
* simplification. The sum of this map is equal to the number of EXTF or
* EXTF_N inferences.
@@ -87,8 +92,8 @@ class SequencesStatistics
//--------------- conflicts, partition of calls to OutputChannel::conflict
/** Number of equality engine conflicts */
IntStat d_conflictsEqEngine;
- /** Number of eager prefix conflicts */
- IntStat d_conflictsEagerPrefix;
+ /** Number of eager conflicts */
+ IntStat d_conflictsEager;
/** Number of inference conflicts */
IntStat d_conflictsInfer;
//--------------- end of conflicts
diff --git a/src/theory/strings/skolem_cache.cpp b/src/theory/strings/skolem_cache.cpp
index 8fb854d91..a1e04071b 100644
--- a/src/theory/strings/skolem_cache.cpp
+++ b/src/theory/strings/skolem_cache.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/skolem_cache.h b/src/theory/strings/skolem_cache.h
index 302c69e83..0a6dd367f 100644
--- a/src/theory/strings/skolem_cache.h
+++ b/src/theory/strings/skolem_cache.h
@@ -2,10 +2,10 @@
/*! \file skolem_cache.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Andres Noetzli, Mathias Preiner
+ ** Andrew Reynolds, Andres Noetzli, Yoni Zohar
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -138,6 +138,11 @@ class SkolemCache
// where b is a regular expression, n is the number of occurrences of b
// in a, and k(0)=0.
SK_OCCUR_LEN,
+ // For function k: ((Seq U) x Int) -> U
+ // exists k.
+ // forall s, n.
+ // k(s, n) is some undefined value of sort U
+ SK_NTH,
};
/**
* Returns a skolem of type string that is cached for (a,b,id) and has
diff --git a/src/theory/strings/solver_state.cpp b/src/theory/strings/solver_state.cpp
index 06a86935f..89d77b033 100644
--- a/src/theory/strings/solver_state.cpp
+++ b/src/theory/strings/solver_state.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tianyi Liang, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -27,17 +27,11 @@ namespace strings {
SolverState::SolverState(context::Context* c,
context::UserContext* u,
- eq::EqualityEngine& ee,
Valuation& v)
- : d_context(c),
- d_ucontext(u),
- d_ee(ee),
- d_eeDisequalities(c),
- d_valuation(v),
- d_conflict(c, false),
- d_pendingConflict(c)
+ : TheoryState(c, u, v), d_eeDisequalities(c), d_pendingConflictSet(c, false)
{
d_zero = NodeManager::currentNM()->mkConst(Rational(0));
+ d_false = NodeManager::currentNM()->mkConst(false);
}
SolverState::~SolverState()
@@ -48,53 +42,6 @@ SolverState::~SolverState()
}
}
-context::Context* SolverState::getSatContext() const { return d_context; }
-context::UserContext* SolverState::getUserContext() const { return d_ucontext; }
-
-Node SolverState::getRepresentative(Node t) const
-{
- if (d_ee.hasTerm(t))
- {
- return d_ee.getRepresentative(t);
- }
- return t;
-}
-
-bool SolverState::hasTerm(Node a) const { return d_ee.hasTerm(a); }
-
-bool SolverState::areEqual(Node a, Node b) const
-{
- if (a == b)
- {
- return true;
- }
- else if (hasTerm(a) && hasTerm(b))
- {
- return d_ee.areEqual(a, b);
- }
- return false;
-}
-
-bool SolverState::areDisequal(Node a, Node b) const
-{
- if (a == b)
- {
- return false;
- }
- else if (hasTerm(a) && hasTerm(b))
- {
- Node ar = d_ee.getRepresentative(a);
- Node br = d_ee.getRepresentative(b);
- return (ar != br && ar.isConst() && br.isConst())
- || d_ee.areDisequal(ar, br, false);
- }
- Node ar = getRepresentative(a);
- Node br = getRepresentative(b);
- return ar != br && ar.isConst() && br.isConst();
-}
-
-eq::EqualityEngine* SolverState::getEqualityEngine() const { return &d_ee; }
-
const context::CDList<Node>& SolverState::getDisequalityList() const
{
return d_eeDisequalities;
@@ -105,7 +52,7 @@ void SolverState::eqNotifyNewClass(TNode t)
Kind k = t.getKind();
if (k == STRING_LENGTH || k == STRING_TO_CODE)
{
- Node r = d_ee.getRepresentative(t[0]);
+ Node r = d_ee->getRepresentative(t[0]);
EqcInfo* ei = getOrMakeEqcInfo(r);
if (k == STRING_LENGTH)
{
@@ -118,10 +65,12 @@ void SolverState::eqNotifyNewClass(TNode t)
}
else if (t.isConst())
{
- EqcInfo* ei = getOrMakeEqcInfo(t);
- ei->d_prefixC = t;
- ei->d_suffixC = t;
- return;
+ if (t.getType().isStringLike())
+ {
+ EqcInfo* ei = getOrMakeEqcInfo(t);
+ ei->d_prefixC = t;
+ ei->d_suffixC = t;
+ }
}
else if (k == STRING_CONCAT)
{
@@ -129,11 +78,12 @@ void SolverState::eqNotifyNewClass(TNode t)
}
}
-void SolverState::eqNotifyPreMerge(TNode t1, TNode t2)
+void SolverState::eqNotifyMerge(TNode t1, TNode t2)
{
EqcInfo* e2 = getOrMakeEqcInfo(t2, false);
if (e2)
{
+ Assert(t1.getType().isStringLike());
EqcInfo* e1 = getOrMakeEqcInfo(t1);
// add information from e2 to e1
if (!e2->d_lengthTerm.get().isNull())
@@ -146,12 +96,12 @@ void SolverState::eqNotifyPreMerge(TNode t1, TNode t2)
}
if (!e2->d_prefixC.get().isNull())
{
- setPendingConflictWhen(
+ setPendingPrefixConflictWhen(
e1->addEndpointConst(e2->d_prefixC, Node::null(), false));
}
if (!e2->d_suffixC.get().isNull())
{
- setPendingConflictWhen(
+ setPendingPrefixConflictWhen(
e1->addEndpointConst(e2->d_suffixC, Node::null(), true));
}
if (e2->d_cardinalityLemK.get() > e1->d_cardinalityLemK.get())
@@ -191,7 +141,7 @@ EqcInfo* SolverState::getOrMakeEqcInfo(Node eqc, bool doMake)
return nullptr;
}
-TheoryModel* SolverState::getModel() const { return d_valuation.getModel(); }
+TheoryModel* SolverState::getModel() { return d_valuation.getModel(); }
void SolverState::addEndpointsToEqcInfo(Node t, Node concat, Node eqc)
{
@@ -212,7 +162,7 @@ void SolverState::addEndpointsToEqcInfo(Node t, Node concat, Node eqc)
Trace("strings-eager-pconf-debug")
<< "New term: " << concat << " for " << t << " with prefix " << c
<< " (" << (r == 1) << ")" << std::endl;
- setPendingConflictWhen(ei->addEndpointConst(t, c, r == 1));
+ setPendingPrefixConflictWhen(ei->addEndpointConst(t, c, r == 1));
}
}
}
@@ -278,18 +228,39 @@ bool SolverState::isEqualEmptyWord(Node s, Node& emps)
return false;
}
-void SolverState::setConflict() { d_conflict = true; }
-bool SolverState::isInConflict() const { return d_conflict; }
+void SolverState::setPendingPrefixConflictWhen(Node conf)
+{
+ if (conf.isNull() || d_pendingConflictSet.get())
+ {
+ return;
+ }
+ InferInfo iiPrefixConf;
+ iiPrefixConf.d_id = Inference::PREFIX_CONFLICT;
+ iiPrefixConf.d_conc = d_false;
+ utils::flattenOp(AND, conf, iiPrefixConf.d_ant);
+ setPendingConflict(iiPrefixConf);
+}
-void SolverState::setPendingConflictWhen(Node conf)
+void SolverState::setPendingConflict(InferInfo& ii)
{
- if (!conf.isNull() && d_pendingConflict.get().isNull())
+ if (!d_pendingConflictSet.get())
{
- d_pendingConflict = conf;
+ d_pendingConflict = ii;
+ d_pendingConflictSet.set(true);
}
}
-Node SolverState::getPendingConflict() const { return d_pendingConflict; }
+bool SolverState::hasPendingConflict() const { return d_pendingConflictSet; }
+
+bool SolverState::getPendingConflict(InferInfo& ii) const
+{
+ if (d_pendingConflictSet)
+ {
+ ii = d_pendingConflict;
+ return true;
+ }
+ return false;
+}
std::pair<bool, Node> SolverState::entailmentCheck(options::TheoryOfMode mode,
TNode lit)
@@ -314,14 +285,14 @@ void SolverState::separateByLength(
NodeManager* nm = NodeManager::currentNM();
for (const Node& eqc : n)
{
- Assert(d_ee.getRepresentative(eqc) == eqc);
+ Assert(d_ee->getRepresentative(eqc) == eqc);
TypeNode tnEqc = eqc.getType();
EqcInfo* ei = getOrMakeEqcInfo(eqc, false);
Node lt = ei ? ei->d_lengthTerm : Node::null();
if (!lt.isNull())
{
lt = nm->mkNode(STRING_LENGTH, lt);
- Node r = d_ee.getRepresentative(lt);
+ Node r = d_ee->getRepresentative(lt);
std::pair<Node, TypeNode> lkey(r, tnEqc);
if (eqc_to_leqc.find(lkey) == eqc_to_leqc.end())
{
diff --git a/src/theory/strings/solver_state.h b/src/theory/strings/solver_state.h
index 2eee90ca4..291a15feb 100644
--- a/src/theory/strings/solver_state.h
+++ b/src/theory/strings/solver_state.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tianyi Liang, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,12 +19,15 @@
#include <map>
+#include "context/cdlist.h"
#include "context/context.h"
#include "expr/node.h"
+#include "theory/strings/eqc_info.h"
+#include "theory/strings/infer_info.h"
#include "theory/theory_model.h"
+#include "theory/theory_state.h"
#include "theory/uf/equality_engine.h"
#include "theory/valuation.h"
-#include "theory/strings/eqc_info.h"
namespace CVC4 {
namespace theory {
@@ -39,41 +42,17 @@ namespace strings {
* (2) Whether the set of assertions is in conflict.
* (3) Equivalence class information as in the class above.
*/
-class SolverState
+class SolverState : public TheoryState
{
typedef context::CDList<Node> NodeList;
public:
SolverState(context::Context* c,
context::UserContext* u,
- eq::EqualityEngine& ee,
Valuation& v);
~SolverState();
- /** Get the SAT context */
- context::Context* getSatContext() const;
- /** Get the user context */
- context::UserContext* getUserContext() const;
//-------------------------------------- equality information
/**
- * Get the representative of t in the equality engine of this class, or t
- * itself if it is not registered as a term.
- */
- Node getRepresentative(Node t) const;
- /** Is t registered as a term in the equality engine of this class? */
- bool hasTerm(Node a) const;
- /**
- * Are a and b equal according to the equality engine of this class? Also
- * returns true if a and b are identical.
- */
- bool areEqual(Node a, Node b) const;
- /**
- * Are a and b disequal according to the equality engine of this class? Also
- * returns true if the representative of a and b are distinct constants.
- */
- bool areDisequal(Node a, Node b) const;
- /** get equality engine */
- eq::EqualityEngine* getEqualityEngine() const;
- /**
* Get the list of disequalities that are currently asserted to the equality
* engine.
*/
@@ -82,21 +61,13 @@ class SolverState
//-------------------------------------- notifications for equalities
/** called when a new equivalence class is created */
void eqNotifyNewClass(TNode t);
- /** called when two equivalence classes will merge */
- void eqNotifyPreMerge(TNode t1, TNode t2);
+ /** called when two equivalence classes merge */
+ void eqNotifyMerge(TNode t1, TNode t2);
/** called when two equivalence classes are made disequal */
void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
//-------------------------------------- end notifications for equalities
//------------------------------------------ conflicts
- /**
- * Set that the current state of the solver is in conflict. This should be
- * called immediately after a call to conflict(...) on the output channel of
- * the theory of strings.
- */
- void setConflict();
- /** Are we currently in conflict? */
- bool isInConflict() const;
- /** set pending conflict
+ /** set pending prefix conflict
*
* If conf is non-null, this is called when conf is a conjunction of literals
* that hold in the current context that are unsatisfiable. It is set as the
@@ -106,9 +77,16 @@ class SolverState
* during a merge operation, when the equality engine is not in a state to
* provide explanations.
*/
- void setPendingConflictWhen(Node conf);
+ void setPendingPrefixConflictWhen(Node conf);
+ /**
+ * Set pending conflict, infer info version. Called when we are in conflict
+ * based on the inference ii. This generalizes the above method.
+ */
+ void setPendingConflict(InferInfo& ii);
+ /** return true if we have a pending conflict */
+ bool hasPendingConflict() const;
/** get the pending conflict, or null if none exist */
- Node getPendingConflict() const;
+ bool getPendingConflict(InferInfo& ii) const;
//------------------------------------------ end conflicts
/** get length with explanation
*
@@ -149,7 +127,7 @@ class SolverState
*/
EqcInfo* getOrMakeEqcInfo(Node eqc, bool doMake = true);
/** Get pointer to the model object of the Valuation object */
- TheoryModel* getModel() const;
+ TheoryModel* getModel();
/** add endpoints to eqc info
*
@@ -182,23 +160,16 @@ class SolverState
private:
/** Common constants */
Node d_zero;
- /** Pointer to the SAT context object used by the theory of strings. */
- context::Context* d_context;
- /** Pointer to the user context object used by the theory of strings. */
- context::UserContext* d_ucontext;
- /** Reference to equality engine of the theory of strings. */
- eq::EqualityEngine& d_ee;
+ Node d_false;
/**
* The (SAT-context-dependent) list of disequalities that have been asserted
* to the equality engine above.
*/
NodeList d_eeDisequalities;
- /** Reference to the valuation of the theory of strings */
- Valuation& d_valuation;
- /** Are we in conflict? */
- context::CDO<bool> d_conflict;
/** The pending conflict if one exists */
- context::CDO<Node> d_pendingConflict;
+ context::CDO<bool> d_pendingConflictSet;
+ /** The pending conflict, valid if the above flag is true */
+ InferInfo d_pendingConflict;
/** Map from representatives to their equivalence class information */
std::map<Node, EqcInfo*> d_eqcInfo;
}; /* class TheoryStrings */
diff --git a/src/theory/strings/strategy.cpp b/src/theory/strings/strategy.cpp
index 549bba9d6..7ead6f45f 100644
--- a/src/theory/strings/strategy.cpp
+++ b/src/theory/strings/strategy.cpp
@@ -2,10 +2,10 @@
/*! \file strategy.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Tianyi Liang, Morgan Deters
+ ** Andrew Reynolds
** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/strategy.h b/src/theory/strings/strategy.h
index 9afb6a92f..802994d06 100644
--- a/src/theory/strings/strategy.h
+++ b/src/theory/strings/strategy.h
@@ -4,8 +4,8 @@
** Top contributors (to current version):
** Andrew Reynolds
** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/strings_entail.cpp b/src/theory/strings/strings_entail.cpp
index 928414523..874854be5 100644
--- a/src/theory/strings/strings_entail.cpp
+++ b/src/theory/strings/strings_entail.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -111,95 +111,92 @@ bool StringsEntail::canConstantContainList(Node c,
bool StringsEntail::stripSymbolicLength(std::vector<Node>& n1,
std::vector<Node>& nr,
int dir,
- Node& curr)
+ Node& curr,
+ bool strict)
{
Assert(dir == 1 || dir == -1);
Assert(nr.empty());
NodeManager* nm = NodeManager::currentNM();
Node zero = nm->mkConst(CVC4::Rational(0));
bool ret = false;
- bool success;
+ bool success = true;
unsigned sindex = 0;
- do
+ while (success && curr != zero && sindex < n1.size())
{
Assert(!curr.isNull());
success = false;
- if (curr != zero && sindex < n1.size())
+ unsigned sindex_use = dir == 1 ? sindex : ((n1.size() - 1) - sindex);
+ if (n1[sindex_use].isConst())
{
- unsigned sindex_use = dir == 1 ? sindex : ((n1.size() - 1) - sindex);
- if (n1[sindex_use].isConst())
+ // could strip part of a constant
+ Node lowerBound = ArithEntail::getConstantBound(Rewriter::rewrite(curr));
+ if (!lowerBound.isNull())
{
- // could strip part of a constant
- Node lowerBound =
- ArithEntail::getConstantBound(Rewriter::rewrite(curr));
- if (!lowerBound.isNull())
+ Assert(lowerBound.isConst());
+ Rational lbr = lowerBound.getConst<Rational>();
+ if (lbr.sgn() > 0)
{
- Assert(lowerBound.isConst());
- Rational lbr = lowerBound.getConst<Rational>();
- if (lbr.sgn() > 0)
+ Assert(ArithEntail::check(curr, true));
+ Node s = n1[sindex_use];
+ size_t slen = Word::getLength(s);
+ Node ncl = nm->mkConst(CVC4::Rational(slen));
+ Node next_s = nm->mkNode(MINUS, lowerBound, ncl);
+ next_s = Rewriter::rewrite(next_s);
+ Assert(next_s.isConst());
+ // we can remove the entire constant
+ if (next_s.getConst<Rational>().sgn() >= 0)
{
- Assert(ArithEntail::check(curr, true));
- Node s = n1[sindex_use];
- size_t slen = Word::getLength(s);
- Node ncl = nm->mkConst(CVC4::Rational(slen));
- Node next_s = nm->mkNode(MINUS, lowerBound, ncl);
- next_s = Rewriter::rewrite(next_s);
- Assert(next_s.isConst());
- // we can remove the entire constant
- if (next_s.getConst<Rational>().sgn() >= 0)
+ curr = Rewriter::rewrite(nm->mkNode(MINUS, curr, ncl));
+ success = true;
+ sindex++;
+ }
+ else
+ {
+ // we can remove part of the constant
+ // lower bound minus the length of a concrete string is negative,
+ // hence lowerBound cannot be larger than long max
+ Assert(lbr < Rational(String::maxSize()));
+ curr = Rewriter::rewrite(nm->mkNode(MINUS, curr, lowerBound));
+ uint32_t lbsize = lbr.getNumerator().toUnsignedInt();
+ Assert(lbsize < slen);
+ if (dir == 1)
{
- curr = Rewriter::rewrite(nm->mkNode(MINUS, curr, ncl));
- success = true;
- sindex++;
+ // strip partially from the front
+ nr.push_back(Word::prefix(s, lbsize));
+ n1[sindex_use] = Word::suffix(s, slen - lbsize);
}
else
{
- // we can remove part of the constant
- // lower bound minus the length of a concrete string is negative,
- // hence lowerBound cannot be larger than long max
- Assert(lbr < Rational(String::maxSize()));
- curr = Rewriter::rewrite(nm->mkNode(MINUS, curr, lowerBound));
- uint32_t lbsize = lbr.getNumerator().toUnsignedInt();
- Assert(lbsize < slen);
- if (dir == 1)
- {
- // strip partially from the front
- nr.push_back(Word::prefix(s, lbsize));
- n1[sindex_use] = Word::suffix(s, slen - lbsize);
- }
- else
- {
- // strip partially from the back
- nr.push_back(Word::suffix(s, lbsize));
- n1[sindex_use] = Word::prefix(s, slen - lbsize);
- }
- ret = true;
+ // strip partially from the back
+ nr.push_back(Word::suffix(s, lbsize));
+ n1[sindex_use] = Word::prefix(s, slen - lbsize);
}
- Assert(ArithEntail::check(curr));
- }
- else
- {
- // we cannot remove the constant
+ ret = true;
}
+ Assert(ArithEntail::check(curr));
}
- }
- else
- {
- Node next_s = NodeManager::currentNM()->mkNode(
- MINUS,
- curr,
- NodeManager::currentNM()->mkNode(STRING_LENGTH, n1[sindex_use]));
- next_s = Rewriter::rewrite(next_s);
- if (ArithEntail::check(next_s))
+ else
{
- success = true;
- curr = next_s;
- sindex++;
+ // we cannot remove the constant
}
}
}
- } while (success);
- if (sindex > 0)
+ else
+ {
+ Node next_s = NodeManager::currentNM()->mkNode(
+ MINUS,
+ curr,
+ NodeManager::currentNM()->mkNode(STRING_LENGTH, n1[sindex_use]));
+ next_s = Rewriter::rewrite(next_s);
+ if (ArithEntail::check(next_s))
+ {
+ success = true;
+ curr = next_s;
+ sindex++;
+ }
+ }
+ }
+ if (sindex > 0 && (!strict || curr == zero))
{
if (dir == 1)
{
@@ -225,6 +222,9 @@ int StringsEntail::componentContains(std::vector<Node>& n1,
{
Assert(nb.empty());
Assert(ne.empty());
+ Trace("strings-entail") << "Component contains: " << std::endl;
+ Trace("strings-entail") << "n1 = " << n1 << std::endl;
+ Trace("strings-entail") << "n2 = " << n2 << std::endl;
// if n2 is a singleton, we can do optimized version here
if (n2.size() == 1)
{
@@ -301,6 +301,10 @@ int StringsEntail::componentContains(std::vector<Node>& n1,
-1,
computeRemainder && remainderDir != -1))
{
+ Trace("strings-entail-debug")
+ << "Last remainder begin is " << n1rb_last << std::endl;
+ Trace("strings-entail-debug")
+ << "Last remainder end is " << n1re_last << std::endl;
Assert(n1rb_last.isNull());
if (computeRemainder)
{
@@ -325,6 +329,9 @@ int StringsEntail::componentContains(std::vector<Node>& n1,
}
}
}
+ Trace("strings-entail-debug") << "ne = " << ne << std::endl;
+ Trace("strings-entail-debug") << "nb = " << nb << std::endl;
+ Trace("strings-entail-debug") << "...return " << i << std::endl;
return i;
}
else
@@ -444,12 +451,12 @@ bool StringsEntail::componentContainsBase(
{
return false;
}
- if (dir != 1)
+ if (dir != -1)
{
n1rb = nm->mkNode(
STRING_SUBSTR, n2[0], nm->mkConst(Rational(0)), start_pos);
}
- if (dir != -1)
+ if (dir != 1)
{
n1re = nm->mkNode(STRING_SUBSTR, n2[0], end_pos, len_n2s);
}
diff --git a/src/theory/strings/strings_entail.h b/src/theory/strings/strings_entail.h
index 3eb77c5f5..be5743ef4 100644
--- a/src/theory/strings/strings_entail.h
+++ b/src/theory/strings/strings_entail.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -67,10 +67,11 @@ class StringsEntail
/** strip symbolic length
*
- * This function strips off components of n1 whose length is less than
- * or equal to argument curr, and stores them in nr. The direction
- * dir determines whether the components are removed from the start
- * or end of n1.
+ * This function strips off components of n1 whose length is less than or
+ * equal to argument curr, and stores them in nr. The direction dir
+ * determines whether the components are removed from the start or end of n1.
+ * If `strict` is set to true, then the function only returns true if full
+ * length `curr` can be stripped.
*
* In detail, this function updates n1 to n1' such that:
* If dir=1,
@@ -107,7 +108,8 @@ class StringsEntail
static bool stripSymbolicLength(std::vector<Node>& n1,
std::vector<Node>& nr,
int dir,
- Node& curr);
+ Node& curr,
+ bool strict = false);
/** component contains
* This function is used when rewriting str.contains( t1, t2 ), where
* n1 is the vector form of t1
diff --git a/src/theory/strings/strings_fmf.cpp b/src/theory/strings/strings_fmf.cpp
index 9530171f0..bf34ceb1c 100644
--- a/src/theory/strings/strings_fmf.cpp
+++ b/src/theory/strings/strings_fmf.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/strings_fmf.h b/src/theory/strings/strings_fmf.h
index f66c23d5b..262790d0f 100644
--- a/src/theory/strings/strings_fmf.h
+++ b/src/theory/strings/strings_fmf.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/strings_rewriter.cpp b/src/theory/strings/strings_rewriter.cpp
index 76391cc0d..932b5c8cc 100644
--- a/src/theory/strings/strings_rewriter.cpp
+++ b/src/theory/strings/strings_rewriter.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/strings_rewriter.h b/src/theory/strings/strings_rewriter.h
index aadb11f1c..d0eee6089 100644
--- a/src/theory/strings/strings_rewriter.h
+++ b/src/theory/strings/strings_rewriter.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/term_registry.cpp b/src/theory/strings/term_registry.cpp
index 613aa26c8..8274b7dc0 100644
--- a/src/theory/strings/term_registry.cpp
+++ b/src/theory/strings/term_registry.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -37,11 +37,10 @@ typedef expr::Attribute<StringsProxyVarAttributeId, bool>
StringsProxyVarAttribute;
TermRegistry::TermRegistry(SolverState& s,
- eq::EqualityEngine& ee,
OutputChannel& out,
SequencesStatistics& statistics,
ProofNodeManager* pnm)
- : d_ee(ee),
+ : d_state(s),
d_out(out),
d_statistics(statistics),
d_hasStrCode(false),
@@ -50,10 +49,12 @@ TermRegistry::TermRegistry(SolverState& s,
d_preregisteredTerms(s.getUserContext()),
d_registeredTerms(s.getUserContext()),
d_registeredTypes(s.getUserContext()),
- d_proxyVar(s.getUserContext()),
- d_proxyVarToLength(s.getUserContext()),
d_lengthLemmaTermsCache(s.getUserContext()),
- d_epg(nullptr)
+ d_epg(pnm ? new EagerProofGenerator(
+ pnm,
+ s.getUserContext(),
+ "strings::TermRegistry::EagerProofGenerator")
+ : nullptr)
{
NodeManager* nm = NodeManager::currentNM();
d_zero = nm->mkConst(Rational(0));
@@ -128,6 +129,7 @@ void TermRegistry::preRegisterTerm(TNode n)
{
return;
}
+ eq::EqualityEngine* ee = d_state.getEqualityEngine();
d_preregisteredTerms.insert(n);
Trace("strings-preregister")
<< "TheoryString::preregister : " << n << std::endl;
@@ -136,8 +138,8 @@ void TermRegistry::preRegisterTerm(TNode n)
if (!options::stringExp())
{
if (k == STRING_STRIDOF || k == STRING_ITOS || k == STRING_STOI
- || k == STRING_STRREPL || k == STRING_STRREPLALL
- || k == STRING_REPLACE_RE || k == STRING_REPLACE_RE_ALL
+ || k == STRING_STRREPL || k == STRING_SUBSTR || k == STRING_STRREPLALL
+ || k == SEQ_NTH || k == STRING_REPLACE_RE || k == STRING_REPLACE_RE_ALL
|| k == STRING_STRCTN || k == STRING_LEQ || k == STRING_TOLOWER
|| k == STRING_TOUPPER || k == STRING_REV || k == STRING_UPDATE)
{
@@ -155,15 +157,15 @@ void TermRegistry::preRegisterTerm(TNode n)
ss << "Equality between regular expressions is not supported";
throw LogicException(ss.str());
}
- d_ee.addTriggerEquality(n);
+ ee->addTriggerPredicate(n);
return;
}
else if (k == STRING_IN_REGEXP)
{
d_out.requirePhase(n, true);
- d_ee.addTriggerPredicate(n);
- d_ee.addTerm(n[0]);
- d_ee.addTerm(n[1]);
+ ee->addTriggerPredicate(n);
+ ee->addTerm(n[0]);
+ ee->addTerm(n[1]);
return;
}
else if (k == STRING_TO_CODE)
@@ -195,17 +197,21 @@ void TermRegistry::preRegisterTerm(TNode n)
}
}
}
- d_ee.addTerm(n);
+ ee->addTerm(n);
}
else if (tn.isBoolean())
{
- // Get triggered for both equal and dis-equal
- d_ee.addTriggerPredicate(n);
+ // All kinds that we do congruence over that may return a Boolean go here
+ if (k==STRING_STRCTN || k == STRING_LEQ || k == SEQ_NTH)
+ {
+ // Get triggered for both equal and dis-equal
+ ee->addTriggerPredicate(n);
+ }
}
else
{
// Function applications/predicates
- d_ee.addTerm(n);
+ ee->addTerm(n);
}
// Set d_functionsTerms stores all function applications that are
// relevant to theory combination. Notice that this is a subset of
@@ -215,7 +221,7 @@ void TermRegistry::preRegisterTerm(TNode n)
// Concatenation terms do not need to be considered here because
// their arguments have string type and do not introduce any shared
// terms.
- if (n.hasOperator() && d_ee.isFunctionKind(k) && k != STRING_CONCAT)
+ if (n.hasOperator() && ee->isFunctionKind(k) && k != STRING_CONCAT)
{
d_functionsTerms.push_back(n);
}
@@ -264,7 +270,7 @@ void TermRegistry::registerTerm(Node n, int effort)
registerType(tn);
Debug("strings-register") << "TheoryStrings::registerTerm() " << n
<< ", effort = " << effort << std::endl;
- Node regTermLem;
+ TrustNode regTermLem;
if (tn.isStringLike())
{
// register length information:
@@ -275,15 +281,29 @@ void TermRegistry::registerTerm(Node n, int effort)
else if (n.getKind() != STRING_STRCTN)
{
// we don't send out eager reduction lemma for str.contains currently
- regTermLem = eagerReduce(n, &d_skCache);
+ Node eagerRedLemma = eagerReduce(n, &d_skCache);
+ if (!eagerRedLemma.isNull())
+ {
+ // if there was an eager reduction, we make the trust node for it
+ if (d_epg != nullptr)
+ {
+ regTermLem = d_epg->mkTrustNode(
+ eagerRedLemma, PfRule::STRING_EAGER_REDUCTION, {}, {n});
+ }
+ else
+ {
+ regTermLem = TrustNode::mkTrustLemma(eagerRedLemma, nullptr);
+ }
+ }
}
if (!regTermLem.isNull())
{
Trace("strings-lemma") << "Strings::Lemma REG-TERM : " << regTermLem
<< std::endl;
- Trace("strings-assert") << "(assert " << regTermLem << ")" << std::endl;
+ Trace("strings-assert")
+ << "(assert " << regTermLem.getNode() << ")" << std::endl;
++(d_statistics.d_lemmasRegisterTerm);
- d_out.lemma(regTermLem);
+ d_out.trustedLemma(regTermLem);
}
}
@@ -298,14 +318,14 @@ void TermRegistry::registerType(TypeNode tn)
{
// preregister the empty word for the type
Node emp = Word::mkEmptyWord(tn);
- if (!d_ee.hasTerm(emp))
+ if (!d_state.hasTerm(emp))
{
preRegisterTerm(emp);
}
}
}
-Node TermRegistry::getRegisterTermLemma(Node n)
+TrustNode TermRegistry::getRegisterTermLemma(Node n)
{
Assert(n.getType().isStringLike());
NodeManager* nm = NodeManager::currentNM();
@@ -321,7 +341,7 @@ Node TermRegistry::getRegisterTermLemma(Node n)
if (lsum == lsumb)
{
registerTermAtomic(n, LENGTH_SPLIT);
- return Node::null();
+ return TrustNode::null();
}
}
Node sk = d_skCache.mkSkolemCached(n, SkolemCache::SK_PURIFY, "lsym");
@@ -367,7 +387,12 @@ Node TermRegistry::getRegisterTermLemma(Node n)
Node ret = nm->mkNode(AND, eq, ceq);
- return ret;
+ // it is a simple rewrite to justify this
+ if (d_epg != nullptr)
+ {
+ return d_epg->mkTrustNode(ret, PfRule::MACRO_SR_PRED_INTRO, {}, {ret});
+ }
+ return TrustNode::mkTrustLemma(ret, nullptr);
}
void TermRegistry::registerTermAtomic(Node n, LengthStatus s)
@@ -384,14 +409,15 @@ void TermRegistry::registerTermAtomic(Node n, LengthStatus s)
return;
}
std::map<Node, bool> reqPhase;
- Node lenLem = getRegisterTermAtomicLemma(n, s, reqPhase);
+ TrustNode lenLem = getRegisterTermAtomicLemma(n, s, reqPhase);
if (!lenLem.isNull())
{
Trace("strings-lemma") << "Strings::Lemma REGISTER-TERM-ATOMIC : " << lenLem
<< std::endl;
- Trace("strings-assert") << "(assert " << lenLem << ")" << std::endl;
+ Trace("strings-assert")
+ << "(assert " << lenLem.getNode() << ")" << std::endl;
++(d_statistics.d_lemmasRegisterTermAtomic);
- d_out.lemma(lenLem);
+ d_out.trustedLemma(lenLem);
}
for (const std::pair<const Node, bool>& rp : reqPhase)
{
@@ -414,16 +440,15 @@ const context::CDHashSet<Node, NodeHashFunction>& TermRegistry::getInputVars()
bool TermRegistry::hasStringCode() const { return d_hasStrCode; }
-Node TermRegistry::getRegisterTermAtomicLemma(Node n,
- LengthStatus s,
- std::map<Node, bool>& reqPhase)
+TrustNode TermRegistry::getRegisterTermAtomicLemma(
+ Node n, LengthStatus s, std::map<Node, bool>& reqPhase)
{
if (n.isConst())
{
// No need to send length for constant terms. This case may be triggered
// for cases where the skolem cache automatically replaces a skolem by
// a constant.
- return Node::null();
+ return TrustNode::null();
}
Assert(n.getType().isStringLike());
NodeManager* nm = NodeManager::currentNM();
@@ -437,7 +462,7 @@ Node TermRegistry::getRegisterTermAtomicLemma(Node n,
Trace("strings-lemma") << "Strings::Lemma SK-GEQ-ONE : " << len_geq_one
<< std::endl;
Trace("strings-assert") << "(assert " << len_geq_one << ")" << std::endl;
- return len_geq_one;
+ return TrustNode::mkTrustLemma(len_geq_one, nullptr);
}
if (s == LENGTH_ONE)
@@ -446,7 +471,7 @@ Node TermRegistry::getRegisterTermAtomicLemma(Node n,
Trace("strings-lemma") << "Strings::Lemma SK-ONE : " << len_one
<< std::endl;
Trace("strings-assert") << "(assert " << len_one << ")" << std::endl;
- return len_one;
+ return TrustNode::mkTrustLemma(len_one, nullptr);
}
Assert(s == LENGTH_SPLIT);
@@ -477,7 +502,11 @@ Node TermRegistry::getRegisterTermAtomicLemma(Node n,
Assert(!case_emptyr.getConst<bool>());
}
- return lenLemma;
+ if (d_epg != nullptr)
+ {
+ return d_epg->mkTrustNode(lenLemma, PfRule::STRING_LENGTH_POS, {}, {n});
+ }
+ return TrustNode::mkTrustLemma(lenLemma, nullptr);
}
Node TermRegistry::getSymbolicDefinition(Node n, std::vector<Node>& exp) const
@@ -526,7 +555,7 @@ Node TermRegistry::getSymbolicDefinition(Node n, std::vector<Node>& exp) const
Node TermRegistry::getProxyVariableFor(Node n) const
{
- NodeNodeMap::const_iterator it = d_proxyVar.find(n);
+ std::map<Node, Node>::const_iterator it = d_proxyVar.find(n);
if (it != d_proxyVar.end())
{
return (*it).second;
@@ -534,6 +563,18 @@ Node TermRegistry::getProxyVariableFor(Node n) const
return Node::null();
}
+Node TermRegistry::ensureProxyVariableFor(Node n)
+{
+ Node proxy = getProxyVariableFor(n);
+ if (proxy.isNull())
+ {
+ registerTerm(n, 0);
+ proxy = getProxyVariableFor(n);
+ }
+ Assert(!proxy.isNull());
+ return proxy;
+}
+
void TermRegistry::inferSubstitutionProxyVars(Node n,
std::vector<Node>& vars,
std::vector<Node>& subs,
diff --git a/src/theory/strings/term_registry.h b/src/theory/strings/term_registry.h
index 4d5a91d97..a713cc60f 100644
--- a/src/theory/strings/term_registry.h
+++ b/src/theory/strings/term_registry.h
@@ -2,10 +2,10 @@
/*! \file term_registry.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Tim King, Tianyi Liang
+ ** Andrew Reynolds, Andres Noetzli, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -50,7 +50,6 @@ class TermRegistry
public:
TermRegistry(SolverState& s,
- eq::EqualityEngine& ee,
OutputChannel& out,
SequencesStatistics& statistics,
ProofNodeManager* pnm);
@@ -168,6 +167,15 @@ class TermRegistry
*/
Node getProxyVariableFor(Node n) const;
+ /**
+ * Get the proxy variable for a term. If the proxy variable does not exist,
+ * this method registers the term and then returns its proxy variable.
+ *
+ * @param n The term
+ * @return Proxy variable for `n`
+ */
+ Node ensureProxyVariableFor(Node n);
+
/** infer substitution proxy vars
*
* This method attempts to (partially) convert the formula n into a
@@ -209,8 +217,8 @@ class TermRegistry
Node d_negOne;
/** the cardinality of the alphabet */
uint32_t d_cardSize;
- /** Reference to equality engine of the theory of strings. */
- eq::EqualityEngine& d_ee;
+ /** Reference to the solver state of the theory of strings. */
+ SolverState& d_state;
/** Reference to the output channel of the theory of strings. */
OutputChannel& d_out;
/** Reference to the statistics for the theory of strings/sequences. */
@@ -241,12 +249,12 @@ class TermRegistry
* which rewrites to 3 = 3.
* In the above example, we store "ABC" -> v_{"ABC"} in this map.
*/
- NodeNodeMap d_proxyVar;
+ std::map<Node, Node> d_proxyVar;
/**
* Map from proxy variables to their normalized length. In the above example,
* we store "ABC" -> 3.
*/
- NodeNodeMap d_proxyVarToLength;
+ std::map<Node, Node> d_proxyVarToLength;
/** List of terms that we have register length for */
NodeSet d_lengthLemmaTermsCache;
/** Proof generator, manages proofs for lemmas generated by this class */
@@ -267,7 +275,7 @@ class TermRegistry
* If n is an atomic term, the method registerTermAtomic is called for n
* and s = LENGTH_SPLIT and no lemma is returned.
*/
- Node getRegisterTermLemma(Node n);
+ TrustNode getRegisterTermLemma(Node n);
/**
* Get the lemma required for registering the length information for
* atomic term n given length status s. For details, see registerTermAtomic.
@@ -276,9 +284,9 @@ class TermRegistry
* argument reqPhase, which should be processed by a call to requiredPhase by
* the caller of this method.
*/
- Node getRegisterTermAtomicLemma(Node n,
- LengthStatus s,
- std::map<Node, bool>& reqPhase);
+ TrustNode getRegisterTermAtomicLemma(Node n,
+ LengthStatus s,
+ std::map<Node, bool>& reqPhase);
};
} // namespace strings
diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp
index 150ea8977..a9e2c0051 100644
--- a/src/theory/strings/theory_strings.cpp
+++ b/src/theory/strings/theory_strings.cpp
@@ -2,10 +2,10 @@
/*! \file theory_strings.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Tianyi Liang, Andres Noetzli
+ ** Andrew Reynolds, Tianyi Liang, Yoni Zohar
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -15,6 +15,7 @@
#include "theory/strings/theory_strings.h"
#include "expr/kind.h"
+#include "options/smt_options.h"
#include "options/strings_options.h"
#include "options/theory_options.h"
#include "smt/logic_exception.h"
@@ -43,61 +44,30 @@ TheoryStrings::TheoryStrings(context::Context* c,
: Theory(THEORY_STRINGS, c, u, out, valuation, logicInfo, pnm),
d_notify(*this),
d_statistics(),
- d_equalityEngine(d_notify, c, "theory::strings::ee", true),
- d_state(c, u, d_equalityEngine, d_valuation),
- d_termReg(d_state, d_equalityEngine, out, d_statistics, nullptr),
- d_im(nullptr),
+ d_state(c, u, d_valuation),
+ d_termReg(d_state, out, d_statistics, pnm),
+ d_extTheoryCb(),
+ d_extTheory(d_extTheoryCb, c, u, out),
+ d_im(*this, d_state, d_termReg, d_extTheory, d_statistics, pnm),
d_rewriter(&d_statistics.d_rewrites),
- d_bsolver(nullptr),
- d_csolver(nullptr),
- d_esolver(nullptr),
- d_rsolver(nullptr),
+ d_bsolver(d_state, d_im),
+ d_csolver(d_state, d_im, d_termReg, d_bsolver),
+ d_esolver(d_state,
+ d_im,
+ d_termReg,
+ d_rewriter,
+ d_bsolver,
+ d_csolver,
+ d_extTheory,
+ d_statistics),
+ d_rsolver(d_state,
+ d_im,
+ d_termReg.getSkolemCache(),
+ d_csolver,
+ d_esolver,
+ d_statistics),
d_stringsFmf(c, u, valuation, d_termReg)
{
- setupExtTheory();
- ExtTheory* extt = getExtTheory();
- // initialize the inference manager, which requires the extended theory
- d_im.reset(
- new InferenceManager(c, u, d_state, d_termReg, *extt, out, d_statistics));
- // initialize the solvers
- d_bsolver.reset(new BaseSolver(d_state, *d_im));
- d_csolver.reset(new CoreSolver(c, u, d_state, *d_im, d_termReg, *d_bsolver));
- d_esolver.reset(new ExtfSolver(c,
- u,
- d_state,
- *d_im,
- d_termReg,
- d_rewriter,
- *d_bsolver,
- *d_csolver,
- *extt,
- d_statistics));
- d_rsolver.reset(new RegExpSolver(
- d_state, *d_im, *d_csolver, *d_esolver, d_statistics, c, u));
-
- // The kinds we are treating as function application in congruence
- d_equalityEngine.addFunctionKind(kind::STRING_LENGTH);
- d_equalityEngine.addFunctionKind(kind::STRING_CONCAT);
- d_equalityEngine.addFunctionKind(kind::STRING_IN_REGEXP);
- d_equalityEngine.addFunctionKind(kind::STRING_TO_CODE);
- d_equalityEngine.addFunctionKind(kind::SEQ_UNIT);
-
- // extended functions
- d_equalityEngine.addFunctionKind(kind::STRING_STRCTN);
- d_equalityEngine.addFunctionKind(kind::STRING_LEQ);
- d_equalityEngine.addFunctionKind(kind::STRING_SUBSTR);
- d_equalityEngine.addFunctionKind(kind::STRING_UPDATE);
- d_equalityEngine.addFunctionKind(kind::STRING_ITOS);
- d_equalityEngine.addFunctionKind(kind::STRING_STOI);
- d_equalityEngine.addFunctionKind(kind::STRING_STRIDOF);
- d_equalityEngine.addFunctionKind(kind::STRING_STRREPL);
- d_equalityEngine.addFunctionKind(kind::STRING_STRREPLALL);
- d_equalityEngine.addFunctionKind(kind::STRING_REPLACE_RE);
- d_equalityEngine.addFunctionKind(kind::STRING_REPLACE_RE_ALL);
- d_equalityEngine.addFunctionKind(kind::STRING_STRREPLALL);
- d_equalityEngine.addFunctionKind(kind::STRING_TOLOWER);
- d_equalityEngine.addFunctionKind(kind::STRING_TOUPPER);
- d_equalityEngine.addFunctionKind(kind::STRING_REV);
d_zero = NodeManager::currentNM()->mkConst( Rational( 0 ) );
d_one = NodeManager::currentNM()->mkConst( Rational( 1 ) );
@@ -106,6 +76,20 @@ TheoryStrings::TheoryStrings(context::Context* c,
d_false = NodeManager::currentNM()->mkConst( false );
d_cardSize = utils::getAlphabetCardinality();
+
+ // set up the extended function callback
+ d_extTheoryCb.d_esolver = &d_esolver;
+
+ ProofChecker* pc = pnm != nullptr ? pnm->getChecker() : nullptr;
+ if (pc != nullptr)
+ {
+ // add checkers
+ d_sProofChecker.registerTo(pc);
+ }
+ // use the state object as the official theory state
+ d_theoryState = &d_state;
+ // use the inference manager as the official inference manager
+ d_inferManager = &d_im;
}
TheoryStrings::~TheoryStrings() {
@@ -113,27 +97,63 @@ TheoryStrings::~TheoryStrings() {
}
TheoryRewriter* TheoryStrings::getTheoryRewriter() { return &d_rewriter; }
-std::string TheoryStrings::identify() const
-{
- return std::string("TheoryStrings");
-}
-eq::EqualityEngine* TheoryStrings::getEqualityEngine()
+
+bool TheoryStrings::needsEqualityEngine(EeSetupInfo& esi)
{
- return &d_equalityEngine;
+ esi.d_notify = &d_notify;
+ esi.d_name = "theory::strings::ee";
+ return true;
}
+
void TheoryStrings::finishInit()
{
- TheoryModel* tm = d_valuation.getModel();
+ Assert(d_equalityEngine != nullptr);
+
// witness is used to eliminate str.from_code
- tm->setUnevaluatedKind(WITNESS);
+ d_valuation.setUnevaluatedKind(WITNESS);
+
+ bool eagerEval = options::stringEagerEval();
+ // The kinds we are treating as function application in congruence
+ d_equalityEngine->addFunctionKind(kind::STRING_LENGTH, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::STRING_CONCAT, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::STRING_IN_REGEXP, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::STRING_TO_CODE, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::SEQ_UNIT, eagerEval);
+ // `seq.nth` is not always defined, and so we do not evaluate it eagerly.
+ d_equalityEngine->addFunctionKind(kind::SEQ_NTH, false);
+ // extended functions
+ d_equalityEngine->addFunctionKind(kind::STRING_STRCTN, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::STRING_LEQ, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::STRING_SUBSTR, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::STRING_UPDATE, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::STRING_ITOS, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::STRING_STOI, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::STRING_STRIDOF, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::STRING_STRREPL, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::STRING_STRREPLALL, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::STRING_REPLACE_RE, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::STRING_REPLACE_RE_ALL, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::STRING_STRREPLALL, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::STRING_TOLOWER, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::STRING_TOUPPER, eagerEval);
+ d_equalityEngine->addFunctionKind(kind::STRING_REV, eagerEval);
+}
+
+std::string TheoryStrings::identify() const
+{
+ return std::string("TheoryStrings");
}
bool TheoryStrings::areCareDisequal( TNode x, TNode y ) {
- Assert(d_equalityEngine.hasTerm(x));
- Assert(d_equalityEngine.hasTerm(y));
- if( d_equalityEngine.isTriggerTerm(x, THEORY_STRINGS) && d_equalityEngine.isTriggerTerm(y, THEORY_STRINGS) ){
- TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_STRINGS);
- TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_STRINGS);
+ Assert(d_equalityEngine->hasTerm(x));
+ Assert(d_equalityEngine->hasTerm(y));
+ if (d_equalityEngine->isTriggerTerm(x, THEORY_STRINGS)
+ && d_equalityEngine->isTriggerTerm(y, THEORY_STRINGS))
+ {
+ TNode x_shared =
+ d_equalityEngine->getTriggerTermRepresentative(x, THEORY_STRINGS);
+ TNode y_shared =
+ d_equalityEngine->getTriggerTermRepresentative(y, THEORY_STRINGS);
EqualityStatus eqStatus = d_valuation.getEqualityStatus(x_shared, y_shared);
if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
return true;
@@ -142,51 +162,32 @@ bool TheoryStrings::areCareDisequal( TNode x, TNode y ) {
return false;
}
-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);
+void TheoryStrings::notifySharedTerm(TNode t)
+{
+ Debug("strings") << "TheoryStrings::notifySharedTerm(): " << t << " "
+ << t.getType().isBoolean() << endl;
if (options::stringExp())
{
- getExtTheory()->registerTermRec(t);
- }
- 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;
- }
+ d_esolver.addSharedTerm(t);
}
- return EQUALITY_UNKNOWN;
-}
-
-void TheoryStrings::propagate(Effort e) {
- // direct propagation now
+ Debug("strings") << "TheoryStrings::notifySharedTerm() finished" << std::endl;
}
-bool TheoryStrings::propagate(TNode literal) {
- Debug("strings-propagate") << "TheoryStrings::propagate(" << literal << ")" << std::endl;
+bool TheoryStrings::propagateLit(TNode literal)
+{
+ Debug("strings-propagate")
+ << "TheoryStrings::propagateLit(" << literal << ")" << std::endl;
// If already in conflict, no more propagation
if (d_state.isInConflict())
{
- Debug("strings-propagate") << "TheoryStrings::propagate(" << literal << "): already in conflict" << std::endl;
+ Debug("strings-propagate") << "TheoryStrings::propagateLit(" << literal
+ << "): already in conflict" << std::endl;
return false;
}
// Propagate out
bool ok = d_out->propagate(literal);
if (!ok) {
- d_state.setConflict();
+ d_state.notifyInConflict();
}
return ok;
}
@@ -194,29 +195,7 @@ bool TheoryStrings::propagate(TNode literal) {
TrustNode TheoryStrings::explain(TNode literal)
{
Debug("strings-explain") << "explain called on " << literal << std::endl;
- std::vector< TNode > assumptions;
- d_im->explain(literal, assumptions);
- Node ret;
- if( assumptions.empty() ){
- ret = d_true;
- }else if( assumptions.size()==1 ){
- ret = assumptions[0];
- }else{
- ret = NodeManager::currentNM()->mkNode(kind::AND, assumptions);
- }
- return TrustNode::mkTrustPropExp(literal, ret, nullptr);
-}
-
-bool TheoryStrings::getCurrentSubstitution( int effort, std::vector< Node >& vars,
- std::vector< Node >& subs, std::map< Node, std::vector< Node > >& exp ) {
- Trace("strings-subs") << "getCurrentSubstitution, effort = " << effort << std::endl;
- for( unsigned i=0; i<vars.size(); i++ ){
- Node n = vars[i];
- Trace("strings-subs") << " get subs for " << n << "..." << std::endl;
- Node s = d_esolver->getCurrentSubstitutionFor(effort, n, exp[n]);
- subs.push_back(s);
- }
- return true;
+ return d_im.explainLit(literal);
}
void TheoryStrings::presolve() {
@@ -242,23 +221,10 @@ void TheoryStrings::presolve() {
// MODEL GENERATION
/////////////////////////////////////////////////////////////////////////////
-bool TheoryStrings::collectModelInfo(TheoryModel* m)
+bool TheoryStrings::collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet)
{
- Trace("strings-model") << "TheoryStrings : Collect model info" << std::endl;
- Trace("strings-model") << "TheoryStrings : assertEqualityEngine." << std::endl;
-
- std::set<Node> termSet;
-
- // Compute terms appearing in assertions and shared terms
- computeRelevantTerms(termSet);
- // assert the (relevant) portion of the equality engine to the model
- if (!m->assertEqualityEngine(&d_equalityEngine, &termSet))
- {
- Unreachable()
- << "TheoryStrings::collectModelInfo: failed to assert equality engine"
- << std::endl;
- return false;
- }
+ Trace("strings-model") << "TheoryStrings : Collect model values" << std::endl;
std::map<TypeNode, std::unordered_set<Node, NodeHashFunction> > repSet;
// Generate model
@@ -302,7 +268,7 @@ bool TheoryStrings::collectModelInfoType(
std::map< Node, Node > processed;
//step 1 : get all values for known lengths
std::vector< Node > lts_values;
- std::map<unsigned, Node> values_used;
+ std::map<std::size_t, Node> values_used;
std::vector<Node> len_splits;
for( unsigned i=0; i<col.size(); i++ ) {
Trace("strings-model") << "Checking length for {";
@@ -329,15 +295,16 @@ bool TheoryStrings::collectModelInfoType(
else
{
// must throw logic exception if we cannot construct the string
- if (len_value.getConst<Rational>() > Rational(String::maxSize()))
+ if (len_value.getConst<Rational>() > String::maxSize())
{
std::stringstream ss;
- ss << "Cannot generate model with string whose length exceeds UINT32_MAX";
+ ss << "The model was computed to have strings of length " << len_value
+ << ". We only allow strings up to length " << String::maxSize();
throw LogicException(ss.str());
}
- unsigned lvalue =
+ std::size_t lvalue =
len_value.getConst<Rational>().getNumerator().toUnsignedInt();
- std::map<unsigned, Node>::iterator itvu = values_used.find(lvalue);
+ auto itvu = values_used.find(lvalue);
if (itvu == values_used.end())
{
values_used[lvalue] = lts[i];
@@ -364,14 +331,17 @@ bool TheoryStrings::collectModelInfoType(
//check if col[i][j] has only variables
if (!eqc.isConst())
{
- NormalForm& nfe = d_csolver->getNormalForm(eqc);
+ NormalForm& nfe = d_csolver.getNormalForm(eqc);
if (nfe.d_nf.size() == 1)
{
// is it an equivalence class with a seq.unit term?
if (nfe.d_nf[0].getKind() == SEQ_UNIT)
{
- pure_eq_assign[eqc] = nfe.d_nf[0];
+ Node c = Rewriter::rewrite(nm->mkNode(
+ SEQ_UNIT, d_valuation.getModelValue(nfe.d_nf[0][0])));
+ pure_eq_assign[eqc] = c;
Trace("strings-model") << "(unit: " << nfe.d_nf[0] << ") ";
+ m->getEqualityEngine()->addTerm(c);
}
// does it have a code and the length of these equivalence classes are
// one?
@@ -399,6 +369,12 @@ bool TheoryStrings::collectModelInfoType(
else
{
processed[eqc] = eqc;
+ // Make sure that constants are asserted to the theory model that we
+ // are building. It is possible that new constants were introduced by
+ // the eager evaluation in the equality engine. These terms are missing
+ // in the term set and, as a result, are skipped when the equality
+ // engine is asserted to the theory model.
+ m->getEqualityEngine()->addTerm(eqc);
}
}
Trace("strings-model") << "have length " << lts_values[i] << std::endl;
@@ -407,7 +383,7 @@ bool TheoryStrings::collectModelInfoType(
if( !pure_eq.empty() ){
if( lts_values[i].isNull() ){
// start with length two (other lengths have special precendence)
- unsigned lvalue = 2;
+ std::size_t lvalue = 2;
while( values_used.find( lvalue )!=values_used.end() ){
lvalue++;
}
@@ -516,7 +492,7 @@ bool TheoryStrings::collectModelInfoType(
{
if (processed.find(rn) == processed.end())
{
- NormalForm& nf = d_csolver->getNormalForm(rn);
+ NormalForm& nf = d_csolver.getNormalForm(rn);
if (Trace.isOn("strings-model"))
{
Trace("strings-model")
@@ -604,30 +580,68 @@ TrustNode TheoryStrings::expandDefinition(Node node)
ITE, cond, t.eqNode(nm->mkNode(STRING_TO_CODE, k)), k.eqNode(emp)));
return TrustNode::mkTrustRewrite(node, ret, nullptr);
}
-
return TrustNode::null();
}
-void TheoryStrings::check(Effort e) {
- if (done() && e<EFFORT_FULL) {
- return;
+bool TheoryStrings::preNotifyFact(
+ TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal)
+{
+ // this is only required for internal facts, others are already registered
+ if (isInternal && atom.getKind() == EQUAL)
+ {
+ // we must ensure these terms are registered
+ for (const Node& t : atom)
+ {
+ // terms in the equality engine are already registered, hence skip
+ // currently done for only string-like terms, but this could potentially
+ // be avoided.
+ if (!d_equalityEngine->hasTerm(t) && t.getType().isStringLike())
+ {
+ d_termReg.registerTerm(t, 0);
+ }
+ }
}
+ return false;
+}
- TimerStat::CodeTimer checkTimer(d_checkTime);
-
- // Trace("strings-process") << "Theory of strings, check : " << e << std::endl;
- Trace("strings-check-debug")
- << "Theory of strings, check : " << e << std::endl;
- while (!done() && !d_state.isInConflict())
+void TheoryStrings::notifyFact(TNode atom,
+ bool polarity,
+ TNode fact,
+ bool isInternal)
+{
+ if (atom.getKind() == STRING_IN_REGEXP)
{
- // Get all the assertions
- Assertion assertion = get();
- TNode fact = assertion.d_assertion;
-
- Trace("strings-assertion") << "get assertion: " << fact << endl;
- d_im->sendAssumption(fact);
+ if (polarity && atom[1].getKind() == REGEXP_CONCAT)
+ {
+ Node eqc = d_equalityEngine->getRepresentative(atom[0]);
+ d_state.addEndpointsToEqcInfo(atom, atom[1], eqc);
+ }
+ }
+ // process pending conflicts due to reasoning about endpoints
+ if (!d_state.isInConflict() && d_state.hasPendingConflict())
+ {
+ InferInfo iiPendingConf;
+ d_state.getPendingConflict(iiPendingConf);
+ Trace("strings-pending")
+ << "Process pending conflict " << iiPendingConf.d_ant << std::endl;
+ Trace("strings-conflict")
+ << "CONFLICT: Eager : " << iiPendingConf.d_ant << std::endl;
+ ++(d_statistics.d_conflictsEager);
+ // call the inference manager to send the conflict
+ d_im.processConflict(iiPendingConf);
+ return;
}
- d_im->doPendingFacts();
+ Trace("strings-pending-debug") << " Now collect terms" << std::endl;
+ // Collect extended function terms in the atom. Notice that we must register
+ // all extended functions occurring in assertions and shared terms. We
+ // make a similar call to registerTermRec in TheoryStrings::addSharedTerm.
+ d_extTheory.registerTermRec(atom);
+ Trace("strings-pending-debug") << " Finished collect terms" << std::endl;
+}
+
+void TheoryStrings::postCheck(Effort e)
+{
+ d_im.doPendingFacts();
Assert(d_strat.isStrategyInit());
if (!d_state.isInConflict() && !d_valuation.needCheck()
@@ -635,16 +649,19 @@ void TheoryStrings::check(Effort e) {
{
Trace("strings-check-debug")
<< "Theory of strings " << e << " effort check " << std::endl;
- if(Trace.isOn("strings-eqc")) {
- for( unsigned t=0; t<2; t++ ) {
- eq::EqClassesIterator eqcs2_i = eq::EqClassesIterator( &d_equalityEngine );
+ if (Trace.isOn("strings-eqc"))
+ {
+ for (unsigned t = 0; t < 2; t++)
+ {
+ eq::EqClassesIterator eqcs2_i = eq::EqClassesIterator(d_equalityEngine);
Trace("strings-eqc") << (t==0 ? "STRINGS:" : "OTHER:") << std::endl;
while( !eqcs2_i.isFinished() ){
Node eqc = (*eqcs2_i);
bool print = (t == 0 && eqc.getType().isStringLike())
|| (t == 1 && !eqc.getType().isStringLike());
if (print) {
- eq::EqClassIterator eqc2_i = eq::EqClassIterator( eqc, &d_equalityEngine );
+ eq::EqClassIterator eqc2_i =
+ eq::EqClassIterator(eqc, d_equalityEngine);
Trace("strings-eqc") << "Eqc( " << eqc << " ) : { ";
while( !eqc2_i.isFinished() ) {
if( (*eqc2_i)!=eqc && (*eqc2_i).getKind()!=kind::EQUAL ){
@@ -672,58 +689,64 @@ void TheoryStrings::check(Effort e) {
Trace("strings-eqc") << std::endl;
}
++(d_statistics.d_checkRuns);
- bool addedLemma = false;
- bool addedFact;
+ bool sentLemma = false;
+ bool hadPending = false;
Trace("strings-check") << "Full effort check..." << std::endl;
do{
+ d_im.reset();
++(d_statistics.d_strategyRuns);
Trace("strings-check") << " * Run strategy..." << std::endl;
runStrategy(e);
- // flush the facts
- addedFact = d_im->hasPendingFact();
- addedLemma = d_im->hasPendingLemma();
- d_im->doPendingFacts();
- d_im->doPendingLemmas();
+ // remember if we had pending facts or lemmas
+ hadPending = d_im.hasPending();
+ // Send the facts *and* the lemmas. We send lemmas regardless of whether
+ // we send facts since some lemmas cannot be dropped. Other lemmas are
+ // otherwise avoided by aborting the strategy when a fact is ready.
+ d_im.doPending();
+ // Did we successfully send a lemma? Notice that if hasPending = true
+ // and sentLemma = false, then the above call may have:
+ // (1) had no pending lemmas, but successfully processed pending facts,
+ // (2) unsuccessfully processed pending lemmas.
+ // In either case, we repeat the strategy if we are not in conflict.
+ sentLemma = d_im.hasSentLemma();
if (Trace.isOn("strings-check"))
{
Trace("strings-check") << " ...finish run strategy: ";
- Trace("strings-check") << (addedFact ? "addedFact " : "");
- Trace("strings-check") << (addedLemma ? "addedLemma " : "");
+ Trace("strings-check") << (hadPending ? "hadPending " : "");
+ Trace("strings-check") << (sentLemma ? "sentLemma " : "");
Trace("strings-check") << (d_state.isInConflict() ? "conflict " : "");
- if (!addedFact && !addedLemma && !d_state.isInConflict())
+ if (!hadPending && !sentLemma && !d_state.isInConflict())
{
Trace("strings-check") << "(none)";
}
Trace("strings-check") << std::endl;
}
- // repeat if we did not add a lemma or conflict
- } while (!d_state.isInConflict() && !addedLemma && addedFact);
+ // repeat if we did not add a lemma or conflict, and we had pending
+ // facts or lemmas.
+ } while (!d_state.isInConflict() && !sentLemma && hadPending);
}
Trace("strings-check") << "Theory of strings, done check : " << e << std::endl;
- Assert(!d_im->hasPendingFact());
- Assert(!d_im->hasPendingLemma());
+ Assert(!d_im.hasPendingFact());
+ Assert(!d_im.hasPendingLemma());
}
bool TheoryStrings::needsCheckLastEffort() {
if( options::stringGuessModel() ){
- return d_esolver->hasExtendedFunctions();
+ return d_esolver.hasExtendedFunctions();
}
return false;
}
/** Conflict when merging two constants */
void TheoryStrings::conflict(TNode a, TNode b){
- if (!d_state.isInConflict())
+ if (d_state.isInConflict())
{
- Debug("strings-conflict") << "Making conflict..." << std::endl;
- d_state.setConflict();
- TrustNode conflictNode = explain(a.eqNode(b));
- Trace("strings-conflict")
- << "CONFLICT: Eq engine conflict : " << conflictNode.getNode()
- << std::endl;
- ++(d_statistics.d_conflictsEqEngine);
- d_out->conflict(conflictNode.getNode());
+ // already in conflict
+ return;
}
+ d_im.conflictEqConstantMerge(a, b);
+ Trace("strings-conflict") << "CONFLICT: Eq engine conflict" << std::endl;
+ ++(d_statistics.d_conflictsEqEngine);
}
void TheoryStrings::eqNotifyNewClass(TNode t){
@@ -746,20 +769,26 @@ void TheoryStrings::addCarePairs(TNodeTrie* t1,
if( t2!=NULL ){
Node f1 = t1->getData();
Node f2 = t2->getData();
- if( !d_equalityEngine.areEqual( f1, f2 ) ){
+ if (!d_equalityEngine->areEqual(f1, f2))
+ {
Trace("strings-cg-debug") << "TheoryStrings::computeCareGraph(): checking function " << f1 << " and " << f2 << std::endl;
vector< pair<TNode, TNode> > currentPairs;
for (unsigned k = 0; k < f1.getNumChildren(); ++ k) {
TNode x = f1[k];
TNode y = f2[k];
- Assert(d_equalityEngine.hasTerm(x));
- Assert(d_equalityEngine.hasTerm(y));
- Assert(!d_equalityEngine.areDisequal(x, y, false));
+ Assert(d_equalityEngine->hasTerm(x));
+ Assert(d_equalityEngine->hasTerm(y));
+ Assert(!d_equalityEngine->areDisequal(x, y, false));
Assert(!areCareDisequal(x, y));
- if( !d_equalityEngine.areEqual( x, y ) ){
- if( d_equalityEngine.isTriggerTerm(x, THEORY_STRINGS) && d_equalityEngine.isTriggerTerm(y, THEORY_STRINGS) ){
- TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_STRINGS);
- TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_STRINGS);
+ if (!d_equalityEngine->areEqual(x, y))
+ {
+ if (d_equalityEngine->isTriggerTerm(x, THEORY_STRINGS)
+ && d_equalityEngine->isTriggerTerm(y, THEORY_STRINGS))
+ {
+ TNode x_shared = d_equalityEngine->getTriggerTermRepresentative(
+ x, THEORY_STRINGS);
+ TNode y_shared = d_equalityEngine->getTriggerTermRepresentative(
+ y, THEORY_STRINGS);
currentPairs.push_back(make_pair(x_shared, y_shared));
}
}
@@ -787,7 +816,8 @@ void TheoryStrings::addCarePairs(TNodeTrie* t1,
std::map<TNode, TNodeTrie>::iterator it2 = it;
++it2;
for( ; it2 != t1->d_data.end(); ++it2 ){
- if( !d_equalityEngine.areDisequal(it->first, it2->first, false) ){
+ if (!d_equalityEngine->areDisequal(it->first, it2->first, false))
+ {
if( !areCareDisequal(it->first, it2->first) ){
addCarePairs( &it->second, &it2->second, arity, depth+1 );
}
@@ -800,7 +830,7 @@ void TheoryStrings::addCarePairs(TNodeTrie* t1,
{
for (std::pair<const TNode, TNodeTrie>& tt2 : t2->d_data)
{
- if (!d_equalityEngine.areDisequal(tt1.first, tt2.first, false))
+ if (!d_equalityEngine->areDisequal(tt1.first, tt2.first, false))
{
if (!areCareDisequal(tt1.first, tt2.first))
{
@@ -829,8 +859,9 @@ void TheoryStrings::computeCareGraph(){
std::vector< TNode > reps;
bool has_trigger_arg = false;
for( unsigned j=0; j<f1.getNumChildren(); j++ ){
- reps.push_back( d_equalityEngine.getRepresentative( f1[j] ) );
- if( d_equalityEngine.isTriggerTerm( f1[j], THEORY_STRINGS ) ){
+ reps.push_back(d_equalityEngine->getRepresentative(f1[j]));
+ if (d_equalityEngine->isTriggerTerm(f1[j], THEORY_STRINGS))
+ {
has_trigger_arg = true;
}
}
@@ -853,14 +884,14 @@ void TheoryStrings::computeCareGraph(){
void TheoryStrings::checkRegisterTermsPreNormalForm()
{
- const std::vector<Node>& seqc = d_bsolver->getStringEqc();
+ const std::vector<Node>& seqc = d_bsolver.getStringEqc();
for (const Node& eqc : seqc)
{
- eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, &d_equalityEngine);
+ eq::EqClassIterator eqc_i = eq::EqClassIterator(eqc, d_equalityEngine);
while (!eqc_i.isFinished())
{
Node n = (*eqc_i);
- if (!d_bsolver->isCongruent(n))
+ if (!d_bsolver.isCongruent(n))
{
d_termReg.registerTerm(n, 2);
}
@@ -882,10 +913,10 @@ void TheoryStrings::checkCodes()
// str.code applied to the proxy variables for each equivalence classes that
// are constants of size one
std::vector<Node> const_codes;
- const std::vector<Node>& seqc = d_bsolver->getStringEqc();
+ const std::vector<Node>& seqc = d_bsolver.getStringEqc();
for (const Node& eqc : seqc)
{
- NormalForm& nfe = d_csolver->getNormalForm(eqc);
+ NormalForm& nfe = d_csolver.getNormalForm(eqc);
if (nfe.d_nf.size() == 1 && nfe.d_nf[0].isConst())
{
Node c = nfe.d_nf[0];
@@ -894,13 +925,12 @@ void TheoryStrings::checkCodes()
Node cc = nm->mkNode(kind::STRING_TO_CODE, c);
cc = Rewriter::rewrite(cc);
Assert(cc.isConst());
- Node cp = d_termReg.getProxyVariableFor(c);
- AlwaysAssert(!cp.isNull());
+ Node cp = d_termReg.ensureProxyVariableFor(c);
Node vc = nm->mkNode(STRING_TO_CODE, cp);
if (!d_state.areEqual(cc, vc))
{
std::vector<Node> emptyVec;
- d_im->sendInference(emptyVec, cc.eqNode(vc), Inference::CODE_PROXY);
+ d_im.sendInference(emptyVec, cc.eqNode(vc), Inference::CODE_PROXY);
}
const_codes.push_back(vc);
}
@@ -914,7 +944,7 @@ void TheoryStrings::checkCodes()
}
}
}
- if (d_im->hasProcessed())
+ if (d_im.hasProcessed())
{
return;
}
@@ -937,9 +967,10 @@ void TheoryStrings::checkCodes()
Node eqn = c1[0].eqNode(c2[0]);
// str.code(x)==-1 V str.code(x)!=str.code(y) V x==y
Node inj_lem = nm->mkNode(kind::OR, eq_no, deq, eqn);
- d_im->sendPhaseRequirement(deq, false);
+ deq = Rewriter::rewrite(deq);
+ d_im.addPendingPhaseRequirement(deq, false);
std::vector<Node> emptyVec;
- d_im->sendInference(emptyVec, inj_lem, Inference::CODE_INJ);
+ d_im.sendInference(emptyVec, inj_lem, Inference::CODE_INJ);
}
}
}
@@ -948,10 +979,10 @@ void TheoryStrings::checkCodes()
void TheoryStrings::checkRegisterTermsNormalForms()
{
- const std::vector<Node>& seqc = d_bsolver->getStringEqc();
+ const std::vector<Node>& seqc = d_bsolver.getStringEqc();
for (const Node& eqc : seqc)
{
- NormalForm& nfi = d_csolver->getNormalForm(eqc);
+ NormalForm& nfi = d_csolver.getNormalForm(eqc);
// check if there is a length term for this equivalence class
EqcInfo* ei = d_state.getOrMakeEqcInfo(eqc, false);
Node lt = ei ? ei->d_lengthTerm : Node::null();
@@ -982,7 +1013,7 @@ TrustNode TheoryStrings::ppRewrite(TNode atom)
if( !options::stringLazyPreproc() ){
//eager preprocess here
std::vector< Node > new_nodes;
- StringsPreprocess* p = d_esolver->getPreprocess();
+ StringsPreprocess* p = d_esolver.getPreprocess();
Node ret = p->processAssertion(atomRet, new_nodes);
if (ret != atomRet)
{
@@ -1018,25 +1049,25 @@ void TheoryStrings::runInferStep(InferStep s, int effort)
Trace("strings-process") << "..." << std::endl;
switch (s)
{
- case CHECK_INIT: d_bsolver->checkInit(); break;
- case CHECK_CONST_EQC: d_bsolver->checkConstantEquivalenceClasses(); break;
- case CHECK_EXTF_EVAL: d_esolver->checkExtfEval(effort); break;
- case CHECK_CYCLES: d_csolver->checkCycles(); break;
- case CHECK_FLAT_FORMS: d_csolver->checkFlatForms(); break;
+ case CHECK_INIT: d_bsolver.checkInit(); break;
+ case CHECK_CONST_EQC: d_bsolver.checkConstantEquivalenceClasses(); break;
+ case CHECK_EXTF_EVAL: d_esolver.checkExtfEval(effort); break;
+ case CHECK_CYCLES: d_csolver.checkCycles(); break;
+ case CHECK_FLAT_FORMS: d_csolver.checkFlatForms(); break;
case CHECK_REGISTER_TERMS_PRE_NF: checkRegisterTermsPreNormalForm(); break;
- case CHECK_NORMAL_FORMS_EQ: d_csolver->checkNormalFormsEq(); break;
- case CHECK_NORMAL_FORMS_DEQ: d_csolver->checkNormalFormsDeq(); break;
+ case CHECK_NORMAL_FORMS_EQ: d_csolver.checkNormalFormsEq(); break;
+ case CHECK_NORMAL_FORMS_DEQ: d_csolver.checkNormalFormsDeq(); break;
case CHECK_CODES: checkCodes(); break;
- case CHECK_LENGTH_EQC: d_csolver->checkLengthsEqc(); break;
+ case CHECK_LENGTH_EQC: d_csolver.checkLengthsEqc(); break;
case CHECK_REGISTER_TERMS_NF: checkRegisterTermsNormalForms(); break;
- case CHECK_EXTF_REDUCTION: d_esolver->checkExtfReductions(effort); break;
- case CHECK_MEMBERSHIP: d_rsolver->checkMemberships(); break;
- case CHECK_CARDINALITY: d_bsolver->checkCardinality(); break;
+ case CHECK_EXTF_REDUCTION: d_esolver.checkExtfReductions(effort); break;
+ case CHECK_MEMBERSHIP: d_rsolver.checkMemberships(); break;
+ case CHECK_CARDINALITY: d_bsolver.checkCardinality(); break;
default: Unreachable(); break;
}
Trace("strings-process") << "Done " << s
- << ", addedFact = " << d_im->hasPendingFact()
- << ", addedLemma = " << d_im->hasPendingLemma()
+ << ", addedFact = " << d_im.hasPendingFact()
+ << ", addedLemma = " << d_im.hasPendingLemma()
<< ", conflict = " << d_state.isInConflict()
<< std::endl;
}
@@ -1053,7 +1084,7 @@ void TheoryStrings::runStrategy(Theory::Effort e)
InferStep curr = it->first;
if (curr == BREAK)
{
- if (d_im->hasProcessed())
+ if (d_im.hasProcessed())
{
break;
}
diff --git a/src/theory/strings/theory_strings.h b/src/theory/strings/theory_strings.h
index dfaa99c06..13b5a5eba 100644
--- a/src/theory/strings/theory_strings.h
+++ b/src/theory/strings/theory_strings.h
@@ -2,10 +2,10 @@
/*! \file theory_strings.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Tianyi Liang, Tim King
+ ** Andrew Reynolds, Tianyi Liang, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,12 +25,14 @@
#include "context/cdhashset.h"
#include "context/cdlist.h"
#include "expr/node_trie.h"
+#include "theory/ext_theory.h"
#include "theory/strings/base_solver.h"
#include "theory/strings/core_solver.h"
#include "theory/strings/extf_solver.h"
#include "theory/strings/infer_info.h"
#include "theory/strings/inference_manager.h"
#include "theory/strings/normal_form.h"
+#include "theory/strings/proof_checker.h"
#include "theory/strings/regexp_elim.h"
#include "theory/strings/regexp_operation.h"
#include "theory/strings/regexp_solver.h"
@@ -68,80 +70,68 @@ class TheoryStrings : public Theory {
const LogicInfo& logicInfo,
ProofNodeManager* pnm);
~TheoryStrings();
+ //--------------------------------- initialization
+ /** get the official theory rewriter of this theory */
+ TheoryRewriter* getTheoryRewriter() override;
+ /**
+ * Returns true if we need an equality engine. If so, we initialize the
+ * information regarding how it should be setup. For details, see the
+ * documentation in Theory::needsEqualityEngine.
+ */
+ bool needsEqualityEngine(EeSetupInfo& esi) override;
/** finish initialization */
void finishInit() override;
- /** Get the theory rewriter of this class */
- TheoryRewriter* getTheoryRewriter() override;
- /** Set the master equality engine */
- void setMasterEqualityEngine(eq::EqualityEngine* eq) override;
+ //--------------------------------- end initialization
/** Identify this theory */
std::string identify() const override;
- /** Propagate */
- void propagate(Effort e) override;
/** Explain */
TrustNode explain(TNode literal) override;
- /** Get the equality engine */
- eq::EqualityEngine* getEqualityEngine() override;
- /** Get current substitution */
- bool getCurrentSubstitution(int effort,
- std::vector<Node>& vars,
- std::vector<Node>& subs,
- std::map<Node, std::vector<Node> >& exp) override;
/** presolve */
void presolve() override;
/** shutdown */
void shutdown() override {}
/** add shared term */
- void addSharedTerm(TNode n) override;
- /** get equality status */
- EqualityStatus getEqualityStatus(TNode a, TNode b) override;
+ void notifySharedTerm(TNode n) override;
/** preregister term */
void preRegisterTerm(TNode n) override;
/** Expand definition */
TrustNode expandDefinition(Node n) override;
- /** Check at effort e */
- void check(Effort e) override;
- /** needs check last effort */
+ //--------------------------------- standard check
+ /** Do we need a check call at last call effort? */
bool needsCheckLastEffort() override;
+ bool preNotifyFact(TNode atom,
+ bool pol,
+ TNode fact,
+ bool isPrereg,
+ bool isInternal) override;
+ void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal) override;
+ /** Post-check, called after the fact queue of the theory is processed. */
+ void postCheck(Effort level) override;
+ //--------------------------------- end standard check
+ /** propagate method */
+ bool propagateLit(TNode literal);
/** Conflict when merging two constants */
void conflict(TNode a, TNode b);
/** called when a new equivalence class is created */
void eqNotifyNewClass(TNode t);
/** preprocess rewrite */
TrustNode ppRewrite(TNode atom) override;
- /**
- * Get all relevant information in this theory regarding the current
- * model. Return false if a contradiction is discovered.
- */
- bool collectModelInfo(TheoryModel* m) override;
+ /** Collect model values in m based on the relevant terms given by termSet */
+ bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet) override;
private:
/** NotifyClass for equality engine */
class NotifyClass : public eq::EqualityEngineNotify {
public:
NotifyClass(TheoryStrings& ts) : d_str(ts), d_state(ts.d_state) {}
- bool eqNotifyTriggerEquality(TNode equality, bool value) override
- {
- 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) override
{
Debug("strings") << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", " << (value ? "true" : "false") << ")" << std::endl;
if (value) {
- return d_str.propagate(predicate);
- } else {
- return d_str.propagate(predicate.notNode());
+ return d_str.propagateLit(predicate);
}
+ return d_str.propagateLit(predicate.notNode());
}
bool eqNotifyTriggerTermEquality(TheoryId tag,
TNode t1,
@@ -150,10 +140,9 @@ class TheoryStrings : public Theory {
{
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());
+ return d_str.propagateLit(t1.eqNode(t2));
}
+ return d_str.propagateLit(t1.eqNode(t2).notNode());
}
void eqNotifyConstantTermMerge(TNode t1, TNode t2) override
{
@@ -165,14 +154,11 @@ class TheoryStrings : public Theory {
Debug("strings") << "NotifyClass::eqNotifyNewClass(" << t << std::endl;
d_str.eqNotifyNewClass(t);
}
- void eqNotifyPreMerge(TNode t1, TNode t2) override
+ void eqNotifyMerge(TNode t1, TNode t2) override
{
- Debug("strings") << "NotifyClass::eqNotifyPreMerge(" << t1 << ", " << t2 << std::endl;
- d_state.eqNotifyPreMerge(t1, t2);
- }
- void eqNotifyPostMerge(TNode t1, TNode t2) override
- {
- Debug("strings") << "NotifyClass::eqNotifyPostMerge(" << t1 << ", " << t2 << std::endl;
+ Debug("strings") << "NotifyClass::eqNotifyMerge(" << t1 << ", " << t2
+ << std::endl;
+ d_state.eqNotifyMerge(t1, t2);
}
void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override
{
@@ -186,8 +172,6 @@ class TheoryStrings : public Theory {
/** The solver state of the theory of strings */
SolverState& d_state;
};/* class TheoryStrings::NotifyClass */
- /** propagate method */
- bool propagate(TNode literal);
/** compute care graph */
void computeCareGraph() override;
/**
@@ -269,33 +253,37 @@ class TheoryStrings : public Theory {
* theories is collected in this object.
*/
SequencesStatistics d_statistics;
- /** Equaltity engine */
- eq::EqualityEngine d_equalityEngine;
/** The solver state object */
SolverState d_state;
/** The term registry for this theory */
TermRegistry d_termReg;
+ /** The extended theory callback */
+ StringsExtfCallback d_extTheoryCb;
+ /** Extended theory, responsible for context-dependent simplification. */
+ ExtTheory d_extTheory;
/** The (custom) output channel of the theory of strings */
- std::unique_ptr<InferenceManager> d_im;
+ InferenceManager d_im;
/** The theory rewriter for this theory. */
StringsRewriter d_rewriter;
+ /** The proof rule checker */
+ StringProofRuleChecker d_sProofChecker;
/**
* The base solver, responsible for reasoning about congruent terms and
* inferring constants for equivalence classes.
*/
- std::unique_ptr<BaseSolver> d_bsolver;
+ BaseSolver d_bsolver;
/**
* The core solver, responsible for reasoning about string concatenation
* with length constraints.
*/
- std::unique_ptr<CoreSolver> d_csolver;
+ CoreSolver d_csolver;
/**
* Extended function solver, responsible for reductions and simplifications
* involving extended string functions.
*/
- std::unique_ptr<ExtfSolver> d_esolver;
+ ExtfSolver d_esolver;
/** regular expression solver module */
- std::unique_ptr<RegExpSolver> d_rsolver;
+ RegExpSolver d_rsolver;
/** regular expression elimination module */
RegExpElimination d_regexp_elim;
/** Strings finite model finding decision strategy */
diff --git a/src/theory/strings/theory_strings_preprocess.cpp b/src/theory/strings/theory_strings_preprocess.cpp
index a752958b2..81ec79327 100644
--- a/src/theory/strings/theory_strings_preprocess.cpp
+++ b/src/theory/strings/theory_strings_preprocess.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,12 +16,12 @@
#include "theory/strings/theory_strings_preprocess.h"
-#include <stdint.h>
-
#include "expr/kind.h"
+#include "options/smt_options.h"
#include "options/strings_options.h"
#include "proof/proof_manager.h"
#include "smt/logic_exception.h"
+#include "theory/quantifiers/quantifiers_attributes.h"
#include "theory/strings/arith_entail.h"
#include "theory/strings/sequences_rewriter.h"
#include "theory/strings/word.h"
@@ -33,6 +33,13 @@ namespace CVC4 {
namespace theory {
namespace strings {
+/** Mapping to a dummy node for marking an attribute on internal quantified
+ * formulas */
+struct QInternalVarAttributeId
+{
+};
+typedef expr::Attribute<QInternalVarAttributeId, Node> QInternalVarAttribute;
+
StringsPreprocess::StringsPreprocess(SkolemCache* sc,
context::UserContext* u,
SequencesStatistics& stats)
@@ -294,7 +301,7 @@ Node StringsPreprocess::reduce(Node t,
Node ux1lem = nm->mkNode(GEQ, n, ux1);
lem = nm->mkNode(OR, g.negate(), nm->mkNode(AND, eq, cb, ux1lem));
- lem = nm->mkNode(FORALL, xbv, lem);
+ lem = mkForallInternal(xbv, lem);
conc.push_back(lem);
Node nonneg = nm->mkNode(GEQ, n, zero);
@@ -381,7 +388,7 @@ Node StringsPreprocess::reduce(Node t,
Node ux1lem = nm->mkNode(GEQ, stoit, ux1);
lem = nm->mkNode(OR, g.negate(), nm->mkNode(AND, eq, cb, ux1lem));
- lem = nm->mkNode(FORALL, xbv, lem);
+ lem = mkForallInternal(xbv, lem);
conc2.push_back(lem);
Node sneg = nm->mkNode(LT, stoit, zero);
@@ -409,6 +416,55 @@ Node StringsPreprocess::reduce(Node t,
retNode = stoit;
}
+ else if (t.getKind() == kind::SEQ_NTH)
+ {
+ // processing term: str.nth( s, n)
+ // similar to substr.
+ Node s = t[0];
+ Node n = t[1];
+ Node skt = sc->mkSkolemCached(t, SkolemCache::SK_PURIFY, "sst");
+ Node t12 = nm->mkNode(PLUS, n, one);
+ Node lt0 = nm->mkNode(STRING_LENGTH, s);
+ // start point is greater than or equal zero
+ Node c1 = nm->mkNode(GEQ, n, zero);
+ // start point is less than end of string
+ Node c2 = nm->mkNode(GT, lt0, n);
+ // check whether this application of seq.nth is defined.
+ Node cond = nm->mkNode(AND, c1, c2);
+
+ // nodes for the case where `seq.nth` is defined.
+ Node sk1 = sc->mkSkolemCached(s, n, SkolemCache::SK_PREFIX, "sspre");
+ Node sk2 = sc->mkSkolemCached(s, t12, SkolemCache::SK_SUFFIX_REM, "sssufr");
+ Node unit = nm->mkNode(SEQ_UNIT, skt);
+ Node b11 = s.eqNode(nm->mkNode(STRING_CONCAT, sk1, unit, sk2));
+ // length of first skolem is second argument
+ Node b12 = nm->mkNode(STRING_LENGTH, sk1).eqNode(n);
+ Node lsk2 = nm->mkNode(STRING_LENGTH, sk2);
+ Node b13 = nm->mkNode(EQUAL, lsk2, nm->mkNode(MINUS, lt0, t12));
+ Node b1 = nm->mkNode(AND, b11, b12, b13);
+
+ // nodes for the case where `seq.nth` is undefined.
+ std::vector<TypeNode> argTypes;
+ argTypes.push_back(s.getType());
+ argTypes.push_back(nm->integerType());
+ TypeNode elemType = s.getType().getSequenceElementType();
+ TypeNode ufType = nm->mkFunctionType(argTypes, elemType);
+ Node uf = sc->mkTypedSkolemCached(
+ ufType, Node::null(), Node::null(), SkolemCache::SK_NTH, "Uf");
+ Node b2 = nm->mkNode(EQUAL, skt, nm->mkNode(APPLY_UF, uf, s, n));
+
+ // the full ite, split on definedness of `seq.nth`
+ Node lemma = nm->mkNode(ITE, cond, b1, b2);
+
+ // assert:
+ // IF n >=0 AND n < len( s )
+ // THEN: s = sk1 ++ unit(skt) ++ sk2 AND
+ // len( sk1 ) = n AND
+ // ( len( sk2 ) = len( s )- (n+1)
+ // ELSE: skt = Uf(s, n), where Uf is a cached skolem function.
+ asserts.push_back(lemma);
+ retNode = skt;
+ }
else if (t.getKind() == kind::STRING_STRREPL)
{
// processing term: replace( x, y, z )
@@ -518,8 +574,8 @@ Node StringsPreprocess::reduce(Node t,
flem.push_back(
ufip1.eqNode(nm->mkNode(PLUS, ii, nm->mkNode(STRING_LENGTH, y))));
- Node q = nm->mkNode(
- FORALL, bvli, nm->mkNode(OR, bound.negate(), nm->mkNode(AND, flem)));
+ Node body = nm->mkNode(OR, bound.negate(), nm->mkNode(AND, flem));
+ Node q = mkForallInternal(bvli, body);
lem.push_back(q);
// assert:
@@ -688,8 +744,8 @@ Node StringsPreprocess::reduce(Node t,
.eqNode(nm->mkNode(
STRING_CONCAT, pfxMatch, z, nm->mkNode(APPLY_UF, us, ip1))));
- Node forall = nm->mkNode(
- FORALL, bvli, nm->mkNode(OR, bound.negate(), nm->mkNode(AND, flem)));
+ Node body = nm->mkNode(OR, bound.negate(), nm->mkNode(AND, flem));
+ Node forall = mkForallInternal(bvli, body);
lemmas.push_back(forall);
// IF in_re(x, re.++(_*, y', _*))
@@ -744,8 +800,8 @@ Node StringsPreprocess::reduce(Node t,
Node bound =
nm->mkNode(AND, nm->mkNode(LEQ, zero, i), nm->mkNode(LT, i, lenr));
- Node rangeA =
- nm->mkNode(FORALL, bvi, nm->mkNode(OR, bound.negate(), ri.eqNode(res)));
+ Node body = nm->mkNode(OR, bound.negate(), ri.eqNode(res));
+ Node rangeA = mkForallInternal(bvi, body);
// upper 65 ... 90
// lower 97 ... 122
@@ -779,8 +835,8 @@ Node StringsPreprocess::reduce(Node t,
Node bound =
nm->mkNode(AND, nm->mkNode(LEQ, zero, i), nm->mkNode(LT, i, lenr));
- Node rangeA = nm->mkNode(
- FORALL, bvi, nm->mkNode(OR, bound.negate(), ssr.eqNode(ssx)));
+ Node body = nm->mkNode(OR, bound.negate(), ssr.eqNode(ssx));
+ Node rangeA = mkForallInternal(bvi, body);
// assert:
// len(r) = len(x) ^
// forall i. 0 <= i < len(r) =>
@@ -817,7 +873,7 @@ Node StringsPreprocess::reduce(Node t,
{
Node ltp = sc->mkTypedSkolemCached(
nm->booleanType(), t, SkolemCache::SK_PURIFY, "ltp");
- Node k = nm->mkSkolem("k", nm->integerType());
+ Node k = SkolemCache::mkIndexVar(t);
std::vector<Node> conj;
conj.push_back(nm->mkNode(GEQ, k, zero));
@@ -841,6 +897,8 @@ Node StringsPreprocess::reduce(Node t,
}
conj.push_back(nm->mkNode(ITE, ite_ch));
+ Node conjn = nm->mkNode(
+ EXISTS, nm->mkNode(BOUND_VAR_LIST, k), nm->mkNode(AND, conj));
// Intuitively, the reduction says either x and y are equal, or they have
// some (maximal) common prefix after which their characters at position k
// are distinct, and the comparison of their code matches the return value
@@ -854,13 +912,13 @@ Node StringsPreprocess::reduce(Node t,
// assert:
// IF x=y
// THEN: ltp
- // ELSE: k >= 0 AND k <= len( x ) AND k <= len( y ) AND
+ // ELSE: exists k.
+ // k >= 0 AND k <= len( x ) AND k <= len( y ) AND
// substr( x, 0, k ) = substr( y, 0, k ) AND
// IF ltp
// THEN: str.code(substr( x, k, 1 )) < str.code(substr( y, k, 1 ))
// ELSE: str.code(substr( x, k, 1 )) > str.code(substr( y, k, 1 ))
- Node assert =
- nm->mkNode(ITE, t[0].eqNode(t[1]), ltp, nm->mkNode(AND, conj));
+ Node assert = nm->mkNode(ITE, t[0].eqNode(t[1]), ltp, conjn);
asserts.push_back(assert);
// Thus, str.<=( x, y ) = ltp
@@ -972,12 +1030,39 @@ void StringsPreprocess::processAssertions( std::vector< Node > &vec_node ){
: NodeManager::currentNM()->mkNode(kind::AND, asserts);
if( res!=vec_node[i] ){
res = Rewriter::rewrite( res );
- PROOF( ProofManager::currentPM()->addDependence( res, vec_node[i] ); );
+ if (options::unsatCores())
+ {
+ ProofManager::currentPM()->addDependence(res, vec_node[i]);
+ }
vec_node[i] = res;
}
}
}
+Node StringsPreprocess::mkForallInternal(Node bvl, Node body)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ QInternalVarAttribute qiva;
+ Node qvar;
+ if (bvl.hasAttribute(qiva))
+ {
+ qvar = bvl.getAttribute(qiva);
+ }
+ else
+ {
+ qvar = nm->mkSkolem("qinternal", nm->booleanType());
+ // this dummy variable marks that the quantified formula is internal
+ qvar.setAttribute(InternalQuantAttribute(), true);
+ // remember the dummy variable
+ bvl.setAttribute(qiva, qvar);
+ }
+ // make the internal attribute, and put it in a singleton list
+ Node ip = nm->mkNode(INST_ATTRIBUTE, qvar);
+ Node ipl = nm->mkNode(INST_PATTERN_LIST, ip);
+ // make the overall formula
+ return nm->mkNode(FORALL, bvl, body, ipl);
+}
+
}/* 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
index 113d909a8..124a09a4c 100644
--- a/src/theory/strings/theory_strings_preprocess.h
+++ b/src/theory/strings/theory_strings_preprocess.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tianyi Liang, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -100,6 +100,14 @@ class StringsPreprocess {
Node simplifyRec(Node t,
std::vector<Node>& asserts,
std::map<Node, Node>& visited);
+ /**
+ * Make internal quantified formula with bound variable list bvl and body.
+ * Internally, we get a node corresponding to marking a quantified formula as
+ * an "internal" one. This node is provided as the third argument of the
+ * FORALL returned by this method. This ensures that E-matching is not applied
+ * to the quantified formula.
+ */
+ static Node mkForallInternal(Node bvl, Node body);
};
}/* CVC4::theory::strings namespace */
diff --git a/src/theory/strings/theory_strings_type_rules.h b/src/theory/strings/theory_strings_type_rules.h
index 12ddb8a3d..cbf8fb1e0 100644
--- a/src/theory/strings/theory_strings_type_rules.h
+++ b/src/theory/strings/theory_strings_type_rules.h
@@ -2,10 +2,10 @@
/*! \file theory_strings_type_rules.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Tianyi Liang, Mathias Preiner
+ ** Andrew Reynolds, Tianyi Liang, Yoni Zohar
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -376,6 +376,30 @@ class SeqUnitTypeRule
}
};
+class SeqNthTypeRule
+{
+ public:
+ static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ {
+ TypeNode t = n[0].getType(check);
+ TypeNode t1 = t.getSequenceElementType();
+ if (check)
+ {
+ if (!t.isSequence())
+ {
+ throw TypeCheckingExceptionPrivate(n, "expecting a sequence in nth");
+ }
+ TypeNode t2 = n[1].getType(check);
+ if (!t2.isInteger())
+ {
+ throw TypeCheckingExceptionPrivate(
+ n, "expecting an integer start term in nth");
+ }
+ }
+ return t1;
+ }
+};
+
/** Properties of the sequence type */
struct SequenceProperties
{
diff --git a/src/theory/strings/theory_strings_utils.cpp b/src/theory/strings/theory_strings_utils.cpp
index 3cf14fead..286c0dc04 100644
--- a/src/theory/strings/theory_strings_utils.cpp
+++ b/src/theory/strings/theory_strings_utils.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -382,7 +382,7 @@ TypeNode getOwnerStringType(Node n)
TypeNode tn;
Kind k = n.getKind();
if (k == STRING_STRIDOF || k == STRING_LENGTH || k == STRING_STRCTN
- || k == STRING_PREFIX || k == STRING_SUFFIX)
+ || k == SEQ_NTH || k == STRING_PREFIX || k == STRING_SUFFIX)
{
// owning string type is the type of first argument
tn = n[0].getType();
diff --git a/src/theory/strings/theory_strings_utils.h b/src/theory/strings/theory_strings_utils.h
index 803a5ffea..6833d265b 100644
--- a/src/theory/strings/theory_strings_utils.h
+++ b/src/theory/strings/theory_strings_utils.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/type_enumerator.cpp b/src/theory/strings/type_enumerator.cpp
index ae88f63f7..2412f9217 100644
--- a/src/theory/strings/type_enumerator.cpp
+++ b/src/theory/strings/type_enumerator.cpp
@@ -2,10 +2,10 @@
/*! \file type_enumerator.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Mathias Preiner, Tim King
+ ** Andrew Reynolds, Mathias Preiner, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/type_enumerator.h b/src/theory/strings/type_enumerator.h
index 602d73059..91cb0502f 100644
--- a/src/theory/strings/type_enumerator.h
+++ b/src/theory/strings/type_enumerator.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tianyi Liang, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/word.cpp b/src/theory/strings/word.cpp
index 63e3f1dba..944a088ed 100644
--- a/src/theory/strings/word.cpp
+++ b/src/theory/strings/word.cpp
@@ -2,10 +2,10 @@
/*! \file word.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds
+ ** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/strings/word.h b/src/theory/strings/word.h
index bace06bfb..2343dc583 100644
--- a/src/theory/strings/word.h
+++ b/src/theory/strings/word.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/subs_minimize.cpp b/src/theory/subs_minimize.cpp
index fdf3c3cc8..c230c578c 100644
--- a/src/theory/subs_minimize.cpp
+++ b/src/theory/subs_minimize.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/subs_minimize.h b/src/theory/subs_minimize.h
index c2b847f15..5587806e1 100644
--- a/src/theory/subs_minimize.h
+++ b/src/theory/subs_minimize.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/substitutions.cpp b/src/theory/substitutions.cpp
index 671cf9b99..664fcd1b3 100644
--- a/src/theory/substitutions.cpp
+++ b/src/theory/substitutions.cpp
@@ -5,7 +5,7 @@
** Dejan Jovanovic, Clark Barrett, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -147,36 +147,6 @@ Node SubstitutionMap::internalSubstitute(TNode t, NodeCache& cache) {
}/* SubstitutionMap::internalSubstitute() */
-void SubstitutionMap::simplifyRHS(const SubstitutionMap& subMap)
-{
- // Put the new substitutions into the old ones
- NodeMap::iterator it = d_substitutions.begin();
- NodeMap::iterator it_end = d_substitutions.end();
- for(; it != it_end; ++ it) {
- d_substitutions[(*it).first] = subMap.apply((*it).second);
- }
-}
-
-
-void SubstitutionMap::simplifyRHS(TNode x, TNode t) {
- // Temporary substitution cache
- NodeCache tempCache;
- tempCache[x] = t;
-
- // Put the new substitution into the old ones
- NodeMap::iterator it = d_substitutions.begin();
- NodeMap::iterator it_end = d_substitutions.end();
- for(; it != it_end; ++ it) {
- d_substitutions[(*it).first] = internalSubstitute((*it).second, tempCache);
- }
- // it = d_substitutionsLazy.begin();
- // it_end = d_substitutionsLazy.end();
- // for(; it != it_end; ++ it) {
- // d_substitutionsLazy[(*it).first] = internalSubstitute((*it).second, tempCache);
- // }
-}
-
-
void SubstitutionMap::addSubstitution(TNode x, TNode t, bool invalidateCache)
{
Debug("substitution") << "SubstitutionMap::addSubstitution(" << x << ", " << t << ")" << endl;
@@ -214,26 +184,6 @@ void SubstitutionMap::addSubstitutions(SubstitutionMap& subMap, bool invalidateC
}
}
-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();
- SubstitutionMap::NodeMap::const_iterator it_end = substitutions.end();
- Debug("substitution") << "checking " << node << endl;
- for (; it != it_end; ++it)
- {
- Debug("substitution") << "-- hasSubterm( " << (*it).first << " ) ?" << endl;
- if (expr::hasSubterm(node, (*it).first))
- {
- Debug("substitution") << "-- FAIL" << endl;
- return false;
- }
- }
- Debug("substitution") << "-- SUCCEED" << endl;
- return true;
-}
-
Node SubstitutionMap::apply(TNode t) {
Debug("substitution") << "SubstitutionMap::apply(" << t << ")" << endl;
@@ -249,8 +199,6 @@ Node SubstitutionMap::apply(TNode t) {
Node result = internalSubstitute(t, d_substitutionCache);
Debug("substitution") << "SubstitutionMap::apply(" << t << ") => " << result << endl;
- // Assert(check(result, d_substitutions));
-
return result;
}
diff --git a/src/theory/substitutions.h b/src/theory/substitutions.h
index bb59069dd..66dcd81a0 100644
--- a/src/theory/substitutions.h
+++ b/src/theory/substitutions.h
@@ -5,7 +5,7 @@
** Morgan Deters, Dejan Jovanovic, Clark Barrett
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -66,9 +66,6 @@ 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, NodeCache& cache);
@@ -93,15 +90,14 @@ private:
CacheInvalidator d_cacheInvalidator;
public:
-
- SubstitutionMap(context::Context* context, bool substituteUnderQuantifiers = true, bool solvedForm = false) :
- d_substitutions(context),
- d_substitutionCache(),
- d_substituteUnderQuantifiers(substituteUnderQuantifiers),
- d_cacheInvalidated(false),
- d_solvedForm(solvedForm),
- d_cacheInvalidator(context, d_cacheInvalidated)
- {
+ SubstitutionMap(context::Context* context,
+ bool substituteUnderQuantifiers = true)
+ : d_substitutions(context),
+ d_substitutionCache(),
+ d_substituteUnderQuantifiers(substituteUnderQuantifiers),
+ d_cacheInvalidated(false),
+ d_cacheInvalidator(context, d_cacheInvalidated)
+ {
}
/**
@@ -166,20 +162,6 @@ public:
return d_substitutions.empty();
}
- // NOTE [MGD]: removed clear() and swap() from the interface
- // when this data structure became context-dependent
- // because they weren't used---and it's not clear how they
- // 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);
-
- 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 bf7cab4e3..471a94e25 100644
--- a/src/theory/term_registration_visitor.cpp
+++ b/src/theory/term_registration_visitor.cpp
@@ -2,10 +2,10 @@
/*! \file term_registration_visitor.cpp
** \verbatim
** Top contributors (to current version):
- ** Dejan Jovanovic, Andrew Reynolds, Morgan Deters
+ ** Andrew Reynolds, Dejan Jovanovic, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -26,7 +26,8 @@ std::string PreRegisterVisitor::toString() const {
std::stringstream ss;
TNodeToTheorySetMap::const_iterator it = d_visited.begin();
for (; it != d_visited.end(); ++ it) {
- ss << (*it).first << ": " << Theory::setToString((*it).second) << std::endl;
+ ss << (*it).first << ": " << TheoryIdSetUtil::setToString((*it).second)
+ << std::endl;
}
return ss.str();
}
@@ -50,8 +51,8 @@ bool PreRegisterVisitor::alreadyVisited(TNode current, TNode parent) {
TheoryId currentTheoryId = Theory::theoryOf(current);
TheoryId parentTheoryId = Theory::theoryOf(parent);
- d_theories = Theory::setInsert(currentTheoryId, d_theories);
- d_theories = Theory::setInsert(parentTheoryId, d_theories);
+ d_theories = TheoryIdSetUtil::setInsert(currentTheoryId, d_theories);
+ d_theories = TheoryIdSetUtil::setInsert(parentTheoryId, d_theories);
// Should we use the theory of the type
bool useType = false;
@@ -78,19 +79,21 @@ bool PreRegisterVisitor::alreadyVisited(TNode current, TNode parent) {
TNodeToTheorySetMap::iterator find = d_visited.find(current);
if (find == d_visited.end()) {
if (useType) {
- d_theories = Theory::setInsert(typeTheoryId, d_theories);
+ d_theories = TheoryIdSetUtil::setInsert(typeTheoryId, d_theories);
}
return false;
}
- Theory::Set visitedTheories = (*find).second;
- if (Theory::setContains(currentTheoryId, visitedTheories)) {
+ TheoryIdSet visitedTheories = (*find).second;
+ if (TheoryIdSetUtil::setContains(currentTheoryId, visitedTheories))
+ {
// The current theory has already visited it, so now it depends on the parent and the type
- if (Theory::setContains(parentTheoryId, visitedTheories)) {
+ if (TheoryIdSetUtil::setContains(parentTheoryId, visitedTheories))
+ {
if (useType) {
TheoryId typeTheoryId2 = Theory::theoryOf(current.getType());
- d_theories = Theory::setInsert(typeTheoryId2, d_theories);
- return Theory::setContains(typeTheoryId2, visitedTheories);
+ d_theories = TheoryIdSetUtil::setInsert(typeTheoryId2, d_theories);
+ return TheoryIdSetUtil::setContains(typeTheoryId2, visitedTheories);
} else {
return true;
}
@@ -133,33 +136,45 @@ void PreRegisterVisitor::visit(TNode current, TNode parent) {
}
}
}
-
- Theory::Set visitedTheories = d_visited[current];
- Debug("register::internal") << "PreRegisterVisitor::visit(" << current << "," << parent << "): previously registered with " << Theory::setToString(visitedTheories) << std::endl;
- if (!Theory::setContains(currentTheoryId, visitedTheories)) {
- visitedTheories = Theory::setInsert(currentTheoryId, visitedTheories);
+
+ TheoryIdSet visitedTheories = d_visited[current];
+ Debug("register::internal")
+ << "PreRegisterVisitor::visit(" << current << "," << parent
+ << "): previously registered with "
+ << TheoryIdSetUtil::setToString(visitedTheories) << std::endl;
+ if (!TheoryIdSetUtil::setContains(currentTheoryId, visitedTheories))
+ {
+ visitedTheories =
+ TheoryIdSetUtil::setInsert(currentTheoryId, visitedTheories);
d_visited[current] = visitedTheories;
Theory* th = d_engine->theoryOf(currentTheoryId);
th->preRegisterTerm(current);
Debug("register::internal") << "PreRegisterVisitor::visit(" << current << "," << parent << "): adding " << currentTheoryId << std::endl;
}
- if (!Theory::setContains(parentTheoryId, visitedTheories)) {
- visitedTheories = Theory::setInsert(parentTheoryId, visitedTheories);
+ if (!TheoryIdSetUtil::setContains(parentTheoryId, visitedTheories))
+ {
+ visitedTheories =
+ TheoryIdSetUtil::setInsert(parentTheoryId, visitedTheories);
d_visited[current] = visitedTheories;
Theory* th = d_engine->theoryOf(parentTheoryId);
th->preRegisterTerm(current);
Debug("register::internal") << "PreRegisterVisitor::visit(" << current << "," << parent << "): adding " << parentTheoryId << std::endl;
}
if (useType) {
- if (!Theory::setContains(typeTheoryId, visitedTheories)) {
- visitedTheories = Theory::setInsert(typeTheoryId, visitedTheories);
+ if (!TheoryIdSetUtil::setContains(typeTheoryId, visitedTheories))
+ {
+ visitedTheories =
+ TheoryIdSetUtil::setInsert(typeTheoryId, visitedTheories);
d_visited[current] = visitedTheories;
Theory* th = d_engine->theoryOf(typeTheoryId);
th->preRegisterTerm(current);
Debug("register::internal") << "PreRegisterVisitor::visit(" << current << "," << parent << "): adding " << parentTheoryId << std::endl;
}
}
- Debug("register::internal") << "PreRegisterVisitor::visit(" << current << "," << parent << "): now registered with " << Theory::setToString(visitedTheories) << std::endl;
+ Debug("register::internal")
+ << "PreRegisterVisitor::visit(" << current << "," << parent
+ << "): now registered with "
+ << TheoryIdSetUtil::setToString(visitedTheories) << std::endl;
Assert(d_visited.find(current) != d_visited.end());
Assert(alreadyVisited(current, parent));
@@ -169,7 +184,8 @@ std::string SharedTermsVisitor::toString() const {
std::stringstream ss;
TNodeVisitedMap::const_iterator it = d_visited.begin();
for (; it != d_visited.end(); ++ it) {
- ss << (*it).first << ": " << Theory::setToString((*it).second) << std::endl;
+ ss << (*it).first << ": " << TheoryIdSetUtil::setToString((*it).second)
+ << std::endl;
}
return ss.str();
}
@@ -197,7 +213,7 @@ bool SharedTermsVisitor::alreadyVisited(TNode current, TNode parent) const {
return false;
}
- Theory::Set theories = (*find).second;
+ TheoryIdSet theories = (*find).second;
TheoryId currentTheoryId = Theory::theoryOf(current);
TheoryId parentTheoryId = Theory::theoryOf(parent);
@@ -239,16 +255,23 @@ bool SharedTermsVisitor::alreadyVisited(TNode current, TNode parent) const {
}
}
- if (Theory::setContains(currentTheoryId, theories)) {
- if (Theory::setContains(parentTheoryId, theories)) {
- if (useType) {
- return Theory::setContains(typeTheoryId, theories);
- } else {
- return true;
- }
- } else {
- return false;
+ if (TheoryIdSetUtil::setContains(currentTheoryId, theories))
+ {
+ if (TheoryIdSetUtil::setContains(parentTheoryId, theories))
+ {
+ if (useType)
+ {
+ return TheoryIdSetUtil::setContains(typeTheoryId, theories);
}
+ else
+ {
+ return true;
+ }
+ }
+ else
+ {
+ return false;
+ }
} else {
return false;
}
@@ -286,29 +309,43 @@ void SharedTermsVisitor::visit(TNode current, TNode parent) {
}
}
- Theory::Set visitedTheories = d_visited[current];
- Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): previously registered with " << Theory::setToString(visitedTheories) << std::endl;
- if (!Theory::setContains(currentTheoryId, visitedTheories)) {
- visitedTheories = Theory::setInsert(currentTheoryId, visitedTheories);
+ TheoryIdSet visitedTheories = d_visited[current];
+ Debug("register::internal")
+ << "SharedTermsVisitor::visit(" << current << "," << parent
+ << "): previously registered with "
+ << TheoryIdSetUtil::setToString(visitedTheories) << std::endl;
+ if (!TheoryIdSetUtil::setContains(currentTheoryId, visitedTheories))
+ {
+ visitedTheories =
+ TheoryIdSetUtil::setInsert(currentTheoryId, visitedTheories);
Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): adding " << currentTheoryId << std::endl;
}
- if (!Theory::setContains(parentTheoryId, visitedTheories)) {
- visitedTheories = Theory::setInsert(parentTheoryId, visitedTheories);
+ if (!TheoryIdSetUtil::setContains(parentTheoryId, visitedTheories))
+ {
+ visitedTheories =
+ TheoryIdSetUtil::setInsert(parentTheoryId, visitedTheories);
Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): adding " << parentTheoryId << std::endl;
}
if (useType) {
- if (!Theory::setContains(typeTheoryId, visitedTheories)) {
- visitedTheories = Theory::setInsert(typeTheoryId, visitedTheories);
+ if (!TheoryIdSetUtil::setContains(typeTheoryId, visitedTheories))
+ {
+ visitedTheories =
+ TheoryIdSetUtil::setInsert(typeTheoryId, visitedTheories);
Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): adding " << typeTheoryId << std::endl;
}
}
- Debug("register::internal") << "SharedTermsVisitor::visit(" << current << "," << parent << "): now registered with " << Theory::setToString(visitedTheories) << std::endl;
+ Debug("register::internal")
+ << "SharedTermsVisitor::visit(" << current << "," << parent
+ << "): now registered with "
+ << TheoryIdSetUtil::setToString(visitedTheories) << std::endl;
// Record the new theories that we visited
d_visited[current] = visitedTheories;
// If there is more than two theories and a new one has been added notify the shared terms database
- if (Theory::setDifference(visitedTheories, Theory::setInsert(currentTheoryId))) {
+ if (TheoryIdSetUtil::setDifference(
+ visitedTheories, TheoryIdSetUtil::setInsert(currentTheoryId)))
+ {
d_sharedTerms.addSharedTerm(d_atom, current, visitedTheories);
}
diff --git a/src/theory/term_registration_visitor.h b/src/theory/term_registration_visitor.h
index 6c6696f64..94fc83b30 100644
--- a/src/theory/term_registration_visitor.h
+++ b/src/theory/term_registration_visitor.h
@@ -2,10 +2,10 @@
/*! \file term_registration_visitor.h
** \verbatim
** Top contributors (to current version):
- ** Dejan Jovanovic, Morgan Deters, Tim King
+ ** Dejan Jovanovic, Andrew Reynolds, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -42,7 +42,8 @@ class PreRegisterVisitor {
/** The engine */
TheoryEngine* d_engine;
- typedef context::CDHashMap<TNode, theory::Theory::Set, TNodeHashFunction> TNodeToTheorySetMap;
+ typedef context::CDHashMap<TNode, theory::TheoryIdSet, TNodeHashFunction>
+ TNodeToTheorySetMap;
/**
* Map from terms to the theories that have already had this term pre-registered.
@@ -52,43 +53,43 @@ class PreRegisterVisitor {
/**
* A set of all theories in the term
*/
- theory::Theory::Set d_theories;
+ theory::TheoryIdSet d_theories;
/**
* String representation of the visited map, for debugging purposes.
*/
std::string toString() const;
-public:
-
+ public:
/** Returned set tells us which theories there are */
- typedef theory::Theory::Set return_type;
-
+ typedef theory::TheoryIdSet return_type;
+
PreRegisterVisitor(TheoryEngine* engine, context::Context* context)
- : d_engine(engine)
- , d_visited(context)
- , d_theories(0)
- {}
+ : d_engine(engine), d_visited(context), d_theories(0)
+ {
+ }
/**
- * Returns true is current has already been pre-registered with both current and parent theories.
+ * Returns true is current has already been pre-registered with both current
+ * and parent theories.
*/
bool alreadyVisited(TNode current, TNode parent);
-
+
/**
- * Pre-registeres current with any of the current and parent theories that haven't seen the term yet.
+ * Pre-registeres current with any of the current and parent theories that
+ * haven't seen the term yet.
*/
void visit(TNode current, TNode parent);
-
+
/**
* Marks the node as the starting literal.
*/
- void start(TNode node) { }
+ void start(TNode node) {}
/**
* Notifies the engine of all the theories used.
*/
- theory::Theory::Set done(TNode node) { return d_theories; }
+ theory::TheoryIdSet done(TNode node) { return d_theories; }
};
@@ -105,7 +106,8 @@ class SharedTermsVisitor {
/**
* Cache from preprocessing of atoms.
*/
- typedef std::unordered_map<TNode, theory::Theory::Set, TNodeHashFunction> TNodeVisitedMap;
+ typedef std::unordered_map<TNode, theory::TheoryIdSet, TNodeHashFunction>
+ TNodeVisitedMap;
TNodeVisitedMap d_visited;
/**
diff --git a/src/theory/theory.cpp b/src/theory/theory.cpp
index b0db8ab30..78fe6927f 100644
--- a/src/theory/theory.cpp
+++ b/src/theory/theory.cpp
@@ -2,10 +2,10 @@
/*! \file theory.cpp
** \verbatim
** Top contributors (to current version):
- ** Tim King, Mathias Preiner, Dejan Jovanovic
+ ** Andrew Reynolds, Tim King, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -23,6 +23,7 @@
#include "base/check.h"
#include "expr/node_algorithm.h"
+#include "options/smt_options.h"
#include "options/theory_options.h"
#include "smt/smt_statistics_registry.h"
#include "theory/ext_theory.h"
@@ -44,8 +45,6 @@ std::ostream& operator<<(std::ostream& os, Theory::Effort level){
os << "EFFORT_STANDARD"; break;
case Theory::EFFORT_FULL:
os << "EFFORT_FULL"; break;
- case Theory::EFFORT_COMBINATION:
- os << "EFFORT_COMBINATION"; break;
case Theory::EFFORT_LAST_CALL:
os << "EFFORT_LAST_CALL"; break;
default:
@@ -63,25 +62,27 @@ Theory::Theory(TheoryId id,
ProofNodeManager* pnm,
std::string name)
: d_id(id),
- d_instanceName(name),
d_satContext(satContext),
d_userContext(userContext),
d_logicInfo(logicInfo),
- d_pnm(pnm),
d_facts(satContext),
d_factsHead(satContext, 0),
d_sharedTermsIndex(satContext, 0),
d_careGraph(NULL),
d_quantEngine(NULL),
d_decManager(nullptr),
- d_extTheory(NULL),
+ d_instanceName(name),
d_checkTime(getStatsPrefix(id) + name + "::checkTime"),
d_computeCareGraphTime(getStatsPrefix(id) + name
+ "::computeCareGraphTime"),
d_sharedTerms(satContext),
d_out(&out),
d_valuation(valuation),
- d_proofsEnabled(false)
+ d_equalityEngine(nullptr),
+ d_allocEqualityEngine(nullptr),
+ d_theoryState(nullptr),
+ d_inferManager(nullptr),
+ d_pnm(pnm)
{
smtStatisticsRegistry()->registerStat(&d_checkTime);
smtStatisticsRegistry()->registerStat(&d_computeCareGraphTime);
@@ -90,8 +91,54 @@ Theory::Theory(TheoryId id,
Theory::~Theory() {
smtStatisticsRegistry()->unregisterStat(&d_checkTime);
smtStatisticsRegistry()->unregisterStat(&d_computeCareGraphTime);
+}
+
+bool Theory::needsEqualityEngine(EeSetupInfo& esi)
+{
+ // by default, this theory does not use an (official) equality engine
+ return false;
+}
+
+void Theory::setEqualityEngine(eq::EqualityEngine* ee)
+{
+ // set the equality engine pointer
+ d_equalityEngine = ee;
+ if (d_theoryState != nullptr)
+ {
+ d_theoryState->setEqualityEngine(ee);
+ }
+ if (d_inferManager != nullptr)
+ {
+ d_inferManager->setEqualityEngine(ee);
+ }
+}
+
+void Theory::setQuantifiersEngine(QuantifiersEngine* qe)
+{
+ Assert(d_quantEngine == nullptr);
+ // quantifiers engine may be null if not in quantified logic
+ d_quantEngine = qe;
+}
- delete d_extTheory;
+void Theory::setDecisionManager(DecisionManager* dm)
+{
+ Assert(d_decManager == nullptr);
+ Assert(dm != nullptr);
+ d_decManager = dm;
+}
+
+void Theory::finishInitStandalone()
+{
+ EeSetupInfo esi;
+ if (needsEqualityEngine(esi))
+ {
+ // always associated with the same SAT context as the theory (d_satContext)
+ d_allocEqualityEngine.reset(new eq::EqualityEngine(
+ *esi.d_notify, d_satContext, esi.d_name, esi.d_constantsAreTriggers));
+ // use it as the official equality engine
+ setEqualityEngine(d_allocEqualityEngine.get());
+ }
+ finishInit();
}
TheoryId Theory::theoryOf(options::TheoryOfMode mode, TNode node)
@@ -224,11 +271,9 @@ TheoryId Theory::theoryOf(options::TheoryOfMode mode, TNode node)
return tid;
}
-void Theory::addSharedTermInternal(TNode n) {
- Debug("sharing") << "Theory::addSharedTerm<" << getId() << ">(" << n << ")" << endl;
- Debug("theory::assertions") << "Theory::addSharedTerm<" << getId() << ">(" << n << ")" << endl;
- d_sharedTerms.push_back(n);
- addSharedTerm(n);
+void Theory::notifySharedTerm(TNode n)
+{
+ // do nothing
}
void Theory::computeCareGraph() {
@@ -245,12 +290,12 @@ void Theory::computeCareGraph() {
switch (d_valuation.getEqualityStatus(a, b)) {
case EQUALITY_TRUE_AND_PROPAGATED:
case EQUALITY_FALSE_AND_PROPAGATED:
- // If we know about it, we should have propagated it, so we can skip
- break;
+ // If we know about it, we should have propagated it, so we can skip
+ break;
default:
- // Let's split on it
- addCarePair(a, b);
- break;
+ // Let's split on it
+ addCarePair(a, b);
+ break;
}
}
}
@@ -306,60 +351,34 @@ std::unordered_set<TNode, TNodeHashFunction> Theory::currentlySharedTerms() cons
return currentlyShared;
}
-void Theory::collectTerms(TNode n,
- set<Kind>& irrKinds,
- set<Node>& termSet) const
+bool Theory::collectModelInfo(TheoryModel* m, const std::set<Node>& termSet)
{
- if (termSet.find(n) != termSet.end()) {
- return;
- }
- Kind nk = n.getKind();
- if (irrKinds.find(nk) == irrKinds.end())
- {
- Trace("theory::collectTerms")
- << "Theory::collectTerms: adding " << n << endl;
- termSet.insert(n);
- }
- if (nk == kind::NOT || nk == kind::EQUAL || !isLeaf(n))
+ // if we are using an equality engine, assert it to the model
+ if (d_equalityEngine != nullptr)
{
- for(TNode::iterator child_it = n.begin(); child_it != n.end(); ++child_it) {
- collectTerms(*child_it, irrKinds, termSet);
+ if (!m->assertEqualityEngine(d_equalityEngine, &termSet))
+ {
+ return false;
}
}
+ // now, collect theory-specific value assigments
+ return collectModelValues(m, termSet);
}
-
-void Theory::computeRelevantTerms(set<Node>& termSet, bool includeShared) const
+void Theory::computeRelevantTerms(std::set<Node>& termSet)
{
- set<Kind> irrKinds;
- computeRelevantTerms(termSet, irrKinds, includeShared);
+ // by default, there are no additional relevant terms
}
-void Theory::computeRelevantTerms(set<Node>& termSet,
- set<Kind>& irrKinds,
- bool includeShared) const
+bool Theory::collectModelValues(TheoryModel* m, const std::set<Node>& termSet)
{
- // Collect all terms appearing in assertions
- irrKinds.insert(kind::EQUAL);
- irrKinds.insert(kind::NOT);
- context::CDList<Assertion>::const_iterator assert_it = facts_begin(), assert_it_end = facts_end();
- for (; assert_it != assert_it_end; ++assert_it) {
- collectTerms(*assert_it, irrKinds, termSet);
- }
-
- if (!includeShared) return;
-
- // Add terms that are shared terms
- set<Kind> kempty;
- context::CDList<TNode>::const_iterator shared_it = shared_terms_begin(), shared_it_end = shared_terms_end();
- for (; shared_it != shared_it_end; ++shared_it) {
- collectTerms(*shared_it, kempty, termSet);
- }
+ return true;
}
-Theory::PPAssertStatus Theory::ppAssert(TNode in,
- SubstitutionMap& outSubstitutions)
+Theory::PPAssertStatus Theory::ppAssert(TrustNode tin,
+ TrustSubstitutionMap& outSubstitutions)
{
+ TNode in = tin.getNode();
if (in.getKind() == kind::EQUAL)
{
// (and (= x t) phi) can be replaced by phi[x/t] if
@@ -369,13 +388,13 @@ Theory::PPAssertStatus Theory::ppAssert(TNode in,
if (in[0].isVar() && isLegalElimination(in[0], in[1])
&& in[0].getKind() != kind::BOOLEAN_TERM_VARIABLE)
{
- outSubstitutions.addSubstitution(in[0], in[1]);
+ outSubstitutions.addSubstitutionSolved(in[0], in[1], tin);
return PP_ASSERT_STATUS_SOLVED;
}
if (in[1].isVar() && isLegalElimination(in[1], in[0])
&& in[1].getKind() != kind::BOOLEAN_TERM_VARIABLE)
{
- outSubstitutions.addSubstitution(in[1], in[0]);
+ outSubstitutions.addSubstitutionSolved(in[1], in[0], tin);
return PP_ASSERT_STATUS_SOLVED;
}
if (in[0].isConst() && in[1].isConst())
@@ -395,11 +414,6 @@ std::pair<bool, Node> Theory::entailmentCheck(TNode lit)
return make_pair(false, Node::null());
}
-ExtTheory* Theory::getExtTheory() {
- Assert(d_extTheory != NULL);
- return d_extTheory;
-}
-
void Theory::addCarePair(TNode t1, TNode t2) {
if (d_careGraph) {
d_careGraph->insert(CarePair(t1, t2, d_id));
@@ -416,22 +430,133 @@ void Theory::getCareGraph(CareGraph* careGraph) {
d_careGraph = NULL;
}
-void Theory::setQuantifiersEngine(QuantifiersEngine* qe) {
- Assert(d_quantEngine == NULL);
- Assert(qe != NULL);
- d_quantEngine = qe;
+EqualityStatus Theory::getEqualityStatus(TNode a, TNode b)
+{
+ // if not using an equality engine, then by default we don't know the status
+ if (d_equalityEngine == nullptr)
+ {
+ return EQUALITY_UNKNOWN;
+ }
+ Trace("sharing") << "Theory<" << getId() << ">::getEqualityStatus(" << a << ", " << b << ")" << std::endl;
+ Assert(d_equalityEngine->hasTerm(a) && d_equalityEngine->hasTerm(b));
+
+ // Check for equality (simplest)
+ if (d_equalityEngine->areEqual(a, b))
+ {
+ // The terms are implied to be equal
+ return EQUALITY_TRUE;
+ }
+
+ // Check for disequality
+ if (d_equalityEngine->areDisequal(a, b, false))
+ {
+ // The terms are implied to be dis-equal
+ return EQUALITY_FALSE;
+ }
+
+ // All other terms are unknown, which is conservative. A theory may override
+ // this method if it knows more information.
+ return EQUALITY_UNKNOWN;
}
-void Theory::setDecisionManager(DecisionManager* dm)
+void Theory::check(Effort level)
{
- Assert(d_decManager == nullptr);
- Assert(dm != nullptr);
- d_decManager = dm;
+ // see if we are already done (as an optimization)
+ if (done() && level < EFFORT_FULL)
+ {
+ return;
+ }
+ Assert(d_theoryState!=nullptr);
+ // standard calls for resource, stats
+ d_out->spendResource(ResourceManager::Resource::TheoryCheckStep);
+ TimerStat::CodeTimer checkTimer(d_checkTime);
+ Trace("theory-check") << "Theory::preCheck " << level << " " << d_id
+ << std::endl;
+ // pre-check at level
+ if (preCheck(level))
+ {
+ // check aborted for a theory-specific reason
+ return;
+ }
+ Assert(d_theoryState != nullptr);
+ Trace("theory-check") << "Theory::process fact queue " << d_id << std::endl;
+ // process the pending fact queue
+ while (!done() && !d_theoryState->isInConflict())
+ {
+ // Get the next assertion from the fact queue
+ Assertion assertion = get();
+ TNode fact = assertion.d_assertion;
+ Trace("theory-check") << "Theory::preNotifyFact " << fact << " " << d_id
+ << std::endl;
+ bool polarity = fact.getKind() != kind::NOT;
+ TNode atom = polarity ? fact : fact[0];
+ // call the pre-notify method
+ if (preNotifyFact(atom, polarity, fact, assertion.d_isPreregistered, false))
+ {
+ // handled in theory-specific way that doesn't involve equality engine
+ continue;
+ }
+ Trace("theory-check") << "Theory::assert " << fact << " " << d_id
+ << std::endl;
+ // Theories that don't have an equality engine should always return true
+ // for preNotifyFact
+ Assert(d_equalityEngine != nullptr);
+ // assert to the equality engine
+ if (atom.getKind() == kind::EQUAL)
+ {
+ d_equalityEngine->assertEquality(atom, polarity, fact);
+ }
+ else
+ {
+ d_equalityEngine->assertPredicate(atom, polarity, fact);
+ }
+ Trace("theory-check") << "Theory::notifyFact " << fact << " " << d_id
+ << std::endl;
+ // notify the theory of the new fact, which is not internal
+ notifyFact(atom, polarity, fact, false);
+ }
+ Trace("theory-check") << "Theory::postCheck " << d_id << std::endl;
+ // post-check at level
+ postCheck(level);
+ Trace("theory-check") << "Theory::finish check " << d_id << std::endl;
}
-void Theory::setupExtTheory() {
- Assert(d_extTheory == NULL);
- d_extTheory = new ExtTheory(this);
+bool Theory::preCheck(Effort level) { return false; }
+
+void Theory::postCheck(Effort level) {}
+
+bool Theory::preNotifyFact(
+ TNode atom, bool polarity, TNode fact, bool isPrereg, bool isInternal)
+{
+ return false;
+}
+
+void Theory::notifyFact(TNode atom, bool polarity, TNode fact, bool isInternal)
+{
+}
+
+void Theory::preRegisterTerm(TNode node) {}
+
+void Theory::addSharedTerm(TNode n)
+{
+ Debug("sharing") << "Theory::addSharedTerm<" << getId() << ">(" << n << ")"
+ << std::endl;
+ Debug("theory::assertions")
+ << "Theory::addSharedTerm<" << getId() << ">(" << n << ")" << std::endl;
+ d_sharedTerms.push_back(n);
+ // now call theory-specific method notifySharedTerm
+ notifySharedTerm(n);
+ // if we have an equality engine, add the trigger term
+ if (d_equalityEngine != nullptr)
+ {
+ d_equalityEngine->addTriggerTerm(n, d_id);
+ }
+}
+
+eq::EqualityEngine* Theory::getEqualityEngine()
+{
+ // get the assigned equality engine, which is a pointer stored in this class
+ return d_equalityEngine;
}
}/* CVC4::theory namespace */
diff --git a/src/theory/theory.h b/src/theory/theory.h
index 1dead8183..6256360e4 100644
--- a/src/theory/theory.h
+++ b/src/theory/theory.h
@@ -2,10 +2,10 @@
/*! \file theory.h
** \verbatim
** Top contributors (to current version):
- ** Dejan Jovanovic, Morgan Deters, Tim King
+ ** Andrew Reynolds, Morgan Deters, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -30,20 +30,21 @@
#include "context/cdo.h"
#include "context/context.h"
#include "expr/node.h"
-#include "lib/ffs.h"
#include "options/options.h"
#include "options/theory_options.h"
-#include "smt/command.h"
-#include "smt/dump.h"
#include "smt/logic_request.h"
#include "theory/assertion.h"
#include "theory/care_graph.h"
#include "theory/decision_manager.h"
+#include "theory/ee_setup_info.h"
#include "theory/logic_info.h"
#include "theory/output_channel.h"
#include "theory/theory_id.h"
+#include "theory/theory_inference_manager.h"
#include "theory/theory_rewriter.h"
+#include "theory/theory_state.h"
#include "theory/trust_node.h"
+#include "theory/trust_substitutions.h"
#include "theory/valuation.h"
#include "util/statistics_registry.h"
@@ -57,7 +58,6 @@ namespace theory {
class QuantifiersEngine;
class TheoryModel;
class SubstitutionMap;
-class ExtTheory;
class TheoryRewriter;
namespace rrinst {
@@ -77,11 +77,35 @@ namespace eq {
* RegisteredAttr works. (If you need multiple instances of the same
* theory, you'll have to write a multiplexed theory that dispatches
* all calls to them.)
+ *
+ * NOTE: A Theory has a special way of being initialized. The owner of a Theory
+ * is either:
+ *
+ * (A) Using Theory as a standalone object, not associated with a TheoryEngine.
+ * In this case, simply call the public initialization method
+ * (Theory::finishInitStandalone).
+ *
+ * (B) TheoryEngine, which determines how the Theory acts in accordance with
+ * its theory combination policy. We require the following steps in order:
+ * (B.1) Get information about whether the theory wishes to use an equality
+ * eninge, and more specifically which equality engine notifications the Theory
+ * would like to be notified of (Theory::needsEqualityEngine).
+ * (B.2) Set the equality engine of the theory (Theory::setEqualityEngine),
+ * which we refer to as the "official equality engine" of this Theory. The
+ * equality engine passed to the theory must respect the contract(s) specified
+ * by the equality engine setup information (EeSetupInfo) returned in the
+ * previous step.
+ * (B.3) Set the other required utilities including setQuantifiersEngine and
+ * setDecisionManager.
+ * (B.4) Call the private initialization method (Theory::finishInit).
+ *
+ * Initialization of the second form happens during TheoryEngine::finishInit,
+ * after the quantifiers engine and model objects have been set up.
*/
class Theory {
- private:
friend class ::CVC4::TheoryEngine;
+ private:
// Disallow default construction, copy, assignment.
Theory() = delete;
Theory(const Theory&) = delete;
@@ -90,11 +114,6 @@ class Theory {
/** An integer identifying the type of the theory. */
TheoryId d_id;
- /** Name of this theory instance. Along with the TheoryId this should provide
- * an unique string identifier for each instance of a Theory class. We need
- * this to ensure unique statistics names over multiple theory instances. */
- std::string d_instanceName;
-
/** The SAT search context for the Theory. */
context::Context* d_satContext;
@@ -104,9 +123,6 @@ class Theory {
/** Information about the logic we're operating within. */
const LogicInfo& d_logicInfo;
- /** Pointer to proof node manager */
- ProofNodeManager* d_pnm;
-
/**
* The assertFact() queue.
*
@@ -118,9 +134,6 @@ class Theory {
/** Index into the head of the facts list */
context::CDO<unsigned> d_factsHead;
- /** Add shared term to the theory. */
- void addSharedTermInternal(TNode node);
-
/** Indices for splitting on the shared terms. */
context::CDO<unsigned> d_sharedTermsIndex;
@@ -136,10 +149,11 @@ class Theory {
/** Pointer to the decision manager. */
DecisionManager* d_decManager;
- /** Extended theory module or NULL. Owned by the theory. */
- ExtTheory* d_extTheory;
-
protected:
+ /** Name of this theory instance. Along with the TheoryId this should provide
+ * an unique string identifier for each instance of a Theory class. We need
+ * this to ensure unique statistics names over multiple theory instances. */
+ std::string d_instanceName;
// === STATISTICS ===
/** time spent in check calls */
@@ -164,32 +178,6 @@ class Theory {
context::CDList<TNode> d_sharedTerms;
/**
- * Helper function for computeRelevantTerms
- */
- void collectTerms(TNode n,
- std::set<Kind>& irrKinds,
- std::set<Node>& termSet) const;
-
- /**
- * Scans the current set of assertions and shared terms top-down
- * until a theory-leaf is reached, and adds all terms found to
- * termSet. This is used by collectModelInfo to delimit the set of
- * terms that should be used when constructing a model.
- *
- * irrKinds: The kinds of terms that appear in assertions that should *not*
- * be included in termSet. Note that the kinds EQUAL and NOT are always
- * treated as irrelevant kinds.
- *
- * includeShared: Whether to include shared terms in termSet. Notice that
- * shared terms are not influenced by irrKinds.
- */
- void computeRelevantTerms(std::set<Node>& termSet,
- std::set<Kind>& irrKinds,
- bool includeShared = true) const;
- /** same as above, but with empty irrKinds */
- void computeRelevantTerms(std::set<Node>& termSet, bool includeShared = true) const;
-
- /**
* Construct a Theory.
*
* The pair <id, instance> is assumed to uniquely identify this Theory
@@ -225,12 +213,29 @@ class Theory {
* theory engine (and other theories).
*/
Valuation d_valuation;
-
/**
- * Whether proofs are enabled
- *
+ * Pointer to the official equality engine of this theory, which is owned by
+ * the equality engine manager of TheoryEngine.
+ */
+ eq::EqualityEngine* d_equalityEngine;
+ /**
+ * The official equality engine, if we allocated it.
*/
- bool d_proofsEnabled;
+ std::unique_ptr<eq::EqualityEngine> d_allocEqualityEngine;
+ /**
+ * The theory state, which contains contexts, valuation, and equality engine.
+ * Notice the theory is responsible for memory management of this class.
+ */
+ TheoryState* d_theoryState;
+ /**
+ * The theory inference manager. This is a wrapper around the equality
+ * engine and the output channel. It ensures that the output channel and
+ * the equality engine are used properly.
+ */
+ TheoryInferenceManager* d_inferManager;
+
+ /** Pointer to proof node manager */
+ ProofNodeManager* d_pnm;
/**
* Returns the next assertion in the assertFact() queue.
@@ -244,6 +249,15 @@ class Theory {
}
/**
+ * Set separation logic heap. This is called when the location and data
+ * types for separation logic are determined. This should be called at
+ * most once, before solving.
+ *
+ * This currently should be overridden by the separation logic theory only.
+ */
+ virtual void declareSepHeap(TypeNode locT, TypeNode dataT) {}
+
+ /**
* The theory that owns the uninterpreted sort.
*/
static TheoryId s_uninterpretedSortOwner;
@@ -267,8 +281,65 @@ class Theory {
* its value must be computed (approximated) by the non-linear solver.
*/
bool isLegalElimination(TNode x, TNode val);
+ //--------------------------------- private initialization
+ /**
+ * Called to set the official equality engine. This should be done by
+ * TheoryEngine only.
+ */
+ void setEqualityEngine(eq::EqualityEngine* ee);
+ /** Called to set the quantifiers engine. */
+ void setQuantifiersEngine(QuantifiersEngine* qe);
+ /** Called to set the decision manager. */
+ void setDecisionManager(DecisionManager* dm);
+ /**
+ * Finish theory initialization. At this point, options and the logic
+ * setting are final, the master equality engine and quantifiers
+ * engine (if any) are initialized, and the official equality engine of this
+ * theory has been assigned. This base class implementation
+ * does nothing. This should be called by TheoryEngine only.
+ */
+ virtual void finishInit() {}
+ //--------------------------------- end private initialization
+
+ /**
+ * This method is called to notify a theory that the node n should
+ * be considered a "shared term" by this theory. This does anything
+ * theory-specific concerning the fact that n is now marked as a shared
+ * term, which is done in addition to explicitly storing n as a shared
+ * term and adding it as a trigger term in the equality engine of this
+ * class (see addSharedTerm).
+ */
+ virtual void notifySharedTerm(TNode n);
public:
+ //--------------------------------- initialization
+ /**
+ * @return The theory rewriter associated with this theory.
+ */
+ virtual TheoryRewriter* getTheoryRewriter() = 0;
+ /**
+ * Returns true if this theory needs an equality engine for checking
+ * satisfiability.
+ *
+ * If this method returns true, then the equality engine manager will
+ * initialize its equality engine field via setEqualityEngine above during
+ * TheoryEngine::finishInit, prior to calling finishInit for this theory.
+ *
+ * Additionally, if this method returns true, then this method is required to
+ * update the argument esi with instructions for initializing and setting up
+ * notifications from its equality engine, which is commonly done with
+ * a notifications class (eq::EqualityEngineNotify).
+ */
+ virtual bool needsEqualityEngine(EeSetupInfo& esi);
+ /**
+ * Finish theory initialization, standalone version. This is used to
+ * initialize this class if it is not associated with a theory engine.
+ * This allocates the official equality engine of this Theory and then
+ * calls the finishInit method above.
+ */
+ void finishInitStandalone();
+ //--------------------------------- end initialization
+
/**
* Return the ID of the theory responsible for the given type.
*/
@@ -335,36 +406,29 @@ class Theory {
virtual ~Theory();
/**
- * @return The theory rewriter associated with this theory.
- */
- virtual TheoryRewriter* getTheoryRewriter() = 0;
-
- /**
* Subclasses of Theory may add additional efforts. DO NOT CHECK
* equality with one of these values (e.g. if STANDARD xxx) but
* rather use range checks (or use the helper functions below).
* Normally we call QUICK_CHECK or STANDARD; at the leaves we call
* with FULL_EFFORT.
*/
- enum Effort {
+ enum Effort
+ {
/**
* Standard effort where theory need not do anything
*/
EFFORT_STANDARD = 50,
/**
- * Full effort requires the theory make sure its assertions are satisfiable or not
+ * Full effort requires the theory make sure its assertions are satisfiable
+ * or not
*/
EFFORT_FULL = 100,
/**
- * Combination effort means that the individual theories are already satisfied, and
- * it is time to put some effort into propagation of shared term equalities
- */
- EFFORT_COMBINATION = 150,
- /**
- * Last call effort, reserved for quantifiers.
+ * Last call effort, called after theory combination has completed with
+ * no lemmas and a model is available.
*/
EFFORT_LAST_CALL = 200
- };/* enum Effort */
+ }; /* enum Effort */
static inline bool standardEffortOrMore(Effort e) CVC4_CONST_FUNCTION
{ return e >= EFFORT_STANDARD; }
@@ -372,8 +436,6 @@ class Theory {
{ return e >= EFFORT_STANDARD && e < EFFORT_FULL; }
static inline bool fullEffort(Effort e) CVC4_CONST_FUNCTION
{ return e == EFFORT_FULL; }
- static inline bool combination(Effort e) CVC4_CONST_FUNCTION
- { return e == EFFORT_COMBINATION; }
/**
* Get the id for this Theory.
@@ -417,6 +479,9 @@ class Theory {
return d_valuation;
}
+ /** Get the equality engine being used by this theory. */
+ eq::EqualityEngine* getEqualityEngine();
+
/**
* Get the quantifiers engine associated to this theory.
*/
@@ -424,23 +489,18 @@ class Theory {
return d_quantEngine;
}
- /**
- * Get the quantifiers engine associated to this theory (const version).
- */
- const QuantifiersEngine* getQuantifiersEngine() const {
- return d_quantEngine;
- }
-
/** Get the decision manager associated to this theory. */
DecisionManager* getDecisionManager() { return d_decManager; }
/**
- * Finish theory initialization. At this point, options and the logic
- * setting are final, and the master equality engine and quantifiers
- * engine (if any) are initialized. This base class implementation
- * does nothing.
+ * @return The theory state associated with this theory.
*/
- virtual void finishInit() { }
+ TheoryState* getTheoryState() { return d_theoryState; }
+
+ /**
+ * @return The theory inference manager associated with this theory.
+ */
+ TheoryInferenceManager* getInferenceManager() { return d_inferManager; }
/**
* Expand definitions in the term node. This returns a term that is
@@ -478,7 +538,7 @@ class Theory {
/**
* Pre-register a term. Done one time for a Node per SAT context level.
*/
- virtual void preRegisterTerm(TNode) { }
+ virtual void preRegisterTerm(TNode);
/**
* Assert a fact in the current context.
@@ -490,24 +550,8 @@ class Theory {
d_facts.push_back(Assertion(assertion, isPreregistered));
}
- /**
- * This method is called to notify a theory that the node n should
- * be considered a "shared term" by this theory
- */
- virtual void addSharedTerm(TNode n) { }
-
- /**
- * Called to set the master equality engine.
- */
- virtual void setMasterEqualityEngine(eq::EqualityEngine* eq) { }
-
- /** Called to set the quantifiers engine. */
- void setQuantifiersEngine(QuantifiersEngine* qe);
- /** Called to set the decision manager. */
- void setDecisionManager(DecisionManager* dm);
-
- /** Setup an ExtTheory module for this Theory. Can only be called once. */
- void setupExtTheory();
+ /** Add shared term to the theory. */
+ void addSharedTerm(TNode node);
/**
* Return the current theory care graph. Theories should overload
@@ -520,31 +564,17 @@ class Theory {
* Return the status of two terms in the current context. Should be
* implemented in sub-theories to enable more efficient theory-combination.
*/
- virtual EqualityStatus getEqualityStatus(TNode a, TNode b) {
- return EQUALITY_UNKNOWN;
- }
+ virtual EqualityStatus getEqualityStatus(TNode a, TNode b);
/**
* Return the model value of the give shared term (or null if not available).
- */
- virtual Node getModelValue(TNode var) { return Node::null(); }
-
- /**
- * Check the current assignment's consistency.
*
- * An implementation of check() is required to either:
- * - return a conflict on the output channel,
- * - be interrupted,
- * - throw an exception
- * - or call get() until done() is true.
+ * TODO (project #39): this method is likely to become deprecated.
*/
- virtual void check(Effort level = EFFORT_FULL) { }
-
- /** Needs last effort check? */
- virtual bool needsCheckLastEffort() { return false; }
+ virtual Node getModelValue(TNode var) { return Node::null(); }
/** T-propagate new literal assignments in the current context. */
- virtual void propagate(Effort level = EFFORT_FULL) { }
+ virtual void propagate(Effort level = EFFORT_FULL) {}
/**
* Return an explanation for the literal represented by parameter n
@@ -555,8 +585,78 @@ class Theory {
Unimplemented() << "Theory " << identify()
<< " propagated a node but doesn't implement the "
"Theory::explain() interface!";
+ return TrustNode::null();
}
+ //--------------------------------- check
+ /**
+ * Does this theory wish to be called to check at last call effort? This is
+ * the case for any theory that wishes to run when a model is available.
+ */
+ virtual bool needsCheckLastEffort() { return false; }
+ /**
+ * Check the current assignment's consistency.
+ *
+ * An implementation of check() is required to either:
+ * - return a conflict on the output channel,
+ * - be interrupted,
+ * - throw an exception
+ * - or call get() until done() is true.
+ *
+ * The standard method for check consists of a loop that processes the entire
+ * fact queue when preCheck returns false. It makes four theory-specific
+ * callbacks, (preCheck, postCheck, preNotifyFact, notifyFact) as described
+ * below. It asserts each fact to the official equality engine when
+ * preNotifyFact returns false.
+ *
+ * Theories that use this check method must use an official theory
+ * state object (d_theoryState).
+ */
+ void check(Effort level = EFFORT_FULL);
+ /**
+ * Pre-check, called before the fact queue of the theory is processed.
+ * If this method returns false, then the theory will process its fact
+ * queue. If this method returns true, then the theory has indicated
+ * its check method should finish immediately.
+ */
+ virtual bool preCheck(Effort level = EFFORT_FULL);
+ /**
+ * Post-check, called after the fact queue of the theory is processed.
+ */
+ virtual void postCheck(Effort level = EFFORT_FULL);
+ /**
+ * Pre-notify fact, return true if the theory processed it. If this
+ * method returns false, then the atom will be added to the equality engine
+ * of the theory and notifyFact will be called with isInternal=false.
+ *
+ * Theories that implement check but do not use official equality
+ * engines should always return true for this method.
+ *
+ * @param atom The atom
+ * @param polarity Its polarity
+ * @param fact The original literal that was asserted
+ * @param isPrereg Whether the assertion is preregistered
+ * @param isInternal Whether the origin of the fact was internal. If this
+ * is false, the fact was asserted via the fact queue of the theory.
+ * @return true if the theory completely processed this fact, i.e. it does
+ * not need to assert the fact to its equality engine.
+ */
+ virtual bool preNotifyFact(
+ TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal);
+ /**
+ * Notify fact, called immediately after the fact was pushed into the
+ * equality engine.
+ *
+ * @param atom The atom
+ * @param polarity Its polarity
+ * @param fact The original literal that was asserted.
+ * @param isInternal Whether the origin of the fact was internal. If this
+ * is false, the fact was asserted via the fact queue of the theory.
+ */
+ virtual void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal);
+ //--------------------------------- end check
+
+ //--------------------------------- collect model info
/**
* Get all relevant information in this theory regarding the current
* model. This should be called after a call to check( FULL_EFFORT )
@@ -564,10 +664,32 @@ class Theory {
*
* This method returns true if and only if the equality engine of m is
* consistent as a result of this call.
+ *
+ * The standard method for collectModelInfo computes the relevant terms,
+ * asserts the theory's equality engine to the model (if necessary) and
+ * then calls computeModelValues.
+ *
+ * TODO (project #39): this method should be non-virtual, once all theories
+ * conform to the new standard, delete, move to model manager distributed.
+ */
+ virtual bool collectModelInfo(TheoryModel* m, const std::set<Node>& termSet);
+ /**
+ * Compute terms that are not necessarily part of the assertions or
+ * shared terms that should be considered relevant, add them to termSet.
+ */
+ virtual void computeRelevantTerms(std::set<Node>& termSet);
+ /**
+ * Collect model values, after equality information is added to the model.
+ * The argument termSet is the set of relevant terms returned by
+ * computeRelevantTerms.
*/
- virtual bool collectModelInfo(TheoryModel* m) { return true; }
+ virtual bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet);
/** if theories want to do something with model after building, do it here */
virtual void postProcessModel( TheoryModel* m ){ }
+ //--------------------------------- end collect model info
+
+ //--------------------------------- preprocessing
/**
* Statically learn from assertion "in," which has been asserted
* true at the top level. The theory should only add (via
@@ -587,10 +709,16 @@ class Theory {
};
/**
- * Given a literal, add the solved substitutions to the map, if any.
- * The method should return true if the literal can be safely removed.
+ * Given a literal and its proof generator (encapsulated by trust node tin),
+ * add the solved substitutions to the map, if any. The method should return
+ * true if the literal can be safely removed from the input problem.
+ *
+ * Note that tin has trude node kind LEMMA. Its proof generator should be
+ * take into account when adding a substitution to outSubstitutions when
+ * proofs are enabled.
*/
- virtual PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions);
+ virtual PPAssertStatus ppAssert(TrustNode tin,
+ TrustSubstitutionMap& outSubstitutions);
/**
* Given an atom of the theory coming from the input formula, this
@@ -608,6 +736,7 @@ class Theory {
* preprocessing before they are asserted to theory engine.
*/
virtual void ppNotifyAssertions(const std::vector<Node>& assertions) {}
+ //--------------------------------- end preprocessing
/**
* A Theory is called with presolve exactly one time per user
@@ -658,84 +787,6 @@ class Theory {
<< " doesn't support Theory::setUserAttribute interface";
}
- /** A set of theories */
- typedef uint32_t Set;
-
- /** A set of all theories */
- static const Set AllTheories = (1 << theory::THEORY_LAST) - 1;
-
- /** Pops a first theory off the set */
- static inline TheoryId setPop(Set& set) {
- uint32_t i = ffs(set); // Find First Set (bit)
- if (i == 0) { return THEORY_LAST; }
- TheoryId id = (TheoryId)(i-1);
- set = setRemove(id, set);
- return id;
- }
-
- /** Returns the size of a set of theories */
- static inline size_t setSize(Set set) {
- size_t count = 0;
- while (setPop(set) != THEORY_LAST) {
- ++ count;
- }
- return count;
- }
-
- /** Returns the index size of a set of theories */
- static inline size_t setIndex(TheoryId id, Set set) {
- Assert(setContains(id, set));
- size_t count = 0;
- while (setPop(set) != id) {
- ++ count;
- }
- return count;
- }
-
- /** Add the theory to the set. If no set specified, just returns a singleton set */
- static inline Set setInsert(TheoryId theory, Set set = 0) {
- return set | (1 << theory);
- }
-
- /** Add the theory to the set. If no set specified, just returns a singleton set */
- static inline Set setRemove(TheoryId theory, Set set = 0) {
- return setDifference(set, setInsert(theory));
- }
-
- /** Check if the set contains the theory */
- static inline bool setContains(TheoryId theory, Set set) {
- return set & (1 << theory);
- }
-
- static inline Set setComplement(Set a) {
- return (~a) & AllTheories;
- }
-
- static inline Set setIntersection(Set a, Set b) {
- return a & b;
- }
-
- static inline Set setUnion(Set a, Set b) {
- return a | b;
- }
-
- /** a - b */
- static inline Set setDifference(Set a, Set b) {
- return (~b) & a;
- }
-
- static inline std::string setToString(theory::Theory::Set theorySet) {
- std::stringstream ss;
- ss << "[";
- for(unsigned theoryId = 0; theoryId < theory::THEORY_LAST; ++theoryId) {
- if (theory::Theory::setContains((theory::TheoryId)theoryId, theorySet)) {
- ss << (theory::TheoryId) theoryId << " ";
- }
- }
- ss << "]";
- return ss.str();
- }
-
typedef context::CDList<Assertion>::const_iterator assertions_iterator;
/**
@@ -762,15 +813,13 @@ class Theory {
*
* @return true iff facts have been asserted to this theory.
*/
- bool hasFacts() {
- return !d_facts.empty();
- }
+ bool hasFacts() { return !d_facts.empty(); }
/** Return total number of facts asserted to this theory */
size_t numAssertions() {
return d_facts.size();
}
-
+
typedef context::CDList<TNode>::const_iterator shared_terms_iterator;
/**
@@ -841,40 +890,6 @@ class Theory {
* E |= lit in the theory.
*/
virtual std::pair<bool, Node> entailmentCheck(TNode lit);
-
- /* equality engine TODO: use? */
- virtual eq::EqualityEngine* getEqualityEngine() { return NULL; }
-
- /* Get extended theory if one has been installed. */
- ExtTheory* getExtTheory();
-
- /* get current substitution at an effort
- * input : vars
- * output : subs, exp
- * where ( exp[vars[i]] => vars[i] = subs[i] ) holds for all i
- */
- virtual bool getCurrentSubstitution(int effort, std::vector<Node>& vars,
- std::vector<Node>& subs,
- std::map<Node, std::vector<Node> >& exp) {
- return false;
- }
-
- /* is extended function reduced */
- virtual bool isExtfReduced( int effort, Node n, Node on, std::vector< Node >& exp ) { return n.isConst(); }
-
- /**
- * Get reduction for node
- * If return value is not 0, then n is reduced.
- * If return value <0 then n is reduced SAT-context-independently (e.g. by a
- * lemma that persists at this user-context level).
- * If nr is non-null, then ( n = nr ) should be added as a lemma by caller,
- * and return value should be <0.
- */
- virtual int getReduction( int effort, Node n, Node& nr ) { return 0; }
-
- /** Turn on proof-production mode. */
- void produceProofs() { d_proofsEnabled = true; }
-
};/* class Theory */
std::ostream& operator<<(std::ostream& os, theory::Theory::Effort level);
@@ -889,10 +904,6 @@ inline theory::Assertion Theory::get() {
Trace("theory") << "Theory::get() => " << fact << " (" << d_facts.size() - d_factsHead << " left)" << std::endl;
- if(Dump.isOn("state")) {
- Dump("state") << AssertCommand(fact.d_assertion.toExpr());
- }
-
return fact;
}
diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp
index 70e744acf..e771f8bb8 100644
--- a/src/theory/theory_engine.cpp
+++ b/src/theory/theory_engine.cpp
@@ -2,10 +2,10 @@
/*! \file theory_engine.cpp
** \verbatim
** Top contributors (to current version):
- ** Dejan Jovanovic, Andrew Reynolds, Morgan Deters
+ ** Andrew Reynolds, Dejan Jovanovic, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -22,31 +22,33 @@
#include "base/map_util.h"
#include "decision/decision_engine.h"
#include "expr/attribute.h"
+#include "expr/lazy_proof.h"
#include "expr/node.h"
-#include "expr/node_algorithm.h"
#include "expr/node_builder.h"
#include "expr/node_visitor.h"
#include "options/bv_options.h"
#include "options/options.h"
-#include "options/proof_options.h"
#include "options/quantifiers_options.h"
#include "options/theory_options.h"
#include "preprocessing/assertion_pipeline.h"
-#include "proof/cnf_proof.h"
-#include "proof/lemma_proof.h"
-#include "proof/proof_manager.h"
-#include "proof/theory_proof.h"
+#include "printer/printer.h"
+#include "smt/dump.h"
#include "smt/logic_exception.h"
#include "smt/term_formula_removal.h"
#include "theory/arith/arith_ite_utils.h"
#include "theory/bv/theory_bv_utils.h"
#include "theory/care_graph.h"
+#include "theory/combination_care_graph.h"
+#include "theory/decision_manager.h"
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/fmf/model_engine.h"
#include "theory/quantifiers/theory_quantifiers.h"
#include "theory/quantifiers_engine.h"
+#include "theory/relevance_manager.h"
#include "theory/rewriter.h"
#include "theory/theory.h"
+#include "theory/theory_engine_proof_generator.h"
+#include "theory/theory_id.h"
#include "theory/theory_model.h"
#include "theory/theory_traits.h"
#include "theory/uf/equality_engine.h"
@@ -80,6 +82,7 @@ namespace theory {
CVC4_FOR_EACH_THEORY_STATEMENT(CVC4::theory::THEORY_DATATYPES) \
CVC4_FOR_EACH_THEORY_STATEMENT(CVC4::theory::THEORY_SEP) \
CVC4_FOR_EACH_THEORY_STATEMENT(CVC4::theory::THEORY_SETS) \
+ CVC4_FOR_EACH_THEORY_STATEMENT(CVC4::theory::THEORY_BAGS) \
CVC4_FOR_EACH_THEORY_STATEMENT(CVC4::theory::THEORY_STRINGS) \
CVC4_FOR_EACH_THEORY_STATEMENT(CVC4::theory::THEORY_QUANTIFIERS)
@@ -127,71 +130,117 @@ std::string getTheoryString(theory::TheoryId id)
}
}
-void TheoryEngine::finishInit() {
- //initialize the quantifiers engine, master equality engine, model, model builder
- if( d_logicInfo.isQuantified() ) {
- // initialize the quantifiers engine
- d_quantEngine = new QuantifiersEngine(d_context, d_userContext, this);
- Assert(d_masterEqualityEngine == 0);
- d_masterEqualityEngine = new eq::EqualityEngine(d_masterEENotify,getSatContext(), "theory::master", false);
-
- for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) {
- if (d_theoryTable[theoryId]) {
- d_theoryTable[theoryId]->setQuantifiersEngine(d_quantEngine);
- d_theoryTable[theoryId]->setMasterEqualityEngine(d_masterEqualityEngine);
- }
- }
+void TheoryEngine::finishInit()
+{
+ // NOTE: This seems to be required since
+ // theory::TheoryTraits<THEORY>::isParametric cannot be accessed without
+ // using the CVC4_FOR_EACH_THEORY_STATEMENT macro. -AJR
+ std::vector<theory::Theory*> paraTheories;
+#ifdef CVC4_FOR_EACH_THEORY_STATEMENT
+#undef CVC4_FOR_EACH_THEORY_STATEMENT
+#endif
+#define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \
+ if (theory::TheoryTraits<THEORY>::isParametric \
+ && d_logicInfo.isTheoryEnabled(THEORY)) \
+ { \
+ paraTheories.push_back(theoryOf(THEORY)); \
+ }
+ // Collect the parametric theories, which are given to the theory combination
+ // manager below
+ CVC4_FOR_EACH_THEORY;
- d_curr_model_builder = d_quantEngine->getModelBuilder();
- d_curr_model = d_quantEngine->getModel();
- } else {
- d_curr_model = new theory::TheoryModel(
- d_userContext, "DefaultModel", options::assignFunctionValues());
- d_aloc_curr_model = true;
+ // Initialize the theory combination architecture
+ if (options::tcMode() == options::TcMode::CARE_GRAPH)
+ {
+ d_tc.reset(new CombinationCareGraph(*this, paraTheories, d_pnm));
+ }
+ else
+ {
+ Unimplemented() << "TheoryEngine::finishInit: theory combination mode "
+ << options::tcMode() << " not supported";
+ }
+ // create the relevance filter if any option requires it
+ if (options::relevanceFilter())
+ {
+ d_relManager.reset(
+ new RelevanceManager(d_userContext, theory::Valuation(this)));
+ }
+
+ // initialize the quantifiers engine
+ if (d_logicInfo.isQuantified())
+ {
+ // initialize the quantifiers engine
+ d_quantEngine = new QuantifiersEngine(this, *d_decManager.get(), d_pnm);
}
- //make the default builder, e.g. in the case that the quantifiers engine does not have a model builder
- if( d_curr_model_builder==NULL ){
- d_curr_model_builder = new theory::TheoryEngineModelBuilder(this);
- d_aloc_curr_model_builder = true;
+ // initialize the theory combination manager, which decides and allocates the
+ // equality engines to use for all theories.
+ d_tc->finishInit();
+ // get pointer to the shared solver
+ d_sharedSolver = d_tc->getSharedSolver();
+
+ // set the core equality engine on quantifiers engine
+ if (d_logicInfo.isQuantified())
+ {
+ d_quantEngine->setMasterEqualityEngine(d_tc->getCoreEqualityEngine());
}
+ // finish initializing the theories by linking them with the appropriate
+ // utilities and then calling their finishInit method.
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) {
- if (d_theoryTable[theoryId]) {
- // set the decision manager for the theory
- d_theoryTable[theoryId]->setDecisionManager(d_decManager.get());
- // finish initializing the theory
- d_theoryTable[theoryId]->finishInit();
+ Theory* t = d_theoryTable[theoryId];
+ if (t == nullptr)
+ {
+ continue;
}
+ // setup the pointers to the utilities
+ const EeTheoryInfo* eeti = d_tc->getEeTheoryInfo(theoryId);
+ Assert(eeti != nullptr);
+ // the theory's official equality engine is the one specified by the
+ // equality engine manager
+ t->setEqualityEngine(eeti->d_usedEe);
+ // set the quantifiers engine
+ t->setQuantifiersEngine(d_quantEngine);
+ // set the decision manager for the theory
+ t->setDecisionManager(d_decManager.get());
+ // finish initializing the theory
+ t->finishInit();
+ }
+
+ // finish initializing the quantifiers engine
+ if (d_logicInfo.isQuantified())
+ {
+ d_quantEngine->finishInit();
}
}
-void TheoryEngine::eqNotifyNewClass(TNode t){
- if (d_logicInfo.isQuantified()) {
- d_quantEngine->eqNotifyNewClass( t );
- }
-}
+ProofNodeManager* TheoryEngine::getProofNodeManager() const { return d_pnm; }
TheoryEngine::TheoryEngine(context::Context* context,
context::UserContext* userContext,
ResourceManager* rm,
RemoveTermFormulas& iteRemover,
- const LogicInfo& logicInfo)
+ const LogicInfo& logicInfo,
+ OutputManager& outMgr,
+ ProofNodeManager* pnm)
: d_propEngine(nullptr),
d_context(context),
d_userContext(userContext),
d_logicInfo(logicInfo),
- d_sharedTerms(this, context),
- d_masterEqualityEngine(nullptr),
- d_masterEENotify(*this),
+ d_outMgr(outMgr),
+ d_pnm(pnm),
+ d_lazyProof(
+ d_pnm != nullptr
+ ? new LazyCDProof(
+ d_pnm, nullptr, d_userContext, "TheoryEngine::LazyCDProof")
+ : nullptr),
+ d_tepg(new TheoryEngineProofGenerator(d_pnm, d_userContext)),
+ d_tc(nullptr),
+ d_sharedSolver(nullptr),
d_quantEngine(nullptr),
d_decManager(new DecisionManager(userContext)),
- d_curr_model(nullptr),
- d_aloc_curr_model(false),
- d_curr_model_builder(nullptr),
- d_aloc_curr_model_builder(false),
+ d_relManager(nullptr),
+ d_preRegistrationVisitor(this, context),
d_eager_model_building(false),
- d_possiblePropagations(context),
- d_hasPropagated(context),
d_inConflict(context, false),
d_inSatMode(false),
d_hasShutDown(false),
@@ -201,7 +250,7 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_propagatedLiterals(context),
d_propagatedLiteralsIndex(context, 0),
d_atomRequests(context),
- d_tpp(*this, iteRemover),
+ d_tpp(*this, iteRemover, userContext, d_pnm),
d_combineTheoriesTime("TheoryEngine::combineTheoriesTime"),
d_true(),
d_false(),
@@ -209,8 +258,6 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_resourceManager(rm),
d_inPreregister(false),
d_factsAsserted(context, false),
- d_preRegistrationVisitor(this, context),
- d_sharedTermsVisitor(d_sharedTerms),
d_attr_handle(),
d_arithSubstitutionsAdded("theory::arith::zzz::arith::substitutions", 0)
{
@@ -225,10 +272,6 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_true = NodeManager::currentNM()->mkConst<bool>(true);
d_false = NodeManager::currentNM()->mkConst<bool>(false);
-#ifdef CVC4_PROOF
- ProofManager::currentPM()->initTheoryProofEngine();
-#endif
-
smtStatisticsRegistry()->registerStat(&d_arithSubstitutionsAdded);
}
@@ -242,28 +285,16 @@ TheoryEngine::~TheoryEngine() {
}
}
- if( d_aloc_curr_model_builder ){
- delete d_curr_model_builder;
- }
- if( d_aloc_curr_model ){
- delete d_curr_model;
- }
-
delete d_quantEngine;
- delete d_masterEqualityEngine;
-
smtStatisticsRegistry()->unregisterStat(&d_combineTheoriesTime);
smtStatisticsRegistry()->unregisterStat(&d_arithSubstitutionsAdded);
}
void TheoryEngine::interrupt() { d_interrupted = true; }
void TheoryEngine::preRegister(TNode preprocessed) {
-
- Debug("theory") << "TheoryEngine::preRegister( " << preprocessed << ")" << std::endl;
- if(Dump.isOn("missed-t-propagations")) {
- d_possiblePropagations.push_back(preprocessed);
- }
+ Debug("theory") << "TheoryEngine::preRegister( " << preprocessed << ")"
+ << std::endl;
d_preregisterQueue.push(preprocessed);
if (!d_inPreregister) {
@@ -276,44 +307,54 @@ void TheoryEngine::preRegister(TNode preprocessed) {
preprocessed = d_preregisterQueue.front();
d_preregisterQueue.pop();
- if (d_logicInfo.isSharingEnabled() && preprocessed.getKind() == kind::EQUAL) {
- // When sharing is enabled, we propagate from the shared terms manager also
- d_sharedTerms.addEqualityToPropagate(preprocessed);
- }
-
// the atom should not have free variables
Debug("theory") << "TheoryEngine::preRegister: " << preprocessed
<< std::endl;
Assert(!expr::hasFreeVar(preprocessed));
+ // should not have witness
+ Assert(!expr::hasSubtermKind(kind::WITNESS, preprocessed));
+
// Pre-register the terms in the atom
- 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());
+ theory::TheoryIdSet theories = NodeVisitor<PreRegisterVisitor>::run(
+ d_preRegistrationVisitor, preprocessed);
+ theories = TheoryIdSetUtil::setRemove(THEORY_BOOL, theories);
+ // Remove the top theory, if any more that means multiple theories were
+ // involved
+ bool multipleTheories =
+ TheoryIdSetUtil::setRemove(Theory::theoryOf(preprocessed), theories);
+ if (Configuration::isAssertionBuild())
+ {
+ TheoryId i;
+ // This should never throw an exception, since theories should be
+ // guaranteed to be initialized.
+ // 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 = TheoryIdSetUtil::setPop(theories)) != THEORY_LAST)
+ {
+ if (!d_logicInfo.isTheoryEnabled(i))
+ {
+ LogicInfo newLogicInfo = d_logicInfo.getUnlockedCopy();
+ newLogicInfo.enableTheory(i);
+ newLogicInfo.lock();
+ std::stringstream ss;
+ ss << "The logic was specified as " << d_logicInfo.getLogicString()
+ << ", which doesn't include " << i
+ << ", but found a term in that theory." << std::endl
+ << "You might want to extend your logic to "
+ << newLogicInfo.getLogicString() << std::endl;
+ throw LogicException(ss.str());
+ }
}
}
}
- if (multipleTheories) {
- // Collect the shared terms if there are multiple theories
- NodeVisitor<SharedTermsVisitor>::run(d_sharedTermsVisitor, preprocessed);
- }
+
+ // pre-register with the shared solver, which also handles
+ // calling prepregister on individual theories.
+ Assert(d_sharedSolver != nullptr);
+ d_sharedSolver->preRegisterShared(preprocessed, multipleTheories);
}
// Leaving pre-register
@@ -361,26 +402,28 @@ void TheoryEngine::printAssertions(const char* tag) {
void TheoryEngine::dumpAssertions(const char* tag) {
if (Dump.isOn(tag)) {
- Dump(tag) << CommentCommand("Starting completeness check");
+ const Printer& printer = d_outMgr.getPrinter();
+ std::ostream& out = d_outMgr.getDumpOut();
+ printer.toStreamCmdComment(out, "Starting completeness check");
for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) {
Theory* theory = d_theoryTable[theoryId];
if (theory && d_logicInfo.isTheoryEnabled(theoryId)) {
- Dump(tag) << CommentCommand("Completeness check");
- Dump(tag) << PushCommand();
+ printer.toStreamCmdComment(out, "Completeness check");
+ printer.toStreamCmdPush(out);
// Dump the shared terms
if (d_logicInfo.isSharingEnabled()) {
- Dump(tag) << CommentCommand("Shared terms");
+ printer.toStreamCmdComment(out, "Shared terms");
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) {
stringstream ss;
ss << (*it);
- Dump(tag) << CommentCommand(ss.str());
+ printer.toStreamCmdComment(out, ss.str());
}
}
// Dump the assertions
- Dump(tag) << CommentCommand("Assertions");
+ printer.toStreamCmdComment(out, "Assertions");
context::CDList<Assertion>::const_iterator it = theory->facts_begin(), it_end = theory->facts_end();
for (; it != it_end; ++ it) {
// Get the assertion
@@ -389,17 +432,17 @@ void TheoryEngine::dumpAssertions(const char* tag) {
if ((*it).d_isPreregistered)
{
- Dump(tag) << CommentCommand("Preregistered");
+ printer.toStreamCmdComment(out, "Preregistered");
}
else
{
- Dump(tag) << CommentCommand("Shared assertion");
+ printer.toStreamCmdComment(out, "Shared assertion");
}
- Dump(tag) << AssertCommand(assertionNode.toExpr());
+ printer.toStreamCmdAssert(out, assertionNode);
}
- Dump(tag) << CheckSatCommand();
+ printer.toStreamCmdCheckSat(out);
- Dump(tag) << PopCommand();
+ printer.toStreamCmdPop(out);
}
}
}
@@ -418,14 +461,17 @@ void TheoryEngine::check(Theory::Effort effort) {
#ifdef CVC4_FOR_EACH_THEORY_STATEMENT
#undef CVC4_FOR_EACH_THEORY_STATEMENT
#endif
-#define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \
- if (theory::TheoryTraits<THEORY>::hasCheck && d_logicInfo.isTheoryEnabled(THEORY)) { \
- theoryOf(THEORY)->check(effort); \
- if (d_inConflict) { \
- Debug("conflict") << THEORY << " in conflict. " << std::endl; \
- break; \
- } \
- }
+#define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \
+ if (theory::TheoryTraits<THEORY>::hasCheck \
+ && d_logicInfo.isTheoryEnabled(THEORY)) \
+ { \
+ theoryOf(THEORY)->check(effort); \
+ if (d_inConflict) \
+ { \
+ Debug("conflict") << THEORY << " in conflict. " << std::endl; \
+ break; \
+ } \
+ }
// Do the checking
try {
@@ -442,6 +488,13 @@ void TheoryEngine::check(Theory::Effort effort) {
// If in full effort, we have a fake new assertion just to jumpstart the checking
if (Theory::fullEffort(effort)) {
d_factsAsserted = true;
+ // Reset round for the relevance manager, which notice only sets a flag
+ // to indicate that its information must be recomputed.
+ if (d_relManager != nullptr)
+ {
+ d_relManager->resetRound();
+ }
+ d_tc->resetRound();
}
// Check until done
@@ -467,12 +520,6 @@ void TheoryEngine::check(Theory::Effort effort) {
// Do the checking
CVC4_FOR_EACH_THEORY;
- if(Dump.isOn("missed-t-conflicts")) {
- Dump("missed-t-conflicts")
- << CommentCommand("Completeness check for T-conflicts; expect sat")
- << CheckSatCommand();
- }
-
Debug("theory") << "TheoryEngine::check(" << effort << "): running propagation after the initial check" << endl;
// We are still satisfiable, propagate as much as possible
@@ -482,7 +529,10 @@ void TheoryEngine::check(Theory::Effort effort) {
if (Theory::fullEffort(effort) && d_logicInfo.isSharingEnabled() && !d_factsAsserted && !d_lemmasAdded && !d_inConflict) {
// Do the combination
Debug("theory") << "TheoryEngine::check(" << effort << "): running combination" << endl;
- combineTheories();
+ {
+ TimerStat::CodeTimer combineTheoriesTimer(d_combineTheoriesTime);
+ d_tc->combineTheories();
+ }
if(d_logicInfo.isQuantified()){
d_quantEngine->notifyCombineTheories();
}
@@ -495,17 +545,17 @@ void TheoryEngine::check(Theory::Effort effort) {
if (Trace.isOn("theory::assertions-model")) {
printAssertions("theory::assertions-model");
}
+ // reset the model in the combination engine
+ d_tc->resetModel();
//checks for theories requiring the model go at last call
- d_curr_model->reset();
for (TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) {
if( theoryId!=THEORY_QUANTIFIERS ){
Theory* theory = d_theoryTable[theoryId];
if (theory && d_logicInfo.isTheoryEnabled(theoryId)) {
if( theory->needsCheckLastEffort() ){
- if( !d_curr_model->isBuilt() ){
- if( !d_curr_model_builder->buildModel(d_curr_model) ){
- break;
- }
+ if (!d_tc->buildModel())
+ {
+ break;
}
theory->check(Theory::EFFORT_LAST_CALL);
}
@@ -525,9 +575,9 @@ void TheoryEngine::check(Theory::Effort effort) {
// are in "SAT mode". We build the model later only if the user asks
// for it via getBuiltModel.
d_inSatMode = true;
- if (d_eager_model_building && !d_curr_model->isBuilt())
+ if (d_eager_model_building)
{
- d_curr_model_builder->buildModel(d_curr_model);
+ d_tc->buildModel();
}
}
}
@@ -536,24 +586,9 @@ void TheoryEngine::check(Theory::Effort effort) {
Debug("theory") << ", need check = " << (needCheck() ? "YES" : "NO") << endl;
if( Theory::fullEffort(effort) && !d_inConflict && !needCheck()) {
- // case where we are about to answer SAT
- if( d_masterEqualityEngine != NULL ){
- AlwaysAssert(d_masterEqualityEngine->consistent());
- }
- if (d_curr_model->isBuilt())
- {
- // model construction should always succeed unless lemmas were added
- AlwaysAssert(d_curr_model->isBuiltSuccess());
- if (options::produceModels())
- {
- // Do post-processing of model from the theories (used for THEORY_SEP
- // to construct heap model)
- postProcessModel(d_curr_model);
- // also call the model builder's post-process model
- d_curr_model_builder->postProcessModel(d_incomplete.get(),
- d_curr_model);
- }
- }
+ // Do post-processing of model from the theories (e.g. used for THEORY_SEP
+ // to construct heap model)
+ d_tc->postProcessModel(d_incomplete.get());
}
} catch(const theory::Interrupted&) {
Trace("theory") << "TheoryEngine::check() => interrupted" << endl;
@@ -566,81 +601,8 @@ void TheoryEngine::check(Theory::Effort effort) {
}
}
-void TheoryEngine::combineTheories() {
-
- Trace("combineTheories") << "TheoryEngine::combineTheories()" << endl;
-
- TimerStat::CodeTimer combineTheoriesTimer(d_combineTheoriesTime);
-
- // Care graph we'll be building
- CareGraph careGraph;
-
-#ifdef CVC4_FOR_EACH_THEORY_STATEMENT
-#undef CVC4_FOR_EACH_THEORY_STATEMENT
-#endif
-#define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \
- if (theory::TheoryTraits<THEORY>::isParametric && d_logicInfo.isTheoryEnabled(THEORY)) { \
- theoryOf(THEORY)->getCareGraph(&careGraph); \
- }
-
- // Call on each parametric theory to give us its care graph
- CVC4_FOR_EACH_THEORY;
-
- Trace("combineTheories") << "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();
- CareGraph::const_iterator care_it_end = careGraph.end();
-
- for (; care_it != care_it_end; ++ care_it) {
- const CarePair& carePair = *care_it;
-
- Debug("combineTheories")
- << "TheoryEngine::combineTheories(): checking " << carePair.d_a << " = "
- << carePair.d_b << " from " << carePair.d_theory << endl;
-
- Assert(d_sharedTerms.isShared(carePair.d_a) || carePair.d_a.isConst());
- Assert(d_sharedTerms.isShared(carePair.d_b) || carePair.d_b.isConst());
-
- // The equality in question (order for no repetition)
- Node equality = carePair.d_a.eqNode(carePair.d_b);
- // EqualityStatus es = getEqualityStatus(carePair.d_a, carePair.d_b);
- // Debug("combineTheories") << "TheoryEngine::combineTheories(): " <<
- // (es == EQUALITY_TRUE_AND_PROPAGATED ? "EQUALITY_TRUE_AND_PROPAGATED" :
- // es == EQUALITY_FALSE_AND_PROPAGATED ? "EQUALITY_FALSE_AND_PROPAGATED" :
- // es == EQUALITY_TRUE ? "EQUALITY_TRUE" :
- // es == EQUALITY_FALSE ? "EQUALITY_FALSE" :
- // es == EQUALITY_TRUE_IN_MODEL ? "EQUALITY_TRUE_IN_MODEL" :
- // es == EQUALITY_FALSE_IN_MODEL ? "EQUALITY_FALSE_IN_MODEL" :
- // es == EQUALITY_UNKNOWN ? "EQUALITY_UNKNOWN" :
- // "Unexpected case") << endl;
-
- // We need to split on it
- Debug("combineTheories") << "TheoryEngine::combineTheories(): requesting a split " << endl;
-
- lemma(equality.orNode(equality.notNode()),
- RULE_INVALID,
- false,
- false,
- false,
- carePair.d_theory);
-
- // This code is supposed to force preference to follow what the theory models already have
- // but it doesn't seem to make a big difference - need to explore more -Clark
- // if (true) {
- // if (es == EQUALITY_TRUE || es == EQUALITY_TRUE_IN_MODEL) {
- Node e = ensureLiteral(equality);
- d_propEngine->requirePhase(e, true);
- // }
- // else if (es == EQUALITY_FALSE_IN_MODEL) {
- // Node e = ensureLiteral(equality);
- // d_propEngine->requirePhase(e, false);
- // }
- // }
- }
-}
-
-void TheoryEngine::propagate(Theory::Effort effort) {
+void TheoryEngine::propagate(Theory::Effort effort)
+{
// Reset the interrupt flag
d_interrupted = false;
@@ -658,25 +620,6 @@ void TheoryEngine::propagate(Theory::Effort effort) {
// Propagate for each theory using the statement above
CVC4_FOR_EACH_THEORY;
-
- if(Dump.isOn("missed-t-propagations")) {
- for(unsigned i = 0; i < d_possiblePropagations.size(); ++i) {
- Node atom = d_possiblePropagations[i];
- bool value;
- 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());
- }
- }
- }
}
Node TheoryEngine::getNextDecisionRequest()
@@ -724,99 +667,37 @@ bool TheoryEngine::properConflict(TNode conflict) const {
return true;
}
-bool TheoryEngine::properPropagation(TNode lit) const {
- if(!getPropEngine()->isSatLiteral(lit)) {
- return false;
- }
- bool b;
- return !getPropEngine()->hasValue(lit, b);
-}
-
-bool TheoryEngine::properExplanation(TNode node, TNode expl) const {
- // Explanation must be either a conjunction of true literals that have true SAT values already
- // or a singled literal that has a true SAT value already.
- if (expl.getKind() == kind::AND) {
- for (unsigned i = 0; i < expl.getNumChildren(); ++ i) {
- bool value;
- if (!d_propEngine->hasValue(expl[i], value) || !value) {
- return false;
- }
- }
- } else {
- bool value;
- return d_propEngine->hasValue(expl, value) && value;
- }
- return true;
+TheoryModel* TheoryEngine::getModel()
+{
+ Assert(d_tc != nullptr);
+ TheoryModel* m = d_tc->getModel();
+ Assert(m != nullptr);
+ return m;
}
-bool TheoryEngine::collectModelInfo(theory::TheoryModel* m)
+TheoryModel* TheoryEngine::getBuiltModel()
{
- //have shared term engine collectModelInfo
- // d_sharedTerms.collectModelInfo( m );
- // Consult each active theory to get all relevant information
- // concerning the model.
- for(TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST; ++theoryId) {
- if(d_logicInfo.isTheoryEnabled(theoryId)) {
- Trace("model-builder") << " CollectModelInfo on theory: " << theoryId << endl;
- if (!d_theoryTable[theoryId]->collectModelInfo(m))
- {
- return false;
- }
- }
- }
- Trace("model-builder") << " CollectModelInfo boolean variables" << std::endl;
- // Get the Boolean variables
- vector<TNode> boolVars;
- d_propEngine->getBooleanVariables(boolVars);
- vector<TNode>::iterator it, iend = boolVars.end();
- bool hasValue, value;
- for (it = boolVars.begin(); it != iend; ++it) {
- TNode var = *it;
- hasValue = d_propEngine->hasValue(var, value);
- // TODO: Assert that hasValue is true?
- if (!hasValue) {
- Trace("model-builder-assertions")
- << " has no value : " << var << std::endl;
- value = false;
- }
- Trace("model-builder-assertions") << "(assert" << (value ? " " : " (not ") << var << (value ? ");" : "));") << endl;
- if (!m->assertPredicate(var, value))
- {
- return false;
- }
+ Assert(d_tc != nullptr);
+ // If this method was called, we should be in SAT mode, and produceModels
+ // should be true.
+ AlwaysAssert(options::produceModels());
+ if (!d_inSatMode)
+ {
+ // not available, perhaps due to interuption.
+ return nullptr;
}
- return true;
-}
-
-void TheoryEngine::postProcessModel( theory::TheoryModel* m ){
- for(TheoryId theoryId = theory::THEORY_FIRST; theoryId < theory::THEORY_LAST; ++theoryId) {
- if(d_logicInfo.isTheoryEnabled(theoryId)) {
- Trace("model-builder-debug") << " PostProcessModel on theory: " << theoryId << endl;
- d_theoryTable[theoryId]->postProcessModel( m );
- }
+ // must build model at this point
+ if (!d_tc->buildModel())
+ {
+ return nullptr;
}
+ return d_tc->getModel();
}
-TheoryModel* TheoryEngine::getModel() {
- return d_curr_model;
-}
-
-TheoryModel* TheoryEngine::getBuiltModel()
+bool TheoryEngine::buildModel()
{
- if (!d_curr_model->isBuilt())
- {
- // If this method was called, we should be in SAT mode, and produceModels
- // should be true.
- AlwaysAssert(options::produceModels());
- if (!d_inSatMode)
- {
- // not available, perhaps due to interuption.
- return nullptr;
- }
- // must build model at this point
- d_curr_model_builder->buildModel(d_curr_model);
- }
- return d_curr_model;
+ Assert(d_tc != nullptr);
+ return d_tc->buildModel();
}
bool TheoryEngine::getSynthSolutions(
@@ -922,6 +803,16 @@ void TheoryEngine::ppStaticLearn(TNode in, NodeBuilder<>& learned) {
CVC4_FOR_EACH_THEORY;
}
+bool TheoryEngine::isRelevant(Node lit) const
+{
+ if (d_relManager != nullptr)
+ {
+ return d_relManager->isRelevant(lit);
+ }
+ // otherwise must assume its relevant
+ return true;
+}
+
void TheoryEngine::shutdown() {
// Set this first; if a Theory shutdown() throws an exception,
// at least the destruction of the TheoryEngine won't confound
@@ -934,14 +825,15 @@ void TheoryEngine::shutdown() {
theoryOf(theoryId)->shutdown();
}
}
-
- d_tpp.clearCache();
}
-theory::Theory::PPAssertStatus TheoryEngine::solve(TNode literal, SubstitutionMap& substitutionOut) {
+theory::Theory::PPAssertStatus TheoryEngine::solve(
+ TrustNode tliteral, TrustSubstitutionMap& substitutionOut)
+{
// Reset the interrupt flag
d_interrupted = false;
+ TNode literal = tliteral.getNode();
TNode atom = literal.getKind() == kind::NOT ? literal[0] : literal;
Trace("theory::solve") << "TheoryEngine::solve(" << literal << "): solving with " << theoryOf(atom)->getId() << endl;
@@ -956,14 +848,14 @@ theory::Theory::PPAssertStatus TheoryEngine::solve(TNode literal, SubstitutionMa
throw LogicException(ss.str());
}
- Theory::PPAssertStatus solveStatus = theoryOf(atom)->ppAssert(literal, substitutionOut);
+ Theory::PPAssertStatus solveStatus =
+ theoryOf(atom)->ppAssert(tliteral, substitutionOut);
Trace("theory::solve") << "TheoryEngine::solve(" << literal << ") => " << solveStatus << endl;
return solveStatus;
}
-void TheoryEngine::preprocessStart() { d_tpp.clearCache(); }
-
-Node TheoryEngine::preprocess(TNode assertion) {
+TrustNode TheoryEngine::preprocess(TNode assertion)
+{
return d_tpp.theoryPreprocess(assertion);
}
@@ -976,6 +868,10 @@ void TheoryEngine::notifyPreprocessedAssertions(
theoryOf(theoryId)->ppNotifyAssertions(assertions);
}
}
+ if (d_relManager != nullptr)
+ {
+ d_relManager->notifyPreprocessedAssertions(assertions);
+ }
}
bool TheoryEngine::markPropagation(TNode assertion, TNode originalAssertion, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId) {
@@ -1052,18 +948,17 @@ void TheoryEngine::assertToTheory(TNode assertion, TNode originalAssertion, theo
return;
}
- // Polarity of the assertion
- bool polarity = assertion.getKind() != kind::NOT;
-
- // Atom of the assertion
- TNode atom = polarity ? assertion : assertion[0];
-
// 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 `" << atom << "'";
+ Assert(assertion.getKind() == kind::EQUAL
+ || (assertion.getKind() == kind::NOT
+ && assertion[0].getKind() == kind::EQUAL))
+ << "atom should be an EQUALity, not `" << assertion << "'";
if (markPropagation(assertion, originalAssertion, toTheoryId, fromTheoryId)) {
- d_sharedTerms.assertEquality(atom, polarity, assertion);
+ // assert to the shared solver
+ bool polarity = assertion.getKind() != kind::NOT;
+ TNode atom = polarity ? assertion : assertion[0];
+ d_sharedSolver->assertSharedEquality(atom, polarity, assertion);
}
return;
}
@@ -1104,7 +999,9 @@ void TheoryEngine::assertToTheory(TNode assertion, TNode originalAssertion, theo
return;
}
- Assert(atom.getKind() == kind::EQUAL);
+ Assert(assertion.getKind() == kind::EQUAL
+ || (assertion.getKind() == kind::NOT
+ && assertion[0].getKind() == kind::EQUAL));
// Normalize
Node normalizedLiteral = Rewriter::rewrite(assertion);
@@ -1114,8 +1011,10 @@ void TheoryEngine::assertToTheory(TNode assertion, TNode originalAssertion, theo
if (!normalizedLiteral.getConst<bool>()) {
// Mark the propagation for explanations
if (markPropagation(normalizedLiteral, originalAssertion, toTheoryId, fromTheoryId)) {
+ // special case, trust node has no proof generator
+ TrustNode trnn = TrustNode::mkTrustConflict(normalizedLiteral);
// Get the explanation (conflict will figure out where it came from)
- conflict(normalizedLiteral, toTheoryId);
+ conflict(trnn, toTheoryId);
} else {
Unreachable();
}
@@ -1151,23 +1050,8 @@ void TheoryEngine::assertFact(TNode literal)
TNode atom = polarity ? literal : literal[0];
if (d_logicInfo.isSharingEnabled()) {
-
// If any shared terms, it's time to do sharing work
- if (d_sharedTerms.hasSharedTerms(atom)) {
- // Notify the theories the shared terms
- SharedTermsDatabase::shared_terms_iterator it = d_sharedTerms.begin(atom);
- SharedTermsDatabase::shared_terms_iterator it_end = d_sharedTerms.end(atom);
- for (; it != it_end; ++ it) {
- TNode term = *it;
- Theory::Set theories = d_sharedTerms.getTheoriesToNotify(atom, term);
- for (TheoryId id = THEORY_FIRST; id != THEORY_LAST; ++ id) {
- if (Theory::setContains(id, theories)) {
- theoryOf(id)->addSharedTermInternal(term);
- }
- }
- d_sharedTerms.markNotified(term, theories);
- }
- }
+ d_sharedSolver->preNotifySharedFact(atom);
// If it's an equality, assert it to the shared term manager, even though the terms are not
// yet shared. As the terms become shared later, the shared terms manager will then add them
@@ -1175,7 +1059,8 @@ void TheoryEngine::assertFact(TNode literal)
if (atom.getKind() == kind::EQUAL) {
// Assert it to the the owning theory
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
+ // Shared terms manager will assert to interested theories directly, as
+ // the terms become shared
assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ THEORY_SAT_SOLVER);
// Now, let's check for any atom triggers from lemmas
@@ -1201,7 +1086,6 @@ void TheoryEngine::assertFact(TNode literal)
}
bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) {
-
Debug("theory::propagate") << "TheoryEngine::propagate(" << literal << ", " << theory << ")" << endl;
Trace("dtview::prop") << std::string(d_context->getLevel(), ' ')
@@ -1209,14 +1093,6 @@ bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) {
// spendResource();
- if(Dump.isOn("t-propagations")) {
- Dump("t-propagations") << CommentCommand("negation of theory propagation: expect valid")
- << QueryCommand(literal.toExpr());
- }
- if(Dump.isOn("missed-t-propagations")) {
- d_hasPropagated.insert(literal);
- }
-
// Get the atom
bool polarity = literal.getKind() != kind::NOT;
TNode atom = polarity ? literal : literal[0];
@@ -1231,23 +1107,6 @@ bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) {
assertToTheory(literal, literal, /* to */ THEORY_BUILTIN, /* from */ theory);
}
} else {
- // We could be propagating a unit-clause lemma. In this case, we need to provide a
- // recipe.
- // TODO: Consider putting this someplace else? This is the only refence to the proof
- // manager in this class.
-
- PROOF({
- LemmaProofRecipe proofRecipe;
- proofRecipe.addBaseAssertion(literal);
-
- Node emptyNode;
- LemmaProofRecipe::ProofStep proofStep(theory, emptyNode);
- proofStep.addAssertion(literal);
- proofRecipe.addStep(proofStep);
-
- ProofManager::getCnfProof()->setProofRecipe(&proofRecipe);
- });
-
// Just send off to the SAT solver
Assert(d_propEngine->isSatLiteral(literal));
assertToTheory(literal, literal, /* to */ THEORY_SAT_SOLVER, /* from */ theory);
@@ -1258,17 +1117,45 @@ bool TheoryEngine::propagate(TNode literal, theory::TheoryId theory) {
const LogicInfo& TheoryEngine::getLogicInfo() const { return d_logicInfo; }
+bool TheoryEngine::getSepHeapTypes(TypeNode& locType, TypeNode& dataType) const
+{
+ if (d_sepLocType.isNull())
+ {
+ return false;
+ }
+ locType = d_sepLocType;
+ dataType = d_sepDataType;
+ return true;
+}
+
+void TheoryEngine::declareSepHeap(TypeNode locT, TypeNode dataT)
+{
+ Theory* tsep = theoryOf(THEORY_SEP);
+ if (tsep == nullptr)
+ {
+ Assert(false) << "TheoryEngine::declareSepHeap called without the "
+ "separation logic theory enabled";
+ return;
+ }
+
+ // Definition of the statement that is to be run by every theory
+#ifdef CVC4_FOR_EACH_THEORY_STATEMENT
+#undef CVC4_FOR_EACH_THEORY_STATEMENT
+#endif
+#define CVC4_FOR_EACH_THEORY_STATEMENT(THEORY) \
+ theoryOf(THEORY)->declareSepHeap(locT, dataT);
+
+ // notify each theory using the statement above
+ CVC4_FOR_EACH_THEORY;
+
+ // remember the types we have set
+ d_sepLocType = locT;
+ d_sepDataType = dataT;
+}
+
theory::EqualityStatus TheoryEngine::getEqualityStatus(TNode a, TNode b) {
Assert(a.getType().isComparableTo(b.getType()));
- if (d_sharedTerms.isShared(a) && d_sharedTerms.isShared(b)) {
- if (d_sharedTerms.areEqual(a,b)) {
- return EQUALITY_TRUE_AND_PROPAGATED;
- }
- else if (d_sharedTerms.areDisequal(a,b)) {
- return EQUALITY_FALSE_AND_PROPAGATED;
- }
- }
- return theoryOf(Theory::theoryOf(a.getType()))->getEqualityStatus(a, b);
+ return d_sharedSolver->getEqualityStatus(a, b);
}
Node TheoryEngine::getModelValue(TNode var) {
@@ -1277,17 +1164,27 @@ Node TheoryEngine::getModelValue(TNode var) {
// the model value of a constant must be itself
return var;
}
- Assert(d_sharedTerms.isShared(var));
+ Assert(d_sharedSolver->isShared(var));
return theoryOf(Theory::theoryOf(var.getType()))->getModelValue(var);
}
Node TheoryEngine::ensureLiteral(TNode n) {
- Debug("ensureLiteral") << "rewriting: " << n << std::endl;
+ Trace("ensureLiteral") << "ensureLiteral rewriting: " << n << std::endl;
Node rewritten = Rewriter::rewrite(n);
- Debug("ensureLiteral") << " got: " << rewritten << std::endl;
- Node preprocessed = preprocess(rewritten);
- Debug("ensureLiteral") << "preprocessed: " << preprocessed << std::endl;
+ Trace("ensureLiteral") << " got: " << rewritten << std::endl;
+ std::vector<TrustNode> newLemmas;
+ std::vector<Node> newSkolems;
+ TrustNode tpn = d_tpp.preprocess(n, newLemmas, newSkolems, true);
+ // send lemmas corresponding to the skolems introduced by preprocessing n
+ for (const TrustNode& tnl : newLemmas)
+ {
+ Trace("ensureLiteral") << " lemma: " << tnl.getNode() << std::endl;
+ lemma(tnl, LemmaProperty::NONE);
+ }
+ Node preprocessed = tpn.isNull() ? rewritten : tpn.getNode();
+ Trace("ensureLiteral") << "ensureLiteral preprocessed: " << preprocessed
+ << std::endl;
d_propEngine->ensureLiteral(preprocessed);
return preprocessed;
}
@@ -1319,14 +1216,6 @@ void TheoryEngine::getInstantiatedQuantifiedFormulas( std::vector< Node >& qs )
}
}
-void TheoryEngine::getInstantiations( Node q, std::vector< Node >& insts ) {
- if( d_quantEngine ){
- d_quantEngine->getInstantiations( q, insts );
- }else{
- Assert(false);
- }
-}
-
void TheoryEngine::getInstantiationTermVectors( Node q, std::vector< std::vector< Node > >& tvecs ) {
if( d_quantEngine ){
d_quantEngine->getInstantiationTermVectors( q, tvecs );
@@ -1335,14 +1224,6 @@ void TheoryEngine::getInstantiationTermVectors( Node q, std::vector< std::vector
}
}
-void TheoryEngine::getInstantiations( std::map< Node, std::vector< Node > >& insts ) {
- if( d_quantEngine ){
- d_quantEngine->getInstantiations( insts );
- }else{
- Assert(false);
- }
-}
-
void TheoryEngine::getInstantiationTermVectors( std::map< Node, std::vector< std::vector< Node > > >& insts ) {
if( d_quantEngine ){
d_quantEngine->getInstantiationTermVectors( insts );
@@ -1351,104 +1232,45 @@ void TheoryEngine::getInstantiationTermVectors( std::map< Node, std::vector< std
}
}
-Node TheoryEngine::getInstantiatedConjunction( Node q ) {
- if( d_quantEngine ){
- return d_quantEngine->getInstantiatedConjunction( q );
- }else{
- Assert(false);
- return Node::null();
- }
-}
-
-
-static Node mkExplanation(const std::vector<NodeTheoryPair>& explanation) {
-
- std::set<TNode> all;
- for (unsigned i = 0; i < explanation.size(); ++ i) {
- Assert(explanation[i].d_theory == THEORY_SAT_SOLVER);
- all.insert(explanation[i].d_node);
- }
-
- if (all.size() == 0) {
- // Normalize to true
- return NodeManager::currentNM()->mkConst<bool>(true);
- }
-
- if (all.size() == 1) {
- // All the same, or just one
- return explanation[0].d_node;
- }
-
- NodeBuilder<> conjunction(kind::AND);
- std::set<TNode>::const_iterator it = all.begin();
- std::set<TNode>::const_iterator it_end = all.end();
- while (it != it_end) {
- conjunction << *it;
- ++ it;
- }
-
- return conjunction;
-}
-
-Node TheoryEngine::getExplanationAndRecipe(TNode node, LemmaProofRecipe* proofRecipe) {
- Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << "): current propagation index = " << d_propagationMapTimestamp << endl;
-
+TrustNode TheoryEngine::getExplanation(TNode node)
+{
+ Debug("theory::explain") << "TheoryEngine::getExplanation(" << node
+ << "): current propagation index = "
+ << d_propagationMapTimestamp << endl;
bool polarity = node.getKind() != kind::NOT;
TNode atom = polarity ? node : node[0];
// If we're not in shared mode, explanations are simple
- if (!d_logicInfo.isSharingEnabled()) {
- Debug("theory::explain") << "TheoryEngine::getExplanation: sharing is NOT enabled. "
- << " Responsible theory is: "
- << theoryOf(atom)->getId() << std::endl;
+ if (!d_logicInfo.isSharingEnabled())
+ {
+ Debug("theory::explain")
+ << "TheoryEngine::getExplanation: sharing is NOT enabled. "
+ << " Responsible theory is: " << theoryOf(atom)->getId() << std::endl;
TrustNode texplanation = theoryOf(atom)->explain(node);
Node explanation = texplanation.getNode();
- Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << endl;
- PROOF({
- if(proofRecipe) {
- Node emptyNode;
- LemmaProofRecipe::ProofStep proofStep(theoryOf(atom)->getId(), emptyNode);
- proofStep.addAssertion(node);
- proofRecipe->addBaseAssertion(node);
-
- if (explanation.getKind() == kind::AND) {
- // If the explanation is a conjunction, the recipe for the corresponding lemma is
- // the negation of its conjuncts.
- Node flat = flattenAnd(explanation);
- for (unsigned i = 0; i < flat.getNumChildren(); ++i) {
- if (flat[i].isConst() && flat[i].getConst<bool>()) {
- ++ i;
- continue;
- }
- if (flat[i].getKind() == kind::NOT &&
- flat[i][0].isConst() && !flat[i][0].getConst<bool>()) {
- ++ i;
- continue;
- }
- Debug("theory::explain") << "TheoryEngine::getExplanationAndRecipe: adding recipe assertion: "
- << flat[i].negate() << std::endl;
- proofStep.addAssertion(flat[i].negate());
- proofRecipe->addBaseAssertion(flat[i].negate());
- }
- } else {
- // The recipe for proving it is by negating it. "True" is not an acceptable reason.
- if (!((explanation.isConst() && explanation.getConst<bool>()) ||
- (explanation.getKind() == kind::NOT &&
- explanation[0].isConst() && !explanation[0].getConst<bool>()))) {
- proofStep.addAssertion(explanation.negate());
- proofRecipe->addBaseAssertion(explanation.negate());
- }
- }
-
- proofRecipe->addStep(proofStep);
- }
- });
-
- return explanation;
+ Debug("theory::explain") << "TheoryEngine::getExplanation(" << node
+ << ") => " << explanation << endl;
+ if (isProofEnabled())
+ {
+ texplanation.debugCheckClosed(
+ "te-proof-exp", "texplanation no share", false);
+ // check if no generator, if so, add THEORY_LEMMA
+ if (texplanation.getGenerator() == nullptr)
+ {
+ Node proven = texplanation.getProven();
+ TheoryId tid = theoryOf(atom)->getId();
+ Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(tid);
+ d_lazyProof->addStep(proven, PfRule::THEORY_LEMMA, {}, {proven, tidn});
+ texplanation =
+ TrustNode::mkTrustPropExp(node, explanation, d_lazyProof.get());
+ }
+ }
+ return texplanation;
}
- Debug("theory::explain") << "TheoryEngine::getExplanation: sharing IS enabled" << std::endl;
+ Debug("theory::explain") << "TheoryEngine::getExplanation: sharing IS enabled"
+ << std::endl;
// Initial thing to explain
NodeTheoryPair toExplain(node, THEORY_SAT_SOLVER, d_propagationMapTimestamp);
@@ -1459,31 +1281,14 @@ Node TheoryEngine::getExplanationAndRecipe(TNode node, LemmaProofRecipe* proofRe
<< "TheoryEngine::getExplanation: explainer for node "
<< nodeExplainerPair.d_node
<< " is theory: " << nodeExplainerPair.d_theory << std::endl;
- TheoryId explainer = nodeExplainerPair.d_theory;
// Create the workplace for explanations
- std::vector<NodeTheoryPair> explanationVector;
- explanationVector.push_back(d_propagationMap[toExplain]);
+ std::vector<NodeTheoryPair> vec{d_propagationMap[toExplain]};
// Process the explanation
- if (proofRecipe) {
- Node emptyNode;
- LemmaProofRecipe::ProofStep proofStep(explainer, emptyNode);
- proofStep.addAssertion(node);
- proofRecipe->addStep(proofStep);
- proofRecipe->addBaseAssertion(node);
- }
-
- getExplanation(explanationVector, proofRecipe);
- Node explanation = mkExplanation(explanationVector);
-
- Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => " << explanation << endl;
-
- return explanation;
-}
-
-Node TheoryEngine::getExplanation(TNode node) {
- LemmaProofRecipe *dontCareRecipe = NULL;
- return getExplanationAndRecipe(node, dontCareRecipe);
+ TrustNode texplanation = getExplanation(vec);
+ Debug("theory::explain") << "TheoryEngine::getExplanation(" << node << ") => "
+ << texplanation.getNode() << endl;
+ return texplanation;
}
struct AtomsCollect {
@@ -1584,14 +1389,40 @@ void TheoryEngine::ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::The
}
}
-theory::LemmaStatus TheoryEngine::lemma(TNode node,
- ProofRule rule,
- bool negated,
- bool removable,
- bool preprocess,
- theory::TheoryId atomsTo) {
+theory::LemmaStatus TheoryEngine::lemma(theory::TrustNode tlemma,
+ theory::LemmaProperty p,
+ theory::TheoryId atomsTo,
+ theory::TheoryId from)
+{
// For resource-limiting (also does a time check).
// spendResource();
+ Assert(tlemma.getKind() == TrustNodeKind::LEMMA
+ || tlemma.getKind() == TrustNodeKind::CONFLICT);
+ // get the node
+ Node node = tlemma.getNode();
+ Node lemma = tlemma.getProven();
+ Trace("te-lemma") << "Lemma, input: " << lemma << std::endl;
+
+ Assert(!expr::hasFreeVar(lemma));
+
+ // when proofs are enabled, we ensure the trust node has a generator by
+ // adding a trust step to the lazy proof maintained by this class
+ if (isProofEnabled())
+ {
+ // ensure proof: set THEORY_LEMMA if no generator is provided
+ if (tlemma.getGenerator() == nullptr)
+ {
+ // internal lemmas should have generators
+ Assert(from != THEORY_LAST);
+ // add theory lemma step to proof
+ Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(from);
+ d_lazyProof->addStep(lemma, PfRule::THEORY_LEMMA, {}, {lemma, tidn});
+ // update the trust node
+ tlemma = TrustNode::mkTrustLemma(lemma, d_lazyProof.get());
+ }
+ // ensure closed
+ tlemma.debugCheckClosed("te-proof-debug", "TheoryEngine::lemma_initial");
+ }
// Do we need to check atoms
if (atomsTo != theory::THEORY_LAST) {
@@ -1602,29 +1433,110 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node,
}
if(Dump.isOn("t-lemmas")) {
- Node n = node;
- if (!negated) {
- n = node.negate();
+ // we dump the negation of the lemma, to show validity of the lemma
+ Node n = lemma.negate();
+ const Printer& printer = d_outMgr.getPrinter();
+ std::ostream& out = d_outMgr.getDumpOut();
+ printer.toStreamCmdComment(out, "theory lemma: expect valid");
+ printer.toStreamCmdCheckSat(out, n);
+ }
+ bool removable = isLemmaPropertyRemovable(p);
+ bool preprocess = isLemmaPropertyPreprocess(p);
+
+ // ensure closed
+ tlemma.debugCheckClosed("te-proof-debug", "TheoryEngine::lemma_initial");
+
+ // call preprocessor
+ std::vector<TrustNode> newLemmas;
+ std::vector<Node> newSkolems;
+ TrustNode tplemma =
+ d_tpp.preprocess(lemma, newLemmas, newSkolems, preprocess);
+ // the preprocessed lemma
+ Node lemmap;
+ if (tplemma.isNull())
+ {
+ lemmap = lemma;
+ }
+ else
+ {
+ Assert(tplemma.getKind() == TrustNodeKind::REWRITE);
+ lemmap = tplemma.getNode();
+
+ // must update the trust lemma
+ if (lemmap != lemma)
+ {
+ // process the preprocessing
+ if (isProofEnabled())
+ {
+ Assert(d_lazyProof != nullptr);
+ // add the original proof to the lazy proof
+ d_lazyProof->addLazyStep(tlemma.getProven(), tlemma.getGenerator());
+ // only need to do anything if lemmap changed in a non-trivial way
+ if (!CDProof::isSame(lemmap, lemma))
+ {
+ d_lazyProof->addLazyStep(tplemma.getProven(),
+ tplemma.getGenerator(),
+ PfRule::PREPROCESS_LEMMA,
+ true,
+ "TheoryEngine::lemma_pp");
+ // ---------- from d_lazyProof -------------- from theory preprocess
+ // lemma lemma = lemmap
+ // ------------------------------------------ EQ_RESOLVE
+ // lemmap
+ std::vector<Node> pfChildren;
+ pfChildren.push_back(lemma);
+ pfChildren.push_back(tplemma.getProven());
+ d_lazyProof->addStep(lemmap, PfRule::EQ_RESOLVE, pfChildren, {});
+ }
+ }
+ tlemma = TrustNode::mkTrustLemma(lemmap, d_lazyProof.get());
}
- Dump("t-lemmas") << CommentCommand("theory lemma: expect valid")
- << CheckSatCommand(n.toExpr());
}
- // the assertion pipeline storing the lemmas
+ // must use an assertion pipeline due to decision engine below
AssertionPipeline lemmas;
- // call preprocessor
- d_tpp.preprocess(node, lemmas, preprocess);
- // assert lemmas to prop engine
- for (size_t i = 0, lsize = lemmas.size(); i < lsize; ++i)
+ // make the assertion pipeline
+ lemmas.push_back(lemmap);
+ lemmas.updateRealAssertionsEnd();
+ Assert(newSkolems.size() == newLemmas.size());
+ for (size_t i = 0, nsize = newLemmas.size(); i < nsize; i++)
+ {
+ // store skolem mapping here
+ IteSkolemMap& imap = lemmas.getIteSkolemMap();
+ imap[newSkolems[i]] = lemmas.size();
+ lemmas.push_back(newLemmas[i].getNode());
+ }
+
+ // If specified, we must add this lemma to the set of those that need to be
+ // justified, where note we pass all auxiliary lemmas in lemmas, since these
+ // by extension must be justified as well.
+ if (d_relManager != nullptr && isLemmaPropertyNeedsJustify(p))
+ {
+ d_relManager->notifyPreprocessedAssertions(lemmas.ref());
+ }
+
+ // do final checks on the lemmas we are about to send
+ if (isProofEnabled())
{
- d_propEngine->assertLemma(
- lemmas[i], i == 0 && negated, removable, rule, node);
+ Assert(tlemma.getGenerator() != nullptr);
+ // ensure closed, make the proof node eagerly here to debug
+ tlemma.debugCheckClosed("te-proof-debug", "TheoryEngine::lemma");
+ for (size_t i = 0, lsize = newLemmas.size(); i < lsize; ++i)
+ {
+ Assert(newLemmas[i].getGenerator() != nullptr);
+ newLemmas[i].debugCheckClosed("te-proof-debug",
+ "TheoryEngine::lemma_new");
+ }
}
- // WARNING: Below this point don't assume lemmas[0] to be not negated.
- if(negated) {
- lemmas.replace(0, lemmas[0].notNode());
- negated = false;
+ // now, send the lemmas to the prop engine
+ Trace("te-lemma") << "Lemma, output: " << tlemma.getProven() << std::endl;
+ d_propEngine->assertLemma(tlemma.getProven(), false, removable);
+ for (size_t i = 0, lsize = newLemmas.size(); i < lsize; ++i)
+ {
+ Trace("te-lemma") << "Lemma, new lemma: " << newLemmas[i].getProven()
+ << std::endl;
+ d_propEngine->assertLemma(newLemmas[i].getProven(), false, removable);
}
// assert to decision engine
@@ -1647,9 +1559,16 @@ theory::LemmaStatus TheoryEngine::lemma(TNode node,
return theory::LemmaStatus(retLemma, d_userContext->getLevel());
}
-void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) {
-
- Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << ")" << endl;
+void TheoryEngine::conflict(theory::TrustNode tconflict, TheoryId theoryId)
+{
+ Assert(tconflict.getKind() == TrustNodeKind::CONFLICT);
+ TNode conflict = tconflict.getNode();
+ Trace("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", "
+ << theoryId << ")" << endl;
+ Trace("te-proof-debug") << "Check closed conflict" << std::endl;
+ // doesn't require proof generator, yet, since THEORY_LEMMA is added below
+ tconflict.debugCheckClosed(
+ "te-proof-debug", "TheoryEngine::conflict_initial", false);
Trace("dtview::conflict") << ":THEORY-CONFLICT: " << conflict << std::endl;
@@ -1657,136 +1576,119 @@ void TheoryEngine::conflict(TNode conflict, TheoryId theoryId) {
d_inConflict = true;
if(Dump.isOn("t-conflicts")) {
- Dump("t-conflicts") << CommentCommand("theory conflict: expect unsat")
- << CheckSatCommand(conflict.toExpr());
+ const Printer& printer = d_outMgr.getPrinter();
+ std::ostream& out = d_outMgr.getDumpOut();
+ printer.toStreamCmdComment(out, "theory conflict: expect unsat");
+ printer.toStreamCmdCheckSat(out, conflict);
}
- LemmaProofRecipe* proofRecipe = NULL;
- PROOF({
- proofRecipe = new LemmaProofRecipe;
- Node emptyNode;
- LemmaProofRecipe::ProofStep proofStep(theoryId, emptyNode);
-
- if (conflict.getKind() == kind::AND) {
- for (unsigned i = 0; i < conflict.getNumChildren(); ++i) {
- proofStep.addAssertion(conflict[i].negate());
- }
- } else {
- proofStep.addAssertion(conflict.negate());
- }
-
- proofRecipe->addStep(proofStep);
- });
-
// In the multiple-theories case, we need to reconstruct the conflict
if (d_logicInfo.isSharingEnabled()) {
// Create the workplace for explanations
- std::vector<NodeTheoryPair> explanationVector;
- explanationVector.push_back(NodeTheoryPair(conflict, theoryId, d_propagationMapTimestamp));
+ std::vector<NodeTheoryPair> vec;
+ vec.push_back(
+ NodeTheoryPair(conflict, theoryId, d_propagationMapTimestamp));
// Process the explanation
- getExplanation(explanationVector, proofRecipe);
- PROOF(ProofManager::getCnfProof()->setProofRecipe(proofRecipe));
- Node fullConflict = mkExplanation(explanationVector);
+ TrustNode tncExp = getExplanation(vec);
+ Trace("te-proof-debug")
+ << "Check closed conflict explained with sharing" << std::endl;
+ tncExp.debugCheckClosed("te-proof-debug",
+ "TheoryEngine::conflict_explained_sharing");
+ Node fullConflict = tncExp.getNode();
+
+ if (isProofEnabled())
+ {
+ Trace("te-proof-debug") << "Process conflict: " << conflict << std::endl;
+ Trace("te-proof-debug") << "Conflict " << tconflict << " from "
+ << tconflict.identifyGenerator() << std::endl;
+ Trace("te-proof-debug") << "Explanation " << tncExp << " from "
+ << tncExp.identifyGenerator() << std::endl;
+ Assert(d_lazyProof != nullptr);
+ if (tconflict.getGenerator() != nullptr)
+ {
+ d_lazyProof->addLazyStep(tconflict.getProven(),
+ tconflict.getGenerator());
+ }
+ else
+ {
+ // add theory lemma step
+ Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(theoryId);
+ Node conf = tconflict.getProven();
+ d_lazyProof->addStep(conf, PfRule::THEORY_LEMMA, {}, {conf, tidn});
+ }
+ // store the explicit step, which should come from a different
+ // generator, e.g. d_tepg.
+ Node proven = tncExp.getProven();
+ Assert(tncExp.getGenerator() != d_lazyProof.get());
+ Trace("te-proof-debug") << "add lazy step " << tncExp.identifyGenerator()
+ << " for " << proven << std::endl;
+ d_lazyProof->addLazyStep(proven, tncExp.getGenerator());
+ pfgEnsureClosed(proven,
+ d_lazyProof.get(),
+ "te-proof-debug",
+ "TheoryEngine::conflict_during");
+ Node fullConflictNeg = fullConflict.notNode();
+ std::vector<Node> children;
+ children.push_back(proven);
+ std::vector<Node> args;
+ args.push_back(fullConflictNeg);
+ if (conflict == d_false)
+ {
+ AlwaysAssert(proven == fullConflictNeg);
+ }
+ else
+ {
+ if (fullConflict != conflict)
+ {
+ // ------------------------- explained ---------- from theory
+ // fullConflict => conflict ~conflict
+ // ------------------------------------------ MACRO_SR_PRED_TRANSFORM
+ // ~fullConflict
+ children.push_back(conflict.notNode());
+ args.push_back(mkMethodId(MethodId::SB_LITERAL));
+ d_lazyProof->addStep(
+ fullConflictNeg, PfRule::MACRO_SR_PRED_TRANSFORM, children, args);
+ }
+ }
+ }
+ // pass the processed trust node
+ TrustNode tconf =
+ TrustNode::mkTrustConflict(fullConflict, d_lazyProof.get());
Debug("theory::conflict") << "TheoryEngine::conflict(" << conflict << ", " << theoryId << "): full = " << fullConflict << endl;
Assert(properConflict(fullConflict));
- lemma(fullConflict, RULE_CONFLICT, true, true, false, THEORY_LAST);
-
+ Trace("te-proof-debug")
+ << "Check closed conflict with sharing" << std::endl;
+ tconf.debugCheckClosed("te-proof-debug", "TheoryEngine::conflict:sharing");
+ lemma(tconf, LemmaProperty::REMOVABLE);
} else {
// When only one theory, the conflict should need no processing
Assert(properConflict(conflict));
- PROOF({
- if (conflict.getKind() == kind::AND) {
- // If the conflict is a conjunction, the corresponding lemma is derived by negating
- // its conjuncts.
- for (unsigned i = 0; i < conflict.getNumChildren(); ++i) {
- if (conflict[i].isConst() && conflict[i].getConst<bool>()) {
- ++ i;
- continue;
- }
- if (conflict[i].getKind() == kind::NOT &&
- conflict[i][0].isConst() && !conflict[i][0].getConst<bool>()) {
- ++ i;
- continue;
- }
- proofRecipe->getStep(0)->addAssertion(conflict[i].negate());
- proofRecipe->addBaseAssertion(conflict[i].negate());
- }
- } else {
- proofRecipe->getStep(0)->addAssertion(conflict.negate());
- proofRecipe->addBaseAssertion(conflict.negate());
- }
-
- ProofManager::getCnfProof()->setProofRecipe(proofRecipe);
- });
-
- lemma(conflict, RULE_CONFLICT, true, true, false, THEORY_LAST);
+ // pass the trust node that was sent from the theory
+ lemma(tconflict, LemmaProperty::REMOVABLE, THEORY_LAST, theoryId);
}
-
- PROOF({
- delete proofRecipe;
- proofRecipe = NULL;
- });
}
-void TheoryEngine::staticInitializeBVOptions(
- const std::vector<Node>& assertions)
+theory::TrustNode TheoryEngine::getExplanation(
+ std::vector<NodeTheoryPair>& explanationVector)
{
- bool useSlicer = true;
- if (options::bitvectorEqualitySlicer() == options::BvSlicerMode::ON)
- {
- if (!d_logicInfo.isPure(theory::THEORY_BV) || d_logicInfo.isQuantified())
- throw ModalException(
- "Slicer currently only supports pure QF_BV formulas. Use "
- "--bv-eq-slicer=off");
- if (options::incrementalSolving())
- throw ModalException(
- "Slicer does not currently support incremental mode. Use "
- "--bv-eq-slicer=off");
- if (options::produceModels())
- throw ModalException(
- "Slicer does not currently support model generation. Use "
- "--bv-eq-slicer=off");
- }
- else if (options::bitvectorEqualitySlicer() == options::BvSlicerMode::OFF)
- {
- return;
- }
- else if (options::bitvectorEqualitySlicer() == options::BvSlicerMode::AUTO)
- {
- if ((!d_logicInfo.isPure(theory::THEORY_BV) || d_logicInfo.isQuantified())
- || options::incrementalSolving()
- || options::produceModels())
- return;
-
- bv::utils::TNodeBoolMap cache;
- for (unsigned i = 0; i < assertions.size(); ++i)
- {
- useSlicer = useSlicer && bv::utils::isCoreTerm(assertions[i], cache);
- }
- }
-
- if (useSlicer)
+ Assert(explanationVector.size() == 1);
+ Node conclusion = explanationVector[0].d_node;
+ std::shared_ptr<LazyCDProof> lcp;
+ if (isProofEnabled())
{
- bv::TheoryBV* bv_theory = (bv::TheoryBV*)d_theoryTable[THEORY_BV];
- bv_theory->enableCoreTheorySlicer();
+ Trace("te-proof-exp") << "=== TheoryEngine::getExplanation " << conclusion
+ << std::endl;
+ lcp.reset(new LazyCDProof(
+ d_pnm, nullptr, nullptr, "TheoryEngine::LazyCDProof::getExplanation"));
}
-}
-
-void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector, LemmaProofRecipe* proofRecipe) {
- Assert(explanationVector.size() > 0);
-
unsigned i = 0; // Index of the current literal we are processing
- unsigned j = 0; // Index of the last literal we are keeping
std::unique_ptr<std::set<Node>> inputAssertions = nullptr;
- PROOF({
- if (proofRecipe)
- {
- inputAssertions.reset(
- new std::set<Node>(proofRecipe->getStep(0)->getAssertions()));
- }
- });
+ // the overall explanation
+ std::set<TNode> exp;
+ // vector of trust nodes to explain at the end
+ std::vector<std::pair<TheoryId, TrustNode>> texplains;
// cache of nodes we have already explained by some theory
std::unordered_map<Node, size_t, NodeHashFunction> cache;
@@ -1808,15 +1710,25 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
cache[toExplain.d_node] = toExplain.d_timestamp;
// If a true constant or a negation of a false constant we can ignore it
- if (toExplain.d_node.isConst() && toExplain.d_node.getConst<bool>())
- {
- ++ i;
- continue;
- }
- if (toExplain.d_node.getKind() == kind::NOT && toExplain.d_node[0].isConst()
- && !toExplain.d_node[0].getConst<bool>())
+ if ((toExplain.d_node.isConst() && toExplain.d_node.getConst<bool>())
+ || (toExplain.d_node.getKind() == kind::NOT
+ && toExplain.d_node[0].isConst()
+ && !toExplain.d_node[0].getConst<bool>()))
{
++ i;
+ // if we are building a proof
+ if (lcp != nullptr)
+ {
+ Trace("te-proof-exp")
+ << "- explain " << toExplain.d_node << " trivially..." << std::endl;
+ // ------------------MACRO_SR_PRED_INTRO
+ // toExplain.d_node
+ std::vector<Node> children;
+ std::vector<Node> args;
+ args.push_back(toExplain.d_node);
+ lcp->addStep(
+ toExplain.d_node, PfRule::MACRO_SR_PRED_INTRO, children, args);
+ }
continue;
}
@@ -1824,7 +1736,9 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
if (toExplain.d_theory == THEORY_SAT_SOLVER)
{
Debug("theory::explain") << "\tLiteral came from THEORY_SAT_SOLVER. Kepping it." << endl;
- explanationVector[j++] = explanationVector[i++];
+ exp.insert(explanationVector[i++].d_node);
+ // it will be a free assumption in the proof
+ Trace("te-proof-exp") << "- keep " << toExplain.d_node << std::endl;
continue;
}
@@ -1834,12 +1748,23 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
Debug("theory::explain")
<< "TheoryEngine::explain(): expanding " << toExplain.d_node
<< " got from " << toExplain.d_theory << endl;
- for (unsigned k = 0; k < toExplain.d_node.getNumChildren(); ++k)
+ size_t nchild = toExplain.d_node.getNumChildren();
+ for (size_t k = 0; k < nchild; ++k)
{
NodeTheoryPair newExplain(
toExplain.d_node[k], toExplain.d_theory, toExplain.d_timestamp);
explanationVector.push_back(newExplain);
}
+ if (lcp != nullptr)
+ {
+ Trace("te-proof-exp")
+ << "- AND expand " << toExplain.d_node << std::endl;
+ // delay explanation, use a dummy trust node
+ TrustNode tnAndExp = TrustNode::mkTrustPropExp(
+ toExplain.d_node, toExplain.d_node, nullptr);
+ texplains.push_back(
+ std::pair<TheoryId, TrustNode>(THEORY_LAST, tnAndExp));
+ }
++ i;
continue;
}
@@ -1859,40 +1784,46 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
explanationVector.push_back((*find).second);
++i;
- PROOF({
- if (toExplain.d_node != (*find).second.d_node)
+ if (lcp != nullptr)
+ {
+ if (!CDProof::isSame(toExplain.d_node, (*find).second.d_node))
{
- Debug("pf::explain")
- << "TheoryEngine::getExplanation: Rewrite alert! toAssert = "
- << toExplain.d_node << ", toExplain = " << (*find).second.d_node
- << std::endl;
-
- if (proofRecipe)
- {
- proofRecipe->addRewriteRule(toExplain.d_node,
- (*find).second.d_node);
- }
+ Trace("te-proof-exp")
+ << "- t-explained cached: " << toExplain.d_node << " by "
+ << (*find).second.d_node << std::endl;
+ // delay explanation, use a dummy trust node that says that
+ // (*find).second.d_node explains toExplain.d_node.
+ TrustNode tnRewExp = TrustNode::mkTrustPropExp(
+ toExplain.d_node, (*find).second.d_node, nullptr);
+ texplains.push_back(
+ std::pair<TheoryId, TrustNode>(THEORY_LAST, tnRewExp));
}
- })
-
+ }
continue;
}
}
-
- Node explanation;
- if (toExplain.d_theory == THEORY_BUILTIN)
- {
- explanation = d_sharedTerms.explain(toExplain.d_node);
- Debug("theory::explain") << "\tTerm was propagated by THEORY_BUILTIN. Explanation: " << explanation << std::endl;
- }
- else
+ // It was produced by the theory, so ask for an explanation
+ TrustNode texplanation =
+ d_sharedSolver->explain(toExplain.d_node, toExplain.d_theory);
+ if (lcp != nullptr)
{
- TrustNode texp = theoryOf(toExplain.d_theory)->explain(toExplain.d_node);
- explanation = texp.getNode();
- Debug("theory::explain") << "\tTerm was propagated by owner theory: "
- << theoryOf(toExplain.d_theory)->getId()
- << ". Explanation: " << explanation << std::endl;
+ texplanation.debugCheckClosed("te-proof-exp", "texplanation", false);
+ Trace("te-proof-exp")
+ << "- t-explained[" << toExplain.d_theory << "]: " << toExplain.d_node
+ << " by " << texplanation.getNode() << std::endl;
+ // if not a trivial explanation
+ if (!CDProof::isSame(texplanation.getNode(), toExplain.d_node))
+ {
+ // We add it to the list of theory explanations, to be processed at
+ // the end of this method. We wait to explain here because it may
+ // be that a later explanation may preempt the need for proving this
+ // step. For instance, if the conclusion lit is later added as an
+ // assumption in the final explanation. This avoids cyclic proofs.
+ texplains.push_back(
+ std::pair<TheoryId, TrustNode>(toExplain.d_theory, texplanation));
+ }
}
+ Node explanation = texplanation.getNode();
Debug("theory::explain")
<< "TheoryEngine::explain(): got explanation " << explanation
@@ -1905,61 +1836,143 @@ void TheoryEngine::getExplanation(std::vector<NodeTheoryPair>& explanationVector
explanationVector.push_back(newExplain);
++ i;
+ }
- PROOF({
- if (proofRecipe && inputAssertions)
+ // make the explanation node
+ Node expNode;
+ if (exp.size() == 0)
+ {
+ // Normalize to true
+ expNode = NodeManager::currentNM()->mkConst<bool>(true);
+ }
+ else if (exp.size() == 1)
+ {
+ // All the same, or just one
+ expNode = *exp.begin();
+ }
+ else
+ {
+ NodeBuilder<> conjunction(kind::AND);
+ std::set<TNode>::const_iterator it = exp.begin();
+ std::set<TNode>::const_iterator it_end = exp.end();
+ while (it != it_end)
+ {
+ conjunction << *it;
+ ++it;
+ }
+ expNode = conjunction;
+ }
+ // if we are building a proof, go back through the explanations and
+ // build the proof
+ if (lcp != nullptr)
+ {
+ if (Trace.isOn("te-proof-exp"))
+ {
+ Trace("te-proof-exp") << "Explanation is:" << std::endl;
+ for (const Node& e : exp)
+ {
+ Trace("te-proof-exp") << " " << e << std::endl;
+ }
+ Trace("te-proof-exp") << "=== Replay explanations..." << std::endl;
+ }
+ // Now, go back and add the necessary steps of theory explanations, i.e.
+ // add those that prove things that aren't in the final explanation. We
+ // iterate in reverse order so that most recent steps take priority. This
+ // avoids cyclic proofs in the lazy proof we are building (lcp).
+ for (std::vector<std::pair<TheoryId, TrustNode>>::reverse_iterator
+ it = texplains.rbegin(),
+ itEnd = texplains.rend();
+ it != itEnd;
+ ++it)
+ {
+ TrustNode trn = it->second;
+ Assert(trn.getKind() == TrustNodeKind::PROP_EXP);
+ Node proven = trn.getProven();
+ Assert(proven.getKind() == kind::IMPLIES);
+ Node tConc = proven[1];
+ Trace("te-proof-exp") << "- Process " << trn << std::endl;
+ if (exp.find(tConc) != exp.end())
+ {
+ // already added to proof
+ Trace("te-proof-exp") << "...already added" << std::endl;
+ continue;
+ }
+ Node symTConc = CDProof::getSymmFact(tConc);
+ if (!symTConc.isNull())
{
- // If we're expanding the target node of the explanation (this is the
- // first expansion...), we don't want to add it as a separate proof
- // step. It is already part of the assertions.
- if (!ContainsKey(*inputAssertions, toExplain.d_node))
+ if (exp.find(symTConc) != exp.end())
{
- LemmaProofRecipe::ProofStep proofStep(toExplain.d_theory,
- toExplain.d_node);
- if (explanation.getKind() == kind::AND)
- {
- Node flat = flattenAnd(explanation);
- for (unsigned k = 0; k < flat.getNumChildren(); ++k)
- {
- // If a true constant or a negation of a false constant we can
- // ignore it
- if (!((flat[k].isConst() && flat[k].getConst<bool>())
- || (flat[k].getKind() == kind::NOT && flat[k][0].isConst()
- && !flat[k][0].getConst<bool>())))
- {
- proofStep.addAssertion(flat[k].negate());
- }
- }
- }
- else
- {
- if (!((explanation.isConst() && explanation.getConst<bool>())
- || (explanation.getKind() == kind::NOT
- && explanation[0].isConst()
- && !explanation[0].getConst<bool>())))
- {
- proofStep.addAssertion(explanation.negate());
- }
- }
- proofRecipe->addStep(proofStep);
+ // symmetric direction
+ Trace("te-proof-exp") << "...already added (SYMM)" << std::endl;
+ continue;
}
}
- });
- }
-
- // Keep only the relevant literals
- explanationVector.resize(j);
-
- PROOF({
- if (proofRecipe) {
- // The remaining literals are the base of the proof
- for (unsigned k = 0; k < explanationVector.size(); ++k) {
- proofRecipe->addBaseAssertion(explanationVector[k].d_node.negate());
+ // remember that we've explained this formula, to avoid cycles in lcp
+ exp.insert(tConc);
+ TheoryId ttid = it->first;
+ Node tExp = proven[0];
+ if (ttid == THEORY_LAST)
+ {
+ if (tConc == tExp)
+ {
+ // dummy trust node, do AND expansion
+ Assert(tConc.getKind() == kind::AND);
+ // tConc[0] ... tConc[n]
+ // ---------------------- AND_INTRO
+ // tConc
+ std::vector<Node> pfChildren;
+ pfChildren.insert(pfChildren.end(), tConc.begin(), tConc.end());
+ lcp->addStep(tConc, PfRule::AND_INTRO, pfChildren, {});
+ Trace("te-proof-exp") << "...via AND_INTRO" << std::endl;
+ continue;
}
+ // otherwise should hold by rewriting
+ Assert(Rewriter::rewrite(tConc) == Rewriter::rewrite(tExp));
+ // tExp
+ // ---- MACRO_SR_PRED_TRANSFORM
+ // tConc
+ lcp->addStep(tConc, PfRule::MACRO_SR_PRED_TRANSFORM, {tExp}, {tConc});
+ Trace("te-proof-exp") << "...via MACRO_SR_PRED_TRANSFORM" << std::endl;
+ continue;
+ }
+ if (tExp == tConc)
+ {
+ // trivial
+ Trace("te-proof-exp") << "...trivial" << std::endl;
+ continue;
}
- });
+ // ------------- Via theory
+ // tExp tExp => tConc
+ // ---------------------------------MODUS_PONENS
+ // tConc
+ if (trn.getGenerator() != nullptr)
+ {
+ Trace("te-proof-exp") << "...via theory generator" << std::endl;
+ lcp->addLazyStep(proven, trn.getGenerator());
+ }
+ else
+ {
+ Trace("te-proof-exp") << "...via trust THEORY_LEMMA" << std::endl;
+ // otherwise, trusted theory lemma
+ Node tidn = builtin::BuiltinProofRuleChecker::mkTheoryIdNode(it->first);
+ lcp->addStep(proven, PfRule::THEORY_LEMMA, {}, {proven, tidn});
+ }
+ std::vector<Node> pfChildren;
+ pfChildren.push_back(trn.getNode());
+ pfChildren.push_back(proven);
+ lcp->addStep(tConc, PfRule::MODUS_PONENS, pfChildren, {});
+ }
+ // store in the proof generator
+ TrustNode trn = d_tepg->mkTrustExplain(conclusion, expNode, lcp);
+ // return the trust node
+ return trn;
+ }
+
+ return theory::TrustNode::mkTrustLemma(expNode, nullptr);
}
+bool TheoryEngine::isProofEnabled() const { return d_pnm != nullptr; }
+
void TheoryEngine::setUserAttribute(const std::string& attr,
Node n,
const std::vector<Node>& node_values,
@@ -1990,11 +2003,16 @@ void TheoryEngine::checkTheoryAssertionsWithModel(bool hardFailure) {
it != it_end;
++it) {
Node assertion = (*it).d_assertion;
- Node val = getModel()->getValue(assertion);
+ if (!isRelevant(assertion))
+ {
+ // not relevant, skip
+ continue;
+ }
+ Node val = d_tc->getModel()->getValue(assertion);
if (val != d_true)
{
std::stringstream ss;
- ss << theoryId
+ ss << " " << theoryId
<< " has an asserted fact that the model doesn't satisfy." << endl
<< "The fact: " << assertion << endl
<< "Model value: " << val << endl;
diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h
index 8c0ce6dbf..1412d7464 100644
--- a/src/theory/theory_engine.h
+++ b/src/theory/theory_engine.h
@@ -2,10 +2,10 @@
/*! \file theory_engine.h
** \verbatim
** Top contributors (to current version):
- ** Dejan Jovanovic, Andrew Reynolds, Morgan Deters
+ ** Andrew Reynolds, Dejan Jovanovic, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -33,18 +33,16 @@
#include "options/smt_options.h"
#include "options/theory_options.h"
#include "prop/prop_engine.h"
-#include "smt/command.h"
#include "theory/atom_requests.h"
-#include "theory/decision_manager.h"
#include "theory/engine_output_channel.h"
#include "theory/interrupted.h"
#include "theory/rewriter.h"
-#include "theory/shared_terms_database.h"
#include "theory/sort_inference.h"
-#include "theory/substitutions.h"
#include "theory/term_registration_visitor.h"
#include "theory/theory.h"
#include "theory/theory_preprocessor.h"
+#include "theory/trust_node.h"
+#include "theory/trust_substitutions.h"
#include "theory/uf/equality_engine.h"
#include "theory/valuation.h"
#include "util/hash.h"
@@ -55,7 +53,7 @@
namespace CVC4 {
class ResourceManager;
-class LemmaProofRecipe;
+class TheoryEngineProofGenerator;
/**
* A pair of a theory and a node. This is used to mark the flow of
@@ -88,19 +86,18 @@ struct NodeTheoryPairHashFunction {
/* Forward declarations */
namespace theory {
- class TheoryModel;
- class TheoryEngineModelBuilder;
-
- namespace eq {
- class EqualityEngine;
- }/* CVC4::theory::eq namespace */
-
- namespace quantifiers {
- class TermDb;
- }
-
- class EntailmentCheckParameters;
- class EntailmentCheckSideEffects;
+class TheoryModel;
+class CombinationEngine;
+class SharedSolver;
+class DecisionManager;
+class RelevanceManager;
+
+namespace eq {
+class EqualityEngine;
+} // namespace eq
+
+class EntailmentCheckParameters;
+class EntailmentCheckSideEffects;
}/* CVC4::theory namespace */
class RemoveTermFormulas;
@@ -115,8 +112,9 @@ class TheoryEngine {
/** Shared terms database can use the internals notify the theories */
friend class SharedTermsDatabase;
- friend class theory::quantifiers::TermDb;
friend class theory::EngineOutputChannel;
+ friend class theory::CombinationEngine;
+ friend class theory::SharedSolver;
/** Associated PropEngine engine */
prop::PropEngine* d_propEngine;
@@ -141,59 +139,28 @@ class TheoryEngine {
* the cost of walking the DAG on registration, etc.
*/
const LogicInfo& d_logicInfo;
+ /** The separation logic location and data types */
+ TypeNode d_sepLocType;
+ TypeNode d_sepDataType;
- /**
- * The database of shared terms.
- */
- SharedTermsDatabase d_sharedTerms;
+ /** Reference to the output manager of the smt engine */
+ OutputManager& d_outMgr;
- /**
- * Master equality engine, to share with theories.
- */
- theory::eq::EqualityEngine* d_masterEqualityEngine;
-
- /** notify class for master equality engine */
- class NotifyClass : public theory::eq::EqualityEngineNotify {
- TheoryEngine& d_te;
- public:
- NotifyClass(TheoryEngine& te): d_te(te) {}
- bool eqNotifyTriggerEquality(TNode equality, bool value) override
- {
- return true;
- }
- bool eqNotifyTriggerPredicate(TNode predicate, bool value) override
- {
- return true;
- }
- bool eqNotifyTriggerTermEquality(theory::TheoryId tag,
- TNode t1,
- TNode t2,
- bool value) override
- {
- return true;
- }
- void eqNotifyConstantTermMerge(TNode t1, TNode t2) override {}
- void eqNotifyNewClass(TNode t) override { d_te.eqNotifyNewClass(t); }
- void eqNotifyPreMerge(TNode t1, TNode t2) override
- {
- }
- void eqNotifyPostMerge(TNode t1, TNode t2) override
- {
- }
- void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override
- {
- }
- };/* class TheoryEngine::NotifyClass */
- NotifyClass d_masterEENotify;
-
- /**
- * notification methods
+ //--------------------------------- new proofs
+ /** Proof node manager used by this theory engine, if proofs are enabled */
+ ProofNodeManager* d_pnm;
+ /** The lazy proof object
+ *
+ * This stores instructions for how to construct proofs for all theory lemmas.
*/
- void eqNotifyNewClass(TNode t);
- void eqNotifyPreMerge(TNode t1, TNode t2);
- void eqNotifyPostMerge(TNode t1, TNode t2);
- void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
-
+ std::shared_ptr<LazyCDProof> d_lazyProof;
+ /** The proof generator */
+ std::shared_ptr<TheoryEngineProofGenerator> d_tepg;
+ //--------------------------------- end new proofs
+ /** The combination manager we are using */
+ std::unique_ptr<theory::CombinationEngine> d_tc;
+ /** The shared solver of the above combination engine. */
+ theory::SharedSolver* d_sharedSolver;
/**
* The quantifiers engine
*/
@@ -202,36 +169,15 @@ class TheoryEngine {
* The decision manager
*/
std::unique_ptr<theory::DecisionManager> d_decManager;
+ /** The relevance manager */
+ std::unique_ptr<theory::RelevanceManager> d_relManager;
+
+ /** Default visitor for pre-registration */
+ PreRegisterVisitor d_preRegistrationVisitor;
- /**
- * Default model object
- */
- theory::TheoryModel* d_curr_model;
- bool d_aloc_curr_model;
- /**
- * Model builder object
- */
- theory::TheoryEngineModelBuilder* d_curr_model_builder;
- bool d_aloc_curr_model_builder;
/** are we in eager model building mode? (see setEagerModelBuilding). */
bool d_eager_model_building;
- typedef std::unordered_map<Node, Node, NodeHashFunction> NodeMap;
- typedef std::unordered_map<TNode, Node, TNodeHashFunction> TNodeMap;
-
- /**
- * Used for "missed-t-propagations" dumping mode only. A set of all
- * theory-propagable literals.
- */
- context::CDList<TNode> d_possiblePropagations;
-
- /**
- * Used for "missed-t-propagations" dumping mode only. A
- * context-dependent set of those theory-propagable literals that
- * have been propagated.
- */
- context::CDHashSet<Node, NodeHashFunction> d_hasPropagated;
-
/**
* Output channels for individual theories.
*/
@@ -251,8 +197,12 @@ class TheoryEngine {
/**
* Called by the theories to notify of a conflict.
+ *
+ * @param conflict The trust node containing the conflict and its proof
+ * generator (if it exists),
+ * @param theoryId The theory that sent the conflict
*/
- void conflict(TNode conflict, theory::TheoryId theoryId);
+ void conflict(theory::TrustNode conflict, theory::TheoryId theoryId);
/**
* Debugging flag to ensure that shutdown() is called before the
@@ -273,7 +223,6 @@ class TheoryEngine {
d_incomplete = true;
}
-
/**
* Mapping of propagations from recievers to senders.
*/
@@ -329,16 +278,16 @@ class TheoryEngine {
/**
* 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
+ * @param p the properties of the lemma.
+ * @param atomsTo the theory that atoms of the lemma should be sent to
+ * @param from the theory that sent the lemma
+ * @return a lemma status, containing the lemma and context information
+ * about when it was sent.
*/
- theory::LemmaStatus lemma(TNode node,
- ProofRule rule,
- bool negated,
- bool removable,
- bool preprocess,
- theory::TheoryId atomsTo);
+ theory::LemmaStatus lemma(theory::TrustNode node,
+ theory::LemmaProperty p,
+ theory::TheoryId atomsTo = theory::THEORY_LAST,
+ theory::TheoryId from = theory::THEORY_LAST);
/** Enusre that the given atoms are send to the given theory */
void ensureLemmaAtoms(const std::vector<TNode>& atoms, theory::TheoryId theory);
@@ -365,7 +314,9 @@ class TheoryEngine {
context::UserContext* userContext,
ResourceManager* rm,
RemoveTermFormulas& iteRemover,
- const LogicInfo& logic);
+ const LogicInfo& logic,
+ OutputManager& outMgr,
+ ProofNodeManager* pnm);
/** Destroys a theory engine */
~TheoryEngine();
@@ -389,7 +340,7 @@ class TheoryEngine {
*d_theoryOut[theoryId],
theory::Valuation(this),
d_logicInfo,
- nullptr);
+ d_pnm);
theory::Rewriter::registerTheoryRewriter(
theoryId, d_theoryTable[theoryId]->getTheoryRewriter());
}
@@ -399,7 +350,13 @@ class TheoryEngine {
d_propEngine = propEngine;
}
- /** Called when all initialization of options/logic is done */
+ /**
+ * Called when all initialization of options/logic is done, after theory
+ * objects have been created.
+ *
+ * This initializes the quantifiers engine, the "official" equality engines
+ * of each theory as required, and the model and model builder utilities.
+ */
void finishInit();
/**
@@ -409,19 +366,18 @@ class TheoryEngine {
return d_propEngine;
}
+ /** Get the proof node manager */
+ ProofNodeManager* getProofNodeManager() const;
+
/**
* Get a pointer to the underlying sat context.
*/
- inline context::Context* getSatContext() const {
- return d_context;
- }
+ context::Context* getSatContext() const { return d_context; }
/**
* Get a pointer to the underlying user context.
*/
- inline context::Context* getUserContext() const {
- return d_userContext;
- }
+ context::UserContext* getUserContext() const { return d_userContext; }
/**
* Get a pointer to the underlying quantifiers engine.
@@ -455,11 +411,6 @@ class TheoryEngine {
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
@@ -484,28 +435,25 @@ class TheoryEngine {
bool markPropagation(TNode assertion, TNode originalAssertions, theory::TheoryId toTheoryId, theory::TheoryId fromTheoryId);
/**
- * Computes the explanation by travarsing the propagation graph and
+ * Computes the explanation by traversing the propagation graph and
* asking relevant theories to explain the propagations. Initially
* the explanation vector should contain only the element (node, theory)
* where the node is the one to be explained, and the theory is the
- * theory that sent the literal. The lemmaProofRecipe will contain a list
- * of the explanation steps required to produce the original node.
+ * theory that sent the literal.
*/
- void getExplanation(std::vector<NodeTheoryPair>& explanationVector, LemmaProofRecipe* lemmaProofRecipe);
+ theory::TrustNode getExplanation(
+ std::vector<NodeTheoryPair>& explanationVector);
-public:
-
- /**
- * Signal the start of a new round of assertion preprocessing
- */
- void preprocessStart();
+ /** Are proofs enabled? */
+ bool isProofEnabled() const;
+ public:
/**
* Runs theory specific preprocessing on the non-Boolean parts of
* the formula. This is only called on input assertions, after ITEs
* have been removed.
*/
- Node preprocess(TNode node);
+ theory::TrustNode preprocess(TNode node);
/** Notify (preprocessed) assertions. */
void notifyPreprocessedAssertions(const std::vector<Node>& assertions);
@@ -531,7 +479,12 @@ public:
inline bool needCheck() const {
return d_outputChannelUsed || d_lemmasAdded;
}
-
+ /**
+ * Is the literal lit (possibly) critical for satisfying the input formula in
+ * the current context? This call is applicable only during collectModelInfo
+ * or during LAST_CALL effort.
+ */
+ bool isRelevant(Node lit) const;
/**
* This is called at shutdown time by the SmtEngine, just before
* destruction. It is important because there are destruction
@@ -540,10 +493,13 @@ public:
void shutdown();
/**
- * Solve the given literal with a theory that owns it.
+ * Solve the given literal with a theory that owns it. The proof of tliteral
+ * is carried in the trust node. The proof added to substitutionOut should
+ * take this proof into account (when proofs are enabled).
*/
- theory::Theory::PPAssertStatus solve(TNode literal,
- theory::SubstitutionMap& substitutionOut);
+ theory::Theory::PPAssertStatus solve(
+ theory::TrustNode tliteral,
+ theory::TrustSubstitutionMap& substitutionOut);
/**
* Preregister a Theory atom with the responsible theory (or
@@ -564,11 +520,6 @@ public:
void check(theory::Theory::Effort effort);
/**
- * Run the combination framework.
- */
- void combineTheories();
-
- /**
* Calls ppStaticLearn() on all theories, accumulating their
* combined contributions in the "learned" builder.
*/
@@ -606,26 +557,11 @@ public:
Node getNextDecisionRequest();
bool properConflict(TNode conflict) const;
- bool properPropagation(TNode lit) const;
- bool properExplanation(TNode node, TNode expl) const;
/**
* Returns an explanation of the node propagated to the SAT solver.
*/
- Node getExplanation(TNode node);
-
- /**
- * Returns an explanation of the node propagated to the SAT solver and the theory
- * that propagated it.
- */
- Node getExplanationAndRecipe(TNode node, LemmaProofRecipe* proofRecipe);
-
- /**
- * collect model info
- */
- bool collectModelInfo(theory::TheoryModel* m);
- /** post process model */
- void postProcessModel( theory::TheoryModel* m );
+ theory::TrustNode getExplanation(TNode node);
/**
* Get the pointer to the model object used by this theory engine.
@@ -643,6 +579,15 @@ public:
* was interrupted), then this returns the null pointer.
*/
theory::TheoryModel* getBuiltModel();
+ /**
+ * This forces the model maintained by the combination engine to be built
+ * if it has not been done so already. This should be called only during a
+ * last call effort check after theory combination is run.
+ *
+ * @return true if the model was successfully built (possibly prior to this
+ * call).
+ */
+ bool buildModel();
/** set eager model building
*
* If this method is called, then this TheoryEngine will henceforth build
@@ -671,11 +616,6 @@ public:
bool getSynthSolutions(std::map<Node, std::map<Node, Node> >& sol_map);
/**
- * Get the model builder
- */
- theory::TheoryEngineModelBuilder* getModelBuilder() { return d_curr_model_builder; }
-
- /**
* Get the theory associated to a given Node.
*
* @returns the theory, or NULL if the TNode is
@@ -700,6 +640,16 @@ public:
}
/** get the logic info used by this theory engine */
const LogicInfo& getLogicInfo() const;
+ /** get the separation logic heap types */
+ bool getSepHeapTypes(TypeNode& locType, TypeNode& dataType) const;
+
+ /**
+ * Declare heap. This is used for separation logics to set the location
+ * and data types. It should be called only once, and before any separation
+ * logic constraints are asserted to this theory engine.
+ */
+ void declareSepHeap(TypeNode locT, TypeNode dataT);
+
/**
* Returns the equality status of the two terms, from the theory
* that owns the domain type. The types of a and b must be the same.
@@ -713,7 +663,9 @@ public:
Node getModelValue(TNode var);
/**
- * Takes a literal and returns an equivalent literal that is guaranteed to be a SAT literal
+ * Takes a literal and returns an equivalent literal that is guaranteed to be
+ * a SAT literal. This rewrites and preprocesses n, which notice may involve
+ * sending lemmas if preprocessing n involves introducing new skolems.
*/
Node ensureLiteral(TNode n);
@@ -734,20 +686,12 @@ public:
/**
* Get instantiation methods
- * first inputs forall x.q[x] and returns ( q[a], ..., q[z] )
- * second inputs forall x.q[x] and returns ( a, ..., z )
- * third and fourth return mappings e.g. forall x.q1[x] -> ( q1[a]...q1[z] ) , ... , forall x.qn[x] -> ( qn[a]...qn[z] )
+ * the first given forall x.q[x] returns ( a, ..., z )
+ * the second returns mappings e.g. forall x.q1[x] -> ( q1[a]...q1[z] )
+ * , ... , forall x.qn[x] -> ( qn[a]...qn[z] )
*/
- void getInstantiations( Node q, std::vector< Node >& insts );
void getInstantiationTermVectors( Node q, std::vector< std::vector< Node > >& tvecs );
- void getInstantiations( std::map< Node, std::vector< Node > >& insts );
void getInstantiationTermVectors( std::map< Node, std::vector< std::vector< Node > > >& insts );
-
- /**
- * Get instantiated conjunction, returns q[t1] ^ ... ^ q[tn] where t1...tn are current set of instantiations for q.
- * Can be used for quantifier elimination when satisfiable and q[t1] ^ ... ^ q[tn] |= q
- */
- Node getInstantiatedConjunction( Node q );
/**
* Forwards an entailment check according to the given theoryOfMode.
@@ -756,26 +700,12 @@ public:
std::pair<bool, Node> entailmentCheck(options::TheoryOfMode mode, TNode lit);
private:
- /** Default visitor for pre-registration */
- PreRegisterVisitor d_preRegistrationVisitor;
-
- /** Visitor for collecting shared terms */
- SharedTermsVisitor d_sharedTermsVisitor;
/** Dump the assertions to the dump */
void dumpAssertions(const char* tag);
/** For preprocessing pass lifting bit-vectors of size 1 to booleans */
public:
- void staticInitializeBVOptions(const std::vector<Node>& assertions);
-
- Node ppSimpITE(TNode assertion);
- /** Returns false if an assertion simplified to false. */
- bool donePPSimpITE(std::vector<Node>& assertions);
-
- SharedTermsDatabase* getSharedTermsDatabase() { return &d_sharedTerms; }
-
- theory::eq::EqualityEngine* getMasterEqualityEngine() { return d_masterEqualityEngine; }
SortInference* getSortInference() { return &d_sortInfer; }
@@ -788,7 +718,7 @@ private:
public:
/** Set user attribute.
- *
+ *
* This function is called when an attribute is set by a user. In SMT-LIBv2
* this is done via the syntax (! n :attr)
*/
@@ -798,7 +728,7 @@ private:
const std::string& str_value);
/** Handle user attribute.
- *
+ *
* Associates theory t with the attribute attr. Theory t will be
* notified whenever an attribute of name attr is set.
*/
@@ -809,10 +739,8 @@ private:
* This function is called from the smt engine's checkModel routine.
*/
void checkTheoryAssertionsWithModel(bool hardFailure);
-
private:
IntStat d_arithSubstitutionsAdded;
-
};/* class TheoryEngine */
}/* CVC4 namespace */
diff --git a/src/theory/theory_engine_proof_generator.cpp b/src/theory/theory_engine_proof_generator.cpp
index 2ac1236f8..2ba0a49ff 100644
--- a/src/theory/theory_engine_proof_generator.cpp
+++ b/src/theory/theory_engine_proof_generator.cpp
@@ -4,8 +4,8 @@
** Top contributors (to current version):
** Andrew Reynolds
** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -22,14 +22,27 @@ TheoryEngineProofGenerator::TheoryEngineProofGenerator(ProofNodeManager* pnm,
context::UserContext* u)
: d_pnm(pnm), d_proofs(u)
{
+ d_false = NodeManager::currentNM()->mkConst(false);
}
theory::TrustNode TheoryEngineProofGenerator::mkTrustExplain(
TNode lit, Node exp, std::shared_ptr<LazyCDProof> lpf)
{
- theory::TrustNode trn = theory::TrustNode::mkTrustPropExp(lit, exp, this);
- Node p = trn.getProven();
- Assert(p.getKind() == IMPLIES && p.getNumChildren() == 2);
+ Node p;
+ theory::TrustNode trn;
+ if (lit == d_false)
+ {
+ // propagation of false is a conflict
+ trn = theory::TrustNode::mkTrustConflict(exp, this);
+ p = trn.getProven();
+ Assert(p.getKind() == NOT);
+ }
+ else
+ {
+ trn = theory::TrustNode::mkTrustPropExp(lit, exp, this);
+ p = trn.getProven();
+ Assert(p.getKind() == IMPLIES && p.getNumChildren() == 2);
+ }
// should not already be proven
NodeLazyCDProofMap::iterator it = d_proofs.find(p);
if (it == d_proofs.end())
@@ -42,33 +55,67 @@ theory::TrustNode TheoryEngineProofGenerator::mkTrustExplain(
std::shared_ptr<ProofNode> TheoryEngineProofGenerator::getProofFor(Node f)
{
- // should only ask this generator for proofs of implications
- Assert(f.getKind() == IMPLIES && f.getNumChildren() == 2);
+ Trace("tepg-debug") << "TheoryEngineProofGenerator::getProofFor: " << f
+ << std::endl;
NodeLazyCDProofMap::iterator it = d_proofs.find(f);
if (it == d_proofs.end())
{
+ Trace("tepg-debug") << "...null" << std::endl;
return nullptr;
}
std::shared_ptr<LazyCDProof> lcp = (*it).second;
// finalize it via scope
std::vector<Node> scopeAssumps;
- if (f[0].getKind() == AND)
+ // should only ask this generator for proofs of implications, or conflicts
+ Node exp;
+ Node conclusion;
+ if (f.getKind() == IMPLIES && f.getNumChildren() == 2)
{
- for (const Node& fc : f[0])
+ exp = f[0];
+ conclusion = f[1];
+ }
+ else if (f.getKind() == NOT)
+ {
+ exp = f[0];
+ conclusion = d_false;
+ }
+ else
+ {
+ Unhandled() << "TheoryEngineProofGenerator::getProofFor: unexpected fact "
+ << f << std::endl;
+ return nullptr;
+ }
+ // get the assumptions to assume in a scope
+ if (exp.getKind() == AND)
+ {
+ for (const Node& fc : exp)
{
scopeAssumps.push_back(fc);
}
}
else
{
- scopeAssumps.push_back(f[0]);
+ scopeAssumps.push_back(exp);
}
- Node conclusion = f[1];
-
+ Trace("tepg-debug") << "...get proof body" << std::endl;
// get the proof for conclusion
std::shared_ptr<ProofNode> pfb = lcp->getProofFor(conclusion);
+ Trace("tepg-debug") << "...mkScope" << std::endl;
// call the scope method of proof node manager
std::shared_ptr<ProofNode> pf = d_pnm->mkScope(pfb, scopeAssumps);
+
+ if (pf->getResult() != f)
+ {
+ std::stringstream serr;
+ serr << "TheoryEngineProofGenerator::getProofFor: Proof: " << std::endl;
+ serr << *pf << std::endl;
+ serr << "TheoryEngineProofGenerator::getProofFor: unexpected return proof"
+ << std::endl;
+ serr << " Expected: " << f << std::endl;
+ serr << " Got: " << pf->getResult() << std::endl;
+ Unhandled() << serr.str();
+ }
+ Trace("tepg-debug") << "...finished" << std::endl;
return pf;
}
diff --git a/src/theory/theory_engine_proof_generator.h b/src/theory/theory_engine_proof_generator.h
index a551e79b2..426899cd1 100644
--- a/src/theory/theory_engine_proof_generator.h
+++ b/src/theory/theory_engine_proof_generator.h
@@ -1,11 +1,11 @@
/********************* */
-/*! \file theory_engine.h
+/*! \file theory_engine_proof_generator.h
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds
+ ** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -71,6 +71,8 @@ class TheoryEngineProofGenerator : public ProofGenerator
ProofNodeManager* d_pnm;
/** Map from formulas to lazy CD proofs */
NodeLazyCDProofMap d_proofs;
+ /** The false node */
+ Node d_false;
};
} // namespace CVC4
diff --git a/src/theory/theory_eq_notify.h b/src/theory/theory_eq_notify.h
new file mode 100644
index 000000000..3df5d32cb
--- /dev/null
+++ b/src/theory/theory_eq_notify.h
@@ -0,0 +1,82 @@
+/********************* */
+/*! \file theory_eq_notify.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The theory equality notify utility.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__THEORY_EQ_NOTIFY_H
+#define CVC4__THEORY__THEORY_EQ_NOTIFY_H
+
+#include "expr/node.h"
+#include "theory/theory_inference_manager.h"
+#include "theory/uf/equality_engine_notify.h"
+
+namespace CVC4 {
+namespace theory {
+
+/**
+ * The default class for equality engine callbacks for a theory. This forwards
+ * calls for trigger predicates, trigger term equalities and conflicts due to
+ * constant merges to the provided theory inference manager.
+ */
+class TheoryEqNotifyClass : public eq::EqualityEngineNotify
+{
+ public:
+ TheoryEqNotifyClass(TheoryInferenceManager& im) : d_im(im) {}
+ ~TheoryEqNotifyClass() {}
+
+ bool eqNotifyTriggerPredicate(TNode predicate, bool value) override
+ {
+ if (value)
+ {
+ return d_im.propagateLit(predicate);
+ }
+ return d_im.propagateLit(predicate.notNode());
+ }
+ bool eqNotifyTriggerTermEquality(TheoryId tag,
+ TNode t1,
+ TNode t2,
+ bool value) override
+ {
+ if (value)
+ {
+ return d_im.propagateLit(t1.eqNode(t2));
+ }
+ return d_im.propagateLit(t1.eqNode(t2).notNode());
+ }
+ void eqNotifyConstantTermMerge(TNode t1, TNode t2) override
+ {
+ d_im.conflictEqConstantMerge(t1, t2);
+ }
+ void eqNotifyNewClass(TNode t) override
+ {
+ // do nothing
+ }
+ void eqNotifyMerge(TNode t1, TNode t2) override
+ {
+ // do nothing
+ }
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override
+ {
+ // do nothing
+ }
+
+ protected:
+ /** Reference to the theory inference manager */
+ TheoryInferenceManager& d_im;
+};
+
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/theory_id.cpp b/src/theory/theory_id.cpp
index 2c87458ef..31b864e7f 100644
--- a/src/theory/theory_id.cpp
+++ b/src/theory/theory_id.cpp
@@ -2,10 +2,10 @@
/*! \file theory_id.cpp
** \verbatim
** Top contributors (to current version):
- ** Aina Niemetz, Tim King, Dejan Jovanovic
+ ** Andrew Reynolds, Aina Niemetz, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -17,6 +17,9 @@
#include "theory/theory_id.h"
+#include "base/check.h"
+#include "lib/ffs.h"
+
namespace CVC4 {
namespace theory {
@@ -40,6 +43,7 @@ std::ostream& operator<<(std::ostream& out, TheoryId theoryId)
case THEORY_SAT_SOLVER: out << "THEORY_SAT_SOLVER"; break;
case THEORY_SEP: out << "THEORY_SEP"; break;
case THEORY_SETS: out << "THEORY_SETS"; break;
+ case THEORY_BAGS: out << "THEORY_BAGS"; break;
case THEORY_STRINGS: out << "THEORY_STRINGS"; break;
case THEORY_QUANTIFIERS: out << "THEORY_QUANTIFIERS"; break;
@@ -62,6 +66,7 @@ std::string getStatsPrefix(TheoryId theoryId)
case THEORY_DATATYPES: return "theory::datatypes"; break;
case THEORY_SEP: return "theory::sep"; break;
case THEORY_SETS: return "theory::sets"; break;
+ case THEORY_BAGS: return "theory::bags"; break;
case THEORY_STRINGS: return "theory::strings"; break;
case THEORY_QUANTIFIERS: return "theory::quantifiers"; break;
@@ -70,5 +75,89 @@ std::string getStatsPrefix(TheoryId theoryId)
return "unknown";
}
+TheoryId TheoryIdSetUtil::setPop(TheoryIdSet& set)
+{
+ uint32_t i = ffs(set); // Find First Set (bit)
+ if (i == 0)
+ {
+ return THEORY_LAST;
+ }
+ TheoryId id = static_cast<TheoryId>(i - 1);
+ set = setRemove(id, set);
+ return id;
+}
+
+size_t TheoryIdSetUtil::setSize(TheoryIdSet set)
+{
+ size_t count = 0;
+ while (setPop(set) != THEORY_LAST)
+ {
+ ++count;
+ }
+ return count;
+}
+
+size_t TheoryIdSetUtil::setIndex(TheoryId id, TheoryIdSet set)
+{
+ Assert(setContains(id, set));
+ size_t count = 0;
+ while (setPop(set) != id)
+ {
+ ++count;
+ }
+ return count;
+}
+
+TheoryIdSet TheoryIdSetUtil::setInsert(TheoryId theory, TheoryIdSet set)
+{
+ return set | (1 << theory);
+}
+
+TheoryIdSet TheoryIdSetUtil::setRemove(TheoryId theory, TheoryIdSet set)
+{
+ return setDifference(set, setInsert(theory));
+}
+
+bool TheoryIdSetUtil::setContains(TheoryId theory, TheoryIdSet set)
+{
+ return set & (1 << theory);
+}
+
+TheoryIdSet TheoryIdSetUtil::setComplement(TheoryIdSet a)
+{
+ return (~a) & AllTheories;
+}
+
+TheoryIdSet TheoryIdSetUtil::setIntersection(TheoryIdSet a, TheoryIdSet b)
+{
+ return a & b;
+}
+
+TheoryIdSet TheoryIdSetUtil::setUnion(TheoryIdSet a, TheoryIdSet b)
+{
+ return a | b;
+}
+
+TheoryIdSet TheoryIdSetUtil::setDifference(TheoryIdSet a, TheoryIdSet b)
+{
+ return (~b) & a;
+}
+
+std::string TheoryIdSetUtil::setToString(TheoryIdSet theorySet)
+{
+ std::stringstream ss;
+ ss << "[";
+ for (unsigned theoryId = 0; theoryId < THEORY_LAST; ++theoryId)
+ {
+ TheoryId tid = static_cast<TheoryId>(theoryId);
+ if (setContains(tid, theorySet))
+ {
+ ss << tid << " ";
+ }
+ }
+ ss << "]";
+ return ss.str();
+}
+
} // namespace theory
} // namespace CVC4
diff --git a/src/theory/theory_id.h b/src/theory/theory_id.h
index 005380352..e0dfaa507 100644
--- a/src/theory/theory_id.h
+++ b/src/theory/theory_id.h
@@ -2,10 +2,10 @@
/*! \file theory_id.h
** \verbatim
** Top contributors (to current version):
- ** Aina Niemetz, Dejan Jovanovic, Mathias Preiner
+ ** Andrew Reynolds, Aina Niemetz, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -23,7 +23,6 @@
#include <iostream>
namespace CVC4 {
-
namespace theory {
/**
@@ -43,6 +42,7 @@ enum TheoryId
THEORY_DATATYPES,
THEORY_SEP,
THEORY_SETS,
+ THEORY_BAGS,
THEORY_STRINGS,
THEORY_QUANTIFIERS,
@@ -58,6 +58,53 @@ std::ostream& operator<<(std::ostream& out, TheoryId theoryId);
std::string getStatsPrefix(TheoryId theoryId) CVC4_PUBLIC;
+/**
+ * A set of theories. Utilities for TheoryIdSet can be found below.
+ */
+typedef uint32_t TheoryIdSet;
+
+class TheoryIdSetUtil
+{
+ public:
+ /** A set of all theories */
+ static const TheoryIdSet AllTheories = (1 << theory::THEORY_LAST) - 1;
+
+ /** Pops a first theory off the set */
+ static TheoryId setPop(TheoryIdSet& set);
+
+ /** Returns the size of a set of theories */
+ static size_t setSize(TheoryIdSet set);
+
+ /** Returns the index size of a set of theories */
+ static size_t setIndex(TheoryId id, TheoryIdSet set);
+
+ /** Add the theory to the set. If no set specified, just returns a singleton
+ * set */
+ static TheoryIdSet setInsert(TheoryId theory, TheoryIdSet set = 0);
+
+ /** Add the theory to the set. If no set specified, just returns a singleton
+ * set */
+ static TheoryIdSet setRemove(TheoryId theory, TheoryIdSet set = 0);
+
+ /** Check if the set contains the theory */
+ static bool setContains(TheoryId theory, TheoryIdSet set);
+
+ /** Set complement of a */
+ static TheoryIdSet setComplement(TheoryIdSet a);
+
+ /** Set intersection of a and b */
+ static TheoryIdSet setIntersection(TheoryIdSet a, TheoryIdSet b);
+
+ /** Set union of a and b */
+ static TheoryIdSet setUnion(TheoryIdSet a, TheoryIdSet b);
+
+ /** Set difference of a and b */
+ static TheoryIdSet setDifference(TheoryIdSet a, TheoryIdSet b);
+
+ /** Convert theorySet to string (for debugging) */
+ static std::string setToString(TheoryIdSet theorySet);
+};
+
} // namespace theory
} // namespace CVC4
#endif
diff --git a/src/theory/theory_inference.cpp b/src/theory/theory_inference.cpp
new file mode 100644
index 000000000..8e52c8cd1
--- /dev/null
+++ b/src/theory/theory_inference.cpp
@@ -0,0 +1,65 @@
+/********************* */
+/*! \file theory_inference.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The theory inference utility
+ **/
+
+#include "theory/theory_inference.h"
+
+#include "theory/theory_inference_manager.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+
+SimpleTheoryLemma::SimpleTheoryLemma(Node n,
+ LemmaProperty p,
+ ProofGenerator* pg)
+ : d_node(n), d_property(p), d_pg(pg)
+{
+}
+
+bool SimpleTheoryLemma::process(TheoryInferenceManager* im, bool asLemma)
+{
+ Assert(!d_node.isNull());
+ Assert(asLemma);
+ // send (trusted) lemma on the output channel with property p
+ return im->trustedLemma(TrustNode::mkTrustLemma(d_node, d_pg), d_property);
+}
+
+SimpleTheoryInternalFact::SimpleTheoryInternalFact(Node conc,
+ Node exp,
+ ProofGenerator* pg)
+ : d_conc(conc), d_exp(exp), d_pg(pg)
+{
+}
+
+bool SimpleTheoryInternalFact::process(TheoryInferenceManager* im, bool asLemma)
+{
+ Assert(!asLemma);
+ bool polarity = d_conc.getKind() != NOT;
+ TNode atom = polarity ? d_conc : d_conc[0];
+ // no double negation or conjunctive conclusions
+ Assert(atom.getKind() != NOT && atom.getKind() != AND);
+ if (d_pg != nullptr)
+ {
+ im->assertInternalFact(atom, polarity, {d_exp}, d_pg);
+ }
+ else
+ {
+ im->assertInternalFact(atom, polarity, d_exp);
+ }
+ return true;
+}
+
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/theory_inference.h b/src/theory/theory_inference.h
new file mode 100644
index 000000000..4fea944d6
--- /dev/null
+++ b/src/theory/theory_inference.h
@@ -0,0 +1,119 @@
+/********************* */
+/*! \file theory_inference.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The theory inference utility
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__THEORY_INFERENCE_H
+#define CVC4__THEORY__THEORY_INFERENCE_H
+
+#include "expr/node.h"
+#include "theory/output_channel.h"
+
+namespace CVC4 {
+namespace theory {
+
+class TheoryInferenceManager;
+
+/**
+ * A theory inference base class. This class is an abstract data structure for
+ * storing pending lemmas or facts in the buffered inference manager. It can
+ * be seen a single use object capturing instructions for making a single
+ * call to TheoryInferenceManager for lemmas or facts.
+ */
+class TheoryInference
+{
+ public:
+ virtual ~TheoryInference() {}
+ /**
+ * Called by the provided inference manager to process this inference. This
+ * method should make call(s) to inference manager to process this
+ * inference, as well as processing any specific side effects. This method
+ * typically makes a single call to the provided inference manager e.g.
+ * d_im->trustedLemma or d_im->assertInternalFact. Notice it is the sole
+ * responsibility of this class to make this call; the inference manager
+ * does not call itself otherwise when processing pending inferences.
+ *
+ * @param im The inference manager to use
+ * @param asLemma Whether this inference is being processed as a lemma
+ * during doPendingLemmas (otherwise it is being processed in doPendingFacts).
+ * Typically, this method calls lemma or conflict when asLemma is
+ * true, and assertInternalFact when this flag is false, although this
+ * behavior is (intentionally) not strictly enforced. In particular, the
+ * choice to send a conflict, lemma or fact may depend on local state of the
+ * theory, which may change while the inference is pending. Hence the
+ * implementation of this method may choose to implement any call to the
+ * inference manager. This flag simply serves to track whether the inference
+ * initially was added a pending lemma or not.
+ * @return true if the inference was successfully processed by the inference
+ * manager. This method for instance returns false if it corresponds to a
+ * lemma that was already cached by im and hence was discarded.
+ */
+ virtual bool process(TheoryInferenceManager* im, bool asLemma) = 0;
+};
+
+/**
+ * A simple theory lemma with no side effects. Makes a single call to
+ * trustedLemma in its process method.
+ */
+class SimpleTheoryLemma : public TheoryInference
+{
+ public:
+ SimpleTheoryLemma(Node n, LemmaProperty p, ProofGenerator* pg);
+ virtual ~SimpleTheoryLemma() {}
+ /**
+ * Send the lemma using inference manager im, return true if the lemma was
+ * sent. It should be the case that asLemma = true or an assertion failure
+ * is thrown.
+ */
+ virtual bool process(TheoryInferenceManager* im, bool asLemma) override;
+ /** The lemma to send */
+ Node d_node;
+ /** The lemma property (see OutputChannel::lemma) */
+ LemmaProperty d_property;
+ /**
+ * The proof generator for this lemma, which if non-null, is wrapped in a
+ * TrustNode to be set on the output channel via trustedLemma at the time
+ * the lemma is sent. This proof generator must be able to provide a proof
+ * for d_node in the remainder of the user context.
+ */
+ ProofGenerator* d_pg;
+};
+
+/**
+ * A simple internal fact with no side effects. Makes a single call to
+ * assertInternalFact in its process method.
+ */
+class SimpleTheoryInternalFact : public TheoryInference
+{
+ public:
+ SimpleTheoryInternalFact(Node conc, Node exp, ProofGenerator* pg);
+ virtual ~SimpleTheoryInternalFact() {}
+ /**
+ * Send the lemma using inference manager im, return true if the lemma was
+ * sent. It should be the case that asLemma = false or an assertion failure
+ * is thrown.
+ */
+ virtual bool process(TheoryInferenceManager* im, bool asLemma) override;
+ /** The lemma to send */
+ Node d_conc;
+ /** The explanation */
+ Node d_exp;
+ /** The proof generator */
+ ProofGenerator* d_pg;
+};
+
+} // namespace theory
+} // namespace CVC4
+
+#endif
diff --git a/src/theory/theory_inference_manager.cpp b/src/theory/theory_inference_manager.cpp
new file mode 100644
index 000000000..16ccc45ec
--- /dev/null
+++ b/src/theory/theory_inference_manager.cpp
@@ -0,0 +1,474 @@
+/********************* */
+/*! \file theory_inference_manager.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Mathias Preiner, Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief An inference manager for Theory
+ **/
+
+#include "theory/theory_inference_manager.h"
+
+#include "theory/theory.h"
+#include "theory/uf/equality_engine.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+
+TheoryInferenceManager::TheoryInferenceManager(Theory& t,
+ TheoryState& state,
+ ProofNodeManager* pnm)
+ : d_theory(t),
+ d_theoryState(state),
+ d_out(t.getOutputChannel()),
+ d_ee(nullptr),
+ d_pnm(pnm),
+ d_keep(t.getSatContext()),
+ d_lemmasSent(t.getUserContext()),
+ d_numConflicts(0),
+ d_numCurrentLemmas(0),
+ d_numCurrentFacts(0)
+{
+}
+
+void TheoryInferenceManager::setEqualityEngine(eq::EqualityEngine* ee)
+{
+ d_ee = ee;
+ // if proofs are enabled, also make a proof equality engine to wrap ee
+ if (d_pnm != nullptr)
+ {
+ d_pfee.reset(new eq::ProofEqEngine(d_theoryState.getSatContext(),
+ d_theoryState.getUserContext(),
+ *d_ee,
+ d_pnm));
+ }
+}
+
+bool TheoryInferenceManager::isProofEnabled() const { return d_pnm != nullptr; }
+
+void TheoryInferenceManager::reset()
+{
+ d_numConflicts = 0;
+ d_numCurrentLemmas = 0;
+ d_numCurrentFacts = 0;
+}
+
+bool TheoryInferenceManager::hasSent() const
+{
+ return d_theoryState.isInConflict() || d_numCurrentLemmas > 0
+ || d_numCurrentFacts > 0;
+}
+
+eq::ProofEqEngine* TheoryInferenceManager::getProofEqEngine()
+{
+ return d_pfee.get();
+}
+
+void TheoryInferenceManager::conflictEqConstantMerge(TNode a, TNode b)
+{
+ if (!d_theoryState.isInConflict())
+ {
+ TrustNode tconf = explainConflictEqConstantMerge(a, b);
+ d_theoryState.notifyInConflict();
+ d_out.trustedConflict(tconf);
+ }
+}
+
+void TheoryInferenceManager::conflict(TNode conf)
+{
+ if (!d_theoryState.isInConflict())
+ {
+ d_theoryState.notifyInConflict();
+ d_out.conflict(conf);
+ ++d_numConflicts;
+ }
+}
+
+void TheoryInferenceManager::trustedConflict(TrustNode tconf)
+{
+ if (!d_theoryState.isInConflict())
+ {
+ d_theoryState.notifyInConflict();
+ d_out.trustedConflict(tconf);
+ }
+}
+
+void TheoryInferenceManager::conflictExp(PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& args)
+{
+ if (!d_theoryState.isInConflict())
+ {
+ // make the trust node
+ TrustNode tconf = mkConflictExp(id, exp, args);
+ // send it on the output channel
+ trustedConflict(tconf);
+ }
+}
+
+TrustNode TheoryInferenceManager::mkConflictExp(PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& args)
+{
+ if (d_pfee != nullptr)
+ {
+ // use proof equality engine to construct the trust node
+ return d_pfee->assertConflict(id, exp, args);
+ }
+ // version without proofs
+ Node conf = mkExplainPartial(exp, {});
+ return TrustNode::mkTrustConflict(conf, nullptr);
+}
+
+void TheoryInferenceManager::conflictExp(const std::vector<Node>& exp,
+ ProofGenerator* pg)
+{
+ if (!d_theoryState.isInConflict())
+ {
+ // make the trust node
+ TrustNode tconf = mkConflictExp(exp, pg);
+ // send it on the output channel
+ trustedConflict(tconf);
+ }
+}
+
+TrustNode TheoryInferenceManager::mkConflictExp(const std::vector<Node>& exp,
+ ProofGenerator* pg)
+{
+ if (d_pfee != nullptr)
+ {
+ Assert(pg != nullptr);
+ // use proof equality engine to construct the trust node
+ return d_pfee->assertConflict(exp, pg);
+ }
+ // version without proofs
+ Node conf = mkExplainPartial(exp, {});
+ return TrustNode::mkTrustConflict(conf, nullptr);
+}
+
+bool TheoryInferenceManager::propagateLit(TNode lit)
+{
+ // If already in conflict, no more propagation
+ if (d_theoryState.isInConflict())
+ {
+ return false;
+ }
+ // Propagate out
+ bool ok = d_out.propagate(lit);
+ if (!ok)
+ {
+ d_theoryState.notifyInConflict();
+ }
+ return ok;
+}
+
+TrustNode TheoryInferenceManager::explainLit(TNode lit)
+{
+ if (d_pfee != nullptr)
+ {
+ return d_pfee->explain(lit);
+ }
+ if (d_ee != nullptr)
+ {
+ Node exp = d_ee->mkExplainLit(lit);
+ return TrustNode::mkTrustPropExp(lit, exp, nullptr);
+ }
+ Unimplemented() << "Inference manager for " << d_theory.getId()
+ << " was asked to explain a propagation but doesn't have an "
+ "equality engine or implement the "
+ "TheoryInferenceManager::explainLit interface!";
+}
+
+TrustNode TheoryInferenceManager::explainConflictEqConstantMerge(TNode a,
+ TNode b)
+{
+ Node lit = a.eqNode(b);
+ if (d_pfee != nullptr)
+ {
+ return d_pfee->assertConflict(lit);
+ }
+ if (d_ee != nullptr)
+ {
+ Node conf = d_ee->mkExplainLit(lit);
+ return TrustNode::mkTrustConflict(conf, nullptr);
+ }
+ Unimplemented() << "Inference manager for " << d_theory.getId()
+ << " mkTrustedConflictEqConstantMerge";
+}
+
+bool TheoryInferenceManager::lemma(TNode lem, LemmaProperty p, bool doCache)
+{
+ TrustNode tlem = TrustNode::mkTrustLemma(lem, nullptr);
+ return trustedLemma(tlem, p, doCache);
+}
+
+bool TheoryInferenceManager::trustedLemma(const TrustNode& tlem,
+ LemmaProperty p,
+ bool doCache)
+{
+ if (doCache)
+ {
+ if (!cacheLemma(tlem.getNode(), p))
+ {
+ return false;
+ }
+ }
+ d_numCurrentLemmas++;
+ d_out.trustedLemma(tlem, p);
+ return true;
+}
+
+bool TheoryInferenceManager::lemmaExp(Node conc,
+ PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& noExplain,
+ const std::vector<Node>& args,
+ LemmaProperty p,
+ bool doCache)
+{
+ // make the trust node
+ TrustNode trn = mkLemmaExp(conc, id, exp, noExplain, args);
+ // send it on the output channel
+ return trustedLemma(trn, p, doCache);
+}
+
+TrustNode TheoryInferenceManager::mkLemmaExp(Node conc,
+ PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& noExplain,
+ const std::vector<Node>& args)
+{
+ if (d_pfee != nullptr)
+ {
+ // make the trust node from the proof equality engine
+ return d_pfee->assertLemma(conc, id, exp, noExplain, args);
+ }
+ // otherwise, not using proofs, explain and make trust node
+ Node ant = mkExplainPartial(exp, noExplain);
+ Node lem = NodeManager::currentNM()->mkNode(kind::IMPLIES, ant, conc);
+ return TrustNode::mkTrustLemma(lem, nullptr);
+}
+
+bool TheoryInferenceManager::lemmaExp(Node conc,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& noExplain,
+ ProofGenerator* pg,
+ LemmaProperty p,
+ bool doCache)
+{
+ // make the trust node
+ TrustNode trn = mkLemmaExp(conc, exp, noExplain, pg);
+ // send it on the output channel
+ return trustedLemma(trn, p, doCache);
+}
+
+TrustNode TheoryInferenceManager::mkLemmaExp(Node conc,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& noExplain,
+ ProofGenerator* pg)
+{
+ if (d_pfee != nullptr)
+ {
+ // make the trust node from the proof equality engine
+ return d_pfee->assertLemma(conc, exp, noExplain, pg);
+ }
+ // otherwise, not using proofs, explain and make trust node
+ Node ant = mkExplainPartial(exp, noExplain);
+ Node lem = NodeManager::currentNM()->mkNode(kind::IMPLIES, ant, conc);
+ return TrustNode::mkTrustLemma(lem, nullptr);
+}
+
+bool TheoryInferenceManager::hasCachedLemma(TNode lem, LemmaProperty p)
+{
+ return d_lemmasSent.find(lem) != d_lemmasSent.end();
+}
+
+uint32_t TheoryInferenceManager::numSentLemmas() const
+{
+ return d_numCurrentLemmas;
+}
+
+bool TheoryInferenceManager::hasSentLemma() const
+{
+ return d_numCurrentLemmas != 0;
+}
+
+bool TheoryInferenceManager::assertInternalFact(TNode atom, bool pol, TNode exp)
+{
+ return processInternalFact(atom, pol, PfRule::UNKNOWN, {exp}, {}, nullptr);
+}
+
+bool TheoryInferenceManager::assertInternalFact(TNode atom,
+ bool pol,
+ PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& args)
+{
+ Assert(id != PfRule::UNKNOWN);
+ return processInternalFact(atom, pol, id, exp, args, nullptr);
+}
+
+bool TheoryInferenceManager::assertInternalFact(TNode atom,
+ bool pol,
+ const std::vector<Node>& exp,
+ ProofGenerator* pg)
+{
+ Assert(pg != nullptr);
+ return processInternalFact(atom, pol, PfRule::ASSUME, exp, {}, pg);
+}
+
+bool TheoryInferenceManager::processInternalFact(TNode atom,
+ bool pol,
+ PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& args,
+ ProofGenerator* pg)
+{
+ // make the node corresponding to the explanation
+ Node expn = NodeManager::currentNM()->mkAnd(exp);
+ // call the pre-notify fact method with preReg = false, isInternal = true
+ if (d_theory.preNotifyFact(atom, pol, expn, false, true))
+ {
+ // Handled in a theory-specific way that doesn't require equality engine,
+ // notice we return true, indicating that the fact was processed.
+ return true;
+ }
+ Assert(d_ee != nullptr);
+ Trace("infer-manager") << "TheoryInferenceManager::assertInternalFact: "
+ << expn << std::endl;
+ d_numCurrentFacts++;
+ // Now, assert the fact. How to do so depends on whether proofs are enabled.
+ // If no proof production, or no proof rule was given
+ bool ret = false;
+ if (d_pfee == nullptr || id == PfRule::UNKNOWN)
+ {
+ if (atom.getKind() == kind::EQUAL)
+ {
+ ret = d_ee->assertEquality(atom, pol, expn);
+ }
+ else
+ {
+ ret = d_ee->assertPredicate(atom, pol, expn);
+ }
+ // Must reference count the equality and its explanation, which is not done
+ // by the equality engine. Notice that we do *not* need to do this for
+ // external assertions, which enter as facts in theory check. This is also
+ // not done if we are asserting to the proof equality engine, which does
+ // this caching itself within ProofEqEngine::assertFact.
+ d_keep.insert(atom);
+ d_keep.insert(expn);
+ }
+ else
+ {
+ // Note that we reconstruct the original literal lit here, since both the
+ // original literal is needed for bookkeeping proofs. It is possible to
+ // optimize this so that a few less nodes are created, but at the cost
+ // of a more verbose interface to proof equality engine.
+ Node lit = pol ? Node(atom) : atom.notNode();
+ if (pg != nullptr)
+ {
+ // use the proof generator interface
+ ret = d_pfee->assertFact(lit, expn, pg);
+ }
+ else
+ {
+ // use the explict proof step interface
+ ret = d_pfee->assertFact(lit, id, expn, args);
+ }
+ }
+ // call the notify fact method with isInternal = true
+ d_theory.notifyFact(atom, pol, expn, true);
+ Trace("infer-manager")
+ << "TheoryInferenceManager::finished assertInternalFact" << std::endl;
+ return ret;
+}
+
+void TheoryInferenceManager::explain(TNode n, std::vector<TNode>& assumptions)
+{
+ if (n.getKind() == kind::AND)
+ {
+ for (const Node& nc : n)
+ {
+ d_ee->explainLit(nc, assumptions);
+ }
+ }
+ else
+ {
+ d_ee->explainLit(n, assumptions);
+ }
+}
+
+Node TheoryInferenceManager::mkExplain(TNode n)
+{
+ std::vector<TNode> assumptions;
+ explain(n, assumptions);
+ return NodeManager::currentNM()->mkAnd(assumptions);
+}
+
+Node TheoryInferenceManager::mkExplainPartial(
+ const std::vector<Node>& exp, const std::vector<Node>& noExplain)
+{
+ std::vector<TNode> assumps;
+ for (const Node& e : exp)
+ {
+ if (std::find(noExplain.begin(), noExplain.end(), e) != noExplain.end())
+ {
+ if (std::find(assumps.begin(), assumps.end(), e) == assumps.end())
+ {
+ // a non-explained literal
+ assumps.push_back(e);
+ }
+ continue;
+ }
+ // otherwise, explain it
+ explain(e, assumps);
+ }
+ return NodeManager::currentNM()->mkAnd(assumps);
+}
+
+uint32_t TheoryInferenceManager::numSentFacts() const
+{
+ return d_numCurrentFacts;
+}
+
+bool TheoryInferenceManager::hasSentFact() const
+{
+ return d_numCurrentFacts != 0;
+}
+
+bool TheoryInferenceManager::cacheLemma(TNode lem, LemmaProperty p)
+{
+ if (d_lemmasSent.find(lem) != d_lemmasSent.end())
+ {
+ return false;
+ }
+ d_lemmasSent.insert(lem);
+ return true;
+}
+
+void TheoryInferenceManager::requirePhase(TNode n, bool pol)
+{
+ return d_out.requirePhase(n, pol);
+}
+
+void TheoryInferenceManager::spendResource(ResourceManager::Resource r)
+{
+ d_out.spendResource(r);
+}
+
+void TheoryInferenceManager::safePoint(ResourceManager::Resource r)
+{
+ d_out.safePoint(r);
+}
+
+void TheoryInferenceManager::setIncomplete() { d_out.setIncomplete(); }
+
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/theory_inference_manager.h b/src/theory/theory_inference_manager.h
new file mode 100644
index 000000000..35d9031ae
--- /dev/null
+++ b/src/theory/theory_inference_manager.h
@@ -0,0 +1,430 @@
+/********************* */
+/*! \file theory_inference_manager.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Mathias Preiner, Martin Brain
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief An inference manager for Theory
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__THEORY_INFERENCE_MANAGER_H
+#define CVC4__THEORY__THEORY_INFERENCE_MANAGER_H
+
+#include <memory>
+
+#include "context/cdhashset.h"
+#include "expr/node.h"
+#include "theory/output_channel.h"
+#include "theory/theory_state.h"
+#include "theory/trust_node.h"
+#include "theory/uf/proof_equality_engine.h"
+
+namespace CVC4 {
+
+class ProofNodeManager;
+
+namespace theory {
+
+class Theory;
+namespace eq {
+class EqualityEngine;
+}
+
+/**
+ * The base class for inference manager. An inference manager is a wrapper
+ * around the output channel and the official equality engine of a Theory.
+ * It is used for ensuring that the equality engine and output channel
+ * are used properly. This includes the following invariants:
+ *
+ * (1) The state tracks conflicts.
+ * In particular, TheoryState::isInConflict returns true whenever we have
+ * called OutputChannel::conflict in the current context, which we enforce
+ * by always setting d_state.notifyInConflict at the same time we send
+ * conflicts on the output channel.
+ *
+ * (2) The theory is notified of (internal) facts.
+ * In particular, Theory::preNotifyFact and Theory::notifyFact are called
+ * (with isInternal = true) whenever we assert internal facts using
+ * assertFactInernal below, mirroring what is done for facts from the fact
+ * queue (where isInternal = false).
+ *
+ * (3) The proof equality engine is used whenever proofs are enabled (when
+ * the proof node manager provided to this class is non-null). Notice this
+ * class automatically will construct a proof equality engine during
+ * setEqualityEngine, and use it for handling variants of assertInternalFact
+ * below that involve proofs.
+ */
+class TheoryInferenceManager
+{
+ typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
+
+ public:
+ /**
+ * Constructor, note that state should be the official state of theory t.
+ */
+ TheoryInferenceManager(Theory& t, TheoryState& state, ProofNodeManager* pnm);
+ virtual ~TheoryInferenceManager() {}
+ /**
+ * Set equality engine, ee is a pointer to the official equality engine
+ * of theory.
+ */
+ void setEqualityEngine(eq::EqualityEngine* ee);
+ /**
+ * Are proofs enabled in this inference manager? Returns true if the proof
+ * node manager pnm provided to the constructor of this class was non-null.
+ */
+ bool isProofEnabled() const;
+ /**
+ * Reset, which resets counters regarding the number of added lemmas and
+ * internal facts. This method should be manually called by the theory at
+ * the appropriate time for the purpose of tracking the usage of this
+ * inference manager.
+ *
+ * For example, some theories implement an internal checking loop that
+ * repeats while new facts are added. The theory should call reset at the
+ * beginning of this loop and repeat its strategy while hasAddedFact is true.
+ */
+ void reset();
+ /**
+ * Returns true if we are in conflict, or if we have sent a lemma or fact
+ * since the last call to reset.
+ */
+ bool hasSent() const;
+ /** Get the underlying proof equality engine */
+ eq::ProofEqEngine* getProofEqEngine();
+ //--------------------------------------- propagations
+ /**
+ * T-propagate literal lit, possibly encountered by equality engine,
+ * returns false if we are in conflict.
+ *
+ * Note that this is the preferred method to call on
+ * EqualityEngineNotify::eqNotifyTriggerPredicate and
+ * EqualityEngineNotify::eqNotifyTriggerTermEquality.
+ */
+ bool propagateLit(TNode lit);
+ /**
+ * Return an explanation for the literal represented by parameter lit
+ * (which was previously propagated by this theory). By default, this
+ * returns the explanation given by the official equality engine of the
+ * Theory, if it exists.
+ */
+ virtual TrustNode explainLit(TNode lit);
+ //--------------------------------------- conflicts
+ /**
+ * Raise conflict, called when constants a and b merge. Sends the conflict
+ * on the output channel corresponding to the equality engine's explanation
+ * of (= a b). The proof equality engine (if it exists) will be used as the
+ * proof generator.
+ *
+ * Note that this is the preferred method to call on
+ * EqualityEngineNotify::eqNotifyConstantTermMerge.
+ */
+ void conflictEqConstantMerge(TNode a, TNode b);
+ /**
+ * Raise conflict conf (of any form), without proofs. This method should
+ * only be called if there is not yet proof support in the given theory.
+ */
+ void conflict(TNode conf);
+ /**
+ * Raise trusted conflict tconf (of any form) where a proof generator has
+ * been provided (as part of the trust node) in a custom way.
+ */
+ void trustedConflict(TrustNode tconf);
+ /**
+ * Explain and send conflict from contradictory facts. This method is called
+ * when the proof rule id with premises exp and arguments args concludes
+ * false. This method sends a trusted conflict corresponding to the official
+ * equality engine's explanation of literals in exp, with the proof equality
+ * engine as the proof generator (if it exists).
+ */
+ void conflictExp(PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& args);
+ /**
+ * Make the trust node corresponding to the conflict of the above form. It is
+ * the responsibility of the caller to subsequently call trustedConflict with
+ * the returned trust node.
+ */
+ TrustNode mkConflictExp(PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& args);
+ /**
+ * Explain and send conflict from contradictory facts. This method is called
+ * when proof generator pg has a proof of false from free assumptions exp.
+ * This method sends a trusted conflict corresponding to the official
+ * equality engine's explanation of literals in exp, with the proof equality
+ * engine as the proof generator (if it exists), where pg provides the
+ * final step(s) of this proof during this call.
+ */
+ void conflictExp(const std::vector<Node>& exp, ProofGenerator* pg);
+ /**
+ * Make the trust node corresponding to the conflict of the above form. It is
+ * the responsibility of the caller to subsequently call trustedConflict with
+ * the returned trust node.
+ */
+ TrustNode mkConflictExp(const std::vector<Node>& exp, ProofGenerator* pg);
+ //--------------------------------------- lemmas
+ /**
+ * Send (trusted) lemma lem with property p on the output channel.
+ *
+ * @param tlem The trust node containing the lemma and its proof generator.
+ * @param p The property of the lemma
+ * @param doCache If true, we send the lemma only if it has not already been
+ * cached (see cacheLemma), and add it to the cache during this call.
+ * @return true if the lemma was sent on the output channel.
+ */
+ bool trustedLemma(const TrustNode& tlem,
+ LemmaProperty p = LemmaProperty::NONE,
+ bool doCache = true);
+ /**
+ * Send lemma lem with property p on the output channel. Same as above, with
+ * a node instead of a trust node.
+ */
+ bool lemma(TNode lem,
+ LemmaProperty p = LemmaProperty::NONE,
+ bool doCache = true);
+ /**
+ * Explained lemma. This should be called when
+ * ( exp => conc )
+ * is a valid theory lemma. This method adds a lemma where part of exp
+ * is replaced by its explanation according to the official equality engine
+ * of the theory.
+ *
+ * In particular, this method adds a lemma on the output channel of the form
+ * ( ^_{e in exp \ noExplain} EXPLAIN(e) ^ noExplain ) => conc
+ * where EXPLAIN(e) returns the explanation of literal e according to the
+ * official equality engine of the theory. Note that noExplain is the *subset*
+ * of exp that should not be explained.
+ *
+ * @param conc The conclusion of the lemma
+ * @param id The proof rule concluding conc
+ * @param exp The set of (all) literals that imply conc
+ * @param noExplain The subset of exp that should not be explained by the
+ * equality engine
+ * @param args The arguments to the proof step concluding conc
+ * @param p The property of the lemma
+ * @param doCache Whether to check and add the lemma to the cache
+ * @return true if the lemma was sent on the output channel.
+ */
+ bool lemmaExp(Node conc,
+ PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& noExplain,
+ const std::vector<Node>& args,
+ LemmaProperty p = LemmaProperty::NONE,
+ bool doCache = true);
+ /**
+ * Make the trust node for the above method. It is responsibility of the
+ * caller to subsequently call trustedLemma with the returned trust node.
+ */
+ TrustNode mkLemmaExp(Node conc,
+ PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& noExplain,
+ const std::vector<Node>& args);
+ /**
+ * Same as above, but where pg can provide a proof of conc from free
+ * assumptions in exp. This sends a trusted lemma on the output channel where
+ * the proof equality engine is the proof generator. The generator pg
+ * is asked to provide the final step(s) of this proof during this call.
+ *
+ * @param conc The conclusion of the lemma
+ * @param exp The set of (all) literals that imply conc
+ * @param noExplain The subset of exp that should not be explained by the
+ * equality engine
+ * @param pg If non-null, the proof generator who can provide a proof of conc.
+ * @param p The property of the lemma
+ * @param doCache Whether to check and add the lemma to the cache
+ * @return true if the lemma was sent on the output channel.
+ */
+ bool lemmaExp(Node conc,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& noExplain,
+ ProofGenerator* pg = nullptr,
+ LemmaProperty p = LemmaProperty::NONE,
+ bool doCache = true);
+ /**
+ * Make the trust node for the above method. It is responsibility of the
+ * caller to subsequently call trustedLemma with the returned trust node.
+ */
+ TrustNode mkLemmaExp(Node conc,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& noExplain,
+ ProofGenerator* pg = nullptr);
+ /**
+ * Has this inference manager cached and sent the given lemma (in this user
+ * context)? This method can be overridden by the particular manager. If not,
+ * this returns true if lem is in the cache d_lemmasSent maintained by this
+ * class. Notice that the default cache in this base class is not dependent
+ * on the lemma property.
+ */
+ virtual bool hasCachedLemma(TNode lem, LemmaProperty p);
+ /** The number of lemmas we have sent since the last call to reset */
+ uint32_t numSentLemmas() const;
+ /** Have we added a lemma since the last call to reset? */
+ bool hasSentLemma() const;
+ //--------------------------------------- internal facts
+ /**
+ * Assert internal fact. This is recommended method for asserting "internal"
+ * facts into the equality engine of the theory. In particular, this method
+ * should be used for anything the theory infers that is not sent on the
+ * output channel as a propagation or lemma. This method ensures that the
+ * Theory's preNotifyFact and notifyFact method have been called with
+ * isInternal = true.
+ *
+ * @param atom The atom of the fact to assert
+ * @param pol Its polarity
+ * @param exp Its explanation, i.e. ( exp => (~) atom ) is valid.
+ * @return true if the fact was processed, i.e. it was asserted to the
+ * equality engine or preNotifyFact returned true.
+ */
+ bool assertInternalFact(TNode atom, bool pol, TNode exp);
+ /**
+ * Assert internal fact, with a proof step justification. Notice that if
+ * proofs are not enabled in this inference manager, then this asserts
+ * a fact to the equality engine in the normal way.
+ *
+ * @param atom The atom of the fact to assert
+ * @param pol Its polarity
+ * @param id The proof rule identifier of the proof step
+ * @param exp Its explanation, interpreted as a conjunction
+ * @param args The arguments of the proof step
+ * @return true if the fact was processed, i.e. it was asserted to the
+ * equality engine or preNotifyFact returned true.
+ */
+ bool assertInternalFact(TNode atom,
+ bool pol,
+ PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& args);
+ /**
+ * Assert internal fact, with a proof generator justification. Same as above,
+ * but with a proof generator instead of an explicit step.
+ *
+ * @param atom The atom of the fact to assert
+ * @param pol Its polarity
+ * @param exp Its explanation, interpreted as a conjunction
+ * @param pg The proof generator for this step. If non-null, pg must be able
+ * to provide a proof concluding (~) atom from free asumptions in exp in
+ * the remainder of the current SAT context.
+ * @return true if the fact was processed, i.e. it was asserted to the
+ * equality engine or preNotifyFact returned true.
+ */
+ bool assertInternalFact(TNode atom,
+ bool pol,
+ const std::vector<Node>& exp,
+ ProofGenerator* pg);
+ /** The number of internal facts we have added since the last call to reset */
+ uint32_t numSentFacts() const;
+ /** Have we added a internal fact since the last call to reset? */
+ bool hasSentFact() const;
+ //--------------------------------------- phase requirements
+ /**
+ * Set that literal n has SAT phase requirement pol, that is, it should be
+ * decided with polarity pol, for details see OutputChannel::requirePhase.
+ */
+ void requirePhase(TNode n, bool pol);
+
+ /**
+ * Forward to OutputChannel::spendResource() to spend resources.
+ */
+ void spendResource(ResourceManager::Resource r);
+
+ /**
+ * Forward to OutputChannel::safePoint() to spend resources.
+ */
+ void safePoint(ResourceManager::Resource r);
+ /**
+ * Notification from a theory that it realizes it is incomplete at
+ * this context level.
+ */
+ void setIncomplete();
+
+ protected:
+ /**
+ * Process internal fact. This is a common helper method for the
+ * assertInternalFact variants above. Returns true if the fact was processed.
+ */
+ bool processInternalFact(TNode atom,
+ bool pol,
+ PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& args,
+ ProofGenerator* pg);
+ /**
+ * Explain conflict from constants merging in the equality engine. This
+ * method is called by conflictEqConstantMerge. By default, it returns
+ * the explanation of the official equality engine of the theory, if it
+ * exists.
+ */
+ virtual TrustNode explainConflictEqConstantMerge(TNode a, TNode b);
+ /**
+ * Explain formula n (which is possibly a conjunction with no nested
+ * conjunctions), add its explanation to assumptions.
+ */
+ void explain(TNode n, std::vector<TNode>& assumptions);
+ /**
+ * Explain formula n (which is possibly a conjunction with no nested
+ * conjunctions), return the explanation as a conjunction.
+ */
+ Node mkExplain(TNode n);
+ /**
+ * Explain the set of formulas in exp using the official equality engine of
+ * the theory. We ask the equality engine to explain literals in exp
+ * that do not occur in noExplain, and return unchanged those that occur in
+ * noExplain. Note the vector noExplain should be a subset of exp.
+ */
+ Node mkExplainPartial(const std::vector<Node>& exp,
+ const std::vector<Node>& noExplain);
+ /**
+ * Cache that lemma lem is being sent with property p. Return true if it
+ * did not already exist in the cache maintained by this class. If this
+ * method is not overridden, then we use the d_lemmasSent cache maintained
+ * by this class, which notice is not dependent on lemma property. If
+ * the lemma property should be taken into account, the manager should
+ * override this method to take the lemma property into account as needed.
+ */
+ virtual bool cacheLemma(TNode lem, LemmaProperty p);
+ /** The theory object */
+ Theory& d_theory;
+ /** Reference to the state of theory */
+ TheoryState& d_theoryState;
+ /** Reference to the output channel of the theory */
+ OutputChannel& d_out;
+ /** Pointer to equality engine of the theory. */
+ eq::EqualityEngine* d_ee;
+ /** A proof equality engine */
+ std::unique_ptr<eq::ProofEqEngine> d_pfee;
+ /** The proof node manager of the theory */
+ ProofNodeManager* d_pnm;
+ /**
+ * The keep set of this class. This set is maintained to ensure that
+ * facts and their explanations are ref-counted. Since facts and their
+ * explanations are SAT-context-dependent, this set is also
+ * SAT-context-dependent.
+ */
+ NodeSet d_keep;
+ /**
+ * A cache of all lemmas sent, which is a user-context-dependent set of
+ * nodes. Notice that this cache does not depedent on lemma property.
+ */
+ NodeSet d_lemmasSent;
+ /** The number of conflicts sent since the last call to reset. */
+ uint32_t d_numConflicts;
+ /** The number of lemmas sent since the last call to reset. */
+ uint32_t d_numCurrentLemmas;
+ /** The number of internal facts added since the last call to reset. */
+ uint32_t d_numCurrentFacts;
+};
+
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__THEORY_INFERENCE_MANAGER_H */
diff --git a/src/theory/theory_model.cpp b/src/theory/theory_model.cpp
index 70f46d6e5..f240d5113 100644
--- a/src/theory/theory_model.cpp
+++ b/src/theory/theory_model.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Clark Barrett, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,6 +16,7 @@
#include "expr/node_algorithm.h"
#include "options/quantifiers_options.h"
#include "options/smt_options.h"
+#include "options/theory_options.h"
#include "options/uf_options.h"
#include "smt/smt_engine.h"
@@ -29,9 +30,9 @@ namespace theory {
TheoryModel::TheoryModel(context::Context* c,
std::string name,
bool enableFuncModels)
- : d_substitutions(c, false),
- d_modelBuilt(false),
- d_modelBuiltSuccess(false),
+ : d_name(name),
+ d_substitutions(c, false),
+ d_equalityEngine(nullptr),
d_using_model_core(false),
d_enableFuncModels(enableFuncModels)
{
@@ -39,10 +40,14 @@ TheoryModel::TheoryModel(context::Context* c,
Assert(d_enableFuncModels || !options::ufHo());
d_true = NodeManager::currentNM()->mkConst( true );
d_false = NodeManager::currentNM()->mkConst( false );
+}
- d_eeContext = new context::Context();
- d_equalityEngine = new eq::EqualityEngine(d_eeContext, name, false);
+TheoryModel::~TheoryModel() {}
+void TheoryModel::finishInit(eq::EqualityEngine* ee)
+{
+ Assert(ee != nullptr);
+ d_equalityEngine = ee;
// The kinds we are treating as function application in congruence
d_equalityEngine->addFunctionKind(kind::APPLY_UF, false, options::ufHo());
d_equalityEngine->addFunctionKind(kind::HO_APPLY);
@@ -51,24 +56,20 @@ TheoryModel::TheoryModel(context::Context* c,
d_equalityEngine->addFunctionKind(kind::APPLY_CONSTRUCTOR);
d_equalityEngine->addFunctionKind(kind::APPLY_SELECTOR_TOTAL);
d_equalityEngine->addFunctionKind(kind::APPLY_TESTER);
- d_eeContext->push();
// do not interpret APPLY_UF if we are not assigning function values
- if (!enableFuncModels)
+ if (!d_enableFuncModels)
{
setSemiEvaluatedKind(kind::APPLY_UF);
}
-}
-
-TheoryModel::~TheoryModel()
-{
- d_eeContext->pop();
- delete d_equalityEngine;
- delete d_eeContext;
+ // Equal and not terms are not relevant terms. In other words, asserted
+ // equalities and negations of predicates (as terms) do not need to be sent
+ // to the model. Regardless, theories should send information to the model
+ // that ensures that all assertions are satisfied.
+ setIrrelevantKind(EQUAL);
+ setIrrelevantKind(NOT);
}
void TheoryModel::reset(){
- d_modelBuilt = false;
- d_modelBuiltSuccess = false;
d_modelCache.clear();
d_comment_str.clear();
d_sep_heap = Node::null();
@@ -83,8 +84,6 @@ void TheoryModel::reset(){
d_uf_terms.clear();
d_ho_uf_terms.clear();
d_uf_models.clear();
- d_eeContext->pop();
- d_eeContext->push();
d_using_model_core = false;
d_model_core.clear();
}
@@ -99,48 +98,38 @@ void TheoryModel::setHeapModel( Node h, Node neq ) {
d_sep_nil_eq = neq;
}
-bool TheoryModel::getHeapModel( Expr& h, Expr& neq ) const {
- if( d_sep_heap.isNull() || d_sep_nil_eq.isNull() ){
+bool TheoryModel::getHeapModel(Node& h, Node& neq) const
+{
+ if (d_sep_heap.isNull() || d_sep_nil_eq.isNull())
+ {
return false;
- }else{
- h = d_sep_heap.toExpr();
- neq = d_sep_nil_eq.toExpr();
- return true;
}
+ h = d_sep_heap;
+ neq = d_sep_nil_eq;
+ return true;
}
bool TheoryModel::hasApproximations() const { return !d_approx_list.empty(); }
-std::vector<std::pair<Expr, Expr> > TheoryModel::getApproximations() const
+std::vector<std::pair<Node, Node> > TheoryModel::getApproximations() const
{
- std::vector<std::pair<Expr, Expr> > approx;
- for (const std::pair<Node, Node>& ap : d_approx_list)
- {
- approx.push_back(
- std::pair<Expr, Expr>(ap.first.toExpr(), ap.second.toExpr()));
- }
- return approx;
+ return d_approx_list;
}
-std::vector<Expr> TheoryModel::getDomainElements(Type t) const
+std::vector<Node> TheoryModel::getDomainElements(TypeNode tn) const
{
// must be an uninterpreted sort
- Assert(t.isSort());
- std::vector<Expr> elements;
- TypeNode tn = TypeNode::fromType(t);
+ Assert(tn.isSort());
+ std::vector<Node> elements;
const std::vector<Node>* type_refs = d_rep_set.getTypeRepsOrNull(tn);
if (type_refs == nullptr || type_refs->empty())
{
// This is called when t is a sort that does not occur in this model.
// Sorts are always interpreted as non-empty, thus we add a single element.
- elements.push_back(t.mkGroundTerm());
+ elements.push_back(tn.mkGroundTerm());
return elements;
}
- for (const Node& n : *type_refs)
- {
- elements.push_back(n.toExpr());
- }
- return elements;
+ return *type_refs;
}
Node TheoryModel::getValue(TNode n) const
@@ -160,39 +149,35 @@ Node TheoryModel::getValue(TNode n) const
return nn;
}
-bool TheoryModel::isModelCoreSymbol(Expr sym) const
+bool TheoryModel::isModelCoreSymbol(Node s) const
{
if (!d_using_model_core)
{
return true;
}
- Node s = Node::fromExpr(sym);
Assert(s.isVar() && s.getKind() != BOUND_VARIABLE);
return d_model_core.find(s) != d_model_core.end();
}
-Expr TheoryModel::getValue( Expr expr ) const{
- Node n = Node::fromExpr( expr );
- Node ret = getValue( n );
- return d_smt.postprocess(ret, TypeNode::fromType(expr.getType())).toExpr();
-}
-
-/** get cardinality for sort */
-Cardinality TheoryModel::getCardinality( Type t ) const{
- TypeNode tn = TypeNode::fromType( t );
+Cardinality TheoryModel::getCardinality(TypeNode tn) const
+{
//for now, we only handle cardinalities for uninterpreted sorts
- if( tn.isSort() ){
- if( d_rep_set.hasType( tn ) ){
- Debug("model-getvalue-debug") << "Get cardinality sort, #rep : " << d_rep_set.getNumRepresentatives( tn ) << std::endl;
- return Cardinality( d_rep_set.getNumRepresentatives( tn ) );
- }else{
- Debug("model-getvalue-debug") << "Get cardinality sort, unconstrained, return 1." << std::endl;
- return Cardinality( 1 );
- }
- }else{
- Debug("model-getvalue-debug") << "Get cardinality other sort, unknown." << std::endl;
+ if (!tn.isSort())
+ {
+ Debug("model-getvalue-debug")
+ << "Get cardinality other sort, unknown." << std::endl;
return Cardinality( CardinalityUnknown() );
}
+ if (d_rep_set.hasType(tn))
+ {
+ Debug("model-getvalue-debug")
+ << "Get cardinality sort, #rep : "
+ << d_rep_set.getNumRepresentatives(tn) << std::endl;
+ return Cardinality(d_rep_set.getNumRepresentatives(tn));
+ }
+ Debug("model-getvalue-debug")
+ << "Get cardinality sort, unconstrained, return 1." << std::endl;
+ return Cardinality(1);
}
Node TheoryModel::getModelValue(TNode n) const
@@ -248,16 +233,15 @@ Node TheoryModel::getModelValue(TNode n) const
{
Debug("model-getvalue-debug")
<< "get cardinality constraint " << ret[0].getType() << std::endl;
- ret = nm->mkConst(
- getCardinality(ret[0].getType().toType()).getFiniteCardinality()
- <= ret[1].getConst<Rational>().getNumerator());
+ ret = nm->mkConst(getCardinality(ret[0].getType()).getFiniteCardinality()
+ <= ret[1].getConst<Rational>().getNumerator());
}
else if (ret.getKind() == kind::CARDINALITY_VALUE)
{
Debug("model-getvalue-debug")
<< "get cardinality value " << ret[0].getType() << std::endl;
- ret = nm->mkConst(Rational(
- getCardinality(ret[0].getType().toType()).getFiniteCardinality()));
+ ret = nm->mkConst(
+ Rational(getCardinality(ret[0].getType()).getFiniteCardinality()));
}
d_modelCache[n] = ret;
return ret;
@@ -445,7 +429,7 @@ bool TheoryModel::assertPredicate(TNode a, bool polarity)
/** assert equality engine */
bool TheoryModel::assertEqualityEngine(const eq::EqualityEngine* ee,
- set<Node>* termSet)
+ const std::set<Node>* termSet)
{
Assert(d_equalityEngine->consistent());
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( ee );
@@ -611,10 +595,7 @@ void TheoryModel::setUsingModelCore()
d_model_core.clear();
}
-void TheoryModel::recordModelCoreSymbol(Expr sym)
-{
- d_model_core.insert(Node::fromExpr(sym));
-}
+void TheoryModel::recordModelCoreSymbol(Node sym) { d_model_core.insert(sym); }
void TheoryModel::setUnevaluatedKind(Kind k) { d_unevaluated_kinds.insert(k); }
@@ -623,6 +604,13 @@ void TheoryModel::setSemiEvaluatedKind(Kind k)
d_semi_evaluated_kinds.insert(k);
}
+void TheoryModel::setIrrelevantKind(Kind k) { d_irrKinds.insert(k); }
+
+const std::set<Kind>& TheoryModel::getIrrelevantKinds() const
+{
+ return d_irrKinds;
+}
+
bool TheoryModel::isLegalElimination(TNode x, TNode val)
{
return !expr::hasSubtermKinds(d_unevaluated_kinds, val);
@@ -754,5 +742,7 @@ std::vector< Node > TheoryModel::getFunctionsToAssign() {
return funcs_to_assign;
}
+const std::string& TheoryModel::getName() const { return d_name; }
+
} /* namespace CVC4::theory */
} /* namespace CVC4 */
diff --git a/src/theory/theory_model.h b/src/theory/theory_model.h
index 2d6bdd2af..e8665bb83 100644
--- a/src/theory/theory_model.h
+++ b/src/theory/theory_model.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Clark Barrett
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,7 +20,7 @@
#include <unordered_map>
#include <unordered_set>
-#include "smt/model.h"
+#include "theory/ee_setup_info.h"
#include "theory/rep_set.h"
#include "theory/substitutions.h"
#include "theory/type_enumerator.h"
@@ -75,30 +75,19 @@ namespace theory {
* above functions such as getRepresentative() when assigning total
* interpretations for uninterpreted functions.
*/
-class TheoryModel : public Model
+class TheoryModel
{
friend class TheoryEngineModelBuilder;
public:
TheoryModel(context::Context* c, std::string name, bool enableFuncModels);
- ~TheoryModel() override;
+ virtual ~TheoryModel();
+ /**
+ * Finish init, where ee is the equality engine the model should use.
+ */
+ void finishInit(eq::EqualityEngine* ee);
/** reset the model */
virtual void reset();
- /** is built
- *
- * Have we attempted to build this model since the last
- * call to reset? Notice for model building techniques
- * that are not guaranteed to succeed (such as
- * when quantified formulas are enabled), a true return
- * value does not imply that this is a model of the
- * current assertions.
- */
- bool isBuilt() { return d_modelBuilt; }
- /** is built success
- *
- * Was this model successfully built since the last call to reset?
- */
- bool isBuiltSuccess() { return d_modelBuiltSuccess; }
//---------------------------- for building the model
/** Adds a substitution from x to t. */
void addSubstitution(TNode x, TNode t, bool invalidateCache = true);
@@ -120,7 +109,7 @@ public:
* is consistent after asserting the equality engine to this model.
*/
bool assertEqualityEngine(const eq::EqualityEngine* ee,
- std::set<Node>* termSet = NULL);
+ const std::set<Node>* termSet = NULL);
/** assert skeleton
*
* This method gives a "skeleton" for the model value of the equivalence
@@ -266,6 +255,17 @@ public:
*/
void setUnevaluatedKind(Kind k);
void setSemiEvaluatedKind(Kind k);
+ /**
+ * Set irrelevant kind. These kinds do not impact model generation, that is,
+ * registered terms in theories of this kind do not need to be sent to
+ * the model. An example is APPLY_TESTER.
+ */
+ void setIrrelevantKind(Kind k);
+ /**
+ * Get the set of irrelevant kinds that have been registered by the above
+ * method.
+ */
+ const std::set<Kind>& getIrrelevantKinds() const;
/** is legal elimination
*
* Returns true if x -> val is a legal elimination of variable x.
@@ -294,21 +294,21 @@ public:
*/
Node getValue(TNode n) const;
/** get comments */
- void getComments(std::ostream& out) const override;
+ void getComments(std::ostream& out) const;
//---------------------------- separation logic
/** set the heap and value sep.nil is equal to */
void setHeapModel(Node h, Node neq);
/** get the heap and value sep.nil is equal to */
- bool getHeapModel(Expr& h, Expr& neq) const override;
+ bool getHeapModel(Node& h, Node& neq) const;
//---------------------------- end separation logic
/** is the list of approximations non-empty? */
- bool hasApproximations() const override;
+ bool hasApproximations() const;
/** get approximations */
- std::vector<std::pair<Expr, Expr> > getApproximations() const override;
+ std::vector<std::pair<Node, Node> > getApproximations() const;
/** get domain elements for uninterpreted sort t */
- std::vector<Expr> getDomainElements(Type t) const override;
+ std::vector<Node> getDomainElements(TypeNode t) const;
/** get the representative set object */
const RepSet* getRepSet() const { return &d_rep_set; }
/** get the representative set object (FIXME: remove this, see #1199) */
@@ -316,17 +316,15 @@ public:
//---------------------------- model cores
/** set using model core */
- void setUsingModelCore() override;
+ void setUsingModelCore();
/** record model core symbol */
- void recordModelCoreSymbol(Expr sym) override;
+ void recordModelCoreSymbol(Node sym);
/** Return whether symbol expr is in the model core. */
- bool isModelCoreSymbol(Expr sym) const override;
+ bool isModelCoreSymbol(Node sym) const;
//---------------------------- end model cores
- /** get value function for Exprs. */
- Expr getValue(Expr expr) const override;
/** get cardinality for sort */
- Cardinality getCardinality(Type t) const override;
+ Cardinality getCardinality(TypeNode t) const;
//---------------------------- function values
/** a map from functions f to a list of all APPLY_UF terms with operator f */
@@ -347,16 +345,14 @@ public:
*/
std::vector< Node > getFunctionsToAssign();
//---------------------------- end function values
+ /** Get the name of this model */
+ const std::string& getName() const;
+
protected:
+ /** Unique name of this model */
+ std::string d_name;
/** substitution map for this model */
SubstitutionMap d_substitutions;
- /** whether we have tried to build this model in the current context */
- bool d_modelBuilt;
- /** whether this model has been built successfully */
- bool d_modelBuiltSuccess;
- /** special local context for our equalityEngine so we can clear it
- * independently of search context */
- context::Context* d_eeContext;
/** equality engine containing all known equalities/disequalities */
eq::EqualityEngine* d_equalityEngine;
/** approximations (see recordApproximation) */
@@ -367,6 +363,8 @@ public:
std::unordered_set<Kind, kind::KindHashFunction> d_unevaluated_kinds;
/** a set of kinds that are semi-evaluated */
std::unordered_set<Kind, kind::KindHashFunction> d_semi_evaluated_kinds;
+ /** The set of irrelevant kinds */
+ std::set<Kind> d_irrKinds;
/**
* Map of representatives of equality engine to used representatives in
* representative set
diff --git a/src/theory/theory_model_builder.cpp b/src/theory/theory_model_builder.cpp
index c82486bdd..1fc609632 100644
--- a/src/theory/theory_model_builder.cpp
+++ b/src/theory/theory_model_builder.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Clark Barrett, Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -372,32 +372,11 @@ void TheoryEngineModelBuilder::addToTypeList(
}
}
-bool TheoryEngineModelBuilder::buildModel(Model* m)
+bool TheoryEngineModelBuilder::buildModel(TheoryModel* tm)
{
Trace("model-builder") << "TheoryEngineModelBuilder: buildModel" << std::endl;
- TheoryModel* tm = (TheoryModel*)m;
eq::EqualityEngine* ee = tm->d_equalityEngine;
- // buildModel should only be called once per check
- Assert(!tm->isBuilt());
-
- // Reset model
- tm->reset();
-
- // mark as built
- tm->d_modelBuilt = true;
- tm->d_modelBuiltSuccess = false;
-
- // Collect model info from the theories
- Trace("model-builder") << "TheoryEngineModelBuilder: Collect model info..."
- << std::endl;
- if (!d_te->collectModelInfo(tm))
- {
- Trace("model-builder")
- << "TheoryEngineModelBuilder: fail collect model info" << std::endl;
- return false;
- }
-
Trace("model-builder")
<< "TheoryEngineModelBuilder: Preprocess build model..." << std::endl;
// model-builder specific initialization
@@ -943,7 +922,6 @@ bool TheoryEngineModelBuilder::buildModel(Model* m)
return false;
}
Trace("model-builder") << "TheoryEngineModelBuilder: success" << std::endl;
- tm->d_modelBuiltSuccess = true;
return true;
}
void TheoryEngineModelBuilder::computeAssignableInfo(
@@ -1104,7 +1082,7 @@ void TheoryEngineModelBuilder::computeAssignableInfo(
}
}
-void TheoryEngineModelBuilder::postProcessModel(bool incomplete, Model* m)
+void TheoryEngineModelBuilder::postProcessModel(bool incomplete, TheoryModel* m)
{
// if we are incomplete, there is no guarantee on the model.
// thus, we do not check the model here.
@@ -1112,19 +1090,17 @@ void TheoryEngineModelBuilder::postProcessModel(bool incomplete, Model* m)
{
return;
}
- TheoryModel* tm = static_cast<TheoryModel*>(m);
- Assert(tm != nullptr);
+ Assert(m != nullptr);
// debug-check the model if the checkModels() is enabled.
if (options::debugCheckModels())
{
- debugCheckModel(tm);
+ debugCheckModel(m);
}
}
void TheoryEngineModelBuilder::debugCheckModel(TheoryModel* tm)
{
#ifdef CVC4_ASSERTIONS
- Assert(tm->isBuilt());
if (tm->hasApproximations())
{
// models with approximations may fail the assertions below
@@ -1209,13 +1185,19 @@ Node TheoryEngineModelBuilder::normalize(TheoryModel* m, TNode r, bool evalOnly)
if (itMap != d_constantReps.end())
{
ri = (*itMap).second;
+ Trace("model-builder-debug") << i << ": const child " << ri << std::endl;
recurse = false;
}
else if (!evalOnly)
{
recurse = false;
+ Trace("model-builder-debug") << i << ": keep " << ri << std::endl;
}
}
+ else
+ {
+ Trace("model-builder-debug") << i << ": no hasTerm " << ri << std::endl;
+ }
if (recurse)
{
ri = normalize(m, ri, evalOnly);
@@ -1231,8 +1213,6 @@ Node TheoryEngineModelBuilder::normalize(TheoryModel* m, TNode r, bool evalOnly)
if (childrenConst)
{
retNode = Rewriter::rewrite(retNode);
- Assert(retNode.getKind() == kind::APPLY_UF
- || !retNode.getType().isFirstClass() || retNode.isConst());
}
}
d_normalizedCache[r] = retNode;
diff --git a/src/theory/theory_model_builder.h b/src/theory/theory_model_builder.h
index caf8bd6b8..4ffcbeee7 100644
--- a/src/theory/theory_model_builder.h
+++ b/src/theory/theory_model_builder.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -23,6 +23,9 @@
#include "theory/theory_model.h"
namespace CVC4 {
+
+class TheoryEngine;
+
namespace theory {
/** TheoryEngineModelBuilder class
@@ -38,7 +41,7 @@ namespace theory {
* this will set up the data structures in TheoryModel to represent
* a model for the current set of assertions.
*/
-class TheoryEngineModelBuilder : public ModelBuilder
+class TheoryEngineModelBuilder
{
typedef std::unordered_map<Node, Node, NodeHashFunction> NodeMap;
typedef std::unordered_set<Node, NodeHashFunction> NodeSet;
@@ -46,19 +49,22 @@ class TheoryEngineModelBuilder : public ModelBuilder
public:
TheoryEngineModelBuilder(TheoryEngine* te);
virtual ~TheoryEngineModelBuilder() {}
- /** Build model function.
- *
- * Should be called only on TheoryModels m.
+ /**
+ * Should be called only on models m after they have been prepared
+ * (e.g. using ModelManager). In other words, the equality engine of model
+ * m contains all relevant information from each theory that is needed
+ * for building a model. This class is responsible simply for ensuring
+ * that all equivalence classes of the equality engine of m are assigned
+ * constants.
*
* This constructs the model m, via the following steps:
- * (1) call TheoryEngine::collectModelInfo,
- * (2) builder-specified pre-processing,
- * (3) find the equivalence classes of m's
+ * (1) builder-specified pre-processing,
+ * (2) find the equivalence classes of m's
* equality engine that initially contain constants,
- * (4) assign constants to all equivalence classes
+ * (3) assign constants to all equivalence classes
* of m's equality engine, through alternating
* iterations of evaluation and enumeration,
- * (5) builder-specific processing, which includes assigning total
+ * (4) builder-specific processing, which includes assigning total
* interpretations to uninterpreted functions.
*
* This function returns false if any of the above
@@ -67,7 +73,7 @@ class TheoryEngineModelBuilder : public ModelBuilder
* builder in steps (2) or (5), for instance, if the model we
* are building fails to satisfy a quantified formula.
*/
- bool buildModel(Model* m) override;
+ bool buildModel(TheoryModel* m);
/** postprocess model
*
@@ -75,7 +81,7 @@ class TheoryEngineModelBuilder : public ModelBuilder
* method checks the internal consistency of the model if we are in a debug
* build.
*/
- void postProcessModel(bool incomplete, Model* m);
+ void postProcessModel(bool incomplete, TheoryModel* m);
protected:
/** pointer to theory engine */
diff --git a/src/theory/theory_preprocessor.cpp b/src/theory/theory_preprocessor.cpp
index b12916b7d..3b68a33ca 100644
--- a/src/theory/theory_preprocessor.cpp
+++ b/src/theory/theory_preprocessor.cpp
@@ -2,10 +2,10 @@
/*! \file theory_preprocessor.cpp
** \verbatim
** Top contributors (to current version):
- ** Andrew Reynolds, Morgan Deters
+ ** Andrew Reynolds, Morgan Deters, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,6 +14,8 @@
#include "theory/theory_preprocessor.h"
+#include "expr/lazy_proof.h"
+#include "expr/skolem_manager.h"
#include "theory/logic_info.h"
#include "theory/rewriter.h"
#include "theory/theory_engine.h"
@@ -24,53 +26,202 @@ namespace CVC4 {
namespace theory {
TheoryPreprocessor::TheoryPreprocessor(TheoryEngine& engine,
- RemoveTermFormulas& tfr)
+ RemoveTermFormulas& tfr,
+ context::UserContext* userContext,
+ ProofNodeManager* pnm)
: d_engine(engine),
d_logicInfo(engine.getLogicInfo()),
- d_ppCache(),
- d_tfr(tfr)
+ d_ppCache(userContext),
+ d_tfr(tfr),
+ d_tpg(pnm ? new TConvProofGenerator(
+ pnm,
+ userContext,
+ TConvPolicy::FIXPOINT,
+ TConvCachePolicy::NEVER,
+ "TheoryPreprocessor::preprocess_rewrite",
+ &d_iqtc)
+ : nullptr),
+ d_tspg(nullptr),
+ d_tpgRew(pnm ? new TConvProofGenerator(pnm,
+ userContext,
+ TConvPolicy::FIXPOINT,
+ TConvCachePolicy::NEVER,
+ "TheoryPreprocessor::rewrite")
+ : nullptr),
+ d_tspgNoPp(nullptr),
+ d_lp(pnm ? new LazyCDProof(pnm,
+ nullptr,
+ userContext,
+ "TheoryPreprocessor::LazyCDProof")
+ : nullptr)
{
+ if (isProofEnabled())
+ {
+ // Make the main term conversion sequence generator, which tracks up to
+ // three conversions made in succession:
+ // (1) theory preprocessing+rewriting
+ // (2) term formula removal
+ // (3) rewriting
+ // Steps (1) and (3) use a common term conversion generator.
+ std::vector<ProofGenerator*> ts;
+ ts.push_back(d_tpg.get());
+ ts.push_back(d_tfr.getTConvProofGenerator());
+ ts.push_back(d_tpg.get());
+ d_tspg.reset(new TConvSeqProofGenerator(
+ pnm, ts, userContext, "TheoryPreprocessor::sequence"));
+ // Make the "no preprocess" term conversion sequence generator, which
+ // applies only steps (2) and (3), where notice (3) must use the
+ // "pure rewrite" term conversion (d_tpgRew).
+ std::vector<ProofGenerator*> tsNoPp;
+ tsNoPp.push_back(d_tfr.getTConvProofGenerator());
+ tsNoPp.push_back(d_tpgRew.get());
+ d_tspgNoPp.reset(new TConvSeqProofGenerator(
+ pnm, tsNoPp, userContext, "TheoryPreprocessor::sequence_no_pp"));
+ }
}
TheoryPreprocessor::~TheoryPreprocessor() {}
-void TheoryPreprocessor::clearCache() { d_ppCache.clear(); }
-
-void TheoryPreprocessor::preprocess(TNode node,
- preprocessing::AssertionPipeline& lemmas,
- bool doTheoryPreprocess)
+TrustNode TheoryPreprocessor::preprocess(TNode node,
+ std::vector<TrustNode>& newLemmas,
+ std::vector<Node>& newSkolems,
+ bool doTheoryPreprocess)
{
+ // In this method, all rewriting steps of node are stored in d_tpg.
+
+ Trace("tpp-debug") << "TheoryPreprocessor::preprocess: start " << node
+ << ", doTheoryPreprocess=" << doTheoryPreprocess
+ << std::endl;
// Run theory preprocessing, maybe
- Node ppNode = doTheoryPreprocess ? theoryPreprocess(node) : Node(node);
+ Node ppNode = node;
+ if (doTheoryPreprocess)
+ {
+ // run theory preprocessing
+ TrustNode tpp = theoryPreprocess(node);
+ ppNode = tpp.getNode();
+ }
// Remove the ITEs
- Trace("te-tform-rm") << "Remove term formulas from " << ppNode << std::endl;
- lemmas.push_back(ppNode);
- lemmas.updateRealAssertionsEnd();
- d_tfr.run(lemmas.ref(), lemmas.getIteSkolemMap());
- Trace("te-tform-rm") << "..done " << lemmas[0] << std::endl;
+ TrustNode ttfr = d_tfr.run(ppNode, newLemmas, newSkolems, false);
+ Node rtfNode = ttfr.getNode();
if (Debug.isOn("lemma-ites"))
{
- Debug("lemma-ites") << "removed ITEs from lemma: " << ppNode << endl;
- Debug("lemma-ites") << " + now have the following " << lemmas.size()
+ Debug("lemma-ites") << "removed ITEs from lemma: " << ttfr.getNode()
+ << endl;
+ Debug("lemma-ites") << " + now have the following " << newLemmas.size()
<< " lemma(s):" << endl;
- for (std::vector<Node>::const_iterator i = lemmas.begin();
- i != lemmas.end();
- ++i)
+ for (size_t i = 0, lsize = newLemmas.size(); i <= lsize; ++i)
{
- Debug("lemma-ites") << " + " << *i << endl;
+ Debug("lemma-ites") << " + " << newLemmas[i].getNode() << endl;
}
Debug("lemma-ites") << endl;
}
+ // Rewrite the main node, we rewrite and store the proof step, if necessary,
+ // in d_tpg, which maintains the fact that d_tpg can prove the rewrite.
+ Node retNode = rewriteWithProof(rtfNode);
+
+ if (Trace.isOn("tpp-debug"))
+ {
+ if (node != ppNode)
+ {
+ Trace("tpp-debug") << "after preprocessing : " << ppNode << std::endl;
+ }
+ if (rtfNode != ppNode)
+ {
+ Trace("tpp-debug") << "after rtf : " << rtfNode << std::endl;
+ }
+ if (retNode != rtfNode)
+ {
+ Trace("tpp-debug") << "after rewriting : " << retNode << std::endl;
+ }
+ Trace("tpp-debug") << "TheoryPreprocessor::preprocess: finish" << std::endl;
+ }
+ if (node == retNode)
+ {
+ Trace("tpp-debug") << "...TheoryPreprocessor::preprocess returned no change"
+ << std::endl;
+ // no change
+ Assert(newLemmas.empty());
+ return TrustNode::null();
+ }
+
+ // Now, sequence the conversion steps if proofs are enabled.
+ TrustNode tret;
+ if (isProofEnabled())
+ {
+ std::vector<Node> cterms;
+ cterms.push_back(node);
+ if (doTheoryPreprocess)
+ {
+ cterms.push_back(ppNode);
+ }
+ cterms.push_back(rtfNode);
+ cterms.push_back(retNode);
+ // We have that:
+ // node -> ppNode via preprocessing + rewriting (if doTheoryPreprocess)
+ // ppNode -> rtfNode via term formula removal
+ // rtfNode -> retNode via rewriting
+ if (!doTheoryPreprocess)
+ {
+ // If preprocessing is not performed, we cannot use the main sequence
+ // generator, instead we use d_tspgNoPp.
+ // We register the top-level rewrite in the pure rewrite term converter.
+ d_tpgRew->addRewriteStep(
+ rtfNode, retNode, PfRule::REWRITE, {}, {rtfNode});
+ // Now get the trust node from the sequence generator
+ tret = d_tspgNoPp->mkTrustRewriteSequence(cterms);
+ }
+ else
+ {
+ // we wil use the sequence generator
+ tret = d_tspg->mkTrustRewriteSequence(cterms);
+ }
+ tret.debugCheckClosed("tpp-debug", "TheoryPreprocessor::lemma_ret");
+ }
+ else
+ {
+ tret = TrustNode::mkTrustRewrite(node, retNode, nullptr);
+ }
// now, rewrite the lemmas
- Node retLemma;
- for (size_t i = 0, lsize = lemmas.size(); i < lsize; ++i)
+ Trace("tpp-debug") << "TheoryPreprocessor::preprocess: process lemmas"
+ << std::endl;
+ for (size_t i = 0, lsize = newLemmas.size(); i < lsize; ++i)
{
- Node rewritten = Rewriter::rewrite(lemmas[i]);
- lemmas.replace(i, rewritten);
+ // get the trust node to process
+ TrustNode trn = newLemmas[i];
+ trn.debugCheckClosed(
+ "tpp-debug", "TheoryPreprocessor::lemma_new_initial", false);
+ Assert(trn.getKind() == TrustNodeKind::LEMMA);
+ Node assertion = trn.getNode();
+ // rewrite, which is independent of d_tpg, since additional lemmas
+ // are justified separately.
+ Node rewritten = Rewriter::rewrite(assertion);
+ if (assertion != rewritten)
+ {
+ if (isProofEnabled())
+ {
+ Assert(d_lp != nullptr);
+ // store in the lazy proof
+ d_lp->addLazyStep(assertion,
+ trn.getGenerator(),
+ PfRule::THEORY_PREPROCESS_LEMMA,
+ true,
+ "TheoryPreprocessor::rewrite_lemma_new");
+ d_lp->addStep(rewritten,
+ PfRule::MACRO_SR_PRED_TRANSFORM,
+ {assertion},
+ {rewritten});
+ }
+ newLemmas[i] = TrustNode::mkTrustLemma(rewritten, d_lp.get());
+ }
+ Assert(!isProofEnabled() || newLemmas[i].getGenerator() != nullptr);
+ newLemmas[i].debugCheckClosed("tpp-debug", "TheoryPreprocessor::lemma_new");
}
+ Trace("tpp-debug") << "...TheoryPreprocessor::preprocess returned "
+ << tret.getNode() << std::endl;
+ return tret;
}
struct preprocess_stack_element
@@ -80,7 +231,7 @@ struct preprocess_stack_element
preprocess_stack_element(TNode n) : node(n), children_added(false) {}
};
-Node TheoryPreprocessor::theoryPreprocess(TNode assertion)
+TrustNode TheoryPreprocessor::theoryPreprocess(TNode assertion)
{
Trace("theory::preprocess")
<< "TheoryPreprocessor::theoryPreprocess(" << assertion << ")" << endl;
@@ -96,7 +247,7 @@ Node TheoryPreprocessor::theoryPreprocess(TNode assertion)
preprocess_stack_element& stackHead = toVisit.back();
TNode current = stackHead.node;
- Debug("theory::internal")
+ Trace("theory::preprocess-debug")
<< "TheoryPreprocessor::theoryPreprocess(" << assertion
<< "): processing " << current << endl;
@@ -125,7 +276,8 @@ Node TheoryPreprocessor::theoryPreprocess(TNode assertion)
{
Node ppRewritten = ppTheoryRewrite(current);
d_ppCache[current] = ppRewritten;
- Assert(Rewriter::rewrite(d_ppCache[current]) == d_ppCache[current]);
+ Assert(Rewriter::rewrite(d_ppCache[current].get())
+ == d_ppCache[current].get());
continue;
}
@@ -141,15 +293,15 @@ Node TheoryPreprocessor::theoryPreprocess(TNode assertion)
for (unsigned i = 0; i < current.getNumChildren(); ++i)
{
Assert(d_ppCache.find(current[i]) != d_ppCache.end());
- builder << d_ppCache[current[i]];
+ builder << d_ppCache[current[i]].get();
}
// Mark the substitution and continue
Node result = builder;
if (result != current)
{
- result = Rewriter::rewrite(result);
+ result = rewriteWithProof(result);
}
- Debug("theory::internal")
+ Trace("theory::preprocess-debug")
<< "TheoryPreprocessor::theoryPreprocess(" << assertion
<< "): setting " << current << " -> " << result << endl;
d_ppCache[current] = result;
@@ -177,7 +329,7 @@ Node TheoryPreprocessor::theoryPreprocess(TNode assertion)
else
{
// No children, so we're done
- Debug("substitution::internal")
+ Trace("theory::preprocess-debug")
<< "SubstitutionMap::internalSubstitute(" << assertion
<< "): setting " << current << " -> " << current << endl;
d_ppCache[current] = current;
@@ -185,9 +337,9 @@ Node TheoryPreprocessor::theoryPreprocess(TNode assertion)
}
}
}
-
// Return the substituted version
- return d_ppCache[assertion];
+ Node res = d_ppCache[assertion];
+ return TrustNode::mkTrustRewrite(assertion, res, d_tpg.get());
}
// Recursively traverse a term and call the theory rewriter on its sub-terms
@@ -201,18 +353,13 @@ Node TheoryPreprocessor::ppTheoryRewrite(TNode term)
unsigned nc = term.getNumChildren();
if (nc == 0)
{
- TrustNode trn = d_engine.theoryOf(term)->ppRewrite(term);
- return trn.isNull() ? Node(term) : trn.getNode();
+ return preprocessWithProof(term);
}
Trace("theory-pp") << "ppTheoryRewrite { " << term << endl;
- Node newTerm;
+ Node newTerm = term;
// do not rewrite inside quantifiers
- if (term.isClosure())
- {
- newTerm = Rewriter::rewrite(term);
- }
- else
+ if (!term.isClosure())
{
NodeBuilder<> newNode(term.getKind());
if (term.getMetaKind() == kind::metakind::PARAMETERIZED)
@@ -224,18 +371,75 @@ Node TheoryPreprocessor::ppTheoryRewrite(TNode term)
{
newNode << ppTheoryRewrite(term[i]);
}
- newTerm = Rewriter::rewrite(Node(newNode));
- }
- TrustNode trn = d_engine.theoryOf(newTerm)->ppRewrite(newTerm);
- Node newTerm2 = trn.isNull() ? newTerm : trn.getNode();
- if (newTerm != newTerm2)
- {
- newTerm = ppTheoryRewrite(Rewriter::rewrite(newTerm2));
+ newTerm = Node(newNode);
}
+ newTerm = rewriteWithProof(newTerm);
+ newTerm = preprocessWithProof(newTerm);
d_ppCache[term] = newTerm;
Trace("theory-pp") << "ppTheoryRewrite returning " << newTerm << "}" << endl;
return newTerm;
}
+Node TheoryPreprocessor::rewriteWithProof(Node term)
+{
+ Node termr = Rewriter::rewrite(term);
+ // store rewrite step if tracking proofs and it rewrites
+ if (isProofEnabled())
+ {
+ // may rewrite the same term more than once, thus check hasRewriteStep
+ if (termr != term)
+ {
+ Trace("tpp-debug") << "TheoryPreprocessor: addRewriteStep (rewriting) "
+ << term << " -> " << termr << std::endl;
+ // always use term context hash 0 (default)
+ d_tpg->addRewriteStep(term, termr, PfRule::REWRITE, {}, {term});
+ }
+ }
+ return termr;
+}
+
+Node TheoryPreprocessor::preprocessWithProof(Node term)
+{
+ // Important that it is in rewritten form, to ensure that the rewrite steps
+ // recorded in d_tpg are functional. In other words, there should not
+ // be steps from the same term to multiple rewritten forms, which would be
+ // the case if we registered a preprocessing step for a non-rewritten term.
+ Assert(term == Rewriter::rewrite(term));
+ // call ppRewrite for the given theory
+ TrustNode trn = d_engine.theoryOf(term)->ppRewrite(term);
+ if (trn.isNull())
+ {
+ // no change, return original term
+ return term;
+ }
+ Node termr = trn.getNode();
+ Assert(term != termr);
+ if (isProofEnabled())
+ {
+ if (trn.getGenerator() != nullptr)
+ {
+ Trace("tpp-debug") << "TheoryPreprocessor: addRewriteStep (generator) "
+ << term << " -> " << termr << std::endl;
+ trn.debugCheckClosed("tpp-debug",
+ "TheoryPreprocessor::preprocessWithProof");
+ // always use term context hash 0 (default)
+ d_tpg->addRewriteStep(
+ term, termr, trn.getGenerator(), PfRule::ASSUME, true);
+ }
+ else
+ {
+ Trace("tpp-debug") << "TheoryPreprocessor: addRewriteStep (trusted) "
+ << term << " -> " << termr << std::endl;
+ // small step trust
+ d_tpg->addRewriteStep(
+ term, termr, PfRule::THEORY_PREPROCESS, {}, {term.eqNode(termr)});
+ }
+ }
+ termr = rewriteWithProof(termr);
+ return ppTheoryRewrite(termr);
+}
+
+bool TheoryPreprocessor::isProofEnabled() const { return d_tpg != nullptr; }
+
} // namespace theory
} // namespace CVC4
diff --git a/src/theory/theory_preprocessor.h b/src/theory/theory_preprocessor.h
index 2488cf162..e34b10b1d 100644
--- a/src/theory/theory_preprocessor.h
+++ b/src/theory/theory_preprocessor.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,15 +19,19 @@
#include <unordered_map>
+#include "context/cdhashmap.h"
+#include "context/context.h"
+#include "expr/lazy_proof.h"
#include "expr/node.h"
-#include "preprocessing/assertion_pipeline.h"
+#include "expr/tconv_seq_proof_generator.h"
+#include "expr/term_conversion_proof_generator.h"
+#include "theory/trust_node.h"
namespace CVC4 {
class LogicInfo;
class TheoryEngine;
class RemoveTermFormulas;
-class LazyCDProof;
namespace theory {
@@ -36,31 +40,41 @@ namespace theory {
*/
class TheoryPreprocessor
{
- typedef std::unordered_map<Node, Node, NodeHashFunction> NodeMap;
+ typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeMap;
public:
/** Constructs a theory preprocessor */
- TheoryPreprocessor(TheoryEngine& engine, RemoveTermFormulas& tfr);
+ TheoryPreprocessor(TheoryEngine& engine,
+ RemoveTermFormulas& tfr,
+ context::UserContext* userContext,
+ ProofNodeManager* pnm = nullptr);
/** Destroys a theory preprocessor */
~TheoryPreprocessor();
- /** Clear the cache of this class */
- void clearCache();
/**
- * Preprocesses node and stores it along with lemmas generated by
- * preprocessing into the assertion pipeline lemmas. The (optional) argument
- * lcp is the proof that stores a proof of all top-level formulas in lemmas,
- * assuming that lcp initially contains a proof of node. The flag
- * doTheoryPreprocess is whether we should run theory-specific preprocessing.
+ * Preprocesses the given assertion node. It returns a TrustNode of kind
+ * TrustNodeKind::REWRITE indicating the preprocessed form of node. It stores
+ * additional lemmas in newLemmas, which are trust nodes of kind
+ * TrustNodeKind::LEMMA. These correspond to e.g. lemmas corresponding to ITE
+ * removal. For each lemma in newLemmas, we add the corresponding skolem that
+ * the lemma defines. The flag doTheoryPreprocess is whether we should run
+ * theory-specific preprocessing.
+ *
+ * @param node The assertion to preprocess,
+ * @param newLemmas The lemmas to add to the set of assertions,
+ * @param newSkolems The skolems that newLemmas correspond to,
+ * @param doTheoryPreprocess whether to run theory-specific preprocessing.
+ * @return The trust node corresponding to rewriting node via preprocessing.
*/
- void preprocess(TNode node,
- preprocessing::AssertionPipeline& lemmas,
- bool doTheoryPreprocess);
+ TrustNode preprocess(TNode node,
+ std::vector<TrustNode>& newLemmas,
+ std::vector<Node>& newSkolems,
+ bool doTheoryPreprocess);
/**
* Runs theory specific preprocessing on the non-Boolean parts of
* the formula. This is only called on input assertions, after ITEs
* have been removed.
*/
- Node theoryPreprocess(TNode node);
+ TrustNode theoryPreprocess(TNode node);
private:
/** Reference to owning theory engine */
@@ -71,8 +85,49 @@ class TheoryPreprocessor
NodeMap d_ppCache;
/** The term formula remover */
RemoveTermFormulas& d_tfr;
+ /** The term context, which computes hash values for term contexts. */
+ InQuantTermContext d_iqtc;
+ /**
+ * A term conversion proof generator storing preprocessing and rewriting
+ * steps.
+ */
+ std::unique_ptr<TConvProofGenerator> d_tpg;
+ /**
+ * A term conversion sequence generator, which applies theory preprocessing,
+ * term formula removal, and rewriting in sequence.
+ */
+ std::unique_ptr<TConvSeqProofGenerator> d_tspg;
+ /**
+ * A term conversion proof generator storing rewriting steps, which is used
+ * for calls to preprocess when doTheoryPreprocess is false. We store
+ * (top-level) rewrite steps only. Notice this is intentionally separate
+ * from d_tpg, which interleaves both preprocessing and rewriting.
+ */
+ std::unique_ptr<TConvProofGenerator> d_tpgRew;
+ /**
+ * A term conversion sequence generator, which applies term formula removal
+ * and rewriting in sequence. This is used for reconstruct proofs of
+ * calls to preprocess where doTheoryPreprocess is false.
+ */
+ std::unique_ptr<TConvSeqProofGenerator> d_tspgNoPp;
+ /** A lazy proof, for additional lemmas. */
+ std::unique_ptr<LazyCDProof> d_lp;
/** Helper for theoryPreprocess */
Node ppTheoryRewrite(TNode term);
+ /**
+ * Rewrite with proof, which stores a REWRITE step in d_tpg if necessary
+ * and returns the rewritten form of term.
+ */
+ Node rewriteWithProof(Node term);
+ /**
+ * Preprocess with proof, which calls the appropriate ppRewrite method,
+ * stores the corresponding rewrite step in d_tpg if necessary and returns
+ * the preprocessed and rewritten form of term. It should be the case that
+ * term is already in rewritten form.
+ */
+ Node preprocessWithProof(Node term);
+ /** Proofs enabled */
+ bool isProofEnabled() const;
};
} // namespace theory
diff --git a/src/theory/theory_proof_step_buffer.cpp b/src/theory/theory_proof_step_buffer.cpp
index 8a518b49a..a08b15901 100644
--- a/src/theory/theory_proof_step_buffer.cpp
+++ b/src/theory/theory_proof_step_buffer.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -26,6 +26,33 @@ TheoryProofStepBuffer::TheoryProofStepBuffer(ProofChecker* pc)
{
}
+bool TheoryProofStepBuffer::applyEqIntro(Node src,
+ Node tgt,
+ const std::vector<Node>& exp,
+ MethodId ids,
+ MethodId idr)
+{
+ std::vector<Node> args;
+ args.push_back(src);
+ builtin::BuiltinProofRuleChecker::addMethodIds(args, ids, idr);
+ Node res = tryStep(PfRule::MACRO_SR_EQ_INTRO, exp, args);
+ if (res.isNull())
+ {
+ // failed to apply
+ return false;
+ }
+ // should have concluded the expected equality
+ Node expected = src.eqNode(tgt);
+ if (res != expected)
+ {
+ // did not provide the correct target
+ popStep();
+ return false;
+ }
+ // successfully proved src == tgt.
+ return true;
+}
+
bool TheoryProofStepBuffer::applyPredTransform(Node src,
Node tgt,
const std::vector<Node>& exp,
@@ -90,5 +117,119 @@ Node TheoryProofStepBuffer::applyPredElim(Node src,
return srcRew;
}
+Node TheoryProofStepBuffer::factorReorderElimDoubleNeg(Node n)
+{
+ if (n.getKind() != kind::OR)
+ {
+ return elimDoubleNegLit(n);
+ }
+ NodeManager* nm = NodeManager::currentNM();
+ std::vector<Node> children{n.begin(), n.end()};
+ std::vector<Node> childrenEqs;
+ // eliminate double neg for each lit. Do it first because it may expose
+ // duplicates
+ bool hasDoubleNeg = false;
+ for (unsigned i = 0; i < children.size(); ++i)
+ {
+ if (children[i].getKind() == kind::NOT
+ && children[i][0].getKind() == kind::NOT)
+ {
+ hasDoubleNeg = true;
+ childrenEqs.push_back(children[i].eqNode(children[i][0][0]));
+ addStep(PfRule::MACRO_SR_PRED_INTRO,
+ {},
+ {childrenEqs.back()},
+ childrenEqs.back());
+ // update child
+ children[i] = children[i][0][0];
+ }
+ else
+ {
+ childrenEqs.push_back(children[i].eqNode(children[i]));
+ addStep(PfRule::REFL, {}, {children[i]}, childrenEqs.back());
+ }
+ }
+ if (hasDoubleNeg)
+ {
+ Node oldn = n;
+ n = nm->mkNode(kind::OR, children);
+ // Create a congruence step to justify replacement of each doubly negated
+ // literal. This is done to avoid having to use MACRO_SR_PRED_TRANSFORM
+ // from the old clause to the new one, which, under the standard rewriter,
+ // may not hold. An example is
+ //
+ // ---------------------------------------------------------------------
+ // (or (or (not x2) x1 x2) (not (not x2))) = (or (or (not x2) x1 x2) x2)
+ //
+ // which fails due to factoring not happening after flattening.
+ //
+ // Using congruence only the
+ //
+ // ------------------ MACRO_SR_PRED_INTRO
+ // (not (not t)) = t
+ //
+ // steps are added, which, since double negation is eliminated in a
+ // pre-rewrite in the Boolean rewriter, will always hold under the
+ // standard rewriter.
+ Node congEq = oldn.eqNode(n);
+ addStep(PfRule::CONG,
+ childrenEqs,
+ {ProofRuleChecker::mkKindNode(kind::OR)},
+ congEq);
+ // add an equality resolution step to derive normalize clause
+ addStep(PfRule::EQ_RESOLVE, {oldn, congEq}, {}, n);
+ }
+ children.clear();
+ // remove duplicates while keeping the order of children
+ std::unordered_set<TNode, TNodeHashFunction> clauseSet;
+ unsigned size = n.getNumChildren();
+ for (unsigned i = 0; i < size; ++i)
+ {
+ if (clauseSet.count(n[i]))
+ {
+ continue;
+ }
+ children.push_back(n[i]);
+ clauseSet.insert(n[i]);
+ }
+ // if factoring changed
+ if (children.size() < size)
+ {
+ Node factored = children.empty()
+ ? nm->mkConst<bool>(false)
+ : children.size() == 1 ? children[0]
+ : nm->mkNode(kind::OR, children);
+ // don't overwrite what already has a proof step to avoid cycles
+ addStep(PfRule::FACTORING, {n}, {}, factored);
+ n = factored;
+ }
+ // nothing to order
+ if (children.size() < 2)
+ {
+ return n;
+ }
+ // order
+ std::sort(children.begin(), children.end());
+ Node ordered = nm->mkNode(kind::OR, children);
+ // if ordering changed
+ if (ordered != n)
+ {
+ // don't overwrite what already has a proof step to avoid cycles
+ addStep(PfRule::REORDERING, {n}, {ordered}, ordered);
+ }
+ return ordered;
+}
+
+Node TheoryProofStepBuffer::elimDoubleNegLit(Node n)
+{
+ // eliminate double neg
+ if (n.getKind() == kind::NOT && n[0].getKind() == kind::NOT)
+ {
+ addStep(PfRule::NOT_NOT_ELIM, {n}, {}, n[0][0]);
+ return n[0][0];
+ }
+ return n;
+}
+
} // namespace theory
} // namespace CVC4
diff --git a/src/theory/theory_proof_step_buffer.h b/src/theory/theory_proof_step_buffer.h
index 55b4ee1c0..d67781428 100644
--- a/src/theory/theory_proof_step_buffer.h
+++ b/src/theory/theory_proof_step_buffer.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -37,6 +37,17 @@ class TheoryProofStepBuffer : public ProofStepBuffer
~TheoryProofStepBuffer() {}
//---------------------------- utilities builtin proof rules
/**
+ * Apply equality introduction. If this method returns true, it adds proof
+ * step(s) to the buffer that conclude (= src tgt) from premises exp. In
+ * particular, it may attempt to apply the rule MACRO_SR_EQ_INTRO. This
+ * method should be applied when tgt is equivalent to src assuming exp.
+ */
+ bool applyEqIntro(Node src,
+ Node tgt,
+ const std::vector<Node>& exp,
+ MethodId ids = MethodId::SB_DEFAULT,
+ MethodId idr = MethodId::RW_REWRITE);
+ /**
* Apply predicate transform. If this method returns true, it adds (at most
* one) proof step to the buffer that conclude tgt from premises src, exp. In
* particular, it may attempt to apply MACRO_SR_PRED_TRANSFORM. This method
@@ -73,6 +84,29 @@ class TheoryProofStepBuffer : public ProofStepBuffer
MethodId ids = MethodId::SB_DEFAULT,
MethodId idr = MethodId::RW_REWRITE);
//---------------------------- end utilities builtin proof rules
+
+ //---------------------------- utility methods for normalizing clauses
+ /**
+ * Normalizes a non-unit clause (an OR node) according to factoring and
+ * reordering, i.e. removes duplicates and reorders literals (according to
+ * node ids). Moreover it eliminates double negations, which can be done also
+ * for unit clauses (a arbitrary Boolean node). All normalization steps are
+ * tracked via proof steps added to this proof step buffer.
+ *
+ * @param n the clause to be normalized
+ * @return the normalized clause node
+ */
+ Node factorReorderElimDoubleNeg(Node n);
+
+ /**
+ * Eliminates double negation of a literal if it has the form
+ * (not (not t))
+ * If the elimination happens, a step is added to this proof step buffer.
+ *
+ * @param n the node to have the top-level double negation eliminated
+ * @return the normalized clause node
+ */
+ Node elimDoubleNegLit(Node n);
};
} // namespace theory
diff --git a/src/theory/theory_registrar.h b/src/theory/theory_registrar.h
index f2217f619..bc88b93f4 100644
--- a/src/theory/theory_registrar.h
+++ b/src/theory/theory_registrar.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Tim King, Liana Hadarean
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/theory_rewriter.cpp b/src/theory/theory_rewriter.cpp
index a8dfbb2bb..35f25dc5a 100644
--- a/src/theory/theory_rewriter.cpp
+++ b/src/theory/theory_rewriter.cpp
@@ -4,8 +4,8 @@
** Top contributors (to current version):
** Andrew Reynolds
** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/theory_rewriter.h b/src/theory/theory_rewriter.h
index cabfad2fc..bbf1c853f 100644
--- a/src/theory/theory_rewriter.h
+++ b/src/theory/theory_rewriter.h
@@ -2,10 +2,10 @@
/*! \file theory_rewriter.h
** \verbatim
** Top contributors (to current version):
- ** Andres Noetzli, Morgan Deters, Andrew Reynolds
+ ** Andres Noetzli, Andrew Reynolds, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/theory_state.cpp b/src/theory/theory_state.cpp
new file mode 100644
index 000000000..95a96808e
--- /dev/null
+++ b/src/theory/theory_state.cpp
@@ -0,0 +1,141 @@
+/********************* */
+/*! \file theory_state.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Mathias Preiner
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief A theory state for Theory
+ **/
+
+#include "theory/theory_state.h"
+
+#include "theory/uf/equality_engine.h"
+
+namespace CVC4 {
+namespace theory {
+
+TheoryState::TheoryState(context::Context* c,
+ context::UserContext* u,
+ Valuation val)
+ : d_context(c),
+ d_ucontext(u),
+ d_valuation(val),
+ d_ee(nullptr),
+ d_conflict(c, false)
+{
+}
+
+void TheoryState::setEqualityEngine(eq::EqualityEngine* ee) { d_ee = ee; }
+
+context::Context* TheoryState::getSatContext() const { return d_context; }
+
+context::UserContext* TheoryState::getUserContext() const { return d_ucontext; }
+
+bool TheoryState::hasTerm(TNode a) const
+{
+ Assert(d_ee != nullptr);
+ return d_ee->hasTerm(a);
+}
+
+TNode TheoryState::getRepresentative(TNode t) const
+{
+ Assert(d_ee != nullptr);
+ if (d_ee->hasTerm(t))
+ {
+ return d_ee->getRepresentative(t);
+ }
+ return t;
+}
+
+bool TheoryState::areEqual(TNode a, TNode b) const
+{
+ Assert(d_ee != nullptr);
+ if (a == b)
+ {
+ return true;
+ }
+ else if (hasTerm(a) && hasTerm(b))
+ {
+ return d_ee->areEqual(a, b);
+ }
+ return false;
+}
+
+bool TheoryState::areDisequal(TNode a, TNode b) const
+{
+ Assert(d_ee != nullptr);
+ if (a == b)
+ {
+ return false;
+ }
+
+ bool isConst = true;
+ bool hasTerms = true;
+ if (hasTerm(a))
+ {
+ a = d_ee->getRepresentative(a);
+ isConst = a.isConst();
+ }
+ else if (!a.isConst())
+ {
+ // if not constant and not a term in the ee, it cannot be disequal
+ return false;
+ }
+ else
+ {
+ hasTerms = false;
+ }
+
+ if (hasTerm(b))
+ {
+ b = d_ee->getRepresentative(b);
+ isConst = isConst && b.isConst();
+ }
+ else if (!b.isConst())
+ {
+ // same as above, it cannot be disequal
+ return false;
+ }
+ else
+ {
+ hasTerms = false;
+ }
+
+ if (isConst)
+ {
+ // distinct constants are disequal
+ return a != b;
+ }
+ else if (!hasTerms)
+ {
+ return false;
+ }
+ // otherwise there may be an explicit disequality in the equality engine
+ return d_ee->areDisequal(a, b, false);
+}
+
+eq::EqualityEngine* TheoryState::getEqualityEngine() const { return d_ee; }
+
+void TheoryState::notifyInConflict() { d_conflict = true; }
+
+bool TheoryState::isInConflict() const { return d_conflict; }
+
+bool TheoryState::isSatLiteral(TNode lit) const
+{
+ return d_valuation.isSatLiteral(lit);
+}
+
+TheoryModel* TheoryState::getModel() { return d_valuation.getModel(); }
+
+bool TheoryState::hasSatValue(TNode n, bool& value) const
+{
+ return d_valuation.hasSatValue(n, value);
+}
+
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/theory_state.h b/src/theory/theory_state.h
new file mode 100644
index 000000000..187d586a1
--- /dev/null
+++ b/src/theory/theory_state.h
@@ -0,0 +1,105 @@
+/********************* */
+/*! \file theory_state.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Morgan Deters, Mathias Preiner
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief A theory state for Theory
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__THEORY_STATE_H
+#define CVC4__THEORY__THEORY_STATE_H
+
+#include "context/cdo.h"
+#include "expr/node.h"
+#include "theory/valuation.h"
+
+namespace CVC4 {
+namespace theory {
+
+namespace eq {
+class EqualityEngine;
+}
+
+class TheoryState
+{
+ public:
+ TheoryState(context::Context* c, context::UserContext* u, Valuation val);
+ virtual ~TheoryState() {}
+ /**
+ * Set equality engine, where ee is a pointer to the official equality engine
+ * of theory.
+ */
+ void setEqualityEngine(eq::EqualityEngine* ee);
+ /** Get the SAT context */
+ context::Context* getSatContext() const;
+ /** Get the user context */
+ context::UserContext* getUserContext() const;
+ //-------------------------------------- equality information
+ /** Is t registered as a term in the equality engine of this class? */
+ virtual bool hasTerm(TNode a) const;
+ /**
+ * Get the representative of t in the equality engine of this class, or t
+ * itself if it is not registered as a term.
+ */
+ virtual TNode getRepresentative(TNode t) const;
+ /**
+ * Are a and b equal according to the equality engine of this class? Also
+ * returns true if a and b are identical.
+ */
+ virtual bool areEqual(TNode a, TNode b) const;
+ /**
+ * Are a and b disequal according to the equality engine of this class? Also
+ * returns true if the representative of a and b are distinct constants.
+ */
+ virtual bool areDisequal(TNode a, TNode b) const;
+ /** get equality engine */
+ eq::EqualityEngine* getEqualityEngine() const;
+ //-------------------------------------- end equality information
+ /**
+ * Set that the current state of the solver is in conflict. This should be
+ * called immediately after a call to conflict(...) on the output channel of
+ * the theory.
+ */
+ virtual void notifyInConflict();
+ /** Are we currently in conflict? */
+ virtual bool isInConflict() const;
+
+ /** Returns true if lit is a SAT literal. */
+ virtual bool isSatLiteral(TNode lit) const;
+ /**
+ * Returns pointer to model. This model is only valid during last call effort
+ * check.
+ */
+ TheoryModel* getModel();
+
+ /** Returns true if n has a current SAT assignment and stores it in value. */
+ virtual bool hasSatValue(TNode n, bool& value) const;
+
+ protected:
+ /** Pointer to the SAT context object used by the theory. */
+ context::Context* d_context;
+ /** Pointer to the user context object used by the theory. */
+ context::UserContext* d_ucontext;
+ /**
+ * The valuation proxy for the Theory to communicate back with the
+ * theory engine (and other theories).
+ */
+ Valuation d_valuation;
+ /** Pointer to equality engine of the theory. */
+ eq::EqualityEngine* d_ee;
+ /** Are we in conflict? */
+ context::CDO<bool> d_conflict;
+};
+
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__SOLVER_STATE_H */
diff --git a/src/theory/theory_test_utils.h b/src/theory/theory_test_utils.h
index 61caca82a..5d2711f1d 100644
--- a/src/theory/theory_test_utils.h
+++ b/src/theory/theory_test_utils.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -27,7 +27,6 @@
#include "expr/node.h"
#include "theory/interrupted.h"
#include "theory/output_channel.h"
-#include "util/proof.h"
#include "util/resource_manager.h"
#include "util/unsafe_interrupt_exception.h"
@@ -69,22 +68,27 @@ public:
~TestOutputChannel() override {}
void safePoint(ResourceManager::Resource r) override {}
- void conflict(TNode n, std::unique_ptr<Proof> pf) override
- {
- push(CONFLICT, n);
- }
+ void conflict(TNode n) override { push(CONFLICT, n); }
+
+ void trustedConflict(TrustNode n) override { push(CONFLICT, n.getNode()); }
bool propagate(TNode n) override {
push(PROPAGATE, n);
return true;
}
- LemmaStatus lemma(TNode n, ProofRule rule, bool removable = false,
- bool preprocess = false, bool sendAtoms = false) override {
+ LemmaStatus lemma(TNode n, LemmaProperty p) override
+ {
push(LEMMA, n);
return LemmaStatus(Node::null(), 0);
}
+ LemmaStatus trustedLemma(TrustNode n, LemmaProperty p) override
+ {
+ push(LEMMA, n.getNode());
+ return LemmaStatus(Node::null(), 0);
+ }
+
void requirePhase(TNode, bool) override {}
void setIncomplete() override {}
void handleUserAttribute(const char* attr, theory::Theory* t) override {}
diff --git a/src/theory/theory_traits_template.h b/src/theory/theory_traits_template.h
index 775f42a46..658c3c98a 100644
--- a/src/theory/theory_traits_template.h
+++ b/src/theory/theory_traits_template.h
@@ -5,7 +5,7 @@
** Morgan Deters, Dejan Jovanovic, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -34,8 +34,6 @@ struct TheoryTraits;
${theory_traits}
-#line 38 "${template}"
-
struct TheoryConstructor {
static void addTheory(TheoryEngine* engine, TheoryId id) {
switch(id) {
diff --git a/src/theory/trust_node.cpp b/src/theory/trust_node.cpp
index 25aef5a72..6c792e355 100644
--- a/src/theory/trust_node.cpp
+++ b/src/theory/trust_node.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -101,7 +101,7 @@ ProofGenerator* TrustNode::getGenerator() const { return d_gen; }
bool TrustNode::isNull() const { return d_proven.isNull(); }
-std::shared_ptr<ProofNode> TrustNode::toProofNode()
+std::shared_ptr<ProofNode> TrustNode::toProofNode() const
{
if (d_gen == nullptr)
{
@@ -121,9 +121,26 @@ Node TrustNode::getPropExpProven(TNode lit, Node exp)
Node TrustNode::getRewriteProven(TNode n, Node nr) { return n.eqNode(nr); }
+void TrustNode::debugCheckClosed(const char* c,
+ const char* ctx,
+ bool reqNullGen)
+{
+ pfgEnsureClosed(d_proven, d_gen, c, ctx, reqNullGen);
+}
+
+std::string TrustNode::identifyGenerator() const
+{
+ if (d_gen == nullptr)
+ {
+ return "null";
+ }
+ return d_gen->identify();
+}
+
std::ostream& operator<<(std::ostream& out, TrustNode n)
{
- out << "(" << n.getKind() << " " << n.getProven() << ")";
+ out << "(" << n.getKind() << " " << n.getProven() << " "
+ << n.identifyGenerator() << ")";
return out;
}
diff --git a/src/theory/trust_node.h b/src/theory/trust_node.h
index ff174b63e..a0586bd0c 100644
--- a/src/theory/trust_node.h
+++ b/src/theory/trust_node.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -132,7 +132,7 @@ class TrustNode
* Gets the proof node for this trust node, which is obtained by
* calling the generator's getProofFor method on the proven node.
*/
- std::shared_ptr<ProofNode> toProofNode();
+ std::shared_ptr<ProofNode> toProofNode() const;
/** Get the proven formula corresponding to a conflict call */
static Node getConflictProven(Node conf);
@@ -142,6 +142,15 @@ class TrustNode
static Node getPropExpProven(TNode lit, Node exp);
/** Get the proven formula corresponding to a rewrite */
static Node getRewriteProven(TNode n, Node nr);
+ /** For debugging */
+ std::string identifyGenerator() const;
+
+ /**
+ * debug check closed on Trace c, context ctx is string for debugging
+ *
+ * @param reqNullGen Whether we consider a null generator to be a failure.
+ */
+ void debugCheckClosed(const char* c, const char* ctx, bool reqNullGen = true);
private:
TrustNode(TrustNodeKind tnk, Node p, ProofGenerator* g = nullptr);
diff --git a/src/theory/trust_substitutions.cpp b/src/theory/trust_substitutions.cpp
new file mode 100644
index 000000000..aaa3b44f7
--- /dev/null
+++ b/src/theory/trust_substitutions.cpp
@@ -0,0 +1,253 @@
+/********************* */
+/*! \file trust_substitutions.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Trust substitutions
+ **/
+
+#include "theory/trust_substitutions.h"
+
+#include "theory/rewriter.h"
+
+namespace CVC4 {
+namespace theory {
+
+TrustSubstitutionMap::TrustSubstitutionMap(context::Context* c,
+ ProofNodeManager* pnm,
+ std::string name,
+ PfRule trustId,
+ MethodId ids)
+ : d_ctx(c),
+ d_subs(c),
+ d_pnm(pnm),
+ d_tsubs(c),
+ d_tspb(pnm ? new TheoryProofStepBuffer(pnm->getChecker()) : nullptr),
+ d_subsPg(
+ pnm ? new LazyCDProof(pnm, nullptr, c, "TrustSubstitutionMap::subsPg")
+ : nullptr),
+ d_applyPg(pnm ? new LazyCDProof(
+ pnm, nullptr, c, "TrustSubstitutionMap::applyPg")
+ : nullptr),
+ d_helperPf(pnm, c),
+ d_currentSubs(c),
+ d_name(name),
+ d_trustId(trustId),
+ d_ids(ids)
+{
+}
+
+void TrustSubstitutionMap::addSubstitution(TNode x, TNode t, ProofGenerator* pg)
+{
+ Trace("trust-subs") << "TrustSubstitutionMap::addSubstitution: add " << x
+ << " -> " << t << std::endl;
+ d_subs.addSubstitution(x, t);
+ if (isProofEnabled())
+ {
+ TrustNode tnl = TrustNode::mkTrustRewrite(x, t, pg);
+ d_tsubs.push_back(tnl);
+ // current substitution node is no longer valid.
+ d_currentSubs = Node::null();
+ // add to lazy proof
+ d_subsPg->addLazyStep(tnl.getProven(), pg, d_trustId);
+ }
+}
+
+void TrustSubstitutionMap::addSubstitution(TNode x,
+ TNode t,
+ PfRule id,
+ const std::vector<Node>& args)
+{
+ if (!isProofEnabled())
+ {
+ addSubstitution(x, t, nullptr);
+ return;
+ }
+ LazyCDProof* stepPg = d_helperPf.allocateProof(nullptr, d_ctx);
+ Node eq = x.eqNode(t);
+ stepPg->addStep(eq, id, {}, args);
+ addSubstitution(x, t, stepPg);
+}
+
+ProofGenerator* TrustSubstitutionMap::addSubstitutionSolved(TNode x,
+ TNode t,
+ TrustNode tn)
+{
+ Trace("trust-subs") << "TrustSubstitutionMap::addSubstitutionSolved: add "
+ << x << " -> " << t << " from " << tn.getProven()
+ << std::endl;
+ if (!isProofEnabled() || tn.getGenerator() == nullptr)
+ {
+ // no generator or not proof enabled, nothing to do
+ addSubstitution(x, t, nullptr);
+ Trace("trust-subs") << "...no proof" << std::endl;
+ return nullptr;
+ }
+ Node eq = x.eqNode(t);
+ Node proven = tn.getProven();
+ // notice that this checks syntactic equality, not CDProof::isSame since
+ // tn.getGenerator() is not necessarily robust to symmetry.
+ if (eq == proven)
+ {
+ // no rewrite required, just use the generator
+ addSubstitution(x, t, tn.getGenerator());
+ Trace("trust-subs") << "...use generator directly" << std::endl;
+ return tn.getGenerator();
+ }
+ LazyCDProof* solvePg = d_helperPf.allocateProof(nullptr, d_ctx);
+ // Try to transform tn.getProven() to (= x t) here, if necessary
+ if (!d_tspb->applyPredTransform(proven, eq, {}))
+ {
+ // failed to rewrite
+ addSubstitution(x, t, nullptr);
+ Trace("trust-subs") << "...failed to rewrite" << std::endl;
+ return nullptr;
+ }
+ Trace("trust-subs") << "...successful rewrite" << std::endl;
+ solvePg->addSteps(*d_tspb.get());
+ d_tspb->clear();
+ // link the given generator
+ solvePg->addLazyStep(proven, tn.getGenerator());
+ addSubstitution(x, t, solvePg);
+ return solvePg;
+}
+
+void TrustSubstitutionMap::addSubstitutions(TrustSubstitutionMap& t)
+{
+ if (!isProofEnabled())
+ {
+ // just use the basic utility
+ d_subs.addSubstitutions(t.get());
+ return;
+ }
+ // call addSubstitution above in sequence
+ for (const TrustNode& tns : t.d_tsubs)
+ {
+ Node proven = tns.getProven();
+ addSubstitution(proven[0], proven[1], tns.getGenerator());
+ }
+}
+
+TrustNode TrustSubstitutionMap::apply(Node n, bool doRewrite)
+{
+ Trace("trust-subs") << "TrustSubstitutionMap::addSubstitution: apply " << n
+ << std::endl;
+ Node ns = d_subs.apply(n);
+ Trace("trust-subs") << "...subs " << ns << std::endl;
+ // rewrite if indicated
+ if (doRewrite)
+ {
+ ns = Rewriter::rewrite(ns);
+ Trace("trust-subs") << "...rewrite " << ns << std::endl;
+ }
+ if (n == ns)
+ {
+ // no change
+ return TrustNode::null();
+ }
+ if (!isProofEnabled())
+ {
+ // no proofs, use null generator
+ return TrustNode::mkTrustRewrite(n, ns, nullptr);
+ }
+ Node cs = getCurrentSubstitution();
+ Trace("trust-subs")
+ << "TrustSubstitutionMap::addSubstitution: current substitution is " << cs
+ << std::endl;
+ // Easy case: if n is in the domain of the substitution, maybe it is already
+ // a proof in the substitution proof generator. This is moreover required
+ // to avoid cyclic proofs below. For example, if { x -> 5 } is a substitution,
+ // and we are asked to transform x, resulting in 5, we hence must provide
+ // a proof of (= x 5) based on the substitution. However, it must be the
+ // case that (= x 5) is a proven fact of the substitution generator. Hence
+ // we avoid a proof that looks like:
+ // ---------- from d_subsPg
+ // (= x 5)
+ // ---------- MACRO_SR_EQ_INTRO{x}
+ // (= x 5)
+ // by taking the premise proof directly.
+ Node eq = n.eqNode(ns);
+ if (d_subsPg->hasStep(eq) || d_subsPg->hasGenerator(eq))
+ {
+ return TrustNode::mkTrustRewrite(n, ns, d_subsPg.get());
+ }
+ Assert(eq != cs);
+ std::vector<Node> pfChildren;
+ if (!cs.isConst())
+ {
+ // note we will get more proof reuse if we do not special case AND here.
+ if (cs.getKind() == kind::AND)
+ {
+ for (const Node& csc : cs)
+ {
+ pfChildren.push_back(csc);
+ // connect substitution generator into apply generator
+ d_applyPg->addLazyStep(csc, d_subsPg.get());
+ }
+ }
+ else
+ {
+ pfChildren.push_back(cs);
+ // connect substitution generator into apply generator
+ d_applyPg->addLazyStep(cs, d_subsPg.get());
+ }
+ }
+ if (!d_tspb->applyEqIntro(n, ns, pfChildren, d_ids))
+ {
+ return TrustNode::mkTrustRewrite(n, ns, nullptr);
+ }
+ // ------- ------- from external proof generators
+ // x1 = t1 ... xn = tn
+ // ----------------------- AND_INTRO
+ // ...
+ // --------- MACRO_SR_EQ_INTRO
+ // n == ns
+ // add it to the apply proof generator.
+ //
+ // Notice that we use a single child to MACRO_SR_EQ_INTRO here. This is an
+ // optimization motivated by the fact that n may be large and reused many
+ // time. For instance, if this class is being used to track substitutions
+ // derived during non-clausal simplification during preprocessing, it is
+ // a fixed (possibly) large substitution applied to many terms. Having
+ // a single child saves us from creating many proofs with n children, where
+ // notice this proof is reused.
+ d_applyPg->addSteps(*d_tspb.get());
+ d_tspb->clear();
+ return TrustNode::mkTrustRewrite(n, ns, d_applyPg.get());
+}
+
+SubstitutionMap& TrustSubstitutionMap::get() { return d_subs; }
+
+bool TrustSubstitutionMap::isProofEnabled() const
+{
+ return d_subsPg != nullptr;
+}
+
+Node TrustSubstitutionMap::getCurrentSubstitution()
+{
+ Assert(isProofEnabled());
+ if (!d_currentSubs.get().isNull())
+ {
+ return d_currentSubs;
+ }
+ std::vector<Node> csubsChildren;
+ for (const TrustNode& tns : d_tsubs)
+ {
+ csubsChildren.push_back(tns.getProven());
+ }
+ d_currentSubs = NodeManager::currentNM()->mkAnd(csubsChildren);
+ if (d_currentSubs.get().getKind() == kind::AND)
+ {
+ d_subsPg->addStep(d_currentSubs, PfRule::AND_INTRO, csubsChildren, {});
+ }
+ return d_currentSubs;
+}
+
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/trust_substitutions.h b/src/theory/trust_substitutions.h
new file mode 100644
index 000000000..c316f08c5
--- /dev/null
+++ b/src/theory/trust_substitutions.h
@@ -0,0 +1,138 @@
+/********************* */
+/*! \file trust_substitutions.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Trust substitutions
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__TRUST_SUBSTITUTIONS_H
+#define CVC4__THEORY__TRUST_SUBSTITUTIONS_H
+
+#include "context/cdlist.h"
+#include "context/context.h"
+#include "expr/lazy_proof.h"
+#include "expr/proof_node_manager.h"
+#include "expr/proof_set.h"
+#include "expr/term_conversion_proof_generator.h"
+#include "theory/eager_proof_generator.h"
+#include "theory/substitutions.h"
+#include "theory/theory_proof_step_buffer.h"
+#include "theory/trust_node.h"
+
+namespace CVC4 {
+namespace theory {
+
+/**
+ * A layer on top of SubstitutionMap that tracks proofs.
+ */
+class TrustSubstitutionMap
+{
+ public:
+ TrustSubstitutionMap(context::Context* c,
+ ProofNodeManager* pnm,
+ std::string name = "TrustSubstitutionMap",
+ PfRule trustId = PfRule::TRUST_SUBS_MAP,
+ MethodId ids = MethodId::SB_DEFAULT);
+ /** Gets a reference to the underlying substitution map */
+ SubstitutionMap& get();
+ /**
+ * Add substitution x -> t, where pg can provide a closed proof of (= x t)
+ * in the remainder of this user context.
+ */
+ void addSubstitution(TNode x, TNode t, ProofGenerator* pg = nullptr);
+ /**
+ * Add substitution x -> t from a single proof step with rule id, no children
+ * and arguments args.
+ */
+ void addSubstitution(TNode x,
+ TNode t,
+ PfRule id,
+ const std::vector<Node>& args);
+ /**
+ * Add substitution x -> t, which was derived from the proven field of
+ * trust node tn. In other words, (= x t) is the solved form of
+ * tn.getProven(). This method is a helper function for methods (e.g.
+ * ppAssert) that put literals into solved form. It should be the case
+ * that (= x t) and tn.getProven() can be shown equivalent by rewriting.
+ *
+ * This ensures that we add a substitution with a proof
+ * based on transforming the tn.getProven() to (= x t) if tn has a
+ * non-null proof generator; otherwise if tn has no proof generator
+ * we simply add the substitution.
+ *
+ * @return The proof generator that can prove (= x t).
+ */
+ ProofGenerator* addSubstitutionSolved(TNode x, TNode t, TrustNode tn);
+ /**
+ * Add substitutions from trust substitution map t. This adds all
+ * substitutions from the map t and carries over its information about proofs.
+ */
+ void addSubstitutions(TrustSubstitutionMap& t);
+ /**
+ * Apply substitutions in this class to node n. Returns a trust node
+ * proving n = n*sigma, where the proof generator is provided by this class
+ * (when proofs are enabled).
+ */
+ TrustNode apply(Node n, bool doRewrite = true);
+
+ private:
+ /** Are proofs enabled? */
+ bool isProofEnabled() const;
+ /**
+ * Get current substitution. This returns a node of the form:
+ * (and (= x1 t1) ... (= xn tn))
+ * where (x1, t1) ... (xn, tn) have been registered via addSubstitution above.
+ * Moreover, it ensures that d_subsPg has a proof of the returned value.
+ */
+ Node getCurrentSubstitution();
+ /** The context used here */
+ context::Context* d_ctx;
+ /** The substitution map */
+ SubstitutionMap d_subs;
+ /** The proof node manager */
+ ProofNodeManager* d_pnm;
+ /** A context-dependent list of trust nodes */
+ context::CDList<TrustNode> d_tsubs;
+ /** Theory proof step buffer */
+ std::unique_ptr<TheoryProofStepBuffer> d_tspb;
+ /** A lazy proof for substitution steps */
+ std::unique_ptr<LazyCDProof> d_subsPg;
+ /** A lazy proof for apply steps */
+ std::unique_ptr<LazyCDProof> d_applyPg;
+ /**
+ * A context-dependent list of LazyCDProof, allocated for internal steps.
+ */
+ CDProofSet<LazyCDProof> d_helperPf;
+ /**
+ * The formula corresponding to the current substitution. This is of the form
+ * (and (= x1 t1) ... (= xn tn))
+ * when the substitution map contains { x1 -> t1, ... xn -> tn }. This field
+ * is updated on demand. When this class applies a substitution to a node,
+ * this formula is computed and recorded as the premise of a
+ * MACRO_SR_EQ_INTRO step.
+ */
+ context::CDO<Node> d_currentSubs;
+ /** Name for debugging */
+ std::string d_name;
+ /**
+ * The placeholder trusted PfRule identifier for calls to addSubstitution
+ * that are not given proof generators.
+ */
+ PfRule d_trustId;
+ /** The method id for which form of substitution to apply */
+ MethodId d_ids;
+};
+
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__TRUST_SUBSTITUTIONS_H */
diff --git a/src/theory/type_enumerator.h b/src/theory/type_enumerator.h
index bb223a950..b77fdcd9f 100644
--- a/src/theory/type_enumerator.h
+++ b/src/theory/type_enumerator.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/type_enumerator_template.cpp b/src/theory/type_enumerator_template.cpp
index e9fdc6a86..c34d3cdf9 100644
--- a/src/theory/type_enumerator_template.cpp
+++ b/src/theory/type_enumerator_template.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -22,7 +22,6 @@
${type_enumerator_includes}
-#line 26 "${template}"
using namespace std;
@@ -42,7 +41,6 @@ TypeEnumeratorInterface* TypeEnumerator::mkTypeEnumerator(
}
Unreachable();
${mk_type_enumerator_cases}
-#line 46 "${template}"
default: Unhandled() << "No type enumerator for type `" << type << "'";
}
Unreachable();
diff --git a/src/theory/type_set.cpp b/src/theory/type_set.cpp
index 85364fb33..8a5f6258e 100644
--- a/src/theory/type_set.cpp
+++ b/src/theory/type_set.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Clark Barrett
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/type_set.h b/src/theory/type_set.h
index 3914d6a3c..c27f5f1c7 100644
--- a/src/theory/type_set.h
+++ b/src/theory/type_set.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/uf/cardinality_extension.cpp b/src/theory/uf/cardinality_extension.cpp
index 1f83c94d6..b51e40a6c 100644
--- a/src/theory/uf/cardinality_extension.cpp
+++ b/src/theory/uf/cardinality_extension.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -22,15 +22,10 @@
#include "theory/quantifiers/term_database.h"
#include "theory/theory_model.h"
-//#define ONE_SPLIT_REGION
-//#define COMBINE_REGIONS_SMALL_INTO_LARGE
-//#define LAZY_REL_EQC
-
using namespace std;
using namespace CVC4::kind;
using namespace CVC4::context;
-
namespace CVC4 {
namespace theory {
namespace uf {
@@ -183,7 +178,7 @@ void Region::setDisequal( Node n1, Node n2, int type, bool valid ){
void Region::setRep( Node n, bool valid ) {
Assert(hasRep(n) != valid);
if( valid && d_nodes.find( n )==d_nodes.end() ){
- d_nodes[n] = new RegionNodeInfo( d_cf->d_thss->getSatContext() );
+ d_nodes[n] = new RegionNodeInfo(d_cf->d_state.getSatContext());
}
d_nodes[n]->setValid(valid);
d_reps_size = d_reps_size + ( valid ? 1 : -1 );
@@ -460,22 +455,22 @@ std::string SortModel::CardinalityDecisionStrategy::identify() const
}
SortModel::SortModel(Node n,
- context::Context* c,
- context::UserContext* u,
+ TheoryState& state,
+ TheoryInferenceManager& im,
CardinalityExtension* thss)
: d_type(n.getType()),
+ d_state(state),
+ d_im(im),
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_hasCard(c, false),
- d_maxNegCard(c, 0),
- d_initialized(u, false),
- d_lemma_cache(u),
+ d_regions_index(d_state.getSatContext(), 0),
+ d_regions_map(d_state.getSatContext()),
+ d_split_score(d_state.getSatContext()),
+ d_disequalities_index(d_state.getSatContext(), 0),
+ d_reps(d_state.getSatContext(), 0),
+ d_cardinality(d_state.getSatContext(), 1),
+ d_hasCard(d_state.getSatContext(), false),
+ d_maxNegCard(d_state.getSatContext(), 0),
+ d_initialized(d_state.getUserContext(), false),
d_c_dec_strat(nullptr)
{
d_cardinality_term = n;
@@ -486,7 +481,7 @@ SortModel::SortModel(Node n,
// We are guaranteed that the decision manager is ready since we
// construct this module during TheoryUF::finishInit.
d_c_dec_strat.reset(new CardinalityDecisionStrategy(
- n, c, thss->getTheory()->getValuation()));
+ n, d_state.getSatContext(), thss->getTheory()->getValuation()));
}
}
@@ -500,7 +495,8 @@ SortModel::~SortModel() {
}
/** initialize */
-void SortModel::initialize( OutputChannel* out ){
+void SortModel::initialize()
+{
if (d_c_dec_strat.get() != nullptr && !d_initialized)
{
d_initialized = true;
@@ -513,40 +509,24 @@ void SortModel::initialize( OutputChannel* out ){
/** new node */
void SortModel::newEqClass( Node n ){
- if( !d_conflict ){
+ if (!d_state.isInConflict())
+ {
if( d_regions_map.find( n )==d_regions_map.end() ){
- // Must generate totality axioms for every cardinality we have
- // allocated thus far.
- for( std::map< int, Node >::iterator it = d_cardinality_literal.begin();
- it != d_cardinality_literal.end(); ++it ){
- if( applyTotality( it->first ) ){
- addTotalityAxiom( n, it->first, &d_thss->getOutputChannel() );
- }
- }
- if( options::ufssTotality() ){
- // Regions map will store whether we need to equate this term
- // with a constant equivalence class.
- if( std::find( d_totality_terms[0].begin(), d_totality_terms[0].end(), n )==d_totality_terms[0].end() ){
- d_regions_map[n] = 0;
- }else{
- d_regions_map[n] = -1;
- }
+ d_regions_map[n] = d_regions_index;
+ Debug("uf-ss") << "CardinalityExtension: New Eq Class " << n << std::endl;
+ Debug("uf-ss-debug") << d_regions_index << " " << (int)d_regions.size()
+ << std::endl;
+ if (d_regions_index < d_regions.size())
+ {
+ d_regions[d_regions_index]->debugPrint("uf-ss-debug", true);
+ d_regions[d_regions_index]->setValid(true);
+ Assert(d_regions[d_regions_index]->getNumReps() == 0);
}else{
- d_regions_map[n] = d_regions_index;
- Debug("uf-ss") << "CardinalityExtension: New Eq Class " << n
- << std::endl;
- Debug("uf-ss-debug") << d_regions_index << " "
- << (int)d_regions.size() << std::endl;
- if( d_regions_index<d_regions.size() ){
- d_regions[ d_regions_index ]->debugPrint("uf-ss-debug",true);
- d_regions[ d_regions_index ]->setValid(true);
- Assert(d_regions[d_regions_index]->getNumReps() == 0);
- }else{
- d_regions.push_back( new Region( this, d_thss->getSatContext() ) );
- }
- d_regions[ d_regions_index ]->addRep( n );
- d_regions_index = d_regions_index + 1;
+ d_regions.push_back(new Region(this, d_state.getSatContext()));
}
+ d_regions[d_regions_index]->addRep(n);
+ d_regions_index = d_regions_index + 1;
+
d_reps = d_reps + 1;
}
}
@@ -554,105 +534,116 @@ void SortModel::newEqClass( Node n ){
/** merge */
void SortModel::merge( Node a, Node b ){
- if( !d_conflict ){
- if( options::ufssTotality() ){
- if( d_regions_map[b]==-1 ){
- d_regions_map[a] = -1;
+ if (d_state.isInConflict())
+ {
+ return;
+ }
+ Debug("uf-ss") << "CardinalityExtension: Merging " << a << " = " << b << "..."
+ << std::endl;
+ if (a != b)
+ {
+ Assert(d_regions_map.find(a) != d_regions_map.end());
+ Assert(d_regions_map.find(b) != d_regions_map.end());
+ int ai = d_regions_map[a];
+ int bi = d_regions_map[b];
+ Debug("uf-ss") << " regions: " << ai << " " << bi << std::endl;
+ if (ai != bi)
+ {
+ if (d_regions[ai]->getNumReps() == 1)
+ {
+ int ri = combineRegions(bi, ai);
+ d_regions[ri]->setEqual(a, b);
+ checkRegion(ri);
}
- d_regions_map[b] = -1;
- }else{
- Debug("uf-ss") << "CardinalityExtension: Merging " << a << " = " << b
- << "..." << std::endl;
- if( a!=b ){
- Assert(d_regions_map.find(a) != d_regions_map.end());
- Assert(d_regions_map.find(b) != d_regions_map.end());
- int ai = d_regions_map[a];
- int bi = d_regions_map[b];
- Debug("uf-ss") << " regions: " << ai << " " << bi << std::endl;
- if( ai!=bi ){
- if( d_regions[ai]->getNumReps()==1 ){
- int ri = combineRegions( bi, ai );
- d_regions[ri]->setEqual( a, b );
- checkRegion( ri );
- }else if( d_regions[bi]->getNumReps()==1 ){
- int ri = combineRegions( ai, bi );
- d_regions[ri]->setEqual( a, b );
- checkRegion( ri );
- }else{
- // Either move a to d_regions[bi], or b to d_regions[ai].
- RegionNodeInfo* a_region_info = d_regions[ai]->getRegionInfo(a);
- RegionNodeInfo* b_region_info = d_regions[bi]->getRegionInfo(b);
- int aex = ( a_region_info->getNumInternalDisequalities() -
- getNumDisequalitiesToRegion( a, bi ) );
- int bex = ( b_region_info->getNumInternalDisequalities() -
- getNumDisequalitiesToRegion( b, ai ) );
- // Based on which would produce the fewest number of
- // external disequalities.
- if( aex<bex ){
- moveNode( a, bi );
- d_regions[bi]->setEqual( a, b );
- }else{
- moveNode( b, ai );
- d_regions[ai]->setEqual( a, b );
- }
- checkRegion( ai );
- checkRegion( bi );
- }
+ else if (d_regions[bi]->getNumReps() == 1)
+ {
+ int ri = combineRegions(ai, bi);
+ d_regions[ri]->setEqual(a, b);
+ checkRegion(ri);
+ }
+ else
+ {
+ // Either move a to d_regions[bi], or b to d_regions[ai].
+ RegionNodeInfo* a_region_info = d_regions[ai]->getRegionInfo(a);
+ RegionNodeInfo* b_region_info = d_regions[bi]->getRegionInfo(b);
+ int aex = (a_region_info->getNumInternalDisequalities()
+ - getNumDisequalitiesToRegion(a, bi));
+ int bex = (b_region_info->getNumInternalDisequalities()
+ - getNumDisequalitiesToRegion(b, ai));
+ // Based on which would produce the fewest number of
+ // external disequalities.
+ if (aex < bex)
+ {
+ moveNode(a, bi);
+ d_regions[bi]->setEqual(a, b);
}else{
+ moveNode(b, ai);
d_regions[ai]->setEqual( a, b );
- checkRegion( ai );
}
- d_regions_map[b] = -1;
+ checkRegion(ai);
+ checkRegion(bi);
}
- d_reps = d_reps - 1;
}
+ else
+ {
+ d_regions[ai]->setEqual(a, b);
+ checkRegion(ai);
+ }
+ d_regions_map[b] = -1;
}
+ d_reps = d_reps - 1;
}
/** assert terms are disequal */
void SortModel::assertDisequal( Node a, Node b, Node reason ){
- if( !d_conflict ){
- if( options::ufssTotality() ){
- //do nothing
- }else{
- //if they are not already disequal
- eq::EqualityEngine* ee = d_thss->getTheory()->getEqualityEngine();
- a = ee->getRepresentative(a);
- b = ee->getRepresentative(b);
- int ai = d_regions_map[a];
- int bi = d_regions_map[b];
- if( !d_regions[ai]->isDisequal( a, b, ai==bi ) ){
- Debug("uf-ss") << "Assert disequal " << a << " != " << b << "..." << std::endl;
- //if( reason.getKind()!=NOT || reason[0].getKind()!=EQUAL ||
- // a!=reason[0][0] || b!=reason[0][1] ){
- // Notice() << "Assert disequal " << a << " != " << b << ", reason = " << reason << "..." << std::endl;
- //}
- Debug("uf-ss-disequal") << "Assert disequal " << a << " != " << b << "..." << std::endl;
- //add to list of disequalities
- if( d_disequalities_index<d_disequalities.size() ){
- d_disequalities[d_disequalities_index] = reason;
- }else{
- d_disequalities.push_back( reason );
- }
- d_disequalities_index = d_disequalities_index + 1;
- //now, add disequalities to regions
- Assert(d_regions_map.find(a) != d_regions_map.end());
- Assert(d_regions_map.find(b) != d_regions_map.end());
- Debug("uf-ss") << " regions: " << ai << " " << bi << std::endl;
- if( ai==bi ){
- //internal disequality
- d_regions[ai]->setDisequal( a, b, 1, true );
- d_regions[ai]->setDisequal( b, a, 1, true );
- checkRegion( ai, false ); //do not need to check if it needs to combine (no new ext. disequalities)
- }else{
- //external disequality
- d_regions[ai]->setDisequal( a, b, 0, true );
- d_regions[bi]->setDisequal( b, a, 0, true );
- checkRegion( ai );
- checkRegion( bi );
- }
- }
- }
+ if (d_state.isInConflict())
+ {
+ return;
+ }
+ // if they are not already disequal
+ eq::EqualityEngine* ee = d_thss->getTheory()->getEqualityEngine();
+ a = ee->getRepresentative(a);
+ b = ee->getRepresentative(b);
+ int ai = d_regions_map[a];
+ int bi = d_regions_map[b];
+ if (d_regions[ai]->isDisequal(a, b, ai == bi))
+ {
+ // already disequal
+ return;
+ }
+ Debug("uf-ss") << "Assert disequal " << a << " != " << b << "..."
+ << std::endl;
+ Debug("uf-ss-disequal") << "Assert disequal " << a << " != " << b << "..."
+ << std::endl;
+ // add to list of disequalities
+ if (d_disequalities_index < d_disequalities.size())
+ {
+ d_disequalities[d_disequalities_index] = reason;
+ }
+ else
+ {
+ d_disequalities.push_back(reason);
+ }
+ d_disequalities_index = d_disequalities_index + 1;
+ // now, add disequalities to regions
+ Assert(d_regions_map.find(a) != d_regions_map.end());
+ Assert(d_regions_map.find(b) != d_regions_map.end());
+ Debug("uf-ss") << " regions: " << ai << " " << bi << std::endl;
+ if (ai == bi)
+ {
+ // internal disequality
+ d_regions[ai]->setDisequal(a, b, 1, true);
+ d_regions[ai]->setDisequal(b, a, 1, true);
+ // do not need to check if it needs to combine (no new ext. disequalities)
+ checkRegion(ai, false);
+ }
+ else
+ {
+ // external disequality
+ d_regions[ai]->setDisequal(a, b, 0, true);
+ d_regions[bi]->setDisequal(b, a, 0, true);
+ checkRegion(ai);
+ checkRegion(bi);
}
}
@@ -669,125 +660,140 @@ bool SortModel::areDisequal( Node a, Node b ) {
}
}
-/** check */
-void SortModel::check( Theory::Effort level, OutputChannel* out ){
+void SortModel::check(Theory::Effort level)
+{
Assert(options::ufssMode() == options::UfssMode::FULL);
- if( level>=Theory::EFFORT_STANDARD && d_hasCard && !d_conflict ){
- Debug("uf-ss") << "CardinalityExtension: Check " << level << " " << d_type
- << std::endl;
+ if (!d_hasCard && d_state.isInConflict())
+ {
+ // not necessary to check
+ return;
+ }
+ Debug("uf-ss") << "CardinalityExtension: Check " << level << " " << d_type
+ << std::endl;
+ if (level == Theory::EFFORT_FULL)
+ {
+ Debug("fmf-full-check") << std::endl;
+ Debug("fmf-full-check")
+ << "Full check for SortModel " << d_type << ", status : " << std::endl;
+ debugPrint("fmf-full-check");
+ Debug("fmf-full-check") << std::endl;
+ }
+ if (d_reps <= (unsigned)d_cardinality)
+ {
+ Debug("uf-ss-debug") << "We have " << d_reps << " representatives for type "
+ << d_type << ", <= " << d_cardinality << std::endl;
if( level==Theory::EFFORT_FULL ){
- Debug("fmf-full-check") << std::endl;
- Debug("fmf-full-check") << "Full check for SortModel " << d_type << ", status : " << std::endl;
- debugPrint("fmf-full-check");
- Debug("fmf-full-check") << std::endl;
+ Debug("uf-ss-sat") << "We have " << d_reps << " representatives for type "
+ << d_type << ", <= " << d_cardinality << std::endl;
}
- if( d_reps<=(unsigned)d_cardinality ){
- Debug("uf-ss-debug") << "We have " << d_reps << " representatives for type " << d_type << ", <= " << d_cardinality << std::endl;
- if( level==Theory::EFFORT_FULL ){
- Debug("uf-ss-sat") << "We have " << d_reps << " representatives for type " << d_type << ", <= " << d_cardinality << std::endl;
- //Notice() << "We have " << d_reps << " representatives for type " << d_type << ", <= " << cardinality << std::endl;
- //Notice() << "Model size for " << d_type << " is " << cardinality << std::endl;
- //Notice() << cardinality << " ";
+ return;
+ }
+ // first check if we can generate a clique conflict
+ // do a check within each region
+ for (size_t i = 0; i < d_regions_index; i++)
+ {
+ if (d_regions[i]->valid())
+ {
+ std::vector<Node> clique;
+ if (d_regions[i]->check(level, d_cardinality, clique))
+ {
+ // add clique lemma
+ addCliqueLemma(clique);
+ return;
}
- return;
- }else{
- //first check if we can generate a clique conflict
- if( !options::ufssTotality() ){
- //do a check within each region
- for( int i=0; i<(int)d_regions_index; i++ ){
- if( d_regions[i]->valid() ){
- std::vector< Node > clique;
- if( d_regions[i]->check( level, d_cardinality, clique ) ){
- //add clique lemma
- addCliqueLemma( clique, out );
- return;
- }else{
- Trace("uf-ss-debug") << "No clique in Region #" << i << std::endl;
- }
- }
+ else
+ {
+ Trace("uf-ss-debug") << "No clique in Region #" << i << std::endl;
+ }
+ }
+ }
+ // do splitting on demand
+ bool addedLemma = false;
+ if (level == Theory::EFFORT_FULL)
+ {
+ Trace("uf-ss-debug") << "Add splits?" << std::endl;
+ // see if we have any recommended splits from large regions
+ for (size_t i = 0; i < d_regions_index; i++)
+ {
+ if (d_regions[i]->valid() && d_regions[i]->getNumReps() > d_cardinality)
+ {
+ int sp = addSplit(d_regions[i]);
+ if (sp == 1)
+ {
+ addedLemma = true;
+ }
+ else if (sp == -1)
+ {
+ check(level);
+ return;
}
}
- if( !applyTotality( d_cardinality ) ){
- //do splitting on demand
- bool addedLemma = false;
- if (level==Theory::EFFORT_FULL)
+ }
+ }
+ // If no added lemmas, force continuation via combination of regions.
+ if (level != Theory::EFFORT_FULL || addedLemma)
+ {
+ return;
+ }
+ // check at full effort
+ Trace("uf-ss-debug") << "No splits added. " << d_cardinality << std::endl;
+ Trace("uf-ss-si") << "Must combine region" << std::endl;
+ bool recheck = false;
+ SortInference* si = d_thss->getSortInference();
+ if (si != nullptr)
+ {
+ // If sort inference is enabled, search for regions with same sort.
+ std::map<int, int> sortsFound;
+ for (size_t i = 0; i < d_regions_index; i++)
+ {
+ if (d_regions[i]->valid())
+ {
+ Node op = d_regions[i]->frontKey();
+ int sort_id = si->getSortId(op);
+ if (sortsFound.find(sort_id) != sortsFound.end())
{
- Trace("uf-ss-debug") << "Add splits?" << std::endl;
- //see if we have any recommended splits from large regions
- for( int i=0; i<(int)d_regions_index; i++ ){
- if( d_regions[i]->valid() && d_regions[i]->getNumReps()>d_cardinality ){
-
- int sp = addSplit( d_regions[i], out );
- if( sp==1 ){
- addedLemma = true;
-#ifdef ONE_SPLIT_REGION
- break;
-#endif
- }else if( sp==-1 ){
- check( level, out );
- return;
- }
- }
- }
+ Debug("fmf-full-check") << "Combined regions " << i << " "
+ << sortsFound[sort_id] << std::endl;
+ combineRegions(sortsFound[sort_id], i);
+ recheck = true;
+ break;
}
- //If no added lemmas, force continuation via combination of regions.
- if( level==Theory::EFFORT_FULL ){
- if( !addedLemma ){
- Trace("uf-ss-debug") << "No splits added. " << d_cardinality
- << std::endl;
- Trace("uf-ss-si") << "Must combine region" << std::endl;
- bool recheck = false;
- SortInference* si = d_thss->getSortInference();
- if (si != nullptr)
- {
- //If sort inference is enabled, search for regions with same sort.
- std::map< int, int > sortsFound;
- for( int i=0; i<(int)d_regions_index; i++ ){
- if( d_regions[i]->valid() ){
- Node op = d_regions[i]->frontKey();
- int sort_id = si->getSortId(op);
- if( sortsFound.find( sort_id )!=sortsFound.end() ){
- Debug("fmf-full-check") << "Combined regions " << i << " " << sortsFound[sort_id] << std::endl;
- combineRegions( sortsFound[sort_id], i );
- recheck = true;
- break;
- }else{
- sortsFound[sort_id] = i;
- }
- }
- }
- }
- if( !recheck ) {
- //naive strategy, force region combination involving the first valid region
- for( int i=0; i<(int)d_regions_index; i++ ){
- if( d_regions[i]->valid() ){
- int fcr = forceCombineRegion( i, false );
- Debug("fmf-full-check") << "Combined regions " << i << " " << fcr << std::endl;
- Trace("uf-ss-debug") << "Combined regions " << i << " " << fcr << std::endl;
- recheck = true;
- break;
- }
- }
- }
- if( recheck ){
- Trace("uf-ss-debug") << "Must recheck." << std::endl;
- check( level, out );
- }
- }
+ else
+ {
+ sortsFound[sort_id] = i;
}
}
}
}
+ if (!recheck)
+ {
+ // naive strategy, force region combination involving the first
+ // valid region
+ for (size_t i = 0; i < d_regions_index; i++)
+ {
+ if (d_regions[i]->valid())
+ {
+ int fcr = forceCombineRegion(i, false);
+ Debug("fmf-full-check")
+ << "Combined regions " << i << " " << fcr << std::endl;
+ Trace("uf-ss-debug")
+ << "Combined regions " << i << " " << fcr << std::endl;
+ recheck = true;
+ break;
+ }
+ }
+ }
+ if (recheck)
+ {
+ Trace("uf-ss-debug") << "Must recheck." << std::endl;
+ check(level);
+ }
}
void SortModel::presolve() {
d_initialized = false;
}
-void SortModel::propagate( Theory::Effort level, OutputChannel* out ){
-
-}
-
int SortModel::getNumDisequalitiesToRegion( Node n, int ri ){
int ni = d_regions_map[n];
int counter = 0;
@@ -832,8 +838,10 @@ void SortModel::setSplitScore( Node n, int s ){
}
}
-void SortModel::assertCardinality( OutputChannel* out, int c, bool val ){
- if( !d_conflict ){
+void SortModel::assertCardinality(uint32_t c, bool val)
+{
+ if (!d_state.isInConflict())
+ {
Trace("uf-ss-assert")
<< "Assert cardinality " << d_type << " " << c << " " << val
<< " level = "
@@ -844,27 +852,32 @@ void SortModel::assertCardinality( OutputChannel* out, int c, bool val ){
bool doCheckRegions = !d_hasCard;
bool prevHasCard = d_hasCard;
d_hasCard = true;
- if( !prevHasCard || c<d_cardinality ){
+ if (!prevHasCard || c < d_cardinality)
+ {
d_cardinality = c;
simpleCheckCardinality();
- if( d_thss->d_conflict.get() ){
+ if (d_state.isInConflict())
+ {
return;
}
}
//should check all regions now
- if( doCheckRegions ){
- for( int i=0; i<(int)d_regions_index; i++ ){
+ if (doCheckRegions)
+ {
+ for (size_t i = 0; i < d_regions_index; i++)
+ {
if( d_regions[i]->valid() ){
checkRegion( i );
- if( d_conflict ){
+ if (d_state.isInConflict())
+ {
return;
}
}
}
}
// we assert it positively, if its beyond the bound, abort
- if (options::ufssAbortCardinality() != -1
- && c >= options::ufssAbortCardinality())
+ if (options::ufssAbortCardinality() >= 0
+ && c >= static_cast<uint32_t>(options::ufssAbortCardinality()))
{
std::stringstream ss;
ss << "Maximum cardinality (" << options::ufssAbortCardinality()
@@ -874,9 +887,11 @@ void SortModel::assertCardinality( OutputChannel* out, int c, bool val ){
}
else
{
- if( c>d_maxNegCard.get() ){
- Trace("uf-ss-com-card-debug") << "Maximum negative cardinality for " << d_type << " is now " << c << std::endl;
- d_maxNegCard.set( c );
+ if (c > d_maxNegCard.get())
+ {
+ Trace("uf-ss-com-card-debug") << "Maximum negative cardinality for "
+ << d_type << " is now " << c << std::endl;
+ d_maxNegCard.set(c);
simpleCheckCardinality();
}
}
@@ -887,15 +902,6 @@ void SortModel::checkRegion( int ri, bool checkCombine ){
if( isValid(ri) && d_hasCard ){
Assert(d_cardinality > 0);
if( checkCombine && d_regions[ri]->getMustCombine( d_cardinality ) ){
- ////alternatively, check if we can reduce the number of external disequalities by moving single nodes
- //for( std::map< Node, bool >::iterator it = d_regions[i]->d_reps.begin(); it != d_regions[i]->d_reps.end(); ++it ){
- // if( it->second ){
- // int inDeg = d_regions[i]->d_disequalities_size[1][ it-> first ];
- // int outDeg = d_regions[i]->d_disequalities_size[0][ it-> first ];
- // if( inDeg<outDeg ){
- // }
- // }
- //}
int riNew = forceCombineRegion( ri, true );
if( riNew>=0 ){
checkRegion( riNew, checkCombine );
@@ -905,7 +911,7 @@ void SortModel::checkRegion( int ri, bool checkCombine ){
std::vector< Node > clique;
if( d_regions[ri]->check( Theory::EFFORT_STANDARD, d_cardinality, clique ) ){
//explain clique
- addCliqueLemma( clique, &d_thss->getOutputChannel() );
+ addCliqueLemma(clique);
}
}
}
@@ -955,11 +961,6 @@ int SortModel::forceCombineRegion( int ri, bool useDensity ){
int SortModel::combineRegions( int ai, int bi ){
-#ifdef COMBINE_REGIONS_SMALL_INTO_LARGE
- if( d_regions[ai]->getNumReps()<d_regions[bi]->getNumReps() ){
- return combineRegions( bi, ai );
- }
-#endif
Debug("uf-ss-region") << "uf-ss: Combine Region #" << bi << " with Region #" << ai << std::endl;
Assert(isValid(ai) && isValid(bi));
Region* region_bi = d_regions[bi];
@@ -984,7 +985,8 @@ void SortModel::moveNode( Node n, int ri ){
d_regions_map[n] = ri;
}
-int SortModel::addSplit( Region* r, OutputChannel* out ){
+int SortModel::addSplit(Region* r)
+{
Node s;
if( r->hasSplits() ){
//take the first split you find
@@ -1032,10 +1034,12 @@ int SortModel::addSplit( Region* r, OutputChannel* out ){
//Notice() << "*** Split on " << s << std::endl;
//split on the equality s
Node lem = NodeManager::currentNM()->mkNode( kind::OR, ss, ss.negate() );
- if( doSendLemma( lem ) ){
+ // send lemma, with caching
+ if (d_im.lemma(lem))
+ {
Trace("uf-ss-lemma") << "*** Split on " << s << std::endl;
//tell the sat solver to explore the equals branch first
- out->requirePhase( ss, true );
+ d_im.requirePhase(ss, true);
++( d_thss->d_statistics.d_split_lemmas );
}
return 1;
@@ -1044,11 +1048,12 @@ int SortModel::addSplit( Region* r, OutputChannel* out ){
}
}
-
-void SortModel::addCliqueLemma( std::vector< Node >& clique, OutputChannel* out ){
+void SortModel::addCliqueLemma(std::vector<Node>& clique)
+{
Assert(d_hasCard);
Assert(d_cardinality > 0);
- while( clique.size()>size_t(d_cardinality+1) ){
+ while (clique.size() > d_cardinality + 1)
+ {
clique.pop_back();
}
// add as lemma
@@ -1062,94 +1067,20 @@ void SortModel::addCliqueLemma( std::vector< Node >& clique, OutputChannel* out
}
eqs.push_back(d_cardinality_literal[d_cardinality].notNode());
Node lem = NodeManager::currentNM()->mkNode(OR, eqs);
- if (doSendLemma(lem))
+ // send lemma, with caching
+ if (d_im.lemma(lem))
{
Trace("uf-ss-lemma") << "*** Add clique lemma " << lem << std::endl;
++(d_thss->d_statistics.d_clique_lemmas);
}
}
-void SortModel::addTotalityAxiom( Node n, int cardinality, OutputChannel* out ){
- 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() ){
- NodeManager* nm = NodeManager::currentNM();
- d_totality_lems[n].push_back( cardinality );
- Node cardLit = d_cardinality_literal[ cardinality ];
- int sort_id = 0;
- SortInference* si = d_thss->getSortInference();
- if (si != nullptr)
- {
- sort_id = si->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;
- if( d_sym_break_terms[n.getType()][sort_id].size()>1 ){
- //enforce canonicity
- for( int i=2; i<use_cardinality; i++ ){
- //can only be assigned to domain constant d if someone has been assigned domain constant d-1
- Node eq = n.eqNode( getTotalityLemmaTerm( cardinality, i ) );
- std::vector< Node > eqs;
- for( unsigned j=0; j<(d_sym_break_terms[n.getType()][sort_id].size()-1); j++ ){
- eqs.push_back( d_sym_break_terms[n.getType()][sort_id][j].eqNode( getTotalityLemmaTerm( cardinality, i-1 ) ) );
- }
- Node ax = eqs.size()==1 ? eqs[0] : NodeManager::currentNM()->mkNode( OR, eqs );
- Node lem = NodeManager::currentNM()->mkNode( IMPLIES, eq, ax );
- Trace("uf-ss-lemma") << "*** Add (canonicity) totality axiom " << lem << std::endl;
- d_thss->getOutputChannel().lemma( lem );
- }
- }
- }
- }
-
- std::vector< Node > eqs;
- for( int i=0; i<use_cardinality; i++ ){
- eqs.push_back( n.eqNode( getTotalityLemmaTerm( cardinality, i ) ) );
- }
- Node ax = eqs.size() == 1 ? eqs[0] : nm->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 );
- }
- }
-}
-
-/** apply totality */
-bool SortModel::applyTotality( int cardinality ){
- return options::ufssTotality() || cardinality<=options::ufssTotalityLimited();
-}
-
-/** get totality lemma terms */
-Node SortModel::getTotalityLemmaTerm( int cardinality, int i ){
- return d_totality_terms[0][i];
-}
-
void SortModel::simpleCheckCardinality() {
if( d_maxNegCard.get()!=0 && d_hasCard.get() && d_cardinality.get()<d_maxNegCard.get() ){
Node lem = NodeManager::currentNM()->mkNode( AND, getCardinalityLiteral( d_cardinality.get() ),
getCardinalityLiteral( d_maxNegCard.get() ).negate() );
Trace("uf-ss-lemma") << "*** Simple cardinality conflict : " << lem << std::endl;
- d_thss->getOutputChannel().conflict( lem );
- d_thss->d_conflict.set( true );
- }
-}
-
-bool SortModel::doSendLemma( Node lem ) {
- if( d_lemma_cache.find( lem )==d_lemma_cache.end() ){
- d_lemma_cache[lem] = true;
- d_thss->getOutputChannel().lemma( lem );
- return true;
- }else{
- return false;
+ d_im.conflict(lem);
}
}
@@ -1183,7 +1114,9 @@ void SortModel::debugPrint( const char* c ){
}
}
-bool SortModel::debugModel( TheoryModel* m ){
+bool SortModel::checkLastCall()
+{
+ TheoryModel* m = d_state.getModel();
if( Trace.isOn("uf-ss-warn") ){
std::vector< Node > eqcs;
eq::EqClassesIterator eqcs_i =
@@ -1205,32 +1138,45 @@ bool SortModel::debugModel( TheoryModel* m ){
}
}
RepSet* rs = m->getRepSetPtr();
- int nReps = (int)rs->getNumRepresentatives(d_type);
- if( nReps!=(d_maxNegCard+1) ){
- Trace("uf-ss-warn") << "WARNING : Model does not have same # representatives as cardinality for " << d_type << "." << std::endl;
- Trace("uf-ss-warn") << " Max neg cardinality : " << d_maxNegCard << std::endl;
+ size_t nReps = rs->getNumRepresentatives(d_type);
+ if (nReps != d_maxNegCard + 1)
+ {
+ Trace("uf-ss-warn") << "WARNING : Model does not have same # "
+ "representatives as cardinality for "
+ << d_type << "." << std::endl;
+ Trace("uf-ss-warn") << " Max neg cardinality : " << d_maxNegCard
+ << std::endl;
Trace("uf-ss-warn") << " # Reps : " << nReps << std::endl;
- if( d_maxNegCard>=nReps ){
- while( (int)d_fresh_aloc_reps.size()<=d_maxNegCard ){
+ if (d_maxNegCard >= nReps)
+ {
+ while (d_fresh_aloc_reps.size() <= d_maxNegCard)
+ {
std::stringstream ss;
ss << "r_" << d_type << "_";
- Node nn = NodeManager::currentNM()->mkSkolem( ss.str(), d_type, "enumeration to meet negative card constraint" );
+ Node nn = NodeManager::currentNM()->mkSkolem(
+ ss.str(), d_type, "enumeration to meet negative card constraint");
d_fresh_aloc_reps.push_back( nn );
}
- if( d_maxNegCard==0 ){
+ if (d_maxNegCard == 0)
+ {
rs->d_type_reps[d_type].push_back(d_fresh_aloc_reps[0]);
- }else{
+ }
+ else
+ {
//must add lemma
std::vector< Node > force_cl;
- for( int i=0; i<=d_maxNegCard; i++ ){
- for( int j=(i+1); j<=d_maxNegCard; j++ ){
- force_cl.push_back( d_fresh_aloc_reps[i].eqNode( d_fresh_aloc_reps[j] ).negate() );
+ for (size_t i = 0; i <= d_maxNegCard; i++)
+ {
+ for (size_t j = (i + 1); j <= d_maxNegCard; j++)
+ {
+ force_cl.push_back(
+ d_fresh_aloc_reps[i].eqNode(d_fresh_aloc_reps[j]).negate());
}
}
Node cl = getCardinalityLiteral( d_maxNegCard );
Node lem = NodeManager::currentNM()->mkNode( OR, cl, NodeManager::currentNM()->mkNode( AND, force_cl ) );
Trace("uf-ss-lemma") << "*** Enforce negative cardinality constraint lemma : " << lem << std::endl;
- d_thss->getOutputChannel().lemma( lem );
+ d_im.lemma(lem, LemmaProperty::NONE, false);
return false;
}
}
@@ -1248,10 +1194,10 @@ int SortModel::getNumRegions(){
return count;
}
-Node SortModel::getCardinalityLiteral(unsigned c)
+Node SortModel::getCardinalityLiteral(uint32_t c)
{
Assert(c > 0);
- std::map<int, Node>::iterator itcl = d_cardinality_literal.find(c);
+ std::map<uint32_t, Node>::iterator itcl = d_cardinality_literal.find(c);
if (itcl != d_cardinality_literal.end())
{
return itcl->second;
@@ -1260,74 +1206,33 @@ Node SortModel::getCardinalityLiteral(unsigned c)
Node lit = d_c_dec_strat->getLiteral(c - 1);
d_cardinality_literal[c] = lit;
- // Since we are reasoning about cardinality c, we invoke a totality axiom
- if (!applyTotality(c))
- {
- // return if we are not using totality axioms
- return lit;
- }
-
- NodeManager* nm = NodeManager::currentNM();
- Node var;
- if (c == 1 && !options::ufssTotalitySymBreak())
- {
- // get arbitrary ground term
- var = d_cardinality_term;
- }
- else
- {
- std::stringstream ss;
- ss << "_c_" << c;
- var = nm->mkSkolem(ss.str(), d_type, "is a cardinality lemma term");
- }
- if ((c - 1) < d_totality_terms[0].size())
- {
- d_totality_terms[0][c - 1] = var;
- }
- else
- {
- d_totality_terms[0].push_back(var);
- }
- // must be distinct from all other cardinality terms
- for (unsigned i = 1, size = d_totality_terms[0].size(); i < size; i++)
- {
- Node lem = var.eqNode(d_totality_terms[0][i - 1]).notNode();
- Trace("uf-ss-lemma") << "Totality distinctness lemma : " << lem
- << std::endl;
- d_thss->getOutputChannel().lemma(lem);
- }
- // must send totality axioms for each existing term
- for (NodeIntMap::iterator it = d_regions_map.begin();
- it != d_regions_map.end();
- ++it)
- {
- addTotalityAxiom((*it).first, c, &d_thss->getOutputChannel());
- }
+ // return the literal
return lit;
}
-CardinalityExtension::CardinalityExtension(context::Context* c,
- context::UserContext* u,
- OutputChannel& out,
+CardinalityExtension::CardinalityExtension(TheoryState& state,
+ TheoryInferenceManager& im,
TheoryUF* th)
- : d_out(&out),
+ : d_state(state),
+ d_im(im),
d_th(th),
- d_conflict(c, false),
d_rep_model(),
- d_min_pos_com_card(c, -1),
+ d_min_pos_com_card(state.getSatContext(), 0),
+ d_min_pos_com_card_set(state.getSatContext(), false),
d_cc_dec_strat(nullptr),
- d_initializedCombinedCardinality(u, false),
- d_card_assertions_eqv_lemma(u),
- d_min_pos_tn_master_card(c, -1),
- d_rel_eqc(c)
+ d_initializedCombinedCardinality(state.getUserContext(), false),
+ d_card_assertions_eqv_lemma(state.getUserContext()),
+ d_min_pos_tn_master_card(state.getSatContext(), 0),
+ d_min_pos_tn_master_card_set(state.getSatContext(), false),
+ d_rel_eqc(state.getSatContext())
{
if (options::ufssMode() == options::UfssMode::FULL && options::ufssFairness())
{
// Register the strategy with the decision manager of the theory.
// We are guaranteed that the decision manager is ready since we
// construct this module during TheoryUF::finishInit.
- d_cc_dec_strat.reset(
- new CombinedCardinalityDecisionStrategy(c, th->getValuation()));
+ d_cc_dec_strat.reset(new CombinedCardinalityDecisionStrategy(
+ state.getSatContext(), th->getValuation()));
}
}
@@ -1353,18 +1258,6 @@ SortInference* CardinalityExtension::getSortInference()
return nullptr;
}
-/** get default sat context */
-context::Context* CardinalityExtension::getSatContext()
-{
- return d_th->getSatContext();
-}
-
-/** get default output channel */
-OutputChannel& CardinalityExtension::getOutputChannel()
-{
- return d_th->getOutputChannel();
-}
-
/** ensure eqc */
void CardinalityExtension::ensureEqc(SortModel* c, Node a)
{
@@ -1403,15 +1296,11 @@ void CardinalityExtension::newEqClass(Node a)
{
SortModel* c = getSortModel( a );
if( c ){
-#ifdef LAZY_REL_EQC
- //do nothing
-#else
Trace("uf-ss-solver") << "CardinalityExtension: New eq class " << a << " : "
<< a.getType() << std::endl;
c->newEqClass( a );
Trace("uf-ss-solver") << "CardinalityExtension: Done New eq class."
<< std::endl;
-#endif
}
}
@@ -1421,23 +1310,10 @@ void CardinalityExtension::merge(Node a, Node b)
//TODO: ensure they are relevant
SortModel* c = getSortModel( a );
if( c ){
-#ifdef LAZY_REL_EQC
- ensureEqc( c, a );
- if( hasEqc( b ) ){
- Trace("uf-ss-solver") << "CardinalityExtension: Merge " << a << " " << b
- << " : " << a.getType() << std::endl;
- c->merge( a, b );
- Trace("uf-ss-solver") << "CardinalityExtension: Done Merge." << std::endl;
- }else{
- //c->assignEqClass( b, a );
- d_rel_eqc[b] = true;
- }
-#else
Trace("uf-ss-solver") << "CardinalityExtension: Merge " << a << " " << b
<< " : " << a.getType() << std::endl;
c->merge( a, b );
Trace("uf-ss-solver") << "CardinalityExtension: Done Merge." << std::endl;
-#endif
}
}
@@ -1446,10 +1322,6 @@ void CardinalityExtension::assertDisequal(Node a, Node b, Node reason)
{
SortModel* c = getSortModel( a );
if( c ){
-#ifdef LAZY_REL_EQC
- ensureEqc( c, a );
- ensureEqc( c, b );
-#endif
Trace("uf-ss-solver") << "CardinalityExtension: Assert disequal " << a
<< " " << b << " : " << a.getType() << std::endl;
c->assertDisequal( a, b, reason );
@@ -1462,9 +1334,6 @@ void CardinalityExtension::assertDisequal(Node a, Node b, Node reason)
void CardinalityExtension::assertNode(Node n, bool isDecision)
{
Trace("uf-ss") << "Assert " << n << " " << isDecision << std::endl;
-#ifdef LAZY_REL_EQC
- ensureEqcRec( n );
-#endif
bool polarity = n.getKind() != kind::NOT;
TNode lit = polarity ? n : n[0];
if (options::ufssMode() == options::UfssMode::FULL)
@@ -1473,7 +1342,8 @@ void CardinalityExtension::assertNode(Node n, bool isDecision)
TypeNode tn = lit[0].getType();
Assert(tn.isSort());
Assert(d_rep_model[tn]);
- int nCard = lit[1].getConst<Rational>().getNumerator().getSignedInt();
+ uint32_t nCard =
+ lit[1].getConst<Rational>().getNumerator().getUnsignedInt();
Node ct = d_rep_model[tn]->getCardinalityTerm();
Trace("uf-ss-debug") << "...check cardinality terms : " << lit[0] << " " << ct << std::endl;
if( lit[0]==ct ){
@@ -1508,13 +1378,16 @@ void CardinalityExtension::assertNode(Node n, bool isDecision)
//set the minimum positive cardinality for master if necessary
if( polarity && tn==d_tn_mono_master ){
Trace("uf-ss-com-card-debug") << "...set min positive cardinality" << std::endl;
- if( d_min_pos_tn_master_card.get()==-1 || nCard<d_min_pos_tn_master_card.get() ){
+ if (!d_min_pos_tn_master_card_set.get()
+ || nCard < d_min_pos_tn_master_card.get())
+ {
+ d_min_pos_tn_master_card_set.set(true);
d_min_pos_tn_master_card.set( nCard );
}
}
}
Trace("uf-ss-com-card-debug") << "...assert cardinality" << std::endl;
- d_rep_model[tn]->assertCardinality( d_out, nCard, polarity );
+ d_rep_model[tn]->assertCardinality(nCard, polarity);
//check if combined cardinality is violated
checkCombinedCardinality();
}else{
@@ -1523,15 +1396,18 @@ void CardinalityExtension::assertNode(Node n, bool isDecision)
Node eqv_lit = NodeManager::currentNM()->mkNode( CARDINALITY_CONSTRAINT, ct, lit[1] );
eqv_lit = lit.eqNode( eqv_lit );
Trace("uf-ss-lemma") << "*** Cardinality equiv lemma : " << eqv_lit << std::endl;
- getOutputChannel().lemma( eqv_lit );
+ d_im.lemma(eqv_lit, LemmaProperty::NONE, false);
d_card_assertions_eqv_lemma[lit] = true;
}
}
}else if( lit.getKind()==COMBINED_CARDINALITY_CONSTRAINT ){
if( polarity ){
//safe to assume int here
- int nCard = lit[0].getConst<Rational>().getNumerator().getSignedInt();
- if( d_min_pos_com_card.get()==-1 || nCard<d_min_pos_com_card.get() ){
+ uint32_t nCard =
+ lit[0].getConst<Rational>().getNumerator().getUnsignedInt();
+ if (!d_min_pos_com_card_set.get() || nCard < d_min_pos_com_card.get())
+ {
+ d_min_pos_com_card_set.set(true);
d_min_pos_com_card.set( nCard );
checkCombinedCardinality();
}
@@ -1557,7 +1433,7 @@ void CardinalityExtension::assertNode(Node n, bool isDecision)
if( lit.getKind()==CARDINALITY_CONSTRAINT || lit.getKind()==COMBINED_CARDINALITY_CONSTRAINT ){
// cardinality constraint from user input, set incomplete
Trace("uf-ss") << "Literal " << lit << " not handled when uf ss mode is not FULL, set incomplete." << std::endl;
- d_out->setIncomplete();
+ d_im.setIncomplete();
}
}
Trace("uf-ss") << "Assert: done " << n << " " << isDecision << std::endl;
@@ -1586,7 +1462,20 @@ bool CardinalityExtension::areDisequal(Node a, Node b)
/** check */
void CardinalityExtension::check(Theory::Effort level)
{
- if( !d_conflict ){
+ if (level == Theory::EFFORT_LAST_CALL)
+ {
+ // if last call, call last call check for each sort
+ for (std::pair<const TypeNode, SortModel*>& r : d_rep_model)
+ {
+ if (!r.second->checkLastCall())
+ {
+ break;
+ }
+ }
+ return;
+ }
+ if (!d_state.isInConflict())
+ {
if (options::ufssMode() == options::UfssMode::FULL)
{
Trace("uf-ss-solver")
@@ -1609,9 +1498,9 @@ void CardinalityExtension::check(Theory::Effort level)
}
}
for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
- it->second->check( level, d_out );
- if( it->second->isConflict() ){
- d_conflict = true;
+ it->second->check(level);
+ if (d_state.isInConflict())
+ {
break;
}
}
@@ -1636,8 +1525,8 @@ void CardinalityExtension::check(Theory::Effort level)
Node eq = Rewriter::rewrite( a.eqNode( b ) );
Node lem = NodeManager::currentNM()->mkNode( kind::OR, eq, eq.negate() );
Trace("uf-ss-lemma") << "*** Split (no-minimal) : " << lem << std::endl;
- d_out->lemma( lem );
- d_out->requirePhase( eq, true );
+ d_im.lemma(lem, LemmaProperty::NONE, false);
+ d_im.requirePhase(eq, true);
type_proc[tn] = true;
break;
}
@@ -1665,7 +1554,7 @@ void CardinalityExtension::presolve()
d_initializedCombinedCardinality = false;
for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
it->second->presolve();
- it->second->initialize( d_out );
+ it->second->initialize();
}
}
@@ -1703,31 +1592,16 @@ void CardinalityExtension::preRegisterTerm(TNode n)
SortModel* rm = NULL;
if( tn.isSort() ){
Trace("uf-ss-register") << "Create sort model " << tn << "." << std::endl;
- rm = new SortModel( n, d_th->getSatContext(), d_th->getUserContext(), this );
- //getOutputChannel().lemma( n.eqNode( rm->getCardinalityTerm() ) );
- }else{
- /*
- if( tn==NodeManager::currentNM()->integerType() || tn==NodeManager::currentNM()->realType() ){
- Debug("uf-ss-na") << "Error: Cannot perform finite model finding on arithmetic quantifier";
- Debug("uf-ss-na") << " (" << f << ")";
- Debug("uf-ss-na") << std::endl;
- Unimplemented() << "Cannot perform finite model finding on arithmetic quantifier";
- }else if( tn.isDatatype() ){
- Debug("uf-ss-na") << "Error: Cannot perform finite model finding on datatype quantifier";
- Debug("uf-ss-na") << " (" << f << ")";
- Debug("uf-ss-na") << std::endl;
- Unimplemented() << "Cannot perform finite model finding on datatype quantifier";
- }
- */
+ rm = new SortModel(n, d_state, d_im, this);
}
if( rm ){
- rm->initialize( d_out );
+ rm->initialize();
d_rep_model[tn] = rm;
//d_rep_model_init[tn] = true;
}
}else{
//ensure sort model is initialized
- it->second->initialize( d_out );
+ it->second->initialize();
}
}
}
@@ -1778,16 +1652,6 @@ void CardinalityExtension::debugPrint(const char* c)
}
}
-bool CardinalityExtension::debugModel(TheoryModel* m)
-{
- for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
- if( !it->second->debugModel( m ) ){
- return false;
- }
- }
- return true;
-}
-
/** initialize */
void CardinalityExtension::initializeCombinedCardinality()
{
@@ -1806,11 +1670,11 @@ void CardinalityExtension::checkCombinedCardinality()
Assert(options::ufssMode() == options::UfssMode::FULL);
if( options::ufssFairness() ){
Trace("uf-ss-com-card-debug") << "Check combined cardinality, get maximum negative cardinalities..." << std::endl;
- int totalCombinedCard = 0;
- int maxMonoSlave = 0;
+ uint32_t totalCombinedCard = 0;
+ uint32_t maxMonoSlave = 0;
TypeNode maxSlaveType;
for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin(); it != d_rep_model.end(); ++it ){
- int max_neg = it->second->getMaximumNegativeCardinality();
+ uint32_t max_neg = it->second->getMaximumNegativeCardinality();
if( !options::ufssFairnessMonotone() ){
totalCombinedCard += max_neg;
}else{
@@ -1828,8 +1692,10 @@ void CardinalityExtension::checkCombinedCardinality()
Trace("uf-ss-com-card-debug") << "Check combined cardinality, total combined card : " << totalCombinedCard << std::endl;
if( options::ufssFairnessMonotone() ){
Trace("uf-ss-com-card-debug") << "Max slave monotonic negated cardinality : " << maxMonoSlave << std::endl;
- if( d_min_pos_tn_master_card.get()!=-1 && maxMonoSlave>d_min_pos_tn_master_card.get() ){
- int mc = d_min_pos_tn_master_card.get();
+ if (!d_min_pos_tn_master_card_set.get()
+ && maxMonoSlave > d_min_pos_tn_master_card.get())
+ {
+ uint32_t mc = d_min_pos_tn_master_card.get();
std::vector< Node > conf;
conf.push_back( d_rep_model[d_tn_mono_master]->getCardinalityLiteral( mc ) );
conf.push_back( d_rep_model[maxSlaveType]->getCardinalityLiteral( maxMonoSlave ).negate() );
@@ -1838,18 +1704,18 @@ void CardinalityExtension::checkCombinedCardinality()
<< " : " << cf << std::endl;
Trace("uf-ss-com-card") << "*** Combined monotone cardinality conflict"
<< " : " << cf << std::endl;
- getOutputChannel().conflict( cf );
- d_conflict.set( true );
+ d_im.conflict(cf);
return;
}
}
- int cc = d_min_pos_com_card.get();
- if( cc !=-1 && totalCombinedCard > cc ){
+ uint32_t cc = d_min_pos_com_card.get();
+ if (d_min_pos_com_card_set.get() && totalCombinedCard > cc)
+ {
//conflict
Node com_lit = d_cc_dec_strat->getLiteral(cc);
std::vector< Node > conf;
conf.push_back( com_lit );
- int totalAdded = 0;
+ uint32_t totalAdded = 0;
for( std::map< TypeNode, SortModel* >::iterator it = d_rep_model.begin();
it != d_rep_model.end(); ++it ){
bool doAdd = true;
@@ -1861,7 +1727,7 @@ void CardinalityExtension::checkCombinedCardinality()
}
}
if( doAdd ){
- int c = it->second->getMaximumNegativeCardinality();
+ uint32_t c = it->second->getMaximumNegativeCardinality();
if( c>0 ){
conf.push_back( it->second->getCardinalityLiteral( c ).negate() );
totalAdded += c;
@@ -1876,8 +1742,7 @@ void CardinalityExtension::checkCombinedCardinality()
<< std::endl;
Trace("uf-ss-com-card") << "*** Combined cardinality conflict : " << cf
<< std::endl;
- getOutputChannel().conflict( cf );
- d_conflict.set( true );
+ d_im.conflict(cf);
}
}
}
@@ -1886,15 +1751,11 @@ CardinalityExtension::Statistics::Statistics()
: d_clique_conflicts("CardinalityExtension::Clique_Conflicts", 0),
d_clique_lemmas("CardinalityExtension::Clique_Lemmas", 0),
d_split_lemmas("CardinalityExtension::Split_Lemmas", 0),
- d_disamb_term_lemmas("CardinalityExtension::Disambiguate_Term_Lemmas", 0),
- d_totality_lemmas("CardinalityExtension::Totality_Lemmas", 0),
d_max_model_size("CardinalityExtension::Max_Model_Size", 1)
{
smtStatisticsRegistry()->registerStat(&d_clique_conflicts);
smtStatisticsRegistry()->registerStat(&d_clique_lemmas);
smtStatisticsRegistry()->registerStat(&d_split_lemmas);
- smtStatisticsRegistry()->registerStat(&d_disamb_term_lemmas);
- smtStatisticsRegistry()->registerStat(&d_totality_lemmas);
smtStatisticsRegistry()->registerStat(&d_max_model_size);
}
@@ -1903,8 +1764,6 @@ CardinalityExtension::Statistics::~Statistics()
smtStatisticsRegistry()->unregisterStat(&d_clique_conflicts);
smtStatisticsRegistry()->unregisterStat(&d_clique_lemmas);
smtStatisticsRegistry()->unregisterStat(&d_split_lemmas);
- smtStatisticsRegistry()->unregisterStat(&d_disamb_term_lemmas);
- smtStatisticsRegistry()->unregisterStat(&d_totality_lemmas);
smtStatisticsRegistry()->unregisterStat(&d_max_model_size);
}
diff --git a/src/theory/uf/cardinality_extension.h b/src/theory/uf/cardinality_extension.h
index e1ca46bfb..6b5349ce7 100644
--- a/src/theory/uf/cardinality_extension.h
+++ b/src/theory/uf/cardinality_extension.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -133,14 +133,14 @@ class CardinalityExtension
/** conflict find pointer */
SortModel* d_cf;
- context::CDO< unsigned > d_testCliqueSize;
+ context::CDO<size_t> d_testCliqueSize;
context::CDO< unsigned > d_splitsSize;
//a postulated clique
NodeBoolMap d_testClique;
//disequalities needed for this clique to happen
NodeBoolMap d_splits;
//number of valid representatives in this region
- context::CDO< unsigned > d_reps_size;
+ context::CDO<size_t> d_reps_size;
//total disequality size (external)
context::CDO< unsigned > d_total_diseq_external;
//total disequality size (internal)
@@ -188,9 +188,9 @@ class CardinalityExtension
//set n1 != n2 to value 'valid', type is whether it is internal/external
void setDisequal( Node n1, Node n2, int type, bool valid );
//get num reps
- int getNumReps() { return d_reps_size; }
+ size_t getNumReps() const { return d_reps_size; }
//get test clique size
- int getTestCliqueSize() { return d_testCliqueSize; }
+ size_t getTestCliqueSize() const { return d_testCliqueSize; }
// has representative
bool hasRep( Node n ) {
return d_nodes.find(n) != d_nodes.end() && d_nodes[n]->valid();
@@ -215,10 +215,14 @@ class CardinalityExtension
private:
/** the type this model is for */
TypeNode d_type;
+ /** Reference to the state object */
+ TheoryState& d_state;
+ /** Reference to the inference manager */
+ TheoryInferenceManager& d_im;
/** Pointer to the cardinality extension that owns this. */
CardinalityExtension* d_thss;
/** regions used to d_region_index */
- context::CDO< unsigned > d_regions_index;
+ context::CDO<size_t> d_regions_index;
/** vector of regions */
std::vector< Region* > d_regions;
/** map from Nodes to index of d_regions they exist in, -1 means invalid */
@@ -251,58 +255,43 @@ class CardinalityExtension
/** move node n to region ri */
void moveNode( Node n, int ri );
/** allocate cardinality */
- void allocateCardinality( OutputChannel* out );
+ void allocateCardinality();
/**
* Add splits. Returns
* 0 = no split,
* -1 = entailed disequality added, or
* 1 = split added.
*/
- int addSplit( Region* r, OutputChannel* out );
+ int addSplit(Region* r);
/** add clique lemma */
- void addCliqueLemma( std::vector< Node >& clique, OutputChannel* out );
- /** add totality axiom */
- void addTotalityAxiom( Node n, int cardinality, OutputChannel* out );
- /** Are we in conflict */
- context::CDO<bool> d_conflict;
+ void addCliqueLemma(std::vector<Node>& clique);
/** cardinality */
- context::CDO< int > d_cardinality;
+ context::CDO<uint32_t> d_cardinality;
/** cardinality lemma term */
Node d_cardinality_term;
- /** cardinality totality terms */
- std::map< int, std::vector< Node > > d_totality_terms;
/** cardinality literals */
- std::map< int, Node > d_cardinality_literal;
+ std::map<uint32_t, Node> d_cardinality_literal;
/** whether a positive cardinality constraint has been asserted */
context::CDO< bool > d_hasCard;
/** clique lemmas that have been asserted */
std::map< int, std::vector< std::vector< Node > > > d_cliques;
/** maximum negatively asserted cardinality */
- context::CDO< int > d_maxNegCard;
+ context::CDO<uint32_t> d_maxNegCard;
/** list of fresh representatives allocated */
std::vector< Node > d_fresh_aloc_reps;
/** whether we are initialized */
context::CDO< bool > d_initialized;
- /** cache for lemmas */
- NodeBoolMap d_lemma_cache;
-
- /** apply totality */
- bool applyTotality( int cardinality );
- /** get totality lemma terms */
- Node getTotalityLemmaTerm( int cardinality, int i );
/** simple check cardinality */
void simpleCheckCardinality();
- bool doSendLemma( Node lem );
-
public:
SortModel(Node n,
- context::Context* c,
- context::UserContext* u,
+ TheoryState& state,
+ TheoryInferenceManager& im,
CardinalityExtension* thss);
virtual ~SortModel();
/** initialize */
- void initialize( OutputChannel* out );
+ void initialize();
/** new node */
void newEqClass( Node n );
/** merge */
@@ -312,29 +301,35 @@ class CardinalityExtension
/** are disequal */
bool areDisequal( Node a, Node b );
/** check */
- void check( Theory::Effort level, OutputChannel* out );
+ void check(Theory::Effort level);
/** presolve */
void presolve();
- /** propagate */
- void propagate( Theory::Effort level, OutputChannel* out );
/** assert cardinality */
- void assertCardinality( OutputChannel* out, int c, bool val );
- /** is in conflict */
- bool isConflict() { return d_conflict; }
+ void assertCardinality(uint32_t c, bool val);
/** get cardinality */
- int getCardinality() { return d_cardinality; }
+ uint32_t getCardinality() const { return d_cardinality; }
/** has cardinality */
- bool hasCardinalityAsserted() { return d_hasCard; }
+ bool hasCardinalityAsserted() const { return d_hasCard; }
/** get cardinality term */
- Node getCardinalityTerm() { return d_cardinality_term; }
+ Node getCardinalityTerm() const { return d_cardinality_term; }
/** get cardinality literal */
- Node getCardinalityLiteral(unsigned c);
+ Node getCardinalityLiteral(uint32_t c);
/** get maximum negative cardinality */
- int getMaximumNegativeCardinality() { return d_maxNegCard.get(); }
+ uint32_t getMaximumNegativeCardinality() const
+ {
+ return d_maxNegCard.get();
+ }
//print debug
void debugPrint( const char* c );
- /** debug a model */
- bool debugModel( TheoryModel* m );
+ /**
+ * Check at last call effort. This will verify that the model is minimal.
+ * This return lemmas if there are terms in the model that the cardinality
+ * extension was not notified of.
+ *
+ * @return false if current model is not minimal. In this case, lemmas are
+ * sent on the output channel of the UF theory.
+ */
+ bool checkLastCall();
/** get number of regions (for debugging) */
int getNumRegions();
@@ -365,19 +360,14 @@ class CardinalityExtension
}; /** class SortModel */
public:
- CardinalityExtension(context::Context* c,
- context::UserContext* u,
- OutputChannel& out,
+ CardinalityExtension(TheoryState& state,
+ TheoryInferenceManager& im,
TheoryUF* th);
~CardinalityExtension();
/** get theory */
TheoryUF* getTheory() { return d_th; }
/** get sort inference module */
SortInference* getSortInference();
- /** get default sat context */
- context::Context* getSatContext();
- /** get default output channel */
- OutputChannel& getOutputChannel();
/** new node */
void newEqClass( Node n );
/** merge */
@@ -398,10 +388,6 @@ class CardinalityExtension
std::string identify() const { return std::string("CardinalityExtension"); }
//print debug
void debugPrint( const char* c );
- /** debug a model */
- bool debugModel( TheoryModel* m );
- /** get is in conflict */
- bool isConflict() { return d_conflict; }
/** get cardinality for node */
int getCardinality( Node n );
/** get cardinality for type */
@@ -414,8 +400,6 @@ class CardinalityExtension
IntStat d_clique_conflicts;
IntStat d_clique_lemmas;
IntStat d_split_lemmas;
- IntStat d_disamb_term_lemmas;
- IntStat d_totality_lemmas;
IntStat d_max_model_size;
Statistics();
~Statistics();
@@ -435,17 +419,19 @@ class CardinalityExtension
/** ensure eqc for all subterms of n */
void ensureEqcRec(Node n);
- /** The output channel used by this class. */
- OutputChannel* d_out;
+ /** Reference to the state object */
+ TheoryState& d_state;
+ /** Reference to the inference manager */
+ TheoryInferenceManager& d_im;
/** theory uf pointer */
TheoryUF* d_th;
- /** Are we in conflict */
- context::CDO<bool> d_conflict;
/** rep model structure, one for each type */
std::map<TypeNode, SortModel*> d_rep_model;
/** minimum positive combined cardinality */
- context::CDO<int> d_min_pos_com_card;
+ context::CDO<uint32_t> d_min_pos_com_card;
+ /** Whether the field above has been set */
+ context::CDO<bool> d_min_pos_com_card_set;
/**
* Decision strategy for combined cardinality constraints. This asserts
* the minimal combined cardinality constraint positively in the SAT
@@ -473,7 +459,10 @@ class CardinalityExtension
/** the master monotone type (if ufssFairnessMonotone enabled) */
TypeNode d_tn_mono_master;
std::map<TypeNode, bool> d_tn_mono_slave;
- context::CDO<int> d_min_pos_tn_master_card;
+ /** The minimum positive asserted master cardinality */
+ context::CDO<uint32_t> d_min_pos_tn_master_card;
+ /** Whether the field above has been set */
+ context::CDO<bool> d_min_pos_tn_master_card_set;
/** relevant eqc */
NodeBoolMap d_rel_eqc;
}; /* class CardinalityExtension */
diff --git a/src/theory/uf/eq_proof.cpp b/src/theory/uf/eq_proof.cpp
index 3a60d246e..7ab43091a 100644
--- a/src/theory/uf/eq_proof.cpp
+++ b/src/theory/uf/eq_proof.cpp
@@ -1,11 +1,11 @@
/********************* */
-/*! \file eq_proof.h
+/*! \file eq_proof.cpp
** \verbatim
** Top contributors (to current version):
- ** Haniel Barbosa
+ ** Haniel Barbosa, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -16,38 +16,26 @@
#include "theory/uf/eq_proof.h"
#include "expr/proof.h"
+#include "options/uf_options.h"
namespace CVC4 {
namespace theory {
namespace eq {
-void EqProof::debug_print(const char* c,
- unsigned tb,
- PrettyPrinter* prettyPrinter) const
+void EqProof::debug_print(const char* c, unsigned tb) const
{
std::stringstream ss;
- debug_print(ss, tb, prettyPrinter);
+ debug_print(ss, tb);
Debug(c) << ss.str();
}
-void EqProof::debug_print(std::ostream& os,
- unsigned tb,
- PrettyPrinter* prettyPrinter) const
+void EqProof::debug_print(std::ostream& os, unsigned tb) const
{
for (unsigned i = 0; i < tb; i++)
{
os << " ";
}
-
- if (prettyPrinter)
- {
- os << prettyPrinter->printTag(d_id);
- }
- else
- {
- os << static_cast<MergeReasonType>(d_id);
- }
- os << "(";
+ os << d_id << "(";
if (d_children.empty() && d_node.isNull())
{
os << ")";
@@ -66,7 +54,7 @@ void EqProof::debug_print(std::ostream& os,
for (unsigned i = 0; i < size; ++i)
{
os << std::endl;
- d_children[i]->debug_print(os, tb + 1, prettyPrinter);
+ d_children[i]->debug_print(os, tb + 1);
if (i < size - 1)
{
for (unsigned j = 0; j < tb + 1; ++j)
@@ -86,7 +74,31 @@ void EqProof::debug_print(std::ostream& os,
os << ")" << std::endl;
}
-void EqProof::cleanReflPremises(std::vector<Node>& premises) const {}
+void EqProof::cleanReflPremises(std::vector<Node>& premises) const
+{
+ std::vector<Node> newPremises;
+ unsigned size = premises.size();
+ for (unsigned i = 0; i < size; ++i)
+ {
+ if (premises[i][0] == premises[i][1])
+ {
+ continue;
+ }
+ newPremises.push_back(premises[i]);
+ }
+ if (newPremises.size() != size)
+ {
+ Trace("eqproof-conv") << "EqProof::cleanReflPremises: removed "
+ << (newPremises.size() >= size
+ ? newPremises.size() - size
+ : 0)
+ << " refl premises from " << premises << "\n";
+ premises.clear();
+ premises.insert(premises.end(), newPremises.begin(), newPremises.end());
+ Trace("eqproof-conv") << "EqProof::cleanReflPremises: new premises "
+ << premises << "\n";
+ }
+}
bool EqProof::expandTransitivityForDisequalities(
Node conclusion,
@@ -94,12 +106,574 @@ bool EqProof::expandTransitivityForDisequalities(
CDProof* p,
std::unordered_set<Node, NodeHashFunction>& assumptions) const
{
- return false;
+ Trace("eqproof-conv")
+ << "EqProof::expandTransitivityForDisequalities: check if need "
+ "to expand transitivity step to conclude "
+ << conclusion << " from premises " << premises << "\n";
+ // Check premises to see if any of the form (= (= t1 t2) false), modulo
+ // symmetry
+ unsigned size = premises.size();
+ // termPos is, in (= (= t1 t2) false) or (= false (= t1 t2)), the position of
+ // the equality. When the i-th premise has that form, offending = i
+ unsigned termPos = 2, offending = size;
+ for (unsigned i = 0; i < size; ++i)
+ {
+ Assert(premises[i].getKind() == kind::EQUAL);
+ for (unsigned j = 0; j < 2; ++j)
+ {
+ if (premises[i][j].getKind() == kind::CONST_BOOLEAN
+ && !premises[i][j].getConst<bool>()
+ && premises[i][1 - j].getKind() == kind::EQUAL)
+ {
+ // there is only one offending equality
+ Assert(offending == size);
+ offending = i;
+ termPos = 1 - j;
+ break;
+ }
+ }
+ }
+ // if no equality of the searched form, nothing to do
+ if (offending == size)
+ {
+ return false;
+ }
+ NodeManager* nm = NodeManager::currentNM();
+ Assert(termPos == 0 || termPos == 1);
+ Trace("eqproof-conv") << "EqProof::expandTransitivityForDisequalities: found "
+ "offending equality at index "
+ << offending << " : " << premises[offending] << "\n";
+ // collect the premises to be used in the expansion, which are all but the
+ // offending one
+ std::vector<Node> expansionPremises;
+ for (unsigned i = 0; i < size; ++i)
+ {
+ if (i != offending)
+ {
+ expansionPremises.push_back(premises[i]);
+ }
+ }
+ // Eliminate spurious premises. Reasoning below assumes no refl steps.
+ cleanReflPremises(expansionPremises);
+ Assert(!expansionPremises.empty());
+ // Check if we are in the substitution case
+ Node expansionConclusion;
+ std::vector<Node> substPremises;
+ bool inSubstCase = false, substConclusionInReverseOrder = false;
+ if ((conclusion[0].getKind() == kind::CONST_BOOLEAN)
+ != (conclusion[1].getKind() == kind::CONST_BOOLEAN))
+ {
+ inSubstCase = true;
+ // reorder offending premise if constant is the first argument
+ if (termPos == 1)
+ {
+ premises[offending] =
+ premises[offending][1].eqNode(premises[offending][0]);
+ }
+ // reorder conclusion if constant is the first argument
+ conclusion = conclusion[1].getKind() == kind::CONST_BOOLEAN
+ ? conclusion
+ : conclusion[1].eqNode(conclusion[0]);
+ // equality term in premise disequality
+ Node premiseTermEq = premises[offending][0];
+ // equality term in conclusion disequality
+ Node conclusionTermEq = conclusion[0];
+ Trace("eqproof-conv")
+ << "EqProof::expandTransitivityForDisequalities: Substitition "
+ "case. Need to build subst from "
+ << premiseTermEq << " to " << conclusionTermEq << "\n";
+ // If only one argument in the premise is substituted, premiseTermEq and
+ // conclusionTermEq will share one argument and the other argument change
+ // defines the single substitution. Otherwise both arguments are replaced,
+ // so there are two substitutions.
+ std::vector<Node> subs[2];
+ subs[0].push_back(premiseTermEq[0]);
+ subs[1].push_back(premiseTermEq[1]);
+ // which of the arguments of premiseTermEq, if any, is equal to one argument
+ // of conclusionTermEq
+ int equalArg = -1;
+ for (unsigned i = 0; i < 2; ++i)
+ {
+ for (unsigned j = 0; j < 2; ++j)
+ {
+ if (premiseTermEq[i] == conclusionTermEq[j])
+ {
+ equalArg = i;
+ // identity sub
+ subs[i].push_back(conclusionTermEq[j]);
+ // sub that changes argument
+ subs[1 - i].push_back(conclusionTermEq[1 - j]);
+ // wither e.g. (= t1 t2), with sub t1->t3, becomes (= t2 t3)
+ substConclusionInReverseOrder = i != j;
+ break;
+ }
+ }
+ }
+ // simple case of single substitution
+ if (equalArg >= 0)
+ {
+ // case of
+ // (= (= t1 t2) false) (= t1 x1) ... (= xn t3)
+ // -------------------------------------------- EQP::TR
+ // (= (= t3 t2) false)
+ // where
+ //
+ // (= t1 x1) ... (= xn t3) - expansion premises
+ // ------------------------ TRANS
+ // (= t1 t3) - expansion conclusion
+ //
+ // will be the expansion made to justify the substitution for t1->t3.
+ expansionConclusion = subs[1 - equalArg][0].eqNode(subs[1 - equalArg][1]);
+ Trace("eqproof-conv") << "EqProof::expandTransitivityForDisequalities: "
+ "Need to expand premises into "
+ << expansionConclusion << "\n";
+ // add refl step for the substitition t2->t2
+ p->addStep(subs[equalArg][0].eqNode(subs[equalArg][1]),
+ PfRule::REFL,
+ {},
+ {subs[equalArg][0]});
+ }
+ else
+ {
+ // Hard case. We determine, and justify, the substitutions t1->t3/t4 and
+ // t2->t3/t4 based on the expansion premises.
+ Trace("eqproof-conv") << "EqProof::expandTransitivityForDisequalities: "
+ "Need two substitutions. Look for "
+ << premiseTermEq[0] << " and " << premiseTermEq[1]
+ << " in premises " << expansionPremises << "\n";
+ Assert(expansionPremises.size() >= 2)
+ << "Less than 2 expansion premises for substituting BOTH terms in "
+ "disequality.\nDisequality: "
+ << premises[offending]
+ << "\nExpansion premises: " << expansionPremises
+ << "\nConclusion: " << conclusion << "\n";
+ // Easier case where we can determine the substitutions by directly
+ // looking at the premises, i.e. the two expansion premises are for
+ // example (= t1 t3) and (= t2 t4)
+ if (expansionPremises.size() == 2)
+ {
+ // iterate over args to be substituted
+ for (unsigned i = 0; i < 2; ++i)
+ {
+ // iterate over premises
+ for (unsigned j = 0; j < 2; ++j)
+ {
+ // iterate over args in premise
+ for (unsigned k = 0; k < 2; ++k)
+ {
+ if (premiseTermEq[i] == expansionPremises[j][k])
+ {
+ subs[i].push_back(expansionPremises[j][1 - k]);
+ break;
+ }
+ }
+ }
+ Assert(subs[i].size() == 2)
+ << " did not find term " << subs[i][0] << "\n";
+ // check if argument to be substituted is in the same order in the
+ // conclusion
+ substConclusionInReverseOrder =
+ premiseTermEq[i] != conclusionTermEq[i];
+ }
+ }
+ else
+ {
+ Trace("eqproof-conv") << "EqProof::expandTransitivityForDisequalities: "
+ "Build transitivity chains "
+ "for two subs among more than 2 premises: "
+ << expansionPremises << "\n";
+ // Hardest case. Try building a transitivity chain for (= t1 t3). If it
+ // can be built, use the remaining expansion premises to build a chain
+ // for (= t2 t4). Otherwise build it for (= t1 t4) and then build it for
+ // (= t2 t3). It should always succeed.
+ subs[0].push_back(conclusionTermEq[0]);
+ subs[1].push_back(conclusionTermEq[1]);
+ for (unsigned i = 0; i < 2; ++i)
+ {
+ // copy premises, since buildTransitivityChain is destructive
+ std::vector<Node> copy1ofExpPremises(expansionPremises.begin(),
+ expansionPremises.end());
+ Node transConclusion1 = subs[0][0].eqNode(subs[0][1]);
+ if (!buildTransitivityChain(transConclusion1, copy1ofExpPremises))
+ {
+ AlwaysAssert(i == 0)
+ << "Couldn't find sub at all for substituting BOTH terms in "
+ "disequality.\nDisequality: "
+ << premises[offending]
+ << "\nExpansion premises: " << expansionPremises
+ << "\nConclusion: " << conclusion << "\n";
+ // Failed. So flip sub and try again
+ subs[0][1] = conclusionTermEq[1];
+ subs[1][1] = conclusionTermEq[0];
+ substConclusionInReverseOrder = false;
+ continue;
+ }
+ // build next chain
+ std::vector<Node> copy2ofExpPremises(expansionPremises.begin(),
+ expansionPremises.end());
+ Node transConclusion2 = subs[1][0].eqNode(subs[1][1]);
+ if (!buildTransitivityChain(transConclusion2, copy2ofExpPremises))
+ {
+ Unreachable() << "Found sub " << transConclusion1
+ << " but not other sub " << transConclusion2
+ << ".\nDisequality: " << premises[offending]
+ << "\nExpansion premises: " << expansionPremises
+ << "\nConclusion: " << conclusion << "\n";
+ }
+ Trace("eqproof-conv")
+ << "EqProof::expandTransitivityForDisequalities: Built trans "
+ "chains: "
+ "for two subs among more than 2 premises:\n";
+ Trace("eqproof-conv")
+ << "EqProof::expandTransitivityForDisequalities: "
+ << transConclusion1 << " <- " << copy1ofExpPremises << "\n";
+ Trace("eqproof-conv")
+ << "EqProof::expandTransitivityForDisequalities: "
+ << transConclusion2 << " <- " << copy2ofExpPremises << "\n";
+ // do transitivity steps if need be to justify each substitution
+ if (copy1ofExpPremises.size() > 1
+ && !assumptions.count(transConclusion1))
+ {
+ p->addStep(
+ transConclusion1, PfRule::TRANS, copy1ofExpPremises, {}, true);
+ }
+ if (copy2ofExpPremises.size() > 1
+ && !assumptions.count(transConclusion2))
+ {
+ p->addStep(
+ transConclusion2, PfRule::TRANS, copy2ofExpPremises, {}, true);
+ }
+ }
+ }
+ }
+ Trace("eqproof-conv")
+ << "EqProof::expandTransitivityForDisequalities: Built substutitions "
+ << subs[0] << " and " << subs[1] << " to map " << premiseTermEq
+ << " -> " << conclusionTermEq << "\n";
+ Assert(subs[0][1] == conclusion[0][0] || subs[0][1] == conclusion[0][1])
+ << "EqProof::expandTransitivityForDisequalities: First substitution "
+ << subs[0] << " doest not map to conclusion " << conclusion << "\n";
+ Assert(subs[1][1] == conclusion[0][0] || subs[1][1] == conclusion[0][1])
+ << "EqProof::expandTransitivityForDisequalities: Second substitution "
+ << subs[1] << " doest not map to conclusion " << conclusion << "\n";
+ // In the premises for the original conclusion, the substitution of
+ // premiseTermEq (= t1 t2) into conclusionTermEq (= t3 t4) is stored
+ // reversed, i.e. as (= (= t3 t4) (= t1 t2)), since the transitivity with
+ // the disequality is built as as
+ // (= (= t3 t4) (= t1 t2)) (= (= t1 t2) false)
+ // --------------------------------------------------------------------- TR
+ // (= (= t3 t4) false)
+ substPremises.push_back(subs[0][1].eqNode(subs[0][0]));
+ substPremises.push_back(subs[1][1].eqNode(subs[1][0]));
+ }
+ else
+ {
+ // In simple case the conclusion is always, modulo symmetry, false = true
+ Assert(conclusion[0].getKind() == kind::CONST_BOOLEAN
+ && conclusion[1].getKind() == kind::CONST_BOOLEAN);
+ // The expansion conclusion is the same as the equality term in the
+ // disequality, which is going to be justified by a transitivity step from
+ // the expansion premises
+ expansionConclusion = premises[offending][termPos];
+ }
+ // Unless we are in the double-substitution case, the proof has the shape
+ //
+ // ... ... ... ... - expansionPremises
+ // ------------------ TRANS
+ // (= (= (t t') false) (= t'' t''') - expansionConclusion
+ // ---------------------------------------------- TRANS or PRED_TRANSFORM
+ // conclusion
+ //
+ // although note that if it's a TRANS step, (= t'' t''') will be turned into a
+ // predicate equality and the premises are ordered.
+ //
+ // We build the transitivity step for the expansionConclusion here. It being
+ // non-null marks that we are not in the double-substitution case.
+ if (!expansionConclusion.isNull())
+ {
+ Trace("eqproof-conv")
+ << "EqProof::expandTransitivityForDisequalities: need to derive "
+ << expansionConclusion << " with premises " << expansionPremises
+ << "\n";
+ Assert(expansionPremises.size() > 1
+ || expansionConclusion == expansionPremises.back()
+ || (expansionConclusion[0] == expansionPremises.back()[1]
+ && expansionConclusion[1] == expansionPremises.back()[0]))
+ << "single expansion premise " << expansionPremises.back()
+ << " is not the same as expansionConclusion " << expansionConclusion
+ << " and not its symmetric\n";
+ // We track assumptions to avoid cyclic proofs, which can happen in EqProofs
+ // such as:
+ //
+ // (= l1 "") (= "" t)
+ // ----------------------- EQP::TR
+ // (= l1 "") (= l1 t) (= (= "" t) false)
+ // ----------------------------------------------------------------- EQP::TR
+ // (= false true)
+ //
+ // which would lead to the cyclic expansion proof:
+ //
+ // (= l1 "") (= l1 "") (= "" t)
+ // --------- SYMM ----------------------- TRANS
+ // (= "" l1) (= l1 t)
+ // ------------------------------------------ TRANS
+ // (= "" t)
+ if (expansionPremises.size() > 1 && !assumptions.count(expansionConclusion))
+ {
+ // create transitivity step to derive expected premise
+ buildTransitivityChain(expansionConclusion, expansionPremises);
+ Trace("eqproof-conv")
+ << "EqProof::expandTransitivityForDisequalities: add transitivity "
+ "step for "
+ << expansionConclusion << " with premises " << expansionPremises
+ << "\n";
+ // create expansion step
+ p->addStep(
+ expansionConclusion, PfRule::TRANS, expansionPremises, {}, true);
+ }
+ }
+ Trace("eqproof-conv")
+ << "EqProof::expandTransitivityForDisequalities: now derive conclusion "
+ << conclusion;
+ premises.clear();
+ premises.push_back(premises[offending]);
+ if (inSubstCase)
+ {
+ Trace("eqproof-conv") << (substConclusionInReverseOrder ? " [inverted]"
+ : "")
+ << " via subsitution from " << premises[offending]
+ << " and (inverted subst) " << substPremises << "\n";
+ // By this point, for premise disequality (= (= t1 t2) false), we have
+ // potentially already built
+ //
+ // (= t1 x1) ... (= xn t3) (= t2 y1) ... (= ym t4)
+ // ------------------------ TR ------------------------ TR
+ // (= t1 t3) (= t2 t4)
+ //
+ // to justify the substitutions t1->t3 and t2->t4 (where note that if t1=t3
+ // or t2=4, the step will actually be a REFL one). Not do
+ //
+ // ----------- SYMM ----------- SYMM
+ // (= t3 t1) (= t4 t2)
+ // ---------------------------------------- CONG
+ // (= (= t3 t4) (= t1 t2)) (= (= t1 t2) false)
+ // --------------------------------------------------------------------- TR
+ // (= (= t3 t4) false)
+ //
+ // where note that the SYMM steps are implicitly added by CDProof.
+ Node congConclusion = nm->mkNode(
+ kind::EQUAL,
+ nm->mkNode(kind::EQUAL, substPremises[0][0], substPremises[1][0]),
+ premises[offending][0]);
+ p->addStep(congConclusion,
+ PfRule::CONG,
+ substPremises,
+ {ProofRuleChecker::mkKindNode(kind::EQUAL)},
+ true);
+ Trace("eqproof-conv") << "EqProof::expandTransitivityForDisequalities: via "
+ "congruence derived "
+ << congConclusion << "\n";
+ // transitivity step between that and the original premise
+ premises.insert(premises.begin(), congConclusion);
+ Node transConclusion =
+ !substConclusionInReverseOrder
+ ? conclusion
+ : nm->mkNode(kind::EQUAL, congConclusion[0], conclusion[1]);
+ // check to avoid cyclic proofs
+ if (!assumptions.count(transConclusion))
+ {
+ p->addStep(transConclusion, PfRule::TRANS, premises, {}, true);
+ Trace("eqproof-conv") << "EqProof::expandTransitivityForDisequalities: "
+ "via transitivity derived "
+ << transConclusion << "\n";
+ }
+ // if order is reversed, finish the proof of conclusion with
+ // (= (= t3 t4) false)
+ // --------------------- MACRO_SR_PRED_TRANSFORM
+ // (= (= t4 t3) false)
+ if (substConclusionInReverseOrder)
+ {
+ p->addStep(conclusion,
+ PfRule::MACRO_SR_PRED_TRANSFORM,
+ {transConclusion},
+ {conclusion},
+ true);
+ Trace("eqproof-conv") << "EqProof::expandTransitivityForDisequalities: "
+ "via macro transform derived "
+ << conclusion << "\n";
+ }
+ }
+ else
+ {
+ // create TRUE_INTRO step for expansionConclusion and add it to the premises
+ Trace("eqproof-conv")
+ << " via transitivity.\nEqProof::expandTransitivityForDisequalities: "
+ "adding "
+ << PfRule::TRUE_INTRO << " step for " << expansionConclusion[0] << "\n";
+ Node newExpansionConclusion =
+ expansionConclusion.eqNode(nm->mkConst<bool>(true));
+ p->addStep(
+ newExpansionConclusion, PfRule::TRUE_INTRO, {expansionConclusion}, {});
+ premises.push_back(newExpansionConclusion);
+ Trace("eqproof-conv") << PfRule::TRANS << " from " << premises << "\n";
+ buildTransitivityChain(conclusion, premises);
+ // create final transitivity step
+ p->addStep(conclusion, PfRule::TRANS, premises, {}, true);
+ }
+ return true;
+}
+
+// TEMPORARY NOTE: This may not be enough. Worst case scenario I need to
+// reproduce here a search for arbitrary chains between each of the variables in
+// the conclusion and a constant
+bool EqProof::expandTransitivityForTheoryDisequalities(
+ Node conclusion, std::vector<Node>& premises, CDProof* p) const
+{
+ // whether conclusion is a disequality (= (= t1 t2) false), modulo symmetry
+ unsigned termPos = -1;
+ for (unsigned i = 0; i < 2; ++i)
+ {
+ if (conclusion[i].getKind() == kind::CONST_BOOLEAN
+ && !conclusion[i].getConst<bool>()
+ && conclusion[1 - i].getKind() == kind::EQUAL)
+ {
+ termPos = i - 1;
+ break;
+ }
+ }
+ // no disequality
+ if (termPos == static_cast<unsigned>(-1))
+ {
+ return false;
+ }
+ Trace("eqproof-conv")
+ << "EqProof::expandTransitivityForTheoryDisequalities: check if need "
+ "to expand transitivity step to conclude disequality "
+ << conclusion << " from premises " << premises << "\n";
+
+ // Check if the premises are (= t1 c1) and (= t2 c2), modulo symmetry
+ std::vector<Node> subChildren, constChildren;
+ for (unsigned i = 0; i < 2; ++i)
+ {
+ Node term = conclusion[termPos][i];
+ for (const Node& premise : premises)
+ {
+ for (unsigned j = 0; j < 2; ++j)
+ {
+ if (premise[j] == term && premise[1 - j].isConst())
+ {
+ subChildren.push_back(premise[j].eqNode(premise[1 - j]));
+ constChildren.push_back(premise[1 - j]);
+ break;
+ }
+ }
+ }
+ }
+ if (subChildren.size() < 2)
+ {
+ return false;
+ }
+ // Now build
+ // (= t1 c1) (= t2 c2)
+ // ------------------------- CONG ------------------- MACRO_SR_PRED_INTRO
+ // (= (= t1 t2) (= c1 c2)) (= (= c1 c2) false)
+ // --------------------------------------------------------------------- TR
+ // (= (= t1 t2) false)
+ Node constApp = NodeManager::currentNM()->mkNode(kind::EQUAL, constChildren);
+ Node constEquality = constApp.eqNode(conclusion[1 - termPos]);
+ Trace("eqproof-conv")
+ << "EqProof::expandTransitivityForTheoryDisequalities: adding "
+ << PfRule::MACRO_SR_PRED_INTRO << " step for " << constApp << " = "
+ << conclusion[1 - termPos] << "\n";
+ p->addStep(constEquality, PfRule::MACRO_SR_PRED_INTRO, {}, {constEquality});
+ // build congruence conclusion (= (= t1 t2) (t c1 c2))
+ Node congConclusion = conclusion[termPos].eqNode(constApp);
+ Trace("eqproof-conv")
+ << "EqProof::expandTransitivityForTheoryDisequalities: adding "
+ << PfRule::CONG << " step for " << congConclusion << " from "
+ << subChildren << "\n";
+ p->addStep(congConclusion,
+ PfRule::CONG,
+ {subChildren},
+ {ProofRuleChecker::mkKindNode(kind::EQUAL)},
+ true);
+ Trace("eqproof-conv") << "EqProof::expandTransitivityForDisequalities: via "
+ "congruence derived "
+ << congConclusion << "\n";
+ std::vector<Node> transitivityChildren{congConclusion, constEquality};
+ p->addStep(conclusion, PfRule::TRANS, {transitivityChildren}, {});
+ return true;
}
bool EqProof::buildTransitivityChain(Node conclusion,
std::vector<Node>& premises) const
{
+ Trace("eqproof-conv") << push
+ << "EqProof::buildTransitivityChain: Build chain for "
+ << conclusion << " with premises " << premises << "\n";
+ for (unsigned i = 0, size = premises.size(); i < size; ++i)
+ {
+ bool occurs = false, correctlyOrdered = false;
+ if (conclusion[0] == premises[i][0])
+ {
+ occurs = correctlyOrdered = true;
+ }
+ else if (conclusion[0] == premises[i][1])
+ {
+ occurs = true;
+ }
+ if (occurs)
+ {
+ Trace("eqproof-conv")
+ << "EqProof::buildTransitivityChain: found " << conclusion[0] << " in"
+ << (correctlyOrdered ? "" : " non-") << " ordered premise "
+ << premises[i] << "\n";
+ if (conclusion[1] == premises[i][correctlyOrdered ? 1 : 0])
+ {
+ Trace("eqproof-conv")
+ << "EqProof::buildTransitivityChain: found " << conclusion[1]
+ << " in same premise. Closed chain.\n"
+ << pop;
+ premises.clear();
+ premises.push_back(conclusion);
+ return true;
+ }
+ // Build chain with remaining equalities
+ std::vector<Node> recursivePremises;
+ for (unsigned j = 0; j < size; ++j)
+ {
+ if (j != i)
+ {
+ recursivePremises.push_back(premises[j]);
+ }
+ }
+ Node newTarget =
+ premises[i][correctlyOrdered ? 1 : 0].eqNode(conclusion[1]);
+ Trace("eqproof-conv")
+ << "EqProof::buildTransitivityChain: search recursively for "
+ << newTarget << "\n";
+ if (buildTransitivityChain(newTarget, recursivePremises))
+ {
+ Trace("eqproof-conv")
+ << "EqProof::buildTransitivityChain: closed chain with "
+ << 1 + recursivePremises.size() << " of the original "
+ << premises.size() << " premises\n"
+ << pop;
+ premises.clear();
+ premises.insert(premises.begin(),
+ correctlyOrdered
+ ? premises[i]
+ : premises[i][1].eqNode(premises[i][0]));
+ premises.insert(
+ premises.end(), recursivePremises.begin(), recursivePremises.end());
+ return true;
+ }
+ }
+ }
+ Trace("eqproof-conv")
+ << "EqProof::buildTransitivityChain: Could not build chain for"
+ << conclusion << " with premises " << premises << "\n";
+ Trace("eqproof-conv") << pop;
return false;
}
@@ -112,16 +686,752 @@ void EqProof::reduceNestedCongruence(
std::unordered_set<Node, NodeHashFunction>& assumptions,
bool isNary) const
{
+ Trace("eqproof-conv") << "EqProof::reduceNestedCongruence: building for " << i
+ << "-th arg\n";
+ if (d_id == MERGED_THROUGH_CONGRUENCE)
+ {
+ Assert(d_children.size() == 2);
+ Trace("eqproof-conv") << "EqProof::reduceNestedCongruence: it's a "
+ "congruence step. Reduce second child\n"
+ << push;
+ transitivityMatrix[i].push_back(
+ d_children[1]->addToProof(p, visited, assumptions));
+ Trace("eqproof-conv")
+ << pop << "EqProof::reduceNestedCongruence: child conclusion "
+ << transitivityMatrix[i].back() << "\n";
+ // if i == 0, first child must be REFL step, standing for (= f f), which can
+ // be ignored in a first-order calculus
+ Assert(i > 0 || d_children[0]->d_id == MERGED_THROUGH_REFLEXIVITY
+ || options::ufHo());
+ // recurse
+ if (i > 1)
+ {
+ Trace("eqproof-conv")
+ << "EqProof::reduceNestedCongruence: Reduce first child\n"
+ << push;
+ d_children[0]->reduceNestedCongruence(i - 1,
+ conclusion,
+ transitivityMatrix,
+ p,
+ visited,
+ assumptions,
+ isNary);
+ Trace("eqproof-conv") << pop;
+ }
+ // higher-order case
+ else if (d_children[0]->d_id != MERGED_THROUGH_REFLEXIVITY)
+ {
+ Trace("eqproof-conv") << "EqProof::reduceNestedCongruence: HO case. "
+ "Processing first child\n";
+ // we only handle these cases
+ Assert(d_children[0]->d_id == MERGED_THROUGH_EQUALITY
+ || d_children[0]->d_id == MERGED_THROUGH_TRANS);
+ transitivityMatrix[0].push_back(
+ d_children[0]->addToProof(p, visited, assumptions));
+ }
+ return;
+ }
+ Assert(d_id == MERGED_THROUGH_TRANS)
+ << "id is " << static_cast<MergeReasonType>(d_id) << "\n";
+ Trace("eqproof-conv") << "EqProof::reduceNestedCongruence: it's a "
+ "transitivity step.\n";
+ Assert(d_node.isNull()
+ || d_node[0].getNumChildren() == d_node[1].getNumChildren() || isNary)
+ << "Non-null (internal cong) transitivity conclusion of different arity "
+ "but not marked by isNary flag\n";
+ // If handling n-ary kinds and got a transitivity conclusion, we process it
+ // with addToProof, store the result into row i, and stop. This marks an
+ // "adjustment" of the arity, with empty rows 0..i-1 in the matrix determining
+ // the adjustment in addToProof processing the congruence of the original
+ // conclusion. See details there.
+ if (isNary && !d_node.isNull())
+ {
+ Trace("eqproof-conv") << "EqProof::reduceNestedCongruence: n-ary case, "
+ "break recursion and indepedently process "
+ << d_node << "\n"
+ << push;
+ transitivityMatrix[i].push_back(addToProof(p, visited, assumptions));
+ Trace("eqproof-conv") << pop
+ << "EqProof::reduceNestedCongruence: Got conclusion "
+ << transitivityMatrix[i].back()
+ << " from n-ary transitivity processing\n";
+ return;
+ }
+ // Regular recursive processing of each transitivity premise
+ for (unsigned j = 0, sizeTrans = d_children.size(); j < sizeTrans; ++j)
+ {
+ if (d_children[j]->d_id == MERGED_THROUGH_CONGRUENCE)
+ {
+ Trace("eqproof-conv") << "EqProof::reduceNestedCongruence: Reduce " << j
+ << "-th transitivity congruence child\n"
+ << push;
+ d_children[j]->reduceNestedCongruence(
+ i, conclusion, transitivityMatrix, p, visited, assumptions, isNary);
+ Trace("eqproof-conv") << pop;
+ }
+ else
+ {
+ Trace("eqproof-conv") << "EqProof::reduceNestedCongruence: Add " << j
+ << "-th transitivity child to proof\n"
+ << push;
+ transitivityMatrix[i].push_back(
+ d_children[j]->addToProof(p, visited, assumptions));
+ Trace("eqproof-conv") << pop;
+ }
+ }
}
-Node EqProof::addToProof(CDProof* p) const { return Node::null(); }
+Node EqProof::addToProof(CDProof* p) const
+{
+ std::unordered_map<Node, Node, NodeHashFunction> cache;
+ std::unordered_set<Node, NodeHashFunction> assumptions;
+ Node conclusion = addToProof(p, cache, assumptions);
+ Trace("eqproof-conv") << "EqProof::addToProof: root of proof: " << conclusion
+ << "\n";
+ Trace("eqproof-conv") << "EqProof::addToProof: tracked assumptions: "
+ << assumptions << "\n";
+ // If conclusion t1 = tn is, modulo symmetry, of the form (= t true/false), in
+ // which t is not true/false, it must be turned into t or (not t) with
+ // TRUE/FALSE_ELIM.
+ Node newConclusion = conclusion;
+ Assert(conclusion.getKind() == kind::EQUAL);
+ if ((conclusion[0].getKind() == kind::CONST_BOOLEAN)
+ != (conclusion[1].getKind() == kind::CONST_BOOLEAN))
+ {
+ Trace("eqproof-conv")
+ << "EqProof::addToProof: process root for TRUE/FALSE_ELIM\n";
+ // Index of constant in equality
+ unsigned constIndex =
+ conclusion[0].getKind() == kind::CONST_BOOLEAN ? 0 : 1;
+ // The premise for the elimination rule must have the constant as the second
+ // argument of the equality. If that's not the case, build it as such,
+ // relying on an implicit SYMM step to be added to the proof when justifying
+ // t / (not t).
+ Node elimPremise =
+ constIndex == 1 ? conclusion : conclusion[1].eqNode(conclusion[0]);
+ // Determine whether TRUE_ELIM or FALSE_ELIM, depending on the constant
+ // value. The new conclusion, whether t or (not t), is also determined
+ // accordingly.
+ PfRule elimRule;
+ if (conclusion[constIndex].getConst<bool>())
+ {
+ elimRule = PfRule::TRUE_ELIM;
+ newConclusion = conclusion[1 - constIndex];
+ }
+ else
+ {
+ elimRule = PfRule::FALSE_ELIM;
+ newConclusion = conclusion[1 - constIndex].notNode();
+ }
+ // We also check if the final conclusion t / (not t) has already been
+ // justified, so that we can avoid a cyclic proof, which can be due to
+ // either t / (not t) being assumption in the original EqProof or it having
+ // a non-assumption proof step in the proof of (= t true/false).
+ if (!assumptions.count(newConclusion) && !p->hasStep(newConclusion))
+ {
+ Trace("eqproof-conv")
+ << "EqProof::addToProof: conclude " << newConclusion << " via "
+ << elimRule << " step for " << elimPremise << "\n";
+ p->addStep(newConclusion, elimRule, {elimPremise}, {});
+ }
+ }
+ return newConclusion;
+}
Node EqProof::addToProof(
CDProof* p,
std::unordered_map<Node, Node, NodeHashFunction>& visited,
std::unordered_set<Node, NodeHashFunction>& assumptions) const
{
- return Node::null();
+ std::unordered_map<Node, Node, NodeHashFunction>::const_iterator it =
+ visited.find(d_node);
+ if (it != visited.end())
+ {
+ Trace("eqproof-conv") << "EqProof::addToProof: already processed " << d_node
+ << ", returning " << it->second << "\n";
+ return it->second;
+ }
+ Trace("eqproof-conv") << "EqProof::addToProof: adding step for " << d_id
+ << " with conclusion " << d_node << "\n";
+ // Assumption
+ if (d_id == MERGED_THROUGH_EQUALITY)
+ {
+ // Check that no (= true/false true/false) assumptions
+ if (Configuration::isDebugBuild() && d_node.getKind() == kind::EQUAL)
+ {
+ for (unsigned i = 0; i < 2; ++i)
+ {
+ Assert(d_node[i].getKind() != kind::CONST_BOOLEAN
+ || d_node[1 - i].getKind() != kind::CONST_BOOLEAN)
+ << "EqProof::addToProof: fully boolean constant assumption "
+ << d_node << " is disallowed\n";
+ }
+ }
+ // If conclusion is (= t true/false), we add a proof step
+ // t
+ // ---------------- TRUE/FALSE_INTRO
+ // (= t true/false)
+ // according to the value of the Boolean constant
+ if (d_node.getKind() == kind::EQUAL
+ && ((d_node[0].getKind() == kind::CONST_BOOLEAN)
+ != (d_node[1].getKind() == kind::CONST_BOOLEAN)))
+ {
+ Trace("eqproof-conv")
+ << "EqProof::addToProof: add an intro step for " << d_node << "\n";
+ // Index of constant in equality
+ unsigned constIndex = d_node[0].getKind() == kind::CONST_BOOLEAN ? 0 : 1;
+ // The premise for the intro rule is either t or (not t), according to the
+ // Boolean constant.
+ Node introPremise;
+ PfRule introRule;
+ if (d_node[constIndex].getConst<bool>())
+ {
+ introRule = PfRule::TRUE_INTRO;
+ introPremise = d_node[1 - constIndex];
+ // Track the new assumption. If it's an equality, also its symmetric
+ assumptions.insert(introPremise);
+ if (introPremise.getKind() == kind::EQUAL)
+ {
+ assumptions.insert(introPremise[1].eqNode(introPremise[0]));
+ }
+ }
+ else
+ {
+ introRule = PfRule::FALSE_INTRO;
+ introPremise = d_node[1 - constIndex].notNode();
+ // Track the new assumption. If it's a disequality, also its symmetric
+ assumptions.insert(introPremise);
+ if (introPremise[0].getKind() == kind::EQUAL)
+ {
+ assumptions.insert(
+ introPremise[0][1].eqNode(introPremise[0][0]).notNode());
+ }
+ }
+ // The original assumption can be e.g. (= false (= t1 t2)) in which case
+ // the necessary proof to be built is
+ // (not (= t1 t2))
+ // -------------------- FALSE_INTRO
+ // (= (= t1 t2) false)
+ // -------------------- SYMM
+ // (= false (= t1 t2))
+ //
+ // with the SYMM step happening automatically whenever the assumption is
+ // used in the proof p
+ Node introConclusion =
+ constIndex == 1 ? d_node : d_node[1].eqNode(d_node[0]);
+ p->addStep(introConclusion, introRule, {introPremise}, {});
+ }
+ else
+ {
+ p->addStep(d_node, PfRule::ASSUME, {}, {d_node});
+ }
+ // If non-equality predicate, turn into one via TRUE/FALSE intro
+ Node conclusion = d_node;
+ if (d_node.getKind() != kind::EQUAL)
+ {
+ // Track original assumption
+ assumptions.insert(d_node);
+ PfRule intro;
+ if (d_node.getKind() == kind::NOT)
+ {
+ intro = PfRule::FALSE_INTRO;
+ conclusion =
+ d_node[0].eqNode(NodeManager::currentNM()->mkConst<bool>(false));
+ }
+ else
+ {
+ intro = PfRule::TRUE_INTRO;
+ conclusion =
+ d_node.eqNode(NodeManager::currentNM()->mkConst<bool>(true));
+ }
+ Trace("eqproof-conv") << "EqProof::addToProof: adding " << intro
+ << " step for " << d_node << "\n";
+ p->addStep(conclusion, intro, {d_node}, {});
+ }
+ // Keep track of assumptions to avoid cyclic proofs. Both the assumption and
+ // its symmetric are added
+ assumptions.insert(conclusion);
+ assumptions.insert(conclusion[1].eqNode(conclusion[0]));
+ Trace("eqproof-conv") << "EqProof::addToProof: tracking assumptions "
+ << conclusion << ", (= " << conclusion[1] << " "
+ << conclusion[0] << ")\n";
+ visited[d_node] = conclusion;
+ return conclusion;
+ }
+ // Refl and laborious congruence steps for (= (f t1 ... tn) (f t1 ... tn)),
+ // which can be safely turned into reflexivity steps. These laborious
+ // congruence steps are currently generated in the equality engine because of
+ // the suboptimal handling of n-ary operators.
+ if (d_id == MERGED_THROUGH_REFLEXIVITY
+ || (d_node.getKind() == kind::EQUAL && d_node[0] == d_node[1]))
+ {
+ Node conclusion =
+ d_node.getKind() == kind::EQUAL ? d_node : d_node.eqNode(d_node);
+ p->addStep(conclusion, PfRule::REFL, {}, {conclusion[0]});
+ visited[d_node] = conclusion;
+ return conclusion;
+ }
+ // Equalities due to theory reasoning
+ if (d_id == MERGED_THROUGH_CONSTANTS)
+ {
+ Assert(!d_node.isNull() && d_node.getKind() == kind::EQUAL
+ && d_node[1].isConst())
+ << ". Conclusion " << d_node << " from " << d_id
+ << " was expected to be (= (f t1 ... tn) c)\n";
+ Assert(!assumptions.count(d_node))
+ << "Conclusion " << d_node << " from " << d_id << " is an assumption\n";
+ // The step has the form
+ // [(= t1 c1)] ... [(= tn cn)]
+ // ------------------------
+ // (= (f t1 ... tn) c)
+ // where premises equating ti to constants are present when they are not
+ // already constants. Note that the premises may be in any order, e.g. with
+ // the equality for the second term being justified in the first premise.
+ // Moreover, they may be of the form (= ci ti).
+ //
+ // First recursively process premises, if any
+ std::vector<Node> premises;
+ for (unsigned i = 0; i < d_children.size(); ++i)
+ {
+ Trace("eqproof-conv")
+ << "EqProof::addToProof: recurse on child " << i << "\n"
+ << push;
+ premises.push_back(d_children[i]->addToProof(p, visited, assumptions));
+ Trace("eqproof-conv") << pop;
+ }
+ // After building the proper premises we could build a step like
+ // [(= t1 c1)] ... [(= tn cn)]
+ // ---------------------------- MACRO_SR_PRED_INTRO
+ // (= (f t1 ... tn) c)
+ // but note that since the substitution applied by MACRO_SR_PRED_INTRO is
+ // *not* simultenous this could lead to issues if t_{i+1} occurred in some
+ // t_{i}. So we build proofs as
+ //
+ // [(= t1 c1)] ... [(= tn cn)]
+ // ------------------------------- CONG -------------- MACRO_SR_PRED_INTRO
+ // (= (f t1 ... tn) (f c1 ... cn)) (= (f c1 ... cn) c)
+ // ---------------------------------------------------------- TRANS
+ // (= (f t1 ... tn) c)
+ std::vector<Node> subChildren, constChildren;
+ for (unsigned i = 0, size = d_node[0].getNumChildren(); i < size; ++i)
+ {
+ Node term = d_node[0][i];
+ // term already is a constant, add a REFL step
+ if (term.isConst())
+ {
+ subChildren.push_back(term.eqNode(term));
+ p->addStep(subChildren.back(), PfRule::REFL, {}, {term});
+ constChildren.push_back(term);
+ continue;
+ }
+ // Build the equality (= ti ci) as a premise, finding the respective ci is
+ // the original premises
+ Node constant;
+ for (const Node& premise : premises)
+ {
+ Assert(premise.getKind() == kind::EQUAL);
+ if (premise[0] == term)
+ {
+ Assert(premise[1].isConst());
+ constant = premise[1];
+ break;
+ }
+ if (premise[1] == term)
+ {
+ Assert(premise[0].isConst());
+ constant = premise[0];
+ break;
+ }
+ }
+ Assert(!constant.isNull());
+ subChildren.push_back(term.eqNode(constant));
+ constChildren.push_back(constant);
+ }
+ // build constant application (f c1 ... cn) and equality (= (f c1 ... cn) c)
+ Kind k = d_node[0].getKind();
+ Node constApp = NodeManager::currentNM()->mkNode(k, constChildren);
+ Node constEquality = constApp.eqNode(d_node[1]);
+ Trace("eqproof-conv") << "EqProof::addToProof: adding "
+ << PfRule::MACRO_SR_PRED_INTRO << " step for "
+ << constApp << " = " << d_node[1] << "\n";
+ p->addStep(constEquality, PfRule::MACRO_SR_PRED_INTRO, {}, {constEquality});
+ // build congruence conclusion (= (f t1 ... tn) (f c1 ... cn))
+ Node congConclusion = d_node[0].eqNode(constApp);
+ Trace("eqproof-conv") << "EqProof::addToProof: adding " << PfRule::CONG
+ << " step for " << congConclusion << " from "
+ << subChildren << "\n";
+ p->addStep(congConclusion,
+ PfRule::CONG,
+ {subChildren},
+ {ProofRuleChecker::mkKindNode(k)},
+ true);
+ Trace("eqproof-conv") << "EqProof::addToProof: adding " << PfRule::TRANS
+ << " step for original conclusion " << d_node << "\n";
+ std::vector<Node> transitivityChildren{congConclusion, constEquality};
+ p->addStep(d_node, PfRule::TRANS, {transitivityChildren}, {});
+ visited[d_node] = d_node;
+ return d_node;
+ }
+ // Transtivity and disequality reasoning steps
+ if (d_id == MERGED_THROUGH_TRANS)
+ {
+ Assert(d_node.getKind() == kind::EQUAL
+ || (d_node.getKind() == kind::NOT
+ && d_node[0].getKind() == kind::EQUAL))
+ << "EqProof::addToProof: transitivity step conclusion " << d_node
+ << " is not equality or negated equality\n";
+ // If conclusion is (not (= t1 t2)) change it to (= (= t1 t2) false), which
+ // is the correct conclusion of the equality reasoning step. A FALSE_ELIM
+ // step to revert this is only necessary when this is the root. That step is
+ // done in the non-recursive caller of this function.
+ Node conclusion =
+ d_node.getKind() != kind::NOT
+ ? d_node
+ : d_node[0].eqNode(NodeManager::currentNM()->mkConst<bool>(false));
+ // If the conclusion is an assumption, its derivation was spurious, so it
+ // can be discarded. Moreover, reconstructing the step may lead to cyclic
+ // proofs, so we *must* cut here.
+ if (assumptions.count(conclusion))
+ {
+ visited[d_node] = conclusion;
+ return conclusion;
+ }
+ // Process premises recursively
+ std::vector<Node> children;
+ for (unsigned i = 0, size = d_children.size(); i < size; ++i)
+ {
+ // If one of the steps is a "fake congruence" one, marked by a null
+ // conclusion, it must deleted. Its premises are moved down to premises of
+ // the transitivity step.
+ EqProof* childProof = d_children[i].get();
+ if (childProof->d_id == MERGED_THROUGH_CONGRUENCE
+ && childProof->d_node.isNull())
+ {
+ Trace("eqproof-conv") << "EqProof::addToProof: child proof " << i
+ << " is fake cong step. Fold it.\n";
+ Assert(childProof->d_children.size() == 2);
+ Trace("eqproof-conv") << push;
+ for (unsigned j = 0, sizeJ = childProof->d_children.size(); j < sizeJ;
+ ++j)
+ {
+ Trace("eqproof-conv")
+ << "EqProof::addToProof: recurse on child " << j << "\n"
+ << push;
+ children.push_back(
+ childProof->d_children[j]->addToProof(p, visited, assumptions));
+ Trace("eqproof-conv") << pop;
+ }
+ Trace("eqproof-conv") << pop;
+ continue;
+ }
+ Trace("eqproof-conv")
+ << "EqProof::addToProof: recurse on child " << i << "\n"
+ << push;
+ children.push_back(childProof->addToProof(p, visited, assumptions));
+ Trace("eqproof-conv") << pop;
+ }
+ // Eliminate spurious premises. Reasoning below assumes no refl steps.
+ cleanReflPremises(children);
+ // If any premise is of the form (= (t1 t2) false), then the transitivity
+ // step may be coarse-grained and needs to be expanded. If the expansion
+ // happens it also finalizes the proof of conclusion.
+ if (!expandTransitivityForDisequalities(
+ conclusion, children, p, assumptions))
+ {
+ Assert(!children.empty());
+ // similarly, if a disequality is concluded because of theory reasoning,
+ // the step is coarse-grained and needs to be expanded, in which case the
+ // proof is finalized in the call
+ if (!expandTransitivityForTheoryDisequalities(conclusion, children, p))
+ {
+ Trace("eqproof-conv")
+ << "EqProof::addToProof: build chain for transitivity premises"
+ << children << " to conclude " << conclusion << "\n";
+ // Build ordered transitivity chain from children to derive the
+ // conclusion
+ buildTransitivityChain(conclusion, children);
+ Assert(
+ children.size() > 1
+ || (!children.empty()
+ && (children[0] == conclusion
+ || children[0][1].eqNode(children[0][0]) == conclusion)));
+ // Only add transitivity step if there is more than one premise in the
+ // chain. Otherwise the premise will be the conclusion itself and it'll
+ // already have had a step added to it when the premises were
+ // recursively processed.
+ if (children.size() > 1)
+ {
+ p->addStep(conclusion, PfRule::TRANS, children, {}, true);
+ }
+ }
+ }
+ Assert(p->hasStep(conclusion));
+ visited[d_node] = conclusion;
+ return conclusion;
+ }
+ Assert(d_id == MERGED_THROUGH_CONGRUENCE);
+ // The processing below is mainly dedicated to flattening congruence steps
+ // (since EqProof assumes currying) and to prossibly reconstructing the
+ // conclusion in case it involves n-ary steps.
+ Assert(d_node.getKind() == kind::EQUAL)
+ << "EqProof::addToProof: conclusion " << d_node << " is not equality\n";
+ // The given conclusion is taken as ground truth. If the premises do not
+ // align, for example with (= (f t1) (f t2)) but a premise being (= t2 t1), we
+ // use (= t1 t2) as a premise and rely on a symmetry step to justify it.
+ unsigned arity = d_node[0].getNumChildren();
+ Kind k = d_node[0].getKind();
+ bool isNary = ExprManager::isNAryKind(k);
+
+ // N-ary operators are fun. The following proof is a valid EqProof
+ //
+ // (= (f t1 t2 t3) (f t6 t5)) (= (f t6 t5) (f t5 t6))
+ // -------------------------------------------------- TRANS
+ // (= (f t1 t2 t3) (f t5 t6)) (= t4 t7)
+ // ------------------------------------------------------------ CONG
+ // (= (f t1 t2 t3 t4) (f t5 t6 t7))
+ //
+ // We modify the above proof to conclude
+ //
+ // (= (f (f t1 t2 t3) t4) (f (f t5 t6) t7))
+ //
+ // which is a valid congruence conclusion (applications of f with the same
+ // arity). For the processing below to be// performed correctly we update
+ // arity to be maximal one among the two applications (4 in the above
+ // example).
+ if (d_node[0].getNumChildren() != d_node[1].getNumChildren())
+ {
+ Assert(isNary) << "We only handle congruences of apps with different "
+ "number of children for theory n-ary operators";
+ arity =
+ d_node[1].getNumChildren() < arity ? arity : d_node[1].getNumChildren();
+ Trace("eqproof-conv")
+ << "EqProof::addToProof: Mismatching arities in cong conclusion "
+ << d_node << ". Use tentative arity " << arity << "\n";
+ }
+ // For a congruence proof of (= (f a0 ... an-1) (g b0 ... bn-1)), build a
+ // transitivity matrix of n rows where the first row contains a transitivity
+ // chain justifying (= f g) and the next rows (= ai bi)
+ std::vector<std::vector<Node>> transitivityChildren;
+ for (unsigned i = 0; i < arity + 1; ++i)
+ {
+ transitivityChildren.push_back(std::vector<Node>());
+ }
+ reduceNestedCongruence(
+ arity, d_node, transitivityChildren, p, visited, assumptions, isNary);
+ // Congruences over n-ary operators may require changing the conclusion (as in
+ // the above example). This is handled in a general manner below according to
+ // whether the transitivity matrix computed by reduceNestedCongruence contains
+ // empty rows
+ Node conclusion = d_node;
+ NodeManager* nm = NodeManager::currentNM();
+ if (isNary)
+ {
+ unsigned emptyRows = 0;
+ for (unsigned i = 1; i <= arity; ++i)
+ {
+ if (transitivityChildren[i].empty())
+ {
+ emptyRows++;
+ }
+ }
+ // Given two n-ary applications f1:(f a0 ... an-1), f2:(f b0 ... bm-1), of
+ // arities n and m, arity = max(n,m), the number emptyRows establishes the
+ // sizes of the prefixes of f1 of f2 that have been equated via a
+ // transitivity step. The prefixes necessarily have different sizes. The
+ // suffixes have the same sizes. The new conclusion will be of the form
+ // (= (f (f a0 ... ak1) ... an-1) (f (f b0 ... bk2) ... bm-1))
+ // where
+ // k1 = emptyRows + 1 - (arity - n)
+ // k2 = emptyRows + 1 - (arity - m)
+ // k1 != k2
+ // n - k1 == m - k2
+ // Note that by construction the equality between the first emptyRows + 1
+ // arguments of each application is justified by the transitivity step in
+ // the row emptyRows + 1 in the matrix.
+ //
+ // All of the above is with the very first row in the matrix, reserved for
+ // justifying the equality between the functions, which is not necessary in
+ // the n-ary case, notwithstanding.
+ if (emptyRows > 0)
+ {
+ Trace("eqproof-conv")
+ << "EqProof::addToProof: Found " << emptyRows
+ << " empty rows. Rebuild conclusion " << d_node << "\n";
+ // New transitivity matrix is as before except that the empty rows in the
+ // beginning are eliminated, as the new arity is the maximal arity among
+ // the applications minus the number of empty rows.
+ std::vector<std::vector<Node>> newTransitivityChildren{
+ transitivityChildren.begin() + 1 + emptyRows,
+ transitivityChildren.end()};
+ transitivityChildren.clear();
+ transitivityChildren.push_back(std::vector<Node>());
+ transitivityChildren.insert(transitivityChildren.end(),
+ newTransitivityChildren.begin(),
+ newTransitivityChildren.end());
+ unsigned arityPrefix1 =
+ emptyRows + 1 - (arity - d_node[0].getNumChildren());
+ Assert(arityPrefix1 < d_node[0].getNumChildren())
+ << "arityPrefix1 " << arityPrefix1 << " not smaller than "
+ << d_node[0] << "'s arity " << d_node[0].getNumChildren() << "\n";
+ unsigned arityPrefix2 =
+ emptyRows + 1 - (arity - d_node[1].getNumChildren());
+ Assert(arityPrefix2 < d_node[1].getNumChildren())
+ << "arityPrefix2 " << arityPrefix2 << " not smaller than "
+ << d_node[1] << "'s arity " << d_node[1].getNumChildren() << "\n";
+ Trace("eqproof-conv") << "EqProof::addToProof: New internal "
+ "applications with arities "
+ << arityPrefix1 << ", " << arityPrefix2 << ":\n";
+ std::vector<Node> childrenPrefix1{d_node[0].begin(),
+ d_node[0].begin() + arityPrefix1};
+ std::vector<Node> childrenPrefix2{d_node[1].begin(),
+ d_node[1].begin() + arityPrefix2};
+ Node newFirstChild1 = nm->mkNode(k, childrenPrefix1);
+ Node newFirstChild2 = nm->mkNode(k, childrenPrefix2);
+ Trace("eqproof-conv")
+ << "EqProof::addToProof:\t " << newFirstChild1 << "\n";
+ Trace("eqproof-conv")
+ << "EqProof::addToProof:\t " << newFirstChild2 << "\n";
+ std::vector<Node> newChildren1{newFirstChild1};
+ newChildren1.insert(newChildren1.end(),
+ d_node[0].begin() + arityPrefix1,
+ d_node[0].end());
+ std::vector<Node> newChildren2{newFirstChild2};
+ newChildren2.insert(newChildren2.end(),
+ d_node[1].begin() + arityPrefix2,
+ d_node[1].end());
+ conclusion = nm->mkNode(kind::EQUAL,
+ nm->mkNode(k, newChildren1),
+ nm->mkNode(k, newChildren2));
+ // update arity
+ Assert((arity - emptyRows) == conclusion[0].getNumChildren());
+ arity = arity - emptyRows;
+ Trace("eqproof-conv")
+ << "EqProof::addToProof: New conclusion " << conclusion << "\n";
+ }
+ }
+ if (Trace.isOn("eqproof-conv"))
+ {
+ Trace("eqproof-conv")
+ << "EqProof::addToProof: premises from reduced cong of " << conclusion
+ << ":\n";
+ for (unsigned i = 0; i <= arity; ++i)
+ {
+ Trace("eqproof-conv") << "EqProof::addToProof:\t" << i
+ << "-th arg: " << transitivityChildren[i] << "\n";
+ }
+ }
+ std::vector<Node> children(arity + 1);
+ // Check if there is a justification for equality between functions (HO case)
+ if (!transitivityChildren[0].empty())
+ {
+ Assert(k == kind::APPLY_UF) << "Congruence with different functions only "
+ "allowed for uninterpreted functions.\n";
+
+ children[0] =
+ conclusion[0].getOperator().eqNode(conclusion[1].getOperator());
+ Assert(transitivityChildren[0].size() == 1
+ && CDProof::isSame(children[0], transitivityChildren[0][0]))
+ << "Justification of operators equality is wrong: "
+ << transitivityChildren[0] << "\n";
+ }
+ // Proccess transitivity matrix to (possibly) generate transitivity steps for
+ // congruence premises (= ai bi)
+ for (unsigned i = 1; i <= arity; ++i)
+ {
+ Node transConclusion = conclusion[0][i - 1].eqNode(conclusion[1][i - 1]);
+ children[i] = transConclusion;
+ Assert(!transitivityChildren[i].empty())
+ << "EqProof::addToProof: did not add any justification for " << i
+ << "-th arg of congruence " << conclusion << "\n";
+ // If the transitivity conclusion is a reflexivity step, just add it. Note
+ // that this can happen even with the respective transitivityChildren row
+ // containing several equalities in the case of (= ai bi) being the same
+ // n-ary application that was justified by a congruence step, which can
+ // happen in the current equality engine.
+ if (transConclusion[0] == transConclusion[1])
+ {
+ p->addStep(transConclusion, PfRule::REFL, {}, {transConclusion[0]});
+ continue;
+ }
+ // Remove spurious refl steps from the premises for (= ai bi)
+ cleanReflPremises(transitivityChildren[i]);
+ Assert(transitivityChildren[i].size() > 1 || transitivityChildren[i].empty()
+ || CDProof::isSame(transitivityChildren[i][0], transConclusion))
+ << "EqProof::addToProof: premises " << transitivityChildren[i] << "for "
+ << i << "-th cong premise " << transConclusion << " don't justify it\n";
+ unsigned sizeTrans = transitivityChildren[i].size();
+ // If no transitivity premise left or if (= ai bi) is an assumption (which
+ // might lead to a cycle with a transtivity step), nothing else to do.
+ if (sizeTrans == 0 || assumptions.count(transConclusion) > 0)
+ {
+ continue;
+ }
+ // If the transitivity conclusion, or its symmetric, occurs in the
+ // transitivity premises, nothing to do, as it is already justified and
+ // doing so again would lead to a cycle.
+ bool occurs = false;
+ for (unsigned j = 0; j < sizeTrans && !occurs; ++j)
+ {
+ if (CDProof::isSame(transitivityChildren[i][j], transConclusion))
+ {
+ occurs = true;
+ }
+ }
+ if (!occurs)
+ {
+ // Build transitivity step
+ buildTransitivityChain(transConclusion, transitivityChildren[i]);
+ Trace("eqproof-conv")
+ << "EqProof::addToProof: adding trans step for cong premise "
+ << transConclusion << " with children " << transitivityChildren[i]
+ << "\n";
+ p->addStep(
+ transConclusion, PfRule::TRANS, transitivityChildren[i], {}, true);
+ }
+ }
+ // first-order case
+ if (children[0].isNull())
+ {
+ // remove placehold for function equality case
+ children.erase(children.begin());
+ // Get node of the function operator over which congruence is being
+ // applied.
+ std::vector<Node> args;
+ args.push_back(ProofRuleChecker::mkKindNode(k));
+ if (kind::metaKindOf(k) == kind::metakind::PARAMETERIZED)
+ {
+ args.push_back(conclusion[0].getOperator());
+ }
+ // Add congruence step
+ Trace("eqproof-conv") << "EqProof::addToProof: build cong step of "
+ << conclusion << " with op " << args[0]
+ << " and children " << children << "\n";
+ p->addStep(conclusion, PfRule::CONG, children, args, true);
+ }
+ // higher-order case
+ else
+ {
+ // Add congruence step
+ Trace("eqproof-conv") << "EqProof::addToProof: build HO-cong step of "
+ << conclusion << " with children " << children
+ << "\n";
+ p->addStep(conclusion, PfRule::HO_CONG, children, {}, true);
+ }
+ // If the conclusion of the congruence step changed due to the n-ary handling,
+ // we obtained for example (= (f (f t1 t2 t3) t4) (f (f t5 t6) t7)), which is
+ // flattened into the original conclusion (= (f t1 t2 t3 t4) (f t5 t6 t7)) via
+ // rewriting
+ if (conclusion != d_node)
+ {
+ Trace("eqproof-conv") << "EqProof::addToProof: add "
+ << PfRule::MACRO_SR_PRED_TRANSFORM
+ << " step to flatten rebuilt conclusion "
+ << conclusion << "into " << d_node << "\n";
+ p->addStep(
+ d_node, PfRule::MACRO_SR_PRED_TRANSFORM, {conclusion}, {d_node}, true);
+ }
+ visited[d_node] = d_node;
+ return d_node;
}
} // namespace eq
diff --git a/src/theory/uf/eq_proof.h b/src/theory/uf/eq_proof.h
index c396da313..6fd737eb6 100644
--- a/src/theory/uf/eq_proof.h
+++ b/src/theory/uf/eq_proof.h
@@ -2,10 +2,10 @@
/*! \file eq_proof.h
** \verbatim
** Top contributors (to current version):
- ** Haniel Barbosa
+ ** Haniel Barbosa, Dejan Jovanovic, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -35,36 +35,21 @@ namespace eq {
class EqProof
{
public:
- /** A custom pretty printer used for custom rules being those in
- * MergeReasonType. */
- class PrettyPrinter
- {
- public:
- virtual ~PrettyPrinter() {}
- virtual std::string printTag(unsigned tag) = 0;
- };
-
EqProof() : d_id(MERGED_THROUGH_REFLEXIVITY) {}
/** The proof rule for concluding d_node */
- unsigned d_id;
+ MergeReasonType d_id;
/** The conclusion of this EqProof */
Node d_node;
/** The proofs of the premises for deriving d_node with d_id */
std::vector<std::shared_ptr<EqProof>> d_children;
/**
- * Debug print this proof on debug trace c with tabulation tb and pretty
- * printer prettyPrinter.
+ * Debug print this proof on debug trace c with tabulation tb.
*/
- void debug_print(const char* c,
- unsigned tb = 0,
- PrettyPrinter* prettyPrinter = nullptr) const;
+ void debug_print(const char* c, unsigned tb = 0) const;
/**
- * Debug print this proof on output stream os with tabulation tb and pretty
- * printer prettyPrinter.
+ * Debug print this proof on output stream os with tabulation tb.
*/
- void debug_print(std::ostream& os,
- unsigned tb = 0,
- PrettyPrinter* prettyPrinter = nullptr) const;
+ void debug_print(std::ostream& os, unsigned tb = 0) const;
/** Add to proof
*
@@ -116,7 +101,7 @@ class EqProof
* Currently the equality engine can represent disequality reasoning in a
* rather coarse-grained manner with EqProof. This is always the case when the
* transitivity step contains a disequality, (= (= t t') false) or its
- * symmetric.
+ * symmetric, as a premise.
*
* There are two cases. In the simplest one the general shape of the EqProof
* is
@@ -180,6 +165,9 @@ class EqProof
* EqProof. These are necessary to avoid cyclic proofs, which could be
* generated by creating transitivity steps for assumptions (which depend on
* themselves).
+ * @return True if the EqProof transitivity step is in either of the above
+ * cases, symbolizing that the ProofNode justifying the conclusion has already
+ * been produced.
*/
bool expandTransitivityForDisequalities(
Node conclusion,
@@ -187,6 +175,36 @@ class EqProof
CDProof* p,
std::unordered_set<Node, NodeHashFunction>& assumptions) const;
+ /** Expand coarse-grained transitivity steps for theory disequalities
+ *
+ * Currently the equality engine can represent disequality reasoning of theory
+ * symbols in a rather coarse-grained manner with EqProof. This is the case
+ * when EqProof is
+ * (= t1 c1) (= t2 c2)
+ * ------------------------------------- EQP::TR
+ * (= (t1 t2) false)
+ *
+ * which is converted into
+ *
+ * (= t1 c1) (= t2 c2)
+ * -------------------------- CONG --------------------- MACRO_SR_PRED_INTRO
+ * (= (= t1 t2) (= c1 t2)) (= (= c1 c2) false)
+ * --------------------------------------------------------- TR
+ * (= (= t1 t2) false)
+ *
+ * @param conclusion the conclusion of the (possibly) coarse-grained
+ * transitivity step
+ * @param premises the premises of the (possibly) coarse-grained
+ * transitivity step
+ * @param p a pointer to a CDProof to store the conversion of this EqProof
+ * @return True if the EqProof transitivity step is the above case,
+ * indicating that the ProofNode justifying the conclusion has already been
+ * produced.
+ */
+ bool expandTransitivityForTheoryDisequalities(Node conclusion,
+ std::vector<Node>& premises,
+ CDProof* p) const;
+
/** Builds a transitivity chain from equalities to derive a conclusion
*
* Given an equality (= t1 tn), and a list of equalities premises, attempts to
diff --git a/src/theory/uf/equality_engine.cpp b/src/theory/uf/equality_engine.cpp
index b532bcfa5..f04ebbb60 100644
--- a/src/theory/uf/equality_engine.cpp
+++ b/src/theory/uf/equality_engine.cpp
@@ -2,10 +2,10 @@
/*! \file equality_engine.cpp
** \verbatim
** Top contributors (to current version):
- ** Dejan Jovanovic, Andrew Reynolds, Guy Katz
+ ** Dejan Jovanovic, Andrew Reynolds, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -17,6 +17,8 @@
#include "theory/uf/equality_engine.h"
+#include "options/smt_options.h"
+#include "proof/proof_manager.h"
#include "smt/smt_statistics_registry.h"
namespace CVC4 {
@@ -101,61 +103,67 @@ void EqualityEngine::init() {
d_trueId = getNodeId(d_true);
d_falseId = getNodeId(d_false);
-
- d_freshMergeReasonType = eq::NUMBER_OF_MERGE_REASONS;
}
EqualityEngine::~EqualityEngine() {
free(d_triggerDatabase);
}
-
-EqualityEngine::EqualityEngine(context::Context* context, std::string name, bool constantsAreTriggers)
-: ContextNotifyObj(context)
-, d_masterEqualityEngine(0)
-, d_context(context)
-, d_done(context, false)
-, d_performNotify(true)
-, d_notify(s_notifyNone)
-, d_applicationLookupsCount(context, 0)
-, d_nodesCount(context, 0)
-, d_assertedEqualitiesCount(context, 0)
-, d_equalityTriggersCount(context, 0)
-, d_subtermEvaluatesSize(context, 0)
-, d_stats(name)
-, d_inPropagate(false)
-, d_constantsAreTriggers(constantsAreTriggers)
-, d_triggerDatabaseSize(context, 0)
-, d_triggerTermSetUpdatesSize(context, 0)
-, d_deducedDisequalitiesSize(context, 0)
-, d_deducedDisequalityReasonsSize(context, 0)
-, d_propagatedDisequalities(context)
-, d_name(name)
+EqualityEngine::EqualityEngine(context::Context* context,
+ std::string name,
+ bool constantsAreTriggers,
+ bool anyTermTriggers)
+ : ContextNotifyObj(context),
+ d_masterEqualityEngine(0),
+ d_context(context),
+ d_done(context, false),
+ d_performNotify(true),
+ d_notify(s_notifyNone),
+ d_applicationLookupsCount(context, 0),
+ d_nodesCount(context, 0),
+ d_assertedEqualitiesCount(context, 0),
+ d_equalityTriggersCount(context, 0),
+ d_subtermEvaluatesSize(context, 0),
+ d_stats(name),
+ d_inPropagate(false),
+ d_constantsAreTriggers(constantsAreTriggers),
+ d_anyTermsAreTriggers(anyTermTriggers),
+ d_triggerDatabaseSize(context, 0),
+ d_triggerTermSetUpdatesSize(context, 0),
+ d_deducedDisequalitiesSize(context, 0),
+ d_deducedDisequalityReasonsSize(context, 0),
+ d_propagatedDisequalities(context),
+ d_name(name)
{
init();
}
-EqualityEngine::EqualityEngine(EqualityEngineNotify& notify, context::Context* context, std::string name, bool constantsAreTriggers)
-: ContextNotifyObj(context)
-, d_masterEqualityEngine(0)
-, d_context(context)
-, d_done(context, false)
-, d_performNotify(true)
-, d_notify(notify)
-, d_applicationLookupsCount(context, 0)
-, d_nodesCount(context, 0)
-, d_assertedEqualitiesCount(context, 0)
-, d_equalityTriggersCount(context, 0)
-, d_subtermEvaluatesSize(context, 0)
-, d_stats(name)
-, d_inPropagate(false)
-, d_constantsAreTriggers(constantsAreTriggers)
-, d_triggerDatabaseSize(context, 0)
-, d_triggerTermSetUpdatesSize(context, 0)
-, d_deducedDisequalitiesSize(context, 0)
-, d_deducedDisequalityReasonsSize(context, 0)
-, d_propagatedDisequalities(context)
-, d_name(name)
+EqualityEngine::EqualityEngine(EqualityEngineNotify& notify,
+ context::Context* context,
+ std::string name,
+ bool constantsAreTriggers,
+ bool anyTermTriggers)
+ : ContextNotifyObj(context),
+ d_masterEqualityEngine(0),
+ d_context(context),
+ d_done(context, false),
+ d_performNotify(true),
+ d_notify(notify),
+ d_applicationLookupsCount(context, 0),
+ d_nodesCount(context, 0),
+ d_assertedEqualitiesCount(context, 0),
+ d_equalityTriggersCount(context, 0),
+ d_subtermEvaluatesSize(context, 0),
+ d_stats(name),
+ d_inPropagate(false),
+ d_constantsAreTriggers(constantsAreTriggers),
+ d_anyTermsAreTriggers(anyTermTriggers),
+ d_triggerDatabaseSize(context, 0),
+ d_triggerTermSetUpdatesSize(context, 0),
+ d_deducedDisequalitiesSize(context, 0),
+ d_deducedDisequalityReasonsSize(context, 0),
+ d_propagatedDisequalities(context),
+ d_name(name)
{
init();
}
@@ -166,10 +174,11 @@ void EqualityEngine::setMasterEqualityEngine(EqualityEngine* master) {
}
void EqualityEngine::enqueue(const MergeCandidate& candidate, bool back) {
- Debug("equality") << d_name << "::eq::enqueue(" << d_nodes[candidate.d_t1Id]
- << ", " << d_nodes[candidate.d_t2Id] << ", "
- << candidate.d_type << "). reason: " << candidate.d_reason
- << std::endl;
+ Debug("equality") << d_name << "::eq::enqueue({" << candidate.d_t1Id << "} "
+ << d_nodes[candidate.d_t1Id] << ", {" << candidate.d_t2Id
+ << "} " << d_nodes[candidate.d_t2Id] << ", "
+ << static_cast<MergeReasonType>(candidate.d_type)
+ << "). reason: " << candidate.d_reason << std::endl;
if (back) {
d_propagationQueue.push_back(candidate);
} else {
@@ -178,7 +187,9 @@ void EqualityEngine::enqueue(const MergeCandidate& candidate, bool back) {
}
EqualityNodeId EqualityEngine::newApplicationNode(TNode original, EqualityNodeId t1, EqualityNodeId t2, FunctionApplicationType type) {
- Debug("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << ")" << std::endl;
+ Debug("equality") << d_name << "::eq::newApplicationNode(" << original
+ << ", {" << t1 << "} " << d_nodes[t1] << ", {" << t2 << "} "
+ << d_nodes[t2] << ")" << std::endl;
++d_stats.d_functionTermsCount;
@@ -190,13 +201,22 @@ EqualityNodeId EqualityEngine::newApplicationNode(TNode original, EqualityNodeId
EqualityNodeId t2ClassId = getEqualityNode(t2).getFind();
FunctionApplication funNormalized(type, t1ClassId, t2ClassId);
+ Debug("equality") << d_name << "::eq::newApplicationNode: funOriginal: ("
+ << type << " " << d_nodes[t1] << " " << d_nodes[t2]
+ << "), funNorm: (" << type << " " << d_nodes[t1ClassId]
+ << " " << d_nodes[t2ClassId] << ")\n";
+
// We add the original version
d_applications[funId] = FunctionApplicationPair(funOriginal, funNormalized);
// Add the lookup data, if it's not already there
ApplicationIdsMap::iterator find = d_applicationLookup.find(funNormalized);
if (find == d_applicationLookup.end()) {
- Debug("equality") << d_name << "::eq::newApplicationNode(" << original << ", " << t1 << ", " << t2 << "): no lookup, setting up" << std::endl;
+ Debug("equality") << d_name << "::eq::newApplicationNode(" << original
+ << ", " << t1 << ", " << t2
+ << "): no lookup, setting up funNorm: (" << type << " "
+ << d_nodes[t1ClassId] << " " << d_nodes[t2ClassId]
+ << ") => " << funId << std::endl;
// Mark the normalization to the lookup
storeApplicationLookup(funNormalized, funId);
} else {
@@ -366,13 +386,13 @@ void EqualityEngine::addTermInternal(TNode t, bool isOperator) {
// Non-Boolean constants are trigger terms for all tags
EqualityNodeId tId = getNodeId(t);
// Setup the new set
- Theory::Set newSetTags = 0;
+ TheoryIdSet newSetTags = 0;
EqualityNodeId newSetTriggers[THEORY_LAST];
unsigned newSetTriggersSize = THEORY_LAST;
for (TheoryId currentTheory = THEORY_FIRST; currentTheory != THEORY_LAST;
++currentTheory)
{
- newSetTags = Theory::setInsert(currentTheory, newSetTags);
+ newSetTags = TheoryIdSetUtil::setInsert(currentTheory, newSetTags);
newSetTriggers[currentTheory] = tId;
}
// Add it to the list for backtracking
@@ -425,8 +445,10 @@ const EqualityNode& EqualityEngine::getEqualityNode(EqualityNodeId nodeId) const
}
void EqualityEngine::assertEqualityInternal(TNode t1, TNode t2, TNode reason, unsigned pid) {
-
- Debug("equality") << d_name << "::eq::addEqualityInternal(" << t1 << "," << t2 << "), reason = " << reason << ", pid = " << pid << std::endl;
+ Debug("equality") << d_name << "::eq::addEqualityInternal(" << t1 << "," << t2
+ << "), reason = " << reason
+ << ", pid = " << static_cast<MergeReasonType>(pid)
+ << std::endl;
if (d_done) {
return;
@@ -442,19 +464,33 @@ void EqualityEngine::assertEqualityInternal(TNode t1, TNode t2, TNode reason, un
enqueue(MergeCandidate(t1Id, t2Id, pid, reason));
}
-void EqualityEngine::assertPredicate(TNode t, bool polarity, TNode reason, unsigned pid) {
+bool EqualityEngine::assertPredicate(TNode t,
+ bool polarity,
+ TNode reason,
+ unsigned pid)
+{
Debug("equality") << d_name << "::eq::addPredicate(" << t << "," << (polarity ? "true" : "false") << ")" << std::endl;
Assert(t.getKind() != kind::EQUAL) << "Use assertEquality instead";
- assertEqualityInternal(t, polarity ? d_true : d_false, reason, pid);
+ TNode b = polarity ? d_true : d_false;
+ if (hasTerm(t) && areEqual(t, b))
+ {
+ return false;
+ }
+ assertEqualityInternal(t, b, reason, pid);
propagate();
+ return true;
}
-void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason, unsigned pid) {
+bool EqualityEngine::assertEquality(TNode eq,
+ bool polarity,
+ TNode reason,
+ unsigned pid)
+{
Debug("equality") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ")" << std::endl;
if (polarity) {
// If two terms are already equal, don't assert anything
if (hasTerm(eq[0]) && hasTerm(eq[1]) && areEqual(eq[0], eq[1])) {
- return;
+ return false;
}
// Add equality between terms
assertEqualityInternal(eq[0], eq[1], reason, pid);
@@ -462,7 +498,7 @@ void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason, unsig
} else {
// If two terms are already dis-equal, don't assert anything
if (hasTerm(eq[0]) && hasTerm(eq[1]) && areDisequal(eq[0], eq[1], false)) {
- return;
+ return false;
}
// notify the theory
@@ -476,7 +512,7 @@ void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason, unsig
propagate();
if (d_done) {
- return;
+ return true;
}
// If both have constant representatives, we don't notify anyone
@@ -485,7 +521,7 @@ void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason, unsig
EqualityNodeId aClassId = getEqualityNode(a).getFind();
EqualityNodeId bClassId = getEqualityNode(b).getFind();
if (d_isConstant[aClassId] && d_isConstant[bClassId]) {
- return;
+ return true;
}
// If we are adding a disequality, notify of the shared term representatives
@@ -498,17 +534,17 @@ void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason, unsig
TriggerTermSet& aTriggerTerms = getTriggerTermSet(aTriggerRef);
TriggerTermSet& bTriggerTerms = getTriggerTermSet(bTriggerRef);
// Go through and notify the shared dis-equalities
- Theory::Set aTags = aTriggerTerms.d_tags;
- Theory::Set bTags = bTriggerTerms.d_tags;
- TheoryId aTag = Theory::setPop(aTags);
- TheoryId bTag = Theory::setPop(bTags);
+ TheoryIdSet aTags = aTriggerTerms.d_tags;
+ TheoryIdSet bTags = bTriggerTerms.d_tags;
+ TheoryId aTag = TheoryIdSetUtil::setPop(aTags);
+ TheoryId bTag = TheoryIdSetUtil::setPop(bTags);
int a_i = 0, b_i = 0;
while (aTag != THEORY_LAST && bTag != THEORY_LAST) {
if (aTag < bTag) {
- aTag = Theory::setPop(aTags);
+ aTag = TheoryIdSetUtil::setPop(aTags);
++ a_i;
} else if (aTag > bTag) {
- bTag = Theory::setPop(bTags);
+ bTag = TheoryIdSetUtil::setPop(bTags);
++ b_i;
} else {
// Same tags, notify
@@ -531,12 +567,13 @@ void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason, unsig
}
}
// Pop the next tags
- aTag = Theory::setPop(aTags);
- bTag = Theory::setPop(bTags);
+ aTag = TheoryIdSetUtil::setPop(aTags);
+ bTag = TheoryIdSetUtil::setPop(bTags);
}
}
}
}
+ return true;
}
TNode EqualityEngine::getRepresentative(TNode t) const {
@@ -564,15 +601,13 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
EqualityNode cc1 = getEqualityNode(n1);
EqualityNode cc2 = getEqualityNode(n2);
bool doNotify = false;
- // notify the theory
- // the second part of this check is needed due to the internal implementation of this class.
- // It ensures that we are merging terms and not operators.
- if (d_performNotify && class1Id==cc1.getFind() && class2Id==cc2.getFind()) {
+ // Determine if we should notify the owner of this class of this merge.
+ // The second part of this check is needed due to the internal implementation
+ // of this class. It ensures that we are merging terms and not operators.
+ if (d_performNotify && class1Id == cc1.getFind() && class2Id == cc2.getFind())
+ {
doNotify = true;
}
- if (doNotify) {
- d_notify.eqNotifyPreMerge(n1, n2);
- }
// Check for constant merges
bool class1isConstant = d_isConstant[class1Id];
@@ -583,12 +618,12 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
// Trigger set of class 1
TriggerTermSetRef class1triggerRef = d_nodeIndividualTrigger[class1Id];
- Theory::Set class1Tags = class1triggerRef == null_set_id
+ TheoryIdSet class1Tags = class1triggerRef == null_set_id
? 0
: getTriggerTermSet(class1triggerRef).d_tags;
// Trigger set of class 2
TriggerTermSetRef class2triggerRef = d_nodeIndividualTrigger[class2Id];
- Theory::Set class2Tags = class2triggerRef == null_set_id
+ TheoryIdSet class2Tags = class2triggerRef == null_set_id
? 0
: getTriggerTermSet(class2triggerRef).d_tags;
@@ -598,8 +633,10 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
TaggedEqualitiesSet class1disequalitiesToNotify;
// Individual tags
- Theory::Set class1OnlyTags = Theory::setDifference(class1Tags, class2Tags);
- Theory::Set class2OnlyTags = Theory::setDifference(class2Tags, class1Tags);
+ TheoryIdSet class1OnlyTags =
+ TheoryIdSetUtil::setDifference(class1Tags, class2Tags);
+ TheoryIdSet class2OnlyTags =
+ TheoryIdSetUtil::setDifference(class2Tags, class1Tags);
// Only get disequalities if they are not both constant
if (!class1isConstant || !class2isConstant) {
@@ -700,7 +737,7 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
// notify the theory
if (doNotify) {
- d_notify.eqNotifyPostMerge(n1, n2);
+ d_notify.eqNotifyMerge(n1, n2);
}
// Go through the trigger term disequalities and propagate
@@ -725,17 +762,17 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
TriggerTermSet& class2triggers = getTriggerTermSet(class2triggerRef);
// Initialize the merged set
- Theory::Set newSetTags =
- Theory::setUnion(class1triggers.d_tags, class2triggers.d_tags);
+ TheoryIdSet newSetTags = TheoryIdSetUtil::setUnion(class1triggers.d_tags,
+ class2triggers.d_tags);
EqualityNodeId newSetTriggers[THEORY_LAST];
unsigned newSetTriggersSize = 0;
int i1 = 0;
int i2 = 0;
- Theory::Set tags1 = class1triggers.d_tags;
- Theory::Set tags2 = class2triggers.d_tags;
- TheoryId tag1 = Theory::setPop(tags1);
- TheoryId tag2 = Theory::setPop(tags2);
+ TheoryIdSet tags1 = class1triggers.d_tags;
+ TheoryIdSet tags2 = class2triggers.d_tags;
+ TheoryId tag1 = TheoryIdSetUtil::setPop(tags1);
+ TheoryId tag2 = TheoryIdSetUtil::setPop(tags2);
// Comparing the THEORY_LAST is OK because all other theories are
// smaller, and will therefore be preferred
@@ -745,12 +782,12 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
// copy tag1
newSetTriggers[newSetTriggersSize++] =
class1triggers.d_triggers[i1++];
- tag1 = Theory::setPop(tags1);
+ tag1 = TheoryIdSetUtil::setPop(tags1);
} else if (tag1 > tag2) {
// copy tag2
newSetTriggers[newSetTriggersSize++] =
class2triggers.d_triggers[i2++];
- tag2 = Theory::setPop(tags2);
+ tag2 = TheoryIdSetUtil::setPop(tags2);
} else {
// copy tag1
EqualityNodeId tag1id = newSetTriggers[newSetTriggersSize++] =
@@ -763,8 +800,8 @@ bool EqualityEngine::merge(EqualityNode& class1, EqualityNode& class2, std::vect
}
}
// Next tags
- tag1 = Theory::setPop(tags1);
- tag2 = Theory::setPop(tags2);
+ tag1 = TheoryIdSetUtil::setPop(tags1);
+ tag2 = TheoryIdSetUtil::setPop(tags2);
}
}
@@ -935,7 +972,9 @@ void EqualityEngine::backtrack() {
}
void EqualityEngine::addGraphEdge(EqualityNodeId t1, EqualityNodeId t2, unsigned type, TNode reason) {
- Debug("equality") << d_name << "::eq::addGraphEdge(" << d_nodes[t1] << "," << d_nodes[t2] << "," << reason << ")" << std::endl;
+ Debug("equality") << d_name << "::eq::addGraphEdge({" << t1 << "} "
+ << d_nodes[t1] << ", {" << t2 << "} " << d_nodes[t2] << ","
+ << reason << ")" << std::endl;
EqualityEdgeId edge = d_equalityEdges.size();
d_equalityEdges.push_back(EqualityEdge(t2, d_equalityGraph[t1], type, reason));
d_equalityEdges.push_back(EqualityEdge(t1, d_equalityGraph[t2], type, reason));
@@ -956,7 +995,7 @@ std::string EqualityEngine::edgesToString(EqualityEdgeId edgeId) const {
while (edgeId != null_edge) {
const EqualityEdge& edge = d_equalityEdges[edgeId];
if (!first) out << ",";
- out << d_nodes[edge.getNodeId()];
+ out << "{" << edge.getNodeId() << "} " << d_nodes[edge.getNodeId()];
edgeId = edge.getNext();
first = false;
}
@@ -964,6 +1003,83 @@ std::string EqualityEngine::edgesToString(EqualityEdgeId edgeId) const {
return out.str();
}
+void EqualityEngine::buildEqConclusion(EqualityNodeId id1,
+ EqualityNodeId id2,
+ EqProof* eqp) const
+{
+ Kind k1 = d_nodes[id1].getKind();
+ Kind k2 = d_nodes[id2].getKind();
+ // only try to build if ids do not correspond to internal nodes. If they do,
+ // only try to build build if full applications corresponding to the given ids
+ // have the same congruence n-ary non-APPLY_* kind, since the internal nodes
+ // may be full nodes.
+ if ((d_isInternal[id1] || d_isInternal[id2])
+ && (k1 != k2 || k1 == kind::APPLY_UF || k1 == kind::APPLY_CONSTRUCTOR
+ || k1 == kind::APPLY_SELECTOR || k1 == kind::APPLY_TESTER
+ || !ExprManager::isNAryKind(k1)))
+ {
+ return;
+ }
+ Debug("equality") << "buildEqConclusion: {" << id1 << "} " << d_nodes[id1]
+ << "\n";
+ Debug("equality") << "buildEqConclusion: {" << id2 << "} " << d_nodes[id2]
+ << "\n";
+ Node eq[2];
+ NodeManager* nm = NodeManager::currentNM();
+ for (unsigned i = 0; i < 2; ++i)
+ {
+ EqualityNodeId equalityNodeId = i == 0 ? id1 : id2;
+ Node equalityNode = d_nodes[equalityNodeId];
+ // if not an internal node, just retrieve it
+ if (!d_isInternal[equalityNodeId])
+ {
+ eq[i] = equalityNode;
+ continue;
+ }
+ // build node relative to partial application of this
+ // n-ary kind. We get the full application, then we get
+ // the arguments relative to how partial the internal
+ // node is, and build the application
+
+ // get number of children of partial app:
+ // #children of full app - (id of full app - id of
+ // partial app)
+ EqualityNodeId fullAppId = getNodeId(equalityNode);
+ EqualityNodeId curr = fullAppId;
+ unsigned separation = 0;
+ Assert(fullAppId >= equalityNodeId);
+ while (curr != equalityNodeId)
+ {
+ separation = separation + (d_nodes[curr--] == equalityNode ? 1 : 0);
+ }
+ // compute separation, which is how many ids with the
+ // same fullappnode exist between equalityNodeId and
+ // fullAppId
+ unsigned numChildren = equalityNode.getNumChildren() - separation;
+ Assert(numChildren < equalityNode.getNumChildren())
+ << "broke for numChildren " << numChildren << ", fullAppId "
+ << fullAppId << ", equalityNodeId " << equalityNodeId << ", node "
+ << equalityNode << ", cong: {" << id1 << "} " << d_nodes[id1] << " = {"
+ << id2 << "} " << d_nodes[id2] << "\n";
+ // if has at least as many children as the minimal
+ // number of children of the n-ary kind, build the node
+ if (numChildren >= ExprManager::minArity(k1))
+ {
+ std::vector<Node> children;
+ for (unsigned j = 0; j < numChildren; ++j)
+ {
+ children.push_back(equalityNode[j]);
+ }
+ eq[i] = nm->mkNode(k1, children);
+ }
+ }
+ // if built equality, add it as eqp's conclusion
+ if (!eq[0].isNull() && !eq[1].isNull())
+ {
+ eqp->d_node = eq[0].eqNode(eq[1]);
+ }
+}
+
void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity,
std::vector<TNode>& equalities,
EqProof* eqp) const {
@@ -973,8 +1089,11 @@ void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity,
// The terms must be there already
Assert(hasTerm(t1) && hasTerm(t2));
- ;
+ if (Debug.isOn("equality::internal"))
+ {
+ debugPrintGraph();
+ }
// Get the ids
EqualityNodeId t1Id = getNodeId(t1);
EqualityNodeId t2Id = getNodeId(t2);
@@ -985,7 +1104,7 @@ void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity,
getExplanation(t1Id, t2Id, equalities, cache, eqp);
} else {
if (eqp) {
- eqp->d_id = eq::MERGED_THROUGH_TRANS;
+ eqp->d_id = MERGED_THROUGH_TRANS;
eqp->d_node = d_nodes[t1Id].eqNode(d_nodes[t2Id]).notNode();
}
@@ -994,7 +1113,12 @@ void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity,
Assert(d_disequalityReasonsMap.find(pair) != d_disequalityReasonsMap.end())
<< "Don't ask for stuff I didn't notify you about";
DisequalityReasonRef reasonRef = d_disequalityReasonsMap.find(pair)->second;
-
+ if (eqp)
+ {
+ Debug("pf::ee") << "Deq reason for " << eqp->d_node << " "
+ << reasonRef.d_mergesStart << "..."
+ << reasonRef.d_mergesEnd << std::endl;
+ }
for (unsigned i = reasonRef.d_mergesStart; i < reasonRef.d_mergesEnd; ++i)
{
EqualityPair toExplain = d_deducedDisequalityReasons[i];
@@ -1003,6 +1127,9 @@ void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity,
// If we're constructing a (transitivity) proof, we don't need to include an explanation for x=x.
if (eqp && toExplain.first != toExplain.second) {
eqpc = std::make_shared<EqProof>();
+ Debug("pf::ee") << "Deq getExplanation #" << i << " for " << eqp->d_node
+ << " : " << toExplain.first << " " << toExplain.second
+ << std::endl;
}
getExplanation(
@@ -1014,12 +1141,13 @@ void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity,
Debug("pf::ee") << "Child proof is:" << std::endl;
eqpc->debug_print("pf::ee", 1);
}
- if (eqpc->d_id == eq::MERGED_THROUGH_TRANS) {
+ if (eqpc->d_id == MERGED_THROUGH_TRANS)
+ {
std::vector<std::shared_ptr<EqProof>> orderedChildren;
bool nullCongruenceFound = false;
for (const auto& child : eqpc->d_children)
{
- if (child->d_id == eq::MERGED_THROUGH_CONGRUENCE
+ if (child->d_id == MERGED_THROUGH_CONGRUENCE
&& child->d_node.isNull())
{
nullCongruenceFound = true;
@@ -1061,10 +1189,48 @@ void EqualityEngine::explainEquality(TNode t1, TNode t2, bool polarity,
Assert(eqp->d_node[0][1].isConst());
eqp->d_id = MERGED_THROUGH_CONSTANTS;
} else if (eqp->d_children.size() == 1) {
- // The transitivity proof has just one child. Simplify.
- std::shared_ptr<EqProof> temp = eqp->d_children[0];
- eqp->d_children.clear();
- *eqp = *temp;
+ Node cnode = eqp->d_children[0]->d_node;
+ Debug("pf::ee") << "Simplifying " << cnode << " from " << eqp->d_node
+ << std::endl;
+ bool simpTrans = true;
+ if (cnode.getKind() == kind::EQUAL)
+ {
+ // It may be the case that we have a proof of x = c2 and we want to
+ // conclude x != c1. If this is the case, below we construct:
+ //
+ // -------- MERGED_THROUGH_EQUALITY
+ // x = c2 c1 != c2
+ // ----------------- TRANS
+ // x != c1
+ TNode c1 = t1.isConst() ? t1 : (t2.isConst() ? t2 : TNode::null());
+ TNode nc = t1.isConst() ? t2 : (t2.isConst() ? t1 : TNode::null());
+ Node c2;
+ // merge constants transitivity
+ for (unsigned i = 0; i < 2; i++)
+ {
+ if (cnode[i].isConst() && cnode[1 - i] == nc)
+ {
+ c2 = cnode[i];
+ break;
+ }
+ }
+ if (!c1.isNull() && !c2.isNull())
+ {
+ simpTrans = false;
+ Assert(c1.getType().isComparableTo(c2.getType()));
+ std::shared_ptr<EqProof> eqpmc = std::make_shared<EqProof>();
+ eqpmc->d_id = MERGED_THROUGH_CONSTANTS;
+ eqpmc->d_node = c1.eqNode(c2).eqNode(d_false);
+ eqp->d_children.push_back(eqpmc);
+ }
+ }
+ if (simpTrans)
+ {
+ // The transitivity proof has just one child. Simplify.
+ std::shared_ptr<EqProof> temp = eqp->d_children[0];
+ eqp->d_children.clear();
+ *eqp = *temp;
+ }
}
if (Debug.isOn("pf::ee"))
@@ -1084,11 +1250,74 @@ void EqualityEngine::explainPredicate(TNode p, bool polarity,
// Must have the term
Assert(hasTerm(p));
std::map<std::pair<EqualityNodeId, EqualityNodeId>, EqProof*> cache;
+ if (Debug.isOn("equality::internal"))
+ {
+ debugPrintGraph();
+ }
// Get the explanation
getExplanation(
getNodeId(p), polarity ? d_trueId : d_falseId, assertions, cache, eqp);
}
+void EqualityEngine::explainLit(TNode lit, std::vector<TNode>& assumptions)
+{
+ Assert(lit.getKind() != kind::AND);
+ bool polarity = lit.getKind() != kind::NOT;
+ TNode atom = polarity ? lit : lit[0];
+ std::vector<TNode> tassumptions;
+ if (atom.getKind() == kind::EQUAL)
+ {
+ Assert(hasTerm(atom[0]));
+ Assert(hasTerm(atom[1]));
+ if (!polarity)
+ {
+ // ensure that we are ready to explain the disequality
+ AlwaysAssert(areDisequal(atom[0], atom[1], true));
+ }
+ else if (atom[0] == atom[1])
+ {
+ // no need to explain reflexivity
+ return;
+ }
+ explainEquality(atom[0], atom[1], polarity, tassumptions);
+ }
+ else
+ {
+ explainPredicate(atom, polarity, tassumptions);
+ }
+ // ensure that duplicates are removed
+ for (const TNode a : tassumptions)
+ {
+ if (std::find(assumptions.begin(), assumptions.end(), a)
+ == assumptions.end())
+ {
+ Assert(!a.isNull());
+ assumptions.push_back(a);
+ }
+ }
+}
+
+Node EqualityEngine::mkExplainLit(TNode lit)
+{
+ Assert(lit.getKind() != kind::AND);
+ std::vector<TNode> assumptions;
+ explainLit(lit, assumptions);
+ Node ret;
+ if (assumptions.empty())
+ {
+ ret = NodeManager::currentNM()->mkConst(true);
+ }
+ else if (assumptions.size() == 1)
+ {
+ ret = assumptions[0];
+ }
+ else
+ {
+ ret = NodeManager::currentNM()->mkNode(kind::AND, assumptions);
+ }
+ return ret;
+}
+
void EqualityEngine::getExplanation(
EqualityNodeId t1Id,
EqualityNodeId t2Id,
@@ -1096,8 +1325,9 @@ void EqualityEngine::getExplanation(
std::map<std::pair<EqualityNodeId, EqualityNodeId>, EqProof*>& cache,
EqProof* eqp) const
{
- Trace("eq-exp") << d_name << "::eq::getExplanation(" << d_nodes[t1Id] << ","
- << d_nodes[t2Id] << ") size = " << cache.size() << std::endl;
+ Trace("eq-exp") << d_name << "::eq::getExplanation({" << t1Id << "} "
+ << d_nodes[t1Id] << ", {" << t2Id << "} " << d_nodes[t2Id]
+ << ") size = " << cache.size() << std::endl;
// determine if we have already computed the explanation.
std::pair<EqualityNodeId, EqualityNodeId> cacheKey;
@@ -1136,7 +1366,7 @@ void EqualityEngine::getExplanation(
// We may have cached null in its place, create the trivial proof now.
Assert(d_nodes[t1Id] == d_nodes[t2Id]);
Assert(eqp->d_id == MERGED_THROUGH_REFLEXIVITY);
- eqp->d_node = d_nodes[t1Id];
+ eqp->d_node = d_nodes[t1Id].eqNode(d_nodes[t1Id]);
}
return;
}
@@ -1157,23 +1387,29 @@ void EqualityEngine::getExplanation(
#endif
// If the nodes are the same, we're done
- if (t1Id == t2Id){
- if( eqp ) {
- if ((d_nodes[t1Id].getKind() == kind::BUILTIN) && (d_nodes[t1Id].getConst<Kind>() == kind::SELECT)) {
- std::vector<Node> no_children;
- eqp->d_node = NodeManager::currentNM()->mkNode(kind::PARTIAL_SELECT_0, no_children);
- } else {
- eqp->d_node = ProofManager::currentPM()->mkOp(d_nodes[t1Id]);
+ if (t1Id == t2Id)
+ {
+ if (eqp)
+ {
+ // ignore equalities between function symbols, i.e. internal nullary
+ // non-constant nodes.
+ //
+ // Note that this is robust for HOL because in that case function
+ // symbols are not internal nodes
+ if (d_isInternal[t1Id] && d_nodes[t1Id].getNumChildren() == 0
+ && !d_isConstant[t1Id])
+ {
+ eqp->d_node = Node::null();
+ }
+ else
+ {
+ Assert(d_nodes[t1Id].getKind() != kind::BUILTIN);
+ eqp->d_node = d_nodes[t1Id].eqNode(d_nodes[t1Id]);
}
}
return;
}
-
- if (Debug.isOn("equality::internal")) {
- debugPrintGraph();
- }
-
// Queue for the BFS containing nodes
std::vector<BfsData> bfsQueue;
@@ -1188,7 +1424,9 @@ void EqualityEngine::getExplanation(
BfsData current = bfsQueue[currentIndex];
EqualityNodeId currentNode = current.d_nodeId;
- Debug("equality") << d_name << "::eq::getExplanation(): currentNode = " << d_nodes[currentNode] << std::endl;
+ Debug("equality") << d_name << "::eq::getExplanation(): currentNode = {"
+ << currentNode << "} " << d_nodes[currentNode]
+ << std::endl;
// Go through the equality edges of this node
EqualityEdgeId currentEdge = d_equalityGraph[currentNode];
@@ -1204,7 +1442,11 @@ void EqualityEngine::getExplanation(
// If not just the backwards edge
if ((currentEdge | 1u) != (current.d_edgeId | 1u))
{
- Debug("equality") << d_name << "::eq::getExplanation(): currentEdge = (" << d_nodes[currentNode] << "," << d_nodes[edge.getNodeId()] << ")" << std::endl;
+ Debug("equality") << d_name
+ << "::eq::getExplanation(): currentEdge = ({"
+ << currentNode << "} " << d_nodes[currentNode]
+ << ", {" << edge.getNodeId() << "} "
+ << d_nodes[edge.getNodeId()] << ")" << std::endl;
// Did we find the path
if (edge.getNodeId() == t2Id) {
@@ -1218,13 +1460,26 @@ void EqualityEngine::getExplanation(
// The current node
currentNode = bfsQueue[currentIndex].d_nodeId;
EqualityNodeId edgeNode = d_equalityEdges[currentEdge].getNodeId();
- unsigned reasonType = d_equalityEdges[currentEdge].getReasonType();
+ MergeReasonType reasonType = static_cast<MergeReasonType>(
+ d_equalityEdges[currentEdge].getReasonType());
Node reason = d_equalityEdges[currentEdge].getReason();
- Debug("equality") << d_name << "::eq::getExplanation(): currentEdge = " << currentEdge << ", currentNode = " << currentNode << std::endl;
- Debug("equality") << d_name << " targetNode = " << d_nodes[edgeNode] << std::endl;
- Debug("equality") << d_name << " in currentEdge = (" << d_nodes[currentNode] << "," << d_nodes[edge.getNodeId()] << ")" << std::endl;
- Debug("equality") << d_name << " reason type = " << reasonType << std::endl;
+ Debug("equality")
+ << d_name
+ << "::eq::getExplanation(): currentEdge = " << currentEdge
+ << ", currentNode = " << currentNode << std::endl;
+ Debug("equality")
+ << d_name << " targetNode = {" << edgeNode
+ << "} " << d_nodes[edgeNode] << std::endl;
+ Debug("equality")
+ << d_name << " in currentEdge = ({"
+ << currentNode << "} " << d_nodes[currentNode] << ", {"
+ << edge.getNodeId() << "} " << d_nodes[edge.getNodeId()] << ")"
+ << std::endl;
+ Debug("equality")
+ << d_name
+ << " reason type = " << reasonType
+ << "\n";
std::shared_ptr<EqProof> eqpc;;
// Make child proof if a proof is being constructed
@@ -1237,7 +1492,10 @@ void EqualityEngine::getExplanation(
switch (reasonType) {
case MERGED_THROUGH_CONGRUENCE: {
// f(x1, x2) == f(y1, y2) because x1 = y1 and x2 = y2
- Debug("equality") << d_name << "::eq::getExplanation(): due to congruence, going deeper" << std::endl;
+ Debug("equality")
+ << d_name
+ << "::eq::getExplanation(): due to congruence, going deeper"
+ << std::endl;
const FunctionApplication& f1 =
d_applications[currentNode].d_original;
const FunctionApplication& f2 =
@@ -1252,44 +1510,25 @@ void EqualityEngine::getExplanation(
std::shared_ptr<EqProof> eqpc2 =
eqpc ? std::make_shared<EqProof>() : nullptr;
getExplanation(f1.d_b, f2.d_b, equalities, cache, eqpc2.get());
- if( eqpc ){
- eqpc->d_children.push_back( eqpc1 );
- eqpc->d_children.push_back( eqpc2 );
- if( d_nodes[currentNode].getKind()==kind::EQUAL ){
- //leave node null for now
- eqpc->d_node = Node::null();
- } else {
- if (d_nodes[f1.d_a].getKind() == kind::APPLY_UF
- || d_nodes[f1.d_a].getKind() == kind::SELECT
- || d_nodes[f1.d_a].getKind() == kind::STORE)
- {
- eqpc->d_node = d_nodes[f1.d_a];
- }
- else
- {
- if (d_nodes[f1.d_a].getKind() == kind::BUILTIN
- && d_nodes[f1.d_a].getConst<Kind>() == kind::SELECT)
- {
- eqpc->d_node = NodeManager::currentNM()->mkNode(
- kind::PARTIAL_SELECT_1, d_nodes[f1.d_b]);
- // The first child is a PARTIAL_SELECT_0.
- // Give it a child so that we know what kind of (read) it is, when we dump to LFSC.
- Assert(eqpc->d_children[0]->d_node.getKind()
- == kind::PARTIAL_SELECT_0);
- Assert(eqpc->d_children[0]->d_children.size() == 0);
-
- eqpc->d_children[0]->d_node =
- NodeManager::currentNM()->mkNode(
- kind::PARTIAL_SELECT_0, d_nodes[f1.d_b]);
- }
- else
- {
- eqpc->d_node = NodeManager::currentNM()->mkNode(
- kind::PARTIAL_APPLY_UF,
- ProofManager::currentPM()->mkOp(d_nodes[f1.d_a]),
- d_nodes[f1.d_b]);
- }
- }
+ if (eqpc)
+ {
+ eqpc->d_children.push_back(eqpc1);
+ eqpc->d_children.push_back(eqpc2);
+ // build conclusion if ids correspond to non-internal nodes or
+ // if non-internal nodes can be retrieved from them (in the
+ // case of n-ary applications), otherwise leave conclusion as
+ // null. This is only done for congruence kinds, since
+ // congruence is not used otherwise.
+ Kind k = d_nodes[currentNode].getKind();
+ if (d_congruenceKinds[k])
+ {
+ buildEqConclusion(currentNode, edgeNode, eqpc.get());
+ }
+ else
+ {
+ Assert(k == kind::EQUAL)
+ << "not an internal node " << d_nodes[currentNode]
+ << " with non-congruence with " << k << "\n";
}
}
Debug("equality") << pop;
@@ -1322,9 +1561,26 @@ void EqualityEngine::getExplanation(
Debug("equality") << push;
// Get the node we interpreted
- TNode interpreted = d_nodes[currentNode];
- if (interpreted.isConst()) {
- interpreted = d_nodes[edgeNode];
+ TNode interpreted;
+ if (eqpc)
+ {
+ // build the conclusion f(c1, ..., cn) = c
+ if (d_nodes[currentNode].isConst())
+ {
+ interpreted = d_nodes[edgeNode];
+ eqpc->d_node = d_nodes[edgeNode].eqNode(d_nodes[currentNode]);
+ }
+ else
+ {
+ interpreted = d_nodes[currentNode];
+ eqpc->d_node = d_nodes[currentNode].eqNode(d_nodes[edgeNode]);
+ }
+ }
+ else
+ {
+ interpreted = d_nodes[currentNode].isConst()
+ ? d_nodes[edgeNode]
+ : d_nodes[currentNode];
}
// Explain why a is a constant by explaining each argument
@@ -1358,19 +1614,20 @@ void EqualityEngine::getExplanation(
// Construct the equality
Debug("equality") << d_name << "::eq::getExplanation(): adding: "
<< reason << std::endl;
- Debug("equality") << d_name << "::eq::getExplanation(): reason type = " << reasonType << std::endl;
+ Debug("equality")
+ << d_name
+ << "::eq::getExplanation(): reason type = " << reasonType
+ << "\n";
Node a = d_nodes[currentNode];
Node b = d_nodes[d_equalityEdges[currentEdge].getNodeId()];
if (eqpc) {
- //apply proof reconstruction processing (when eqpc is non-null)
- if (d_pathReconstructionTriggers.find(reasonType) != d_pathReconstructionTriggers.end()) {
- d_pathReconstructionTriggers.find(reasonType)
- ->second->notify(reasonType, reason, a, b, equalities,
- eqpc.get());
- }
if (reasonType == MERGED_THROUGH_EQUALITY) {
- eqpc->d_node = reason;
+ // in the new proof infrastructure we can assume that "theory
+ // assumptions", which are a consequence of theory reasoning
+ // on other assumptions, are externally justified. In this
+ // case we can use (= a b) directly as the conclusion here.
+ eqpc->d_node = b.eqNode(a);
} else {
// The LFSC translator prefers (not (= a b)) over (= (= a b) false)
@@ -1414,7 +1671,12 @@ void EqualityEngine::getExplanation(
} else {
eqp->d_id = MERGED_THROUGH_TRANS;
eqp->d_children.insert( eqp->d_children.end(), eqp_trans.begin(), eqp_trans.end() );
- eqp->d_node = NodeManager::currentNM()->mkNode(kind::EQUAL, d_nodes[t1Id], d_nodes[t2Id]);
+ // build conclusion in case of equality between non-internal
+ // nodes or of n-ary congruence kinds, otherwise leave as
+ // null. The latter is necessary for the overall handling of
+ // congruence proofs involving n-ary kinds, see
+ // EqProof::reduceNestedCongruence for more details.
+ buildEqConclusion(t1Id, t2Id, eqp);
}
if (Debug.isOn("pf::ee"))
{
@@ -1454,11 +1716,11 @@ void EqualityEngine::addTriggerEquality(TNode eq) {
// If they are equal or disequal already, no need for the trigger
if (areEqual(eq[0], eq[1])) {
- d_notify.eqNotifyTriggerEquality(eq, true);
+ d_notify.eqNotifyTriggerPredicate(eq, true);
skipTrigger = true;
}
if (areDisequal(eq[0], eq[1], true)) {
- d_notify.eqNotifyTriggerEquality(eq, false);
+ d_notify.eqNotifyTriggerPredicate(eq, false);
skipTrigger = true;
}
@@ -1476,10 +1738,14 @@ void EqualityEngine::addTriggerEquality(TNode eq) {
}
void EqualityEngine::addTriggerPredicate(TNode predicate) {
- Assert(predicate.getKind() != kind::NOT
- && predicate.getKind() != kind::EQUAL);
+ Assert(predicate.getKind() != kind::NOT);
+ if (predicate.getKind() == kind::EQUAL)
+ {
+ // equality is handled separately
+ return addTriggerEquality(predicate);
+ }
Assert(d_congruenceKinds.tst(predicate.getKind()))
- << "No point in adding non-congruence predicates";
+ << "No point in adding non-congruence predicates, kind is " << predicate.getKind();
if (d_done) {
return;
@@ -1747,8 +2013,8 @@ void EqualityEngine::propagate() {
d_deducedDisequalityReasons.push_back(EqualityPair(original, d_falseId));
}
storePropagatedDisequality(THEORY_LAST, lhsId, rhsId);
- if (!d_notify.eqNotifyTriggerEquality(triggerInfo.d_trigger,
- triggerInfo.d_polarity))
+ if (!d_notify.eqNotifyTriggerPredicate(triggerInfo.d_trigger,
+ triggerInfo.d_polarity))
{
d_done = true;
}
@@ -1757,8 +2023,8 @@ void EqualityEngine::propagate() {
else
{
// Equalities are simple
- if (!d_notify.eqNotifyTriggerEquality(triggerInfo.d_trigger,
- triggerInfo.d_polarity))
+ if (!d_notify.eqNotifyTriggerPredicate(triggerInfo.d_trigger,
+ triggerInfo.d_polarity))
{
d_done = true;
}
@@ -1893,17 +2159,7 @@ size_t EqualityEngine::getSize(TNode t) {
return getEqualityNode(getEqualityNode(t).getFind()).getSize();
}
-
-void EqualityEngine::addPathReconstructionTrigger(unsigned trigger, const PathReconstructionNotify* notify) {
- // Currently we can only inform one callback per trigger
- Assert(d_pathReconstructionTriggers.find(trigger)
- == d_pathReconstructionTriggers.end());
- d_pathReconstructionTriggers[trigger] = notify;
-}
-
-unsigned EqualityEngine::getFreshMergeReasonType() {
- return d_freshMergeReasonType++;
-}
+std::string EqualityEngine::identify() const { return d_name; }
void EqualityEngine::addTriggerTerm(TNode t, TheoryId tag)
{
@@ -1918,6 +2174,12 @@ void EqualityEngine::addTriggerTerm(TNode t, TheoryId tag)
// Add the term if it's not already there
addTermInternal(t);
+ if (!d_anyTermsAreTriggers)
+ {
+ // if we are not using triggers, we only add the term, but not as a trigger
+ return;
+ }
+
// Get the node id
EqualityNodeId eqNodeId = getNodeId(t);
EqualityNode& eqNode = getEqualityNode(eqNodeId);
@@ -1940,11 +2202,11 @@ void EqualityEngine::addTriggerTerm(TNode t, TheoryId tag)
// uselists that have been asserted to false. All the representatives appearing on the other
// side of such disequalities, that have the tag on, are put in a set.
TaggedEqualitiesSet disequalitiesToNotify;
- Theory::Set tags = Theory::setInsert(tag);
+ TheoryIdSet tags = TheoryIdSetUtil::setInsert(tag);
getDisequalities(!d_isConstant[classId], classId, tags, disequalitiesToNotify);
// Trigger data
- Theory::Set newSetTags;
+ TheoryIdSet newSetTags;
EqualityNodeId newSetTriggers[THEORY_LAST];
unsigned newSetTriggersSize;
@@ -1953,23 +2215,23 @@ void EqualityEngine::addTriggerTerm(TNode t, TheoryId tag)
// Get the existing set
TriggerTermSet& triggerSet = getTriggerTermSet(triggerSetRef);
// Initialize the new set for copy/insert
- newSetTags = Theory::setInsert(tag, triggerSet.d_tags);
+ newSetTags = TheoryIdSetUtil::setInsert(tag, triggerSet.d_tags);
newSetTriggersSize = 0;
// Copy into to new one, and insert the new tag/id
unsigned i = 0;
- Theory::Set tags2 = newSetTags;
+ TheoryIdSet tags2 = newSetTags;
TheoryId current;
- while ((current = Theory::setPop(tags2)) != THEORY_LAST)
+ while ((current = TheoryIdSetUtil::setPop(tags2)) != THEORY_LAST)
{
// Remove from the tags
- tags2 = Theory::setRemove(current, tags2);
+ tags2 = TheoryIdSetUtil::setRemove(current, tags2);
// Insert the id into the triggers
newSetTriggers[newSetTriggersSize++] =
current == tag ? eqNodeId : triggerSet.d_triggers[i++];
}
} else {
// Setup a singleton
- newSetTags = Theory::setInsert(tag);
+ newSetTags = TheoryIdSetUtil::setInsert(tag);
newSetTriggers[0] = eqNodeId;
newSetTriggersSize = 1;
}
@@ -1999,8 +2261,9 @@ TNode EqualityEngine::getTriggerTermRepresentative(TNode t, TheoryId tag) const
EqualityNodeId classId = getEqualityNode(t).getFind();
const TriggerTermSet& triggerSet = getTriggerTermSet(d_nodeIndividualTrigger[classId]);
unsigned i = 0;
- Theory::Set tags = triggerSet.d_tags;
- while (Theory::setPop(tags) != tag) {
+ TheoryIdSet tags = triggerSet.d_tags;
+ while (TheoryIdSetUtil::setPop(tags) != tag)
+ {
++ i;
}
return d_nodes[triggerSet.d_triggers[i]];
@@ -2054,7 +2317,11 @@ void EqualityEngine::getUseListTerms(TNode t, std::set<TNode>& output) {
}
}
-EqualityEngine::TriggerTermSetRef EqualityEngine::newTriggerTermSet(Theory::Set newSetTags, EqualityNodeId* newSetTriggers, unsigned newSetTriggersSize) {
+EqualityEngine::TriggerTermSetRef EqualityEngine::newTriggerTermSet(
+ TheoryIdSet newSetTags,
+ EqualityNodeId* newSetTriggers,
+ unsigned newSetTriggersSize)
+{
// Size of the required set
size_t size = sizeof(TriggerTermSet) + newSetTriggersSize*sizeof(EqualityNodeId);
// Align the size
@@ -2102,7 +2369,7 @@ bool EqualityEngine::hasPropagatedDisequality(TheoryId tag, EqualityNodeId lhsId
}
Assert(d_disequalityReasonsMap.find(eq) != d_disequalityReasonsMap.end())
<< "We propagated but there is no proof";
- bool result = Theory::setContains(tag, (*it).second);
+ bool result = TheoryIdSetUtil::setContains(tag, (*it).second);
Debug("equality::disequality") << d_name << "::eq::hasPropagatedDisequality(" << tag << ", " << d_nodes[lhsId] << ", " << d_nodes[rhsId] << ") => " << (result ? "true" : "false") << std::endl;
return result;
}
@@ -2119,12 +2386,12 @@ void EqualityEngine::storePropagatedDisequality(TheoryId tag, EqualityNodeId lhs
EqualityPair pair2(rhsId, lhsId);
// Store the fact that we've propagated this already
- Theory::Set notified = 0;
+ TheoryIdSet notified = 0;
PropagatedDisequalitiesMap::const_iterator find = d_propagatedDisequalities.find(pair1);
if (find == d_propagatedDisequalities.end()) {
- notified = Theory::setInsert(tag);
+ notified = TheoryIdSetUtil::setInsert(tag);
} else {
- notified = Theory::setInsert(tag, (*find).second);
+ notified = TheoryIdSetUtil::setInsert(tag, (*find).second);
}
d_propagatedDisequalities[pair1] = notified;
d_propagatedDisequalities[pair2] = notified;
@@ -2166,12 +2433,16 @@ void EqualityEngine::storePropagatedDisequality(TheoryId tag, EqualityNodeId lhs
}
}
-void EqualityEngine::getDisequalities(bool allowConstants, EqualityNodeId classId, Theory::Set inputTags, TaggedEqualitiesSet& out) {
+void EqualityEngine::getDisequalities(bool allowConstants,
+ EqualityNodeId classId,
+ TheoryIdSet inputTags,
+ TaggedEqualitiesSet& out)
+{
// Must be empty on input
Assert(out.size() == 0);
// The class we are looking for, shouldn't have any of the tags we are looking for already set
Assert(d_nodeIndividualTrigger[classId] == null_set_id
- || Theory::setIntersection(
+ || TheoryIdSetUtil::setIntersection(
getTriggerTermSet(d_nodeIndividualTrigger[classId]).d_tags,
inputTags)
== 0);
@@ -2229,8 +2500,8 @@ void EqualityEngine::getDisequalities(bool allowConstants, EqualityNodeId classI
// Tags of the other gey
TriggerTermSet& toCompareTriggerSet = getTriggerTermSet(toCompareTriggerSetRef);
// We only care if there are things in inputTags that is also in toCompareTags
- Theory::Set commonTags =
- Theory::setIntersection(inputTags, toCompareTriggerSet.d_tags);
+ TheoryIdSet commonTags = TheoryIdSetUtil::setIntersection(
+ inputTags, toCompareTriggerSet.d_tags);
if (commonTags) {
out.push_back(TaggedEquality(funId, toCompareTriggerSetRef, lhs));
}
@@ -2246,8 +2517,11 @@ void EqualityEngine::getDisequalities(bool allowConstants, EqualityNodeId classI
}
-bool EqualityEngine::propagateTriggerTermDisequalities(Theory::Set tags, TriggerTermSetRef triggerSetRef, const TaggedEqualitiesSet& disequalitiesToNotify) {
-
+bool EqualityEngine::propagateTriggerTermDisequalities(
+ TheoryIdSet tags,
+ TriggerTermSetRef triggerSetRef,
+ const TaggedEqualitiesSet& disequalitiesToNotify)
+{
// No tags, no food
if (!tags) {
return !d_done;
@@ -2265,8 +2539,8 @@ bool EqualityEngine::propagateTriggerTermDisequalities(Theory::Set tags, Trigger
const TaggedEquality& disequalityInfo = *it;
const TriggerTermSet& disequalityTriggerSet =
getTriggerTermSet(disequalityInfo.d_triggerSetRef);
- Theory::Set commonTags =
- Theory::setIntersection(disequalityTriggerSet.d_tags, tags);
+ TheoryIdSet commonTags =
+ TheoryIdSetUtil::setIntersection(disequalityTriggerSet.d_tags, tags);
Assert(commonTags);
// This is the actual function
const FunctionApplication& fun =
@@ -2281,7 +2555,10 @@ bool EqualityEngine::propagateTriggerTermDisequalities(Theory::Set tags, Trigger
}
// Go through the tags, and add the disequalities
TheoryId currentTag;
- while (!d_done && ((currentTag = Theory::setPop(commonTags)) != THEORY_LAST)) {
+ while (
+ !d_done
+ && ((currentTag = TheoryIdSetUtil::setPop(commonTags)) != THEORY_LAST))
+ {
// Get the tag representative
EqualityNodeId tagRep = disequalityTriggerSet.getTrigger(currentTag);
EqualityNodeId myRep = triggerSet.getTrigger(currentTag);
@@ -2309,107 +2586,14 @@ bool EqualityEngine::propagateTriggerTermDisequalities(Theory::Set tags, Trigger
return !d_done;
}
-EqClassesIterator::EqClassesIterator() :
- d_ee(NULL), d_it(0) {
-}
-
-EqClassesIterator::EqClassesIterator(const eq::EqualityEngine* ee)
-: d_ee(ee)
+TheoryIdSet EqualityEngine::TriggerTermSet::hasTrigger(TheoryId tag) const
{
- Assert(d_ee->consistent());
- d_it = 0;
- // Go to the first non-internal node that is it's own representative
- if(d_it < d_ee->d_nodesCount && (d_ee->d_isInternal[d_it] || d_ee->getEqualityNode(d_it).getFind() != d_it)) {
- ++d_it;
- }
-}
-
-Node EqClassesIterator::operator*() const {
- return d_ee->d_nodes[d_it];
-}
-
-bool EqClassesIterator::operator==(const EqClassesIterator& i) const {
- return d_ee == i.d_ee && d_it == i.d_it;
-}
-
-bool EqClassesIterator::operator!=(const EqClassesIterator& i) const {
- return !(*this == i);
-}
-
-EqClassesIterator& EqClassesIterator::operator++() {
- ++d_it;
- while(d_it < d_ee->d_nodesCount && (d_ee->d_isInternal[d_it] || d_ee->getEqualityNode(d_it).getFind() != d_it)) {
- ++d_it;
- }
- return *this;
-}
-
-EqClassesIterator EqClassesIterator::operator++(int) {
- EqClassesIterator i = *this;
- ++*this;
- return i;
+ return TheoryIdSetUtil::setContains(tag, d_tags);
}
-bool EqClassesIterator::isFinished() const {
- return d_it >= d_ee->d_nodesCount;
-}
-
-EqClassIterator::EqClassIterator()
-: d_ee(NULL)
-, d_start(null_id)
-, d_current(null_id)
-{}
-
-EqClassIterator::EqClassIterator(Node eqc, const eq::EqualityEngine* ee)
-: d_ee(ee)
+EqualityNodeId EqualityEngine::TriggerTermSet::getTrigger(TheoryId tag) const
{
- Assert(d_ee->consistent());
- d_current = d_start = d_ee->getNodeId(eqc);
- Assert(d_start == d_ee->getEqualityNode(d_start).getFind());
- Assert(!d_ee->d_isInternal[d_start]);
-}
-
-Node EqClassIterator::operator*() const {
- return d_ee->d_nodes[d_current];
-}
-
-bool EqClassIterator::operator==(const EqClassIterator& i) const {
- return d_ee == i.d_ee && d_current == i.d_current;
-}
-
-bool EqClassIterator::operator!=(const EqClassIterator& i) const {
- return !(*this == i);
-}
-
-EqClassIterator& EqClassIterator::operator++() {
- Assert(!isFinished());
-
- Assert(d_start == d_ee->getEqualityNode(d_current).getFind());
- Assert(!d_ee->d_isInternal[d_current]);
-
- // Find the next one
- do {
- d_current = d_ee->getEqualityNode(d_current).getNext();
- } while(d_ee->d_isInternal[d_current]);
-
- Assert(d_start == d_ee->getEqualityNode(d_current).getFind());
- Assert(!d_ee->d_isInternal[d_current]);
-
- if(d_current == d_start) {
- // we end when we have cycled back to the original representative
- d_current = null_id;
- }
- return *this;
-}
-
-EqClassIterator EqClassIterator::operator++(int) {
- EqClassIterator i = *this;
- ++*this;
- return i;
-}
-
-bool EqClassIterator::isFinished() const {
- return d_current == null_id;
+ return d_triggers[TheoryIdSetUtil::setIndex(tag, d_tags)];
}
} // Namespace uf
diff --git a/src/theory/uf/equality_engine.h b/src/theory/uf/equality_engine.h
index 6b1f3b6aa..70d5389c1 100644
--- a/src/theory/uf/equality_engine.h
+++ b/src/theory/uf/equality_engine.h
@@ -5,7 +5,7 @@
** Dejan Jovanovic, Andrew Reynolds, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -17,7 +17,8 @@
#include "cvc4_private.h"
-#pragma once
+#ifndef CVC4__THEORY__UF__EQUALITY_ENGINE_H
+#define CVC4__THEORY__UF__EQUALITY_ENGINE_H
#include <deque>
#include <queue>
@@ -31,8 +32,10 @@
#include "expr/kind_map.h"
#include "expr/node.h"
#include "theory/rewriter.h"
-#include "theory/theory.h"
+#include "theory/theory_id.h"
#include "theory/uf/eq_proof.h"
+#include "theory/uf/equality_engine_iterator.h"
+#include "theory/uf/equality_engine_notify.h"
#include "theory/uf/equality_engine_types.h"
#include "util/statistics_registry.h"
@@ -40,135 +43,10 @@ namespace CVC4 {
namespace theory {
namespace eq {
-
-class EqProof;
class EqClassesIterator;
class EqClassIterator;
/**
- * Interface for equality engine notifications. All the notifications
- * are safe as TNodes, but not necessarily for negations.
- */
-class EqualityEngineNotify {
-
- friend class EqualityEngine;
-
-public:
-
- virtual ~EqualityEngineNotify() {};
-
- /**
- * Notifies about a trigger equality that became true or false.
- *
- * @param equality the equality that became true or false
- * @param value the value of the equality
- */
- virtual bool eqNotifyTriggerEquality(TNode equality, bool value) = 0;
-
- /**
- * Notifies about a trigger predicate that became true or false.
- *
- * @param predicate the trigger predicate that became true or false
- * @param value the value of the predicate
- */
- virtual bool eqNotifyTriggerPredicate(TNode predicate, bool value) = 0;
-
- /**
- * Notifies about the merge of two trigger terms.
- *
- * @param tag the theory that both triggers were tagged with
- * @param t1 a term marked as trigger
- * @param t2 a term marked as trigger
- * @param value true if equal, false if dis-equal
- */
- virtual bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) = 0;
-
- /**
- * Notifies about the merge of two constant terms. After this, all work is suspended and all you
- * can do is ask for explanations.
- *
- * @param t1 a constant term
- * @param t2 a constant term
- */
- virtual void eqNotifyConstantTermMerge(TNode t1, TNode t2) = 0;
-
- /**
- * Notifies about the creation of a new equality class.
- *
- * @param t the term forming the new class
- */
- virtual void eqNotifyNewClass(TNode t) = 0;
-
- /**
- * Notifies about the merge of two classes (just before the merge).
- *
- * @param t1 a term
- * @param t2 a term
- */
- virtual void eqNotifyPreMerge(TNode t1, TNode t2) = 0;
-
- /**
- * Notifies about the merge of two classes (just after the merge).
- *
- * @param t1 a term
- * @param t2 a term
- */
- virtual void eqNotifyPostMerge(TNode t1, TNode t2) = 0;
-
- /**
- * Notifies about the disequality of two terms.
- *
- * @param t1 a term
- * @param t2 a term
- * @param reason the reason
- */
- virtual void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) = 0;
-
-};/* class EqualityEngineNotify */
-
-/**
- * Implementation of the notification interface that ignores all the
- * notifications.
- */
-class EqualityEngineNotifyNone : public EqualityEngineNotify {
-public:
- bool eqNotifyTriggerEquality(TNode equality, bool value) override
- {
- return true;
- }
- bool eqNotifyTriggerPredicate(TNode predicate, bool value) override
- {
- return true;
- }
- bool eqNotifyTriggerTermEquality(TheoryId tag,
- TNode t1,
- TNode t2,
- bool value) override
- {
- return true;
- }
- void eqNotifyConstantTermMerge(TNode t1, TNode t2) override {}
- void eqNotifyNewClass(TNode t) override {}
- void eqNotifyPreMerge(TNode t1, TNode t2) override {}
- void eqNotifyPostMerge(TNode t1, TNode t2) override {}
- void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override {}
-};/* class EqualityEngineNotifyNone */
-
-/**
- * An interface for equality engine notifications during equality path reconstruction.
- * Can be used to add theory-specific logic for, e.g., proof construction.
- */
-class PathReconstructionNotify {
-public:
-
- virtual ~PathReconstructionNotify() {}
-
- virtual void notify(unsigned reasonType, Node reason, Node a, Node b,
- std::vector<TNode>& equalities,
- EqProof* proof) const = 0;
-};
-
-/**
* Class for keeping an incremental congruence closure over a set of terms. It provides
* notifications via an EqualityEngineNotify object.
*/
@@ -186,17 +64,26 @@ class EqualityEngine : public context::ContextNotifyObj {
*/
EqualityEngine* d_masterEqualityEngine;
-public:
-
+ public:
/**
* Initialize the equality engine, given the notification class.
+ *
+ * @param constantTriggers Whether we treat constants as trigger terms
+ * @param anyTermTriggers Whether we use any terms as triggers
*/
- EqualityEngine(EqualityEngineNotify& notify, context::Context* context, std::string name, bool constantsAreTriggers);
+ EqualityEngine(EqualityEngineNotify& notify,
+ context::Context* context,
+ std::string name,
+ bool constantTriggers,
+ bool anyTermTriggers = true);
/**
* Initialize the equality engine with no notification class.
*/
- EqualityEngine(context::Context* context, std::string name, bool constantsAreTriggers);
+ EqualityEngine(context::Context* context,
+ std::string name,
+ bool constantsAreTriggers,
+ bool anyTermTriggers = true);
/**
* Just a destructor.
@@ -204,13 +91,14 @@ public:
virtual ~EqualityEngine();
/**
- * Set the master equality engine for this one. Master engine will get copies of all
- * the terms and equalities from this engine.
+ * Set the master equality engine for this one. Master engine will get copies
+ * of all the terms and equalities from this engine.
*/
void setMasterEqualityEngine(EqualityEngine* master);
/** Statistics about the equality engine instance */
- struct Statistics {
+ struct Statistics
+ {
/** Total number of merges */
IntStat d_mergesCount;
/** Number of terms managed by the system */
@@ -248,9 +136,6 @@ private:
/** The map of kinds with operators to be considered external (for higher-order) */
KindMap d_congruenceKindsExtOperators;
- /** Objects that need to be notified during equality path reconstruction */
- std::map<unsigned, const PathReconstructionNotify*> d_pathReconstructionTriggers;
-
/** Map from nodes to their ids */
std::unordered_map<TNode, EqualityNodeId, TNodeHashFunction> d_nodeIds;
@@ -292,9 +177,6 @@ private:
/** Memory for the use-list nodes */
std::vector<UseListNode> d_useListNodes;
- /** A fresh merge reason type to return upon request */
- unsigned d_freshMergeReasonType;
-
/**
* We keep a list of asserted equalities. Not among original terms, but
* among the class representatives.
@@ -521,6 +403,23 @@ private:
/** Are we in propagate */
bool d_inPropagate;
+ /** Proof-new specific construction of equality conclusions for EqProofs
+ *
+ * Given two equality node ids, build an equality between the nodes they
+ * correspond to and add it as a conclusion to the given EqProof.
+ *
+ * The equality is only built if the nodes the ids correspond to are not
+ * internal nodes in the equality engine, i.e., they correspond to full
+ * applications of the respective kinds. Since the equality engine also
+ * applies congruence over n-ary kinds, internal nodes, i.e., partial
+ * applications, may still correspond to "full applications" in the
+ * first-order sense. Therefore this method also checks, in the case of n-ary
+ * congruence kinds, if an equality between "full applications" can be built.
+ */
+ void buildEqConclusion(EqualityNodeId id1,
+ EqualityNodeId id2,
+ EqProof* eqp) const;
+
/**
* Get an explanation of the equality t1 = t2. Returns the asserted equalities
* that imply t1 = t2. Returns TNodes as the assertion equalities should be
@@ -579,22 +478,22 @@ private:
/** Set of trigger terms */
struct TriggerTermSet {
/** Set of theories in this set */
- Theory::Set d_tags;
+ TheoryIdSet d_tags;
/** The trigger terms */
EqualityNodeId d_triggers[0];
/** Returns the theory tags */
- Theory::Set hasTrigger(TheoryId tag) const
- {
- return Theory::setContains(tag, d_tags);
- }
+ TheoryIdSet hasTrigger(TheoryId tag) const;
/** Returns a trigger by tag */
- EqualityNodeId getTrigger(TheoryId tag) const {
- return d_triggers[Theory::setIndex(tag, d_tags)];
- }
+ EqualityNodeId getTrigger(TheoryId tag) const;
};/* struct EqualityEngine::TriggerTermSet */
/** Are the constants triggers */
bool d_constantsAreTriggers;
+ /**
+ * Are any terms triggers? If this is false, then all trigger terms are
+ * ignored (e.g. this means that addTriggerTerm is equivalent to addTerm).
+ */
+ bool d_anyTermsAreTriggers;
/** The information about trigger terms is stored in this easily maintained memory. */
char* d_triggerDatabase;
@@ -609,7 +508,9 @@ private:
static const TriggerTermSetRef null_set_id = (TriggerTermSetRef)(-1);
/** Create new trigger term set based on the internally set information */
- TriggerTermSetRef newTriggerTermSet(Theory::Set newSetTags, EqualityNodeId* newSetTriggers, unsigned newSetTriggersSize);
+ TriggerTermSetRef newTriggerTermSet(TheoryIdSet newSetTags,
+ EqualityNodeId* newSetTriggers,
+ unsigned newSetTriggersSize);
/** Get the trigger set give a reference */
TriggerTermSet& getTriggerTermSet(TriggerTermSetRef ref) {
@@ -681,7 +582,9 @@ private:
/**
* Map from equalities to the tags that have received the notification.
*/
- typedef context::CDHashMap<EqualityPair, Theory::Set, EqualityPairHashFunction> PropagatedDisequalitiesMap;
+ typedef context::
+ CDHashMap<EqualityPair, TheoryIdSet, EqualityPairHashFunction>
+ PropagatedDisequalitiesMap;
PropagatedDisequalitiesMap d_propagatedDisequalities;
/**
@@ -733,23 +636,34 @@ private:
* @param inputTags the tags to filter the equalities
* @param out the output equalities, as described above
*/
- void getDisequalities(bool allowConstants, EqualityNodeId classId, Theory::Set inputTags, TaggedEqualitiesSet& out);
+ void getDisequalities(bool allowConstants,
+ EqualityNodeId classId,
+ TheoryIdSet inputTags,
+ TaggedEqualitiesSet& out);
/**
* Propagates the remembered disequalities with given tags the original triggers for those tags,
* and the set of disequalities produced by above.
*/
- bool propagateTriggerTermDisequalities(Theory::Set tags,
- TriggerTermSetRef triggerSetRef, const TaggedEqualitiesSet& disequalitiesToNotify);
+ bool propagateTriggerTermDisequalities(
+ TheoryIdSet tags,
+ TriggerTermSetRef triggerSetRef,
+ const TaggedEqualitiesSet& disequalitiesToNotify);
/** Name of the equality engine */
std::string d_name;
/** The internal addTerm */
void addTermInternal(TNode t, bool isOperator = false);
+ /**
+ * Adds a notify trigger for equality. When equality becomes true
+ * eqNotifyTriggerPredicate will be called with value = true, and when
+ * equality becomes false eqNotifyTriggerPredicate will be called with value =
+ * false.
+ */
+ void addTriggerEquality(TNode equality);
-public:
-
+ public:
/**
* Adds a term to the term database.
*/
@@ -801,8 +715,12 @@ public:
* @param polarity true if asserting the predicate, false if
* asserting the negated predicate
* @param reason the reason to keep for building explanations
+ * @return true if a new fact was asserted, false if this call was a no-op.
*/
- void assertPredicate(TNode p, bool polarity, TNode reason, unsigned pid = MERGED_THROUGH_EQUALITY);
+ bool assertPredicate(TNode p,
+ bool polarity,
+ TNode reason,
+ unsigned pid = MERGED_THROUGH_EQUALITY);
/**
* Adds an equality eq with the given polarity to the database.
@@ -811,8 +729,12 @@ public:
* @param polarity true if asserting the equality, false if
* asserting the negated equality
* @param reason the reason to keep for building explanations
+ * @return true if a new fact was asserted, false if this call was a no-op.
*/
- void assertEquality(TNode eq, bool polarity, TNode reason, unsigned pid = MERGED_THROUGH_EQUALITY);
+ bool assertEquality(TNode eq,
+ bool polarity,
+ TNode reason,
+ unsigned pid = MERGED_THROUGH_EQUALITY);
/**
* Returns the current representative of the term t.
@@ -842,6 +764,22 @@ public:
void explainPredicate(TNode p, bool polarity, std::vector<TNode>& assertions,
EqProof* eqp = nullptr) const;
+ //--------------------------- standard safe explanation methods
+ /**
+ * Explain literal, add its explanation to assumptions. This method does not
+ * add duplicates to assumptions. It requires that the literal
+ * holds in this class. If lit is a disequality, it
+ * moreover ensures this class is ready to explain it via areDisequal with
+ * ensureProof = true.
+ */
+ void explainLit(TNode lit, std::vector<TNode>& assumptions);
+ /**
+ * Explain literal, return the explanation as a conjunction. This method
+ * relies on the above method.
+ */
+ Node mkExplainLit(TNode lit);
+ //--------------------------- end standard safe explanation methods
+
/**
* Add term to the set of trigger terms with a corresponding tag. The notify class will get
* notified when two trigger terms with the same tag become equal or dis-equal. The notification
@@ -868,16 +806,13 @@ public:
TNode getTriggerTermRepresentative(TNode t, TheoryId theoryTag) const;
/**
- * Adds a notify trigger for equality. When equality becomes true eqNotifyTriggerEquality
- * will be called with value = true, and when equality becomes false eqNotifyTriggerEquality
- * will be called with value = false.
- */
- void addTriggerEquality(TNode equality);
-
- /**
- * Adds a notify trigger for the predicate p. When the predicate becomes true
- * eqNotifyTriggerPredicate will be called with value = true, and when equality becomes false
+ * Adds a notify trigger for the predicate p, where notice that p can be
+ * an equality. When the predicate becomes true, eqNotifyTriggerPredicate will
+ * be called with value = true, and when predicate becomes false
* eqNotifyTriggerPredicate will be called with value = false.
+ *
+ * Notice that if p is an equality, then we use a separate method for
+ * determining when to call eqNotifyTriggerPredicate.
*/
void addTriggerPredicate(TNode predicate);
@@ -904,54 +839,12 @@ public:
*/
bool consistent() const { return !d_done; }
- /**
- * Marks an object for merge type based notification during equality path reconstruction.
- */
- void addPathReconstructionTrigger(unsigned trigger, const PathReconstructionNotify* notify);
-
- /**
- * Returns a fresh merge reason type tag for the client to use.
- */
- unsigned getFreshMergeReasonType();
+ /** Identify this equality engine (for debugging, etc..) */
+ std::string identify() const;
};
-/**
- * Iterator to iterate over the equivalence classes.
- */
-class EqClassesIterator {
- const eq::EqualityEngine* d_ee;
- size_t d_it;
-public:
- EqClassesIterator();
- EqClassesIterator(const eq::EqualityEngine* ee);
- Node operator*() const;
- bool operator==(const EqClassesIterator& i) const;
- bool operator!=(const EqClassesIterator& i) const;
- EqClassesIterator& operator++();
- EqClassesIterator operator++(int);
- bool isFinished() const;
-};/* class EqClassesIterator */
-
-/**
- * Iterator to iterate over the equivalence class members.
- */
-class EqClassIterator {
- const eq::EqualityEngine* d_ee;
- /** Starting node */
- EqualityNodeId d_start;
- /** Current node */
- EqualityNodeId d_current;
-public:
- EqClassIterator();
- EqClassIterator(Node eqc, const eq::EqualityEngine* ee);
- Node operator*() const;
- bool operator==(const EqClassIterator& i) const;
- bool operator!=(const EqClassIterator& i) const;
- EqClassIterator& operator++();
- EqClassIterator operator++(int);
- bool isFinished() const;
-};/* class EqClassIterator */
-
} // Namespace eq
} // Namespace theory
} // Namespace CVC4
+
+#endif
diff --git a/src/theory/uf/equality_engine_iterator.cpp b/src/theory/uf/equality_engine_iterator.cpp
new file mode 100644
index 000000000..0472d44b3
--- /dev/null
+++ b/src/theory/uf/equality_engine_iterator.cpp
@@ -0,0 +1,135 @@
+/********************* */
+/*! \file equality_engine_iterator.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Dejan Jovanovic, Morgan Deters
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of iterator class for equality engine
+ **/
+
+#include "theory/uf/equality_engine_iterator.h"
+
+#include "theory/uf/equality_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace eq {
+
+EqClassesIterator::EqClassesIterator() : d_ee(nullptr), d_it(0) {}
+
+EqClassesIterator::EqClassesIterator(const eq::EqualityEngine* ee) : d_ee(ee)
+{
+ Assert(d_ee->consistent());
+ d_it = 0;
+ // Go to the first non-internal node that is it's own representative
+ if (d_it < d_ee->d_nodesCount
+ && (d_ee->d_isInternal[d_it]
+ || d_ee->getEqualityNode(d_it).getFind() != d_it))
+ {
+ ++d_it;
+ }
+}
+
+Node EqClassesIterator::operator*() const { return d_ee->d_nodes[d_it]; }
+
+bool EqClassesIterator::operator==(const EqClassesIterator& i) const
+{
+ return d_ee == i.d_ee && d_it == i.d_it;
+}
+
+bool EqClassesIterator::operator!=(const EqClassesIterator& i) const
+{
+ return !(*this == i);
+}
+
+EqClassesIterator& EqClassesIterator::operator++()
+{
+ ++d_it;
+ while (d_it < d_ee->d_nodesCount
+ && (d_ee->d_isInternal[d_it]
+ || d_ee->getEqualityNode(d_it).getFind() != d_it))
+ {
+ ++d_it;
+ }
+ return *this;
+}
+
+EqClassesIterator EqClassesIterator::operator++(int)
+{
+ EqClassesIterator i = *this;
+ ++*this;
+ return i;
+}
+
+bool EqClassesIterator::isFinished() const
+{
+ return d_it >= d_ee->d_nodesCount;
+}
+
+EqClassIterator::EqClassIterator()
+ : d_ee(nullptr), d_start(null_id), d_current(null_id)
+{
+}
+
+EqClassIterator::EqClassIterator(Node eqc, const eq::EqualityEngine* ee)
+ : d_ee(ee)
+{
+ Assert(d_ee->consistent());
+ d_current = d_start = d_ee->getNodeId(eqc);
+ Assert(d_start == d_ee->getEqualityNode(d_start).getFind());
+ Assert(!d_ee->d_isInternal[d_start]);
+}
+
+Node EqClassIterator::operator*() const { return d_ee->d_nodes[d_current]; }
+
+bool EqClassIterator::operator==(const EqClassIterator& i) const
+{
+ return d_ee == i.d_ee && d_current == i.d_current;
+}
+
+bool EqClassIterator::operator!=(const EqClassIterator& i) const
+{
+ return !(*this == i);
+}
+
+EqClassIterator& EqClassIterator::operator++()
+{
+ Assert(!isFinished());
+
+ Assert(d_start == d_ee->getEqualityNode(d_current).getFind());
+ Assert(!d_ee->d_isInternal[d_current]);
+
+ // Find the next one
+ do
+ {
+ d_current = d_ee->getEqualityNode(d_current).getNext();
+ } while (d_ee->d_isInternal[d_current]);
+
+ Assert(d_start == d_ee->getEqualityNode(d_current).getFind());
+ Assert(!d_ee->d_isInternal[d_current]);
+
+ if (d_current == d_start)
+ {
+ // we end when we have cycled back to the original representative
+ d_current = null_id;
+ }
+ return *this;
+}
+
+EqClassIterator EqClassIterator::operator++(int)
+{
+ EqClassIterator i = *this;
+ ++*this;
+ return i;
+}
+
+bool EqClassIterator::isFinished() const { return d_current == null_id; }
+
+} // namespace eq
+} // Namespace theory
+} // Namespace CVC4
diff --git a/src/theory/uf/equality_engine_iterator.h b/src/theory/uf/equality_engine_iterator.h
new file mode 100644
index 000000000..f0c7b97da
--- /dev/null
+++ b/src/theory/uf/equality_engine_iterator.h
@@ -0,0 +1,84 @@
+/********************* */
+/*! \file equality_engine_iterator.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Dejan Jovanovic, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Iterator class for equality engine
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__UF__EQUALITY_ENGINE_ITERATOR_H
+#define CVC4__THEORY__UF__EQUALITY_ENGINE_ITERATOR_H
+
+#include "expr/node.h"
+#include "theory/uf/equality_engine_types.h"
+
+namespace CVC4 {
+namespace theory {
+namespace eq {
+
+class EqualityEngine;
+
+/**
+ * Iterator to iterate over all the equivalence classes in an equality engine.
+ */
+class EqClassesIterator
+{
+ public:
+ EqClassesIterator();
+ EqClassesIterator(const eq::EqualityEngine* ee);
+ Node operator*() const;
+ bool operator==(const EqClassesIterator& i) const;
+ bool operator!=(const EqClassesIterator& i) const;
+ EqClassesIterator& operator++();
+ EqClassesIterator operator++(int);
+ bool isFinished() const;
+
+ private:
+ /** Pointer to the equality engine we are iterating over */
+ const eq::EqualityEngine* d_ee;
+ /** The iterator value */
+ size_t d_it;
+};
+
+/**
+ * Iterator to iterate over the equivalence class members in a particular
+ * equivalence class.
+ */
+class EqClassIterator
+{
+ public:
+ EqClassIterator();
+ /**
+ * Iterate over equivalence class eqc, where eqc must be a representative of
+ * argument ee.
+ */
+ EqClassIterator(Node eqc, const eq::EqualityEngine* ee);
+ Node operator*() const;
+ bool operator==(const EqClassIterator& i) const;
+ bool operator!=(const EqClassIterator& i) const;
+ EqClassIterator& operator++();
+ EqClassIterator operator++(int);
+ bool isFinished() const;
+
+ private:
+ /** Pointer to the equality engine we are iterating over */
+ const eq::EqualityEngine* d_ee;
+ /** Starting node */
+ EqualityNodeId d_start;
+ /** Current node */
+ EqualityNodeId d_current;
+};
+
+} // Namespace eq
+} // Namespace theory
+} // Namespace CVC4
+
+#endif
diff --git a/src/theory/uf/equality_engine_notify.h b/src/theory/uf/equality_engine_notify.h
new file mode 100644
index 000000000..1f7104d32
--- /dev/null
+++ b/src/theory/uf/equality_engine_notify.h
@@ -0,0 +1,120 @@
+/********************* */
+/*! \file equality_engine_notify.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds, Morgan Deters, Dejan Jovanovic
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The virtual class for notifications from the equality engine.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__UF__EQUALITY_ENGINE_NOTIFY_H
+#define CVC4__THEORY__UF__EQUALITY_ENGINE_NOTIFY_H
+
+#include "expr/node.h"
+
+namespace CVC4 {
+namespace theory {
+namespace eq {
+
+/**
+ * Interface for equality engine notifications. All the notifications
+ * are safe as TNodes, but not necessarily for negations.
+ */
+class EqualityEngineNotify
+{
+ public:
+ virtual ~EqualityEngineNotify(){};
+
+ /**
+ * Notifies about a trigger predicate that became true or false. Notice that
+ * predicate can be an equality.
+ *
+ * @param predicate the trigger predicate that became true or false
+ * @param value the value of the predicate
+ */
+ virtual bool eqNotifyTriggerPredicate(TNode predicate, bool value) = 0;
+
+ /**
+ * Notifies about the merge of two trigger terms.
+ *
+ * @param tag the theory that both triggers were tagged with
+ * @param t1 a term marked as trigger
+ * @param t2 a term marked as trigger
+ * @param value true if equal, false if dis-equal
+ */
+ virtual bool eqNotifyTriggerTermEquality(TheoryId tag,
+ TNode t1,
+ TNode t2,
+ bool value) = 0;
+
+ /**
+ * Notifies about the merge of two constant terms. After this, all work is
+ * suspended and all you can do is ask for explanations.
+ *
+ * @param t1 a constant term
+ * @param t2 a constant term
+ */
+ virtual void eqNotifyConstantTermMerge(TNode t1, TNode t2) = 0;
+
+ /**
+ * Notifies about the creation of a new equality class.
+ *
+ * @param t the term forming the new class
+ */
+ virtual void eqNotifyNewClass(TNode t) = 0;
+
+ /**
+ * Notifies about the merge of two classes (just after the merge).
+ *
+ * @param t1 a term
+ * @param t2 a term
+ */
+ virtual void eqNotifyMerge(TNode t1, TNode t2) = 0;
+
+ /**
+ * Notifies about the disequality of two terms.
+ *
+ * @param t1 a term
+ * @param t2 a term
+ * @param reason the reason
+ */
+ virtual void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) = 0;
+
+}; /* class EqualityEngineNotify */
+
+/**
+ * Implementation of the notification interface that ignores all the
+ * notifications.
+ */
+class EqualityEngineNotifyNone : public EqualityEngineNotify
+{
+ public:
+ bool eqNotifyTriggerPredicate(TNode predicate, bool value) override
+ {
+ return true;
+ }
+ bool eqNotifyTriggerTermEquality(TheoryId tag,
+ TNode t1,
+ TNode t2,
+ bool value) override
+ {
+ return true;
+ }
+ void eqNotifyConstantTermMerge(TNode t1, TNode t2) override {}
+ void eqNotifyNewClass(TNode t) override {}
+ void eqNotifyMerge(TNode t1, TNode t2) override {}
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override {}
+}; /* class EqualityEngineNotifyNone */
+
+} // Namespace eq
+} // Namespace theory
+} // Namespace CVC4
+
+#endif
diff --git a/src/theory/uf/equality_engine_types.h b/src/theory/uf/equality_engine_types.h
index 14cd80436..2fdbbffa8 100644
--- a/src/theory/uf/equality_engine_types.h
+++ b/src/theory/uf/equality_engine_types.h
@@ -2,10 +2,10 @@
/*! \file equality_engine_types.h
** \verbatim
** Top contributors (to current version):
- ** Dejan Jovanovic, Andrew Reynolds, Morgan Deters
+ ** Dejan Jovanovic, Andrew Reynolds, Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -63,20 +63,18 @@ static const EqualityEdgeId null_edge = (EqualityEdgeId)(-1);
* or a merge of an equality to false due to both sides being
* (different) constants.
*/
-enum MergeReasonType {
- /** Terms were merged due to application of congruence closure */
+enum MergeReasonType
+{
+ /** Terms were merged due to congruence */
MERGED_THROUGH_CONGRUENCE,
- /** Terms were merged due to application of pure equality */
+ /** Terms were merged due to an assumption */
MERGED_THROUGH_EQUALITY,
- /** Equality was merged to true, due to both sides of equality being in the same class */
+ /** Terms were merged due to reflexivity */
MERGED_THROUGH_REFLEXIVITY,
- /** Equality was merged to false, due to both sides of equality being a constant */
+ /** Terms were merged due to theory reasoning */
MERGED_THROUGH_CONSTANTS,
- /** (for proofs only) Equality was merged due to transitivity */
+ /** Terms were merged due to transitivity */
MERGED_THROUGH_TRANS,
-
- /** Reason types beyond this constant are theory specific reasons */
- NUMBER_OF_MERGE_REASONS
};
inline std::ostream& operator << (std::ostream& out, MergeReasonType reason) {
@@ -90,13 +88,10 @@ inline std::ostream& operator << (std::ostream& out, MergeReasonType reason) {
case MERGED_THROUGH_REFLEXIVITY:
out << "reflexivity";
break;
- case MERGED_THROUGH_CONSTANTS:
- out << "constants disequal";
- break;
+ case MERGED_THROUGH_CONSTANTS: out << "theory constants"; break;
case MERGED_THROUGH_TRANS:
out << "transitivity";
break;
-
default:
out << "[theory]";
break;
diff --git a/src/theory/uf/ho_extension.cpp b/src/theory/uf/ho_extension.cpp
index d90a02486..d7de0a025 100644
--- a/src/theory/uf/ho_extension.cpp
+++ b/src/theory/uf/ho_extension.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -18,7 +18,6 @@
#include "expr/node_algorithm.h"
#include "options/uf_options.h"
#include "theory/theory_model.h"
-#include "theory/uf/theory_uf.h"
#include "theory/uf/theory_uf_rewriter.h"
using namespace std;
@@ -28,10 +27,11 @@ namespace CVC4 {
namespace theory {
namespace uf {
-HoExtension::HoExtension(TheoryUF& p,
- context::Context* c,
- context::UserContext* u)
- : d_parent(p), d_extensionality(u), d_uf_std_skolem(u)
+HoExtension::HoExtension(TheoryState& state, TheoryInferenceManager& im)
+ : d_state(state),
+ d_im(im),
+ d_extensionality(state.getUserContext()),
+ d_uf_std_skolem(state.getUserContext())
{
d_true = NodeManager::currentNM()->mkConst(true);
}
@@ -107,7 +107,7 @@ unsigned HoExtension::applyExtensionality(TNode deq)
Node lem = NodeManager::currentNM()->mkNode(OR, deq[0], conc);
Trace("uf-ho-lemma") << "uf-ho-lemma : extensionality : " << lem
<< std::endl;
- d_parent.getOutputChannel().lemma(lem);
+ d_im.lemma(lem);
return 1;
}
return 0;
@@ -167,7 +167,7 @@ Node HoExtension::getApplyUfForHoApply(Node node)
Trace("uf-ho-lemma")
<< "uf-ho-lemma : Skolem definition for apply-conversion : " << lem
<< std::endl;
- d_parent.getOutputChannel().lemma(lem);
+ d_im.lemma(lem);
d_uf_std_skolem[f] = new_f;
}
else
@@ -191,7 +191,7 @@ Node HoExtension::getApplyUfForHoApply(Node node)
unsigned HoExtension::checkExtensionality(TheoryModel* m)
{
- eq::EqualityEngine* ee = d_parent.getEqualityEngine();
+ eq::EqualityEngine* ee = d_state.getEqualityEngine();
NodeManager* nm = NodeManager::currentNM();
unsigned num_lemmas = 0;
bool isCollectModel = (m != nullptr);
@@ -256,7 +256,7 @@ unsigned HoExtension::checkExtensionality(TheoryModel* m)
Node lem = nm->mkNode(OR, deq.negate(), eq);
Trace("uf-ho") << "HoExtension: cmi extensionality lemma " << lem
<< std::endl;
- d_parent.getOutputChannel().lemma(lem);
+ d_im.lemma(lem);
return 1;
}
}
@@ -276,15 +276,15 @@ unsigned HoExtension::applyAppCompletion(TNode n)
{
Assert(n.getKind() == APPLY_UF);
- eq::EqualityEngine* ee = d_parent.getEqualityEngine();
+ eq::EqualityEngine* ee = d_state.getEqualityEngine();
// must expand into APPLY_HO version if not there already
Node ret = TheoryUfRewriter::getHoApplyForApplyUf(n);
if (!ee->hasTerm(ret) || !ee->areEqual(ret, n))
{
- Node eq = ret.eqNode(n);
+ Node eq = n.eqNode(ret);
Trace("uf-ho-lemma") << "uf-ho-lemma : infer, by apply-expand : " << eq
<< std::endl;
- ee->assertEquality(eq, true, d_true);
+ d_im.assertInternalFact(eq, true, PfRule::HO_APP_ENCODE, {}, {n});
return 1;
}
Trace("uf-ho-debug") << " ...already have " << ret << " == " << n << "."
@@ -297,7 +297,7 @@ unsigned HoExtension::checkAppCompletion()
Trace("uf-ho") << "HoExtension::checkApplyCompletion..." << std::endl;
// compute the operators that are relevant (those for which an HO_APPLY exist)
std::set<TNode> rlvOp;
- eq::EqualityEngine* ee = d_parent.getEqualityEngine();
+ eq::EqualityEngine* ee = d_state.getEqualityEngine();
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator(ee);
std::map<TNode, std::vector<Node> > apply_uf;
while (!eqcs_i.isFinished())
@@ -388,7 +388,7 @@ unsigned HoExtension::check()
do
{
num_facts = checkAppCompletion();
- if (d_parent.inConflict())
+ if (d_state.isInConflict())
{
Trace("uf-ho") << "...conflict during app-completion." << std::endl;
return 1;
@@ -413,7 +413,8 @@ unsigned HoExtension::check()
return 0;
}
-bool HoExtension::collectModelInfoHo(std::set<Node>& termSet, TheoryModel* m)
+bool HoExtension::collectModelInfoHo(TheoryModel* m,
+ const std::set<Node>& termSet)
{
for (std::set<Node>::iterator it = termSet.begin(); it != termSet.end(); ++it)
{
@@ -440,7 +441,7 @@ bool HoExtension::collectModelInfoHoTerm(Node n, TheoryModel* m)
Node eq = n.eqNode(hn);
Trace("uf-ho") << "HoExtension: cmi app completion lemma " << eq
<< std::endl;
- d_parent.getOutputChannel().lemma(eq);
+ d_im.lemma(eq);
return false;
}
}
diff --git a/src/theory/uf/ho_extension.h b/src/theory/uf/ho_extension.h
index d00372c98..fa9c5c612 100644
--- a/src/theory/uf/ho_extension.h
+++ b/src/theory/uf/ho_extension.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -21,7 +21,9 @@
#include "context/cdhashset.h"
#include "context/cdo.h"
#include "expr/node.h"
+#include "theory/theory_inference_manager.h"
#include "theory/theory_model.h"
+#include "theory/theory_state.h"
namespace CVC4 {
namespace theory {
@@ -50,7 +52,7 @@ class HoExtension
typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
public:
- HoExtension(TheoryUF& p, context::Context* c, context::UserContext* u);
+ HoExtension(TheoryState& state, TheoryInferenceManager& im);
/** expand definition
*
@@ -110,7 +112,7 @@ class HoExtension
* values in m. It returns false if any (dis)equality added to m led to
* an inconsistency in m.
*/
- bool collectModelInfoHo(std::set<Node>& termSet, TheoryModel* m);
+ bool collectModelInfoHo(TheoryModel* m, const std::set<Node>& termSet);
protected:
/** get apply uf for ho apply
@@ -180,8 +182,10 @@ class HoExtension
private:
/** common constants */
Node d_true;
- /** the parent of this extension */
- TheoryUF& d_parent;
+ /** Reference to the state object */
+ TheoryState& d_state;
+ /** Reference to the inference manager */
+ TheoryInferenceManager& d_im;
/** extensionality has been applied to these disequalities */
NodeSet d_extensionality;
diff --git a/src/theory/uf/kinds b/src/theory/uf/kinds
index 109e6d0a1..9564899fe 100644
--- a/src/theory/uf/kinds
+++ b/src/theory/uf/kinds
@@ -8,7 +8,7 @@ theory THEORY_UF ::CVC4::theory::uf::TheoryUF "theory/uf/theory_uf.h"
typechecker "theory/uf/theory_uf_type_rules.h"
properties stable-infinite parametric
-properties check propagate ppStaticLearn presolve
+properties check ppStaticLearn presolve
rewriter ::CVC4::theory::uf::TheoryUfRewriter "theory/uf/theory_uf_rewriter.h"
parameterized APPLY_UF VARIABLE 1: "application of an uninterpreted function; first parameter is the function, remaining ones are parameters to that function"
diff --git a/src/theory/uf/proof_checker.cpp b/src/theory/uf/proof_checker.cpp
index f866e77dd..824386623 100644
--- a/src/theory/uf/proof_checker.cpp
+++ b/src/theory/uf/proof_checker.cpp
@@ -2,10 +2,10 @@
/*! \file proof_checker.cpp
** \verbatim
** Top contributors (to current version):
- ** Haniel Barbosa
+ ** Haniel Barbosa, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,6 +14,8 @@
#include "theory/uf/proof_checker.h"
+#include "theory/uf/theory_uf_rewriter.h"
+
using namespace CVC4::kind;
namespace CVC4 {
@@ -31,6 +33,8 @@ void UfProofRuleChecker::registerTo(ProofChecker* pc)
pc->registerChecker(PfRule::TRUE_ELIM, this);
pc->registerChecker(PfRule::FALSE_INTRO, this);
pc->registerChecker(PfRule::FALSE_ELIM, this);
+ pc->registerChecker(PfRule::HO_CONG, this);
+ pc->registerChecker(PfRule::HO_APP_ENCODE, this);
}
Node UfProofRuleChecker::checkInternal(PfRule id,
@@ -86,15 +90,15 @@ Node UfProofRuleChecker::checkInternal(PfRule id,
else if (id == PfRule::CONG)
{
Assert(children.size() > 0);
- Assert(args.size() == 1);
+ Assert(args.size() >= 1 && args.size() <= 2);
// We do congruence over builtin kinds using operatorToKind
std::vector<Node> lchildren;
std::vector<Node> rchildren;
- // get the expected kind for args[0]
- Kind k = NodeManager::getKindForFunction(args[0]);
- if (k == kind::UNDEFINED_KIND)
+ // get the kind encoded as args[0]
+ Kind k;
+ if (!getKind(args[0], k))
{
- k = NodeManager::operatorToKind(args[0]);
+ return Node::null();
}
if (k == kind::UNDEFINED_KIND)
{
@@ -104,9 +108,17 @@ Node UfProofRuleChecker::checkInternal(PfRule id,
<< ", metakind=" << kind::metaKindOf(k) << std::endl;
if (kind::metaKindOf(k) == kind::metakind::PARAMETERIZED)
{
+ if (args.size() <= 1)
+ {
+ return Node::null();
+ }
// parameterized kinds require the operator
- lchildren.push_back(args[0]);
- rchildren.push_back(args[0]);
+ lchildren.push_back(args[1]);
+ rchildren.push_back(args[1]);
+ }
+ else if (args.size() > 1)
+ {
+ return Node::null();
}
for (size_t i = 0, nchild = children.size(); i < nchild; i++)
{
@@ -163,6 +175,32 @@ Node UfProofRuleChecker::checkInternal(PfRule id,
}
return children[0][0].notNode();
}
+ if (id == PfRule::HO_CONG)
+ {
+ Assert(children.size() > 0);
+ std::vector<Node> lchildren;
+ std::vector<Node> rchildren;
+ for (size_t i = 0, nchild = children.size(); i < nchild; ++i)
+ {
+ Node eqp = children[i];
+ if (eqp.getKind() != EQUAL)
+ {
+ return Node::null();
+ }
+ lchildren.push_back(eqp[0]);
+ rchildren.push_back(eqp[1]);
+ }
+ NodeManager* nm = NodeManager::currentNM();
+ Node l = nm->mkNode(kind::APPLY_UF, lchildren);
+ Node r = nm->mkNode(kind::APPLY_UF, rchildren);
+ return l.eqNode(r);
+ }
+ else if (id == PfRule::HO_APP_ENCODE)
+ {
+ Assert(args.size() == 1);
+ Node ret = TheoryUfRewriter::getHoApplyForApplyUf(args[0]);
+ return args[0].eqNode(ret);
+ }
// no rule
return Node::null();
}
diff --git a/src/theory/uf/proof_checker.h b/src/theory/uf/proof_checker.h
index 92d853f3a..665db52ac 100644
--- a/src/theory/uf/proof_checker.h
+++ b/src/theory/uf/proof_checker.h
@@ -5,7 +5,7 @@
** Haniel Barbosa
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/uf/proof_equality_engine.cpp b/src/theory/uf/proof_equality_engine.cpp
new file mode 100644
index 000000000..6377f78b6
--- /dev/null
+++ b/src/theory/uf/proof_equality_engine.cpp
@@ -0,0 +1,548 @@
+/********************* */
+/*! \file proof_equality_engine.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of the proof-producing equality engine
+ **/
+
+#include "theory/uf/proof_equality_engine.h"
+
+#include "expr/lazy_proof_chain.h"
+#include "theory/rewriter.h"
+#include "theory/uf/proof_checker.h"
+
+using namespace CVC4::kind;
+
+namespace CVC4 {
+namespace theory {
+namespace eq {
+
+ProofEqEngine::ProofEqEngine(context::Context* c,
+ context::UserContext* u,
+ EqualityEngine& ee,
+ ProofNodeManager* pnm)
+ : EagerProofGenerator(pnm, u, "pfee::" + ee.identify()),
+ d_ee(ee),
+ d_factPg(c, pnm),
+ d_pnm(pnm),
+ d_proof(pnm, nullptr, c, "pfee::LazyCDProof::" + ee.identify()),
+ d_keep(c)
+{
+ NodeManager* nm = NodeManager::currentNM();
+ d_true = nm->mkConst(true);
+ d_false = nm->mkConst(false);
+ AlwaysAssert(pnm != nullptr)
+ << "Should not construct ProofEqEngine without proof node manager";
+}
+
+bool ProofEqEngine::assertFact(Node lit,
+ PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& args)
+{
+ Trace("pfee") << "pfee::assertFact " << lit << " " << id << ", exp = " << exp
+ << ", args = " << args << std::endl;
+
+ Node atom = lit.getKind() == NOT ? lit[0] : lit;
+ bool polarity = lit.getKind() != NOT;
+ // register the step in the proof
+ if (holds(atom, polarity))
+ {
+ // we do not process this fact if it already holds
+ return false;
+ }
+ // Buffer the step in the fact proof generator. We do this instead of
+ // adding explict steps to the lazy proof d_proof since CDProof has
+ // (at most) one proof for each formula. Thus, we "claim" only the
+ // formula that is proved by this fact. Otherwise, aliasing may occur,
+ // which leads to cyclic or bogus proofs.
+ ProofStep ps;
+ ps.d_rule = id;
+ ps.d_children = exp;
+ ps.d_args = args;
+ d_factPg.addStep(lit, ps);
+ // add lazy step to proof
+ d_proof.addLazyStep(lit, &d_factPg);
+ // second, assert it to the equality engine
+ Node reason = NodeManager::currentNM()->mkAnd(exp);
+ return assertFactInternal(atom, polarity, reason);
+}
+
+bool ProofEqEngine::assertFact(Node lit,
+ PfRule id,
+ Node exp,
+ const std::vector<Node>& args)
+{
+ Trace("pfee") << "pfee::assertFact " << lit << " " << id << ", exp = " << exp
+ << ", args = " << args << std::endl;
+ Node atom = lit.getKind() == NOT ? lit[0] : lit;
+ bool polarity = lit.getKind() != NOT;
+ // register the step in the proof
+ if (holds(atom, polarity))
+ {
+ // we do not process this fact if it already holds
+ return false;
+ }
+ // must extract the explanation as a vector
+ std::vector<Node> expv;
+ // Flatten (single occurrences) of AND. We do not allow nested AND, it is
+ // the responsibilty of the caller to ensure these do not occur.
+ if (exp != d_true)
+ {
+ if (exp.getKind() == AND)
+ {
+ for (const Node& expc : exp)
+ {
+ // should not have doubly nested AND
+ Assert(expc.getKind() != AND);
+ expv.push_back(expc);
+ }
+ }
+ else
+ {
+ expv.push_back(exp);
+ }
+ }
+ // buffer the step in the fact proof generator
+ ProofStep ps;
+ ps.d_rule = id;
+ ps.d_children = expv;
+ ps.d_args = args;
+ d_factPg.addStep(lit, ps);
+ // add lazy step to proof
+ d_proof.addLazyStep(lit, &d_factPg);
+ // second, assert it to the equality engine
+ return assertFactInternal(atom, polarity, exp);
+}
+
+bool ProofEqEngine::assertFact(Node lit, Node exp, ProofStepBuffer& psb)
+{
+ Trace("pfee") << "pfee::assertFact " << lit << ", exp = " << exp
+ << " via buffer with " << psb.getNumSteps() << " steps"
+ << std::endl;
+ Node atom = lit.getKind() == NOT ? lit[0] : lit;
+ bool polarity = lit.getKind() != NOT;
+ if (holds(atom, polarity))
+ {
+ // we do not process this fact if it already holds
+ return false;
+ }
+ // buffer the steps in the fact proof generator
+ const std::vector<std::pair<Node, ProofStep>>& steps = psb.getSteps();
+ for (const std::pair<Node, ProofStep>& step : steps)
+ {
+ d_factPg.addStep(step.first, step.second);
+ }
+ // add lazy step to proof
+ d_proof.addLazyStep(lit, &d_factPg);
+ // second, assert it to the equality engine
+ return assertFactInternal(atom, polarity, exp);
+}
+
+bool ProofEqEngine::assertFact(Node lit, Node exp, ProofGenerator* pg)
+{
+ Trace("pfee") << "pfee::assertFact " << lit << ", exp = " << exp
+ << " via generator" << std::endl;
+ Node atom = lit.getKind() == NOT ? lit[0] : lit;
+ bool polarity = lit.getKind() != NOT;
+ if (holds(atom, polarity))
+ {
+ // we do not process this fact if it already holds
+ return false;
+ }
+ // note the proof generator is responsible for remembering the explanation
+ d_proof.addLazyStep(lit, pg);
+ // second, assert it to the equality engine
+ return assertFactInternal(atom, polarity, exp);
+}
+
+TrustNode ProofEqEngine::assertConflict(Node lit)
+{
+ Trace("pfee") << "pfee::assertConflict " << lit << std::endl;
+ std::vector<TNode> assumps;
+ explainWithProof(lit, assumps, &d_proof);
+ // lit may not be equivalent to false, but should rewrite to false
+ if (lit != d_false)
+ {
+ Assert(Rewriter::rewrite(lit) == d_false)
+ << "pfee::assertConflict: conflict literal is not rewritable to "
+ "false";
+ std::vector<Node> exp;
+ exp.push_back(lit);
+ std::vector<Node> args;
+ if (!d_proof.addStep(d_false, PfRule::MACRO_SR_PRED_ELIM, exp, args))
+ {
+ Assert(false) << "pfee::assertConflict: failed conflict step";
+ return TrustNode::null();
+ }
+ }
+ return ensureProofForFact(
+ d_false, assumps, TrustNodeKind::CONFLICT, &d_proof);
+}
+
+TrustNode ProofEqEngine::assertConflict(PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& args)
+{
+ Trace("pfee") << "pfee::assertConflict " << id << ", exp = " << exp
+ << ", args = " << args << std::endl;
+ // conflict is same as lemma concluding false
+ return assertLemma(d_false, id, exp, {}, args);
+}
+
+TrustNode ProofEqEngine::assertConflict(const std::vector<Node>& exp,
+ ProofGenerator* pg)
+{
+ Assert(pg != nullptr);
+ Trace("pfee") << "pfee::assertConflict " << exp << " via generator"
+ << std::endl;
+ return assertLemma(d_false, exp, {}, pg);
+}
+
+TrustNode ProofEqEngine::assertLemma(Node conc,
+ PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& noExplain,
+ const std::vector<Node>& args)
+{
+ Trace("pfee") << "pfee::assertLemma " << conc << " " << id
+ << ", exp = " << exp << ", noExplain = " << noExplain
+ << ", args = " << args << std::endl;
+ Assert(conc != d_true);
+ LazyCDProof tmpProof(d_pnm, &d_proof);
+ LazyCDProof* curr;
+ TrustNodeKind tnk;
+ // same policy as above: for conflicts, use existing lazy proof
+ if (conc == d_false)
+ {
+ curr = &d_proof;
+ tnk = TrustNodeKind::CONFLICT;
+ }
+ else
+ {
+ curr = &tmpProof;
+ tnk = TrustNodeKind::LEMMA;
+ }
+ // explain each literal in the vector
+ std::vector<TNode> assumps;
+ explainVecWithProof(tnk, assumps, exp, noExplain, curr);
+ // Register the proof step. We use a separate lazy CDProof which will make
+ // calls to curr above for the proofs of the literals in exp.
+ LazyCDProof outer(d_pnm, curr);
+ if (!outer.addStep(conc, id, exp, args))
+ {
+ // a step went wrong, e.g. during checking
+ Assert(false) << "pfee::assertConflict: register proof step";
+ return TrustNode::null();
+ }
+ // Now get the proof for conc.
+ return ensureProofForFact(conc, assumps, tnk, &outer);
+}
+
+TrustNode ProofEqEngine::assertLemma(Node conc,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& noExplain,
+ ProofGenerator* pg)
+{
+ Assert(pg != nullptr);
+ Trace("pfee") << "pfee::assertLemma " << conc << ", exp = " << exp
+ << ", noExplain = " << noExplain << " via generator"
+ << std::endl;
+ LazyCDProof tmpProof(d_pnm, &d_proof);
+ LazyCDProof* curr;
+ TrustNodeKind tnk;
+ // same policy as above: for conflicts, use existing lazy proof
+ if (conc == d_false)
+ {
+ curr = &d_proof;
+ tnk = TrustNodeKind::CONFLICT;
+ }
+ else
+ {
+ curr = &tmpProof;
+ tnk = TrustNodeKind::LEMMA;
+ }
+ // explain each literal in the vector
+ std::vector<TNode> assumps;
+ explainVecWithProof(tnk, assumps, exp, noExplain, curr);
+ // We use a lazy proof chain here. The provided proof generator sets up the
+ // "skeleton" that is the base of the proof we are constructing. The call to
+ // LazyCDProofChain::getProofFor will expand the leaves of this proof via
+ // calls to curr.
+ LazyCDProofChain outer(d_pnm, true, nullptr, curr, false);
+ outer.addLazyStep(conc, pg);
+ return ensureProofForFact(conc, assumps, tnk, &outer);
+}
+
+TrustNode ProofEqEngine::explain(Node conc)
+{
+ Trace("pfee") << "pfee::explain " << conc << std::endl;
+ LazyCDProof tmpProof(d_pnm, &d_proof);
+ std::vector<TNode> assumps;
+ explainWithProof(conc, assumps, &tmpProof);
+ return ensureProofForFact(conc, assumps, TrustNodeKind::PROP_EXP, &tmpProof);
+}
+
+void ProofEqEngine::explainVecWithProof(TrustNodeKind& tnk,
+ std::vector<TNode>& assumps,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& noExplain,
+ LazyCDProof* curr)
+{
+ std::vector<Node> expn;
+ for (const Node& e : exp)
+ {
+ if (std::find(noExplain.begin(), noExplain.end(), e) == noExplain.end())
+ {
+ explainWithProof(e, assumps, curr);
+ }
+ else
+ {
+ // it did not have a proof; it was an assumption of the previous rule
+ assumps.push_back(e);
+ // it is not a conflict, since it may involve new literals
+ tnk = TrustNodeKind::LEMMA;
+ }
+ }
+}
+
+TrustNode ProofEqEngine::ensureProofForFact(Node conc,
+ const std::vector<TNode>& assumps,
+ TrustNodeKind tnk,
+ ProofGenerator* curr)
+{
+ Trace("pfee-proof") << std::endl;
+ Trace("pfee-proof") << "pfee::ensureProofForFact: input " << conc << " via "
+ << assumps << ", TrustNodeKind=" << tnk << std::endl;
+ NodeManager* nm = NodeManager::currentNM();
+ // The proof
+ std::shared_ptr<ProofNode> pf;
+ ProofGenerator* pfg = nullptr;
+ // the explanation is the conjunction of assumptions
+ Node exp;
+ // If proofs are enabled, generate the proof and possibly modify the
+ // assumptions to match SCOPE.
+ Assert(curr != nullptr);
+ Trace("pfee-proof") << "pfee::ensureProofForFact: make proof for fact"
+ << std::endl;
+ // get the proof for conc
+ std::shared_ptr<ProofNode> pfBody = curr->getProofFor(conc);
+ if (pfBody == nullptr)
+ {
+ Trace("pfee-proof")
+ << "pfee::ensureProofForFact: failed to make proof for fact"
+ << std::endl
+ << std::endl;
+ // should have existed
+ Assert(false) << "pfee::assertConflict: failed to get proof for " << conc;
+ return TrustNode::null();
+ }
+ // clone it so that we have a fresh copy
+ pfBody = pfBody->clone();
+ Trace("pfee-proof") << "pfee::ensureProofForFact: add scope" << std::endl;
+ // The free assumptions must be closed by assumps, which should be passed
+ // as arguments of SCOPE. However, some of the free assumptions may not
+ // literally be equal to assumps, for instance, due to symmetry. In other
+ // words, the SCOPE could be closing (= x y) in a proof with free
+ // assumption (= y x). We modify the proof leaves to account for this
+ // below.
+
+ std::vector<Node> scopeAssumps;
+ // we first ensure the assumptions are flattened
+ for (const TNode& a : assumps)
+ {
+ if (a.getKind() == AND)
+ {
+ scopeAssumps.insert(scopeAssumps.end(), a.begin(), a.end());
+ }
+ else
+ {
+ scopeAssumps.push_back(a);
+ }
+ }
+ // Scope the proof constructed above, and connect the formula with the proof
+ // minimize the assumptions.
+ pf = d_pnm->mkScope(pfBody, scopeAssumps, true, true);
+ // If we have no assumptions, and are proving an explanation for propagation
+ if (scopeAssumps.empty() && tnk == TrustNodeKind::PROP_EXP)
+ {
+ // Must add "true" as an explicit argument. This is to ensure that the
+ // propagation F from true proves (=> true F) instead of F, since this is
+ // the form required by TrustNodeKind::PROP_EXP. We do not ensure closed or
+ // minimize here, since we already ensured the proof was closed above, and
+ // we do not want to minimize, or else "true" would be omitted.
+ scopeAssumps.push_back(nm->mkConst(true));
+ pf = d_pnm->mkScope(pf, scopeAssumps, false);
+ }
+ exp = nm->mkAnd(scopeAssumps);
+ // Make the lemma or conflict node. This must exactly match the conclusion
+ // of SCOPE below.
+ Node formula;
+ if (tnk == TrustNodeKind::CONFLICT)
+ {
+ // conflict is negated
+ Assert(conc == d_false);
+ formula = exp;
+ }
+ else
+ {
+ formula =
+ exp == d_true
+ ? conc
+ : (conc == d_false ? exp.negate() : nm->mkNode(IMPLIES, exp, conc));
+ }
+ Trace("pfee-proof") << "pfee::ensureProofForFact: formula is " << formula
+ << std::endl;
+ // should always be non-null
+ Assert(pf != nullptr);
+ if (Trace.isOn("pfee-proof") || Trace.isOn("pfee-proof-final"))
+ {
+ Trace("pfee-proof") << "pfee::ensureProofForFact: printing proof"
+ << std::endl;
+ std::stringstream ss;
+ pf->printDebug(ss);
+ Trace("pfee-proof") << "pfee::ensureProofForFact: Proof is " << ss.str()
+ << std::endl;
+ }
+ // Should be a closed proof now. If it is not, then the overall proof
+ // is malformed.
+ Assert(pf->isClosed());
+ pfg = this;
+ // set the proof for the conflict or lemma, which can be queried later
+ switch (tnk)
+ {
+ case TrustNodeKind::CONFLICT: setProofForConflict(formula, pf); break;
+ case TrustNodeKind::LEMMA: setProofForLemma(formula, pf); break;
+ case TrustNodeKind::PROP_EXP: setProofForPropExp(conc, exp, pf); break;
+ default:
+ pfg = nullptr;
+ Unhandled() << "Unhandled trust node kind " << tnk;
+ break;
+ }
+ Trace("pfee-proof") << "pfee::ensureProofForFact: finish" << std::endl
+ << std::endl;
+ // we can provide a proof for conflict, lemma or explained propagation
+ switch (tnk)
+ {
+ case TrustNodeKind::CONFLICT:
+ return TrustNode::mkTrustConflict(formula, pfg);
+ case TrustNodeKind::LEMMA: return TrustNode::mkTrustLemma(formula, pfg);
+ case TrustNodeKind::PROP_EXP:
+ return TrustNode::mkTrustPropExp(conc, exp, pfg);
+ default: Unhandled() << "Unhandled trust node kind " << tnk; break;
+ }
+ return TrustNode::null();
+}
+
+bool ProofEqEngine::assertFactInternal(TNode atom, bool polarity, TNode reason)
+{
+ Trace("pfee-debug") << "pfee::assertFactInternal: " << atom << " " << polarity
+ << " " << reason << std::endl;
+ bool ret;
+ if (atom.getKind() == EQUAL)
+ {
+ ret = d_ee.assertEquality(atom, polarity, reason);
+ }
+ else
+ {
+ ret = d_ee.assertPredicate(atom, polarity, reason);
+ }
+ if (ret)
+ {
+ // must reference count the new atom and explanation
+ d_keep.insert(atom);
+ d_keep.insert(reason);
+ }
+ return ret;
+}
+
+bool ProofEqEngine::holds(TNode atom, bool polarity)
+{
+ if (atom.getKind() == EQUAL)
+ {
+ if (!d_ee.hasTerm(atom[0]) || !d_ee.hasTerm(atom[1]))
+ {
+ return false;
+ }
+ return polarity ? d_ee.areEqual(atom[0], atom[1])
+ : d_ee.areDisequal(atom[0], atom[1], false);
+ }
+ if (!d_ee.hasTerm(atom))
+ {
+ return false;
+ }
+ TNode b = polarity ? d_true : d_false;
+ return d_ee.areEqual(atom, b);
+}
+
+void ProofEqEngine::explainWithProof(Node lit,
+ std::vector<TNode>& assumps,
+ LazyCDProof* curr)
+{
+ if (std::find(assumps.begin(), assumps.end(), lit) != assumps.end())
+ {
+ return;
+ }
+ std::shared_ptr<eq::EqProof> pf = std::make_shared<eq::EqProof>();
+ Trace("pfee-proof") << "pfee::explainWithProof: " << lit << std::endl;
+ bool polarity = lit.getKind() != NOT;
+ TNode atom = polarity ? lit : lit[0];
+ Assert(atom.getKind() != AND);
+ std::vector<TNode> tassumps;
+ if (atom.getKind() == EQUAL)
+ {
+ if (atom[0] == atom[1])
+ {
+ return;
+ }
+ Assert(d_ee.hasTerm(atom[0]));
+ Assert(d_ee.hasTerm(atom[1]));
+ if (!polarity)
+ {
+ // ensure the explanation exists
+ AlwaysAssert(d_ee.areDisequal(atom[0], atom[1], true));
+ }
+ d_ee.explainEquality(atom[0], atom[1], polarity, tassumps, pf.get());
+ }
+ else
+ {
+ Assert(d_ee.hasTerm(atom));
+ d_ee.explainPredicate(atom, polarity, tassumps, pf.get());
+ }
+ Trace("pfee-proof") << "...got " << tassumps << std::endl;
+ // avoid duplicates
+ for (const TNode a : tassumps)
+ {
+ if (a == lit)
+ {
+ assumps.push_back(a);
+ }
+ else if (std::find(assumps.begin(), assumps.end(), a) == assumps.end())
+ {
+ assumps.push_back(a);
+ }
+ }
+ if (Trace.isOn("pfee-proof"))
+ {
+ Trace("pfee-proof") << "pfee::explainWithProof: add to proof ---"
+ << std::endl;
+ std::stringstream sse;
+ pf->debug_print(sse);
+ Trace("pfee-proof") << sse.str() << std::endl;
+ Trace("pfee-proof") << "---" << std::endl;
+ }
+ // add the steps in the equality engine proof to the Proof
+ pf->addToProof(curr);
+ Trace("pfee-proof") << "pfee::explainWithProof: finished" << std::endl;
+}
+
+} // namespace eq
+} // namespace theory
+} // namespace CVC4
diff --git a/src/theory/uf/proof_equality_engine.h b/src/theory/uf/proof_equality_engine.h
new file mode 100644
index 000000000..4148da1de
--- /dev/null
+++ b/src/theory/uf/proof_equality_engine.h
@@ -0,0 +1,299 @@
+/********************* */
+/*! \file proof_equality_engine.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Andrew Reynolds
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The proof-producing equality engine
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__THEORY__UF__PROOF_EQUALITY_ENGINE_H
+#define CVC4__THEORY__UF__PROOF_EQUALITY_ENGINE_H
+
+#include <map>
+#include <vector>
+
+#include "context/cdhashmap.h"
+#include "context/cdhashset.h"
+#include "expr/buffered_proof_generator.h"
+#include "expr/lazy_proof.h"
+#include "expr/node.h"
+#include "expr/proof_node.h"
+#include "expr/proof_node_manager.h"
+#include "theory/eager_proof_generator.h"
+#include "theory/uf/equality_engine.h"
+
+namespace CVC4 {
+namespace theory {
+namespace eq {
+
+/**
+ * A layer on top of an EqualityEngine. The goal of this class is manage the
+ * use of an EqualityEngine object in such a way that the proper proofs are
+ * internally constructed, and can be retrieved from this class when
+ * necessary.
+ *
+ * Notice that this class is intended to be a *partial layer* on top of
+ * equality engine. A user of this class should still issue low-level calls
+ * (getRepresentative, areEqual, areDisequal, etc.) on the underlying equality
+ * engine directly. The methods that should *not* be called directly on the
+ * underlying equality engine are:
+ * - assertEquality/assertPredicate [*]
+ * - explain
+ * Instead, the user should use variants of the above methods provided by
+ * the public interface of this class.
+ *
+ * [*] the exception is that assertions from the fact queue (who are their own
+ * explanation) should be sent directly to the underlying equality engine. This
+ * is for the sake of efficiency.
+ *
+ * This class tracks the reason for why all facts are added to an EqualityEngine
+ * in a SAT-context dependent manner in a context-dependent (CDProof) object.
+ * It furthermore maintains an internal FactProofGenerator class for managing
+ * proofs of facts whose steps are explicitly provided (those that are given
+ * concrete PfRule, children, and args). Call these "simple facts".
+ *
+ * Overall, this class is an eager proof generator (theory/proof_generator.h),
+ * in that it stores (copies) of proofs for lemmas at the moment they are sent
+ * out.
+ *
+ * A theory that is proof producing and uses the equality engine may use this
+ * class to manage proofs that are justified by its underlying equality engine.
+ * In particular, the following interfaces are available for constructing
+ * a TrustNode:
+ * - assertConflict, when the user of the equality engine has discovered that
+ * false can be derived from the current state,
+ * - assertLemma, for lemmas/conflicts that can be (partially) explained in the
+ * current state,
+ * - explain, for explaining why a literal is true in the current state.
+ * Details on these methods can be found below.
+ */
+class ProofEqEngine : public EagerProofGenerator
+{
+ typedef context::CDHashSet<Node, NodeHashFunction> NodeSet;
+ typedef context::CDHashMap<Node, std::shared_ptr<ProofNode>, NodeHashFunction>
+ NodeProofMap;
+
+ public:
+ ProofEqEngine(context::Context* c,
+ context::UserContext* u,
+ EqualityEngine& ee,
+ ProofNodeManager* pnm);
+ ~ProofEqEngine() {}
+ //-------------------------- assert fact
+ /**
+ * Assert the literal lit by proof step id, given explanation exp and
+ * arguments args. This fact is
+ *
+ * @param lit The literal to assert to the equality engine
+ * @param id The proof rule of the proof step concluding lit
+ * @param exp The premises of the proof step concluding lit. These are also
+ * the premises that are used when calling explain(lit).
+ * @param args The arguments to the proof step concluding lit.
+ * @return true if this fact was processed by this method. If lit already
+ * holds in the equality engine, this method returns false.
+ */
+ bool assertFact(Node lit,
+ PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& args);
+ /** Same as above but where exp is (conjunctive) node */
+ bool assertFact(Node lit, PfRule id, Node exp, const std::vector<Node>& args);
+ /**
+ * Multi-step version of assert fact via a proof step buffer. This method
+ * is similar to above, but the justification for lit may have multiple steps.
+ * In particular, we assume that psb has a list of proof steps where the
+ * proof step concluding lit has free assumptions exp.
+ *
+ * For example, a legal call to this method is such that:
+ * lit: A
+ * exp: B
+ * psb.d_steps: { A by (step id1 {B,C} {}), C by (step id2 {} {}) )
+ * In other words, A holds by a proof step with rule id1 and premises
+ * B and C, and C holds by proof step with rule id2 and no premises.
+ *
+ * @param lit The literal to assert to the equality engine.
+ * @param exp The premises of the proof steps concluding lit. These are also
+ * the premises that are used when calling explain(lit).
+ * @param psb The proof step buffer containing the proof steps.
+ * @return true if this fact was processed by this method. If lit already
+ * holds in the equality engine, this method returns false.
+ */
+ bool assertFact(Node lit, Node exp, ProofStepBuffer& psb);
+ /**
+ * Assert fact via generator pg. This method asserts lit with explanation exp
+ * to the equality engine of this class. It must be the case that pg can
+ * provide a proof for lit in terms of exp. More precisely, pg should be
+ * prepared in the remainder of the SAT context to respond to a call to
+ * ProofGenerator::getProofFor(lit), and return a proof whose free
+ * assumptions are a subset of the conjuncts of exp.
+ *
+ * @param lit The literal to assert to the equality engine.
+ * @param exp The premises of the proof concluding lit. These are also
+ * the premises that are used when calling explain(lit).
+ * @param pg The proof generator that can provide a proof concluding lit
+ * from free asumptions in exp.
+ * @return true if this fact was processed by this method. If lit already
+ * holds in the equality engine, this method returns false.
+ */
+ bool assertFact(Node lit, Node exp, ProofGenerator* pg);
+ //-------------------------- assert conflicts
+ /**
+ * This method is called when the equality engine of this class is
+ * inconsistent (false has been proven) by a contradictory literal lit. This
+ * returns the trust node corresponding to the current conflict.
+ *
+ * @param lit The conflicting literal, which must rewrite to false.
+ * @return The trust node capturing the fact that this class can provide a
+ * proof for this conflict.
+ */
+ TrustNode assertConflict(Node lit);
+ /**
+ * Get proven conflict from contradictory facts. This method is called when
+ * the proof rule with premises exp and arguments args implies a contradiction
+ * by proof rule id.
+ *
+ * This method returns the TrustNode containing the corresponding conflict
+ * resulting from adding this step, and ensures that a proof has been stored
+ * internally so that this class may respond to a call to
+ * ProofGenerator::getProof(...).
+ */
+ TrustNode assertConflict(PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& args);
+ /** Generator version, where pg has a proof of false from assumptions exp */
+ TrustNode assertConflict(const std::vector<Node>& exp, ProofGenerator* pg);
+ //-------------------------- assert lemma
+ /**
+ * Called when we have concluded conc, typically via theory specific
+ * reasoning. The purpose of this method is to construct a TrustNode of
+ * kind TrustNodeKind::LEMMA or TrustNodeKind::CONFLICT corresponding to the
+ * lemma or conflict to be sent on the output channel of the Theory.
+ *
+ * The user provides the explanation of conc in two parts:
+ * (1) (exp \ noExplain), which are literals that hold in the equality engine
+ * of this class,
+ * (2) noExplain, which do not necessarily hold in the equality engine of this
+ * class.
+ * Notice that noExplain is a subset of exp.
+ *
+ * The proof for conc follows from exp by proof rule with the given
+ * id and arguments.
+ *
+ * This call corresponds to a conflict if conc is false and noExplain is
+ * empty.
+ *
+ * This returns the TrustNode corresponding to the formula corresonding to
+ * the call to this method [*], for which a proof can be provided by this
+ * generator in the remainder of the user context.
+ *
+ * [*]
+ * a. If this call does not correspond to a conflict, then this formula is:
+ * ( ^_{e in exp \ noExplain} <explain>(e) ^ noExplain ) => conc
+ * where <explain>(e) is a conjunction of literals L1 ^ ... ^ Ln such that
+ * L1 ^ ... ^ Ln entail e, and each Li was passed as an explanation to a
+ * call to assertFact in the current SAT context. This explanation method
+ * always succeeds, provided that e is a literal that currently holds in
+ * the equality engine of this class. Notice that if the antecedant is empty,
+ * the formula above is assumed to be conc itself. The above formula is
+ * intended to be valid in Theory that owns this class.
+ * b. If this call is a conflict, then this formula is:
+ * ^_{e in exp} <explain>(e)
+ * The formula can be queried via TrustNode::getProven in the standard way.
+ */
+ TrustNode assertLemma(Node conc,
+ PfRule id,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& noExplain,
+ const std::vector<Node>& args);
+ /** Generator version, where pg has a proof of conc */
+ TrustNode assertLemma(Node conc,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& noExplain,
+ ProofGenerator* pg);
+ //-------------------------- explain
+ /**
+ * Explain literal conc. This calls the appropriate methods in the underlying
+ * equality engine of this class to construct the explanation of why conc
+ * currently holds.
+ *
+ * It returns a trust node of kind TrustNodeKind::PROP_EXP whose node
+ * is the explanation of conc (a conjunction of literals that implies it).
+ * The proof that can be proven by this generator is then (=> exp conc), see
+ * TrustNode::getPropExpProven(conc,exp);
+ *
+ * @param conc The conclusion to explain
+ * @return The trust node indicating the explanation of conc and the generator
+ * (this class) that can prove the implication.
+ */
+ TrustNode explain(Node conc);
+
+ private:
+ /** Assert internal */
+ bool assertFactInternal(TNode pred, bool polarity, TNode reason);
+ /** holds */
+ bool holds(TNode pred, bool polarity);
+ /**
+ * Ensure proof for fact. This is called by the above method after we have
+ * determined the final set of assumptions used for showing conc. This
+ * method is used for lemmas, conflicts, and explanations for propagations.
+ * The argument tnk is the kind of trust node to return.
+ */
+ TrustNode ensureProofForFact(Node conc,
+ const std::vector<TNode>& assumps,
+ TrustNodeKind tnk,
+ ProofGenerator* curr);
+ /**
+ * This ensures the proof of the literals that are in exp but not in
+ * noExplain have been added to curr. This additionally adds the
+ * explanation of exp to assumps. It updates tnk to LEMMA if there
+ * are any literals in exp that are not in noExplain.
+ */
+ void explainVecWithProof(TrustNodeKind& tnk,
+ std::vector<TNode>& assumps,
+ const std::vector<Node>& exp,
+ const std::vector<Node>& noExplain,
+ LazyCDProof* curr);
+ /** Explain
+ *
+ * This adds to assumps the set of facts that were asserted to this
+ * class in the current SAT context that are required for showing lit.
+ *
+ * This additionally registers the equality proof steps required to
+ * regress the explanation of lit in curr.
+ */
+ void explainWithProof(Node lit,
+ std::vector<TNode>& assumps,
+ LazyCDProof* curr);
+ /** Reference to the equality engine */
+ eq::EqualityEngine& d_ee;
+ /** The default proof generator (for simple facts) */
+ BufferedProofGenerator d_factPg;
+ /** common nodes */
+ Node d_true;
+ Node d_false;
+ /** the proof node manager */
+ ProofNodeManager* d_pnm;
+ /** The SAT-context-dependent proof object */
+ LazyCDProof d_proof;
+ /**
+ * The keep set of this class. This set is maintained to ensure that
+ * facts and their explanations are reference counted. Since facts and their
+ * explanations are SAT-context-dependent, this set is also
+ * SAT-context-dependent.
+ */
+ NodeSet d_keep;
+};
+
+} // namespace eq
+} // namespace theory
+} // namespace CVC4
+
+#endif /* CVC4__THEORY__STRINGS__PROOF_MANAGER_H */
diff --git a/src/theory/uf/symmetry_breaker.cpp b/src/theory/uf/symmetry_breaker.cpp
index c79047d85..ea87eff2b 100644
--- a/src/theory/uf/symmetry_breaker.cpp
+++ b/src/theory/uf/symmetry_breaker.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner, Liana Hadarean
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/uf/symmetry_breaker.h b/src/theory/uf/symmetry_breaker.h
index c7fc51465..f37fa3ade 100644
--- a/src/theory/uf/symmetry_breaker.h
+++ b/src/theory/uf/symmetry_breaker.h
@@ -5,7 +5,7 @@
** Morgan Deters, Liana Hadarean, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/uf/theory_uf.cpp b/src/theory/uf/theory_uf.cpp
index 5d47cef4a..099b56a33 100644
--- a/src/theory/uf/theory_uf.cpp
+++ b/src/theory/uf/theory_uf.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,9 +25,6 @@
#include "options/smt_options.h"
#include "options/theory_options.h"
#include "options/uf_options.h"
-#include "proof/proof_manager.h"
-#include "proof/theory_proof.h"
-#include "proof/uf_proof.h"
#include "theory/theory_model.h"
#include "theory/type_enumerator.h"
#include "theory/uf/cardinality_extension.h"
@@ -49,53 +46,56 @@ TheoryUF::TheoryUF(context::Context* c,
ProofNodeManager* pnm,
std::string instanceName)
: Theory(THEORY_UF, c, u, out, valuation, logicInfo, pnm, instanceName),
- d_notify(*this),
- /* The strong theory solver can be notified by EqualityEngine::init(),
- * so make sure it's initialized first. */
d_thss(nullptr),
d_ho(nullptr),
- d_equalityEngine(d_notify, c, instanceName + "theory::uf::ee", true),
- d_conflict(c, false),
d_functionsTerms(c),
- d_symb(u, instanceName)
+ d_symb(u, instanceName),
+ d_state(c, u, valuation),
+ d_im(*this, d_state, pnm),
+ d_notify(d_im, *this)
{
d_true = NodeManager::currentNM()->mkConst( true );
- // The kinds we are treating as function application in congruence
- d_equalityEngine.addFunctionKind(kind::APPLY_UF, false, options::ufHo());
-
ProofChecker* pc = pnm != nullptr ? pnm->getChecker() : nullptr;
if (pc != nullptr)
{
d_ufProofChecker.registerTo(pc);
}
+ // indicate we are using the default theory state and inference managers
+ d_theoryState = &d_state;
+ d_inferManager = &d_im;
}
TheoryUF::~TheoryUF() {
}
-void TheoryUF::setMasterEqualityEngine(eq::EqualityEngine* eq) {
- d_equalityEngine.setMasterEqualityEngine(eq);
+TheoryRewriter* TheoryUF::getTheoryRewriter() { return &d_rewriter; }
+
+bool TheoryUF::needsEqualityEngine(EeSetupInfo& esi)
+{
+ esi.d_notify = &d_notify;
+ esi.d_name = d_instanceName + "theory::uf::ee";
+ return true;
}
void TheoryUF::finishInit() {
+ Assert(d_equalityEngine != nullptr);
// combined cardinality constraints are not evaluated in getModelValue
- TheoryModel* tm = d_valuation.getModel();
- Assert(tm != nullptr);
- tm->setUnevaluatedKind(kind::COMBINED_CARDINALITY_CONSTRAINT);
+ d_valuation.setUnevaluatedKind(kind::COMBINED_CARDINALITY_CONSTRAINT);
// Initialize the cardinality constraints solver if the logic includes UF,
// finite model finding is enabled, and it is not disabled by
// options::ufssMode().
- if (getLogicInfo().isTheoryEnabled(THEORY_UF) && options::finiteModelFind()
+ if (options::finiteModelFind()
&& options::ufssMode() != options::UfssMode::NONE)
{
- d_thss.reset(new CardinalityExtension(
- getSatContext(), getUserContext(), *d_out, this));
+ d_thss.reset(new CardinalityExtension(d_state, d_im, this));
}
+ // The kinds we are treating as function application in congruence
+ d_equalityEngine->addFunctionKind(kind::APPLY_UF, false, options::ufHo());
if (options::ufHo())
{
- d_equalityEngine.addFunctionKind(kind::HO_APPLY);
- d_ho.reset(new HoExtension(*this, getSatContext(), getUserContext()));
+ d_equalityEngine->addFunctionKind(kind::HO_APPLY);
+ d_ho.reset(new HoExtension(d_state, d_im));
}
}
@@ -121,93 +121,88 @@ static Node mkAnd(const std::vector<TNode>& conjunctions) {
return conjunction;
}/* mkAnd() */
-void TheoryUF::check(Effort level) {
- if (done() && !fullEffort(level)) {
+//--------------------------------- standard check
+
+bool TheoryUF::needsCheckLastEffort()
+{
+ // last call effort needed if using finite model finding
+ return d_thss != nullptr;
+}
+
+void TheoryUF::postCheck(Effort level)
+{
+ if (d_state.isInConflict())
+ {
return;
}
- getOutputChannel().spendResource(ResourceManager::Resource::TheoryCheckStep);
- TimerStat::CodeTimer checkTimer(d_checkTime);
-
- while (!done() && !d_conflict)
+ // check with the cardinality constraints extension
+ if (d_thss != nullptr)
{
- // Get all the assertions
- Assertion assertion = get();
- TNode fact = assertion.d_assertion;
-
- Debug("uf") << "TheoryUF::check(): processing " << fact << std::endl;
- Debug("uf") << "Term's theory: " << theory::Theory::theoryOf(fact.toExpr()) << std::endl;
-
- if (d_thss != NULL) {
- bool isDecision = d_valuation.isSatLiteral(fact) && d_valuation.isDecision(fact);
- d_thss->assertNode(fact, isDecision);
- if( d_thss->isConflict() ){
- d_conflict = true;
- return;
- }
+ d_thss->check(level);
+ }
+ // check with the higher-order extension at full effort
+ if (!d_state.isInConflict() && fullEffort(level))
+ {
+ if (options::ufHo())
+ {
+ d_ho->check();
}
+ }
+}
- // Do the work
- bool polarity = fact.getKind() != kind::NOT;
- TNode atom = polarity ? fact : fact[0];
- if (atom.getKind() == kind::EQUAL) {
- d_equalityEngine.assertEquality(atom, polarity, fact);
- if( options::ufHo() && options::ufHoExt() ){
- if( !polarity && !d_conflict && atom[0].getType().isFunction() ){
- // apply extensionality eagerly using the ho extension
- d_ho->applyExtensionality(fact);
- }
- }
- } else if (atom.getKind() == kind::CARDINALITY_CONSTRAINT || atom.getKind() == kind::COMBINED_CARDINALITY_CONSTRAINT) {
- if( d_thss == NULL ){
- if( !getLogicInfo().hasCardinalityConstraints() ){
- std::stringstream ss;
- ss << "Cardinality constraint " << atom << " was asserted, but the logic does not allow it." << std::endl;
- ss << "Try using a logic containing \"UFC\"." << std::endl;
- throw Exception( ss.str() );
- }else{
- // support for cardinality constraints is not enabled, set incomplete
- d_out->setIncomplete();
- }
- }
- //needed for models
- if( options::produceModels() ){
- d_equalityEngine.assertPredicate(atom, polarity, fact);
- }
- } else {
- d_equalityEngine.assertPredicate(atom, polarity, fact);
+bool TheoryUF::preNotifyFact(
+ TNode atom, bool pol, TNode fact, bool isPrereg, bool isInternal)
+{
+ if (d_thss != nullptr)
+ {
+ bool isDecision =
+ d_valuation.isSatLiteral(fact) && d_valuation.isDecision(fact);
+ d_thss->assertNode(fact, isDecision);
+ if (d_state.isInConflict())
+ {
+ return true;
}
}
-
- if(! d_conflict ){
- // check with the cardinality constraints extension
- if (d_thss != NULL) {
- d_thss->check(level);
- if( d_thss->isConflict() ){
- d_conflict = true;
+ if (atom.getKind() == kind::CARDINALITY_CONSTRAINT
+ || atom.getKind() == kind::COMBINED_CARDINALITY_CONSTRAINT)
+ {
+ if (d_thss == nullptr)
+ {
+ if (!getLogicInfo().hasCardinalityConstraints())
+ {
+ std::stringstream ss;
+ ss << "Cardinality constraint " << atom
+ << " was asserted, but the logic does not allow it." << std::endl;
+ ss << "Try using a logic containing \"UFC\"." << std::endl;
+ throw Exception(ss.str());
}
- }
- // check with the higher-order extension
- if(! d_conflict && fullEffort(level) ){
- if( options::ufHo() ){
- d_ho->check();
+ else
+ {
+ // support for cardinality constraints is not enabled, set incomplete
+ d_out->setIncomplete();
}
}
+ // don't need to assert cardinality constraints if not producing models
+ return !options::produceModels();
}
-}/* TheoryUF::check() */
-
-Node TheoryUF::getOperatorForApplyTerm( TNode node ) {
- Assert(node.getKind() == kind::APPLY_UF || node.getKind() == kind::HO_APPLY);
- if( node.getKind()==kind::APPLY_UF ){
- return node.getOperator();
- }else{
- return d_equalityEngine.getRepresentative( node[0] );
- }
+ return false;
}
-unsigned TheoryUF::getArgumentStartIndexForApplyTerm( TNode node ) {
- Assert(node.getKind() == kind::APPLY_UF || node.getKind() == kind::HO_APPLY);
- return node.getKind()==kind::APPLY_UF ? 0 : 1;
+void TheoryUF::notifyFact(TNode atom, bool pol, TNode fact, bool isInternal)
+{
+ if (!d_state.isInConflict() && atom.getKind() == kind::EQUAL)
+ {
+ if (options::ufHo() && options::ufHoExt())
+ {
+ if (!pol && !d_state.isInConflict() && atom[0].getType().isFunction())
+ {
+ // apply extensionality eagerly using the ho extension
+ d_ho->applyExtensionality(fact);
+ }
+ }
+ }
}
+//--------------------------------- end standard check
TrustNode TheoryUF::expandDefinition(Node node)
{
@@ -230,7 +225,8 @@ TrustNode TheoryUF::expandDefinition(Node node)
return TrustNode::null();
}
-void TheoryUF::preRegisterTerm(TNode node) {
+void TheoryUF::preRegisterTerm(TNode node)
+{
Debug("uf") << "TheoryUF::preRegisterTerm(" << node << ")" << std::endl;
if (d_thss != NULL) {
@@ -244,17 +240,17 @@ void TheoryUF::preRegisterTerm(TNode node) {
switch (node.getKind()) {
case kind::EQUAL:
// Add the trigger for equality
- d_equalityEngine.addTriggerEquality(node);
+ d_equalityEngine->addTriggerPredicate(node);
break;
case kind::APPLY_UF:
case kind::HO_APPLY:
// Maybe it's a predicate
if (node.getType().isBoolean()) {
// Get triggered for both equal and dis-equal
- d_equalityEngine.addTriggerPredicate(node);
+ d_equalityEngine->addTriggerPredicate(node);
} else {
// Function applications/predicates
- d_equalityEngine.addTerm(node);
+ d_equalityEngine->addTerm(node);
}
// Remember the function and predicate terms
d_functionsTerms.push_back(node);
@@ -265,84 +261,38 @@ void TheoryUF::preRegisterTerm(TNode node) {
break;
default:
// Variables etc
- d_equalityEngine.addTerm(node);
+ d_equalityEngine->addTerm(node);
break;
}
-}/* TheoryUF::preRegisterTerm() */
-
-bool TheoryUF::propagate(TNode literal) {
- Debug("uf::propagate") << "TheoryUF::propagate(" << literal << ")" << std::endl;
- // If already in conflict, no more propagation
- if (d_conflict) {
- Debug("uf::propagate") << "TheoryUF::propagate(" << literal << "): already in conflict" << std::endl;
- return false;
- }
- // Propagate out
- bool ok = d_out->propagate(literal);
- if (!ok) {
- d_conflict = true;
- }
- return ok;
-}/* TheoryUF::propagate(TNode) */
-
-void TheoryUF::propagate(Effort effort) {
- //if (d_thss != NULL) {
- // return d_thss->propagate(effort);
- //}
}
-void TheoryUF::explain(TNode literal, std::vector<TNode>& assumptions, eq::EqProof* pf) {
+void TheoryUF::explain(TNode literal, Node& exp)
+{
+ Debug("uf") << "TheoryUF::explain(" << literal << ")" << std::endl;
+ std::vector<TNode> assumptions;
// Do the work
bool polarity = literal.getKind() != kind::NOT;
TNode atom = polarity ? literal : literal[0];
- if (atom.getKind() == kind::EQUAL) {
- d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions, pf);
- } else {
- d_equalityEngine.explainPredicate(atom, polarity, assumptions, pf);
- }
- if( pf ){
- Debug("pf::uf") << std::endl;
- pf->debug_print("pf::uf");
+ if (atom.getKind() == kind::EQUAL)
+ {
+ d_equalityEngine->explainEquality(
+ atom[0], atom[1], polarity, assumptions, nullptr);
}
-
- Debug("pf::uf") << "UF: explain( " << literal << " ):" << std::endl << "\t";
- for (unsigned i = 0; i < assumptions.size(); ++i) {
- Debug("pf::uf") << assumptions[i] << " ";
+ else
+ {
+ d_equalityEngine->explainPredicate(atom, polarity, assumptions, nullptr);
}
- Debug("pf::uf") << std::endl;
+ exp = mkAnd(assumptions);
}
-TrustNode TheoryUF::explain(TNode literal)
-{
- Node exp = explain(literal, NULL);
- return TrustNode::mkTrustPropExp(literal, exp, nullptr);
-}
-
-Node TheoryUF::explain(TNode literal, eq::EqProof* pf) {
- Debug("uf") << "TheoryUF::explain(" << literal << ")" << std::endl;
- std::vector<TNode> assumptions;
- explain(literal, assumptions, pf);
- return mkAnd(assumptions);
-}
+TrustNode TheoryUF::explain(TNode literal) { return d_im.explainLit(literal); }
-bool TheoryUF::collectModelInfo(TheoryModel* m)
+bool TheoryUF::collectModelValues(TheoryModel* m, const std::set<Node>& termSet)
{
- Debug("uf") << "UF : collectModelInfo " << std::endl;
- set<Node> termSet;
-
- // Compute terms appearing in assertions and shared terms
- computeRelevantTerms(termSet);
-
- if (!m->assertEqualityEngine(&d_equalityEngine, &termSet))
- {
- Trace("uf") << "Collect model info fail UF" << std::endl;
- return false;
- }
-
if( options::ufHo() ){
// must add extensionality disequalities for all pairs of (non-disequal)
// function equivalence classes.
- if (!d_ho->collectModelInfoHo(termSet, m))
+ if (!d_ho->collectModelInfoHo(m, termSet))
{
Trace("uf") << "Collect model info fail HO" << std::endl;
return false;
@@ -364,7 +314,8 @@ void TheoryUF::presolve() {
i != newClauses.end();
++i) {
Debug("uf") << "uf: generating a lemma: " << *i << std::endl;
- d_out->lemma(*i);
+ // no proof generator provided
+ d_im.lemma(*i);
}
}
if( d_thss ){
@@ -497,13 +448,15 @@ void TheoryUF::ppStaticLearn(TNode n, NodeBuilder<>& learned) {
EqualityStatus TheoryUF::getEqualityStatus(TNode a, TNode b) {
// Check for equality (simplest)
- if (d_equalityEngine.areEqual(a, b)) {
+ if (d_equalityEngine->areEqual(a, b))
+ {
// The terms are implied to be equal
return EQUALITY_TRUE;
}
// Check for disequality
- if (d_equalityEngine.areDisequal(a, b, false)) {
+ if (d_equalityEngine->areDisequal(a, b, false))
+ {
// The terms are implied to be dis-equal
return EQUALITY_FALSE;
}
@@ -512,17 +465,16 @@ EqualityStatus TheoryUF::getEqualityStatus(TNode a, TNode b) {
return EQUALITY_FALSE_IN_MODEL;
}
-void TheoryUF::addSharedTerm(TNode t) {
- Debug("uf::sharing") << "TheoryUF::addSharedTerm(" << t << ")" << std::endl;
- d_equalityEngine.addTriggerTerm(t, THEORY_UF);
-}
-
bool TheoryUF::areCareDisequal(TNode x, TNode y){
- Assert(d_equalityEngine.hasTerm(x));
- Assert(d_equalityEngine.hasTerm(y));
- if( d_equalityEngine.isTriggerTerm(x, THEORY_UF) && d_equalityEngine.isTriggerTerm(y, THEORY_UF) ){
- TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_UF);
- TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_UF);
+ Assert(d_equalityEngine->hasTerm(x));
+ Assert(d_equalityEngine->hasTerm(y));
+ if (d_equalityEngine->isTriggerTerm(x, THEORY_UF)
+ && d_equalityEngine->isTriggerTerm(y, THEORY_UF))
+ {
+ TNode x_shared =
+ d_equalityEngine->getTriggerTermRepresentative(x, THEORY_UF);
+ TNode y_shared =
+ d_equalityEngine->getTriggerTermRepresentative(y, THEORY_UF);
EqualityStatus eqStatus = d_valuation.getEqualityStatus(x_shared, y_shared);
if( eqStatus==EQUALITY_FALSE_AND_PROPAGATED || eqStatus==EQUALITY_FALSE || eqStatus==EQUALITY_FALSE_IN_MODEL ){
return true;
@@ -531,8 +483,8 @@ bool TheoryUF::areCareDisequal(TNode x, TNode y){
return false;
}
-void TheoryUF::addCarePairs(TNodeTrie* t1,
- TNodeTrie* t2,
+void TheoryUF::addCarePairs(const TNodeTrie* t1,
+ const TNodeTrie* t2,
unsigned arity,
unsigned depth)
{
@@ -540,21 +492,27 @@ void TheoryUF::addCarePairs(TNodeTrie* t1,
if( t2!=NULL ){
Node f1 = t1->getData();
Node f2 = t2->getData();
- if( !d_equalityEngine.areEqual( f1, f2 ) ){
+ if (!d_equalityEngine->areEqual(f1, f2))
+ {
Debug("uf::sharing") << "TheoryUf::computeCareGraph(): checking function " << f1 << " and " << f2 << std::endl;
vector< pair<TNode, TNode> > currentPairs;
- unsigned arg_start_index = getArgumentStartIndexForApplyTerm( f1 );
- for (unsigned k = arg_start_index; k < f1.getNumChildren(); ++ k) {
+ for (size_t k = 0, nchildren = f1.getNumChildren(); k < nchildren; ++k)
+ {
TNode x = f1[k];
TNode y = f2[k];
- Assert(d_equalityEngine.hasTerm(x));
- Assert(d_equalityEngine.hasTerm(y));
- Assert(!d_equalityEngine.areDisequal(x, y, false));
+ Assert(d_equalityEngine->hasTerm(x));
+ Assert(d_equalityEngine->hasTerm(y));
+ Assert(!d_equalityEngine->areDisequal(x, y, false));
Assert(!areCareDisequal(x, y));
- if( !d_equalityEngine.areEqual( x, y ) ){
- if( d_equalityEngine.isTriggerTerm(x, THEORY_UF) && d_equalityEngine.isTriggerTerm(y, THEORY_UF) ){
- TNode x_shared = d_equalityEngine.getTriggerTermRepresentative(x, THEORY_UF);
- TNode y_shared = d_equalityEngine.getTriggerTermRepresentative(y, THEORY_UF);
+ if (!d_equalityEngine->areEqual(x, y))
+ {
+ if (d_equalityEngine->isTriggerTerm(x, THEORY_UF)
+ && d_equalityEngine->isTriggerTerm(y, THEORY_UF))
+ {
+ TNode x_shared =
+ d_equalityEngine->getTriggerTermRepresentative(x, THEORY_UF);
+ TNode y_shared =
+ d_equalityEngine->getTriggerTermRepresentative(y, THEORY_UF);
currentPairs.push_back(make_pair(x_shared, y_shared));
}
}
@@ -569,20 +527,21 @@ void TheoryUF::addCarePairs(TNodeTrie* t1,
if( t2==NULL ){
if( depth<(arity-1) ){
//add care pairs internal to each child
- for (std::pair<const TNode, TNodeTrie>& tt : t1->d_data)
+ for (const std::pair<const TNode, TNodeTrie>& tt : t1->d_data)
{
addCarePairs(&tt.second, NULL, arity, depth + 1);
}
}
//add care pairs based on each pair of non-disequal arguments
- for (std::map<TNode, TNodeTrie>::iterator it = t1->d_data.begin();
+ for (std::map<TNode, TNodeTrie>::const_iterator it = t1->d_data.begin();
it != t1->d_data.end();
++it)
{
- std::map<TNode, TNodeTrie>::iterator it2 = it;
+ std::map<TNode, TNodeTrie>::const_iterator it2 = it;
++it2;
for( ; it2 != t1->d_data.end(); ++it2 ){
- if( !d_equalityEngine.areDisequal(it->first, it2->first, false) ){
+ if (!d_equalityEngine->areDisequal(it->first, it2->first, false))
+ {
if( !areCareDisequal(it->first, it2->first) ){
addCarePairs( &it->second, &it2->second, arity, depth+1 );
}
@@ -591,11 +550,11 @@ void TheoryUF::addCarePairs(TNodeTrie* t1,
}
}else{
//add care pairs based on product of indices, non-disequal arguments
- for (std::pair<const TNode, TNodeTrie>& tt1 : t1->d_data)
+ for (const std::pair<const TNode, TNodeTrie>& tt1 : t1->d_data)
{
- for (std::pair<const TNode, TNodeTrie>& tt2 : t2->d_data)
+ for (const std::pair<const TNode, TNodeTrie>& tt2 : t2->d_data)
{
- if (!d_equalityEngine.areDisequal(tt1.first, tt2.first, false))
+ if (!d_equalityEngine->areDisequal(tt1.first, tt2.first, false))
{
if (!areCareDisequal(tt1.first, tt2.first))
{
@@ -609,63 +568,73 @@ void TheoryUF::addCarePairs(TNodeTrie* t1,
}
void TheoryUF::computeCareGraph() {
-
- if (d_sharedTerms.size() > 0) {
- //use term indexing
- Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Build term indices..." << std::endl;
- std::map<Node, TNodeTrie> index;
- std::map< Node, unsigned > arity;
- unsigned functionTerms = d_functionsTerms.size();
- for (unsigned i = 0; i < functionTerms; ++ i) {
- TNode f1 = d_functionsTerms[i];
- Node op = getOperatorForApplyTerm( f1 );
- unsigned arg_start_index = getArgumentStartIndexForApplyTerm( f1 );
- std::vector< TNode > reps;
- bool has_trigger_arg = false;
- for( unsigned j=arg_start_index; j<f1.getNumChildren(); j++ ){
- reps.push_back( d_equalityEngine.getRepresentative( f1[j] ) );
- if( d_equalityEngine.isTriggerTerm( f1[j], THEORY_UF ) ){
- has_trigger_arg = true;
- }
- }
- if( has_trigger_arg ){
- index[op].addTerm(f1, reps);
- arity[op] = reps.size();
+ if (d_sharedTerms.empty())
+ {
+ return;
+ }
+ // Use term indexing. We build separate indices for APPLY_UF and HO_APPLY.
+ // We maintain indices per operator for the former, and indices per
+ // function type for the latter.
+ Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Build term indices..."
+ << std::endl;
+ std::map<Node, TNodeTrie> index;
+ std::map<TypeNode, TNodeTrie> hoIndex;
+ std::map<Node, size_t> arity;
+ for (TNode app : d_functionsTerms)
+ {
+ std::vector<TNode> reps;
+ bool has_trigger_arg = false;
+ for (const Node& j : app)
+ {
+ reps.push_back(d_equalityEngine->getRepresentative(j));
+ if (d_equalityEngine->isTriggerTerm(j, THEORY_UF))
+ {
+ has_trigger_arg = true;
}
}
- //for each index
- for (std::pair<const Node, TNodeTrie>& tt : index)
+ if (has_trigger_arg)
{
- Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Process index "
- << tt.first << "..." << std::endl;
- addCarePairs(&tt.second, nullptr, arity[tt.first], 0);
+ if (app.getKind() == kind::APPLY_UF)
+ {
+ Node op = app.getOperator();
+ index[op].addTerm(app, reps);
+ arity[op] = reps.size();
+ }
+ else
+ {
+ Assert(app.getKind() == kind::HO_APPLY);
+ // add it to the hoIndex for the function type
+ hoIndex[app[0].getType()].addTerm(app, reps);
+ }
}
- Debug("uf::sharing") << "TheoryUf::computeCareGraph(): finished." << std::endl;
}
+ // for each index
+ for (std::pair<const Node, TNodeTrie>& tt : index)
+ {
+ Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Process index "
+ << tt.first << "..." << std::endl;
+ Assert(arity.find(tt.first) != arity.end());
+ addCarePairs(&tt.second, nullptr, arity[tt.first], 0);
+ }
+ for (std::pair<const TypeNode, TNodeTrie>& tt : hoIndex)
+ {
+ Debug("uf::sharing") << "TheoryUf::computeCareGraph(): Process ho index "
+ << tt.first << "..." << std::endl;
+ // the arity of HO_APPLY is always two
+ addCarePairs(&tt.second, nullptr, 2, 0);
+ }
+ Debug("uf::sharing") << "TheoryUf::computeCareGraph(): finished."
+ << std::endl;
}/* TheoryUF::computeCareGraph() */
-void TheoryUF::conflict(TNode a, TNode b) {
- std::shared_ptr<eq::EqProof> pf =
- d_proofsEnabled ? std::make_shared<eq::EqProof>() : nullptr;
- d_conflictNode = explain(a.eqNode(b), pf.get());
- std::unique_ptr<ProofUF> puf(d_proofsEnabled ? new ProofUF(pf) : nullptr);
- d_out->conflict(d_conflictNode, std::move(puf));
- d_conflict = true;
-}
-
void TheoryUF::eqNotifyNewClass(TNode t) {
if (d_thss != NULL) {
d_thss->newEqClass(t);
}
}
-void TheoryUF::eqNotifyPreMerge(TNode t1, TNode t2) {
- //if (getLogicInfo().isQuantified()) {
- //getQuantifiersEngine()->getEfficientEMatcher()->merge( t1, t2 );
- //}
-}
-
-void TheoryUF::eqNotifyPostMerge(TNode t1, TNode t2) {
+void TheoryUF::eqNotifyMerge(TNode t1, TNode t2)
+{
if (d_thss != NULL) {
d_thss->merge(t1, t2);
}
diff --git a/src/theory/uf/theory_uf.h b/src/theory/uf/theory_uf.h
index 58f4f18a5..4a63d9584 100644
--- a/src/theory/uf/theory_uf.h
+++ b/src/theory/uf/theory_uf.h
@@ -2,10 +2,10 @@
/*! \file theory_uf.h
** \verbatim
** Top contributors (to current version):
- ** Dejan Jovanovic, Andrew Reynolds, Morgan Deters
+ ** Andrew Reynolds, Dejan Jovanovic, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -24,8 +24,10 @@
#include "expr/node.h"
#include "expr/node_trie.h"
#include "theory/theory.h"
+#include "theory/theory_eq_notify.h"
#include "theory/uf/equality_engine.h"
#include "theory/uf/proof_checker.h"
+#include "theory/uf/proof_equality_engine.h"
#include "theory/uf/symmetry_breaker.h"
#include "theory/uf/theory_uf_rewriter.h"
@@ -37,70 +39,27 @@ class CardinalityExtension;
class HoExtension;
class TheoryUF : public Theory {
-
-public:
-
- class NotifyClass : public eq::EqualityEngineNotify {
- TheoryUF& d_uf;
- public:
- NotifyClass(TheoryUF& uf): d_uf(uf) {}
-
- bool eqNotifyTriggerEquality(TNode equality, bool value) override
- {
- Debug("uf") << "NotifyClass::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false" )<< ")" << std::endl;
- if (value) {
- return d_uf.propagate(equality);
- } else {
- // We use only literal triggers so taking not is safe
- return d_uf.propagate(equality.notNode());
- }
- }
-
- bool eqNotifyTriggerPredicate(TNode predicate, bool value) override
- {
- Debug("uf") << "NotifyClass::eqNotifyTriggerPredicate(" << predicate << ", " << (value ? "true" : "false") << ")" << std::endl;
- if (value) {
- return d_uf.propagate(predicate);
- } else {
- return d_uf.propagate(predicate.notNode());
- }
- }
-
- bool eqNotifyTriggerTermEquality(TheoryId tag,
- TNode t1,
- TNode t2,
- bool value) override
- {
- Debug("uf") << "NotifyClass::eqNotifyTriggerTermMerge(" << tag << ", " << t1 << ", " << t2 << ")" << std::endl;
- if (value) {
- return d_uf.propagate(t1.eqNode(t2));
- } else {
- return d_uf.propagate(t1.eqNode(t2).notNode());
- }
- }
-
- void eqNotifyConstantTermMerge(TNode t1, TNode t2) override
+ public:
+ class NotifyClass : public TheoryEqNotifyClass
+ {
+ public:
+ NotifyClass(TheoryInferenceManager& im, TheoryUF& uf)
+ : TheoryEqNotifyClass(im), d_uf(uf)
{
- Debug("uf-notify") << "NotifyClass::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << ")" << std::endl;
- d_uf.conflict(t1, t2);
}
void eqNotifyNewClass(TNode t) override
{
- Debug("uf-notify") << "NotifyClass::eqNotifyNewClass(" << t << ")" << std::endl;
+ Debug("uf-notify") << "NotifyClass::eqNotifyNewClass(" << t << ")"
+ << std::endl;
d_uf.eqNotifyNewClass(t);
}
- void eqNotifyPreMerge(TNode t1, TNode t2) override
- {
- Debug("uf-notify") << "NotifyClass::eqNotifyPreMerge(" << t1 << ", " << t2 << ")" << std::endl;
- d_uf.eqNotifyPreMerge(t1, t2);
- }
-
- void eqNotifyPostMerge(TNode t1, TNode t2) override
+ void eqNotifyMerge(TNode t1, TNode t2) override
{
- Debug("uf-notify") << "NotifyClass::eqNotifyPostMerge(" << t1 << ", " << t2 << ")" << std::endl;
- d_uf.eqNotifyPostMerge(t1, t2);
+ Debug("uf-notify") << "NotifyClass::eqNotifyMerge(" << t1 << ", " << t2
+ << ")" << std::endl;
+ d_uf.eqNotifyMerge(t1, t2);
}
void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) override
@@ -109,78 +68,35 @@ public:
d_uf.eqNotifyDisequal(t1, t2, reason);
}
+ private:
+ /** Reference to the parent theory */
+ TheoryUF& d_uf;
};/* class TheoryUF::NotifyClass */
private:
-
- /** The notify class */
- NotifyClass d_notify;
-
/** The associated cardinality extension (or nullptr if it does not exist) */
std::unique_ptr<CardinalityExtension> d_thss;
/** the higher-order solver extension (or nullptr if it does not exist) */
std::unique_ptr<HoExtension> d_ho;
- /** Equaltity engine */
- eq::EqualityEngine d_equalityEngine;
-
- /** Are we in conflict */
- context::CDO<bool> d_conflict;
-
- /** The conflict node */
- Node d_conflictNode;
-
-
/** node for true */
Node d_true;
- /**
- * Should be called to propagate the literal. We use a node here
- * since some of the propagated literals are not kept anywhere.
- */
- bool propagate(TNode literal);
-
- /**
- * Explain why this literal is true by adding assumptions
- * with proof (if "pf" is non-NULL).
- */
- void explain(TNode literal, std::vector<TNode>& assumptions, eq::EqProof* pf);
-
- /**
- * Explain a literal, with proof (if "pf" is non-NULL).
- */
- Node explain(TNode literal, eq::EqProof* pf);
-
/** All the function terms that the theory has seen */
context::CDList<TNode> d_functionsTerms;
/** Symmetry analyzer */
SymmetryBreaker d_symb;
- /** 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);
+ void eqNotifyMerge(TNode t1, TNode t2);
/** called when two equivalence classes are made disequal */
void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
- private:
- /** get the operator for this node (node should be either APPLY_UF or
- * HO_APPLY)
- */
- Node getOperatorForApplyTerm(TNode node);
- /** get the starting index of the arguments for node (node should be either
- * APPLY_UF or HO_APPLY) */
- unsigned getArgumentStartIndexForApplyTerm(TNode node);
-
public:
/** Constructs a new instance of TheoryUF w.r.t. the provided context.*/
@@ -194,47 +110,70 @@ private:
~TheoryUF();
- TheoryRewriter* getTheoryRewriter() override { return &d_rewriter; }
-
- void setMasterEqualityEngine(eq::EqualityEngine* eq) override;
+ //--------------------------------- initialization
+ /** get the official theory rewriter of this theory */
+ TheoryRewriter* getTheoryRewriter() override;
+ /**
+ * Returns true if we need an equality engine. If so, we initialize the
+ * information regarding how it should be setup. For details, see the
+ * documentation in Theory::needsEqualityEngine.
+ */
+ bool needsEqualityEngine(EeSetupInfo& esi) override;
+ /** finish initialization */
void finishInit() override;
+ //--------------------------------- end initialization
+
+ //--------------------------------- standard check
+ /** Do we need a check call at last call effort? */
+ bool needsCheckLastEffort() override;
+ /** Post-check, called after the fact queue of the theory is processed. */
+ void postCheck(Effort level) override;
+ /** Pre-notify fact, return true if processed. */
+ bool preNotifyFact(TNode atom,
+ bool pol,
+ TNode fact,
+ bool isPrereg,
+ bool isInternal) override;
+ /** Notify fact */
+ void notifyFact(TNode atom, bool pol, TNode fact, bool isInternal) override;
+ //--------------------------------- end standard check
+
+ /** Collect model values in m based on the relevant terms given by termSet */
+ bool collectModelValues(TheoryModel* m,
+ const std::set<Node>& termSet) override;
- void check(Effort) override;
TrustNode expandDefinition(Node node) override;
void preRegisterTerm(TNode term) override;
TrustNode explain(TNode n) override;
- bool collectModelInfo(TheoryModel* m) override;
void ppStaticLearn(TNode in, NodeBuilder<>& learned) override;
void presolve() override;
- void addSharedTerm(TNode n) override;
void computeCareGraph() override;
- void propagate(Effort effort) override;
-
EqualityStatus getEqualityStatus(TNode a, TNode b) override;
std::string identify() const override { return "THEORY_UF"; }
-
- eq::EqualityEngine* getEqualityEngine() override { return &d_equalityEngine; }
-
- /** get a pointer to the uf with cardinality */
- CardinalityExtension* getCardinalityExtension() const { return d_thss.get(); }
- /** are we in conflict? */
- bool inConflict() const { return d_conflict; }
-
private:
+ /** Explain why this literal is true by building an explanation */
+ void explain(TNode literal, Node& exp);
+
bool areCareDisequal(TNode x, TNode y);
- void addCarePairs(TNodeTrie* t1,
- TNodeTrie* t2,
+ void addCarePairs(const TNodeTrie* t1,
+ const TNodeTrie* t2,
unsigned arity,
unsigned depth);
TheoryUfRewriter d_rewriter;
/** Proof rule checker */
UfProofRuleChecker d_ufProofChecker;
+ /** A (default) theory state object */
+ TheoryState d_state;
+ /** A (default) inference manager */
+ TheoryInferenceManager d_im;
+ /** The notify class */
+ NotifyClass d_notify;
};/* class TheoryUF */
}/* CVC4::theory::uf namespace */
diff --git a/src/theory/uf/theory_uf_model.cpp b/src/theory/uf/theory_uf_model.cpp
index 56d44b769..a014cccb2 100644
--- a/src/theory/uf/theory_uf_model.cpp
+++ b/src/theory/uf/theory_uf_model.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/uf/theory_uf_model.h b/src/theory/uf/theory_uf_model.h
index 138ad1238..1165f310c 100644
--- a/src/theory/uf/theory_uf_model.h
+++ b/src/theory/uf/theory_uf_model.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/uf/theory_uf_rewriter.h b/src/theory/uf/theory_uf_rewriter.h
index e651edb51..bae3dbdc6 100644
--- a/src/theory/uf/theory_uf_rewriter.h
+++ b/src/theory/uf/theory_uf_rewriter.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Haniel Barbosa, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -22,6 +22,7 @@
#include "expr/node_algorithm.h"
#include "options/uf_options.h"
+#include "theory/rewriter.h"
#include "theory/substitutions.h"
#include "theory/theory_rewriter.h"
diff --git a/src/theory/uf/theory_uf_type_rules.h b/src/theory/uf/theory_uf_type_rules.h
index 372ca9ad0..13b4acd99 100644
--- a/src/theory/uf/theory_uf_type_rules.h
+++ b/src/theory/uf/theory_uf_type_rules.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/theory/valuation.cpp b/src/theory/valuation.cpp
index d8233bff7..ad6ee9fdf 100644
--- a/src/theory/valuation.cpp
+++ b/src/theory/valuation.cpp
@@ -2,10 +2,10 @@
/*! \file valuation.cpp
** \verbatim
** Top contributors (to current version):
- ** Dejan Jovanovic, Andrew Reynolds, Morgan Deters
+ ** Andrew Reynolds, Dejan Jovanovic, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,6 +20,7 @@
#include "options/theory_options.h"
#include "theory/rewriter.h"
#include "theory/theory_engine.h"
+#include "theory/theory_model.h"
namespace CVC4 {
namespace theory {
@@ -76,10 +77,12 @@ bool equalityStatusCompatible(EqualityStatus s1, EqualityStatus s2) {
}
bool Valuation::isSatLiteral(TNode n) const {
+ Assert(d_engine != nullptr);
return d_engine->getPropEngine()->isSatLiteral(n);
}
Node Valuation::getSatValue(TNode n) const {
+ Assert(d_engine != nullptr);
if(n.getKind() == kind::NOT) {
Node atomRes = d_engine->getPropEngine()->getValue(n[0]);
if(atomRes.getKind() == kind::CONST_BOOLEAN) {
@@ -94,6 +97,7 @@ Node Valuation::getSatValue(TNode n) const {
}
bool Valuation::hasSatValue(TNode n, bool& value) const {
+ Assert(d_engine != nullptr);
if (d_engine->getPropEngine()->isSatLiteral(n)) {
return d_engine->getPropEngine()->hasValue(n, value);
} else {
@@ -102,38 +106,82 @@ bool Valuation::hasSatValue(TNode n, bool& value) const {
}
EqualityStatus Valuation::getEqualityStatus(TNode a, TNode b) {
+ Assert(d_engine != nullptr);
return d_engine->getEqualityStatus(a, b);
}
Node Valuation::getModelValue(TNode var) {
+ Assert(d_engine != nullptr);
return d_engine->getModelValue(var);
}
TheoryModel* Valuation::getModel() {
+ if (d_engine == nullptr)
+ {
+ // no theory engine, thus we don't have a model object
+ return nullptr;
+ }
return d_engine->getModel();
}
+void Valuation::setUnevaluatedKind(Kind k)
+{
+ TheoryModel* m = getModel();
+ if (m != nullptr)
+ {
+ m->setUnevaluatedKind(k);
+ }
+ // If no model is available, this command has no effect. This is the case
+ // when e.g. calling Theory::finishInit for theories that are using a
+ // Valuation with no model.
+}
+
+void Valuation::setSemiEvaluatedKind(Kind k)
+{
+ TheoryModel* m = getModel();
+ if (m != nullptr)
+ {
+ m->setSemiEvaluatedKind(k);
+ }
+}
+
+void Valuation::setIrrelevantKind(Kind k)
+{
+ TheoryModel* m = getModel();
+ if (m != nullptr)
+ {
+ m->setIrrelevantKind(k);
+ }
+}
+
Node Valuation::ensureLiteral(TNode n) {
+ Assert(d_engine != nullptr);
return d_engine->ensureLiteral(n);
}
bool Valuation::isDecision(Node lit) const {
+ Assert(d_engine != nullptr);
return d_engine->getPropEngine()->isDecision(lit);
}
unsigned Valuation::getAssertionLevel() const{
+ Assert(d_engine != nullptr);
return d_engine->getPropEngine()->getAssertionLevel();
}
std::pair<bool, Node> Valuation::entailmentCheck(options::TheoryOfMode mode,
TNode lit)
{
+ Assert(d_engine != nullptr);
return d_engine->entailmentCheck(mode, lit);
}
bool Valuation::needCheck() const{
+ Assert(d_engine != nullptr);
return d_engine->needCheck();
}
+bool Valuation::isRelevant(Node lit) const { return d_engine->isRelevant(lit); }
+
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/valuation.h b/src/theory/valuation.h
index b1985971a..01b33eb99 100644
--- a/src/theory/valuation.h
+++ b/src/theory/valuation.h
@@ -2,10 +2,10 @@
/*! \file valuation.h
** \verbatim
** Top contributors (to current version):
- ** Morgan Deters, Dejan Jovanovic, Andrew Reynolds
+ ** Morgan Deters, Andrew Reynolds, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -107,10 +107,29 @@ public:
Node getModelValue(TNode var);
/**
- * Returns pointer to model.
+ * Returns pointer to model. This model is only valid during last call effort
+ * check.
*/
TheoryModel* getModel();
-
+
+ //-------------------------------------- static configuration of the model
+ /**
+ * Set that k is an unevaluated kind in the TheoryModel, if it exists.
+ * See TheoryModel::setUnevaluatedKind for details.
+ */
+ void setUnevaluatedKind(Kind k);
+ /**
+ * Set that k is an unevaluated kind in the TheoryModel, if it exists.
+ * See TheoryModel::setSemiEvaluatedKind for details.
+ */
+ void setSemiEvaluatedKind(Kind k);
+ /**
+ * Set that k is an irrelevant kind in the TheoryModel, if it exists.
+ * See TheoryModel::setIrrelevantKind for details.
+ */
+ void setIrrelevantKind(Kind k);
+ //-------------------------------------- end static configuration of the model
+
/**
* Ensure that the given node will have a designated SAT literal
* that is definitionally equal to it. The result of this function
@@ -143,7 +162,13 @@ public:
/** need check ? */
bool needCheck() const;
-
+
+ /**
+ * Is the literal lit (possibly) critical for satisfying the input formula in
+ * the current context? This call is applicable only during collectModelInfo
+ * or during LAST_CALL effort.
+ */
+ bool isRelevant(Node lit) const;
};/* class Valuation */
}/* CVC4::theory namespace */
diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt
index 028288dbc..24e485f5e 100644
--- a/src/util/CMakeLists.txt
+++ b/src/util/CMakeLists.txt
@@ -1,6 +1,17 @@
-configure_file(floatingpoint.h.in floatingpoint.h)
+#####################
+## CMakeLists.txt
+## Top contributors (to current version):
+## Mathias Preiner, Gereon Kremer, Andrew Reynolds
+## This file is part of the CVC4 project.
+## Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+## in the top-level source directory and their institutional affiliations.
+## All rights reserved. See the file COPYING in the top-level source
+## directory for licensing information.
+##
+configure_file(floatingpoint_literal_symfpu.h.in floatingpoint_literal_symfpu.h)
configure_file(rational.h.in rational.h)
configure_file(integer.h.in integer.h)
+configure_file(real_algebraic_number.h.in real_algebraic_number.h)
libcvc4_add_sources(
abstract_value.cpp
@@ -15,6 +26,9 @@ libcvc4_add_sources(
divisible.cpp
divisible.h
floatingpoint.cpp
+ floatingpoint.h
+ floatingpoint_size.cpp
+ floatingpoint_size.h
gmp_util.h
hash.h
iand.h
@@ -23,7 +37,8 @@ libcvc4_add_sources(
maybe.h
ostream_util.cpp
ostream_util.h
- proof.h
+ poly_util.cpp
+ poly_util.h
random.cpp
random.h
resource_manager.cpp
@@ -32,6 +47,7 @@ libcvc4_add_sources(
result.h
regexp.cpp
regexp.h
+ roundingmode.h
safe_print.cpp
safe_print.h
sampler.cpp
@@ -46,6 +62,7 @@ libcvc4_add_sources(
statistics_registry.h
string.cpp
string.h
+ floatingpoint_literal_symfpu.cpp
tuple.h
unsafe_interrupt_exception.h
utility.cpp
@@ -59,3 +76,7 @@ endif()
if(CVC4_USE_GMP_IMP)
libcvc4_add_sources(rational_gmp_imp.cpp integer_gmp_imp.cpp)
endif()
+
+if(CVC4_USE_POLY_IMP)
+ libcvc4_add_sources(real_algebraic_number_poly_imp.cpp real_algebraic_number_poly_imp.h)
+endif()
diff --git a/src/util/abstract_value.cpp b/src/util/abstract_value.cpp
index e004a22a7..39edb7c5a 100644
--- a/src/util/abstract_value.cpp
+++ b/src/util/abstract_value.cpp
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/abstract_value.h b/src/util/abstract_value.h
index f1fe9f575..f994e818f 100644
--- a/src/util/abstract_value.h
+++ b/src/util/abstract_value.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/bin_heap.h b/src/util/bin_heap.h
index d7d3a8e18..d232f1983 100644
--- a/src/util/bin_heap.h
+++ b/src/util/bin_heap.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/bitvector.cpp b/src/util/bitvector.cpp
index 3f3327c93..9233bde53 100644
--- a/src/util/bitvector.cpp
+++ b/src/util/bitvector.cpp
@@ -5,7 +5,7 @@
** Aina Niemetz, Liana Hadarean, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -58,10 +58,10 @@ size_t BitVector::hash() const
return d_value.hash() + d_size;
}
-BitVector BitVector::setBit(uint32_t i) const
+BitVector BitVector::setBit(uint32_t i, bool value) const
{
CheckArgument(i < d_size, i);
- Integer res = d_value.setBit(i);
+ Integer res = d_value.setBit(i, value);
return BitVector(d_size, res);
}
@@ -341,6 +341,18 @@ BitVector BitVector::arithRightShift(const BitVector& y) const
** Static helpers.
* ----------------------------------------------------------------------- */
+BitVector BitVector::mkZero(unsigned size)
+{
+ CheckArgument(size > 0, size);
+ return BitVector(size);
+}
+
+BitVector BitVector::mkOne(unsigned size)
+{
+ CheckArgument(size > 0, size);
+ return BitVector(size, 1u);
+}
+
BitVector BitVector::mkOnes(unsigned size)
{
CheckArgument(size > 0, size);
@@ -350,7 +362,7 @@ BitVector BitVector::mkOnes(unsigned size)
BitVector BitVector::mkMinSigned(unsigned size)
{
CheckArgument(size > 0, size);
- return BitVector(size).setBit(size - 1);
+ return BitVector(size).setBit(size - 1, true);
}
BitVector BitVector::mkMaxSigned(unsigned size)
diff --git a/src/util/bitvector.h b/src/util/bitvector.h
index 8e11d2465..997293639 100644
--- a/src/util/bitvector.h
+++ b/src/util/bitvector.h
@@ -5,7 +5,7 @@
** Aina Niemetz, Andres Noetzli, Dejan Jovanovic
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,7 +19,6 @@
#ifndef CVC4__BITVECTOR_H
#define CVC4__BITVECTOR_H
-#include <cstdint>
#include <iosfwd>
#include "base/exception.h"
@@ -116,9 +115,15 @@ class CVC4_PUBLIC BitVector
/* Return hash value. */
size_t hash() const;
- /* Set bit at index 'i'. */
- BitVector setBit(uint32_t i) const;
- /* Return true if bit at index 'i' is set. */
+ /**
+ * Set bit at index 'i' to given value.
+ * value: True to set bit to 1, and false to set it to 0.
+ *
+ * Note: Least significant bit is at index 0.
+ */
+ BitVector setBit(uint32_t i, bool value) const;
+
+ /** Return true if bit at index 'i' is 1, and false otherwise. */
bool isBitSet(uint32_t i) const;
/* Return k if the value of this is equal to 2^{k-1}, and zero otherwise. */
@@ -240,6 +245,12 @@ class CVC4_PUBLIC BitVector
** Static helpers.
* ----------------------------------------------------------------------- */
+ /* Create zero bit-vector of given size. */
+ static BitVector mkZero(unsigned size);
+
+ /* Create bit-vector representing value 1 of given size. */
+ static BitVector mkOne(unsigned size);
+
/* Create bit-vector of ones of given size. */
static BitVector mkOnes(unsigned size);
diff --git a/src/util/bool.h b/src/util/bool.h
index 5779f073b..ad07cbf63 100644
--- a/src/util/bool.h
+++ b/src/util/bool.h
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/cardinality.cpp b/src/util/cardinality.cpp
index e7c0ac01c..585512138 100644
--- a/src/util/cardinality.cpp
+++ b/src/util/cardinality.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/cardinality.h b/src/util/cardinality.h
index d1b003300..8ad3edbe2 100644
--- a/src/util/cardinality.h
+++ b/src/util/cardinality.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/dense_map.h b/src/util/dense_map.h
index 8e5f5f9cf..e4dfaf4a7 100644
--- a/src/util/dense_map.h
+++ b/src/util/dense_map.h
@@ -5,7 +5,7 @@
** Tim King, Dejan Jovanovic, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/divisible.cpp b/src/util/divisible.cpp
index a218642d7..d6072aed4 100644
--- a/src/util/divisible.cpp
+++ b/src/util/divisible.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/divisible.h b/src/util/divisible.h
index bb2370f0b..36bb37db0 100644
--- a/src/util/divisible.h
+++ b/src/util/divisible.h
@@ -5,7 +5,7 @@
** Morgan Deters, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/floatingpoint.cpp b/src/util/floatingpoint.cpp
index 7403c340b..c5ec4d0c6 100644
--- a/src/util/floatingpoint.cpp
+++ b/src/util/floatingpoint.cpp
@@ -2,25 +2,30 @@
/*! \file floatingpoint.cpp
** \verbatim
** Top contributors (to current version):
- ** Martin Brain, Haniel Barbosa, Mathias Preiner
+ ** Martin Brain, Aina Niemetz, Haniel Barbosa
** Copyright (c) 2013 University of Oxford
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
- ** \brief [[ Implementations of the utility functions for working with floating point theories. ]]
+ ** \brief A floating-point value.
**
+ ** This file contains the data structures used by the constant and parametric
+ ** types of the floating point theory.
**/
#include "util/floatingpoint.h"
-#include "base/check.h"
-#include "util/integer.h"
#include <math.h>
+
#include <limits>
+#include "base/check.h"
+#include "util/floatingpoint_literal_symfpu.h"
+#include "util/integer.h"
+
#ifdef CVC4_USE_SYMFPU
#include "symfpu/core/add.h"
#include "symfpu/core/classify.h"
@@ -38,19 +43,21 @@
#include "symfpu/utils/properties.h"
#endif
+/* -------------------------------------------------------------------------- */
+
#ifdef CVC4_USE_SYMFPU
namespace symfpu {
-#define CVC4_LIT_ITE_DFN(T) \
- template <> \
- struct ite<::CVC4::symfpuLiteral::prop, T> \
- { \
- static const T &iteOp(const ::CVC4::symfpuLiteral::prop &cond, \
- const T &l, \
- const T &r) \
- { \
- return cond ? l : r; \
- } \
+#define CVC4_LIT_ITE_DFN(T) \
+ template <> \
+ struct ite<::CVC4::symfpuLiteral::CVC4Prop, T> \
+ { \
+ static const T& iteOp(const ::CVC4::symfpuLiteral::CVC4Prop& cond, \
+ const T& l, \
+ const T& r) \
+ { \
+ return cond ? l : r; \
+ } \
}
CVC4_LIT_ITE_DFN(::CVC4::symfpuLiteral::traits::rm);
@@ -62,859 +69,678 @@ CVC4_LIT_ITE_DFN(::CVC4::symfpuLiteral::traits::ubv);
}
#endif
-#ifndef CVC4_USE_SYMFPU
-#define PRECONDITION(X) Assert((X))
-#endif
+/* -------------------------------------------------------------------------- */
namespace CVC4 {
-FloatingPointSize::FloatingPointSize (unsigned _e, unsigned _s) : e(_e), s(_s)
-{
- PrettyCheckArgument(validExponentSize(_e),_e,"Invalid exponent size : %d",_e);
- PrettyCheckArgument(validSignificandSize(_s),_s,"Invalid significand size : %d",_s);
-}
+/* -------------------------------------------------------------------------- */
-FloatingPointSize::FloatingPointSize (const FloatingPointSize &old) : e(old.e), s(old.s)
+uint32_t FloatingPoint::getUnpackedExponentWidth(FloatingPointSize& size)
{
- PrettyCheckArgument(validExponentSize(e),e,"Invalid exponent size : %d",e);
- PrettyCheckArgument(validSignificandSize(s),s,"Invalid significand size : %d",s);
-}
-
-namespace symfpuLiteral {
-
-// To simplify the property macros
-typedef traits t;
-
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::one(const bwt &w)
-{
- return wrappedBitVector<isSigned>(w, 1);
-}
-
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::zero(const bwt &w)
-{
- return wrappedBitVector<isSigned>(w, 0);
+#ifdef CVC4_USE_SYMFPU
+ return SymFPUUnpackedFloatLiteral::exponentWidth(size);
+#else
+ Unreachable() << "no concrete implementation of FloatingPointLiteral";
+ return 2;
+#endif
}
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::allOnes(const bwt &w)
+uint32_t FloatingPoint::getUnpackedSignificandWidth(FloatingPointSize& size)
{
- return ~wrappedBitVector<isSigned>::zero(w);
+#ifdef CVC4_USE_SYMFPU
+ return SymFPUUnpackedFloatLiteral::significandWidth(size);
+#else
+ Unreachable() << "no concrete implementation of FloatingPointLiteral";
+ return 2;
+#endif
}
-template <bool isSigned>
-prop wrappedBitVector<isSigned>::isAllOnes() const
-{
- return (*this == wrappedBitVector<isSigned>::allOnes(this->getWidth()));
-}
-template <bool isSigned>
-prop wrappedBitVector<isSigned>::isAllZeros() const
+FloatingPoint::FloatingPoint(uint32_t d_exp_size,
+ uint32_t d_sig_size,
+ const BitVector& bv)
+ : d_fp_size(d_exp_size, d_sig_size),
+#ifdef CVC4_USE_SYMFPU
+ d_fpl(new FloatingPointLiteral(symfpu::unpack<symfpuLiteral::traits>(
+ symfpuLiteral::CVC4FPSize(d_exp_size, d_sig_size), bv)))
+#else
+ d_fpl(new FloatingPointLiteral(d_exp_size, d_sig_size, 0.0))
+#endif
{
- return (*this == wrappedBitVector<isSigned>::zero(this->getWidth()));
}
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::maxValue(const bwt &w)
+FloatingPoint::FloatingPoint(const FloatingPointSize& size, const BitVector& bv)
+ : d_fp_size(size),
+#ifdef CVC4_USE_SYMFPU
+ d_fpl(new FloatingPointLiteral(
+ symfpu::unpack<symfpuLiteral::traits>(size, bv)))
+#else
+ d_fpl(new FloatingPointLiteral(
+ size.exponentWidth(), size.significandWidth(), 0.0))
+#endif
{
- if (isSigned)
- {
- BitVector base(w - 1, 0U);
- return wrappedBitVector<true>((~base).zeroExtend(1));
- }
- else
- {
- return wrappedBitVector<false>::allOnes(w);
- }
}
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::minValue(const bwt &w)
+FloatingPoint::FloatingPoint(const FloatingPointSize& size,
+ const RoundingMode& rm,
+ const BitVector& bv,
+ bool signedBV)
+ : d_fp_size(size)
{
- if (isSigned)
+#ifdef CVC4_USE_SYMFPU
+ if (signedBV)
{
- BitVector base(w, 1U);
- BitVector shiftAmount(w, w - 1);
- BitVector result(base.leftShift(shiftAmount));
- return wrappedBitVector<true>(result);
+ d_fpl = new FloatingPointLiteral(
+ symfpu::convertSBVToFloat<symfpuLiteral::traits>(
+ symfpuLiteral::CVC4FPSize(size),
+ symfpuLiteral::CVC4RM(rm),
+ symfpuLiteral::CVC4SignedBitVector(bv)));
}
else
{
- return wrappedBitVector<false>::zero(w);
+ d_fpl = new FloatingPointLiteral(
+ symfpu::convertUBVToFloat<symfpuLiteral::traits>(
+ symfpuLiteral::CVC4FPSize(size),
+ symfpuLiteral::CVC4RM(rm),
+ symfpuLiteral::CVC4UnsignedBitVector(bv)));
}
+#else
+ d_fpl = new FloatingPointLiteral(2, 2, 0.0);
+#endif
}
-/*** Operators ***/
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::operator<<(
- const wrappedBitVector<isSigned> &op) const
-{
- return this->BitVector::leftShift(op);
-}
-
-template <>
-wrappedBitVector<true> wrappedBitVector<true>::operator>>(
- const wrappedBitVector<true> &op) const
-{
- return this->BitVector::arithRightShift(op);
-}
-
-template <>
-wrappedBitVector<false> wrappedBitVector<false>::operator>>(
- const wrappedBitVector<false> &op) const
-{
- return this->BitVector::logicalRightShift(op);
-}
-
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::operator|(
- const wrappedBitVector<isSigned> &op) const
-{
- return this->BitVector::operator|(op);
-}
-
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::operator&(
- const wrappedBitVector<isSigned> &op) const
-{
- return this->BitVector::operator&(op);
-}
-
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::operator+(
- const wrappedBitVector<isSigned> &op) const
-{
- return this->BitVector::operator+(op);
-}
-
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::operator-(
- const wrappedBitVector<isSigned> &op) const
-{
- return this->BitVector::operator-(op);
-}
-
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::operator*(
- const wrappedBitVector<isSigned> &op) const
-{
- return this->BitVector::operator*(op);
-}
-
-template <>
-wrappedBitVector<false> wrappedBitVector<false>::operator/(
- const wrappedBitVector<false> &op) const
-{
- return this->BitVector::unsignedDivTotal(op);
-}
-
-template <>
-wrappedBitVector<false> wrappedBitVector<false>::operator%(
- const wrappedBitVector<false> &op) const
-{
- return this->BitVector::unsignedRemTotal(op);
-}
-
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::operator-(void) const
-{
- return this->BitVector::operator-();
-}
-
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::operator~(void)const
-{
- return this->BitVector::operator~();
-}
-
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::increment() const
+FloatingPoint::FloatingPoint(const FloatingPointSize& fp_size,
+ const FloatingPointLiteral* fpl)
+ : d_fp_size(fp_size)
{
- return *this + wrappedBitVector<isSigned>::one(this->getWidth());
+ d_fpl = new FloatingPointLiteral(*fpl);
}
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::decrement() const
+FloatingPoint::FloatingPoint(const FloatingPoint& fp) : d_fp_size(fp.d_fp_size)
{
- return *this - wrappedBitVector<isSigned>::one(this->getWidth());
+ d_fpl = new FloatingPointLiteral(*fp.d_fpl);
}
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::signExtendRightShift(
- const wrappedBitVector<isSigned> &op) const
+FloatingPoint::FloatingPoint(const FloatingPointSize& size,
+ const RoundingMode& rm,
+ const Rational& r)
+ : d_fp_size(size)
{
- return this->BitVector::arithRightShift(BitVector(this->getWidth(), op));
-}
+ Rational two(2, 1);
-/*** Modular opertaions ***/
-// No overflow checking so these are the same as other operations
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::modularLeftShift(
- const wrappedBitVector<isSigned> &op) const
-{
- return *this << op;
-}
+ if (r.isZero())
+ {
+#ifdef CVC4_USE_SYMFPU
+ // In keeping with the SMT-LIB standard
+ d_fpl = new FloatingPointLiteral(
+ SymFPUUnpackedFloatLiteral::makeZero(size, false));
+#else
+ d_fpl = new FloatingPointLiteral(2, 2, 0.0);
+#endif
+ }
+ else
+ {
+#ifdef CVC4_USE_SYMFPU
+ uint32_t negative = (r.sgn() < 0) ? 1 : 0;
+#endif
+ Rational rabs(r.abs());
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::modularRightShift(
- const wrappedBitVector<isSigned> &op) const
-{
- return *this >> op;
-}
+ // Compute the exponent
+ Integer exp(0U);
+ Integer inc(1U);
+ Rational working(1, 1);
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::modularIncrement() const
-{
- return this->increment();
-}
+ if (rabs != working)
+ {
+ if (rabs < working)
+ {
+ while (rabs < working)
+ {
+ exp -= inc;
+ working /= two;
+ }
+ }
+ else
+ {
+ while (rabs >= working)
+ {
+ exp += inc;
+ working *= two;
+ }
+ exp -= inc;
+ working /= two;
+ }
+ }
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::modularDecrement() const
-{
- return this->decrement();
-}
+ Assert(working <= rabs);
+ Assert(rabs < working * two);
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::modularAdd(
- const wrappedBitVector<isSigned> &op) const
-{
- return *this + op;
-}
+ // Work out the number of bits required to represent the exponent for a
+ // normal number
+ uint32_t expBits = 2; // No point starting with an invalid amount
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::modularNegate() const
-{
- return -(*this);
-}
+ Integer doubleInt(2);
+ if (exp.strictlyPositive())
+ {
+ // 1 more than exactly representable with expBits
+ Integer representable(4);
+ while (representable <= exp)
+ { // hence <=
+ representable *= doubleInt;
+ ++expBits;
+ }
+ }
+ else if (exp.strictlyNegative())
+ {
+ Integer representable(-4); // Exactly representable with expBits + sign
+ // but -2^n and -(2^n - 1) are both subnormal
+ while ((representable + doubleInt) > exp)
+ {
+ representable *= doubleInt;
+ ++expBits;
+ }
+ }
+ ++expBits; // To allow for sign
-/*** Comparisons ***/
+ BitVector exactExp(expBits, exp);
-template <bool isSigned>
-prop wrappedBitVector<isSigned>::operator==(
- const wrappedBitVector<isSigned> &op) const
-{
- return this->BitVector::operator==(op);
-}
+ // Compute the significand.
+ uint32_t sigBits = size.significandWidth() + 2; // guard and sticky bits
+ BitVector sig(sigBits, 0U);
+ BitVector one(sigBits, 1U);
+ Rational workingSig(0, 1);
+ for (uint32_t i = 0; i < sigBits - 1; ++i)
+ {
+ Rational mid(workingSig + working);
-template <>
-prop wrappedBitVector<true>::operator<=(const wrappedBitVector<true> &op) const
-{
- return this->signedLessThanEq(op);
-}
+ if (mid <= rabs)
+ {
+ sig = sig | one;
+ workingSig = mid;
+ }
-template <>
-prop wrappedBitVector<true>::operator>=(const wrappedBitVector<true> &op) const
-{
- return !(this->signedLessThan(op));
-}
+ sig = sig.leftShift(one);
+ working /= two;
+ }
-template <>
-prop wrappedBitVector<true>::operator<(const wrappedBitVector<true> &op) const
-{
- return this->signedLessThan(op);
-}
+ // Compute the sticky bit
+ Rational remainder(rabs - workingSig);
+ Assert(Rational(0, 1) <= remainder);
-template <>
-prop wrappedBitVector<true>::operator>(const wrappedBitVector<true> &op) const
-{
- return !(this->signedLessThanEq(op));
-}
+ if (!remainder.isZero())
+ {
+ sig = sig | one;
+ }
-template <>
-prop wrappedBitVector<false>::operator<=(
- const wrappedBitVector<false> &op) const
-{
- return this->unsignedLessThanEq(op);
-}
+ // Build an exact float
+ FloatingPointSize exactFormat(expBits, sigBits);
-template <>
-prop wrappedBitVector<false>::operator>=(
- const wrappedBitVector<false> &op) const
-{
- return !(this->unsignedLessThan(op));
-}
+ // A small subtlety... if the format has expBits the unpacked format
+ // may have more to allow subnormals to be normalised.
+ // Thus...
+#ifdef CVC4_USE_SYMFPU
+ uint32_t extension =
+ SymFPUUnpackedFloatLiteral::exponentWidth(exactFormat) - expBits;
-template <>
-prop wrappedBitVector<false>::operator<(const wrappedBitVector<false> &op) const
-{
- return this->unsignedLessThan(op);
-}
+ FloatingPointLiteral exactFloat(
+ negative, exactExp.signExtend(extension), sig);
-template <>
-prop wrappedBitVector<false>::operator>(const wrappedBitVector<false> &op) const
-{
- return !(this->unsignedLessThanEq(op));
+ // Then cast...
+ d_fpl = new FloatingPointLiteral(
+ symfpu::convertFloatToFloat(exactFormat, size, rm, exactFloat.d_symuf));
+#else
+ Unreachable() << "no concrete implementation of FloatingPointLiteral";
+#endif
+ }
}
-/*** Type conversion ***/
-// CVC4 nodes make no distinction between signed and unsigned, thus ...
-template <bool isSigned>
-wrappedBitVector<true> wrappedBitVector<isSigned>::toSigned(void) const
+FloatingPoint::~FloatingPoint()
{
- return wrappedBitVector<true>(*this);
+ delete d_fpl;
+ d_fpl = nullptr;
}
-template <bool isSigned>
-wrappedBitVector<false> wrappedBitVector<isSigned>::toUnsigned(void) const
+FloatingPoint FloatingPoint::makeNaN(const FloatingPointSize& size)
{
- return wrappedBitVector<false>(*this);
+#ifdef CVC4_USE_SYMFPU
+ return FloatingPoint(
+ size,
+ new FloatingPointLiteral(SymFPUUnpackedFloatLiteral::makeNaN(size)));
+#else
+ return FloatingPoint(2, 2, BitVector(4U, 0U));
+#endif
}
-/*** Bit hacks ***/
-
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::extend(
- bwt extension) const
+FloatingPoint FloatingPoint::makeInf(const FloatingPointSize& size, bool sign)
{
- if (isSigned)
- {
- return this->BitVector::signExtend(extension);
- }
- else
- {
- return this->BitVector::zeroExtend(extension);
- }
+#ifdef CVC4_USE_SYMFPU
+ return FloatingPoint(size,
+ new FloatingPointLiteral(
+ SymFPUUnpackedFloatLiteral::makeInf(size, sign)));
+#else
+ return FloatingPoint(2, 2, BitVector(4U, 0U));
+#endif
}
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::contract(
- bwt reduction) const
+FloatingPoint FloatingPoint::makeZero(const FloatingPointSize& size, bool sign)
{
- PRECONDITION(this->getWidth() > reduction);
-
- return this->extract((this->getWidth() - 1) - reduction, 0);
+#ifdef CVC4_USE_SYMFPU
+ return FloatingPoint(size,
+ new FloatingPointLiteral(
+ SymFPUUnpackedFloatLiteral::makeZero(size, sign)));
+#else
+ return FloatingPoint(2, 2, BitVector(4U, 0U));
+#endif
}
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::resize(bwt newSize) const
+FloatingPoint FloatingPoint::makeMinSubnormal(const FloatingPointSize& size,
+ bool sign)
{
- bwt width = this->getWidth();
-
- if (newSize > width)
- {
- return this->extend(newSize - width);
- }
- else if (newSize < width)
- {
- return this->contract(width - newSize);
- }
- else
- {
- return *this;
- }
+ BitVector bvsign = sign ? BitVector::mkOne(1) : BitVector::mkZero(1);
+ BitVector bvexp = BitVector::mkZero(size.packedExponentWidth());
+ BitVector bvsig = BitVector::mkOne(size.packedSignificandWidth());
+ return FloatingPoint(size, bvsign.concat(bvexp).concat(bvsig));
}
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::matchWidth(
- const wrappedBitVector<isSigned> &op) const
+FloatingPoint FloatingPoint::makeMaxSubnormal(const FloatingPointSize& size,
+ bool sign)
{
- PRECONDITION(this->getWidth() <= op.getWidth());
- return this->extend(op.getWidth() - this->getWidth());
+ BitVector bvsign = sign ? BitVector::mkOne(1) : BitVector::mkZero(1);
+ BitVector bvexp = BitVector::mkZero(size.packedExponentWidth());
+ BitVector bvsig = BitVector::mkOnes(size.packedSignificandWidth());
+ return FloatingPoint(size, bvsign.concat(bvexp).concat(bvsig));
}
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::append(
- const wrappedBitVector<isSigned> &op) const
+FloatingPoint FloatingPoint::makeMinNormal(const FloatingPointSize& size,
+ bool sign)
{
- return this->BitVector::concat(op);
+ BitVector bvsign = sign ? BitVector::mkOne(1) : BitVector::mkZero(1);
+ BitVector bvexp = BitVector::mkOne(size.packedExponentWidth());
+ BitVector bvsig = BitVector::mkZero(size.packedSignificandWidth());
+ return FloatingPoint(size, bvsign.concat(bvexp).concat(bvsig));
}
-// Inclusive of end points, thus if the same, extracts just one bit
-template <bool isSigned>
-wrappedBitVector<isSigned> wrappedBitVector<isSigned>::extract(bwt upper,
- bwt lower) const
+FloatingPoint FloatingPoint::makeMaxNormal(const FloatingPointSize& size,
+ bool sign)
{
- PRECONDITION(upper >= lower);
- return this->BitVector::extract(upper, lower);
+ BitVector bvsign = sign ? BitVector::mkOne(1) : BitVector::mkZero(1);
+ BitVector bvexp =
+ BitVector::mkOnes(size.packedExponentWidth()).setBit(0, false);
+ BitVector bvsig = BitVector::mkOnes(size.packedSignificandWidth());
+ return FloatingPoint(size, bvsign.concat(bvexp).concat(bvsig));
}
-// Explicit instantiation
-template class wrappedBitVector<true>;
-template class wrappedBitVector<false>;
-
-rm traits::RNE(void) { return ::CVC4::roundNearestTiesToEven; };
-rm traits::RNA(void) { return ::CVC4::roundNearestTiesToAway; };
-rm traits::RTP(void) { return ::CVC4::roundTowardPositive; };
-rm traits::RTN(void) { return ::CVC4::roundTowardNegative; };
-rm traits::RTZ(void) { return ::CVC4::roundTowardZero; };
-// This is a literal back-end so props are actually bools
-// so these can be handled in the same way as the internal assertions above
-
-void traits::precondition(const prop &p)
-{
- AlwaysAssert(p);
- return;
-}
-void traits::postcondition(const prop &p)
-{
- AlwaysAssert(p);
- return;
-}
-void traits::invariant(const prop &p)
+/* Operations implemented using symfpu */
+FloatingPoint FloatingPoint::absolute(void) const
{
- AlwaysAssert(p);
- return;
-}
-}
-
-#ifndef CVC4_USE_SYMFPU
-void FloatingPointLiteral::unfinished(void) const
-{
- Unimplemented() << "Floating-point literals not yet implemented.";
-}
-#endif
-
-FloatingPoint::FloatingPoint(unsigned e, unsigned s, const BitVector &bv)
- :
#ifdef CVC4_USE_SYMFPU
- fpl(symfpu::unpack<symfpuLiteral::traits>(symfpuLiteral::fpt(e, s), bv)),
+ return FloatingPoint(
+ d_fp_size,
+ new FloatingPointLiteral(
+ symfpu::absolute<symfpuLiteral::traits>(d_fp_size, d_fpl->d_symuf)));
#else
- fpl(e, s, 0.0),
+ return *this;
#endif
- t(e, s)
-{
}
-static FloatingPointLiteral constructorHelperBitVector(
- const FloatingPointSize &ct,
- const RoundingMode &rm,
- const BitVector &bv,
- bool signedBV)
+FloatingPoint FloatingPoint::negate(void) const
{
#ifdef CVC4_USE_SYMFPU
- if (signedBV)
- {
- return FloatingPointLiteral(
- symfpu::convertSBVToFloat<symfpuLiteral::traits>(
- symfpuLiteral::fpt(ct),
- symfpuLiteral::rm(rm),
- symfpuLiteral::sbv(bv)));
- }
- else
- {
- return FloatingPointLiteral(
- symfpu::convertUBVToFloat<symfpuLiteral::traits>(
- symfpuLiteral::fpt(ct),
- symfpuLiteral::rm(rm),
- symfpuLiteral::ubv(bv)));
- }
+ return FloatingPoint(
+ d_fp_size,
+ new FloatingPointLiteral(
+ symfpu::negate<symfpuLiteral::traits>(d_fp_size, d_fpl->d_symuf)));
#else
- return FloatingPointLiteral(2, 2, 0.0);
+ return *this;
#endif
- Unreachable() << "Constructor helper broken";
- }
-
- FloatingPoint::FloatingPoint (const FloatingPointSize &ct, const RoundingMode &rm, const BitVector &bv, bool signedBV) :
- fpl(constructorHelperBitVector(ct, rm, bv, signedBV)),
- t(ct) {}
+}
-
- static FloatingPointLiteral constructorHelperRational (const FloatingPointSize &ct, const RoundingMode &rm, const Rational &ri) {
- Rational r(ri);
- Rational two(2,1);
-
- if (r.isZero()) {
+FloatingPoint FloatingPoint::plus(const RoundingMode& rm,
+ const FloatingPoint& arg) const
+{
#ifdef CVC4_USE_SYMFPU
- return FloatingPointLiteral::makeZero(
- ct, false); // In keeping with the SMT-LIB standard
+ Assert(d_fp_size == arg.d_fp_size);
+ return FloatingPoint(
+ d_fp_size,
+ new FloatingPointLiteral(symfpu::add<symfpuLiteral::traits>(
+ d_fp_size, rm, d_fpl->d_symuf, arg.d_fpl->d_symuf, true)));
#else
- return FloatingPointLiteral(2,2,0.0);
-#endif
- } else {
-#ifdef CVC4_USE_SYMFPU
- int negative = (r.sgn() < 0) ? 1 : 0;
+ return *this;
#endif
- r = r.abs();
-
- // Compute the exponent
- Integer exp(0U);
- Integer inc(1U);
- Rational working(1,1);
-
- if (r == working) {
-
- } else if ( r < working ) {
- while (r < working) {
- exp -= inc;
- working /= two;
- }
- } else {
- while (r >= working) {
- exp += inc;
- working *= two;
- }
- exp -= inc;
- working /= two;
- }
-
- Assert(working <= r);
- Assert(r < working * two);
-
- // Work out the number of bits required to represent the exponent for a normal number
- unsigned expBits = 2; // No point starting with an invalid amount
-
- Integer doubleInt(2);
- if (exp.strictlyPositive()) {
- Integer representable(4); // 1 more than exactly representable with expBits
- while (representable <= exp) {// hence <=
- representable *= doubleInt;
- ++expBits;
- }
- } else if (exp.strictlyNegative()) {
- Integer representable(-4); // Exactly representable with expBits + sign
- // but -2^n and -(2^n - 1) are both subnormal
- while ((representable + doubleInt) > exp) {
- representable *= doubleInt;
- ++expBits;
- }
- }
- ++expBits; // To allow for sign
-
- BitVector exactExp(expBits, exp);
-
-
-
- // Compute the significand.
- unsigned sigBits = ct.significandWidth() + 2; // guard and sticky bits
- BitVector sig(sigBits, 0U);
- BitVector one(sigBits, 1U);
- Rational workingSig(0,1);
- for (unsigned i = 0; i < sigBits - 1; ++i) {
- Rational mid(workingSig + working);
-
- if (mid <= r) {
- sig = sig | one;
- workingSig = mid;
- }
-
- sig = sig.leftShift(one);
- working /= two;
- }
-
- // Compute the sticky bit
- Rational remainder(r - workingSig);
- Assert(Rational(0, 1) <= remainder);
-
- if (!remainder.isZero()) {
- sig = sig | one;
- }
-
- // Build an exact float
- FloatingPointSize exactFormat(expBits, sigBits);
+}
- // A small subtlety... if the format has expBits the unpacked format
- // may have more to allow subnormals to be normalised.
- // Thus...
+FloatingPoint FloatingPoint::sub(const RoundingMode& rm,
+ const FloatingPoint& arg) const
+{
#ifdef CVC4_USE_SYMFPU
- unsigned extension =
- FloatingPointLiteral::exponentWidth(exactFormat) - expBits;
-
- FloatingPointLiteral exactFloat(
- negative, exactExp.signExtend(extension), sig);
-
- // Then cast...
- FloatingPointLiteral rounded(
- symfpu::convertFloatToFloat(exactFormat, ct, rm, exactFloat));
- return rounded;
+ Assert(d_fp_size == arg.d_fp_size);
+ return FloatingPoint(
+ d_fp_size,
+ new FloatingPointLiteral(symfpu::add<symfpuLiteral::traits>(
+ d_fp_size, rm, d_fpl->d_symuf, arg.d_fpl->d_symuf, false)));
#else
- Unreachable() << "no concrete implementation of FloatingPointLiteral";
+ return *this;
#endif
- }
- Unreachable() << "Constructor helper broken";
- }
-
- FloatingPoint::FloatingPoint (const FloatingPointSize &ct, const RoundingMode &rm, const Rational &r) :
- fpl(constructorHelperRational(ct, rm, r)),
- t(ct) {}
+}
-
- FloatingPoint FloatingPoint::makeNaN (const FloatingPointSize &t) {
+FloatingPoint FloatingPoint::mult(const RoundingMode& rm,
+ const FloatingPoint& arg) const
+{
#ifdef CVC4_USE_SYMFPU
- return FloatingPoint(
- t, symfpu::unpackedFloat<symfpuLiteral::traits>::makeNaN(t));
+ Assert(d_fp_size == arg.d_fp_size);
+ return FloatingPoint(
+ d_fp_size,
+ new FloatingPointLiteral(symfpu::multiply<symfpuLiteral::traits>(
+ d_fp_size, rm, d_fpl->d_symuf, arg.d_fpl->d_symuf)));
#else
- return FloatingPoint(2, 2, BitVector(4U,0U));
+ return *this;
#endif
- }
+}
- FloatingPoint FloatingPoint::makeInf (const FloatingPointSize &t, bool sign) {
+FloatingPoint FloatingPoint::fma(const RoundingMode& rm,
+ const FloatingPoint& arg1,
+ const FloatingPoint& arg2) const
+{
#ifdef CVC4_USE_SYMFPU
- return FloatingPoint(
- t, symfpu::unpackedFloat<symfpuLiteral::traits>::makeInf(t, sign));
+ Assert(d_fp_size == arg1.d_fp_size);
+ Assert(d_fp_size == arg2.d_fp_size);
+ return FloatingPoint(
+ d_fp_size,
+ new FloatingPointLiteral(
+ symfpu::fma<symfpuLiteral::traits>(d_fp_size,
+ rm,
+ d_fpl->d_symuf,
+ arg1.d_fpl->d_symuf,
+ arg2.d_fpl->d_symuf)));
#else
- return FloatingPoint(2, 2, BitVector(4U,0U));
+ return *this;
#endif
- }
+}
- FloatingPoint FloatingPoint::makeZero (const FloatingPointSize &t, bool sign) {
+FloatingPoint FloatingPoint::div(const RoundingMode& rm,
+ const FloatingPoint& arg) const
+{
#ifdef CVC4_USE_SYMFPU
- return FloatingPoint(
- t, symfpu::unpackedFloat<symfpuLiteral::traits>::makeZero(t, sign));
+ Assert(d_fp_size == arg.d_fp_size);
+ return FloatingPoint(
+ d_fp_size,
+ new FloatingPointLiteral(symfpu::divide<symfpuLiteral::traits>(
+ d_fp_size, rm, d_fpl->d_symuf, arg.d_fpl->d_symuf)));
#else
- return FloatingPoint(2, 2, BitVector(4U,0U));
+ return *this;
#endif
- }
-
+}
- /* Operations implemented using symfpu */
- FloatingPoint FloatingPoint::absolute (void) const {
-#ifdef CVC4_USE_SYMFPU
- return FloatingPoint(t, symfpu::absolute<symfpuLiteral::traits>(t, fpl));
-#else
- return *this;
-#endif
- }
-
- FloatingPoint FloatingPoint::negate (void) const {
-#ifdef CVC4_USE_SYMFPU
- return FloatingPoint(t, symfpu::negate<symfpuLiteral::traits>(t, fpl));
-#else
- return *this;
-#endif
- }
-
- FloatingPoint FloatingPoint::plus (const RoundingMode &rm, const FloatingPoint &arg) const {
+FloatingPoint FloatingPoint::sqrt(const RoundingMode& rm) const
+{
#ifdef CVC4_USE_SYMFPU
- Assert(this->t == arg.t);
- return FloatingPoint(
- t, symfpu::add<symfpuLiteral::traits>(t, rm, fpl, arg.fpl, true));
+ return FloatingPoint(
+ d_fp_size,
+ new FloatingPointLiteral(
+ symfpu::sqrt<symfpuLiteral::traits>(d_fp_size, rm, d_fpl->d_symuf)));
#else
- return *this;
+ return *this;
#endif
- }
+}
- FloatingPoint FloatingPoint::sub (const RoundingMode &rm, const FloatingPoint &arg) const {
+FloatingPoint FloatingPoint::rti(const RoundingMode& rm) const
+{
#ifdef CVC4_USE_SYMFPU
- Assert(this->t == arg.t);
- return FloatingPoint(
- t, symfpu::add<symfpuLiteral::traits>(t, rm, fpl, arg.fpl, false));
+ return FloatingPoint(
+ d_fp_size,
+ new FloatingPointLiteral(symfpu::roundToIntegral<symfpuLiteral::traits>(
+ d_fp_size, rm, d_fpl->d_symuf)));
#else
- return *this;
+ return *this;
#endif
- }
+}
- FloatingPoint FloatingPoint::mult (const RoundingMode &rm, const FloatingPoint &arg) const {
+FloatingPoint FloatingPoint::rem(const FloatingPoint& arg) const
+{
#ifdef CVC4_USE_SYMFPU
- Assert(this->t == arg.t);
- return FloatingPoint(
- t, symfpu::multiply<symfpuLiteral::traits>(t, rm, fpl, arg.fpl));
+ Assert(d_fp_size == arg.d_fp_size);
+ return FloatingPoint(
+ d_fp_size,
+ new FloatingPointLiteral(symfpu::remainder<symfpuLiteral::traits>(
+ d_fp_size, d_fpl->d_symuf, arg.d_fpl->d_symuf)));
#else
- return *this;
+ return *this;
#endif
- }
+}
- FloatingPoint FloatingPoint::fma (const RoundingMode &rm, const FloatingPoint &arg1, const FloatingPoint &arg2) const {
+FloatingPoint FloatingPoint::maxTotal(const FloatingPoint& arg,
+ bool zeroCaseLeft) const
+{
#ifdef CVC4_USE_SYMFPU
- Assert(this->t == arg1.t);
- Assert(this->t == arg2.t);
- return FloatingPoint(
- t, symfpu::fma<symfpuLiteral::traits>(t, rm, fpl, arg1.fpl, arg2.fpl));
+ Assert(d_fp_size == arg.d_fp_size);
+ return FloatingPoint(
+ d_fp_size,
+ new FloatingPointLiteral(symfpu::max<symfpuLiteral::traits>(
+ d_fp_size, d_fpl->d_symuf, arg.d_fpl->d_symuf, zeroCaseLeft)));
#else
- return *this;
+ return *this;
#endif
- }
+}
- FloatingPoint FloatingPoint::div (const RoundingMode &rm, const FloatingPoint &arg) const {
+FloatingPoint FloatingPoint::minTotal(const FloatingPoint& arg,
+ bool zeroCaseLeft) const
+{
#ifdef CVC4_USE_SYMFPU
- Assert(this->t == arg.t);
- return FloatingPoint(
- t, symfpu::divide<symfpuLiteral::traits>(t, rm, fpl, arg.fpl));
+ Assert(d_fp_size == arg.d_fp_size);
+ return FloatingPoint(
+ d_fp_size,
+ new FloatingPointLiteral(symfpu::min<symfpuLiteral::traits>(
+ d_fp_size, d_fpl->d_symuf, arg.d_fpl->d_symuf, zeroCaseLeft)));
#else
- return *this;
+ return *this;
#endif
- }
+}
- FloatingPoint FloatingPoint::sqrt (const RoundingMode &rm) const {
-#ifdef CVC4_USE_SYMFPU
- return FloatingPoint(t, symfpu::sqrt<symfpuLiteral::traits>(t, rm, fpl));
-#else
- return *this;
-#endif
- }
+FloatingPoint::PartialFloatingPoint FloatingPoint::max(
+ const FloatingPoint& arg) const
+{
+ FloatingPoint tmp(maxTotal(arg, true));
+ return PartialFloatingPoint(tmp, tmp == maxTotal(arg, false));
+}
- FloatingPoint FloatingPoint::rti (const RoundingMode &rm) const {
-#ifdef CVC4_USE_SYMFPU
- return FloatingPoint(
- t, symfpu::roundToIntegral<symfpuLiteral::traits>(t, rm, fpl));
-#else
- return *this;
-#endif
- }
+FloatingPoint::PartialFloatingPoint FloatingPoint::min(
+ const FloatingPoint& arg) const
+{
+ FloatingPoint tmp(minTotal(arg, true));
+ return PartialFloatingPoint(tmp, tmp == minTotal(arg, false));
+}
- FloatingPoint FloatingPoint::rem (const FloatingPoint &arg) const {
+bool FloatingPoint::operator==(const FloatingPoint& fp) const
+{
#ifdef CVC4_USE_SYMFPU
- Assert(this->t == arg.t);
- return FloatingPoint(
- t, symfpu::remainder<symfpuLiteral::traits>(t, fpl, arg.fpl));
+ return ((d_fp_size == fp.d_fp_size)
+ && symfpu::smtlibEqual<symfpuLiteral::traits>(
+ d_fp_size, d_fpl->d_symuf, fp.d_fpl->d_symuf));
#else
- return *this;
+ return ((d_fp_size == fp.d_fp_size));
#endif
- }
+}
- FloatingPoint FloatingPoint::maxTotal (const FloatingPoint &arg, bool zeroCaseLeft) const {
+bool FloatingPoint::operator<=(const FloatingPoint& arg) const
+{
#ifdef CVC4_USE_SYMFPU
- Assert(this->t == arg.t);
- return FloatingPoint(
- t, symfpu::max<symfpuLiteral::traits>(t, fpl, arg.fpl, zeroCaseLeft));
+ Assert(d_fp_size == arg.d_fp_size);
+ return symfpu::lessThanOrEqual<symfpuLiteral::traits>(
+ d_fp_size, d_fpl->d_symuf, arg.d_fpl->d_symuf);
#else
- return *this;
+ return false;
#endif
- }
-
- FloatingPoint FloatingPoint::minTotal (const FloatingPoint &arg, bool zeroCaseLeft) const {
+}
+
+bool FloatingPoint::operator<(const FloatingPoint& arg) const
+{
#ifdef CVC4_USE_SYMFPU
- Assert(this->t == arg.t);
- return FloatingPoint(
- t, symfpu::min<symfpuLiteral::traits>(t, fpl, arg.fpl, zeroCaseLeft));
+ Assert(d_fp_size == arg.d_fp_size);
+ return symfpu::lessThan<symfpuLiteral::traits>(
+ d_fp_size, d_fpl->d_symuf, arg.d_fpl->d_symuf);
#else
- return *this;
+ return false;
#endif
- }
-
- FloatingPoint::PartialFloatingPoint FloatingPoint::max (const FloatingPoint &arg) const {
- FloatingPoint tmp(maxTotal(arg, true));
- return PartialFloatingPoint(tmp, tmp == maxTotal(arg, false));
- }
-
- FloatingPoint::PartialFloatingPoint FloatingPoint::min (const FloatingPoint &arg) const {
- FloatingPoint tmp(minTotal(arg, true));
- return PartialFloatingPoint(tmp, tmp == minTotal(arg, false));
- }
+}
- bool FloatingPoint::operator ==(const FloatingPoint& fp) const {
+BitVector FloatingPoint::getExponent() const
+{
#ifdef CVC4_USE_SYMFPU
- return ((t == fp.t)
- && symfpu::smtlibEqual<symfpuLiteral::traits>(t, fpl, fp.fpl));
+ return d_fpl->d_symuf.exponent;
#else
- return ( (t == fp.t) );
+ Unreachable() << "no concrete implementation of FloatingPointLiteral";
+ return BitVector();
#endif
- }
+}
- bool FloatingPoint::operator <= (const FloatingPoint &arg) const {
+BitVector FloatingPoint::getSignificand() const
+{
#ifdef CVC4_USE_SYMFPU
- Assert(this->t == arg.t);
- return symfpu::lessThanOrEqual<symfpuLiteral::traits>(t, fpl, arg.fpl);
+ return d_fpl->d_symuf.significand;
#else
- return false;
+ Unreachable() << "no concrete implementation of FloatingPointLiteral";
+ return BitVector();
#endif
- }
+}
- bool FloatingPoint::operator < (const FloatingPoint &arg) const {
+bool FloatingPoint::getSign() const
+{
#ifdef CVC4_USE_SYMFPU
- Assert(this->t == arg.t);
- return symfpu::lessThan<symfpuLiteral::traits>(t, fpl, arg.fpl);
+ return d_fpl->d_symuf.sign;
#else
- return false;
+ Unreachable() << "no concrete implementation of FloatingPointLiteral";
+ return false;
#endif
- }
+}
- bool FloatingPoint::isNormal (void) const {
+bool FloatingPoint::isNormal(void) const
+{
#ifdef CVC4_USE_SYMFPU
- return symfpu::isNormal<symfpuLiteral::traits>(t, fpl);
+ return symfpu::isNormal<symfpuLiteral::traits>(d_fp_size, d_fpl->d_symuf);
#else
- return false;
+ return false;
#endif
- }
+}
- bool FloatingPoint::isSubnormal (void) const {
+bool FloatingPoint::isSubnormal(void) const
+{
#ifdef CVC4_USE_SYMFPU
- return symfpu::isSubnormal<symfpuLiteral::traits>(t, fpl);
+ return symfpu::isSubnormal<symfpuLiteral::traits>(d_fp_size, d_fpl->d_symuf);
#else
- return false;
+ return false;
#endif
- }
+}
- bool FloatingPoint::isZero (void) const {
+bool FloatingPoint::isZero(void) const
+{
#ifdef CVC4_USE_SYMFPU
- return symfpu::isZero<symfpuLiteral::traits>(t, fpl);
+ return symfpu::isZero<symfpuLiteral::traits>(d_fp_size, d_fpl->d_symuf);
#else
- return false;
+ return false;
#endif
- }
+}
- bool FloatingPoint::isInfinite (void) const {
+bool FloatingPoint::isInfinite(void) const
+{
#ifdef CVC4_USE_SYMFPU
- return symfpu::isInfinite<symfpuLiteral::traits>(t, fpl);
+ return symfpu::isInfinite<symfpuLiteral::traits>(d_fp_size, d_fpl->d_symuf);
#else
- return false;
+ return false;
#endif
- }
+}
- bool FloatingPoint::isNaN (void) const {
+bool FloatingPoint::isNaN(void) const
+{
#ifdef CVC4_USE_SYMFPU
- return symfpu::isNaN<symfpuLiteral::traits>(t, fpl);
+ return symfpu::isNaN<symfpuLiteral::traits>(d_fp_size, d_fpl->d_symuf);
#else
- return false;
+ return false;
#endif
- }
+}
- bool FloatingPoint::isNegative (void) const {
+bool FloatingPoint::isNegative(void) const
+{
#ifdef CVC4_USE_SYMFPU
- return symfpu::isNegative<symfpuLiteral::traits>(t, fpl);
+ return symfpu::isNegative<symfpuLiteral::traits>(d_fp_size, d_fpl->d_symuf);
#else
- return false;
+ return false;
#endif
- }
+}
- bool FloatingPoint::isPositive (void) const {
+bool FloatingPoint::isPositive(void) const
+{
#ifdef CVC4_USE_SYMFPU
- return symfpu::isPositive<symfpuLiteral::traits>(t, fpl);
+ return symfpu::isPositive<symfpuLiteral::traits>(d_fp_size, d_fpl->d_symuf);
#else
- return false;
+ return false;
#endif
- }
+}
- FloatingPoint FloatingPoint::convert (const FloatingPointSize &target, const RoundingMode &rm) const {
+FloatingPoint FloatingPoint::convert(const FloatingPointSize& target,
+ const RoundingMode& rm) const
+{
#ifdef CVC4_USE_SYMFPU
- return FloatingPoint(
- target,
- symfpu::convertFloatToFloat<symfpuLiteral::traits>(t, target, rm, fpl));
+ return FloatingPoint(target,
+ new FloatingPointLiteral(
+ symfpu::convertFloatToFloat<symfpuLiteral::traits>(
+ d_fp_size, target, rm, d_fpl->d_symuf)));
#else
- return *this;
+ return *this;
#endif
- }
-
- BitVector FloatingPoint::convertToBVTotal (BitVectorSize width, const RoundingMode &rm, bool signedBV, BitVector undefinedCase) const {
+}
+
+BitVector FloatingPoint::convertToBVTotal(BitVectorSize width,
+ const RoundingMode& rm,
+ bool signedBV,
+ BitVector undefinedCase) const
+{
#ifdef CVC4_USE_SYMFPU
if (signedBV)
return symfpu::convertFloatToSBV<symfpuLiteral::traits>(
- t, rm, fpl, width, undefinedCase);
+ d_fp_size, rm, d_fpl->d_symuf, width, undefinedCase);
else
return symfpu::convertFloatToUBV<symfpuLiteral::traits>(
- t, rm, fpl, width, undefinedCase);
+ d_fp_size, rm, d_fpl->d_symuf, width, undefinedCase);
#else
- return undefinedCase;
+ return undefinedCase;
#endif
- }
+}
- Rational FloatingPoint::convertToRationalTotal (Rational undefinedCase) const {
- PartialRational p(convertToRational());
+Rational FloatingPoint::convertToRationalTotal(Rational undefinedCase) const
+{
+ PartialRational p(convertToRational());
- return p.second ? p.first : undefinedCase;
- }
+ return p.second ? p.first : undefinedCase;
+}
- FloatingPoint::PartialBitVector FloatingPoint::convertToBV (BitVectorSize width, const RoundingMode &rm, bool signedBV) const {
- BitVector tmp(convertToBVTotal (width, rm, signedBV, BitVector(width, 0U)));
- BitVector confirm(convertToBVTotal (width, rm, signedBV, BitVector(width, 1U)));
+FloatingPoint::PartialBitVector FloatingPoint::convertToBV(
+ BitVectorSize width, const RoundingMode& rm, bool signedBV) const
+{
+ BitVector tmp(convertToBVTotal(width, rm, signedBV, BitVector(width, 0U)));
+ BitVector confirm(
+ convertToBVTotal(width, rm, signedBV, BitVector(width, 1U)));
- return PartialBitVector(tmp, tmp == confirm);
- }
+ return PartialBitVector(tmp, tmp == confirm);
+}
- FloatingPoint::PartialRational FloatingPoint::convertToRational (void) const {
- if (this->isNaN() || this->isInfinite()) {
- return PartialRational(Rational(0U, 1U), false);
- }
- if (this->isZero()) {
- return PartialRational(Rational(0U, 1U), true);
-
- } else {
-#ifdef CVC4_USE_SYMFPU
- Integer sign((this->fpl.getSign()) ? -1 : 1);
- Integer exp(
- this->fpl.getExponent().toSignedInteger()
- - (Integer(t.significand()
- - 1))); // -1 as forcibly normalised into the [1,2) range
- Integer significand(this->fpl.getSignificand().toInteger());
+FloatingPoint::PartialRational FloatingPoint::convertToRational(void) const
+{
+ if (isNaN() || isInfinite())
+ {
+ return PartialRational(Rational(0U, 1U), false);
+ }
+ if (isZero())
+ {
+ return PartialRational(Rational(0U, 1U), true);
+ }
+ else
+ {
+#ifdef CVC4_USE_SYMFPU
+ Integer sign((d_fpl->d_symuf.getSign()) ? -1 : 1);
+ Integer exp(
+ d_fpl->d_symuf.getExponent().toSignedInteger()
+ - (Integer(d_fp_size.significandWidth()
+ - 1))); // -1 as forcibly normalised into the [1,2) range
+ Integer significand(d_fpl->d_symuf.getSignificand().toInteger());
#else
Integer sign(0);
Integer exp(0);
@@ -945,35 +771,36 @@ static FloatingPointLiteral constructorHelperBitVector(
Rational r(signedSignificand, q);
return PartialRational(r, true);
}
- }
+ }
Unreachable() << "Convert float literal to real broken.";
- }
+}
- BitVector FloatingPoint::pack (void) const {
+BitVector FloatingPoint::pack(void) const
+{
#ifdef CVC4_USE_SYMFPU
- BitVector bv(symfpu::pack<symfpuLiteral::traits>(this->t, this->fpl));
+ BitVector bv(symfpu::pack<symfpuLiteral::traits>(d_fp_size, d_fpl->d_symuf));
#else
- BitVector bv(4u,0u);
+ BitVector bv(4u, 0u);
#endif
- return bv;
- }
+ return bv;
+}
std::string FloatingPoint::toString(bool printAsIndexed) const
{
std::string str;
// retrive BV value
BitVector bv(pack());
- unsigned largestSignificandBit =
- t.significand() - 2; // -1 for -inclusive, -1 for hidden
- unsigned largestExponentBit =
- (t.exponent() - 1) + (largestSignificandBit + 1);
+ uint32_t largestSignificandBit =
+ d_fp_size.significandWidth() - 2; // -1 for -inclusive, -1 for hidden
+ uint32_t largestExponentBit =
+ (d_fp_size.exponentWidth() - 1) + (largestSignificandBit + 1);
BitVector v[3];
v[0] = bv.extract(largestExponentBit + 1, largestExponentBit + 1);
v[1] = bv.extract(largestExponentBit, largestSignificandBit + 1);
v[2] = bv.extract(largestSignificandBit, 0);
str.append("(fp ");
- for (unsigned i = 0; i < 3; ++i)
+ for (uint32_t i = 0; i < 3; ++i)
{
if (printAsIndexed)
{
@@ -993,7 +820,25 @@ std::string FloatingPoint::toString(bool printAsIndexed) const
str.append(" ");
}
}
+ str.append(")");
return str;
}
+std::ostream& operator<<(std::ostream& os, const FloatingPoint& fp)
+{
+ // print in binary notation
+ return os << fp.toString();
+}
+
+std::ostream& operator<<(std::ostream& os, const FloatingPointSize& fps)
+{
+ return os << "(_ FloatingPoint " << fps.exponentWidth() << " "
+ << fps.significandWidth() << ")";
+}
+
+std::ostream& operator<<(std::ostream& os, const FloatingPointConvertSort& fpcs)
+{
+ return os << "(_ to_fp " << fpcs.d_fp_size.exponentWidth() << " "
+ << fpcs.d_fp_size.significandWidth() << ")";
+}
}/* CVC4 namespace */
diff --git a/src/util/floatingpoint.h b/src/util/floatingpoint.h
new file mode 100644
index 000000000..754c38290
--- /dev/null
+++ b/src/util/floatingpoint.h
@@ -0,0 +1,516 @@
+/********************* */
+/*! \file floatingpoint.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Aina Niemetz, Martin Brain, Mathias Preiner
+ ** Copyright (c) 2013 University of Oxford
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief A floating-point value.
+ **
+ ** This file contains the data structures used by the constant and parametric
+ ** types of the floating point theory.
+ **/
+#include "cvc4_public.h"
+
+#ifndef CVC4__FLOATINGPOINT_H
+#define CVC4__FLOATINGPOINT_H
+
+#include "util/bitvector.h"
+#include "util/floatingpoint_size.h"
+#include "util/rational.h"
+#include "util/roundingmode.h"
+
+/* -------------------------------------------------------------------------- */
+
+namespace CVC4 {
+
+/* -------------------------------------------------------------------------- */
+
+class FloatingPointLiteral;
+
+class CVC4_PUBLIC FloatingPoint
+{
+ public:
+ /**
+ * Wrappers to represent results of non-total functions (e.g., min/max).
+ * The Boolean flag is true if the result is defined, and false otherwise.
+ */
+ using PartialFloatingPoint = std::pair<FloatingPoint, bool>;
+ using PartialBitVector = std::pair<BitVector, bool>;
+ using PartialRational = std::pair<Rational, bool>;
+
+ /**
+ * Get the number of exponent bits in the unpacked format corresponding to a
+ * given packed format. These is the unpacked counter-parts of
+ * FloatingPointSize::exponentWidth().
+ */
+ static uint32_t getUnpackedExponentWidth(FloatingPointSize& size);
+ /**
+ * Get the number of exponent bits in the unpacked format corresponding to a
+ * given packed format. These is the unpacked counter-parts of
+ * FloatingPointSize::significandWidth().
+ */
+ static uint32_t getUnpackedSignificandWidth(FloatingPointSize& size);
+
+ /** Constructors. */
+ FloatingPoint(uint32_t e, uint32_t s, const BitVector& bv);
+ FloatingPoint(const FloatingPointSize& size, const BitVector& bv);
+ FloatingPoint(const FloatingPointSize& fp_size,
+ const FloatingPointLiteral* fpl);
+ FloatingPoint(const FloatingPoint& fp);
+ FloatingPoint(const FloatingPointSize& size,
+ const RoundingMode& rm,
+ const BitVector& bv,
+ bool signedBV);
+ FloatingPoint(const FloatingPointSize& size,
+ const RoundingMode& rm,
+ const Rational& r);
+ /** Destructor. */
+ ~FloatingPoint();
+
+ /**
+ * Create a FP NaN value of given size.
+ * size: The FP size (format).
+ */
+ static FloatingPoint makeNaN(const FloatingPointSize& size);
+ /**
+ * Create a FP infinity value of given size.
+ * size: The FP size (format).
+ * sign: True for -oo, false otherwise.
+ */
+ static FloatingPoint makeInf(const FloatingPointSize& size, bool sign);
+ /**
+ * Create a FP zero value of given size.
+ * size: The FP size (format).
+ * sign: True for -zero, false otherwise.
+ */
+ static FloatingPoint makeZero(const FloatingPointSize& size, bool sign);
+ /**
+ * Create the smallest subnormal FP value of given size.
+ * size: The FP size (format).
+ * sign: True for negative sign, false otherwise.
+ */
+ static FloatingPoint makeMinSubnormal(const FloatingPointSize& size,
+ bool sign);
+ /**
+ * Create the largest subnormal FP value of given size.
+ * size: The FP size (format).
+ * sign: True for negative sign, false otherwise.
+ */
+ static FloatingPoint makeMaxSubnormal(const FloatingPointSize& size,
+ bool sign);
+ /**
+ * Create the smallest normal FP value of given size.
+ * size: The FP size (format).
+ * sign: True for negative sign, false otherwise.
+ */
+ static FloatingPoint makeMinNormal(const FloatingPointSize& size, bool sign);
+ /**
+ * Create the largest normal FP value of given size.
+ * size: The FP size (format).
+ * sign: True for negative sign, false otherwise.
+ */
+ static FloatingPoint makeMaxNormal(const FloatingPointSize& size, bool sign);
+
+ /** Get the wrapped floating-point value. */
+ const FloatingPointLiteral* getLiteral(void) const { return d_fpl; }
+
+ /**
+ * Return a string representation of this floating-point.
+ *
+ * If printAsIndexed is true then it prints the bit-vector components of the
+ * FP value as indexed symbols, otherwise in binary notation.
+ */
+ std::string toString(bool printAsIndexed = false) const;
+
+ /** Return the packed (IEEE-754) representation of this floating-point. */
+ BitVector pack(void) const;
+
+ /** Floating-point absolute value. */
+ FloatingPoint absolute(void) const;
+ /** Floating-point negation. */
+ FloatingPoint negate(void) const;
+ /** Floating-point addition. */
+ FloatingPoint plus(const RoundingMode& rm, const FloatingPoint& arg) const;
+ /** Floating-point subtraction. */
+ FloatingPoint sub(const RoundingMode& rm, const FloatingPoint& arg) const;
+ /** Floating-point multiplication. */
+ FloatingPoint mult(const RoundingMode& rm, const FloatingPoint& arg) const;
+ /** Floating-point division. */
+ FloatingPoint div(const RoundingMode& rm, const FloatingPoint& arg) const;
+ /** Floating-point fused multiplication and addition. */
+ FloatingPoint fma(const RoundingMode& rm,
+ const FloatingPoint& arg1,
+ const FloatingPoint& arg2) const;
+ /** Floating-point square root. */
+ FloatingPoint sqrt(const RoundingMode& rm) const;
+ /** Floating-point round to integral. */
+ FloatingPoint rti(const RoundingMode& rm) const;
+ /** Floating-point remainder. */
+ FloatingPoint rem(const FloatingPoint& arg) const;
+
+ /**
+ * Floating-point max (total version).
+ * zeroCase: true to return the left (rather than the right operand) in case
+ * of max(-0,+0) or max(+0,-0).
+ */
+ FloatingPoint maxTotal(const FloatingPoint& arg, bool zeroCaseLeft) const;
+ /**
+ * Floating-point min (total version).
+ * zeroCase: true to return the left (rather than the right operand) in case
+ * of min(-0,+0) or min(+0,-0).
+ */
+ FloatingPoint minTotal(const FloatingPoint& arg, bool zeroCaseLeft) const;
+
+ /**
+ * Floating-point max.
+ *
+ * Returns a partial floating-point, which is a pair of FloatingPoint and
+ * bool. The boolean flag is true if the result is defined, and false if it
+ * is undefined.
+ */
+ PartialFloatingPoint max(const FloatingPoint& arg) const;
+ /** Floating-point min.
+ *
+ * Returns a partial floating-point, which is a pair of FloatingPoint and
+ * bool. The boolean flag is true if the result is defined, and false if it
+ * is undefined.
+ */
+ PartialFloatingPoint min(const FloatingPoint& arg) const;
+
+ /** Equality (NOT: fp.eq but =) over floating-point values. */
+ bool operator==(const FloatingPoint& fp) const;
+ /** Floating-point less or equal than. */
+ bool operator<=(const FloatingPoint& arg) const;
+ /** Floating-point less than. */
+ bool operator<(const FloatingPoint& arg) const;
+
+ /** Get the exponent of this floating-point value. */
+ BitVector getExponent() const;
+ /** Get the significand of this floating-point value. */
+ BitVector getSignificand() const;
+ /** True if this value is a negative value. */
+ bool getSign() const;
+
+ /** Return true if this floating-point represents a normal value. */
+ bool isNormal(void) const;
+ /** Return true if this floating-point represents a subnormal value. */
+ bool isSubnormal(void) const;
+ /** Return true if this floating-point represents a zero value. */
+ bool isZero(void) const;
+ /** Return true if this floating-point represents an infinite value. */
+ bool isInfinite(void) const;
+ /** Return true if this floating-point represents a NaN value. */
+ bool isNaN(void) const;
+ /** Return true if this floating-point represents a negative value. */
+ bool isNegative(void) const;
+ /** Return true if this floating-point represents a positive value. */
+ bool isPositive(void) const;
+
+ /**
+ * Convert this floating-point to a floating-point of given size, with
+ * respect to given rounding mode.
+ */
+ FloatingPoint convert(const FloatingPointSize& target,
+ const RoundingMode& rm) const;
+
+ /**
+ * Convert this floating-point to a bit-vector of given size, with
+ * respect to given rounding mode (total version).
+ * Returns given bit-vector 'undefinedCase' in the undefined case.
+ */
+ BitVector convertToBVTotal(BitVectorSize width,
+ const RoundingMode& rm,
+ bool signedBV,
+ BitVector undefinedCase) const;
+ /**
+ * Convert this floating-point to a rational, with respect to given rounding
+ * mode (total version).
+ * Returns given rational 'undefinedCase' in the undefined case.
+ */
+ Rational convertToRationalTotal(Rational undefinedCase) const;
+
+ /**
+ * Convert this floating-point to a bit-vector of given size.
+ *
+ * Returns a partial bit-vector, which is a pair of BitVector and bool.
+ * The boolean flag is true if the result is defined, and false if it
+ * is undefined.
+ */
+ PartialBitVector convertToBV(BitVectorSize width,
+ const RoundingMode& rm,
+ bool signedBV) const;
+ /**
+ * Convert this floating-point to a Rational.
+ *
+ * Returns a partial Rational, which is a pair of Rational and bool.
+ * The boolean flag is true if the result is defined, and false if it
+ * is undefined.
+ */
+ PartialRational convertToRational(void) const;
+
+ /** The floating-point size of this floating-point value. */
+ FloatingPointSize d_fp_size;
+
+ private:
+ /** The floating-point literal of this floating-point value. */
+ FloatingPointLiteral* d_fpl;
+
+}; /* class FloatingPoint */
+
+/**
+ * Hash function for floating-point values.
+ */
+struct CVC4_PUBLIC FloatingPointHashFunction
+{
+ size_t operator()(const FloatingPoint& fp) const
+ {
+ FloatingPointSizeHashFunction fpshf;
+ BitVectorHashFunction bvhf;
+
+ return fpshf(fp.d_fp_size) ^ bvhf(fp.pack());
+ }
+}; /* struct FloatingPointHashFunction */
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * The parameter type for the conversions to floating point.
+ */
+class CVC4_PUBLIC FloatingPointConvertSort
+{
+ public:
+ /** Constructors. */
+ FloatingPointConvertSort(uint32_t _e, uint32_t _s) : d_fp_size(_e, _s) {}
+ FloatingPointConvertSort(const FloatingPointSize& fps) : d_fp_size(fps) {}
+
+ /** Operator overload for comparison of conversion sorts. */
+ bool operator==(const FloatingPointConvertSort& fpcs) const
+ {
+ return d_fp_size == fpcs.d_fp_size;
+ }
+
+ /** The floating-point size of this sort. */
+ FloatingPointSize d_fp_size;
+};
+
+/** Hash function for conversion sorts. */
+template <uint32_t key>
+struct CVC4_PUBLIC FloatingPointConvertSortHashFunction
+{
+ inline size_t operator()(const FloatingPointConvertSort& fpcs) const
+ {
+ FloatingPointSizeHashFunction f;
+ return f(fpcs.d_fp_size) ^ (0x00005300 | (key << 24));
+ }
+}; /* struct FloatingPointConvertSortHashFunction */
+
+/**
+ * As different conversions are different parameterised kinds, there
+ * is a need for different (C++) types for each one.
+ */
+
+/**
+ * Conversion from floating-point to IEEE bit-vector (first bit represents the
+ * sign, the following exponent width bits the exponent, and the remaining bits
+ * the significand).
+ */
+class CVC4_PUBLIC FloatingPointToFPIEEEBitVector
+ : public FloatingPointConvertSort
+{
+ public:
+ /** Constructors. */
+ FloatingPointToFPIEEEBitVector(uint32_t _e, uint32_t _s)
+ : FloatingPointConvertSort(_e, _s)
+ {
+ }
+ FloatingPointToFPIEEEBitVector(const FloatingPointConvertSort& old)
+ : FloatingPointConvertSort(old)
+ {
+ }
+};
+
+/**
+ * Conversion from floating-point to another floating-point (of possibly
+ * different size).
+ */
+class CVC4_PUBLIC FloatingPointToFPFloatingPoint
+ : public FloatingPointConvertSort
+{
+ public:
+ /** Constructors. */
+ FloatingPointToFPFloatingPoint(uint32_t _e, uint32_t _s)
+ : FloatingPointConvertSort(_e, _s)
+ {
+ }
+ FloatingPointToFPFloatingPoint(const FloatingPointConvertSort& old)
+ : FloatingPointConvertSort(old)
+ {
+ }
+};
+
+/**
+ * Conversion from floating-point to Real.
+ */
+class CVC4_PUBLIC FloatingPointToFPReal : public FloatingPointConvertSort
+{
+ public:
+ /** Constructors. */
+ FloatingPointToFPReal(uint32_t _e, uint32_t _s)
+ : FloatingPointConvertSort(_e, _s)
+ {
+ }
+ FloatingPointToFPReal(const FloatingPointConvertSort& old)
+ : FloatingPointConvertSort(old)
+ {
+ }
+};
+
+/**
+ * Conversion from floating-point to signed bit-vector value.
+ */
+class CVC4_PUBLIC FloatingPointToFPSignedBitVector
+ : public FloatingPointConvertSort
+{
+ public:
+ /** Constructors. */
+ FloatingPointToFPSignedBitVector(uint32_t _e, uint32_t _s)
+ : FloatingPointConvertSort(_e, _s)
+ {
+ }
+ FloatingPointToFPSignedBitVector(const FloatingPointConvertSort& old)
+ : FloatingPointConvertSort(old)
+ {
+ }
+};
+
+/**
+ * Conversion from floating-point to unsigned bit-vector value.
+ */
+class CVC4_PUBLIC FloatingPointToFPUnsignedBitVector
+ : public FloatingPointConvertSort
+{
+ public:
+ /** Constructors. */
+ FloatingPointToFPUnsignedBitVector(uint32_t _e, uint32_t _s)
+ : FloatingPointConvertSort(_e, _s)
+ {
+ }
+ FloatingPointToFPUnsignedBitVector(const FloatingPointConvertSort& old)
+ : FloatingPointConvertSort(old)
+ {
+ }
+};
+
+class CVC4_PUBLIC FloatingPointToFPGeneric : public FloatingPointConvertSort
+{
+ public:
+ /** Constructors. */
+ FloatingPointToFPGeneric(uint32_t _e, uint32_t _s)
+ : FloatingPointConvertSort(_e, _s)
+ {
+ }
+ FloatingPointToFPGeneric(const FloatingPointConvertSort& old)
+ : FloatingPointConvertSort(old)
+ {
+ }
+};
+
+/**
+ * Base type for floating-point to bit-vector conversion.
+ */
+class CVC4_PUBLIC FloatingPointToBV
+{
+ public:
+ /** Constructors. */
+ FloatingPointToBV(uint32_t s) : d_bv_size(s) {}
+ FloatingPointToBV(const FloatingPointToBV& old) : d_bv_size(old.d_bv_size) {}
+ FloatingPointToBV(const BitVectorSize& old) : d_bv_size(old) {}
+
+ /** Return the bit-width of the bit-vector to convert to. */
+ operator uint32_t() const { return d_bv_size; }
+
+ /** The bit-width of the bit-vector to converto to. */
+ BitVectorSize d_bv_size;
+};
+
+/**
+ * Conversion from floating-point to unsigned bit-vector value.
+ */
+class CVC4_PUBLIC FloatingPointToUBV : public FloatingPointToBV
+{
+ public:
+ FloatingPointToUBV(uint32_t _s) : FloatingPointToBV(_s) {}
+ FloatingPointToUBV(const FloatingPointToBV& old) : FloatingPointToBV(old) {}
+};
+
+/**
+ * Conversion from floating-point to signed bit-vector value.
+ */
+class CVC4_PUBLIC FloatingPointToSBV : public FloatingPointToBV
+{
+ public:
+ FloatingPointToSBV(uint32_t _s) : FloatingPointToBV(_s) {}
+ FloatingPointToSBV(const FloatingPointToBV& old) : FloatingPointToBV(old) {}
+};
+
+/**
+ * Conversion from floating-point to unsigned bit-vector value (total version).
+ */
+class CVC4_PUBLIC FloatingPointToUBVTotal : public FloatingPointToBV
+{
+ public:
+ FloatingPointToUBVTotal(uint32_t _s) : FloatingPointToBV(_s) {}
+ FloatingPointToUBVTotal(const FloatingPointToBV& old) : FloatingPointToBV(old)
+ {
+ }
+};
+
+/**
+ * Conversion from floating-point to signed bit-vector value (total version).
+ */
+class CVC4_PUBLIC FloatingPointToSBVTotal : public FloatingPointToBV
+{
+ public:
+ FloatingPointToSBVTotal(uint32_t _s) : FloatingPointToBV(_s) {}
+ FloatingPointToSBVTotal(const FloatingPointToBV& old) : FloatingPointToBV(old)
+ {
+ }
+};
+
+/**
+ * Hash function for floating-point to bit-vector conversions.
+ */
+template <uint32_t key>
+struct CVC4_PUBLIC FloatingPointToBVHashFunction
+{
+ inline size_t operator()(const FloatingPointToBV& fptbv) const
+ {
+ UnsignedHashFunction< ::CVC4::BitVectorSize> f;
+ return (key ^ 0x46504256) ^ f(fptbv.d_bv_size);
+ }
+}; /* struct FloatingPointToBVHashFunction */
+
+/* Note: It is not possible to pack a number without a size to pack to,
+ * thus it is difficult to implement output stream operator overloads for
+ * FloatingPointLiteral in a sensible way. Use FloatingPoint instead. */
+
+/** Output stream operator overloading for floating-point values. */
+std::ostream& operator<<(std::ostream& os, const FloatingPoint& fp) CVC4_PUBLIC;
+
+/** Output stream operator overloading for floating-point formats. */
+std::ostream& operator<<(std::ostream& os,
+ const FloatingPointSize& fps) CVC4_PUBLIC;
+
+/** Output stream operator overloading for floating-point conversion sorts. */
+std::ostream& operator<<(std::ostream& os,
+ const FloatingPointConvertSort& fpcs) CVC4_PUBLIC;
+
+} // namespace CVC4
+
+#endif /* CVC4__FLOATINGPOINT_H */
diff --git a/src/util/floatingpoint.h.in b/src/util/floatingpoint.h.in
deleted file mode 100644
index d38cae5fa..000000000
--- a/src/util/floatingpoint.h.in
+++ /dev/null
@@ -1,554 +0,0 @@
-/********************* */
-/*! \file floatingpoint.h.in
- ** \verbatim
- ** Top contributors (to current version):
- ** Martin Brain, Haniel Barbosa, Tim King
- ** Copyright (c) 2013 University of Oxford
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief [[ Utility functions for working with floating point theories. ]]
- **
- ** [[ This file contains the data structures used by the constant and
- ** parametric types of the floating point theory. ]]
- **/
-#include "cvc4_public.h"
-
-#ifndef CVC4__FLOATINGPOINT_H
-#define CVC4__FLOATINGPOINT_H
-
-#include "util/bitvector.h"
-#include "util/rational.h"
-
-#include <fenv.h>
-
-#if @CVC4_USE_SYMFPU@
-#include <symfpu/core/unpackedFloat.h>
-#endif /* @CVC4_USE_SYMFPU@ */
-
-namespace CVC4 {
- // Inline these!
- inline bool CVC4_PUBLIC validExponentSize (unsigned e) { return e >= 2; }
- inline bool CVC4_PUBLIC validSignificandSize (unsigned s) { return s >= 2; }
-
- /**
- * Floating point sorts are parameterised by two non-zero constants
- * giving the width (in bits) of the exponent and significand
- * (including the hidden bit).
- */
- class CVC4_PUBLIC FloatingPointSize {
- /*
- Class invariants:
- * VALIDEXPONENTSIZE(e)
- * VALIDSIGNIFCANDSIZE(s)
- */
-
- private :
- unsigned e;
- unsigned s;
-
- public :
- FloatingPointSize (unsigned _e, unsigned _s);
- FloatingPointSize (const FloatingPointSize &old);
-
- inline unsigned exponent (void) const {
- return this->e;
- }
-
- inline unsigned significand (void) const {
- return this->s;
- }
-
- bool operator ==(const FloatingPointSize& fps) const {
- return (e == fps.e) && (s == fps.s);
- }
-
- // Implement the interface that symfpu uses for floating-point formats.
- inline unsigned exponentWidth(void) const { return this->exponent(); }
- inline unsigned significandWidth(void) const { return this->significand(); }
- inline unsigned packedWidth(void) const
- {
- return this->exponentWidth() + this->significandWidth();
- }
- inline unsigned packedExponentWidth(void) const
- {
- return this->exponentWidth();
- }
- inline unsigned packedSignificandWidth(void) const
- {
- return this->significandWidth() - 1;
- }
-
- }; /* class FloatingPointSize */
-
- struct CVC4_PUBLIC FloatingPointSizeHashFunction {
- static inline size_t ROLL(size_t X, size_t N) {
- return (((X) << (N)) | ((X) >> (8*sizeof((X)) - (N)) ));
- }
-
- inline size_t operator() (const FloatingPointSize& fpt) const {
- return size_t(ROLL(fpt.exponent(), 4*sizeof(unsigned)) |
- fpt.significand());
- }
- }; /* struct FloatingPointSizeHashFunction */
-
-
- /**
- * A concrete instance of the rounding mode sort
- */
- enum CVC4_PUBLIC RoundingMode {
- roundNearestTiesToEven = FE_TONEAREST,
- roundTowardPositive = FE_UPWARD,
- roundTowardNegative = FE_DOWNWARD,
- roundTowardZero = FE_TOWARDZERO,
- // Initializes this to the diagonalization of the 4 other values.
- roundNearestTiesToAway = (((~FE_TONEAREST) & 0x1) | ((~FE_UPWARD) & 0x2) |
- ((~FE_DOWNWARD) & 0x4) | ((~FE_TOWARDZERO) & 0x8))
- }; /* enum RoundingMode */
-
- struct CVC4_PUBLIC RoundingModeHashFunction {
- inline size_t operator() (const RoundingMode& rm) const {
- return size_t(rm);
- }
- }; /* struct RoundingModeHashFunction */
-
- /**
- * This is a symfpu literal "back-end". It allows the library to be used as
- * an arbitrary precision floating-point implementation. This is effectively
- * the glue between symfpu's notion of "signed bit-vector" and CVC4's
- * BitVector.
- */
- namespace symfpuLiteral {
- // Forward declaration of wrapper so that traits can be defined early and so
- // used in the implementation of wrappedBitVector.
- template <bool T>
- class wrappedBitVector;
-
- // This is the template parameter for symfpu's templates.
- class traits
- {
- public:
- // The six key types that symfpu uses.
- typedef unsigned bwt;
- typedef bool prop;
- typedef ::CVC4::RoundingMode rm;
- typedef ::CVC4::FloatingPointSize fpt;
- typedef wrappedBitVector<true> sbv;
- typedef wrappedBitVector<false> ubv;
-
- // Give concrete instances of each rounding mode, mainly for comparisons.
- static rm RNE(void);
- static rm RNA(void);
- static rm RTP(void);
- static rm RTN(void);
- static rm RTZ(void);
-
- // The sympfu properties.
- static void precondition(const prop &p);
- static void postcondition(const prop &p);
- static void invariant(const prop &p);
- };
-
- // Use the same type names as symfpu.
- typedef traits::bwt bwt;
- typedef traits::prop prop;
- typedef traits::rm rm;
- typedef traits::fpt fpt;
- typedef traits::ubv ubv;
- typedef traits::sbv sbv;
-
- // Type function for mapping between types
- template <bool T>
- struct signedToLiteralType;
-
- template <>
- struct signedToLiteralType<true>
- {
- typedef int literalType;
- };
- template <>
- struct signedToLiteralType<false>
- {
- typedef unsigned int literalType;
- };
-
- // This is an additional interface for CVC4::BitVector.
- // The template parameter distinguishes signed and unsigned bit-vectors, a
- // distinction symfpu uses.
- template <bool isSigned>
- class wrappedBitVector : public BitVector
- {
- protected:
- typedef typename signedToLiteralType<isSigned>::literalType literalType;
-
- friend wrappedBitVector<!isSigned>; // To allow conversion between the
- // types
-#if @CVC4_USE_SYMFPU@
- friend ::symfpu::ite<prop, wrappedBitVector<isSigned> >; // For ITE
-#endif /* @CVC4_USE_SYMFPU@ */
-
- public:
- wrappedBitVector(const bwt w, const unsigned v) : BitVector(w, v) {}
- wrappedBitVector(const prop &p) : BitVector(1, p ? 1U : 0U) {}
- wrappedBitVector(const wrappedBitVector<isSigned> &old) : BitVector(old) {}
- wrappedBitVector(const BitVector &old) : BitVector(old) {}
- bwt getWidth(void) const { return getSize(); }
- /*** Constant creation and test ***/
-
- static wrappedBitVector<isSigned> one(const bwt &w);
- static wrappedBitVector<isSigned> zero(const bwt &w);
- static wrappedBitVector<isSigned> allOnes(const bwt &w);
-
- prop isAllOnes() const;
- prop isAllZeros() const;
-
- static wrappedBitVector<isSigned> maxValue(const bwt &w);
- static wrappedBitVector<isSigned> minValue(const bwt &w);
-
- /*** Operators ***/
- wrappedBitVector<isSigned> operator<<(
- const wrappedBitVector<isSigned> &op) const;
- wrappedBitVector<isSigned> operator>>(
- const wrappedBitVector<isSigned> &op) const;
-
- /* Inherited but ...
- * *sigh* if we use the inherited version then it will return a
- * CVC4::BitVector which can be converted back to a
- * wrappedBitVector<isSigned> but isn't done automatically when working
- * out types for templates instantiation. ITE is a particular
- * problem as expressions and constants no longer derive the
- * same type. There aren't any good solutions in C++, we could
- * use CRTP but Liana wouldn't appreciate that, so the following
- * pointless wrapping functions are needed.
- */
- wrappedBitVector<isSigned> operator|(
- const wrappedBitVector<isSigned> &op) const;
- wrappedBitVector<isSigned> operator&(
- const wrappedBitVector<isSigned> &op) const;
- wrappedBitVector<isSigned> operator+(
- const wrappedBitVector<isSigned> &op) const;
- wrappedBitVector<isSigned> operator-(
- const wrappedBitVector<isSigned> &op) const;
- wrappedBitVector<isSigned> operator*(
- const wrappedBitVector<isSigned> &op) const;
- wrappedBitVector<isSigned> operator/(
- const wrappedBitVector<isSigned> &op) const;
- wrappedBitVector<isSigned> operator%(
- const wrappedBitVector<isSigned> &op) const;
- wrappedBitVector<isSigned> operator-(void) const;
- wrappedBitVector<isSigned> operator~(void)const;
-
- wrappedBitVector<isSigned> increment() const;
- wrappedBitVector<isSigned> decrement() const;
- wrappedBitVector<isSigned> signExtendRightShift(
- const wrappedBitVector<isSigned> &op) const;
-
- /*** Modular opertaions ***/
- // No overflow checking so these are the same as other operations
- wrappedBitVector<isSigned> modularLeftShift(
- const wrappedBitVector<isSigned> &op) const;
- wrappedBitVector<isSigned> modularRightShift(
- const wrappedBitVector<isSigned> &op) const;
- wrappedBitVector<isSigned> modularIncrement() const;
- wrappedBitVector<isSigned> modularDecrement() const;
- wrappedBitVector<isSigned> modularAdd(
- const wrappedBitVector<isSigned> &op) const;
- wrappedBitVector<isSigned> modularNegate() const;
-
- /*** Comparisons ***/
- // Inherited ... ish ...
- prop operator==(const wrappedBitVector<isSigned> &op) const;
- prop operator<=(const wrappedBitVector<isSigned> &op) const;
- prop operator>=(const wrappedBitVector<isSigned> &op) const;
- prop operator<(const wrappedBitVector<isSigned> &op) const;
- prop operator>(const wrappedBitVector<isSigned> &op) const;
-
- /*** Type conversion ***/
- wrappedBitVector<true> toSigned(void) const;
- wrappedBitVector<false> toUnsigned(void) const;
-
- /*** Bit hacks ***/
- wrappedBitVector<isSigned> extend(bwt extension) const;
- wrappedBitVector<isSigned> contract(bwt reduction) const;
- wrappedBitVector<isSigned> resize(bwt newSize) const;
- wrappedBitVector<isSigned> matchWidth(
- const wrappedBitVector<isSigned> &op) const;
- wrappedBitVector<isSigned> append(
- const wrappedBitVector<isSigned> &op) const;
-
- // Inclusive of end points, thus if the same, extracts just one bit
- wrappedBitVector<isSigned> extract(bwt upper, bwt lower) const;
- };
- }
-
- /**
- * A concrete floating point number
- */
-#if @CVC4_USE_SYMFPU@
- typedef ::symfpu::unpackedFloat<symfpuLiteral::traits> FloatingPointLiteral;
-#else
- class CVC4_PUBLIC FloatingPointLiteral {
- public :
- // This intentional left unfinished as the choice of literal
- // representation is solver specific.
- void unfinished (void) const;
-
- FloatingPointLiteral(unsigned, unsigned, double) { unfinished(); }
- FloatingPointLiteral(unsigned, unsigned, const std::string &) { unfinished(); }
- FloatingPointLiteral(const FloatingPointLiteral &) { unfinished(); }
- bool operator == (const FloatingPointLiteral &op) const {
- unfinished();
- return false;
- }
-
- size_t hash (void) const {
- unfinished();
- return 23;
- }
- };
-#endif /* @CVC4_USE_SYMFPU@ */
-
- class CVC4_PUBLIC FloatingPoint {
- protected :
- FloatingPointLiteral fpl;
-
- public :
- FloatingPointSize t;
-
- FloatingPoint (unsigned e, unsigned s, const BitVector &bv);
- FloatingPoint (const FloatingPointSize &oldt, const FloatingPointLiteral &oldfpl) : fpl(oldfpl), t(oldt) {}
- FloatingPoint (const FloatingPoint &fp) : fpl(fp.fpl), t(fp.t) {}
- FloatingPoint (const FloatingPointSize &ct, const RoundingMode &rm, const BitVector &bv, bool signedBV);
- FloatingPoint (const FloatingPointSize &ct, const RoundingMode &rm, const Rational &r);
-
-
- static FloatingPoint makeNaN (const FloatingPointSize &t);
- static FloatingPoint makeInf (const FloatingPointSize &t, bool sign);
- static FloatingPoint makeZero (const FloatingPointSize &t, bool sign);
-
- const FloatingPointLiteral & getLiteral (void) const {
- return this->fpl;
- }
-
- /* Return string representation.
- *
- * If printAsIndexed is true then it prints
- * the bit-vector components of the FP value as indexed symbols, otherwise
- * in binary notation. */
- std::string toString(bool printAsIndexed = false) const;
-
- // Gives the corresponding IEEE-754 transfer format
- BitVector pack (void) const;
-
-
- FloatingPoint absolute (void) const;
- FloatingPoint negate (void) const;
- FloatingPoint plus (const RoundingMode &rm, const FloatingPoint &arg) const;
- FloatingPoint sub (const RoundingMode &rm, const FloatingPoint &arg) const;
- FloatingPoint mult (const RoundingMode &rm, const FloatingPoint &arg) const;
- FloatingPoint div (const RoundingMode &rm, const FloatingPoint &arg) const;
- FloatingPoint fma (const RoundingMode &rm, const FloatingPoint &arg1, const FloatingPoint &arg2) const;
- FloatingPoint sqrt (const RoundingMode &rm) const;
- FloatingPoint rti (const RoundingMode &rm) const;
- FloatingPoint rem (const FloatingPoint &arg) const;
-
- // zeroCase is whether the left or right is returned in the case of min/max(-0,+0) or (+0,-0)
- FloatingPoint maxTotal (const FloatingPoint &arg, bool zeroCaseLeft) const;
- FloatingPoint minTotal (const FloatingPoint &arg, bool zeroCaseLeft) const;
-
- // These detect when the answer is defined
- typedef std::pair<FloatingPoint, bool> PartialFloatingPoint;
-
- PartialFloatingPoint max (const FloatingPoint &arg) const;
- PartialFloatingPoint min (const FloatingPoint &arg) const;
-
-
- bool operator ==(const FloatingPoint& fp) const;
- bool operator <= (const FloatingPoint &arg) const;
- bool operator < (const FloatingPoint &arg) const;
-
- bool isNormal (void) const;
- bool isSubnormal (void) const;
- bool isZero (void) const;
- bool isInfinite (void) const;
- bool isNaN (void) const;
- bool isNegative (void) const;
- bool isPositive (void) const;
-
- FloatingPoint convert (const FloatingPointSize &target, const RoundingMode &rm) const;
-
- // These require a value to return in the undefined case
- BitVector convertToBVTotal (BitVectorSize width, const RoundingMode &rm,
- bool signedBV, BitVector undefinedCase) const;
- Rational convertToRationalTotal (Rational undefinedCase) const;
-
- // These detect when the answer is defined
- typedef std::pair<BitVector, bool> PartialBitVector;
- typedef std::pair<Rational, bool> PartialRational;
-
- PartialBitVector convertToBV (BitVectorSize width, const RoundingMode &rm,
- bool signedBV) const;
- PartialRational convertToRational (void) const;
-
- }; /* class FloatingPoint */
-
-
- struct CVC4_PUBLIC FloatingPointHashFunction {
- size_t operator() (const FloatingPoint& fp) const {
- FloatingPointSizeHashFunction fpshf;
- BitVectorHashFunction bvhf;
-
- return fpshf(fp.t) ^ bvhf(fp.pack());
- }
- }; /* struct FloatingPointHashFunction */
-
- /**
- * The parameter type for the conversions to floating point.
- */
- class CVC4_PUBLIC FloatingPointConvertSort {
- public :
- FloatingPointSize t;
-
- FloatingPointConvertSort (unsigned _e, unsigned _s)
- : t(_e,_s) {}
- FloatingPointConvertSort (const FloatingPointSize &fps)
- : t(fps) {}
-
- bool operator ==(const FloatingPointConvertSort& fpcs) const {
- return t == fpcs.t;
- }
-
- };
-
- /**
- * As different conversions are different parameterised kinds, there
- * is a need for different (C++) types for each one.
- */
-
- class CVC4_PUBLIC FloatingPointToFPIEEEBitVector : public FloatingPointConvertSort {
- public :
- FloatingPointToFPIEEEBitVector (unsigned _e, unsigned _s) : FloatingPointConvertSort(_e,_s) {}
- FloatingPointToFPIEEEBitVector (const FloatingPointConvertSort &old) : FloatingPointConvertSort(old) {}
- };
-
- class CVC4_PUBLIC FloatingPointToFPFloatingPoint : public FloatingPointConvertSort {
- public :
- FloatingPointToFPFloatingPoint (unsigned _e, unsigned _s) : FloatingPointConvertSort(_e,_s) {}
- FloatingPointToFPFloatingPoint (const FloatingPointConvertSort &old) : FloatingPointConvertSort(old) {}
- };
-
- class CVC4_PUBLIC FloatingPointToFPReal : public FloatingPointConvertSort {
- public :
- FloatingPointToFPReal (unsigned _e, unsigned _s) : FloatingPointConvertSort(_e,_s) {}
- FloatingPointToFPReal (const FloatingPointConvertSort &old) : FloatingPointConvertSort(old) {}
- };
-
- class CVC4_PUBLIC FloatingPointToFPSignedBitVector : public FloatingPointConvertSort {
- public :
- FloatingPointToFPSignedBitVector (unsigned _e, unsigned _s) : FloatingPointConvertSort(_e,_s) {}
- FloatingPointToFPSignedBitVector (const FloatingPointConvertSort &old) : FloatingPointConvertSort(old) {}
- };
-
- class CVC4_PUBLIC FloatingPointToFPUnsignedBitVector : public FloatingPointConvertSort {
- public :
- FloatingPointToFPUnsignedBitVector (unsigned _e, unsigned _s) : FloatingPointConvertSort(_e,_s) {}
- FloatingPointToFPUnsignedBitVector (const FloatingPointConvertSort &old) : FloatingPointConvertSort(old) {}
- };
-
- class CVC4_PUBLIC FloatingPointToFPGeneric : public FloatingPointConvertSort {
- public :
- FloatingPointToFPGeneric (unsigned _e, unsigned _s) : FloatingPointConvertSort(_e,_s) {}
- FloatingPointToFPGeneric (const FloatingPointConvertSort &old) : FloatingPointConvertSort(old) {}
- };
-
-
-
- template <unsigned key>
- struct CVC4_PUBLIC FloatingPointConvertSortHashFunction {
- inline size_t operator() (const FloatingPointConvertSort& fpcs) const {
- FloatingPointSizeHashFunction f;
- return f(fpcs.t) ^ (0x00005300 | (key << 24));
- }
- }; /* struct FloatingPointConvertSortHashFunction */
-
-
-
-
-
-
-
-
- /**
- * The parameter type for the conversion to bit vector.
- */
- class CVC4_PUBLIC FloatingPointToBV {
- public :
- BitVectorSize bvs;
-
- FloatingPointToBV (unsigned s)
- : bvs(s) {}
- FloatingPointToBV (const FloatingPointToBV &old) : bvs(old.bvs) {}
- FloatingPointToBV (const BitVectorSize &old) : bvs(old) {}
- operator unsigned () const { return bvs; }
- };
-
- class CVC4_PUBLIC FloatingPointToUBV : public FloatingPointToBV {
- public : FloatingPointToUBV (unsigned _s) : FloatingPointToBV(_s) {}
- FloatingPointToUBV (const FloatingPointToBV &old) : FloatingPointToBV(old) {}
- };
- class CVC4_PUBLIC FloatingPointToSBV : public FloatingPointToBV {
- public : FloatingPointToSBV (unsigned _s) : FloatingPointToBV(_s) {}
- FloatingPointToSBV (const FloatingPointToBV &old) : FloatingPointToBV(old) {}
- };
- class CVC4_PUBLIC FloatingPointToUBVTotal : public FloatingPointToBV {
- public : FloatingPointToUBVTotal (unsigned _s) : FloatingPointToBV(_s) {}
- FloatingPointToUBVTotal (const FloatingPointToBV &old) : FloatingPointToBV(old) {}
- };
- class CVC4_PUBLIC FloatingPointToSBVTotal : public FloatingPointToBV {
- public : FloatingPointToSBVTotal (unsigned _s) : FloatingPointToBV(_s) {}
- FloatingPointToSBVTotal (const FloatingPointToBV &old) : FloatingPointToBV(old) {}
- };
-
-
- template <unsigned key>
- struct CVC4_PUBLIC FloatingPointToBVHashFunction {
- inline size_t operator() (const FloatingPointToBV& fptbv) const {
- UnsignedHashFunction< ::CVC4::BitVectorSize > f;
- return (key ^ 0x46504256) ^ f(fptbv.bvs);
- }
- }; /* struct FloatingPointToBVHashFunction */
-
-
- // It is not possible to pack a number without a size to pack to,
- // thus it is difficult to implement this in a sensible way. Use
- // FloatingPoint instead...
- /*
- inline std::ostream& operator <<(std::ostream& os, const FloatingPointLiteral& fp) CVC4_PUBLIC;
- inline std::ostream& operator <<(std::ostream& os, const FloatingPointLiteral& fp) {
- return os << "FloatingPointLiteral";
- }
- */
-
- inline std::ostream& operator <<(std::ostream& os, const FloatingPoint& fp) CVC4_PUBLIC;
- inline std::ostream& operator<<(std::ostream& os, const FloatingPoint& fp)
- {
- // print in binary notation
- return os << fp.toString();
- }
-
- inline std::ostream& operator <<(std::ostream& os, const FloatingPointSize& fps) CVC4_PUBLIC;
- inline std::ostream& operator <<(std::ostream& os, const FloatingPointSize& fps) {
- return os << "(_ FloatingPoint " << fps.exponent() << " " << fps.significand() << ")";
- }
-
- inline std::ostream& operator <<(std::ostream& os, const FloatingPointConvertSort& fpcs) CVC4_PUBLIC;
- inline std::ostream& operator <<(std::ostream& os, const FloatingPointConvertSort& fpcs) {
- return os << "(_ to_fp " << fpcs.t.exponent() << " " << fpcs.t.significand() << ")";
- }
-
-}/* CVC4 namespace */
-
-#endif /* CVC4__FLOATINGPOINT_H */
diff --git a/src/util/floatingpoint_literal_symfpu.cpp b/src/util/floatingpoint_literal_symfpu.cpp
new file mode 100644
index 000000000..fb5c0b7b5
--- /dev/null
+++ b/src/util/floatingpoint_literal_symfpu.cpp
@@ -0,0 +1,428 @@
+/********************* */
+/*! \file floatingpoint_literal_symfpu.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Martin Brain, Aina Niemetz
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief SymFPU glue code for floating-point values.
+ **/
+#include "util/floatingpoint_literal_symfpu.h"
+
+#include "base/check.h"
+
+namespace CVC4 {
+
+#ifndef CVC4_USE_SYMFPU
+void FloatingPointLiteral::unfinished(void) const
+{
+ Unimplemented() << "Floating-point literals not yet implemented.";
+}
+
+bool FloatingPointLiteral::operator==(const FloatingPointLiteral& other) const
+{
+ unfinished();
+ return false;
+}
+
+size_t FloatingPointLiteral::hash(void) const
+{
+ unfinished();
+ return 23;
+}
+#endif
+
+namespace symfpuLiteral {
+
+// To simplify the property macros
+typedef traits t;
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::one(
+ const CVC4BitWidth& w)
+{
+ return wrappedBitVector<isSigned>(w, 1);
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::zero(
+ const CVC4BitWidth& w)
+{
+ return wrappedBitVector<isSigned>(w, 0);
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::allOnes(
+ const CVC4BitWidth& w)
+{
+ return ~wrappedBitVector<isSigned>::zero(w);
+}
+
+template <bool isSigned>
+CVC4Prop wrappedBitVector<isSigned>::isAllOnes() const
+{
+ return (*this == wrappedBitVector<isSigned>::allOnes(this->getWidth()));
+}
+template <bool isSigned>
+CVC4Prop wrappedBitVector<isSigned>::isAllZeros() const
+{
+ return (*this == wrappedBitVector<isSigned>::zero(this->getWidth()));
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::maxValue(
+ const CVC4BitWidth& w)
+{
+ if (isSigned)
+ {
+ BitVector base(w - 1, 0U);
+ return wrappedBitVector<true>((~base).zeroExtend(1));
+ }
+ else
+ {
+ return wrappedBitVector<false>::allOnes(w);
+ }
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::minValue(
+ const CVC4BitWidth& w)
+{
+ if (isSigned)
+ {
+ BitVector base(w, 1U);
+ BitVector shiftAmount(w, w - 1);
+ BitVector result(base.leftShift(shiftAmount));
+ return wrappedBitVector<true>(result);
+ }
+ else
+ {
+ return wrappedBitVector<false>::zero(w);
+ }
+}
+
+/*** Operators ***/
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::operator<<(
+ const wrappedBitVector<isSigned>& op) const
+{
+ return this->BitVector::leftShift(op);
+}
+
+template <>
+wrappedBitVector<true> wrappedBitVector<true>::operator>>(
+ const wrappedBitVector<true>& op) const
+{
+ return this->BitVector::arithRightShift(op);
+}
+
+template <>
+wrappedBitVector<false> wrappedBitVector<false>::operator>>(
+ const wrappedBitVector<false>& op) const
+{
+ return this->BitVector::logicalRightShift(op);
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::operator|(
+ const wrappedBitVector<isSigned>& op) const
+{
+ return this->BitVector::operator|(op);
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::operator&(
+ const wrappedBitVector<isSigned>& op) const
+{
+ return this->BitVector::operator&(op);
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::operator+(
+ const wrappedBitVector<isSigned>& op) const
+{
+ return this->BitVector::operator+(op);
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::operator-(
+ const wrappedBitVector<isSigned>& op) const
+{
+ return this->BitVector::operator-(op);
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::operator*(
+ const wrappedBitVector<isSigned>& op) const
+{
+ return this->BitVector::operator*(op);
+}
+
+template <>
+wrappedBitVector<false> wrappedBitVector<false>::operator/(
+ const wrappedBitVector<false>& op) const
+{
+ return this->BitVector::unsignedDivTotal(op);
+}
+
+template <>
+wrappedBitVector<false> wrappedBitVector<false>::operator%(
+ const wrappedBitVector<false>& op) const
+{
+ return this->BitVector::unsignedRemTotal(op);
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::operator-(void) const
+{
+ return this->BitVector::operator-();
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::operator~(void) const
+{
+ return this->BitVector::operator~();
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::increment() const
+{
+ return *this + wrappedBitVector<isSigned>::one(this->getWidth());
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::decrement() const
+{
+ return *this - wrappedBitVector<isSigned>::one(this->getWidth());
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::signExtendRightShift(
+ const wrappedBitVector<isSigned>& op) const
+{
+ return this->BitVector::arithRightShift(BitVector(this->getWidth(), op));
+}
+
+/*** Modular opertaions ***/
+// No overflow checking so these are the same as other operations
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::modularLeftShift(
+ const wrappedBitVector<isSigned>& op) const
+{
+ return *this << op;
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::modularRightShift(
+ const wrappedBitVector<isSigned>& op) const
+{
+ return *this >> op;
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::modularIncrement() const
+{
+ return this->increment();
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::modularDecrement() const
+{
+ return this->decrement();
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::modularAdd(
+ const wrappedBitVector<isSigned>& op) const
+{
+ return *this + op;
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::modularNegate() const
+{
+ return -(*this);
+}
+
+/*** Comparisons ***/
+
+template <bool isSigned>
+CVC4Prop wrappedBitVector<isSigned>::operator==(
+ const wrappedBitVector<isSigned>& op) const
+{
+ return this->BitVector::operator==(op);
+}
+
+template <>
+CVC4Prop wrappedBitVector<true>::operator<=(
+ const wrappedBitVector<true>& op) const
+{
+ return this->signedLessThanEq(op);
+}
+
+template <>
+CVC4Prop wrappedBitVector<true>::operator>=(
+ const wrappedBitVector<true>& op) const
+{
+ return !(this->signedLessThan(op));
+}
+
+template <>
+CVC4Prop wrappedBitVector<true>::operator<(
+ const wrappedBitVector<true>& op) const
+{
+ return this->signedLessThan(op);
+}
+
+template <>
+CVC4Prop wrappedBitVector<true>::operator>(
+ const wrappedBitVector<true>& op) const
+{
+ return !(this->signedLessThanEq(op));
+}
+
+template <>
+CVC4Prop wrappedBitVector<false>::operator<=(
+ const wrappedBitVector<false>& op) const
+{
+ return this->unsignedLessThanEq(op);
+}
+
+template <>
+CVC4Prop wrappedBitVector<false>::operator>=(
+ const wrappedBitVector<false>& op) const
+{
+ return !(this->unsignedLessThan(op));
+}
+
+template <>
+CVC4Prop wrappedBitVector<false>::operator<(
+ const wrappedBitVector<false>& op) const
+{
+ return this->unsignedLessThan(op);
+}
+
+template <>
+CVC4Prop wrappedBitVector<false>::operator>(
+ const wrappedBitVector<false>& op) const
+{
+ return !(this->unsignedLessThanEq(op));
+}
+
+/*** Type conversion ***/
+// CVC4 nodes make no distinction between signed and unsigned, thus ...
+template <bool isSigned>
+wrappedBitVector<true> wrappedBitVector<isSigned>::toSigned(void) const
+{
+ return wrappedBitVector<true>(*this);
+}
+
+template <bool isSigned>
+wrappedBitVector<false> wrappedBitVector<isSigned>::toUnsigned(void) const
+{
+ return wrappedBitVector<false>(*this);
+}
+
+/*** Bit hacks ***/
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::extend(
+ CVC4BitWidth extension) const
+{
+ if (isSigned)
+ {
+ return this->BitVector::signExtend(extension);
+ }
+ else
+ {
+ return this->BitVector::zeroExtend(extension);
+ }
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::contract(
+ CVC4BitWidth reduction) const
+{
+ Assert(this->getWidth() > reduction);
+
+ return this->extract((this->getWidth() - 1) - reduction, 0);
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::resize(
+ CVC4BitWidth newSize) const
+{
+ CVC4BitWidth width = this->getWidth();
+
+ if (newSize > width)
+ {
+ return this->extend(newSize - width);
+ }
+ else if (newSize < width)
+ {
+ return this->contract(width - newSize);
+ }
+ else
+ {
+ return *this;
+ }
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::matchWidth(
+ const wrappedBitVector<isSigned>& op) const
+{
+ Assert(this->getWidth() <= op.getWidth());
+ return this->extend(op.getWidth() - this->getWidth());
+}
+
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::append(
+ const wrappedBitVector<isSigned>& op) const
+{
+ return this->BitVector::concat(op);
+}
+
+// Inclusive of end points, thus if the same, extracts just one bit
+template <bool isSigned>
+wrappedBitVector<isSigned> wrappedBitVector<isSigned>::extract(
+ CVC4BitWidth upper, CVC4BitWidth lower) const
+{
+ Assert(upper >= lower);
+ return this->BitVector::extract(upper, lower);
+}
+
+// Explicit instantiation
+template class wrappedBitVector<true>;
+template class wrappedBitVector<false>;
+
+traits::rm traits::RNE(void) { return ::CVC4::ROUND_NEAREST_TIES_TO_EVEN; };
+traits::rm traits::RNA(void) { return ::CVC4::ROUND_NEAREST_TIES_TO_AWAY; };
+traits::rm traits::RTP(void) { return ::CVC4::ROUND_TOWARD_POSITIVE; };
+traits::rm traits::RTN(void) { return ::CVC4::ROUND_TOWARD_NEGATIVE; };
+traits::rm traits::RTZ(void) { return ::CVC4::ROUND_TOWARD_ZERO; };
+// This is a literal back-end so props are actually bools
+// so these can be handled in the same way as the internal assertions above
+
+void traits::precondition(const traits::prop& p)
+{
+ Assert(p);
+ return;
+}
+void traits::postcondition(const traits::prop& p)
+{
+ Assert(p);
+ return;
+}
+void traits::invariant(const traits::prop& p)
+{
+ Assert(p);
+ return;
+}
+} // namespace symfpuLiteral
+
+} // namespace CVC4
diff --git a/src/util/floatingpoint_literal_symfpu.h.in b/src/util/floatingpoint_literal_symfpu.h.in
new file mode 100644
index 000000000..06a98b7ea
--- /dev/null
+++ b/src/util/floatingpoint_literal_symfpu.h.in
@@ -0,0 +1,327 @@
+/********************* */
+/*! \file floatingpoint_literal_symfpu.h.in
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Aina Niemetz, Martin Brain, Andres Noetzli
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief SymFPU glue code for floating-point values.
+ **
+ ** !!! This header is not to be included in any other headers !!!
+ **/
+#include "cvc4_public.h"
+
+#ifndef CVC4__UTIL__FLOATINGPOINT_LITERAL_SYMFPU_H
+#define CVC4__UTIL__FLOATINGPOINT_LITERAL_SYMFPU_H
+
+#include "util/bitvector.h"
+#include "util/roundingmode.h"
+
+// clang-format off
+#if @CVC4_USE_SYMFPU@
+// clang-format on
+#include <symfpu/core/unpackedFloat.h>
+#endif /* @CVC4_USE_SYMFPU@ */
+
+/* -------------------------------------------------------------------------- */
+
+namespace CVC4 {
+
+class FloatingPointSize;
+class FloatingPoint;
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * This is a symfpu literal "back-end". It allows the library to be used as
+ * an arbitrary precision floating-point implementation. This is effectively
+ * the glue between symfpu's notion of "signed bit-vector" and CVC4's
+ * BitVector.
+ */
+namespace symfpuLiteral {
+
+/* -------------------------------------------------------------------------- */
+
+/**
+ * Forward declaration of wrapper so that traits can be defined early and so
+ * used in the implementation of wrappedBitVector.
+ */
+template <bool T>
+class wrappedBitVector;
+
+using CVC4BitWidth = uint32_t;
+using CVC4Prop = bool;
+using CVC4RM = ::CVC4::RoundingMode;
+using CVC4FPSize = ::CVC4::FloatingPointSize;
+using CVC4UnsignedBitVector = wrappedBitVector<false>;
+using CVC4SignedBitVector = wrappedBitVector<true>;
+
+/**
+ * This is the template parameter for symfpu's templates.
+ */
+class traits
+{
+ public:
+ /** The six key types that symfpu uses. */
+ using bwt = CVC4BitWidth; // bit-width type
+ using prop = CVC4Prop; // boolean type
+ using rm = CVC4RM; // rounding-mode type
+ using fpt = CVC4FPSize; // floating-point format type
+ using ubv = CVC4UnsignedBitVector; // unsigned bit-vector type
+ using sbv = CVC4SignedBitVector; // signed bit-vector type
+
+ /** Give concrete instances of each rounding mode, mainly for comparisons. */
+ static rm RNE(void);
+ static rm RNA(void);
+ static rm RTP(void);
+ static rm RTN(void);
+ static rm RTZ(void);
+
+ /** The sympfu properties. */
+ static void precondition(const prop& p);
+ static void postcondition(const prop& p);
+ static void invariant(const prop& p);
+};
+
+/**
+ * Type function for mapping between types.
+ */
+template <bool T>
+struct signedToLiteralType;
+
+template <>
+struct signedToLiteralType<true>
+{
+ using literalType = int32_t;
+};
+template <>
+struct signedToLiteralType<false>
+{
+ using literalType = uint32_t;
+};
+
+/**
+ * This extends the interface for CVC4::BitVector for compatibility with symFPU.
+ * The template parameter distinguishes signed and unsigned bit-vectors, a
+ * distinction symfpu uses.
+ */
+template <bool isSigned>
+class wrappedBitVector : public BitVector
+{
+ protected:
+ using literalType = typename signedToLiteralType<isSigned>::literalType;
+ friend wrappedBitVector<!isSigned>; // To allow conversion between types
+
+// clang-format off
+#if @CVC4_USE_SYMFPU@
+ // clang-format on
+ friend ::symfpu::ite<CVC4Prop, wrappedBitVector<isSigned> >; // For ITE
+#endif /* @CVC4_USE_SYMFPU@ */
+
+ public:
+ /** Constructors. */
+ wrappedBitVector(const CVC4BitWidth w, const uint32_t v) : BitVector(w, v) {}
+ wrappedBitVector(const CVC4Prop& p) : BitVector(1, p ? 1U : 0U) {}
+ wrappedBitVector(const wrappedBitVector<isSigned>& old) : BitVector(old) {}
+ wrappedBitVector(const BitVector& old) : BitVector(old) {}
+
+ /** Get the bit-width of this wrapped bit-vector. */
+ CVC4BitWidth getWidth(void) const { return getSize(); }
+
+ /** Create a zero value of given bit-width 'w'. */
+ static wrappedBitVector<isSigned> one(const CVC4BitWidth& w);
+ /** Create a one value of given bit-width 'w'. */
+ static wrappedBitVector<isSigned> zero(const CVC4BitWidth& w);
+ /** Create a ones value (all bits 1) of given bit-width 'w'. */
+ static wrappedBitVector<isSigned> allOnes(const CVC4BitWidth& w);
+ /** Create a maximum signed/unsigned value of given bit-width 'w'. */
+ static wrappedBitVector<isSigned> maxValue(const CVC4BitWidth& w);
+ /** Create a minimum signed/unsigned value of given bit-width 'w'. */
+ static wrappedBitVector<isSigned> minValue(const CVC4BitWidth& w);
+
+ /** Return true if this a bit-vector representing a ones value. */
+ CVC4Prop isAllOnes() const;
+ /** Return true if this a bit-vector representing a zero value. */
+ CVC4Prop isAllZeros() const;
+
+ /** Left shift. */
+ wrappedBitVector<isSigned> operator<<(
+ const wrappedBitVector<isSigned>& op) const;
+ /** Logical (unsigned) and arithmetic (signed) right shift. */
+ wrappedBitVector<isSigned> operator>>(
+ const wrappedBitVector<isSigned>& op) const;
+
+ /**
+ * Inherited but ...
+ * *sigh* if we use the inherited version then it will return a
+ * CVC4::BitVector which can be converted back to a
+ * wrappedBitVector<isSigned> but isn't done automatically when working
+ * out types for templates instantiation. ITE is a particular
+ * problem as expressions and constants no longer derive the
+ * same type. There aren't any good solutions in C++, we could
+ * use CRTP but Liana wouldn't appreciate that, so the following
+ * pointless wrapping functions are needed.
+ */
+
+ /** Bit-wise or. */
+ wrappedBitVector<isSigned> operator|(
+ const wrappedBitVector<isSigned>& op) const;
+ /** Bit-wise and. */
+ wrappedBitVector<isSigned> operator&(
+ const wrappedBitVector<isSigned>& op) const;
+ /** Bit-vector addition. */
+ wrappedBitVector<isSigned> operator+(
+ const wrappedBitVector<isSigned>& op) const;
+ /** Bit-vector subtraction. */
+ wrappedBitVector<isSigned> operator-(
+ const wrappedBitVector<isSigned>& op) const;
+ /** Bit-vector multiplication. */
+ wrappedBitVector<isSigned> operator*(
+ const wrappedBitVector<isSigned>& op) const;
+ /** Bit-vector signed/unsigned division. */
+ wrappedBitVector<isSigned> operator/(
+ const wrappedBitVector<isSigned>& op) const;
+ /** Bit-vector signed/unsigned remainder. */
+ wrappedBitVector<isSigned> operator%(
+ const wrappedBitVector<isSigned>& op) const;
+ /** Bit-vector negation. */
+ wrappedBitVector<isSigned> operator-(void) const;
+ /** Bit-wise not. */
+ wrappedBitVector<isSigned> operator~(void) const;
+
+ /** Bit-vector increment. */
+ wrappedBitVector<isSigned> increment() const;
+ /** Bit-vector decrement. */
+ wrappedBitVector<isSigned> decrement() const;
+ /**
+ * Bit-vector logical/arithmetic right shift where 'op' extended to the
+ * bit-width of this wrapped bit-vector.
+ */
+ wrappedBitVector<isSigned> signExtendRightShift(
+ const wrappedBitVector<isSigned>& op) const;
+
+ /**
+ * Modular operations.
+ * Note: No overflow checking so these are the same as other operations.
+ */
+ wrappedBitVector<isSigned> modularLeftShift(
+ const wrappedBitVector<isSigned>& op) const;
+ wrappedBitVector<isSigned> modularRightShift(
+ const wrappedBitVector<isSigned>& op) const;
+ wrappedBitVector<isSigned> modularIncrement() const;
+ wrappedBitVector<isSigned> modularDecrement() const;
+ wrappedBitVector<isSigned> modularAdd(
+ const wrappedBitVector<isSigned>& op) const;
+ wrappedBitVector<isSigned> modularNegate() const;
+
+ /** Bit-vector equality. */
+ CVC4Prop operator==(const wrappedBitVector<isSigned>& op) const;
+ /** Bit-vector signed/unsigned less or equal than. */
+ CVC4Prop operator<=(const wrappedBitVector<isSigned>& op) const;
+ /** Bit-vector sign/unsigned greater or equal than. */
+ CVC4Prop operator>=(const wrappedBitVector<isSigned>& op) const;
+ /** Bit-vector signed/unsigned less than. */
+ CVC4Prop operator<(const wrappedBitVector<isSigned>& op) const;
+ /** Bit-vector sign/unsigned greater or equal than. */
+ CVC4Prop operator>(const wrappedBitVector<isSigned>& op) const;
+
+ /** Convert this bit-vector to a signed bit-vector. */
+ wrappedBitVector<true> toSigned(void) const;
+ /** Convert this bit-vector to an unsigned bit-vector. */
+ wrappedBitVector<false> toUnsigned(void) const;
+
+ /** Bit-vector signed/unsigned (zero) extension. */
+ wrappedBitVector<isSigned> extend(CVC4BitWidth extension) const;
+ /**
+ * Create a "contracted" bit-vector by cutting off the 'reduction' number of
+ * most significant bits, i.e., by extracting the (bit-width - reduction)
+ * least significant bits.
+ */
+ wrappedBitVector<isSigned> contract(CVC4BitWidth reduction) const;
+ /**
+ * Create a "resized" bit-vector of given size bei either extending (if new
+ * size is larger) or contracting (if it is smaller) this wrapped bit-vector.
+ */
+ wrappedBitVector<isSigned> resize(CVC4BitWidth newSize) const;
+ /**
+ * Create an extension of this bit-vector that matches the bit-width of the
+ * given bit-vector.
+ * Note: The size of the given bit-vector may not be larger than the size of
+ * this bit-vector.
+ */
+ wrappedBitVector<isSigned> matchWidth(
+ const wrappedBitVector<isSigned>& op) const;
+ /** Bit-vector concatenation. */
+ wrappedBitVector<isSigned> append(const wrappedBitVector<isSigned>& op) const;
+
+ /** Inclusive of end points, thus if the same, extracts just one bit. */
+ wrappedBitVector<isSigned> extract(CVC4BitWidth upper,
+ CVC4BitWidth lower) const;
+};
+
+/* -------------------------------------------------------------------------- */
+
+} // namespace symfpuLiteral
+
+/* -------------------------------------------------------------------------- */
+
+// clang-format off
+#if @CVC4_USE_SYMFPU@
+// clang-format on
+using SymFPUUnpackedFloatLiteral = ::symfpu::unpackedFloat<symfpuLiteral::traits>;
+#endif
+
+class FloatingPointLiteral
+{
+ friend class FloatingPoint;
+ public:
+ /** Constructors. */
+ FloatingPointLiteral(FloatingPoint& other);
+// clang-format off
+#if @CVC4_USE_SYMFPU@
+// clang-format on
+ FloatingPointLiteral(SymFPUUnpackedFloatLiteral symuf) : d_symuf(symuf){};
+ FloatingPointLiteral(const bool sign,
+ const BitVector& exp,
+ const BitVector& sig)
+ : d_symuf(SymFPUUnpackedFloatLiteral(sign, exp, sig))
+ {
+ }
+#else
+ FloatingPointLiteral(uint32_t, uint32_t, double) { unfinished(); };
+#endif
+ ~FloatingPointLiteral() {}
+
+// clang-format off
+#if @CVC4_USE_SYMFPU@
+// clang-format on
+ /** Return wrapped floating-point literal. */
+ const SymFPUUnpackedFloatLiteral& getSymUF() const { return d_symuf; }
+#else
+ /** Catch-all for unimplemented functions. */
+ void unfinished(void) const;
+ /** Dummy hash function. */
+ size_t hash(void) const;
+ /** Dummy comparison operator overload. */
+ bool operator==(const FloatingPointLiteral& other) const;
+#endif
+
+ private:
+// clang-format off
+#if @CVC4_USE_SYMFPU@
+// clang-format on
+ /** The actual floating-point value, a SymFPU unpackedFloat. */
+ SymFPUUnpackedFloatLiteral d_symuf;
+#endif
+};
+
+
+/* -------------------------------------------------------------------------- */
+
+}
+
+#endif
diff --git a/src/util/floatingpoint_size.cpp b/src/util/floatingpoint_size.cpp
new file mode 100644
index 000000000..e068eb69a
--- /dev/null
+++ b/src/util/floatingpoint_size.cpp
@@ -0,0 +1,34 @@
+/********************* */
+/*! \file floatingpoint_size.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Aina Niemetz, Martin Brain
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The class representing a floating-point format.
+ **/
+#include "util/floatingpoint_size.h"
+
+#include "base/check.h"
+
+namespace CVC4 {
+
+FloatingPointSize::FloatingPointSize(uint32_t exp_size, uint32_t sig_size)
+ : d_exp_size(exp_size), d_sig_size(sig_size)
+{
+ Assert(validExponentSize(exp_size));
+ Assert(validSignificandSize(sig_size));
+}
+
+FloatingPointSize::FloatingPointSize(const FloatingPointSize& old)
+ : d_exp_size(old.d_exp_size), d_sig_size(old.d_sig_size)
+{
+ Assert(validExponentSize(d_exp_size));
+ Assert(validSignificandSize(d_sig_size));
+}
+
+} // namespace CVC4
diff --git a/src/util/floatingpoint_size.h b/src/util/floatingpoint_size.h
new file mode 100644
index 000000000..20684ca42
--- /dev/null
+++ b/src/util/floatingpoint_size.h
@@ -0,0 +1,97 @@
+/********************* */
+/*! \file floatingpoint_size.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Aina Niemetz, Martin Brain, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The class representing a floating-point format.
+ **/
+#include "cvc4_public.h"
+
+#ifndef CVC4__FLOATINGPOINT_SIZE_H
+#define CVC4__FLOATINGPOINT_SIZE_H
+
+namespace CVC4 {
+
+// Inline these!
+inline bool CVC4_PUBLIC validExponentSize(uint32_t e) { return e >= 2; }
+inline bool CVC4_PUBLIC validSignificandSize(uint32_t s) { return s >= 2; }
+
+/**
+ * Floating point sorts are parameterised by two constants > 1 giving the
+ * width (in bits) of the exponent and significand (including the hidden bit).
+ * So, IEEE-754 single precision, a.k.a. float, is described as 8 24.
+ */
+class CVC4_PUBLIC FloatingPointSize
+{
+ public:
+ /** Constructors. */
+ FloatingPointSize(uint32_t exp_size, uint32_t sig_size);
+ FloatingPointSize(const FloatingPointSize& old);
+
+ /** Operator overload for equality comparison. */
+ bool operator==(const FloatingPointSize& fps) const
+ {
+ return (d_exp_size == fps.d_exp_size) && (d_sig_size == fps.d_sig_size);
+ }
+
+ /** Implement the interface that symfpu uses for floating-point formats. */
+
+ /** Get the exponent bit-width of this floating-point format. */
+ inline uint32_t exponentWidth(void) const { return d_exp_size; }
+ /** Get the significand bit-width of this floating-point format. */
+ inline uint32_t significandWidth(void) const { return d_sig_size; }
+ /**
+ * Get the bit-width of the packed representation of this floating-point
+ * format (= exponent + significand bit-width, convenience wrapper).
+ */
+ inline uint32_t packedWidth(void) const
+ {
+ return exponentWidth() + significandWidth();
+ }
+ /**
+ * Get the exponent bit-width of the packed representation of this
+ * floating-point format (= exponent bit-width).
+ */
+ inline uint32_t packedExponentWidth(void) const { return exponentWidth(); }
+ /**
+ * Get the significand bit-width of the packed representation of this
+ * floating-point format (= significand bit-width - 1).
+ */
+ inline uint32_t packedSignificandWidth(void) const
+ {
+ return significandWidth() - 1;
+ }
+
+ private:
+ /** Exponent bit-width. */
+ uint32_t d_exp_size;
+ /** Significand bit-width. */
+ uint32_t d_sig_size;
+
+}; /* class FloatingPointSize */
+
+/**
+ * Hash function for floating point formats.
+ */
+struct CVC4_PUBLIC FloatingPointSizeHashFunction
+{
+ static inline size_t ROLL(size_t X, size_t N)
+ {
+ return (((X) << (N)) | ((X) >> (8 * sizeof((X)) - (N))));
+ }
+
+ inline size_t operator()(const FloatingPointSize& t) const
+ {
+ return size_t(ROLL(t.exponentWidth(), 4 * sizeof(uint32_t))
+ | t.significandWidth());
+ }
+}; /* struct FloatingPointSizeHashFunction */
+} // namespace CVC4
+
+#endif
diff --git a/src/util/gmp_util.h b/src/util/gmp_util.h
index bde7b50a8..995579c3b 100644
--- a/src/util/gmp_util.h
+++ b/src/util/gmp_util.h
@@ -5,7 +5,7 @@
** Tim King, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,13 +20,6 @@
#ifndef CVC4__GMP_UTIL_H
#define CVC4__GMP_UTIL_H
-/*
- * Older versions of GMP in combination with newer versions of GCC and C++11
- * cause errors: https://gcc.gnu.org/gcc-4.9/porting_to.html
- * Including <cstddef> is a workaround for this issue.
- */
-#include <cstddef>
-
#include <gmpxx.h>
namespace CVC4 {
diff --git a/src/util/hash.h b/src/util/hash.h
index 548fb3afc..6f6af2bd7 100644
--- a/src/util/hash.h
+++ b/src/util/hash.h
@@ -5,7 +5,7 @@
** Morgan Deters, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,7 +20,6 @@
#ifndef CVC4__HASH_H
#define CVC4__HASH_H
-#include <cstdint>
#include <functional>
#include <string>
diff --git a/src/util/iand.h b/src/util/iand.h
index b5bc92960..68380824f 100644
--- a/src/util/iand.h
+++ b/src/util/iand.h
@@ -2,10 +2,10 @@
/*! \file iand.h
** \verbatim
** Top contributors (to current version):
- ** Anrew Reynolds
+ ** Andrew Reynolds
** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -17,7 +17,6 @@
#ifndef CVC4__IAND_H
#define CVC4__IAND_H
-#include <cstdint>
#include <iosfwd>
#include "base/exception.h"
diff --git a/src/util/index.cpp b/src/util/index.cpp
index 3d9877135..73fc54907 100644
--- a/src/util/index.cpp
+++ b/src/util/index.cpp
@@ -5,7 +5,7 @@
** Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -17,7 +17,6 @@
#include "util/index.h"
-#include <cstddef>
#include <limits>
namespace CVC4 {
diff --git a/src/util/index.h b/src/util/index.h
index 05227f0d3..d37ddb43e 100644
--- a/src/util/index.h
+++ b/src/util/index.h
@@ -5,7 +5,7 @@
** Mathias Preiner, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -19,8 +19,6 @@
#ifndef CVC4__INDEX_H
#define CVC4__INDEX_H
-#include <cstdint>
-
namespace CVC4 {
/** Index is a standardized unsigned integer used for efficient indexing. */
diff --git a/src/util/integer.h.in b/src/util/integer.h.in
index f13f68a82..54a9fb93e 100644
--- a/src/util/integer.h.in
+++ b/src/util/integer.h.in
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/integer_cln_imp.cpp b/src/util/integer_cln_imp.cpp
index ca59822a7..88db707d9 100644
--- a/src/util/integer_cln_imp.cpp
+++ b/src/util/integer_cln_imp.cpp
@@ -5,7 +5,7 @@
** Tim King, Aina Niemetz, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -14,16 +14,14 @@
** [[ Add lengthier description here ]]
** \todo document this file
**/
-#include "util/integer.h"
-
#include <sstream>
#include <string>
#include "cvc4autoconfig.h"
-
+#include "util/integer.h"
#ifndef CVC4_CLN_IMP
-# error "This source should only ever be built if CVC4_CLN_IMP is on !"
+#error "This source should only ever be built if CVC4_CLN_IMP is on !"
#endif /* CVC4_CLN_IMP */
#include "base/check.h"
@@ -32,54 +30,373 @@ using namespace std;
namespace CVC4 {
-signed int Integer::s_fastSignedIntMin = -(1<<29);
-signed int Integer::s_fastSignedIntMax = (1<<29)-1;
-signed long Integer::s_slowSignedIntMin = (signed long) std::numeric_limits<signed int>::min();
-signed long Integer::s_slowSignedIntMax = (signed long) std::numeric_limits<signed int>::max();
+signed int Integer::s_fastSignedIntMin = -(1 << 29);
+signed int Integer::s_fastSignedIntMax = (1 << 29) - 1;
+signed long Integer::s_slowSignedIntMin =
+ (signed long)std::numeric_limits<signed int>::min();
+signed long Integer::s_slowSignedIntMax =
+ (signed long)std::numeric_limits<signed int>::max();
+
+unsigned int Integer::s_fastUnsignedIntMax = (1 << 29) - 1;
+unsigned long Integer::s_slowUnsignedIntMax =
+ (unsigned long)std::numeric_limits<unsigned int>::max();
+
+unsigned long Integer::s_signedLongMin =
+ std::numeric_limits<signed long>::min();
+unsigned long Integer::s_signedLongMax =
+ std::numeric_limits<signed long>::max();
+unsigned long Integer::s_unsignedLongMax =
+ std::numeric_limits<unsigned long>::max();
+
+Integer& Integer::operator=(const Integer& x)
+{
+ if (this == &x) return *this;
+ d_value = x.d_value;
+ return *this;
+}
+
+bool Integer::operator==(const Integer& y) const
+{
+ return d_value == y.d_value;
+}
+
+Integer Integer::operator-() const { return Integer(-(d_value)); }
+
+bool Integer::operator!=(const Integer& y) const
+{
+ return d_value != y.d_value;
+}
+
+bool Integer::operator<(const Integer& y) const { return d_value < y.d_value; }
+
+bool Integer::operator<=(const Integer& y) const
+{
+ return d_value <= y.d_value;
+}
+
+bool Integer::operator>(const Integer& y) const { return d_value > y.d_value; }
+
+bool Integer::operator>=(const Integer& y) const
+{
+ return d_value >= y.d_value;
+}
+
+Integer Integer::operator+(const Integer& y) const
+{
+ return Integer(d_value + y.d_value);
+}
+
+Integer& Integer::operator+=(const Integer& y)
+{
+ d_value += y.d_value;
+ return *this;
+}
+
+Integer Integer::operator-(const Integer& y) const
+{
+ return Integer(d_value - y.d_value);
+}
-unsigned int Integer::s_fastUnsignedIntMax = (1<<29)-1;
-unsigned long Integer::s_slowUnsignedIntMax = (unsigned long) std::numeric_limits<unsigned int>::max();
+Integer& Integer::operator-=(const Integer& y)
+{
+ d_value -= y.d_value;
+ return *this;
+}
-unsigned long Integer::s_signedLongMin = std::numeric_limits<signed long>::min();
-unsigned long Integer::s_signedLongMax = std::numeric_limits<signed long>::max();
-unsigned long Integer::s_unsignedLongMax = std::numeric_limits<unsigned long>::max();
+Integer Integer::operator*(const Integer& y) const
+{
+ return Integer(d_value * y.d_value);
+}
-Integer Integer::oneExtend(uint32_t size, uint32_t amount) const {
+Integer& Integer::operator*=(const Integer& y)
+{
+ d_value *= y.d_value;
+ return *this;
+}
+
+Integer Integer::bitwiseOr(const Integer& y) const
+{
+ return Integer(cln::logior(d_value, y.d_value));
+}
+
+Integer Integer::bitwiseAnd(const Integer& y) const
+{
+ return Integer(cln::logand(d_value, y.d_value));
+}
+
+Integer Integer::bitwiseXor(const Integer& y) const
+{
+ return Integer(cln::logxor(d_value, y.d_value));
+}
+
+Integer Integer::bitwiseNot() const { return Integer(cln::lognot(d_value)); }
+
+Integer Integer::multiplyByPow2(uint32_t pow) const
+{
+ cln::cl_I ipow(pow);
+ return Integer(d_value << ipow);
+}
+
+bool Integer::isBitSet(uint32_t i) const
+{
+ return !extractBitRange(1, i).isZero();
+}
+
+Integer Integer::setBit(uint32_t i, bool value) const
+{
+ cln::cl_I mask(1);
+ mask = mask << i;
+ if (value) return Integer(cln::logior(d_value, mask));
+ mask = cln::lognot(mask);
+ return Integer(cln::logand(d_value, mask));
+}
+
+Integer Integer::oneExtend(uint32_t size, uint32_t amount) const
+{
DebugCheckArgument((*this) < Integer(1).multiplyByPow2(size), size);
cln::cl_byte range(amount, size);
- cln::cl_I allones = (cln::cl_I(1) << (size + amount))- 1; // 2^size - 1
+ cln::cl_I allones = (cln::cl_I(1) << (size + amount)) - 1; // 2^size - 1
Integer temp(allones);
return Integer(cln::deposit_field(allones, d_value, range));
}
+uint32_t Integer::toUnsignedInt() const { return cln::cl_I_to_uint(d_value); }
+
+Integer Integer::extractBitRange(uint32_t bitCount, uint32_t low) const
+{
+ cln::cl_byte range(bitCount, low);
+ return Integer(cln::ldb(d_value, range));
+}
+
+Integer Integer::floorDivideQuotient(const Integer& y) const
+{
+ return Integer(cln::floor1(d_value, y.d_value));
+}
-Integer Integer::exactQuotient(const Integer& y) const {
+Integer Integer::floorDivideRemainder(const Integer& y) const
+{
+ return Integer(cln::floor2(d_value, y.d_value).remainder);
+}
+
+void Integer::floorQR(Integer& q,
+ Integer& r,
+ const Integer& x,
+ const Integer& y)
+{
+ cln::cl_I_div_t res = cln::floor2(x.d_value, y.d_value);
+ q.d_value = res.quotient;
+ r.d_value = res.remainder;
+}
+
+Integer Integer::ceilingDivideQuotient(const Integer& y) const
+{
+ return Integer(cln::ceiling1(d_value, y.d_value));
+}
+
+Integer Integer::ceilingDivideRemainder(const Integer& y) const
+{
+ return Integer(cln::ceiling2(d_value, y.d_value).remainder);
+}
+
+void Integer::euclidianQR(Integer& q,
+ Integer& r,
+ const Integer& x,
+ const Integer& y)
+{
+ // compute the floor and then fix the value up if needed.
+ floorQR(q, r, x, y);
+
+ if (r.strictlyNegative())
+ {
+ // if r < 0
+ // abs(r) < abs(y)
+ // - abs(y) < r < 0, then 0 < r + abs(y) < abs(y)
+ // n = y * q + r
+ // n = y * q - abs(y) + r + abs(y)
+ if (r.sgn() >= 0)
+ {
+ // y = abs(y)
+ // n = y * q - y + r + y
+ // n = y * (q-1) + (r+y)
+ q -= 1;
+ r += y;
+ }
+ else
+ {
+ // y = -abs(y)
+ // n = y * q + y + r - y
+ // n = y * (q+1) + (r-y)
+ q += 1;
+ r -= y;
+ }
+ }
+}
+
+Integer Integer::euclidianDivideQuotient(const Integer& y) const
+{
+ Integer q, r;
+ euclidianQR(q, r, *this, y);
+ return q;
+}
+
+Integer Integer::euclidianDivideRemainder(const Integer& y) const
+{
+ Integer q, r;
+ euclidianQR(q, r, *this, y);
+ return r;
+}
+
+Integer Integer::exactQuotient(const Integer& y) const
+{
DebugCheckArgument(y.divides(*this), y);
- return Integer( cln::exquo(d_value, y.d_value) );
+ return Integer(cln::exquo(d_value, y.d_value));
+}
+
+Integer Integer::modByPow2(uint32_t exp) const
+{
+ cln::cl_byte range(exp, 0);
+ return Integer(cln::ldb(d_value, range));
+}
+
+Integer Integer::divByPow2(uint32_t exp) const { return d_value >> exp; }
+
+Integer Integer::pow(unsigned long int exp) const
+{
+ if (exp == 0)
+ {
+ return Integer(1);
+ }
+ else
+ {
+ Assert(exp > 0);
+ cln::cl_I result = cln::expt_pos(d_value, exp);
+ return Integer(result);
+ }
+}
+
+Integer Integer::gcd(const Integer& y) const
+{
+ cln::cl_I result = cln::gcd(d_value, y.d_value);
+ return Integer(result);
+}
+
+Integer Integer::lcm(const Integer& y) const
+{
+ cln::cl_I result = cln::lcm(d_value, y.d_value);
+ return Integer(result);
+}
+
+Integer Integer::modAdd(const Integer& y, const Integer& m) const
+{
+ cln::cl_modint_ring ry = cln::find_modint_ring(m.d_value);
+ cln::cl_MI xm = ry->canonhom(d_value);
+ cln::cl_MI ym = ry->canonhom(y.d_value);
+ cln::cl_MI res = xm + ym;
+ return Integer(ry->retract(res));
+}
+
+Integer Integer::modMultiply(const Integer& y, const Integer& m) const
+{
+ cln::cl_modint_ring ry = cln::find_modint_ring(m.d_value);
+ cln::cl_MI xm = ry->canonhom(d_value);
+ cln::cl_MI ym = ry->canonhom(y.d_value);
+ cln::cl_MI res = xm * ym;
+ return Integer(ry->retract(res));
+}
+
+Integer Integer::modInverse(const Integer& m) const
+{
+ PrettyCheckArgument(m > 0, m, "m must be greater than zero");
+ cln::cl_modint_ring ry = cln::find_modint_ring(m.d_value);
+ cln::cl_MI xm = ry->canonhom(d_value);
+ /* normalize to modulo m for coprime check */
+ cln::cl_I x = ry->retract(xm);
+ if (x == 0 || cln::gcd(x, m.d_value) != 1)
+ {
+ return Integer(-1);
+ }
+ cln::cl_MI res = cln::recip(xm);
+ return Integer(ry->retract(res));
+}
+
+bool Integer::divides(const Integer& y) const
+{
+ cln::cl_I result = cln::rem(y.d_value, d_value);
+ return cln::zerop(result);
}
+Integer Integer::abs() const { return d_value >= 0 ? *this : -*this; }
+
+std::string Integer::toString(int base) const
+{
+ std::stringstream ss;
+ switch (base)
+ {
+ case 2: fprintbinary(ss, d_value); break;
+ case 8: fprintoctal(ss, d_value); break;
+ case 10: fprintdecimal(ss, d_value); break;
+ case 16: fprinthexadecimal(ss, d_value); break;
+ default: throw Exception("Unhandled base in Integer::toString()");
+ }
+ std::string output = ss.str();
+ for (unsigned i = 0; i <= output.length(); ++i)
+ {
+ if (isalpha(output[i]))
+ {
+ output.replace(i, 1, 1, tolower(output[i]));
+ }
+ }
+
+ return output;
+}
+
+int Integer::sgn() const
+{
+ cln::cl_I sgn = cln::signum(d_value);
+ return cln::cl_I_to_int(sgn);
+}
+
+bool Integer::strictlyPositive() const { return cln::plusp(d_value); }
+
+bool Integer::strictlyNegative() const { return cln::minusp(d_value); }
+
+bool Integer::isZero() const { return cln::zerop(d_value); }
+
+bool Integer::isOne() const { return d_value == 1; }
+
+bool Integer::isNegativeOne() const { return d_value == -1; }
+
void Integer::parseInt(const std::string& s, unsigned base)
{
cln::cl_read_flags flags;
flags.syntax = cln::syntax_integer;
flags.lsyntax = cln::lsyntax_standard;
flags.rational_base = base;
- if(base == 0) {
+ if (base == 0)
+ {
// infer base in a manner consistent with GMP
- if(s[0] == '0') {
+ if (s[0] == '0')
+ {
flags.lsyntax = cln::lsyntax_commonlisp;
std::string st = s;
- if(s[1] == 'X' || s[1] == 'x') {
+ if (s[1] == 'X' || s[1] == 'x')
+ {
st.replace(0, 2, "#x");
- } else if(s[1] == 'B' || s[1] == 'b') {
+ }
+ else if (s[1] == 'B' || s[1] == 'b')
+ {
st.replace(0, 2, "#b");
- } else {
+ }
+ else
+ {
st.replace(0, 1, "#o");
}
readInt(flags, st, base);
return;
- } else {
+ }
+ else
+ {
flags.rational_base = 10;
}
}
@@ -90,104 +407,159 @@ void Integer::readInt(const cln::cl_read_flags& flags,
const std::string& s,
unsigned base)
{
- try {
+ try
+ {
// Removing leading zeroes, CLN has a bug for these inputs up to and
// including CLN v1.3.2.
- // See http://www.ginac.de/CLN/cln.git/?a=commit;h=4a477b0cc3dd7fbfb23b25090ff8c8869c8fa21a for details.
+ // See
+ // http://www.ginac.de/CLN/cln.git/?a=commit;h=4a477b0cc3dd7fbfb23b25090ff8c8869c8fa21a
+ // for details.
size_t pos = s.find_first_not_of('0');
- if(pos == std::string::npos) {
- d_value = read_integer(flags, "0", NULL, NULL);
- } else {
+ if (pos == std::string::npos)
+ {
+ d_value = cln::read_integer(flags, "0", NULL, NULL);
+ }
+ else
+ {
const char* cstr = s.c_str();
const char* start = cstr + pos;
const char* end = cstr + s.length();
- d_value = read_integer(flags, start, end, NULL);
+ d_value = cln::read_integer(flags, start, end, NULL);
}
- } catch(...) {
+ }
+ catch (...)
+ {
std::stringstream ss;
ss << "Integer() failed to parse value \"" << s << "\" in base " << base;
throw std::invalid_argument(ss.str());
}
}
-bool Integer::fitsSignedInt() const {
+bool Integer::fitsSignedInt() const
+{
// http://www.ginac.de/CLN/cln.html#Conversions
// TODO improve performance
Assert(s_slowSignedIntMin <= s_fastSignedIntMin);
Assert(s_fastSignedIntMin <= s_fastSignedIntMax);
Assert(s_fastSignedIntMax <= s_slowSignedIntMax);
- return (d_value <= s_fastSignedIntMax || d_value <= s_slowSignedIntMax) &&
- (d_value >= s_fastSignedIntMin || d_value >= s_slowSignedIntMax);
+ return (d_value <= s_fastSignedIntMax || d_value <= s_slowSignedIntMax)
+ && (d_value >= s_fastSignedIntMin || d_value >= s_slowSignedIntMax);
}
-bool Integer::fitsUnsignedInt() const {
+bool Integer::fitsUnsignedInt() const
+{
// TODO improve performance
Assert(s_fastUnsignedIntMax <= s_slowUnsignedIntMax);
- return sgn() >= 0 &&
- (d_value <= s_fastUnsignedIntMax || d_value <= s_slowUnsignedIntMax);
+ return sgn() >= 0
+ && (d_value <= s_fastUnsignedIntMax
+ || d_value <= s_slowUnsignedIntMax);
}
-signed int Integer::getSignedInt() const {
+signed int Integer::getSignedInt() const
+{
// ensure there isn't overflow
- CheckArgument(fitsSignedInt(), this, "Overflow detected in Integer::getSignedInt()");
+ CheckArgument(
+ fitsSignedInt(), this, "Overflow detected in Integer::getSignedInt()");
return cln::cl_I_to_int(d_value);
}
-unsigned int Integer::getUnsignedInt() const {
+unsigned int Integer::getUnsignedInt() const
+{
// ensure there isn't overflow
- CheckArgument(fitsUnsignedInt(), this, "Overflow detected in Integer::getUnsignedInt()");
+ CheckArgument(fitsUnsignedInt(),
+ this,
+ "Overflow detected in Integer::getUnsignedInt()");
return cln::cl_I_to_uint(d_value);
}
-bool Integer::fitsSignedLong() const {
+bool Integer::fitsSignedLong() const
+{
return d_value <= s_signedLongMax && d_value >= s_signedLongMin;
}
-bool Integer::fitsUnsignedLong() const {
+bool Integer::fitsUnsignedLong() const
+{
return sgn() >= 0 && d_value <= s_unsignedLongMax;
}
-Integer Integer::pow(unsigned long int exp) const {
- if (exp == 0) {
- return Integer(1);
- } else {
- Assert(exp > 0);
- cln::cl_I result = cln::expt_pos(d_value, exp);
- return Integer(result);
- }
+long Integer::getLong() const
+{
+ // ensure there isn't overflow
+ CheckArgument(d_value <= std::numeric_limits<long>::max(),
+ this,
+ "Overflow detected in Integer::getLong()");
+ CheckArgument(d_value >= std::numeric_limits<long>::min(),
+ this,
+ "Overflow detected in Integer::getLong()");
+ return cln::cl_I_to_long(d_value);
}
-Integer Integer::modAdd(const Integer& y, const Integer& m) const
+unsigned long Integer::getUnsignedLong() const
{
- cln::cl_modint_ring ry = cln::find_modint_ring(m.d_value);
- cln::cl_MI xm = ry->canonhom(d_value);
- cln::cl_MI ym = ry->canonhom(y.d_value);
- cln::cl_MI res = xm + ym;
- return Integer(ry->retract(res));
+ // ensure there isn't overflow
+ CheckArgument(d_value <= std::numeric_limits<unsigned long>::max(),
+ this,
+ "Overflow detected in Integer::getUnsignedLong()");
+ CheckArgument(d_value >= std::numeric_limits<unsigned long>::min(),
+ this,
+ "Overflow detected in Integer::getUnsignedLong()");
+ return cln::cl_I_to_ulong(d_value);
}
-Integer Integer::modMultiply(const Integer& y, const Integer& m) const
+size_t Integer::hash() const { return equal_hashcode(d_value); }
+
+bool Integer::testBit(unsigned n) const { return cln::logbitp(n, d_value); }
+
+unsigned Integer::isPow2() const
{
- cln::cl_modint_ring ry = cln::find_modint_ring(m.d_value);
- cln::cl_MI xm = ry->canonhom(d_value);
- cln::cl_MI ym = ry->canonhom(y.d_value);
- cln::cl_MI res = xm * ym;
- return Integer(ry->retract(res));
+ if (d_value <= 0) return 0;
+ // power2p returns n such that d_value = 2^(n-1)
+ return cln::power2p(d_value);
}
-Integer Integer::modInverse(const Integer& m) const
+size_t Integer::length() const
{
- PrettyCheckArgument(m > 0, m, "m must be greater than zero");
- cln::cl_modint_ring ry = cln::find_modint_ring(m.d_value);
- cln::cl_MI xm = ry->canonhom(d_value);
- /* normalize to modulo m for coprime check */
- cln::cl_I x = ry->retract(xm);
- if (x == 0 || cln::gcd(x, m.d_value) != 1)
+ int s = sgn();
+ if (s == 0)
{
- return Integer(-1);
+ return 1;
}
- cln::cl_MI res = cln::recip(xm);
- return Integer(ry->retract(res));
+ else if (s < 0)
+ {
+ size_t len = cln::integer_length(d_value);
+ /*If this is -2^n, return len+1 not len to stay consistent with the
+ * definition above! From CLN's documentation of integer_length: This is
+ * the smallest n >= 0 such that -2^n <= x < 2^n. If x > 0, this is the
+ * unique n > 0 such that 2^(n-1) <= x < 2^n.
+ */
+ size_t ord2 = cln::ord2(d_value);
+ return (len == ord2) ? (len + 1) : len;
+ }
+ else
+ {
+ return cln::integer_length(d_value);
+ }
+}
+
+void Integer::extendedGcd(
+ Integer& g, Integer& s, Integer& t, const Integer& a, const Integer& b)
+{
+ g.d_value = cln::xgcd(a.d_value, b.d_value, &s.d_value, &t.d_value);
+}
+
+const Integer& Integer::min(const Integer& a, const Integer& b)
+{
+ return (a <= b) ? a : b;
+}
+
+const Integer& Integer::max(const Integer& a, const Integer& b)
+{
+ return (a >= b) ? a : b;
+}
+
+std::ostream& operator<<(std::ostream& os, const Integer& n)
+{
+ return os << n.toString();
}
} /* namespace CVC4 */
diff --git a/src/util/integer_cln_imp.h b/src/util/integer_cln_imp.h
index ff4bcdf69..29a5248e3 100644
--- a/src/util/integer_cln_imp.h
+++ b/src/util/integer_cln_imp.h
@@ -5,7 +5,7 @@
** Tim King, Gereon Kremer, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -58,6 +58,10 @@ class CVC4_PUBLIC Integer
parseInt(std::string(sp), base);
}
+ /**
+ * Constructs a Integer from a C++ string.
+ * Throws std::invalid_argument if the string is not a valid integer.
+ */
explicit Integer(const std::string& s, unsigned base = 10)
{
parseInt(s, base);
@@ -75,154 +79,96 @@ class CVC4_PUBLIC Integer
Integer(uint64_t z) : d_value(static_cast<unsigned long>(z)) {}
#endif /* CVC4_NEED_INT64_T_OVERLOADS */
+ /** Destructor. */
~Integer() {}
- /**
- * Returns a copy of d_value to enable public access of CLN data.
- */
+ /** Returns a copy of d_value to enable public access of CLN data. */
const cln::cl_I& getValue() const { return d_value; }
- Integer& operator=(const Integer& x)
- {
- if (this == &x) return *this;
- d_value = x.d_value;
- return *this;
- }
-
- bool operator==(const Integer& y) const { return d_value == y.d_value; }
-
- Integer operator-() const { return Integer(-(d_value)); }
-
- bool operator!=(const Integer& y) const { return d_value != y.d_value; }
-
- bool operator<(const Integer& y) const { return d_value < y.d_value; }
-
- bool operator<=(const Integer& y) const { return d_value <= y.d_value; }
-
- bool operator>(const Integer& y) const { return d_value > y.d_value; }
-
- bool operator>=(const Integer& y) const { return d_value >= y.d_value; }
-
- Integer operator+(const Integer& y) const
- {
- return Integer(d_value + y.d_value);
- }
- Integer& operator+=(const Integer& y)
- {
- d_value += y.d_value;
- return *this;
- }
-
- Integer operator-(const Integer& y) const
- {
- return Integer(d_value - y.d_value);
- }
- Integer& operator-=(const Integer& y)
- {
- d_value -= y.d_value;
- return *this;
- }
-
- Integer operator*(const Integer& y) const
- {
- return Integer(d_value * y.d_value);
- }
-
- Integer& operator*=(const Integer& y)
- {
- d_value *= y.d_value;
- return *this;
- }
-
- Integer bitwiseOr(const Integer& y) const
- {
- return Integer(cln::logior(d_value, y.d_value));
- }
-
- Integer bitwiseAnd(const Integer& y) const
- {
- return Integer(cln::logand(d_value, y.d_value));
- }
-
- Integer bitwiseXor(const Integer& y) const
- {
- return Integer(cln::logxor(d_value, y.d_value));
- }
-
- Integer bitwiseNot() const { return Integer(cln::lognot(d_value)); }
+ /** Overload copy assignment operator. */
+ Integer& operator=(const Integer& x);
+
+ /** Overload equality comparison operator. */
+ bool operator==(const Integer& y) const;
+ /** Overload disequality comparison operator. */
+ bool operator!=(const Integer& y) const;
+ /** Overload less than comparison operator. */
+ bool operator<(const Integer& y) const;
+ /** Overload less than or equal comparison operator. */
+ bool operator<=(const Integer& y) const;
+ /** Overload greater than comparison operator. */
+ bool operator>(const Integer& y) const;
+ /** Overload greater than or equal comparison operator. */
+ bool operator>=(const Integer& y) const;
+
+ /** Overload negation operator. */
+ Integer operator-() const;
+ /** Overload addition operator. */
+ Integer operator+(const Integer& y) const;
+ /** Overload addition assignment operator. */
+ Integer& operator+=(const Integer& y);
+ /** Overload subtraction operator. */
+ Integer operator-(const Integer& y) const;
+ /** Overload subtraction assignment operator. */
+ Integer& operator-=(const Integer& y);
+ /** Overload multiplication operator. */
+ Integer operator*(const Integer& y) const;
+ /** Overload multiplication assignment operator. */
+ Integer& operator*=(const Integer& y);
+
+ /** Return the bit-wise or of this and the given Integer. */
+ Integer bitwiseOr(const Integer& y) const;
+ /** Return the bit-wise and of this and the given Integer. */
+ Integer bitwiseAnd(const Integer& y) const;
+ /** Return the bit-wise exclusive or of this and the given Integer. */
+ Integer bitwiseXor(const Integer& y) const;
+ /** Return the bit-wise not of this Integer. */
+ Integer bitwiseNot() const;
+
+ /** Return this*(2^pow). */
+ Integer multiplyByPow2(uint32_t pow) const;
+
+ /** Return true if bit at index 'i' is 1, and false otherwise. */
+ bool isBitSet(uint32_t i) const;
/**
- * Return this*(2^pow).
+ * Returns the Integer obtained by setting the ith bit of the
+ * current Integer to 1.
*/
- Integer multiplyByPow2(uint32_t pow) const
- {
- cln::cl_I ipow(pow);
- return Integer(d_value << ipow);
- }
-
- bool isBitSet(uint32_t i) const { return !extractBitRange(1, i).isZero(); }
-
- Integer setBit(uint32_t i) const
- {
- cln::cl_I mask(1);
- mask = mask << i;
- return Integer(cln::logior(d_value, mask));
- }
+ Integer setBit(uint32_t i, bool value) const;
+ /**
+ * Returns the integer with the binary representation of 'size' bits
+ * extended with 'amount' 1's.
+ */
Integer oneExtend(uint32_t size, uint32_t amount) const;
- uint32_t toUnsignedInt() const { return cln::cl_I_to_uint(d_value); }
-
- /** See CLN Documentation. */
- Integer extractBitRange(uint32_t bitCount, uint32_t low) const
- {
- cln::cl_byte range(bitCount, low);
- return Integer(cln::ldb(d_value, range));
- }
+ /** Return a 32 bit unsigned integer representation of this Integer. */
+ uint32_t toUnsignedInt() const;
/**
- * Returns the floor(this / y)
+ * Extract a range of bits from index 'low' to (excluding) 'low + bitCount'.
+ * Note: corresponds to the extract operator of theory BV.
*/
- Integer floorDivideQuotient(const Integer& y) const
- {
- return Integer(cln::floor1(d_value, y.d_value));
- }
+ Integer extractBitRange(uint32_t bitCount, uint32_t low) const;
- /**
- * Returns r == this - floor(this/y)*y
- */
- Integer floorDivideRemainder(const Integer& y) const
- {
- return Integer(cln::floor2(d_value, y.d_value).remainder);
- }
- /**
- * Computes a floor quoient and remainder for x divided by y.
- */
+ /** Returns the floor(this / y). */
+ Integer floorDivideQuotient(const Integer& y) const;
+
+ /** Returns r == this - floor(this/y)*y. */
+ Integer floorDivideRemainder(const Integer& y) const;
+
+ /** Computes a floor quoient and remainder for x divided by y. */
static void floorQR(Integer& q,
Integer& r,
const Integer& x,
- const Integer& y)
- {
- cln::cl_I_div_t res = cln::floor2(x.d_value, y.d_value);
- q.d_value = res.quotient;
- r.d_value = res.remainder;
- }
+ const Integer& y);
- /**
- * Returns the ceil(this / y)
- */
- Integer ceilingDivideQuotient(const Integer& y) const
- {
- return Integer(cln::ceiling1(d_value, y.d_value));
- }
+ /** Returns the ceil(this / y). */
+ Integer ceilingDivideQuotient(const Integer& y) const;
- /**
- * Returns the ceil(this / y)
- */
- Integer ceilingDivideRemainder(const Integer& y) const
- {
- return Integer(cln::ceiling2(d_value, y.d_value).remainder);
- }
+ /** Returns the ceil(this / y). */
+ Integer ceilingDivideRemainder(const Integer& y) const;
/**
* Computes a quoitent and remainder according to Boute's Euclidean
@@ -236,71 +182,28 @@ class CVC4_PUBLIC Integer
static void euclidianQR(Integer& q,
Integer& r,
const Integer& x,
- const Integer& y)
- {
- // compute the floor and then fix the value up if needed.
- floorQR(q, r, x, y);
-
- if (r.strictlyNegative())
- {
- // if r < 0
- // abs(r) < abs(y)
- // - abs(y) < r < 0, then 0 < r + abs(y) < abs(y)
- // n = y * q + r
- // n = y * q - abs(y) + r + abs(y)
- if (r.sgn() >= 0)
- {
- // y = abs(y)
- // n = y * q - y + r + y
- // n = y * (q-1) + (r+y)
- q -= 1;
- r += y;
- }
- else
- {
- // y = -abs(y)
- // n = y * q + y + r - y
- // n = y * (q+1) + (r-y)
- q += 1;
- r -= y;
- }
- }
- }
+ const Integer& y);
/**
* Returns the quoitent according to Boute's Euclidean definition.
* See the documentation for euclidianQR.
*/
- Integer euclidianDivideQuotient(const Integer& y) const
- {
- Integer q, r;
- euclidianQR(q, r, *this, y);
- return q;
- }
+ Integer euclidianDivideQuotient(const Integer& y) const;
/**
* Returns the remainfing according to Boute's Euclidean definition.
* See the documentation for euclidianQR.
*/
- Integer euclidianDivideRemainder(const Integer& y) const
- {
- Integer q, r;
- euclidianQR(q, r, *this, y);
- return r;
- }
+ Integer euclidianDivideRemainder(const Integer& y) const;
- /**
- * If y divides *this, then exactQuotient returns (this/y)
- */
+ /** If y divides *this, then exactQuotient returns (this/y). */
Integer exactQuotient(const Integer& y) const;
- Integer modByPow2(uint32_t exp) const
- {
- cln::cl_byte range(exp, 0);
- return Integer(cln::ldb(d_value, range));
- }
+ /** Return y mod 2^exp. */
+ Integer modByPow2(uint32_t exp) const;
- Integer divByPow2(uint32_t exp) const { return d_value >> exp; }
+ /** Returns y / 2^exp. */
+ Integer divByPow2(uint32_t exp) const;
/**
* Raise this Integer to the power <code>exp</code>.
@@ -309,32 +212,16 @@ class CVC4_PUBLIC Integer
*/
Integer pow(unsigned long int exp) const;
- /**
- * Return the greatest common divisor of this integer with another.
- */
- Integer gcd(const Integer& y) const
- {
- cln::cl_I result = cln::gcd(d_value, y.d_value);
- return Integer(result);
- }
+ /** Return the greatest common divisor of this integer with another. */
+ Integer gcd(const Integer& y) const;
- /**
- * Return the least common multiple of this integer with another.
- */
- Integer lcm(const Integer& y) const
- {
- cln::cl_I result = cln::lcm(d_value, y.d_value);
- return Integer(result);
- }
+ /** Return the least common multiple of this integer with another. */
+ Integer lcm(const Integer& y) const;
- /**
- * Compute addition of this Integer x + y modulo m.
- */
+ /** Compute addition of this Integer x + y modulo m. */
Integer modAdd(const Integer& y, const Integer& m) const;
- /**
- * Compute multiplication of this Integer x * y modulo m.
- */
+ /** Compute multiplication of this Integer x * y modulo m. */
Integer modMultiply(const Integer& y, const Integer& m) const;
/**
@@ -351,102 +238,62 @@ class CVC4_PUBLIC Integer
*/
Integer modInverse(const Integer& m) const;
- /**
- * Return true if *this exactly divides y.
- */
- bool divides(const Integer& y) const
- {
- cln::cl_I result = cln::rem(y.d_value, d_value);
- return cln::zerop(result);
- }
+ /** Return true if *this exactly divides y. */
+ bool divides(const Integer& y) const;
- /**
- * Return the absolute value of this integer.
- */
- Integer abs() const { return d_value >= 0 ? *this : -*this; }
+ /** Return the absolute value of this integer. */
+ Integer abs() const;
- std::string toString(int base = 10) const
- {
- std::stringstream ss;
- switch (base)
- {
- case 2: fprintbinary(ss, d_value); break;
- case 8: fprintoctal(ss, d_value); break;
- case 10: fprintdecimal(ss, d_value); break;
- case 16: fprinthexadecimal(ss, d_value); break;
- default: throw Exception("Unhandled base in Integer::toString()");
- }
- std::string output = ss.str();
- for (unsigned i = 0; i <= output.length(); ++i)
- {
- if (isalpha(output[i]))
- {
- output.replace(i, 1, 1, tolower(output[i]));
- }
- }
-
- return output;
- }
+ /** Return a string representation of this Integer. */
+ std::string toString(int base = 10) const;
- int sgn() const
- {
- cln::cl_I sgn = cln::signum(d_value);
- return cln::cl_I_to_int(sgn);
- }
+ /** Return 1 if this is > 0, 0 if it is 0, and -1 if it is < 0. */
+ int sgn() const;
- inline bool strictlyPositive() const { return sgn() > 0; }
+ /** Return true if this is > 0. */
+ bool strictlyPositive() const;
- inline bool strictlyNegative() const { return sgn() < 0; }
+ /** Return true if this is < 0. */
+ bool strictlyNegative() const;
- inline bool isZero() const { return sgn() == 0; }
+ /** Return true if this is 0. */
+ bool isZero() const;
- inline bool isOne() const { return d_value == 1; }
+ /** Return true if this is 1. */
+ bool isOne() const;
- inline bool isNegativeOne() const { return d_value == -1; }
+ /** Return true if this is -1. */
+ bool isNegativeOne() const;
- /** fits the C "signed int" primitive */
+ /** Return true if this Integer fits into a signed int. */
bool fitsSignedInt() const;
- /** fits the C "unsigned int" primitive */
+ /** Return true if this Integer fits into an unsigned int. */
bool fitsUnsignedInt() const;
+ /** Return the signed int representation of this Integer. */
int getSignedInt() const;
+ /** Return the unsigned int representation of this Integer. */
unsigned int getUnsignedInt() const;
+ /** Return true if this Integer fits into a signed long. */
bool fitsSignedLong() const;
+ /** Return true if this Integer fits into an unsigned long. */
bool fitsUnsignedLong() const;
- long getLong() const
- {
- // ensure there isn't overflow
- CheckArgument(d_value <= std::numeric_limits<long>::max(),
- this,
- "Overflow detected in Integer::getLong()");
- CheckArgument(d_value >= std::numeric_limits<long>::min(),
- this,
- "Overflow detected in Integer::getLong()");
- return cln::cl_I_to_long(d_value);
- }
+ /** Return the signed long representation of this Integer. */
+ long getLong() const;
- unsigned long getUnsignedLong() const
- {
- // ensure there isn't overflow
- CheckArgument(d_value <= std::numeric_limits<unsigned long>::max(),
- this,
- "Overflow detected in Integer::getUnsignedLong()");
- CheckArgument(d_value >= std::numeric_limits<unsigned long>::min(),
- this,
- "Overflow detected in Integer::getUnsignedLong()");
- return cln::cl_I_to_ulong(d_value);
- }
+ /** Return the unsigned long representation of this Integer. */
+ unsigned long getUnsignedLong() const;
/**
* Computes the hash of the node from the first word of the
* numerator, the denominator.
*/
- size_t hash() const { return equal_hashcode(d_value); }
+ size_t hash() const;
/**
* Returns true iff bit n is set.
@@ -454,46 +301,19 @@ class CVC4_PUBLIC Integer
* @param n the bit to test (0 == least significant bit)
* @return true if bit n is set in this integer; false otherwise
*/
- bool testBit(unsigned n) const { return cln::logbitp(n, d_value); }
+ bool testBit(unsigned n) const;
/**
* Returns k if the integer is equal to 2^(k-1)
* @return k if the integer is equal to 2^(k-1) and 0 otherwise
*/
- unsigned isPow2() const
- {
- if (d_value <= 0) return 0;
- // power2p returns n such that d_value = 2^(n-1)
- return cln::power2p(d_value);
- }
+ unsigned isPow2() const;
/**
* If x != 0, returns the unique n s.t. 2^{n-1} <= abs(x) < 2^{n}.
* If x == 0, returns 1.
*/
- size_t length() const
- {
- int s = sgn();
- if (s == 0)
- {
- return 1;
- }
- else if (s < 0)
- {
- size_t len = cln::integer_length(d_value);
- /*If this is -2^n, return len+1 not len to stay consistent with the
- * definition above! From CLN's documentation of integer_length: This is
- * the smallest n >= 0 such that -2^n <= x < 2^n. If x > 0, this is the
- * unique n > 0 such that 2^(n-1) <= x < 2^n.
- */
- size_t ord2 = cln::ord2(d_value);
- return (len == ord2) ? (len + 1) : len;
- }
- else
- {
- return cln::integer_length(d_value);
- }
- }
+ size_t length() const;
/* cl_I xgcd (const cl_I& a, const cl_I& b, cl_I* u, cl_I* v) */
/* This function ("extended gcd") returns the greatest common divisor g of a
@@ -503,22 +323,13 @@ class CVC4_PUBLIC Integer
* sense: If a and b are non-zero, and abs(a) != abs(b), u and v will satisfy
* the inequalities abs(u) <= abs(b)/(2*g), abs(v) <= abs(a)/(2*g). */
static void extendedGcd(
- Integer& g, Integer& s, Integer& t, const Integer& a, const Integer& b)
- {
- g.d_value = cln::xgcd(a.d_value, b.d_value, &s.d_value, &t.d_value);
- }
+ Integer& g, Integer& s, Integer& t, const Integer& a, const Integer& b);
/** Returns a reference to the minimum of two integers. */
- static const Integer& min(const Integer& a, const Integer& b)
- {
- return (a <= b) ? a : b;
- }
+ static const Integer& min(const Integer& a, const Integer& b);
/** Returns a reference to the maximum of two integers. */
- static const Integer& max(const Integer& a, const Integer& b)
- {
- return (a >= b) ? a : b;
- }
+ static const Integer& max(const Integer& a, const Integer& b);
private:
/**
@@ -526,45 +337,55 @@ class CVC4_PUBLIC Integer
* Only accessible to friend classes.
*/
const cln::cl_I& get_cl_I() const { return d_value; }
- // Throws a std::invalid_argument on invalid input `s` for the given base.
+
+ /**
+ * Helper for parseInt.
+ * Throws a std::invalid_argument on invalid input `s` for the given base.
+ */
void readInt(const cln::cl_read_flags& flags,
const std::string& s,
unsigned base);
- // Throws a std::invalid_argument on invalid inputs.
+ /**
+ * Parse string representation of integer into this Integer.
+ * Throws a std::invalid_argument on invalid inputs.
+ */
void parseInt(const std::string& s, unsigned base);
- // These constants are to help with CLN conversion in 32 bit.
- // See http://www.ginac.de/CLN/cln.html#Conversions
- static signed int s_fastSignedIntMax; /* 2^29 - 1 */
- static signed int s_fastSignedIntMin; /* -2^29 */
- static unsigned int s_fastUnsignedIntMax; /* 2^29 - 1 */
-
- static signed long
- s_slowSignedIntMax; /* std::numeric_limits<signed int>::max() */
- static signed long
- s_slowSignedIntMin; /* std::numeric_limits<signed int>::min() */
- static unsigned long
- s_slowUnsignedIntMax; /* std::numeric_limits<unsigned int>::max() */
+ /**
+ * The following constants are to help with CLN conversion in 32 bit.
+ * See http://www.ginac.de/CLN/cln.html#Conversions.
+ */
+
+ /** 2^29 - 1 */
+ static signed int s_fastSignedIntMax;
+ /** -2^29 */
+ static signed int s_fastSignedIntMin;
+ /** 2^29 - 1 */
+ static unsigned int s_fastUnsignedIntMax;
+ /** std::numeric_limits<signed int>::max() */
+ static signed long s_slowSignedIntMax;
+ /** std::numeric_limits<signed int>::min() */
+ static signed long s_slowSignedIntMin;
+ /** std::numeric_limits<unsigned int>::max() */
+ static unsigned long s_slowUnsignedIntMax;
+ /** std::numeric_limits<signed long>::min() */
static unsigned long s_signedLongMin;
+ /** std::numeric_limits<signed long>::max() */
static unsigned long s_signedLongMax;
+ /** std::numeric_limits<unsigned long>::max() */
static unsigned long s_unsignedLongMax;
- /**
- * Stores the value of the rational is stored in a C++ CLN integer class.
- */
+ /** Value of the rational is stored in a C++ CLN integer class. */
cln::cl_I d_value;
}; /* class Integer */
struct IntegerHashFunction
{
- inline size_t operator()(const CVC4::Integer& i) const { return i.hash(); }
+ size_t operator()(const CVC4::Integer& i) const { return i.hash(); }
}; /* struct IntegerHashFunction */
-inline std::ostream& operator<<(std::ostream& os, const Integer& n)
-{
- return os << n.toString();
-}
+std::ostream& operator<<(std::ostream& os, const Integer& n);
} // namespace CVC4
diff --git a/src/util/integer_gmp_imp.cpp b/src/util/integer_gmp_imp.cpp
index 8c59d74b8..5a4fc9349 100644
--- a/src/util/integer_gmp_imp.cpp
+++ b/src/util/integer_gmp_imp.cpp
@@ -5,7 +5,7 @@
** Tim King, Aina Niemetz, Liana Hadarean
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -27,8 +27,7 @@
#ifndef CVC4_GMP_IMP
# error "This source should only ever be built if CVC4_GMP_IMP is on !"
-#endif /* CVC4_GMP_IMP */
-
+#endif
using namespace std;
@@ -42,62 +41,300 @@ Integer::Integer(const std::string& s, unsigned base)
: d_value(s, base)
{}
+Integer& Integer::operator=(const Integer& x)
+{
+ if (this == &x) return *this;
+ d_value = x.d_value;
+ return *this;
+}
-bool Integer::fitsSignedInt() const {
- return d_value.fits_sint_p();
+bool Integer::operator==(const Integer& y) const
+{
+ return d_value == y.d_value;
}
-bool Integer::fitsUnsignedInt() const {
- return d_value.fits_uint_p();
+Integer Integer::operator-() const { return Integer(-(d_value)); }
+
+bool Integer::operator!=(const Integer& y) const
+{
+ return d_value != y.d_value;
}
-signed int Integer::getSignedInt() const {
- // ensure there isn't overflow
- CheckArgument(d_value <= std::numeric_limits<int>::max(), this,
- "Overflow detected in Integer::getSignedInt().");
- CheckArgument(d_value >= std::numeric_limits<int>::min(), this,
- "Overflow detected in Integer::getSignedInt().");
- CheckArgument(fitsSignedInt(), this,
- "Overflow detected in Integer::getSignedInt().");
- return (signed int) d_value.get_si();
+bool Integer::operator<(const Integer& y) const { return d_value < y.d_value; }
+
+bool Integer::operator<=(const Integer& y) const
+{
+ return d_value <= y.d_value;
}
-unsigned int Integer::getUnsignedInt() const {
- // ensure there isn't overflow
- CheckArgument(d_value <= std::numeric_limits<unsigned int>::max(), this,
- "Overflow detected in Integer::getUnsignedInt()");
- CheckArgument(d_value >= std::numeric_limits<unsigned int>::min(), this,
- "Overflow detected in Integer::getUnsignedInt()");
- CheckArgument(fitsSignedInt(), this,
- "Overflow detected in Integer::getUnsignedInt()");
- return (unsigned int) d_value.get_ui();
+bool Integer::operator>(const Integer& y) const { return d_value > y.d_value; }
+
+bool Integer::operator>=(const Integer& y) const
+{
+ return d_value >= y.d_value;
+}
+
+Integer Integer::operator+(const Integer& y) const
+{
+ return Integer(d_value + y.d_value);
+}
+
+Integer& Integer::operator+=(const Integer& y)
+{
+ d_value += y.d_value;
+ return *this;
+}
+
+Integer Integer::operator-(const Integer& y) const
+{
+ return Integer(d_value - y.d_value);
+}
+
+Integer& Integer::operator-=(const Integer& y)
+{
+ d_value -= y.d_value;
+ return *this;
+}
+
+Integer Integer::operator*(const Integer& y) const
+{
+ return Integer(d_value * y.d_value);
+}
+
+Integer& Integer::operator*=(const Integer& y)
+{
+ d_value *= y.d_value;
+ return *this;
+}
+
+Integer Integer::bitwiseOr(const Integer& y) const
+{
+ mpz_class result;
+ mpz_ior(result.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
+ return Integer(result);
+}
+
+Integer Integer::bitwiseAnd(const Integer& y) const
+{
+ mpz_class result;
+ mpz_and(result.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
+ return Integer(result);
+}
+
+Integer Integer::bitwiseXor(const Integer& y) const
+{
+ mpz_class result;
+ mpz_xor(result.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
+ return Integer(result);
}
-bool Integer::fitsSignedLong() const {
- return d_value.fits_slong_p();
+Integer Integer::bitwiseNot() const
+{
+ mpz_class result;
+ mpz_com(result.get_mpz_t(), d_value.get_mpz_t());
+ return Integer(result);
+}
+
+Integer Integer::multiplyByPow2(uint32_t pow) const
+{
+ mpz_class result;
+ mpz_mul_2exp(result.get_mpz_t(), d_value.get_mpz_t(), pow);
+ return Integer(result);
}
-bool Integer::fitsUnsignedLong() const {
- return d_value.fits_ulong_p();
+Integer Integer::setBit(uint32_t i, bool value) const
+{
+ mpz_class res = d_value;
+ if (value)
+ {
+ mpz_setbit(res.get_mpz_t(), i);
+ }
+ else
+ {
+ mpz_clrbit(res.get_mpz_t(), i);
+ }
+ return Integer(res);
}
-Integer Integer::oneExtend(uint32_t size, uint32_t amount) const {
+bool Integer::isBitSet(uint32_t i) const
+{
+ return !extractBitRange(1, i).isZero();
+}
+
+Integer Integer::oneExtend(uint32_t size, uint32_t amount) const
+{
// check that the size is accurate
DebugCheckArgument((*this) < Integer(1).multiplyByPow2(size), size);
mpz_class res = d_value;
- for (unsigned i = size; i < size + amount; ++i) {
+ for (unsigned i = size; i < size + amount; ++i)
+ {
mpz_setbit(res.get_mpz_t(), i);
}
return Integer(res);
}
-Integer Integer::exactQuotient(const Integer& y) const {
+uint32_t Integer::toUnsignedInt() const
+{
+ return mpz_get_ui(d_value.get_mpz_t());
+}
+
+Integer Integer::extractBitRange(uint32_t bitCount, uint32_t low) const
+{
+ // bitCount = high-low+1
+ uint32_t high = low + bitCount - 1;
+ //— Function: void mpz_fdiv_r_2exp (mpz_t r, mpz_t n, mp_bitcnt_t b)
+ mpz_class rem, div;
+ mpz_fdiv_r_2exp(rem.get_mpz_t(), d_value.get_mpz_t(), high + 1);
+ mpz_fdiv_q_2exp(div.get_mpz_t(), rem.get_mpz_t(), low);
+
+ return Integer(div);
+}
+
+Integer Integer::floorDivideQuotient(const Integer& y) const
+{
+ mpz_class q;
+ mpz_fdiv_q(q.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
+ return Integer(q);
+}
+
+Integer Integer::floorDivideRemainder(const Integer& y) const
+{
+ mpz_class r;
+ mpz_fdiv_r(r.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
+ return Integer(r);
+}
+
+void Integer::floorQR(Integer& q,
+ Integer& r,
+ const Integer& x,
+ const Integer& y)
+{
+ mpz_fdiv_qr(q.d_value.get_mpz_t(),
+ r.d_value.get_mpz_t(),
+ x.d_value.get_mpz_t(),
+ y.d_value.get_mpz_t());
+}
+
+Integer Integer::ceilingDivideQuotient(const Integer& y) const
+{
+ mpz_class q;
+ mpz_cdiv_q(q.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
+ return Integer(q);
+}
+
+Integer Integer::ceilingDivideRemainder(const Integer& y) const
+{
+ mpz_class r;
+ mpz_cdiv_r(r.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
+ return Integer(r);
+}
+
+void Integer::euclidianQR(Integer& q,
+ Integer& r,
+ const Integer& x,
+ const Integer& y)
+{
+ // compute the floor and then fix the value up if needed.
+ floorQR(q, r, x, y);
+
+ if (r.strictlyNegative())
+ {
+ // if r < 0
+ // abs(r) < abs(y)
+ // - abs(y) < r < 0, then 0 < r + abs(y) < abs(y)
+ // n = y * q + r
+ // n = y * q - abs(y) + r + abs(y)
+ if (r.sgn() >= 0)
+ {
+ // y = abs(y)
+ // n = y * q - y + r + y
+ // n = y * (q-1) + (r+y)
+ q -= 1;
+ r += y;
+ }
+ else
+ {
+ // y = -abs(y)
+ // n = y * q + y + r - y
+ // n = y * (q+1) + (r-y)
+ q += 1;
+ r -= y;
+ }
+ }
+}
+
+Integer Integer::euclidianDivideQuotient(const Integer& y) const
+{
+ Integer q, r;
+ euclidianQR(q, r, *this, y);
+ return q;
+}
+
+Integer Integer::euclidianDivideRemainder(const Integer& y) const
+{
+ Integer q, r;
+ euclidianQR(q, r, *this, y);
+ return r;
+}
+
+Integer Integer::exactQuotient(const Integer& y) const
+{
DebugCheckArgument(y.divides(*this), y);
mpz_class q;
mpz_divexact(q.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
- return Integer( q );
+ return Integer(q);
+}
+
+Integer Integer::modByPow2(uint32_t exp) const
+{
+ mpz_class res;
+ mpz_fdiv_r_2exp(res.get_mpz_t(), d_value.get_mpz_t(), exp);
+ return Integer(res);
+}
+
+Integer Integer::divByPow2(uint32_t exp) const
+{
+ mpz_class res;
+ mpz_fdiv_q_2exp(res.get_mpz_t(), d_value.get_mpz_t(), exp);
+ return Integer(res);
+}
+
+int Integer::sgn() const { return mpz_sgn(d_value.get_mpz_t()); }
+
+bool Integer::strictlyPositive() const { return sgn() > 0; }
+
+bool Integer::strictlyNegative() const { return sgn() < 0; }
+
+bool Integer::isZero() const { return sgn() == 0; }
+
+bool Integer::isOne() const { return mpz_cmp_si(d_value.get_mpz_t(), 1) == 0; }
+
+bool Integer::isNegativeOne() const
+{
+ return mpz_cmp_si(d_value.get_mpz_t(), -1) == 0;
+}
+
+Integer Integer::pow(unsigned long int exp) const
+{
+ mpz_class result;
+ mpz_pow_ui(result.get_mpz_t(), d_value.get_mpz_t(), exp);
+ return Integer(result);
+}
+
+Integer Integer::gcd(const Integer& y) const
+{
+ mpz_class result;
+ mpz_gcd(result.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
+ return Integer(result);
+}
+
+Integer Integer::lcm(const Integer& y) const
+{
+ mpz_class result;
+ mpz_lcm(result.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
+ return Integer(result);
}
Integer Integer::modAdd(const Integer& y, const Integer& m) const
@@ -127,4 +364,125 @@ Integer Integer::modInverse(const Integer& m) const
}
return Integer(res);
}
+
+bool Integer::divides(const Integer& y) const
+{
+ int res = mpz_divisible_p(y.d_value.get_mpz_t(), d_value.get_mpz_t());
+ return res != 0;
+}
+
+Integer Integer::abs() const { return d_value >= 0 ? *this : -*this; }
+
+std::string Integer::toString(int base) const { return d_value.get_str(base); }
+
+bool Integer::fitsSignedInt() const { return d_value.fits_sint_p(); }
+
+bool Integer::fitsUnsignedInt() const { return d_value.fits_uint_p(); }
+
+signed int Integer::getSignedInt() const
+{
+ // ensure there isn't overflow
+ CheckArgument(d_value <= std::numeric_limits<int>::max(),
+ this,
+ "Overflow detected in Integer::getSignedInt().");
+ CheckArgument(d_value >= std::numeric_limits<int>::min(),
+ this,
+ "Overflow detected in Integer::getSignedInt().");
+ CheckArgument(
+ fitsSignedInt(), this, "Overflow detected in Integer::getSignedInt().");
+ return (signed int)d_value.get_si();
+}
+
+unsigned int Integer::getUnsignedInt() const
+{
+ // ensure there isn't overflow
+ CheckArgument(d_value <= std::numeric_limits<unsigned int>::max(),
+ this,
+ "Overflow detected in Integer::getUnsignedInt()");
+ CheckArgument(d_value >= std::numeric_limits<unsigned int>::min(),
+ this,
+ "Overflow detected in Integer::getUnsignedInt()");
+ CheckArgument(
+ fitsSignedInt(), this, "Overflow detected in Integer::getUnsignedInt()");
+ return (unsigned int)d_value.get_ui();
+}
+
+bool Integer::fitsSignedLong() const { return d_value.fits_slong_p(); }
+
+bool Integer::fitsUnsignedLong() const { return d_value.fits_ulong_p(); }
+
+long Integer::getLong() const
+{
+ long si = d_value.get_si();
+ // ensure there wasn't overflow
+ CheckArgument(mpz_cmp_si(d_value.get_mpz_t(), si) == 0,
+ this,
+ "Overflow detected in Integer::getLong().");
+ return si;
+}
+
+unsigned long Integer::getUnsignedLong() const
+{
+ unsigned long ui = d_value.get_ui();
+ // ensure there wasn't overflow
+ CheckArgument(mpz_cmp_ui(d_value.get_mpz_t(), ui) == 0,
+ this,
+ "Overflow detected in Integer::getUnsignedLong().");
+ return ui;
+}
+
+size_t Integer::hash() const { return gmpz_hash(d_value.get_mpz_t()); }
+
+bool Integer::testBit(unsigned n) const
+{
+ return mpz_tstbit(d_value.get_mpz_t(), n);
+}
+
+unsigned Integer::isPow2() const
+{
+ if (d_value <= 0) return 0;
+ // check that the number of ones in the binary representation is 1
+ if (mpz_popcount(d_value.get_mpz_t()) == 1)
+ {
+ // return the index of the first one plus 1
+ return mpz_scan1(d_value.get_mpz_t(), 0) + 1;
+ }
+ return 0;
+}
+
+size_t Integer::length() const
+{
+ if (sgn() == 0)
+ {
+ return 1;
+ }
+ else
+ {
+ return mpz_sizeinbase(d_value.get_mpz_t(), 2);
+ }
+}
+
+void Integer::extendedGcd(
+ Integer& g, Integer& s, Integer& t, const Integer& a, const Integer& b)
+{
+ // see the documentation for:
+ // mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, mpz_t a, mpz_t b);
+ mpz_gcdext(g.d_value.get_mpz_t(),
+ s.d_value.get_mpz_t(),
+ t.d_value.get_mpz_t(),
+ a.d_value.get_mpz_t(),
+ b.d_value.get_mpz_t());
+}
+
+const Integer& Integer::min(const Integer& a, const Integer& b)
+{
+ return (a <= b) ? a : b;
+}
+
+/** Returns a reference to the maximum of two integers. */
+const Integer& Integer::max(const Integer& a, const Integer& b)
+{
+ return (a >= b) ? a : b;
+}
+
} /* namespace CVC4 */
diff --git a/src/util/integer_gmp_imp.h b/src/util/integer_gmp_imp.h
index 5277923f4..a11a15f81 100644
--- a/src/util/integer_gmp_imp.h
+++ b/src/util/integer_gmp_imp.h
@@ -5,7 +5,7 @@
** Tim King, Gereon Kremer, Liana Hadarean
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -65,189 +65,96 @@ class CVC4_PUBLIC Integer
Integer(uint64_t z) : d_value(static_cast<unsigned long>(z)) {}
#endif /* CVC4_NEED_INT64_T_OVERLOADS */
+ /** Destructor. */
~Integer() {}
- /**
- * Returns a copy of d_value to enable public access of GMP data.
- */
+ /** Returns a copy of d_value to enable public access of GMP data. */
const mpz_class& getValue() const { return d_value; }
- Integer& operator=(const Integer& x)
- {
- if (this == &x) return *this;
- d_value = x.d_value;
- return *this;
- }
-
- bool operator==(const Integer& y) const { return d_value == y.d_value; }
-
- Integer operator-() const { return Integer(-(d_value)); }
-
- bool operator!=(const Integer& y) const { return d_value != y.d_value; }
-
- bool operator<(const Integer& y) const { return d_value < y.d_value; }
-
- bool operator<=(const Integer& y) const { return d_value <= y.d_value; }
-
- bool operator>(const Integer& y) const { return d_value > y.d_value; }
-
- bool operator>=(const Integer& y) const { return d_value >= y.d_value; }
-
- Integer operator+(const Integer& y) const
- {
- return Integer(d_value + y.d_value);
- }
- Integer& operator+=(const Integer& y)
- {
- d_value += y.d_value;
- return *this;
- }
-
- Integer operator-(const Integer& y) const
- {
- return Integer(d_value - y.d_value);
- }
- Integer& operator-=(const Integer& y)
- {
- d_value -= y.d_value;
- return *this;
- }
-
- Integer operator*(const Integer& y) const
- {
- return Integer(d_value * y.d_value);
- }
- Integer& operator*=(const Integer& y)
- {
- d_value *= y.d_value;
- return *this;
- }
-
- Integer bitwiseOr(const Integer& y) const
- {
- mpz_class result;
- mpz_ior(result.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
- return Integer(result);
- }
-
- Integer bitwiseAnd(const Integer& y) const
- {
- mpz_class result;
- mpz_and(result.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
- return Integer(result);
- }
-
- Integer bitwiseXor(const Integer& y) const
- {
- mpz_class result;
- mpz_xor(result.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
- return Integer(result);
- }
-
- Integer bitwiseNot() const
- {
- mpz_class result;
- mpz_com(result.get_mpz_t(), d_value.get_mpz_t());
- return Integer(result);
- }
-
- /**
- * Return this*(2^pow).
- */
- Integer multiplyByPow2(uint32_t pow) const
- {
- mpz_class result;
- mpz_mul_2exp(result.get_mpz_t(), d_value.get_mpz_t(), pow);
- return Integer(result);
- }
+ /** Overload copy assignment operator. */
+ Integer& operator=(const Integer& x);
+
+ /** Overload equality comparison operator. */
+ bool operator==(const Integer& y) const;
+ /** Overload disequality comparison operator. */
+ bool operator!=(const Integer& y) const;
+ /** Overload less than comparison operator. */
+ bool operator<(const Integer& y) const;
+ /** Overload less than or equal comparison operator. */
+ bool operator<=(const Integer& y) const;
+ /** Overload greater than comparison operator. */
+ bool operator>(const Integer& y) const;
+ /** Overload greater than or equal comparison operator. */
+ bool operator>=(const Integer& y) const;
+
+ /** Overload negation operator. */
+ Integer operator-() const;
+ /** Overload addition operator. */
+ Integer operator+(const Integer& y) const;
+ /** Overload addition assignment operator. */
+ Integer& operator+=(const Integer& y);
+ /** Overload subtraction operator. */
+ Integer operator-(const Integer& y) const;
+ /** Overload subtraction assignment operator. */
+ Integer& operator-=(const Integer& y);
+ /** Overload multiplication operator. */
+ Integer operator*(const Integer& y) const;
+ /** Overload multiplication assignment operator. */
+ Integer& operator*=(const Integer& y);
+
+ /** Return the bit-wise or of this and the given Integer. */
+ Integer bitwiseOr(const Integer& y) const;
+ /** Return the bit-wise and of this and the given Integer. */
+ Integer bitwiseAnd(const Integer& y) const;
+ /** Return the bit-wise exclusive or of this and the given Integer. */
+ Integer bitwiseXor(const Integer& y) const;
+ /** Return the bit-wise not of this Integer. */
+ Integer bitwiseNot() const;
+
+ /** Return this*(2^pow). */
+ Integer multiplyByPow2(uint32_t pow) const;
/**
* Returns the Integer obtained by setting the ith bit of the
* current Integer to 1.
*/
- Integer setBit(uint32_t i) const
- {
- mpz_class res = d_value;
- mpz_setbit(res.get_mpz_t(), i);
- return Integer(res);
- }
+ Integer setBit(uint32_t i, bool value) const;
- bool isBitSet(uint32_t i) const { return !extractBitRange(1, i).isZero(); }
+ /** Return true if bit at index 'i' is 1, and false otherwise. */
+ bool isBitSet(uint32_t i) const;
/**
- * Returns the integer with the binary representation of size bits
- * extended with amount 1's
+ * Returns the integer with the binary representation of 'size' bits
+ * extended with 'amount' 1's.
*/
Integer oneExtend(uint32_t size, uint32_t amount) const;
- uint32_t toUnsignedInt() const { return mpz_get_ui(d_value.get_mpz_t()); }
-
- /** See GMP Documentation. */
- Integer extractBitRange(uint32_t bitCount, uint32_t low) const
- {
- // bitCount = high-low+1
- uint32_t high = low + bitCount - 1;
- //— Function: void mpz_fdiv_r_2exp (mpz_t r, mpz_t n, mp_bitcnt_t b)
- mpz_class rem, div;
- mpz_fdiv_r_2exp(rem.get_mpz_t(), d_value.get_mpz_t(), high + 1);
- mpz_fdiv_q_2exp(div.get_mpz_t(), rem.get_mpz_t(), low);
-
- return Integer(div);
- }
+ /** Return a 32 bit unsigned integer representation of this Integer. */
+ uint32_t toUnsignedInt() const;
/**
- * Returns the floor(this / y)
+ * Extract a range of bits from index 'low' to (excluding) 'low + bitCount'.
+ * Note: corresponds to the extract operator of theory BV.
*/
- Integer floorDivideQuotient(const Integer& y) const
- {
- mpz_class q;
- mpz_fdiv_q(q.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
- return Integer(q);
- }
+ Integer extractBitRange(uint32_t bitCount, uint32_t low) const;
- /**
- * Returns r == this - floor(this/y)*y
- */
- Integer floorDivideRemainder(const Integer& y) const
- {
- mpz_class r;
- mpz_fdiv_r(r.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
- return Integer(r);
- }
+ /** Returns the floor(this / y) */
+ Integer floorDivideQuotient(const Integer& y) const;
- /**
- * Computes a floor quotient and remainder for x divided by y.
- */
+ /** Returns r == this - floor(this/y)*y */
+ Integer floorDivideRemainder(const Integer& y) const;
+
+ /** Computes a floor quotient and remainder for x divided by y. */
static void floorQR(Integer& q,
Integer& r,
const Integer& x,
- const Integer& y)
- {
- mpz_fdiv_qr(q.d_value.get_mpz_t(),
- r.d_value.get_mpz_t(),
- x.d_value.get_mpz_t(),
- y.d_value.get_mpz_t());
- }
+ const Integer& y);
- /**
- * Returns the ceil(this / y)
- */
- Integer ceilingDivideQuotient(const Integer& y) const
- {
- mpz_class q;
- mpz_cdiv_q(q.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
- return Integer(q);
- }
+ /** Returns the ceil(this / y). */
+ Integer ceilingDivideQuotient(const Integer& y) const;
- /**
- * Returns the ceil(this / y)
- */
- Integer ceilingDivideRemainder(const Integer& y) const
- {
- mpz_class r;
- mpz_cdiv_r(r.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
- return Integer(r);
- }
+ /** Returns the ceil(this / y). */
+ Integer ceilingDivideRemainder(const Integer& y) const;
/**
* Computes a quotient and remainder according to Boute's Euclidean
@@ -261,139 +168,60 @@ class CVC4_PUBLIC Integer
static void euclidianQR(Integer& q,
Integer& r,
const Integer& x,
- const Integer& y)
- {
- // compute the floor and then fix the value up if needed.
- floorQR(q, r, x, y);
-
- if (r.strictlyNegative())
- {
- // if r < 0
- // abs(r) < abs(y)
- // - abs(y) < r < 0, then 0 < r + abs(y) < abs(y)
- // n = y * q + r
- // n = y * q - abs(y) + r + abs(y)
- if (r.sgn() >= 0)
- {
- // y = abs(y)
- // n = y * q - y + r + y
- // n = y * (q-1) + (r+y)
- q -= 1;
- r += y;
- }
- else
- {
- // y = -abs(y)
- // n = y * q + y + r - y
- // n = y * (q+1) + (r-y)
- q += 1;
- r -= y;
- }
- }
- }
+ const Integer& y);
/**
* Returns the quotient according to Boute's Euclidean definition.
* See the documentation for euclidianQR.
*/
- Integer euclidianDivideQuotient(const Integer& y) const
- {
- Integer q, r;
- euclidianQR(q, r, *this, y);
- return q;
- }
+ Integer euclidianDivideQuotient(const Integer& y) const;
/**
* Returns the remainder according to Boute's Euclidean definition.
* See the documentation for euclidianQR.
*/
- Integer euclidianDivideRemainder(const Integer& y) const
- {
- Integer q, r;
- euclidianQR(q, r, *this, y);
- return r;
- }
+ Integer euclidianDivideRemainder(const Integer& y) const;
- /**
- * If y divides *this, then exactQuotient returns (this/y)
- */
+ /** If y divides *this, then exactQuotient returns (this/y). */
Integer exactQuotient(const Integer& y) const;
- /**
- * Returns y mod 2^exp
- */
- Integer modByPow2(uint32_t exp) const
- {
- mpz_class res;
- mpz_fdiv_r_2exp(res.get_mpz_t(), d_value.get_mpz_t(), exp);
- return Integer(res);
- }
+ /** Returns y mod 2^exp. */
+ Integer modByPow2(uint32_t exp) const;
- /**
- * Returns y / 2^exp
- */
- Integer divByPow2(uint32_t exp) const
- {
- mpz_class res;
- mpz_fdiv_q_2exp(res.get_mpz_t(), d_value.get_mpz_t(), exp);
- return Integer(res);
- }
+ /** Returns y / 2^exp. */
+ Integer divByPow2(uint32_t exp) const;
- int sgn() const { return mpz_sgn(d_value.get_mpz_t()); }
+ /** Return 1 if this is > 0, 0 if it is 0, and -1 if it is < 0. */
+ int sgn() const;
- inline bool strictlyPositive() const { return sgn() > 0; }
+ /** Return true if this is > 0. */
+ bool strictlyPositive() const;
- inline bool strictlyNegative() const { return sgn() < 0; }
+ /** Return true if this is < 0. */
+ bool strictlyNegative() const;
- inline bool isZero() const { return sgn() == 0; }
+ /** Return true if this is 0. */
+ bool isZero() const;
- bool isOne() const { return mpz_cmp_si(d_value.get_mpz_t(), 1) == 0; }
+ /** Return true if this is 1. */
+ bool isOne() const;
- bool isNegativeOne() const
- {
- return mpz_cmp_si(d_value.get_mpz_t(), -1) == 0;
- }
+ /** Return true if this is -1. */
+ bool isNegativeOne() const;
- /**
- * Raise this Integer to the power <code>exp</code>.
- *
- * @param exp the exponent
- */
- Integer pow(unsigned long int exp) const
- {
- mpz_class result;
- mpz_pow_ui(result.get_mpz_t(), d_value.get_mpz_t(), exp);
- return Integer(result);
- }
+ /** Raise this Integer to the power 'exp'. */
+ Integer pow(unsigned long int exp) const;
- /**
- * Return the greatest common divisor of this integer with another.
- */
- Integer gcd(const Integer& y) const
- {
- mpz_class result;
- mpz_gcd(result.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
- return Integer(result);
- }
+ /** Return the greatest common divisor of this integer with another. */
+ Integer gcd(const Integer& y) const;
- /**
- * Return the least common multiple of this integer with another.
- */
- Integer lcm(const Integer& y) const
- {
- mpz_class result;
- mpz_lcm(result.get_mpz_t(), d_value.get_mpz_t(), y.d_value.get_mpz_t());
- return Integer(result);
- }
+ /** Return the least common multiple of this integer with another. */
+ Integer lcm(const Integer& y) const;
- /**
- * Compute addition of this Integer x + y modulo m.
- */
+ /** Compute addition of this Integer x + y modulo m. */
Integer modAdd(const Integer& y, const Integer& m) const;
- /**
- * Compute multiplication of this Integer x * y modulo m.
- */
+ /** Compute multiplication of this Integer x * y modulo m. */
Integer modMultiply(const Integer& y, const Integer& m) const;
/**
@@ -411,59 +239,46 @@ class CVC4_PUBLIC Integer
Integer modInverse(const Integer& m) const;
/**
- * All non-zero integers z, z.divide(0)
- * ! zero.divides(zero)
+ * Return true if 'y' divides this integer.
+ * Note: All non-zero integers devide zero, and zero does not divide zero.
*/
- bool divides(const Integer& y) const
- {
- int res = mpz_divisible_p(y.d_value.get_mpz_t(), d_value.get_mpz_t());
- return res != 0;
- }
+ bool divides(const Integer& y) const;
- /**
- * Return the absolute value of this integer.
- */
- Integer abs() const { return d_value >= 0 ? *this : -*this; }
+ /** Return the absolute value of this integer. */
+ Integer abs() const;
- std::string toString(int base = 10) const { return d_value.get_str(base); }
+ /** Return a string representation of this Integer. */
+ std::string toString(int base = 10) const;
+ /** Return true if this Integer fits into a signed int. */
bool fitsSignedInt() const;
+ /** Return true if this Integer fits into an unsigned int. */
bool fitsUnsignedInt() const;
+ /** Return the signed int representation of this Integer. */
signed int getSignedInt() const;
+ /** Return the unsigned int representation of this Integer. */
unsigned int getUnsignedInt() const;
+ /** Return true if this Integer fits into a signed long. */
bool fitsSignedLong() const;
+ /** Return true if this Integer fits into an unsigned long. */
bool fitsUnsignedLong() const;
- long getLong() const
- {
- long si = d_value.get_si();
- // ensure there wasn't overflow
- CheckArgument(mpz_cmp_si(d_value.get_mpz_t(), si) == 0,
- this,
- "Overflow detected in Integer::getLong().");
- return si;
- }
-
- unsigned long getUnsignedLong() const
- {
- unsigned long ui = d_value.get_ui();
- // ensure there wasn't overflow
- CheckArgument(mpz_cmp_ui(d_value.get_mpz_t(), ui) == 0,
- this,
- "Overflow detected in Integer::getUnsignedLong().");
- return ui;
- }
+ /** Return the signed long representation of this Integer. */
+ long getLong() const;
+
+ /** Return the unsigned long representation of this Integer. */
+ unsigned long getUnsignedLong() const;
/**
* Computes the hash of the node from the first word of the
* numerator, the denominator.
*/
- size_t hash() const { return gmpz_hash(d_value.get_mpz_t()); }
+ size_t hash() const;
/**
* Returns true iff bit n is set.
@@ -471,63 +286,36 @@ class CVC4_PUBLIC Integer
* @param n the bit to test (0 == least significant bit)
* @return true if bit n is set in this integer; false otherwise
*/
- bool testBit(unsigned n) const { return mpz_tstbit(d_value.get_mpz_t(), n); }
+ bool testBit(unsigned n) const;
/**
* Returns k if the integer is equal to 2^(k-1)
* @return k if the integer is equal to 2^(k-1) and 0 otherwise
*/
- unsigned isPow2() const
- {
- if (d_value <= 0) return 0;
- // check that the number of ones in the binary representation is 1
- if (mpz_popcount(d_value.get_mpz_t()) == 1)
- {
- // return the index of the first one plus 1
- return mpz_scan1(d_value.get_mpz_t(), 0) + 1;
- }
- return 0;
- }
+ unsigned isPow2() const;
/**
* If x != 0, returns the smallest n s.t. 2^{n-1} <= abs(x) < 2^{n}.
* If x == 0, returns 1.
*/
- size_t length() const
- {
- if (sgn() == 0)
- {
- return 1;
- }
- else
- {
- return mpz_sizeinbase(d_value.get_mpz_t(), 2);
- }
- }
+ size_t length() const;
+ /**
+ * Return the greatest common divisor of a and b, and in addition set s and t
+ * to coefficients satisfying a*s + b*t = g.
+ *
+ * Note: The returned Integer is always positive, even if one or both of a
+ * and b are negative (or zero if both inputs are zero). For more
+ * details, see https://gmplib.org/manual/Number-Theoretic-Functions.
+ */
static void extendedGcd(
- Integer& g, Integer& s, Integer& t, const Integer& a, const Integer& b)
- {
- // see the documentation for:
- // mpz_gcdext (mpz_t g, mpz_t s, mpz_t t, mpz_t a, mpz_t b);
- mpz_gcdext(g.d_value.get_mpz_t(),
- s.d_value.get_mpz_t(),
- t.d_value.get_mpz_t(),
- a.d_value.get_mpz_t(),
- b.d_value.get_mpz_t());
- }
+ Integer& g, Integer& s, Integer& t, const Integer& a, const Integer& b);
/** Returns a reference to the minimum of two integers. */
- static const Integer& min(const Integer& a, const Integer& b)
- {
- return (a <= b) ? a : b;
- }
+ static const Integer& min(const Integer& a, const Integer& b);
/** Returns a reference to the maximum of two integers. */
- static const Integer& max(const Integer& a, const Integer& b)
- {
- return (a >= b) ? a : b;
- }
+ static const Integer& max(const Integer& a, const Integer& b);
private:
/**
@@ -537,7 +325,7 @@ class CVC4_PUBLIC Integer
const mpz_class& get_mpz() const { return d_value; }
/**
- * Stores the value of the rational is stored in a C++ GMP integer class.
+ * The value of the rational is stored in a C++ GMP integer class.
* Using this instead of mpz_t allows for easier destruction.
*/
mpz_class d_value;
diff --git a/src/util/maybe.h b/src/util/maybe.h
index ed8c999a5..a3ba3c883 100644
--- a/src/util/maybe.h
+++ b/src/util/maybe.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/ostream_util.cpp b/src/util/ostream_util.cpp
index c8d81d363..c97238892 100644
--- a/src/util/ostream_util.cpp
+++ b/src/util/ostream_util.cpp
@@ -5,7 +5,7 @@
** Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/ostream_util.h b/src/util/ostream_util.h
index e58ff8443..b27c22819 100644
--- a/src/util/ostream_util.h
+++ b/src/util/ostream_util.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/poly_util.cpp b/src/util/poly_util.cpp
new file mode 100644
index 000000000..ad769b779
--- /dev/null
+++ b/src/util/poly_util.cpp
@@ -0,0 +1,365 @@
+/********************* */
+/*! \file poly_util.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utilities for working with LibPoly.
+ **
+ ** Utilities for working with LibPoly.
+ **/
+
+#include "poly_util.h"
+
+#ifdef CVC4_POLY_IMP
+
+#include <poly/polyxx.h>
+
+#include <map>
+
+#include "base/check.h"
+#include "maybe.h"
+#include "util/integer.h"
+#include "util/rational.h"
+#include "util/real_algebraic_number.h"
+
+namespace CVC4 {
+namespace poly_utils {
+
+namespace {
+/**
+ * Convert arbitrary data using a string as intermediary.
+ * Assumes the existence of operator<<(std::ostream&, const From&) and To(const
+ * std::string&); should be the last resort for type conversions: it may not
+ * only yield bad performance, but is also dependent on compatible string
+ * representations. Use with care!
+ */
+template <typename To, typename From>
+To cast_by_string(const From& f)
+{
+ std::stringstream s;
+ s << f;
+ return To(s.str());
+}
+} // namespace
+
+Integer toInteger(const poly::Integer& i)
+{
+ const mpz_class& gi = *poly::detail::cast_to_gmp(&i);
+#ifdef CVC4_GMP_IMP
+ return Integer(gi);
+#endif
+#ifdef CVC4_CLN_IMP
+ if (std::numeric_limits<long>::min() <= gi
+ && gi <= std::numeric_limits<long>::max())
+ {
+ return Integer(gi.get_si());
+ }
+ else
+ {
+ return cast_by_string<Integer, poly::Integer>(i);
+ }
+#endif
+}
+Rational toRational(const poly::Integer& i) { return Rational(toInteger(i)); }
+Rational toRational(const poly::Rational& r)
+{
+#ifdef CVC4_GMP_IMP
+ return Rational(*poly::detail::cast_to_gmp(&r));
+#endif
+#ifdef CVC4_CLN_IMP
+ return Rational(toInteger(numerator(r)), toInteger(denominator(r)));
+#endif
+}
+Rational toRational(const poly::DyadicRational& dr)
+{
+ return Rational(toInteger(numerator(dr)), toInteger(denominator(dr)));
+}
+Rational toRationalAbove(const poly::Value& v)
+{
+ if (is_algebraic_number(v))
+ {
+ return toRational(get_upper_bound(as_algebraic_number(v)));
+ }
+ else if (is_dyadic_rational(v))
+ {
+ return toRational(as_dyadic_rational(v));
+ }
+ else if (is_integer(v))
+ {
+ return toRational(as_integer(v));
+ }
+ else if (is_rational(v))
+ {
+ return toRational(as_rational(v));
+ }
+ Assert(false) << "Can not convert " << v << " to rational.";
+ return Rational();
+}
+Rational toRationalBelow(const poly::Value& v)
+{
+ if (is_algebraic_number(v))
+ {
+ return toRational(get_lower_bound(as_algebraic_number(v)));
+ }
+ else if (is_dyadic_rational(v))
+ {
+ return toRational(as_dyadic_rational(v));
+ }
+ else if (is_integer(v))
+ {
+ return toRational(as_integer(v));
+ }
+ else if (is_rational(v))
+ {
+ return toRational(as_rational(v));
+ }
+ Assert(false) << "Can not convert " << v << " to rational.";
+ return Rational();
+}
+
+poly::Integer toInteger(const Integer& i)
+{
+#ifdef CVC4_GMP_IMP
+ return poly::Integer(i.getValue());
+#endif
+#ifdef CVC4_CLN_IMP
+ if (std::numeric_limits<long>::min() <= i.getValue()
+ && i.getValue() <= std::numeric_limits<long>::max())
+ {
+ return poly::Integer(cln::cl_I_to_long(i.getValue()));
+ }
+ else
+ {
+ return poly::Integer(cast_by_string<mpz_class, Integer>(i));
+ }
+#endif
+}
+std::vector<poly::Integer> toInteger(const std::vector<Integer>& vi)
+{
+ std::vector<poly::Integer> res;
+ for (const auto& i : vi) res.emplace_back(toInteger(i));
+ return res;
+}
+poly::Rational toRational(const Rational& r)
+{
+#ifdef CVC4_GMP_IMP
+ return poly::Rational(r.getValue());
+#endif
+#ifdef CVC4_CLN_IMP
+ return poly::Rational(toInteger(r.getNumerator()),
+ toInteger(r.getDenominator()));
+#endif
+}
+
+Maybe<poly::DyadicRational> toDyadicRational(const Rational& r)
+{
+ Integer den = r.getDenominator();
+ if (den.isOne())
+ { // It's an integer anyway.
+ return poly::DyadicRational(toInteger(r.getNumerator()));
+ }
+ unsigned long exp = den.isPow2();
+ if (exp > 0)
+ {
+ // It's a dyadic rational.
+ return div_2exp(poly::DyadicRational(toInteger(r.getNumerator())), exp - 1);
+ }
+ return Maybe<poly::DyadicRational>();
+}
+
+Maybe<poly::DyadicRational> toDyadicRational(const poly::Rational& r)
+{
+ poly::Integer den = denominator(r);
+ if (den == poly::Integer(1))
+ { // It's an integer anyway.
+ return poly::DyadicRational(numerator(r));
+ }
+ // Use bit_size as an estimate for the dyadic exponent.
+ unsigned long size = bit_size(den) - 1;
+ if (mul_pow2(poly::Integer(1), size) == den)
+ {
+ // It's a dyadic rational.
+ return div_2exp(poly::DyadicRational(numerator(r)), size);
+ }
+ return Maybe<poly::DyadicRational>();
+}
+
+poly::Rational approximateToDyadic(const poly::Rational& r,
+ const poly::Rational& original)
+{
+ // Multiply both numerator and denominator by two.
+ // Increase or decrease the numerator, depending on whether r is too small or
+ // too large.
+ poly::Integer n = mul_pow2(numerator(r), 1);
+ if (r < original)
+ {
+ ++n;
+ }
+ else if (r > original)
+ {
+ --n;
+ }
+ return poly::Rational(n, mul_pow2(denominator(r), 1));
+}
+
+poly::AlgebraicNumber toPolyRanWithRefinement(poly::UPolynomial&& p,
+ const Rational& lower,
+ const Rational& upper)
+{
+ Maybe<poly::DyadicRational> ml = toDyadicRational(lower);
+ Maybe<poly::DyadicRational> mu = toDyadicRational(upper);
+ if (ml && mu)
+ {
+ return poly::AlgebraicNumber(std::move(p),
+ poly::DyadicInterval(ml.value(), mu.value()));
+ }
+ // The encoded real algebraic number did not have dyadic rational endpoints.
+ poly::Rational origl = toRational(lower);
+ poly::Rational origu = toRational(upper);
+ poly::Rational l(floor(origl));
+ poly::Rational u(ceil(origu));
+ poly::RationalInterval ri(l, u);
+ while (count_real_roots(p, ri) != 1)
+ {
+ l = approximateToDyadic(l, origl);
+ u = approximateToDyadic(u, origu);
+ ri = poly::RationalInterval(l, u);
+ }
+ Assert(count_real_roots(p, poly::RationalInterval(l, u)) == 1);
+ ml = toDyadicRational(l);
+ mu = toDyadicRational(u);
+ Assert(ml && mu) << "Both bounds should be dyadic by now.";
+ return poly::AlgebraicNumber(std::move(p),
+ poly::DyadicInterval(ml.value(), mu.value()));
+}
+
+RealAlgebraicNumber toRanWithRefinement(poly::UPolynomial&& p,
+ const Rational& lower,
+ const Rational& upper)
+{
+ return RealAlgebraicNumber(
+ toPolyRanWithRefinement(std::move(p), lower, upper));
+}
+
+std::size_t totalDegree(const poly::Polynomial& p)
+{
+ std::size_t tdeg = 0;
+
+ lp_polynomial_traverse_f f =
+ [](const lp_polynomial_context_t* ctx, lp_monomial_t* m, void* data) {
+ std::size_t sum = 0;
+ for (std::size_t i = 0; i < m->n; ++i)
+ {
+ sum += m->p[i].d;
+ }
+
+ std::size_t* td = static_cast<std::size_t*>(data);
+ *td = std::max(*td, sum);
+ };
+
+ lp_polynomial_traverse(p.get_internal(), f, &tdeg);
+
+ return tdeg;
+}
+
+std::ostream& operator<<(std::ostream& os, const VariableInformation& vi)
+{
+ if (vi.var == poly::Variable())
+ {
+ os << "Totals: ";
+ os << "max deg " << vi.max_degree;
+ os << ", sum term deg " << vi.sum_term_degree;
+ os << ", sum poly deg " << vi.sum_poly_degree;
+ os << ", num polys " << vi.num_polynomials;
+ os << ", num terms " << vi.num_terms;
+ }
+ else
+ {
+ os << "Info for " << vi.var << ": ";
+ os << "max deg " << vi.max_degree;
+ os << ", max lc deg: " << vi.max_lc_degree;
+ os << ", max term tdeg: " << vi.max_terms_tdegree;
+ os << ", sum term deg " << vi.sum_term_degree;
+ os << ", sum poly deg " << vi.sum_poly_degree;
+ os << ", num polys " << vi.num_polynomials;
+ os << ", num terms " << vi.num_terms;
+ }
+ return os;
+}
+
+struct GetVarInfo
+{
+ VariableInformation* info;
+ std::size_t cur_var_degree = 0;
+ std::size_t cur_lc_degree = 0;
+};
+void getVariableInformation(VariableInformation& vi,
+ const poly::Polynomial& poly)
+{
+ GetVarInfo varinfo;
+ varinfo.info = &vi;
+ lp_polynomial_traverse_f f =
+ [](const lp_polynomial_context_t* ctx, lp_monomial_t* m, void* data) {
+ GetVarInfo* gvi = static_cast<GetVarInfo*>(data);
+ VariableInformation* info = gvi->info;
+ // Total degree of this term
+ std::size_t tdeg = 0;
+ // Degree of this variable within this term
+ std::size_t vardeg = 0;
+ for (std::size_t i = 0; i < m->n; ++i)
+ {
+ tdeg += m->p[i].d;
+ if (m->p[i].x == info->var)
+ {
+ info->max_degree = std::max(info->max_degree, m->p[i].d);
+ info->sum_term_degree += m->p[i].d;
+ vardeg = m->p[i].d;
+ }
+ }
+ if (info->var == poly::Variable())
+ {
+ ++info->num_terms;
+ info->max_degree = std::max(info->max_degree, tdeg);
+ info->sum_term_degree += tdeg;
+ }
+ else if (vardeg > 0)
+ {
+ ++info->num_terms;
+ if (gvi->cur_var_degree < vardeg)
+ {
+ gvi->cur_lc_degree = tdeg - vardeg;
+ }
+ info->max_terms_tdegree = std::max(info->max_terms_tdegree, tdeg);
+ }
+ };
+ std::size_t tmp_max_degree = vi.max_degree;
+ std::size_t tmp_num_terms = vi.num_terms;
+ vi.max_degree = 0;
+ vi.num_terms = 0;
+ lp_polynomial_traverse(poly.get_internal(), f, &varinfo);
+ vi.max_lc_degree = std::max(vi.max_lc_degree, varinfo.cur_lc_degree);
+ if (vi.num_terms > 0)
+ {
+ ++vi.num_polynomials;
+ }
+ vi.sum_poly_degree += vi.max_degree;
+ vi.max_degree = std::max(vi.max_degree, tmp_max_degree);
+ vi.num_terms += tmp_num_terms;
+}
+
+} // namespace poly_utils
+} // namespace CVC4
+
+#endif
diff --git a/src/util/poly_util.h b/src/util/poly_util.h
new file mode 100644
index 000000000..2766f1957
--- /dev/null
+++ b/src/util/poly_util.h
@@ -0,0 +1,145 @@
+/********************* */
+/*! \file poly_util.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory) and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Utilities for working with LibPoly.
+ **
+ ** Utilities for working with LibPoly.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__POLY_UTIL_H
+#define CVC4__POLY_UTIL_H
+
+#include <vector>
+
+#include "maybe.h"
+#include "util/integer.h"
+#include "util/rational.h"
+#include "util/real_algebraic_number.h"
+
+#ifdef CVC4_POLY_IMP
+
+#include <poly/polyxx.h>
+
+namespace CVC4 {
+/**
+ * Utilities for working with libpoly.
+ * This namespace contains various basic conversion routines necessary for the
+ * integration of LibPoly. Firstly, LibPoly is based on GMP and hence we need
+ * conversion from and to CLN (in case CLN is enabled). Otherwise, conversion of
+ * number types mostly reduces to simple type casts.
+ * Furthermore, conversions between poly::Rational and poly::DyadicRational and
+ * constructors for algebraic numbers that need initial refinement of the
+ * interval are provided.
+ */
+namespace poly_utils {
+
+/** Converts a poly::Integer to a CVC4::Integer. */
+Integer toInteger(const poly::Integer& i);
+/** Converts a poly::Integer to a CVC4::Rational. */
+Rational toRational(const poly::Integer& r);
+/** Converts a poly::Rational to a CVC4::Rational. */
+Rational toRational(const poly::Rational& r);
+/** Converts a poly::DyadicRational to a CVC4::Rational. */
+Rational toRational(const poly::DyadicRational& dr);
+
+/** Converts a poly::Value to a CVC4::Rational (that may be a bit above). */
+Rational toRationalAbove(const poly::Value& v);
+/** Converts a poly::Value to a CVC4::Rational (that may be a bit below). */
+Rational toRationalBelow(const poly::Value& v);
+
+/** Converts a CVC4::Integer to a poly::Integer. */
+poly::Integer toInteger(const Integer& i);
+/** Converts a vector of CVC4::Integers to a vector of poly::Integers. */
+std::vector<poly::Integer> toInteger(const std::vector<Integer>& vi);
+/** Converts a CVC4::Rational to a poly::Rational. */
+poly::Rational toRational(const Rational& r);
+/**
+ * Converts a CVC4::Rational to a poly::DyadicRational. If the input is not
+ * dyadic, no result is produced.
+ */
+Maybe<poly::DyadicRational> toDyadicRational(const Rational& r);
+/**
+ * Converts a poly::Rational to a poly::DyadicRational. If the input is not
+ * dyadic, no result is produced.
+ */
+Maybe<poly::DyadicRational> toDyadicRational(const poly::Rational& r);
+
+/**
+ * Iteratively approximates a poly::Rational by a dyadic poly::Rational.
+ * Assuming that r is dyadic, makes one refinement step to move r closer to
+ * original.
+ * Assumes one starts with lower(original) or ceil(original) for r.
+ */
+poly::Rational approximateToDyadic(const poly::Rational& r,
+ const poly::Rational& original);
+
+/**
+ * Constructs a poly::AlgebraicNumber, allowing for refinement of the
+ * CVC4::Rational bounds. As a poly::AlgebraicNumber works on
+ * poly::DyadicRationals internally, the bounds are iteratively refined using
+ * approximateToDyadic until the respective interval is isolating. If the
+ * provided rational bounds are already dyadic, the refinement is skipped.
+ */
+poly::AlgebraicNumber toPolyRanWithRefinement(poly::UPolynomial&& p,
+ const Rational& lower,
+ const Rational& upper);
+
+/**
+ * Constructs a CVC4::RealAlgebraicNumber, simply wrapping
+ * toPolyRanWithRefinement.
+ */
+RealAlgebraicNumber toRanWithRefinement(poly::UPolynomial&& p,
+ const Rational& lower,
+ const Rational& upper);
+
+std::size_t totalDegree(const poly::Polynomial& p);
+
+/**
+ * Collects information about a single variable in a set of polynomials.
+ * Used for determining a variable ordering.
+ */
+struct VariableInformation
+{
+ poly::Variable var;
+ /** Maximum degree of this variable. */
+ std::size_t max_degree = 0;
+ /** Maximum degree of the leading coefficient of this variable. */
+ std::size_t max_lc_degree = 0;
+ /** Maximum of total degrees of terms that contain this variable. */
+ std::size_t max_terms_tdegree = 0;
+ /** Sum of degrees of this variable within all terms. */
+ std::size_t sum_term_degree = 0;
+ /** Sum of degrees of this variable within all polynomials. */
+ std::size_t sum_poly_degree = 0;
+ /** Number of polynomials that contain this variable. */
+ std::size_t num_polynomials = 0;
+ /** Number of terms that contain this variable. */
+ std::size_t num_terms = 0;
+};
+std::ostream& operator<<(std::ostream& os, const VariableInformation& vi);
+
+void getVariableInformation(VariableInformation& vi,
+ const poly::Polynomial& poly);
+
+} // namespace poly_utils
+} // namespace CVC4
+
+#endif
+
+#endif /* CVC4__POLY_UTIL_H */
diff --git a/src/util/proof.h b/src/util/proof.h
deleted file mode 100644
index c89a3b0a6..000000000
--- a/src/util/proof.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/********************* */
-/*! \file proof.h
- ** \verbatim
- ** Top contributors (to current version):
- ** Tim King, Morgan Deters, Mathias Preiner
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
- ** All rights reserved. See the file COPYING in the top-level source
- ** directory for licensing information.\endverbatim
- **
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#include "cvc4_public.h"
-
-#ifndef CVC4__PROOF_H
-#define CVC4__PROOF_H
-
-#include <iosfwd>
-#include <unordered_map>
-
-namespace CVC4 {
-
-class Expr;
-class ProofLetCount;
-struct ExprHashFunction;
-
-typedef std::unordered_map<Expr, ProofLetCount, ExprHashFunction> ProofLetMap;
-
-class CVC4_PUBLIC Proof
-{
- public:
- virtual ~Proof() {}
- virtual void toStream(std::ostream& out) const = 0;
- virtual void toStream(std::ostream& out, const ProofLetMap& map) const = 0;
-};/* class Proof */
-
-}/* CVC4 namespace */
-
-#endif /* CVC4__PROOF_H */
diff --git a/src/util/random.cpp b/src/util/random.cpp
index 89b8c0513..9efc436b3 100644
--- a/src/util/random.cpp
+++ b/src/util/random.cpp
@@ -5,7 +5,7 @@
** Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/random.h b/src/util/random.h
index 04bea1b69..e916317f5 100644
--- a/src/util/random.h
+++ b/src/util/random.h
@@ -5,7 +5,7 @@
** Aina Niemetz, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/rational.h.in b/src/util/rational.h.in
index b5934cc10..f1135c427 100644
--- a/src/util/rational.h.in
+++ b/src/util/rational.h.in
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/rational_cln_imp.cpp b/src/util/rational_cln_imp.cpp
index 2624698bc..6a66af0c7 100644
--- a/src/util/rational_cln_imp.cpp
+++ b/src/util/rational_cln_imp.cpp
@@ -5,7 +5,7 @@
** Tim King, Christopher L. Conway, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/rational_cln_imp.h b/src/util/rational_cln_imp.h
index 724698363..a0b35a39e 100644
--- a/src/util/rational_cln_imp.h
+++ b/src/util/rational_cln_imp.h
@@ -5,7 +5,7 @@
** Tim King, Gereon Kremer, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/rational_gmp_imp.cpp b/src/util/rational_gmp_imp.cpp
index a6442ac1f..8ff975eae 100644
--- a/src/util/rational_gmp_imp.cpp
+++ b/src/util/rational_gmp_imp.cpp
@@ -5,7 +5,7 @@
** Tim King, Christopher L. Conway, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/rational_gmp_imp.h b/src/util/rational_gmp_imp.h
index 6054cd793..f166d9cdc 100644
--- a/src/util/rational_gmp_imp.h
+++ b/src/util/rational_gmp_imp.h
@@ -5,7 +5,7 @@
** Tim King, Gereon Kremer, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -20,14 +20,8 @@
#ifndef CVC4__RATIONAL_H
#define CVC4__RATIONAL_H
-/*
- * Older versions of GMP in combination with newer versions of GCC and C++11
- * cause errors: https://gcc.gnu.org/gcc-4.9/porting_to.html
- * Including <cstddef> is a workaround for this issue.
- */
#include <gmp.h>
-#include <cstddef>
#include <string>
#include "base/exception.h"
diff --git a/src/util/real_algebraic_number.h.in b/src/util/real_algebraic_number.h.in
new file mode 100644
index 000000000..a4560cf53
--- /dev/null
+++ b/src/util/real_algebraic_number.h.in
@@ -0,0 +1,25 @@
+/********************* */
+/*! \file real_algebraic_number.h.in
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief A real algebraic number constant
+ **
+ ** A real algebraic number constant.
+ **/
+
+// these gestures are used to avoid a public header dependence on cvc4autoconfig.h
+
+#if /* use libpoly */ @CVC4_USE_POLY_IMP@
+# define CVC4_POLY_IMP
+#endif /* @CVC4_USE_POLY_IMP@ */
+
+#ifdef CVC4_POLY_IMP
+# include "util/real_algebraic_number_poly_imp.h"
+#endif /* CVC4_POLY_IMP */
diff --git a/src/util/real_algebraic_number_poly_imp.cpp b/src/util/real_algebraic_number_poly_imp.cpp
new file mode 100644
index 000000000..674850534
--- /dev/null
+++ b/src/util/real_algebraic_number_poly_imp.cpp
@@ -0,0 +1,175 @@
+/********************* */
+/*! \file real_algebraic_number_poly_imp.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Implementation of RealAlgebraicNumber based on libpoly.
+ **
+ ** Implementation of RealAlgebraicNumber based on libpoly.
+ **/
+
+#include "cvc4autoconfig.h"
+#include "util/real_algebraic_number.h"
+
+#ifndef CVC4_POLY_IMP // Make sure this comes after cvc4autoconfig.h
+#error "This source should only ever be built if CVC4_POLY_IMP is on!"
+#endif /* CVC4_POLY_IMP */
+
+#include <poly/polyxx.h>
+
+#include <limits>
+
+#include "base/check.h"
+#include "util/poly_util.h"
+
+namespace CVC4 {
+
+RealAlgebraicNumber::RealAlgebraicNumber(poly::AlgebraicNumber&& an)
+ : d_value(std::move(an))
+{
+}
+
+RealAlgebraicNumber::RealAlgebraicNumber(const Integer& i)
+ : d_value(poly::DyadicRational(poly_utils::toInteger(i)))
+{
+}
+
+RealAlgebraicNumber::RealAlgebraicNumber(const Rational& r)
+{
+ poly::Rational pr = poly_utils::toRational(r);
+ auto dr = poly_utils::toDyadicRational(r);
+ if (dr)
+ {
+ d_value = poly::AlgebraicNumber(dr.value());
+ }
+ else
+ {
+ d_value = poly::AlgebraicNumber(
+ poly::UPolynomial({numerator(pr), -denominator(pr)}),
+ poly::DyadicInterval(floor(pr), ceil(pr)));
+ }
+}
+
+RealAlgebraicNumber::RealAlgebraicNumber(const std::vector<long>& coefficients,
+ long lower,
+ long upper)
+{
+ for (long c : coefficients)
+ {
+ Assert(std::numeric_limits<std::int32_t>::min() <= c
+ && c <= std::numeric_limits<std::int32_t>::max())
+ << "Coefficients need to fit within 32 bit integers. Please use the "
+ "constructor based on Integer instead.";
+ }
+ d_value = poly::AlgebraicNumber(poly::UPolynomial(coefficients),
+ poly::DyadicInterval(lower, upper));
+}
+
+RealAlgebraicNumber::RealAlgebraicNumber(
+ const std::vector<Integer>& coefficients,
+ const Rational& lower,
+ const Rational& upper)
+{
+ *this = poly_utils::toRanWithRefinement(
+ poly::UPolynomial(poly_utils::toInteger(coefficients)), lower, upper);
+}
+RealAlgebraicNumber::RealAlgebraicNumber(
+ const std::vector<Rational>& coefficients,
+ const Rational& lower,
+ const Rational& upper)
+{
+ Integer factor = Integer(1);
+ for (const auto& c : coefficients)
+ {
+ factor = factor.lcm(c.getDenominator());
+ }
+ std::vector<poly::Integer> coeffs;
+ for (const auto& c : coefficients)
+ {
+ Assert((c * factor).getDenominator() == Integer(1));
+ coeffs.emplace_back(poly_utils::toInteger((c * factor).getNumerator()));
+ }
+ *this = poly_utils::toRanWithRefinement(
+ poly::UPolynomial(std::move(coeffs)), lower, upper);
+}
+
+std::ostream& operator<<(std::ostream& os, const RealAlgebraicNumber& ran)
+{
+ return os << ran.getValue();
+}
+
+bool operator==(const RealAlgebraicNumber& lhs, const RealAlgebraicNumber& rhs)
+{
+ return lhs.getValue() == rhs.getValue();
+}
+bool operator!=(const RealAlgebraicNumber& lhs, const RealAlgebraicNumber& rhs)
+{
+ return lhs.getValue() != rhs.getValue();
+}
+bool operator<(const RealAlgebraicNumber& lhs, const RealAlgebraicNumber& rhs)
+{
+ return lhs.getValue() < rhs.getValue();
+}
+bool operator<=(const RealAlgebraicNumber& lhs, const RealAlgebraicNumber& rhs)
+{
+ return lhs.getValue() <= rhs.getValue();
+}
+bool operator>(const RealAlgebraicNumber& lhs, const RealAlgebraicNumber& rhs)
+{
+ return lhs.getValue() > rhs.getValue();
+}
+bool operator>=(const RealAlgebraicNumber& lhs, const RealAlgebraicNumber& rhs)
+{
+ return lhs.getValue() >= rhs.getValue();
+}
+
+RealAlgebraicNumber operator+(const RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs)
+{
+ return lhs.getValue() + rhs.getValue();
+}
+RealAlgebraicNumber operator-(const RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs)
+{
+ return lhs.getValue() - rhs.getValue();
+}
+RealAlgebraicNumber operator-(const RealAlgebraicNumber& ran)
+{
+ return -ran.getValue();
+}
+RealAlgebraicNumber operator*(const RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs)
+{
+ return lhs.getValue() * rhs.getValue();
+}
+
+RealAlgebraicNumber& operator+=(RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs)
+{
+ lhs.getValue() = lhs.getValue() + rhs.getValue();
+ return lhs;
+}
+RealAlgebraicNumber& operator-=(RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs)
+{
+ lhs.getValue() = lhs.getValue() - rhs.getValue();
+ return lhs;
+}
+RealAlgebraicNumber& operator*=(RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs)
+{
+ lhs.getValue() = lhs.getValue() * rhs.getValue();
+ return lhs;
+}
+
+int sgn(const RealAlgebraicNumber& ran) { return sgn(ran.getValue()); }
+bool isZero(const RealAlgebraicNumber& ran) { return is_zero(ran.getValue()); }
+bool isOne(const RealAlgebraicNumber& ran) { return is_one(ran.getValue()); }
+
+} // namespace CVC4
diff --git a/src/util/real_algebraic_number_poly_imp.h b/src/util/real_algebraic_number_poly_imp.h
new file mode 100644
index 000000000..bbc36e81c
--- /dev/null
+++ b/src/util/real_algebraic_number_poly_imp.h
@@ -0,0 +1,160 @@
+/********************* */
+/*! \file real_algebraic_number_poly_imp.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Gereon Kremer
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief Algebraic number constants; wraps a libpoly algebraic number.
+ **
+ ** Algebraic number constants; wraps a libpoly algebraic number.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef CVC4__REAL_ALGEBRAIC_NUMBER_H
+#define CVC4__REAL_ALGEBRAIC_NUMBER_H
+
+#include <vector>
+
+#include <poly/polyxx.h>
+
+#include "util/integer.h"
+#include "util/rational.h"
+
+namespace CVC4 {
+
+/**
+ * Represents a real algebraic number based on poly::AlgebraicNumber.
+ * This real algebraic number is represented by a (univariate) polynomial and an
+ * isolating interval. The interval contains exactly one real root of the
+ * polynomial, which is the number the real algebraic number as a whole
+ * represents.
+ * This representation can hold rationals (where the interval can be a point
+ * interval and the polynomial is omitted), an irrational algebraic number (like
+ * square roots), but no trancendentals (like pi).
+ * Note that the interval representation uses dyadic rationals (denominators are
+ * only powers of two).
+ */
+class CVC4_PUBLIC RealAlgebraicNumber
+{
+ public:
+ /** Construct as zero. */
+ RealAlgebraicNumber() = default;
+ /** Move from a poly::AlgebraicNumber type. */
+ RealAlgebraicNumber(poly::AlgebraicNumber&& an);
+ /** Copy from an Integer. */
+ RealAlgebraicNumber(const Integer& i);
+ /** Copy from a Rational. */
+ RealAlgebraicNumber(const Rational& r);
+ /**
+ * Construct from a polynomial with the given coefficients and an open
+ * interval with the given bounds.
+ */
+ RealAlgebraicNumber(const std::vector<long>& coefficients,
+ long lower,
+ long upper);
+ /**
+ * Construct from a polynomial with the given coefficients and an open
+ * interval with the given bounds. If the bounds are not dyadic, we need to
+ * perform refinement to find a suitable dyadic interval.
+ * See poly_utils::toRanWithRefinement for more details.
+ */
+ RealAlgebraicNumber(const std::vector<Integer>& coefficients,
+ const Rational& lower,
+ const Rational& upper);
+ /**
+ * Construct from a polynomial with the given coefficients and an open
+ * interval with the given bounds. If the bounds are not dyadic, we need to
+ * perform refinement to find a suitable dyadic interval.
+ * See poly_utils::toRanWithRefinement for more details.
+ */
+ RealAlgebraicNumber(const std::vector<Rational>& coefficients,
+ const Rational& lower,
+ const Rational& upper);
+
+ /** Copy constructor. */
+ RealAlgebraicNumber(const RealAlgebraicNumber& ran) = default;
+ /** Move constructor. */
+ RealAlgebraicNumber(RealAlgebraicNumber&& ran) = default;
+
+ /** Default destructor. */
+ ~RealAlgebraicNumber() = default;
+
+ /** Copy assignment. */
+ RealAlgebraicNumber& operator=(const RealAlgebraicNumber& ran) = default;
+ /** Move assignment. */
+ RealAlgebraicNumber& operator=(RealAlgebraicNumber&& ran) = default;
+
+ /** Get the internal value as a const reference. */
+ const poly::AlgebraicNumber& getValue() const { return d_value; }
+ /** Get the internal value as a non-const reference. */
+ poly::AlgebraicNumber& getValue() { return d_value; }
+
+ private:
+ /**
+ * Stores the actual real algebraic number.
+ */
+ poly::AlgebraicNumber d_value;
+}; /* class RealAlgebraicNumber */
+
+/** Stream a real algebraic number to an output stream. */
+CVC4_PUBLIC std::ostream& operator<<(std::ostream& os,
+ const RealAlgebraicNumber& ran);
+
+/** Compare two real algebraic numbers. */
+CVC4_PUBLIC bool operator==(const RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs);
+/** Compare two real algebraic numbers. */
+CVC4_PUBLIC bool operator!=(const RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs);
+/** Compare two real algebraic numbers. */
+CVC4_PUBLIC bool operator<(const RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs);
+/** Compare two real algebraic numbers. */
+CVC4_PUBLIC bool operator<=(const RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs);
+/** Compare two real algebraic numbers. */
+CVC4_PUBLIC bool operator>(const RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs);
+/** Compare two real algebraic numbers. */
+CVC4_PUBLIC bool operator>=(const RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs);
+
+/** Add two real algebraic numbers. */
+CVC4_PUBLIC RealAlgebraicNumber operator+(const RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs);
+/** Subtract two real algebraic numbers. */
+CVC4_PUBLIC RealAlgebraicNumber operator-(const RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs);
+/** Negate a real algebraic number. */
+CVC4_PUBLIC RealAlgebraicNumber operator-(const RealAlgebraicNumber& ran);
+/** Multiply two real algebraic numbers. */
+CVC4_PUBLIC RealAlgebraicNumber operator*(const RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs);
+
+/** Add and assign two real algebraic numbers. */
+CVC4_PUBLIC RealAlgebraicNumber& operator+=(RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs);
+/** Subtract and assign two real algebraic numbers. */
+CVC4_PUBLIC RealAlgebraicNumber& operator-=(RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs);
+/** Multiply and assign two real algebraic numbers. */
+CVC4_PUBLIC RealAlgebraicNumber& operator*=(RealAlgebraicNumber& lhs,
+ const RealAlgebraicNumber& rhs);
+
+/** Compute the sign of a real algebraic number. */
+CVC4_PUBLIC int sgn(const RealAlgebraicNumber& ran);
+
+/** Check whether a real algebraic number is zero. */
+CVC4_PUBLIC bool isZero(const RealAlgebraicNumber& ran);
+/** Check whether a real algebraic number is one. */
+CVC4_PUBLIC bool isOne(const RealAlgebraicNumber& ran);
+
+} // namespace CVC4
+
+#endif /* CVC4__REAL_ALGEBRAIC_NUMBER_H */
diff --git a/src/util/regexp.cpp b/src/util/regexp.cpp
index be1459865..2e673698e 100644
--- a/src/util/regexp.cpp
+++ b/src/util/regexp.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/regexp.h b/src/util/regexp.h
index 180bb0c32..42c1b39d5 100644
--- a/src/util/regexp.h
+++ b/src/util/regexp.h
@@ -5,7 +5,7 @@
** Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -17,7 +17,6 @@
#ifndef CVC4__UTIL__REGEXP_H
#define CVC4__UTIL__REGEXP_H
-#include <cstdint>
#include <iosfwd>
namespace CVC4 {
diff --git a/src/util/resource_manager.cpp b/src/util/resource_manager.cpp
index eddf9e5c9..9afa79ef0 100644
--- a/src/util/resource_manager.cpp
+++ b/src/util/resource_manager.cpp
@@ -2,10 +2,10 @@
/*! \file resource_manager.cpp
** \verbatim
** Top contributors (to current version):
- ** Liana Hadarean, Mathias Preiner, Tim King
+ ** Mathias Preiner, Gereon Kremer, Liana Hadarean
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -25,93 +25,59 @@ using namespace std;
namespace CVC4 {
-void Timer::set(uint64_t millis, bool wallTime) {
- d_ms = millis;
- Trace("limit") << "Timer::set(" << d_ms << ")" << std::endl;
- // keep track of when it was set, even if it's disabled (i.e. == 0)
- d_wall_time = wallTime;
- if (d_wall_time) {
- // Wall time
- gettimeofday(&d_wall_limit, NULL);
- Trace("limit") << "Timer::set(): it's " << d_wall_limit.tv_sec << "," << d_wall_limit.tv_usec << std::endl;
- d_wall_limit.tv_sec += millis / 1000;
- d_wall_limit.tv_usec += (millis % 1000) * 1000;
- if(d_wall_limit.tv_usec > 1000000) {
- ++d_wall_limit.tv_sec;
- d_wall_limit.tv_usec -= 1000000;
- }
- Trace("limit") << "Timer::set(): limit is at " << d_wall_limit.tv_sec << "," << d_wall_limit.tv_usec << std::endl;
- } else {
- // CPU time
- d_cpu_start_time = ((double)clock())/(CLOCKS_PER_SEC *0.001);
- d_cpu_limit = d_cpu_start_time + d_ms;
- }
-}
-
-/** Return the milliseconds elapsed since last set(). */
-uint64_t Timer::elapsedWall() const {
- Assert(d_wall_time);
- timeval tv;
- gettimeofday(&tv, NULL);
- Trace("limit") << "Timer::elapsedWallTime(): it's now " << tv.tv_sec << "," << tv.tv_usec << std::endl;
- tv.tv_sec -= d_wall_limit.tv_sec - d_ms / 1000;
- tv.tv_usec -= d_wall_limit.tv_usec - (d_ms % 1000) * 1000;
- Trace("limit") << "Timer::elapsedWallTime(): elapsed time is " << tv.tv_sec << "," << tv.tv_usec << std::endl;
- return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+bool WallClockTimer::on() const
+{
+ // default-constructed time points are at the respective epoch
+ return d_limit.time_since_epoch().count() != 0;
}
-
-uint64_t Timer::elapsedCPU() const {
- Assert(!d_wall_time);
- clock_t elapsed = ((double)clock())/(CLOCKS_PER_SEC *0.001)- d_cpu_start_time;
- Trace("limit") << "Timer::elapsedCPUTime(): elapsed time is " << elapsed << " ms" <<std::endl;
- return elapsed;
+void WallClockTimer::set(uint64_t millis)
+{
+ if (millis == 0)
+ {
+ // reset / deactivate
+ d_start = time_point();
+ d_limit = time_point();
+ }
+ else
+ {
+ // set to now() + millis
+ d_start = clock::now();
+ d_limit = d_start + std::chrono::milliseconds(millis);
+ }
}
-
-uint64_t Timer::elapsed() const {
- if (d_wall_time)
- return elapsedWall();
- return elapsedCPU();
+uint64_t WallClockTimer::elapsed() const
+{
+ if (!on()) return 0;
+ // now() - d_start casted to milliseconds
+ return std::chrono::duration_cast<std::chrono::milliseconds>(clock::now()
+ - d_start)
+ .count();
}
-
-bool Timer::expired() const {
+bool WallClockTimer::expired() const
+{
+ // whether d_limit is in the past
if (!on()) return false;
-
- if (d_wall_time) {
- timeval tv;
- gettimeofday(&tv, NULL);
- Debug("limit") << "Timer::expired(): current wall time is " << tv.tv_sec << "," << tv.tv_usec << std::endl;
- Debug("limit") << "Timer::expired(): limit wall time is " << d_wall_limit.tv_sec << "," << d_wall_limit.tv_usec << std::endl;
- if(d_wall_limit.tv_sec < tv.tv_sec ||
- (d_wall_limit.tv_sec == tv.tv_sec && d_wall_limit.tv_usec <= tv.tv_usec)) {
- Debug("limit") << "Timer::expired(): OVER LIMIT!" << std::endl;
- return true;
- }
- Debug("limit") << "Timer::expired(): within limit" << std::endl;
- return false;
- }
-
- // cpu time
- double current = ((double)clock())/(CLOCKS_PER_SEC*0.001);
- Debug("limit") << "Timer::expired(): current cpu time is " << current << std::endl;
- Debug("limit") << "Timer::expired(): limit cpu time is " << d_cpu_limit << std::endl;
- if (current >= d_cpu_limit) {
- Debug("limit") << "Timer::expired(): OVER LIMIT!" << current << std::endl;
- return true;
- }
- return false;
+ return d_limit <= clock::now();
}
/*---------------------------------------------------------------------------*/
struct ResourceManager::Statistics
{
+ ReferenceStat<std::uint64_t> d_resourceUnitsUsed;
+ IntStat d_spendResourceCalls;
+ IntStat d_numArithPivotStep;
+ IntStat d_numArithNlLemmaStep;
IntStat d_numBitblastStep;
IntStat d_numBvEagerAssertStep;
IntStat d_numBvPropagationStep;
IntStat d_numBvSatConflictsStep;
+ IntStat d_numBvSatPropagateStep;
+ IntStat d_numBvSatSimplifyStep;
IntStat d_numCnfStep;
IntStat d_numDecisionStep;
IntStat d_numLemmaStep;
+ IntStat d_numNewSkolemStep;
IntStat d_numParseStep;
IntStat d_numPreprocessStep;
IntStat d_numQuantifierStep;
@@ -127,13 +93,20 @@ struct ResourceManager::Statistics
};
ResourceManager::Statistics::Statistics(StatisticsRegistry& stats)
- : d_numBitblastStep("resource::BitblastStep", 0),
+ : d_resourceUnitsUsed("resource::resourceUnitsUsed"),
+ d_spendResourceCalls("resource::spendResourceCalls", 0),
+ d_numArithPivotStep("resource::ArithPivotStep", 0),
+ d_numArithNlLemmaStep("resource::ArithNlLemmaStep", 0),
+ d_numBitblastStep("resource::BitblastStep", 0),
d_numBvEagerAssertStep("resource::BvEagerAssertStep", 0),
d_numBvPropagationStep("resource::BvPropagationStep", 0),
d_numBvSatConflictsStep("resource::BvSatConflictsStep", 0),
+ d_numBvSatPropagateStep("resource::BvSatPropagateStep", 0),
+ d_numBvSatSimplifyStep("resource::BvSatSimplifyStep", 0),
d_numCnfStep("resource::CnfStep", 0),
d_numDecisionStep("resource::DecisionStep", 0),
d_numLemmaStep("resource::LemmaStep", 0),
+ d_numNewSkolemStep("resource::NewSkolemStep", 0),
d_numParseStep("resource::ParseStep", 0),
d_numPreprocessStep("resource::PreprocessStep", 0),
d_numQuantifierStep("resource::QuantifierStep", 0),
@@ -143,13 +116,20 @@ ResourceManager::Statistics::Statistics(StatisticsRegistry& stats)
d_numTheoryCheckStep("resource::TheoryCheckStep", 0),
d_statisticsRegistry(stats)
{
+ d_statisticsRegistry.registerStat(&d_resourceUnitsUsed);
+ d_statisticsRegistry.registerStat(&d_spendResourceCalls);
+ d_statisticsRegistry.registerStat(&d_numArithPivotStep);
+ d_statisticsRegistry.registerStat(&d_numArithNlLemmaStep);
d_statisticsRegistry.registerStat(&d_numBitblastStep);
d_statisticsRegistry.registerStat(&d_numBvEagerAssertStep);
d_statisticsRegistry.registerStat(&d_numBvPropagationStep);
d_statisticsRegistry.registerStat(&d_numBvSatConflictsStep);
+ d_statisticsRegistry.registerStat(&d_numBvSatPropagateStep);
+ d_statisticsRegistry.registerStat(&d_numBvSatSimplifyStep);
d_statisticsRegistry.registerStat(&d_numCnfStep);
d_statisticsRegistry.registerStat(&d_numDecisionStep);
d_statisticsRegistry.registerStat(&d_numLemmaStep);
+ d_statisticsRegistry.registerStat(&d_numNewSkolemStep);
d_statisticsRegistry.registerStat(&d_numParseStep);
d_statisticsRegistry.registerStat(&d_numPreprocessStep);
d_statisticsRegistry.registerStat(&d_numQuantifierStep);
@@ -161,13 +141,20 @@ ResourceManager::Statistics::Statistics(StatisticsRegistry& stats)
ResourceManager::Statistics::~Statistics()
{
+ d_statisticsRegistry.unregisterStat(&d_resourceUnitsUsed);
+ d_statisticsRegistry.unregisterStat(&d_spendResourceCalls);
+ d_statisticsRegistry.unregisterStat(&d_numArithPivotStep);
+ d_statisticsRegistry.unregisterStat(&d_numArithNlLemmaStep);
d_statisticsRegistry.unregisterStat(&d_numBitblastStep);
d_statisticsRegistry.unregisterStat(&d_numBvEagerAssertStep);
d_statisticsRegistry.unregisterStat(&d_numBvPropagationStep);
d_statisticsRegistry.unregisterStat(&d_numBvSatConflictsStep);
+ d_statisticsRegistry.unregisterStat(&d_numBvSatPropagateStep);
+ d_statisticsRegistry.unregisterStat(&d_numBvSatSimplifyStep);
d_statisticsRegistry.unregisterStat(&d_numCnfStep);
d_statisticsRegistry.unregisterStat(&d_numDecisionStep);
d_statisticsRegistry.unregisterStat(&d_numLemmaStep);
+ d_statisticsRegistry.unregisterStat(&d_numNewSkolemStep);
d_statisticsRegistry.unregisterStat(&d_numParseStep);
d_statisticsRegistry.unregisterStat(&d_numPreprocessStep);
d_statisticsRegistry.unregisterStat(&d_numQuantifierStep);
@@ -179,106 +166,89 @@ ResourceManager::Statistics::~Statistics()
/*---------------------------------------------------------------------------*/
-const uint64_t ResourceManager::s_resourceCount = 1000;
-
ResourceManager::ResourceManager(StatisticsRegistry& stats, Options& options)
- : d_cumulativeTimer(),
- d_perCallTimer(),
- d_timeBudgetCumulative(0),
+ : d_perCallTimer(),
d_timeBudgetPerCall(0),
d_resourceBudgetCumulative(0),
d_resourceBudgetPerCall(0),
d_cumulativeTimeUsed(0),
d_cumulativeResourceUsed(0),
d_thisCallResourceUsed(0),
- d_thisCallTimeBudget(0),
d_thisCallResourceBudget(0),
- d_isHardLimit(),
d_on(false),
- d_cpuTime(false),
- d_spendResourceCalls(0),
- d_hardListeners(),
- d_softListeners(),
d_statistics(new ResourceManager::Statistics(stats)),
d_options(options)
-{}
+{
+ d_statistics->d_resourceUnitsUsed.setData(d_cumulativeResourceUsed);
+}
ResourceManager::~ResourceManager() {}
-void ResourceManager::setResourceLimit(uint64_t units, bool cumulative) {
+void ResourceManager::setResourceLimit(uint64_t units, bool cumulative)
+{
d_on = true;
- if(cumulative) {
- Trace("limit") << "ResourceManager: setting cumulative resource limit to " << units << endl;
- d_resourceBudgetCumulative = (units == 0) ? 0 : (d_cumulativeResourceUsed + units);
+ if (cumulative)
+ {
+ Trace("limit") << "ResourceManager: setting cumulative resource limit to "
+ << units << endl;
+ d_resourceBudgetCumulative =
+ (units == 0) ? 0 : (d_cumulativeResourceUsed + units);
d_thisCallResourceBudget = d_resourceBudgetCumulative;
- } else {
- Trace("limit") << "ResourceManager: setting per-call resource limit to " << units << endl;
+ }
+ else
+ {
+ Trace("limit") << "ResourceManager: setting per-call resource limit to "
+ << units << endl;
d_resourceBudgetPerCall = units;
}
}
-void ResourceManager::setTimeLimit(uint64_t millis, bool cumulative) {
+void ResourceManager::setTimeLimit(uint64_t millis)
+{
d_on = true;
- if(cumulative) {
- Trace("limit") << "ResourceManager: setting cumulative time limit to " << millis << " ms" << endl;
- d_timeBudgetCumulative = (millis == 0) ? 0 : (d_cumulativeTimeUsed + millis);
- d_cumulativeTimer.set(millis, !d_cpuTime);
- } else {
- Trace("limit") << "ResourceManager: setting per-call time limit to " << millis << " ms" << endl;
- d_timeBudgetPerCall = millis;
- // perCall timer will be set in beginCall
- }
-
+ Trace("limit") << "ResourceManager: setting per-call time limit to " << millis
+ << " ms" << endl;
+ d_timeBudgetPerCall = millis;
+ // perCall timer will be set in beginCall
}
-const uint64_t& ResourceManager::getResourceUsage() const {
+uint64_t ResourceManager::getResourceUsage() const
+{
return d_cumulativeResourceUsed;
}
-uint64_t ResourceManager::getTimeUsage() const {
- if (d_timeBudgetCumulative) {
- return d_cumulativeTimer.elapsed();
- }
- return d_cumulativeTimeUsed;
-}
-
-uint64_t ResourceManager::getResourceRemaining() const {
- if (d_thisCallResourceBudget <= d_thisCallResourceUsed)
- return 0;
- return d_thisCallResourceBudget - d_thisCallResourceUsed;
-}
+uint64_t ResourceManager::getTimeUsage() const { return d_cumulativeTimeUsed; }
-uint64_t ResourceManager::getTimeRemaining() const {
- uint64_t time_passed = d_cumulativeTimer.elapsed();
- if (time_passed >= d_thisCallTimeBudget)
- return 0;
- return d_thisCallTimeBudget - time_passed;
+uint64_t ResourceManager::getResourceRemaining() const
+{
+ if (d_resourceBudgetCumulative <= d_cumulativeResourceUsed) return 0;
+ return d_resourceBudgetCumulative - d_cumulativeResourceUsed;
}
void ResourceManager::spendResource(unsigned amount)
{
- ++d_spendResourceCalls;
+ ++d_statistics->d_spendResourceCalls;
d_cumulativeResourceUsed += amount;
if (!d_on) return;
Debug("limit") << "ResourceManager::spendResource()" << std::endl;
d_thisCallResourceUsed += amount;
- if(out()) {
+ if (out())
+ {
Trace("limit") << "ResourceManager::spendResource: interrupt!" << std::endl;
- Trace("limit") << " on call " << d_spendResourceCalls << std::endl;
- if (outOfTime()) {
+ Trace("limit") << " on call "
+ << d_statistics->d_spendResourceCalls.getData() << std::endl;
+ if (outOfTime())
+ {
Trace("limit") << "ResourceManager::spendResource: elapsed time"
- << d_cumulativeTimer.elapsed() << std::endl;
+ << d_perCallTimer.elapsed() << std::endl;
}
- if (d_isHardLimit) {
- d_hardListeners.notify();
- throw UnsafeInterruptException();
- } else {
- d_softListeners.notify();
+ for (Listener* l : d_listeners)
+ {
+ l->notify();
}
-
}
}
@@ -287,6 +257,14 @@ void ResourceManager::spendResource(Resource r)
uint32_t amount = 0;
switch (r)
{
+ case Resource::ArithPivotStep:
+ amount = d_options[options::arithPivotStep];
+ ++d_statistics->d_numArithPivotStep;
+ break;
+ case Resource::ArithNlLemmaStep:
+ amount = d_options[options::arithNlLemmaStep];
+ ++d_statistics->d_numArithNlLemmaStep;
+ break;
case Resource::BitblastStep:
amount = d_options[options::bitblastStep];
++d_statistics->d_numBitblastStep;
@@ -303,6 +281,14 @@ void ResourceManager::spendResource(Resource r)
amount = d_options[options::bvSatConflictStep];
++d_statistics->d_numBvSatConflictsStep;
break;
+ case Resource::BvSatPropagateStep:
+ amount = d_options[options::bvSatPropagateStep];
+ ++d_statistics->d_numBvSatPropagateStep;
+ break;
+ case Resource::BvSatSimplifyStep:
+ amount = d_options[options::bvSatSimplifyStep];
+ ++d_statistics->d_numBvSatSimplifyStep;
+ break;
case Resource::CnfStep:
amount = d_options[options::cnfStep];
++d_statistics->d_numCnfStep;
@@ -315,6 +301,10 @@ void ResourceManager::spendResource(Resource r)
amount = d_options[options::lemmaStep];
++d_statistics->d_numLemmaStep;
break;
+ case Resource::NewSkolemStep:
+ amount = d_options[options::newSkolemStep];
+ ++d_statistics->d_numNewSkolemStep;
+ break;
case Resource::ParseStep:
amount = d_options[options::parseStep];
++d_statistics->d_numParseStep;
@@ -348,101 +338,81 @@ void ResourceManager::spendResource(Resource r)
spendResource(amount);
}
-void ResourceManager::beginCall() {
-
- d_perCallTimer.set(d_timeBudgetPerCall, !d_cpuTime);
+void ResourceManager::beginCall()
+{
+ d_perCallTimer.set(d_timeBudgetPerCall);
d_thisCallResourceUsed = 0;
if (!d_on) return;
- if (cumulativeLimitOn()) {
- if (d_resourceBudgetCumulative) {
- d_thisCallResourceBudget = d_resourceBudgetCumulative <= d_cumulativeResourceUsed ? 0 :
- d_resourceBudgetCumulative - d_cumulativeResourceUsed;
- }
-
- if (d_timeBudgetCumulative) {
- AlwaysAssert(d_cumulativeTimer.on());
- // timer was on since the option was set
- d_cumulativeTimeUsed = d_cumulativeTimer.elapsed();
- d_thisCallTimeBudget = d_timeBudgetCumulative <= d_cumulativeTimeUsed? 0 :
- d_timeBudgetCumulative - d_cumulativeTimeUsed;
- d_cumulativeTimer.set(d_thisCallTimeBudget, d_cpuTime);
- }
- // we are out of resources so we shouldn't update the
- // budget for this call to the per call budget
- if (d_thisCallTimeBudget == 0 ||
- d_thisCallResourceUsed == 0)
- return;
+ if (d_resourceBudgetCumulative > 0)
+ {
+ // Compute remaining cumulative resource budget
+ d_thisCallResourceBudget =
+ d_resourceBudgetCumulative - d_cumulativeResourceUsed;
}
-
- if (perCallLimitOn()) {
- // take min of what's left and per-call budget
- if (d_resourceBudgetPerCall) {
- d_thisCallResourceBudget = d_thisCallResourceBudget < d_resourceBudgetPerCall && d_thisCallResourceBudget != 0 ? d_thisCallResourceBudget : d_resourceBudgetPerCall;
- }
-
- if (d_timeBudgetPerCall) {
- d_thisCallTimeBudget = d_thisCallTimeBudget < d_timeBudgetPerCall && d_thisCallTimeBudget != 0 ? d_thisCallTimeBudget : d_timeBudgetPerCall;
+ if (d_resourceBudgetPerCall > 0)
+ {
+ // Check if per-call resource budget is even smaller
+ if (d_resourceBudgetPerCall < d_thisCallResourceBudget)
+ {
+ d_thisCallResourceBudget = d_resourceBudgetPerCall;
}
}
}
-void ResourceManager::endCall() {
- uint64_t usedInCall = d_perCallTimer.elapsed();
+void ResourceManager::endCall()
+{
+ d_cumulativeTimeUsed += d_perCallTimer.elapsed();
d_perCallTimer.set(0);
- d_cumulativeTimeUsed += usedInCall;
-}
-
-bool ResourceManager::cumulativeLimitOn() const {
- return d_timeBudgetCumulative || d_resourceBudgetCumulative;
-}
-
-bool ResourceManager::perCallLimitOn() const {
- return d_timeBudgetPerCall || d_resourceBudgetPerCall;
-}
-
-bool ResourceManager::outOfResources() const {
- // resource limiting not enabled
- if (d_resourceBudgetPerCall == 0 &&
- d_resourceBudgetCumulative == 0)
- return false;
-
- return getResourceRemaining() == 0;
+ d_thisCallResourceUsed = 0;
}
-bool ResourceManager::outOfTime() const {
- if (d_timeBudgetPerCall == 0 &&
- d_timeBudgetCumulative == 0)
- return false;
-
- return d_cumulativeTimer.expired() || d_perCallTimer.expired();
+bool ResourceManager::cumulativeLimitOn() const
+{
+ return d_resourceBudgetCumulative > 0;
}
-void ResourceManager::useCPUTime(bool cpu) {
- Trace("limit") << "ResourceManager::useCPUTime("<< cpu <<")\n";
- d_cpuTime = cpu;
+bool ResourceManager::perCallLimitOn() const
+{
+ return (d_timeBudgetPerCall > 0) || (d_resourceBudgetPerCall > 0);
}
-void ResourceManager::setHardLimit(bool value) {
- Trace("limit") << "ResourceManager::setHardLimit("<< value <<")\n";
- d_isHardLimit = value;
+bool ResourceManager::outOfResources() const
+{
+ if (d_resourceBudgetPerCall > 0)
+ {
+ // Check if per-call resources are exhausted
+ if (d_thisCallResourceUsed >= d_resourceBudgetPerCall)
+ {
+ return true;
+ }
+ }
+ if (d_resourceBudgetCumulative > 0)
+ {
+ // Check if cumulative resources are exhausted
+ if (d_cumulativeResourceUsed >= d_resourceBudgetCumulative)
+ {
+ return true;
+ }
+ }
+ return false;
}
-void ResourceManager::enable(bool on) {
- Trace("limit") << "ResourceManager::enable("<< on <<")\n";
- d_on = on;
+bool ResourceManager::outOfTime() const
+{
+ if (d_timeBudgetPerCall == 0) return false;
+ return d_perCallTimer.expired();
}
-ListenerCollection::Registration* ResourceManager::registerHardListener(
- Listener* listener)
+void ResourceManager::enable(bool on)
{
- return d_hardListeners.registerListener(listener);
+ Trace("limit") << "ResourceManager::enable(" << on << ")\n";
+ d_on = on;
}
-ListenerCollection::Registration* ResourceManager::registerSoftListener(
- Listener* listener)
+void ResourceManager::registerListener(Listener* listener)
{
- return d_softListeners.registerListener(listener);
+ return d_listeners.push_back(listener);
}
} /* namespace CVC4 */
diff --git a/src/util/resource_manager.h b/src/util/resource_manager.h
index 39fceb7ec..3be99021b 100644
--- a/src/util/resource_manager.h
+++ b/src/util/resource_manager.h
@@ -2,18 +2,19 @@
/*! \file resource_manager.h
** \verbatim
** Top contributors (to current version):
- ** Tim King, Liana Hadarean, Morgan Deters
+ ** Gereon Kremer, Mathias Preiner, Liana Hadarean
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
- ** [[ Add lengthier description here ]]
-
- ** \todo document this file
-
-**/
+ ** \brief Provides mechanisms to limit resources.
+ **
+ ** This file provides the ResourceManager class. It can be used to impose
+ ** (cumulative and per-call) resource limits on the solver, as well as per-call
+ ** time limits.
+ **/
#include "cvc4_public.h"
@@ -22,7 +23,7 @@
#include <sys/time.h>
-#include <cstddef>
+#include <chrono>
#include <memory>
#include "base/exception.h"
@@ -35,193 +36,179 @@ namespace CVC4 {
class StatisticsRegistry;
/**
- * A helper class to keep track of a time budget and signal
- * the PropEngine when the budget expires.
+ * This class implements a easy to use wall clock timer based on std::chrono.
*/
-class CVC4_PUBLIC Timer {
+class CVC4_PUBLIC WallClockTimer
+{
+ /**
+ * The underlying clock that is used.
+ * std::chrono::system_clock represents wall clock time.
+ */
+ using clock = std::chrono::system_clock;
+ /** A time point of the clock we use. */
+ using time_point = std::chrono::time_point<clock>;
+
public:
- /** Construct a Timer. */
- Timer()
- : d_ms(0),
- d_cpu_start_time(0),
- d_cpu_limit(0),
- d_wall_time(true)
- {
- d_wall_limit.tv_sec = 0;
- d_wall_limit.tv_usec = 0;
- }
-
- /** Is the timer currently active? */
- bool on() const {
- return d_ms != 0;
- }
-
- /** Set a millisecond timer (0==off). */
- void set(uint64_t millis, bool wall_time = true);
- /** Return the milliseconds elapsed since last set() wall/cpu time
- depending on d_wall_time*/
+ /** Checks whether this timer is active. */
+ bool on() const;
+ /**
+ * Activates this timer with a timeout in milliseconds.
+ * If millis is zero, the timer is deactivated.
+ */
+ void set(uint64_t millis);
+ /** Returns the number of elapsed milliseconds since the last call to set().
+ */
uint64_t elapsed() const;
+ /** Checks whether the current timeout has expired. */
bool expired() const;
private:
+ /** The start of this timer. */
+ time_point d_start;
+ /** The point in time when this timer expires. */
+ time_point d_limit;
+};
+
+/**
+ * This class manages resource limits (cumulative or per call) and (per call)
+ * time limits. The available resources are listed in ResourceManager::Resource
+ * and their individual costs are configured via command line options.
+ */
+class CVC4_PUBLIC ResourceManager
+{
+ public:
+ /** Types of resources. */
+ enum class Resource
+ {
+ ArithPivotStep,
+ ArithNlLemmaStep,
+ BitblastStep,
+ BvEagerAssertStep,
+ BvPropagationStep,
+ BvSatConflictsStep,
+ BvSatPropagateStep,
+ BvSatSimplifyStep,
+ CnfStep,
+ DecisionStep,
+ LemmaStep,
+ NewSkolemStep,
+ ParseStep,
+ PreprocessStep,
+ QuantifierStep,
+ RestartStep,
+ RewriteStep,
+ SatConflictStep,
+ TheoryCheckStep,
+ };
+
+ /** Construst a resource manager. */
+ ResourceManager(StatisticsRegistry& statistics_registry, Options& options);
+ /** Default destructor. */
+ ~ResourceManager();
+ /** Can not be copied. */
+ ResourceManager(const ResourceManager&) = delete;
+ /** Can not be moved. */
+ ResourceManager(ResourceManager&&) = delete;
+ /** Can not be copied. */
+ ResourceManager& operator=(const ResourceManager&) = delete;
+ /** Can not be moved. */
+ ResourceManager& operator=(ResourceManager&&) = delete;
+
+ /** Checks whether any limit is active. */
+ bool limitOn() const { return cumulativeLimitOn() || perCallLimitOn(); }
+ /** Checks whether any cumulative limit is active. */
+ bool cumulativeLimitOn() const;
+ /** Checks whether any per-call limit is active. */
+ bool perCallLimitOn() const;
+
+ /** Checks whether resources have been exhausted. */
+ bool outOfResources() const;
+ /** Checks whether time has been exhausted. */
+ bool outOfTime() const;
+ /** Checks whether any limit has been exhausted. */
+ bool out() const { return d_on && (outOfResources() || outOfTime()); }
+
+ /** Retrieves amount of resources used overall. */
+ uint64_t getResourceUsage() const;
+ /** Retrieves time used over all calls. */
+ uint64_t getTimeUsage() const;
+ /** Retrieves the remaining number of cumulative resources. */
+ uint64_t getResourceRemaining() const;
+
+ /** Retrieves resource budget for this call. */
+ uint64_t getResourceBudgetForThisCall() { return d_thisCallResourceBudget; }
+
+ /**
+ * Spends a given resources. Throws an UnsafeInterruptException if there are
+ * no remaining resources.
+ */
+ void spendResource(Resource r);
+
+ /** Sets the resource limit. */
+ void setResourceLimit(uint64_t units, bool cumulative = false);
+ /** Sets the time limit. */
+ void setTimeLimit(uint64_t millis);
+ /** Sets whether resource limitation is enabled. */
+ void enable(bool on);
+
+ /**
+ * Resets perCall limits to mark the start of a new call,
+ * updates budget for current call and starts the timer
+ */
+ void beginCall();
+
+ /**
+ * Marks the end of a SmtEngine check call, stops the per
+ * call timer.
+ */
+ void endCall();
+
+ /**
+ * Registers a listener that is notified on a resource out or (per-call)
+ * timeout.
+ */
+ void registerListener(Listener* listener);
+
+ private:
+ /** The per-call wall clock timer. */
+ WallClockTimer d_perCallTimer;
+
+ /** A user-imposed per-call time budget, in milliseconds. 0 = no limit. */
+ uint64_t d_timeBudgetPerCall;
+ /** A user-imposed cumulative resource budget. 0 = no limit. */
+ uint64_t d_resourceBudgetCumulative;
+ /** A user-imposed per-call resource budget. 0 = no limit. */
+ uint64_t d_resourceBudgetPerCall;
+
+ /** The total number of milliseconds used. */
+ uint64_t d_cumulativeTimeUsed;
+ /** The total amount of resources used. */
+ uint64_t d_cumulativeResourceUsed;
+
+ /** The amount of resources used during this call. */
+ uint64_t d_thisCallResourceUsed;
+
+ /**
+ * The resource budget for this call (min between per call
+ * budget and left-over cumulative budget.)
+ */
+ uint64_t d_thisCallResourceBudget;
+
+ /** A flag indicating whether resource limitation is active. */
+ bool d_on;
+
+ /** Receives a notification on reaching a limit. */
+ std::vector<Listener*> d_listeners;
+
+ void spendResource(unsigned amount);
+
+ struct Statistics;
+ std::unique_ptr<Statistics> d_statistics;
+
+ Options& d_options;
+
+}; /* class ResourceManager */
- /** Return the milliseconds elapsed since last set() cpu time. */
- uint64_t elapsedCPU() const;
- /** Return the milliseconds elapsed since last set() wall time. */
- uint64_t elapsedWall() const;
-
- uint64_t d_ms;
- clock_t d_cpu_start_time;
- clock_t d_cpu_limit;
- bool d_wall_time;
- timeval d_wall_limit;
-};/* class Timer */
-
-
-class CVC4_PUBLIC ResourceManager {
-public:
- enum class Resource
- {
- BitblastStep,
- BvEagerAssertStep,
- BvPropagationStep,
- BvSatConflictsStep,
- CnfStep,
- DecisionStep,
- LemmaStep,
- ParseStep,
- PreprocessStep,
- QuantifierStep,
- RestartStep,
- RewriteStep,
- SatConflictStep,
- TheoryCheckStep,
- };
-
- ResourceManager(StatisticsRegistry& statistics_registry, Options& options);
- ~ResourceManager();
-
- bool limitOn() const { return cumulativeLimitOn() || perCallLimitOn(); }
- bool cumulativeLimitOn() const;
- bool perCallLimitOn() const;
-
- bool outOfResources() const;
- bool outOfTime() const;
- bool out() const { return d_on && (outOfResources() || outOfTime()); }
-
- /**
- * This returns a const uint64_t& to support being used as a ReferenceStat.
- */
- const uint64_t& getResourceUsage() const;
- uint64_t getTimeUsage() const;
- uint64_t getResourceRemaining() const;
- uint64_t getTimeRemaining() const;
-
- uint64_t getResourceBudgetForThisCall() { return d_thisCallResourceBudget; }
- // Throws an UnsafeInterruptException if there are no remaining resources.
- void spendResource(Resource r);
-
- void setHardLimit(bool value);
- void setResourceLimit(uint64_t units, bool cumulative = false);
- void setTimeLimit(uint64_t millis, bool cumulative = false);
- void useCPUTime(bool cpu);
-
- void enable(bool on);
-
- /**
- * Resets perCall limits to mark the start of a new call,
- * updates budget for current call and starts the timer
- */
- void beginCall();
-
- /**
- * Marks the end of a SmtEngine check call, stops the per
- * call timer, updates cumulative time used.
- */
- void endCall();
-
- static uint64_t getFrequencyCount() { return s_resourceCount; }
-
- /**
- * Registers a listener that is notified on a hard resource out.
- *
- * This Registration must be destroyed by the user before this
- * ResourceManager.
- */
- ListenerCollection::Registration* registerHardListener(Listener* listener);
-
- /**
- * Registers a listener that is notified on a soft resource out.
- *
- * This Registration must be destroyed by the user before this
- * ResourceManager.
- */
- ListenerCollection::Registration* registerSoftListener(Listener* listener);
-
-private:
- Timer d_cumulativeTimer;
- Timer d_perCallTimer;
-
- /** A user-imposed cumulative time budget, in milliseconds. 0 = no limit. */
- uint64_t d_timeBudgetCumulative;
- /** A user-imposed per-call time budget, in milliseconds. 0 = no limit. */
- uint64_t d_timeBudgetPerCall;
- /** A user-imposed cumulative resource budget. 0 = no limit. */
- uint64_t d_resourceBudgetCumulative;
- /** A user-imposed per-call resource budget. 0 = no limit. */
- uint64_t d_resourceBudgetPerCall;
-
- /** The number of milliseconds used. */
- uint64_t d_cumulativeTimeUsed;
- /** The amount of resource used. */
- uint64_t d_cumulativeResourceUsed;
-
- /** The amount of resource used during this call. */
- uint64_t d_thisCallResourceUsed;
-
- /**
- * The amount of resource budget for this call (min between per call
- * budget and left-over cumulative budget.
- */
- uint64_t d_thisCallTimeBudget;
- uint64_t d_thisCallResourceBudget;
-
- bool d_isHardLimit;
- bool d_on;
- bool d_cpuTime;
- uint64_t d_spendResourceCalls;
-
- /** Counter indicating how often to check resource manager in loops */
- static const uint64_t s_resourceCount;
-
- /** Receives a notification on reaching a hard limit. */
- ListenerCollection d_hardListeners;
-
- /** Receives a notification on reaching a hard limit. */
- ListenerCollection d_softListeners;
-
- /**
- * ResourceManagers cannot be copied as they are given an explicit
- * list of Listeners to respond to.
- */
- ResourceManager(const ResourceManager&) = delete;
-
- /**
- * ResourceManagers cannot be assigned as they are given an explicit
- * list of Listeners to respond to.
- */
- ResourceManager& operator=(const ResourceManager&) = delete;
-
- void spendResource(unsigned amount);
-
- struct Statistics;
- std::unique_ptr<Statistics> d_statistics;
-
- Options& d_options;
-
-};/* class ResourceManager */
-
-
-}/* CVC4 namespace */
+} // namespace CVC4
#endif /* CVC4__RESOURCE_MANAGER_H */
diff --git a/src/util/result.cpp b/src/util/result.cpp
index 0ed063ebc..f4e4d13c7 100644
--- a/src/util/result.cpp
+++ b/src/util/result.cpp
@@ -5,7 +5,7 @@
** Tim King, Aina Niemetz, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/result.h b/src/util/result.h
index d9d024b5a..96fe919d0 100644
--- a/src/util/result.h
+++ b/src/util/result.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/roundingmode.h b/src/util/roundingmode.h
new file mode 100644
index 000000000..a1bda2988
--- /dev/null
+++ b/src/util/roundingmode.h
@@ -0,0 +1,50 @@
+/********************* */
+/*! \file roundingmode.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ ** Aina Niemetz, Martin Brain, Tim King
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
+ ** in the top-level source directory and their institutional affiliations.
+ ** All rights reserved. See the file COPYING in the top-level source
+ ** directory for licensing information.\endverbatim
+ **
+ ** \brief The definition of rounding mode values.
+ **/
+#include "cvc4_public.h"
+
+#ifndef CVC4__ROUNDINGMODE_H
+#define CVC4__ROUNDINGMODE_H
+
+#include <fenv.h>
+
+namespace CVC4 {
+
+#define CVC4_NUM_ROUNDING_MODES 5
+
+/**
+ * A concrete instance of the rounding mode sort
+ */
+enum CVC4_PUBLIC RoundingMode
+{
+ ROUND_NEAREST_TIES_TO_EVEN = FE_TONEAREST,
+ ROUND_TOWARD_POSITIVE = FE_UPWARD,
+ ROUND_TOWARD_NEGATIVE = FE_DOWNWARD,
+ ROUND_TOWARD_ZERO = FE_TOWARDZERO,
+ // Initializes this to the diagonalization of the 4 other values.
+ ROUND_NEAREST_TIES_TO_AWAY =
+ (((~FE_TONEAREST) & 0x1) | ((~FE_UPWARD) & 0x2) | ((~FE_DOWNWARD) & 0x4)
+ | ((~FE_TOWARDZERO) & 0x8))
+}; /* enum RoundingMode */
+
+/**
+ * Hash function for rounding mode values.
+ */
+struct CVC4_PUBLIC RoundingModeHashFunction
+{
+ inline size_t operator()(const RoundingMode& rm) const { return size_t(rm); }
+}; /* struct RoundingModeHashFunction */
+
+} // namespace CVC4
+
+#endif
diff --git a/src/util/safe_print.cpp b/src/util/safe_print.cpp
index 7bc7fed9b..f45849736 100644
--- a/src/util/safe_print.cpp
+++ b/src/util/safe_print.cpp
@@ -5,7 +5,7 @@
** Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/safe_print.h b/src/util/safe_print.h
index 4afd08c1a..6f72569bb 100644
--- a/src/util/safe_print.h
+++ b/src/util/safe_print.h
@@ -5,7 +5,7 @@
** Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -37,13 +37,6 @@
#ifndef CVC4__SAFE_PRINT_H
#define CVC4__SAFE_PRINT_H
-#if __cplusplus >= 201103L
-// For c++11 and newer
-#include <cstdint>
-#else
-#include <stdint.h>
-#endif
-
#include <unistd.h>
#include <cstring>
diff --git a/src/util/sampler.cpp b/src/util/sampler.cpp
index 47cc32fb0..20dfb92a7 100644
--- a/src/util/sampler.cpp
+++ b/src/util/sampler.cpp
@@ -5,7 +5,7 @@
** Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/sampler.h b/src/util/sampler.h
index 688c83f1b..8968f5dc7 100644
--- a/src/util/sampler.h
+++ b/src/util/sampler.h
@@ -5,7 +5,7 @@
** Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/sexpr.cpp b/src/util/sexpr.cpp
index 6f2da480e..7efd171b0 100644
--- a/src/util/sexpr.cpp
+++ b/src/util/sexpr.cpp
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/sexpr.h b/src/util/sexpr.h
index 73e25026a..3bcf36abf 100644
--- a/src/util/sexpr.h
+++ b/src/util/sexpr.h
@@ -5,7 +5,7 @@
** Tim King, Morgan Deters, Christopher L. Conway
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/smt2_quote_string.cpp b/src/util/smt2_quote_string.cpp
index 3dc41407a..33e427c41 100644
--- a/src/util/smt2_quote_string.cpp
+++ b/src/util/smt2_quote_string.cpp
@@ -5,7 +5,7 @@
** Tim King, Andres Noetzli, Morgan Deters
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/smt2_quote_string.h b/src/util/smt2_quote_string.h
index fb8332063..9561a1a7f 100644
--- a/src/util/smt2_quote_string.h
+++ b/src/util/smt2_quote_string.h
@@ -5,7 +5,7 @@
** Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/statistics.cpp b/src/util/statistics.cpp
index 0344bb5b1..73e6afb96 100644
--- a/src/util/statistics.cpp
+++ b/src/util/statistics.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Andres Noetzli, Tim King
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/statistics.h b/src/util/statistics.h
index e77b48090..767ba3b5b 100644
--- a/src/util/statistics.h
+++ b/src/util/statistics.h
@@ -5,7 +5,7 @@
** Morgan Deters, Andres Noetzli, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/statistics_registry.cpp b/src/util/statistics_registry.cpp
index 81eaa3559..a8547eaf2 100644
--- a/src/util/statistics_registry.cpp
+++ b/src/util/statistics_registry.cpp
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/statistics_registry.h b/src/util/statistics_registry.h
index 69f6105cd..f706f3321 100644
--- a/src/util/statistics_registry.h
+++ b/src/util/statistics_registry.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -36,8 +36,6 @@
#ifndef CVC4__STATISTICS_REGISTRY_H
#define CVC4__STATISTICS_REGISTRY_H
-#include <stdint.h>
-
#include <ctime>
#include <iomanip>
#include <map>
diff --git a/src/util/string.cpp b/src/util/string.cpp
index 44c4d3e4b..0d40ebb05 100644
--- a/src/util/string.cpp
+++ b/src/util/string.cpp
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -131,7 +131,7 @@ std::vector<unsigned> String::toInternal(const std::string& s,
++i;
// are we an escape sequence?
bool isEscapeSequence = true;
- // the string corresponding to the hexidecimal code point
+ // the string corresponding to the hexadecimal code point
std::stringstream hexString;
// is the slash followed by a 'u'? Could be last character.
if (i >= s.size() || s[i] != 'u')
@@ -195,7 +195,7 @@ std::vector<unsigned> String::toInternal(const std::string& s,
}
if (!isEnd)
{
- // if we were interupted before ending, then this is not a valid
+ // if we were interrupted before ending, then this is not a valid
// escape sequence
isEscapeSequence = false;
}
@@ -210,7 +210,7 @@ std::vector<unsigned> String::toInternal(const std::string& s,
if (val > num_codes())
{
// Failed due to being out of range. This can happen for strings of
- // the form \ u { d_4 d_3 d_2 d_1 d_0 } where d_4 is a hexidecimal not
+ // the form \ u { d_4 d_3 d_2 d_1 d_0 } where d_4 is a hexadecimal not
// in the range [0-2].
isEscapeSequence = false;
}
@@ -274,9 +274,9 @@ std::size_t String::roverlap(const String &y) const {
std::string String::toString(bool useEscSequences) const {
std::stringstream str;
for (unsigned int i = 0; i < size(); ++i) {
- // we always print forward slash as a code point so that it cannot
- // be interpreted as specifying part of a code point, e.g. the string
- // '\' + 'u' + '0' of length three.
+ // we always print backslash as a code point so that it cannot be
+ // interpreted as specifying part of a code point, e.g. the string '\' +
+ // 'u' + '0' of length three.
if (isPrintable(d_str[i]) && d_str[i] != '\\' && !useEscSequences)
{
str << static_cast<char>(d_str[i]);
diff --git a/src/util/string.h b/src/util/string.h
index ca458232f..7102ec1f2 100644
--- a/src/util/string.h
+++ b/src/util/string.h
@@ -5,7 +5,7 @@
** Andrew Reynolds, Tim King, Tianyi Liang
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
@@ -17,7 +17,6 @@
#ifndef CVC4__UTIL__STRING_H
#define CVC4__UTIL__STRING_H
-#include <cstddef>
#include <functional>
#include <ostream>
#include <string>
@@ -58,7 +57,7 @@ class CVC4_PUBLIC String {
* \u{d_2 d_1 d_0}
* \u{d_3 d_2 d_1 d_0}
* \u{d_4 d_3 d_2 d_1 d_0}
- * where d_0 ... d_4 are hexidecimal digits, to the appropriate character.
+ * where d_0 ... d_4 are hexadecimal digits, to the appropriate character.
*
* If useEscSequences is false, then the characters of the constructed
* CVC4::String correspond one-to-one with the input string.
@@ -213,7 +212,7 @@ class CVC4_PUBLIC String {
* This is true for code points between 48 ('0') and 57 ('9').
*/
static bool isDigit(unsigned character);
- /** is the unsigned a hexidecimal digit?
+ /** is the unsigned a hexadecimal digit?
*
* This is true for code points between 48 ('0') and 57 ('9'), code points
* between 65 ('A') and 70 ('F) and code points between 97 ('a') and 102 ('f).
diff --git a/src/util/tuple.h b/src/util/tuple.h
index ff5dd18b3..240e41792 100644
--- a/src/util/tuple.h
+++ b/src/util/tuple.h
@@ -5,7 +5,7 @@
** Morgan Deters, Tim King, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/unsafe_interrupt_exception.h b/src/util/unsafe_interrupt_exception.h
index 0cd390cdd..7991971e3 100644
--- a/src/util/unsafe_interrupt_exception.h
+++ b/src/util/unsafe_interrupt_exception.h
@@ -5,7 +5,7 @@
** Liana Hadarean, Mathias Preiner
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/utility.cpp b/src/util/utility.cpp
index b1b86a38b..7a50eb7fd 100644
--- a/src/util/utility.cpp
+++ b/src/util/utility.cpp
@@ -5,7 +5,7 @@
** Andres Noetzli
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
diff --git a/src/util/utility.h b/src/util/utility.h
index 86dd64df9..6cf8bb3f4 100644
--- a/src/util/utility.h
+++ b/src/util/utility.h
@@ -5,7 +5,7 @@
** Morgan Deters, Andres Noetzli, Aina Niemetz
** This file is part of the CVC4 project.
** Copyright (c) 2009-2020 by the authors listed in the file AUTHORS
- ** in the top-level source directory) and their institutional affiliations.
+ ** in the top-level source directory and their institutional affiliations.
** All rights reserved. See the file COPYING in the top-level source
** directory for licensing information.\endverbatim
**
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback