summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am25
-rw-r--r--src/cvc4.i2
-rw-r--r--src/expr/node.cpp27
-rw-r--r--src/expr/node.h7
-rw-r--r--src/expr/node_manager.h2
-rw-r--r--src/main/Makefile.am8
-rw-r--r--src/main/driver_unified.cpp3
-rw-r--r--src/main/portfolio_util.cpp4
-rw-r--r--src/main/translator.cpp175
-rw-r--r--src/options/Makefile.am4
-rw-r--r--src/parser/smt2/Smt2.g33
-rw-r--r--src/parser/smt2/smt2.cpp12
-rw-r--r--src/parser/smt2/smt2.h6
-rw-r--r--src/printer/smt2/smt2_printer.cpp19
-rw-r--r--src/printer/smt2/smt2_printer.h1
-rw-r--r--src/prop/bvminisat/core/SolverTypes.h4
-rw-r--r--src/prop/minisat/core/SolverTypes.h4
-rw-r--r--src/prop/minisat/minisat.cpp25
-rw-r--r--src/prop/minisat/minisat.h15
-rw-r--r--src/prop/options2
-rw-r--r--src/smt/logic_request.h53
-rw-r--r--src/smt/options9
-rw-r--r--src/smt/options_handlers.h13
-rw-r--r--src/smt/smt_engine.cpp581
-rw-r--r--src/smt/smt_engine.h9
-rw-r--r--src/smt/smt_options_template.cpp8
-rw-r--r--src/theory/arith/approx_simplex.cpp2502
-rw-r--r--src/theory/arith/approx_simplex.h118
-rw-r--r--src/theory/arith/arith_ite_utils.cpp436
-rw-r--r--src/theory/arith/arith_ite_utils.h100
-rw-r--r--src/theory/arith/arith_rewriter.cpp76
-rw-r--r--src/theory/arith/arith_static_learner.cpp56
-rw-r--r--src/theory/arith/arith_static_learner.h2
-rw-r--r--src/theory/arith/arith_utilities.h19
-rw-r--r--src/theory/arith/callbacks.cpp51
-rw-r--r--src/theory/arith/callbacks.h35
-rw-r--r--src/theory/arith/congruence_manager.cpp119
-rw-r--r--src/theory/arith/congruence_manager.h119
-rw-r--r--src/theory/arith/constraint.cpp472
-rw-r--r--src/theory/arith/constraint.h338
-rw-r--r--src/theory/arith/constraint_forward.h15
-rw-r--r--src/theory/arith/cut_log.cpp691
-rw-r--r--src/theory/arith/cut_log.h281
-rw-r--r--src/theory/arith/dio_solver.cpp2
-rw-r--r--src/theory/arith/dio_solver.h22
-rw-r--r--src/theory/arith/error_set.cpp10
-rw-r--r--src/theory/arith/error_set.h10
-rw-r--r--src/theory/arith/fc_simplex.cpp2
-rw-r--r--src/theory/arith/linear_equality.cpp36
-rw-r--r--src/theory/arith/linear_equality.h22
-rw-r--r--src/theory/arith/matrix.h44
-rw-r--r--src/theory/arith/normal_form.cpp205
-rw-r--r--src/theory/arith/normal_form.h41
-rw-r--r--src/theory/arith/options49
-rw-r--r--src/theory/arith/partial_model.cpp186
-rw-r--r--src/theory/arith/partial_model.h189
-rw-r--r--src/theory/arith/simplex.cpp27
-rw-r--r--src/theory/arith/simplex.h6
-rw-r--r--src/theory/arith/simplex_update.cpp14
-rw-r--r--src/theory/arith/simplex_update.h18
-rw-r--r--src/theory/arith/soi_simplex.cpp30
-rw-r--r--src/theory/arith/soi_simplex.h2
-rw-r--r--src/theory/arith/tableau.h2
-rw-r--r--src/theory/arith/theory_arith.cpp4
-rw-r--r--src/theory/arith/theory_arith.h2
-rw-r--r--src/theory/arith/theory_arith_private.cpp2299
-rw-r--r--src/theory/arith/theory_arith_private.h231
-rw-r--r--src/theory/arrays/theory_arrays.cpp18
-rw-r--r--src/theory/bv/theory_bv.cpp64
-rw-r--r--src/theory/bv/theory_bv.h24
-rw-r--r--src/theory/ite_utilities.cpp20
-rw-r--r--src/theory/ite_utilities.h20
-rw-r--r--src/theory/logic_info.h5
-rw-r--r--src/theory/quantifiers/bounded_integers.cpp5
-rw-r--r--src/theory/quantifiers/candidate_generator.cpp3
-rw-r--r--src/theory/quantifiers/first_order_model.cpp1
-rw-r--r--src/theory/quantifiers/first_order_reasoning.cpp9
-rw-r--r--src/theory/quantifiers/first_order_reasoning.h4
-rw-r--r--src/theory/quantifiers/full_model_check.cpp1
-rw-r--r--src/theory/quantifiers/inst_gen.cpp1
-rw-r--r--src/theory/quantifiers/inst_match_generator.cpp1
-rw-r--r--src/theory/quantifiers/inst_strategy_e_matching.cpp21
-rw-r--r--src/theory/quantifiers/instantiation_engine.cpp30
-rw-r--r--src/theory/quantifiers/kinds21
-rw-r--r--src/theory/quantifiers/model_builder.cpp7
-rw-r--r--src/theory/quantifiers/options6
-rw-r--r--src/theory/quantifiers/options_handlers.h3
-rwxr-xr-xsrc/theory/quantifiers/qinterval_builder.cpp2
-rwxr-xr-xsrc/theory/quantifiers/quant_conflict_find.cpp931
-rwxr-xr-xsrc/theory/quantifiers/quant_conflict_find.h42
-rw-r--r--src/theory/quantifiers/quantifiers_rewriter.cpp288
-rw-r--r--src/theory/quantifiers/quantifiers_rewriter.h10
-rw-r--r--src/theory/quantifiers/relevant_domain.cpp6
-rw-r--r--src/theory/quantifiers/rewrite_engine.cpp300
-rw-r--r--src/theory/quantifiers/rewrite_engine.h13
-rw-r--r--src/theory/quantifiers/symmetry_breaking.cpp1
-rw-r--r--src/theory/quantifiers/term_database.cpp96
-rw-r--r--src/theory/quantifiers/term_database.h39
-rw-r--r--src/theory/quantifiers/theory_quantifiers_type_rules.h86
-rw-r--r--src/theory/quantifiers_engine.cpp63
-rw-r--r--src/theory/quantifiers_engine.h32
-rw-r--r--src/theory/rewriterules/efficient_e_matching.cpp680
-rw-r--r--src/theory/rewriterules/efficient_e_matching.h450
-rw-r--r--src/theory/rewriterules/kinds37
-rw-r--r--src/theory/rewriterules/options14
-rw-r--r--src/theory/rewriterules/rr_candidate_generator.cpp67
-rw-r--r--src/theory/rewriterules/rr_candidate_generator.h199
-rw-r--r--src/theory/rewriterules/rr_inst_match.cpp1596
-rw-r--r--src/theory/rewriterules/rr_inst_match.h341
-rw-r--r--src/theory/rewriterules/rr_inst_match_impl.h126
-rw-r--r--src/theory/rewriterules/rr_trigger.cpp385
-rw-r--r--src/theory/rewriterules/rr_trigger.h157
-rw-r--r--src/theory/rewriterules/theory_rewriterules.cpp640
-rw-r--r--src/theory/rewriterules/theory_rewriterules.h288
-rw-r--r--src/theory/rewriterules/theory_rewriterules_params.h86
-rw-r--r--src/theory/rewriterules/theory_rewriterules_preprocess.h176
-rw-r--r--src/theory/rewriterules/theory_rewriterules_rewriter.h115
-rw-r--r--src/theory/rewriterules/theory_rewriterules_rules.cpp403
-rw-r--r--src/theory/rewriterules/theory_rewriterules_rules.h37
-rw-r--r--src/theory/rewriterules/theory_rewriterules_type_rules.h117
-rw-r--r--src/theory/strings/theory_strings.cpp173
-rw-r--r--src/theory/strings/theory_strings.h22
-rw-r--r--src/theory/theory.h19
-rw-r--r--src/theory/theory_engine.cpp97
-rw-r--r--src/theory/theory_engine.h3
-rw-r--r--src/theory/uf/equality_engine.cpp45
-rw-r--r--src/theory/uf/equality_engine.h6
-rw-r--r--src/theory/uf/equality_engine_types.h7
-rw-r--r--src/util/dump.h2
-rw-r--r--src/util/ite_removal.cpp137
-rw-r--r--src/util/ite_removal.h30
-rw-r--r--src/util/rational.i2
-rw-r--r--src/util/rational_cln_imp.cpp54
-rw-r--r--src/util/rational_cln_imp.h19
-rw-r--r--src/util/rational_gmp_imp.cpp51
-rw-r--r--src/util/rational_gmp_imp.h20
136 files changed, 9981 insertions, 8727 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 279e52e09..d75535e15 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -20,7 +20,7 @@ AM_CPPFLAGS = \
AM_CXXFLAGS = -Wall -Wno-unknown-pragmas -Wno-parentheses $(FLAG_VISIBILITY_HIDDEN)
SUBDIRS = lib options expr util prop/minisat prop/bvminisat . parser compat bindings main
-THEORIES = builtin booleans uf arith bv arrays datatypes sets strings quantifiers rewriterules idl
+THEORIES = builtin booleans uf arith bv arrays datatypes sets strings quantifiers idl
lib_LTLIBRARIES = libcvc4.la
@@ -116,6 +116,7 @@ libcvc4_la_SOURCES = \
smt/boolean_terms.h \
smt/boolean_terms.cpp \
smt/logic_exception.h \
+ smt/logic_request.h \
smt/simplification_mode.h \
smt/simplification_mode.cpp \
smt/options_handlers.h \
@@ -307,28 +308,13 @@ libcvc4_la_SOURCES = \
theory/quantifiers/quant_conflict_find.h \
theory/quantifiers/quant_conflict_find.cpp \
theory/quantifiers/options_handlers.h \
- theory/rewriterules/theory_rewriterules_rules.h \
- theory/rewriterules/theory_rewriterules_rules.cpp \
- theory/rewriterules/theory_rewriterules.h \
- theory/rewriterules/theory_rewriterules.cpp \
- theory/rewriterules/theory_rewriterules_rewriter.h \
- theory/rewriterules/theory_rewriterules_type_rules.h \
- theory/rewriterules/theory_rewriterules_preprocess.h \
- theory/rewriterules/theory_rewriterules_params.h \
- theory/rewriterules/rr_inst_match.h \
- theory/rewriterules/rr_inst_match_impl.h \
- theory/rewriterules/rr_inst_match.cpp \
- theory/rewriterules/rr_trigger.h \
- theory/rewriterules/rr_trigger.cpp \
- theory/rewriterules/rr_candidate_generator.h \
- theory/rewriterules/rr_candidate_generator.cpp \
- theory/rewriterules/efficient_e_matching.h \
- theory/rewriterules/efficient_e_matching.cpp \
theory/arith/theory_arith_type_rules.h \
theory/arith/type_enumerator.h \
theory/arith/arithvar.h \
theory/arith/arithvar.cpp \
theory/arith/bound_counts.h \
+ theory/arith/arith_ite_utils.h \
+ theory/arith/arith_ite_utils.cpp \
theory/arith/arith_rewriter.h \
theory/arith/arith_rewriter.cpp \
theory/arith/arith_static_learner.h \
@@ -384,6 +370,8 @@ libcvc4_la_SOURCES = \
theory/arith/arith_unate_lemma_mode.cpp \
theory/arith/arith_propagation_mode.h \
theory/arith/arith_propagation_mode.cpp \
+ theory/arith/cut_log.h \
+ theory/arith/cut_log.cpp \
theory/arith/options_handlers.h \
theory/booleans/type_enumerator.h \
theory/booleans/theory_bool.h \
@@ -468,7 +456,6 @@ EXTRA_DIST = \
theory/strings/kinds \
theory/arrays/kinds \
theory/quantifiers/kinds \
- theory/rewriterules/kinds \
theory/arith/kinds \
theory/booleans/kinds \
theory/example/ecdata.h \
diff --git a/src/cvc4.i b/src/cvc4.i
index aadbc374d..c0042b513 100644
--- a/src/cvc4.i
+++ b/src/cvc4.i
@@ -147,6 +147,8 @@ std::set<JavaInputStreamAdapter*> CVC4::JavaInputStreamAdapter::s_adapters;
%typemap(throws) CVC4::parser::InputStreamException = CVC4::Exception;
%typemap(throws) CVC4::parser::ParserException = CVC4::Exception;
+%typemap(throws) CVC4::RationalFromDoubleException = Exception;
+
// Generate an error if the mapping from C++ CVC4 Exception to Java CVC4 Exception doesn't exist above
%typemap(throws) SWIGTYPE, SWIGTYPE &, SWIGTYPE *, SWIGTYPE [], SWIGTYPE [ANY] %{
#error "exception $1_type doesn't map to Java correctly---please edit src/cvc4.i and add it"
diff --git a/src/expr/node.cpp b/src/expr/node.cpp
index c88fd187d..34a72e106 100644
--- a/src/expr/node.cpp
+++ b/src/expr/node.cpp
@@ -55,8 +55,13 @@ UnknownTypeException::UnknownTypeException(TNode n) throw() :
/** Is this node constant? (and has that been computed yet?) */
struct IsConstTag { };
struct IsConstComputedTag { };
+struct HasBoundVarTag { };
+struct HasBoundVarComputedTag { };
typedef expr::Attribute<IsConstTag, bool> IsConstAttr;
typedef expr::Attribute<IsConstComputedTag, bool> IsConstComputedAttr;
+/** Attribute true for expressions with bound variables in them */
+typedef expr::Attribute<HasBoundVarTag, bool> HasBoundVarAttr;
+typedef expr::Attribute<HasBoundVarComputedTag, bool> HasBoundVarComputedAttr;
template <bool ref_count>
bool NodeTemplate<ref_count>::isConst() const {
@@ -91,7 +96,29 @@ bool NodeTemplate<ref_count>::isConst() const {
}
}
+template <bool ref_count>
+bool NodeTemplate<ref_count>::hasBoundVar() {
+ assertTNodeNotExpired();
+ if(! getAttribute(HasBoundVarComputedAttr())) {
+ bool hasBv = false;
+ if(getKind() == kind::BOUND_VARIABLE) {
+ hasBv = true;
+ } else {
+ for(iterator i = begin(); i != end() && !hasBv; ++i) {
+ hasBv = (*i).hasBoundVar();
+ }
+ }
+ setAttribute(HasBoundVarAttr(), hasBv);
+ setAttribute(HasBoundVarComputedAttr(), true);
+ Debug("bva") << *this << " has bva : " << getAttribute(HasBoundVarAttr()) << std::endl;
+ return hasBv;
+ }
+ return getAttribute(HasBoundVarAttr());
+}
+
template bool NodeTemplate<true>::isConst() const;
template bool NodeTemplate<false>::isConst() const;
+template bool NodeTemplate<true>::hasBoundVar();
+template bool NodeTemplate<false>::hasBoundVar();
}/* CVC4 namespace */
diff --git a/src/expr/node.h b/src/expr/node.h
index 9ada7879c..ba139748e 100644
--- a/src/expr/node.h
+++ b/src/expr/node.h
@@ -424,6 +424,13 @@ public:
// bool properlyContainsDecision(); // maybe not atomic but all children are
/**
+ * Returns true iff this node contains a bound variable. This bound
+ * variable may or may not be free.
+ * @return true iff this node contains a bound variable.
+ */
+ bool hasBoundVar();
+
+ /**
* Convert this Node into an Expr using the currently-in-scope
* manager. Essentially this is like an "operator Expr()" but we
* don't want it to compete with implicit conversions between e.g.
diff --git a/src/expr/node_manager.h b/src/expr/node_manager.h
index b4d20b514..15c49efd8 100644
--- a/src/expr/node_manager.h
+++ b/src/expr/node_manager.h
@@ -1476,4 +1476,4 @@ NodeClass NodeManager::mkConstInternal(const T& val) {
}/* CVC4 namespace */
-#endif /* __CVC4__EXPR_MANAGER_H */
+#endif /* __CVC4__NODE_MANAGER_H */
diff --git a/src/main/Makefile.am b/src/main/Makefile.am
index 042b7cf45..7e87fa59a 100644
--- a/src/main/Makefile.am
+++ b/src/main/Makefile.am
@@ -3,7 +3,7 @@ AM_CPPFLAGS = \
-I@builddir@/.. $(ANTLR_INCLUDES) -I@srcdir@/../include -I@srcdir@/..
AM_CXXFLAGS = -Wall -Wno-unknown-pragmas
-bin_PROGRAMS = cvc4 cvc4-translator
+bin_PROGRAMS = cvc4
noinst_LIBRARIES = libmain.a
@@ -62,12 +62,6 @@ cvc4_LDADD += \
@builddir@/../lib/libreplacements.la
endif
-cvc4_translator_SOURCES = \
- translator.cpp
-cvc4_translator_LDADD = \
- @builddir@/../parser/libcvc4parser.la \
- @builddir@/../libcvc4.la
-
BUILT_SOURCES = \
$(TOKENS_FILES)
diff --git a/src/main/driver_unified.cpp b/src/main/driver_unified.cpp
index bf66629dd..adc40a9d1 100644
--- a/src/main/driver_unified.cpp
+++ b/src/main/driver_unified.cpp
@@ -42,7 +42,6 @@
#include "smt/options.h"
#include "theory/uf/options.h"
#include "util/output.h"
-#include "util/dump.h"
#include "util/result.h"
#include "util/statistics_registry.h"
@@ -184,12 +183,10 @@ int runCvc4(int argc, char* argv[], Options& opts) {
ChatChannel.setStream(CVC4::null_os);
MessageChannel.setStream(CVC4::null_os);
WarningChannel.setStream(CVC4::null_os);
- DumpChannel.setStream(CVC4::null_os);
}
// important even for muzzled builds (to get result output right)
*opts[options::out] << Expr::setlanguage(opts[options::outputLanguage]);
- DumpChannel.getStream() << Expr::setlanguage(opts[options::outputLanguage]);
// Create the expression manager using appropriate options
ExprManager* exprMgr;
diff --git a/src/main/portfolio_util.cpp b/src/main/portfolio_util.cpp
index a2d0ff700..e4fcf6024 100644
--- a/src/main/portfolio_util.cpp
+++ b/src/main/portfolio_util.cpp
@@ -34,7 +34,7 @@ vector<Options> parseThreadSpecificOptions(Options opts)
* Use satRandomSeed for generating random numbers, in particular
* satRandomSeed-s
*/
- srand((unsigned int)(-opts[options::satRandomSeed]));
+ srand(-opts[options::satRandomSeed]);
for(unsigned i = 0; i < numThreads; ++i) {
threadOptions.push_back(opts);
@@ -45,7 +45,7 @@ vector<Options> parseThreadSpecificOptions(Options opts)
// If the random-seed is negative, pick a random seed randomly
if(opts[options::satRandomSeed] < 0) {
- tOpts.set(options::satRandomSeed, (double)rand());
+ tOpts.set(options::satRandomSeed, unsigned(rand()));
}
if(i < opts[options::threadArgv].size() &&
diff --git a/src/main/translator.cpp b/src/main/translator.cpp
deleted file mode 100644
index 7cc90bbd1..000000000
--- a/src/main/translator.cpp
+++ /dev/null
@@ -1,175 +0,0 @@
-/********************* */
-/*! \file translator.cpp
- ** \verbatim
- ** Original author: Morgan Deters
- ** Major contributors: none
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2014 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Main driver for CVC4 translator executable
- **
- ** Main driver for CVC4 translator executable.
- **/
-
-#include <iostream>
-#include <fstream>
-#include <getopt.h>
-#include <cstring>
-#include "util/language.h"
-#include "expr/command.h"
-#include "expr/expr.h"
-#include "parser/parser_builder.h"
-#include "parser/parser.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::language;
-using namespace CVC4::parser;
-
-enum {
- INPUT_LANG = 'L',
- OUTPUT_LANG = 'O',
- OUTPUT_FILE = 'o',
- HELP = 'h'
-};/* enum */
-
-const struct option longopts[] = {
- { "output-lang", required_argument, NULL, OUTPUT_LANG },
- { "output-language", required_argument, NULL, OUTPUT_LANG },
- { "lang", required_argument, NULL, INPUT_LANG },
- { "language", required_argument, NULL, INPUT_LANG },
- { "out", required_argument, NULL, OUTPUT_FILE },
- { "help", no_argument, NULL, HELP },
- { NULL, no_argument, NULL, 0 },
-};/* longopts */
-
-static void showHelp() {
- cerr << "cvc4-translator translation tool" << endl
- << " --output-language | -O set output language (default smt2)" << endl
- << " --input-language | -L set input language (default auto)" << endl
- << " --out | -o set output file (- for stdout)" << endl
- << " --help | -h this help" << endl
- << "Options and input filenames can be intermixed, and order is important." << endl
- << "For instance, \"-O smt2 x -O cvc4 y\" reads file x in smt2 format and"
- << "file y in cvc4 format and writes all output to stdout." << endl
- << "Some canonicalization may occur." << endl
- << "Comments and formatting are not preserved." << endl;
-}
-
-static void readFile(const char* filename, InputLanguage fromLang, OutputLanguage toLang, ostream* out) {
- if(fromLang == input::LANG_AUTO) {
- unsigned len = strlen(filename);
- if(len >= 5 && !strcmp(".smt2", filename + len - 5)) {
- fromLang = language::input::LANG_SMTLIB_V2;
- } else if(len >= 4 && !strcmp(".smt", filename + len - 4)) {
- fromLang = language::input::LANG_SMTLIB_V1;
- } else if(len >= 5 && !strcmp(".smt1", filename + len - 5)) {
- fromLang = language::input::LANG_SMTLIB_V1;
- } else if((len >= 2 && !strcmp(".p", filename + len - 2)) ||
- (len >= 5 && !strcmp(".tptp", filename + len - 5))) {
- fromLang = language::input::LANG_TPTP;
- } else if(( len >= 4 && !strcmp(".cvc", filename + len - 4) ) ||
- ( len >= 5 && !strcmp(".cvc4", filename + len - 5) )) {
- fromLang = language::input::LANG_CVC4;
- } else {
- throw Exception("cannot determine input language to use for `" + string(filename) + "'");
- }
- }
-
- if(toLang == output::LANG_AUTO) {
- toLang = toOutputLanguage(fromLang);
- }
-
- *out << Expr::setlanguage(toLang);
-
- Options opts;
- opts.set(options::inputLanguage, fromLang);
- ExprManager exprMgr(opts);
- ParserBuilder parserBuilder(&exprMgr, filename, opts);
- if(!strcmp(filename, "-")) {
- parserBuilder.withFilename("<stdin>");
- parserBuilder.withLineBufferedStreamInput(cin);
- }
- Parser *parser = parserBuilder.build();
- while(Command* cmd = parser->nextCommand()) {
- *out << cmd << endl;
- if(dynamic_cast<QuitCommand*>(cmd) != NULL) {
- delete cmd;
- break;
- }
- delete cmd;
- }
- *out << flush;
- delete parser;
-}
-
-/**
- * Translate from an input language to an output language.
- */
-int main(int argc, char* argv[]) {
- ostream* out = &cout;
- InputLanguage fromLang = input::LANG_AUTO;
- OutputLanguage toLang = output::LANG_SMTLIB_V2;
- size_t files = 0;
-
- try {
- int c;
- while((c = getopt_long(argc, argv, "-L:O:o:h", longopts, NULL)) != -1) {
- switch(c) {
- case 1:
- ++files;
- readFile(optarg, (!strcmp(optarg, "-") && fromLang == input::LANG_AUTO) ? input::LANG_CVC4 : fromLang, toLang, out);
- break;
- case INPUT_LANG:
- if(!strcmp(optarg, "help")) {
- Options::printLanguageHelp(cerr);
- exit(1);
- }
- fromLang = toInputLanguage(optarg);
- break;
- case OUTPUT_LANG:
- if(!strcmp(optarg, "help")) {
- Options::printLanguageHelp(cerr);
- exit(1);
- }
- toLang = toOutputLanguage(optarg);
- break;
- case OUTPUT_FILE:
- out->flush();
- if(out != &cout) {
- ((ofstream*)out)->close();
- delete out;
- }
- if(strcmp(optarg, "-")) {
- out = new ofstream(optarg);
- } else {
- out = &cout;
- }
- break;
- case 'h':
- showHelp();
- exit(0);
- case '?':
- showHelp();
- exit(1);
- default:
- cerr << "internal error. translator failed ("
- << char(c) << "," << c << ")." << endl;
- exit(1);
- }
- }
-
- if(files == 0) {
- readFile("-", fromLang == input::LANG_AUTO ? input::LANG_CVC4 : fromLang, toLang, out);
- exit(0);
- }
- } catch(Exception& e) {
- cerr << e << endl;
- exit(1);
- }
-
- return 0;
-}
diff --git a/src/options/Makefile.am b/src/options/Makefile.am
index 8780922c9..18b2c42f4 100644
--- a/src/options/Makefile.am
+++ b/src/options/Makefile.am
@@ -21,8 +21,6 @@ OPTIONS_FILES_SRCS = \
../theory/arrays/options.h \
../theory/quantifiers/options.cpp \
../theory/quantifiers/options.h \
- ../theory/rewriterules/options.cpp \
- ../theory/rewriterules/options.h \
../theory/strings/options.cpp \
../theory/strings/options.h \
../prop/options.cpp \
@@ -84,8 +82,6 @@ nodist_liboptions_la_SOURCES = \
../theory/arrays/options.h \
../theory/quantifiers/options.cpp \
../theory/quantifiers/options.h \
- ../theory/rewriterules/options.cpp \
- ../theory/rewriterules/options.h \
../theory/strings/options.cpp \
../theory/strings/options.h \
../prop/options.cpp \
diff --git a/src/parser/smt2/Smt2.g b/src/parser/smt2/Smt2.g
index f1acac6ba..f987de2f1 100644
--- a/src/parser/smt2/Smt2.g
+++ b/src/parser/smt2/Smt2.g
@@ -253,6 +253,13 @@ command returns [CVC4::Command* cmd = NULL]
{ cmd = new GetOptionCommand(AntlrInput::tokenText($KEYWORD).c_str() + 1); }
| /* sort declaration */
DECLARE_SORT_TOK { PARSER_STATE->checkThatLogicIsSet(); }
+ { if(!PARSER_STATE->isTheoryEnabled(Smt2::THEORY_UF) &&
+ !PARSER_STATE->isTheoryEnabled(Smt2::THEORY_ARRAYS) &&
+ !PARSER_STATE->isTheoryEnabled(Smt2::THEORY_DATATYPES) &&
+ !PARSER_STATE->isTheoryEnabled(Smt2::THEORY_SETS)) {
+ PARSER_STATE->parseError(std::string("Free sort symbols not allowed in ") + PARSER_STATE->getLogic().getLogicString());
+ }
+ }
symbol[name,CHECK_UNDECLARED,SYM_SORT]
{ PARSER_STATE->checkUserSymbol(name); }
n=INTEGER_LITERAL
@@ -295,6 +302,9 @@ command returns [CVC4::Command* cmd = NULL]
sortSymbol[t,CHECK_DECLARED]
{ Debug("parser") << "declare fun: '" << name << "'" << std::endl;
if( sorts.size() > 0 ) {
+ if(!PARSER_STATE->isTheoryEnabled(Smt2::THEORY_UF)) {
+ PARSER_STATE->parseError(std::string("Functions (of non-zero arity) cannot be declared in logic ") + PARSER_STATE->getLogic().getLogicString());
+ }
t = EXPR_MANAGER->mkFunctionType(sorts, t);
}
Expr func = PARSER_STATE->mkVar(name, t);
@@ -488,6 +498,13 @@ extendedCommand[CVC4::Command*& cmd]
$cmd = new DeclareFunctionCommand(name, c, t); }
| DECLARE_SORTS_TOK { PARSER_STATE->checkThatLogicIsSet(); }
+ { if(!PARSER_STATE->isTheoryEnabled(Smt2::THEORY_UF) &&
+ !PARSER_STATE->isTheoryEnabled(Smt2::THEORY_ARRAYS) &&
+ !PARSER_STATE->isTheoryEnabled(Smt2::THEORY_DATATYPES) &&
+ !PARSER_STATE->isTheoryEnabled(Smt2::THEORY_SETS)) {
+ PARSER_STATE->parseError(std::string("Free sort symbols not allowed in ") + PARSER_STATE->getLogic().getLogicString());
+ }
+ }
{ $cmd = new CommandSequence(); }
LPAREN_TOK
( symbol[name,CHECK_UNDECLARED,SYM_SORT]
@@ -506,6 +523,9 @@ extendedCommand[CVC4::Command*& cmd]
nonemptySortList[sorts] RPAREN_TOK
{ Type t;
if(sorts.size() > 1) {
+ if(!PARSER_STATE->isTheoryEnabled(Smt2::THEORY_UF)) {
+ PARSER_STATE->parseError(std::string("Functions (of non-zero arity) cannot be declared in logic ") + PARSER_STATE->getLogic().getLogicString());
+ }
t = EXPR_MANAGER->mkFunctionType(sorts);
} else {
t = sorts[0];
@@ -524,6 +544,9 @@ extendedCommand[CVC4::Command*& cmd]
sortList[sorts] RPAREN_TOK
{ Type t = EXPR_MANAGER->booleanType();
if(sorts.size() > 0) {
+ if(!PARSER_STATE->isTheoryEnabled(Smt2::THEORY_UF)) {
+ PARSER_STATE->parseError(std::string("Predicates (of non-zero arity) cannot be declared in logic ") + PARSER_STATE->getLogic().getLogicString());
+ }
t = EXPR_MANAGER->mkFunctionType(sorts, t);
}
Expr func = PARSER_STATE->mkVar(name, t);
@@ -708,6 +731,16 @@ simpleSymbolicExprNoKeyword[CVC4::SExpr& sexpr]
{ sexpr = SExpr(Integer(AntlrInput::tokenText($INTEGER_LITERAL))); }
| DECIMAL_LITERAL
{ sexpr = SExpr(AntlrInput::tokenToRational($DECIMAL_LITERAL)); }
+ | HEX_LITERAL
+ { assert( AntlrInput::tokenText($HEX_LITERAL).find("#x") == 0 );
+ std::string hexString = AntlrInput::tokenTextSubstr($HEX_LITERAL, 2);
+ sexpr = Integer(hexString, 16);
+ }
+ | BINARY_LITERAL
+ { assert( AntlrInput::tokenText($BINARY_LITERAL).find("#b") == 0 );
+ std::string binString = AntlrInput::tokenTextSubstr($BINARY_LITERAL, 2);
+ sexpr = Integer(binString, 2);
+ }
| str[s,false]
{ sexpr = SExpr(s); }
// | LPAREN_TOK STRCST_TOK
diff --git a/src/parser/smt2/smt2.cpp b/src/parser/smt2/smt2.cpp
index b59880a5e..64b321613 100644
--- a/src/parser/smt2/smt2.cpp
+++ b/src/parser/smt2/smt2.cpp
@@ -154,6 +154,12 @@ void Smt2::addTheory(Theory theory) {
addOperator(kind::SET_SINGLETON, "setenum");
break;
+ case THEORY_DATATYPES:
+ Parser::addOperator(kind::APPLY_CONSTRUCTOR);
+ Parser::addOperator(kind::APPLY_TESTER);
+ Parser::addOperator(kind::APPLY_SELECTOR);
+ break;
+
case THEORY_STRINGS:
defineType("String", getExprManager()->stringType());
addStringOperators();
@@ -194,6 +200,8 @@ bool Smt2::isTheoryEnabled(Theory theory) const {
return d_logic.isTheoryEnabled(theory::THEORY_BV);
case THEORY_CORE:
return true;
+ case THEORY_DATATYPES:
+ return d_logic.isTheoryEnabled(theory::THEORY_DATATYPES);
case THEORY_INTS:
return d_logic.isTheoryEnabled(theory::THEORY_ARITH) &&
d_logic.areIntegersUsed() && ( !d_logic.areRealsUsed() );
@@ -253,6 +261,10 @@ void Smt2::setLogic(const std::string& name) {
addTheory(THEORY_BITVECTORS);
}
+ if(d_logic.isTheoryEnabled(theory::THEORY_DATATYPES)) {
+ addTheory(THEORY_DATATYPES);
+ }
+
if(d_logic.isTheoryEnabled(theory::THEORY_SETS)) {
addTheory(THEORY_SETS);
}
diff --git a/src/parser/smt2/smt2.h b/src/parser/smt2/smt2.h
index 969892c5f..55a06a8e3 100644
--- a/src/parser/smt2/smt2.h
+++ b/src/parser/smt2/smt2.h
@@ -40,6 +40,7 @@ public:
THEORY_ARRAYS,
THEORY_BITVECTORS,
THEORY_CORE,
+ THEORY_DATATYPES,
THEORY_INTS,
THEORY_REALS,
THEORY_REALS_INTS,
@@ -83,6 +84,11 @@ public:
*/
void setLogic(const std::string& name);
+ /**
+ * Get the logic.
+ */
+ const LogicInfo& getLogic() const { return d_logic; }
+
void setInfo(const std::string& flag, const SExpr& sexpr);
void setOption(const std::string& flag, const SExpr& sexpr);
diff --git a/src/printer/smt2/smt2_printer.cpp b/src/printer/smt2/smt2_printer.cpp
index 849d5c0a5..6485670b5 100644
--- a/src/printer/smt2/smt2_printer.cpp
+++ b/src/printer/smt2/smt2_printer.cpp
@@ -697,6 +697,25 @@ static inline void toStream(std::ostream& out, const SExpr& sexpr) throw() {
Printer::getPrinter(language::output::LANG_SMTLIB_V2)->toStream(out, sexpr);
}
+void Smt2Printer::toStream(std::ostream& out, const SExpr& sexpr) const throw() {
+ if(sexpr.isKeyword()) {
+ std::string s = sexpr.getValue();
+ if(s.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789~!@%^&*_-+=<>.?/") == std::string::npos) {
+ // simple unquoted symbol
+ out << s;
+ } else {
+ // must quote the symbol, but it cannot contain | or \, we turn those into _
+ size_t p;
+ while((p = s.find_first_of("\\|")) != std::string::npos) {
+ s = s.replace(p, 1, "_");
+ }
+ out << "|" << s << "|";
+ }
+ } else {
+ this->Printer::toStream(out, sexpr);
+ }
+}
+
template <class T>
static bool tryToStream(std::ostream& out, const CommandStatus* s) throw();
diff --git a/src/printer/smt2/smt2_printer.h b/src/printer/smt2/smt2_printer.h
index c70bb78c3..c3f8deb9c 100644
--- a/src/printer/smt2/smt2_printer.h
+++ b/src/printer/smt2/smt2_printer.h
@@ -45,6 +45,7 @@ public:
void toStream(std::ostream& out, const Command* c, int toDepth, bool types, size_t dag) const throw();
void toStream(std::ostream& out, const CommandStatus* s) const throw();
void toStream(std::ostream& out, const Result& r) const throw();
+ void toStream(std::ostream& out, const SExpr& sexpr) const throw();
};/* class Smt2Printer */
}/* CVC4::printer::smt2 namespace */
diff --git a/src/prop/bvminisat/core/SolverTypes.h b/src/prop/bvminisat/core/SolverTypes.h
index 89ffc8a00..0400f956d 100644
--- a/src/prop/bvminisat/core/SolverTypes.h
+++ b/src/prop/bvminisat/core/SolverTypes.h
@@ -46,14 +46,14 @@ struct Lit {
int x;
// Use this as a constructor:
- friend Lit mkLit(Var var, bool sign = false);
+ friend Lit mkLit(Var var, bool sign);
bool operator == (Lit p) const { return x == p.x; }
bool operator != (Lit p) const { return x != p.x; }
bool operator < (Lit p) const { return x < p.x; } // '<' makes p, ~p adjacent in the ordering.
};
-inline Lit mkLit (Var var, bool sign) { Lit p; p.x = var + var + (int)sign; return p; }
+inline Lit mkLit (Var var, bool sign = false) { Lit p; p.x = var + var + (int)sign; return p; }
inline Lit operator ~(Lit p) { Lit q; q.x = p.x ^ 1; return q; }
inline Lit operator ^(Lit p, bool b) { Lit q; q.x = p.x ^ (unsigned int)b; return q; }
inline bool sign (Lit p) { return p.x & 1; }
diff --git a/src/prop/minisat/core/SolverTypes.h b/src/prop/minisat/core/SolverTypes.h
index fac4c92c1..a6413e674 100644
--- a/src/prop/minisat/core/SolverTypes.h
+++ b/src/prop/minisat/core/SolverTypes.h
@@ -49,7 +49,7 @@ struct Lit {
int x;
// Use this as a constructor:
- friend Lit mkLit(Var var, bool sign = false);
+ friend Lit mkLit(Var var, bool sign);
bool operator == (Lit p) const { return x == p.x; }
bool operator != (Lit p) const { return x != p.x; }
@@ -57,7 +57,7 @@ struct Lit {
};
-inline Lit mkLit (Var var, bool sign) { Lit p; p.x = var + var + (int)sign; return p; }
+inline Lit mkLit (Var var, bool sign = false) { Lit p; p.x = var + var + (int)sign; return p; }
inline Lit operator ~(Lit p) { Lit q; q.x = p.x ^ 1; return q; }
inline Lit operator ^(Lit p, bool b) { Lit q; q.x = p.x ^ (unsigned int)b; return q; }
inline bool sign (Lit p) { return p.x & 1; }
diff --git a/src/prop/minisat/minisat.cpp b/src/prop/minisat/minisat.cpp
index 98e43aaf0..c4fe58fd7 100644
--- a/src/prop/minisat/minisat.cpp
+++ b/src/prop/minisat/minisat.cpp
@@ -5,7 +5,7 @@
** Major contributors:
** Minor contributors (to current version):
** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)
+ ** Copyright (c) 2009-2014 The Analysis of Computer Systems Group (ACSys)
** Courant Institute of Mathematical Sciences
** New York University
** See the file COPYING in the top-level source directory for licensing
@@ -13,7 +13,7 @@
**
** \brief SAT Solver.
**
- ** Implementation of the minisat for cvc4.
+ ** Implementation of the minisat interface for cvc4.
**/
#include "prop/minisat/minisat.h"
@@ -111,8 +111,7 @@ void MinisatSatSolver::toSatClause(const Minisat::Clause& clause,
Assert((unsigned)clause.size() == sat_clause.size());
}
-void MinisatSatSolver::initialize(context::Context* context, TheoryProxy* theoryProxy)
-{
+void MinisatSatSolver::initialize(context::Context* context, TheoryProxy* theoryProxy) {
d_context = context;
@@ -125,20 +124,30 @@ void MinisatSatSolver::initialize(context::Context* context, TheoryProxy* theory
d_minisat = new Minisat::SimpSolver(theoryProxy, d_context,
options::incrementalSolving() ||
options::decisionMode() != decision::DECISION_STRATEGY_INTERNAL );
+
+ d_statistics.init(d_minisat);
+}
+
+// Like initialize() above, but called just before each search when in
+// incremental mode
+void MinisatSatSolver::setupOptions() {
+ // Copy options from CVC4 options structure into minisat, as appropriate
+
// Set up the verbosity
d_minisat->verbosity = (options::verbosity() > 0) ? 1 : -1;
// Set up the random decision parameters
d_minisat->random_var_freq = options::satRandomFreq();
- d_minisat->random_seed = options::satRandomSeed();
+ // If 0, we use whatever we like (here, the Minisat default seed)
+ if(options::satRandomSeed() != 0) {
+ d_minisat->random_seed = double(options::satRandomSeed());
+ }
// Give access to all possible options in the sat solver
d_minisat->var_decay = options::satVarDecay();
d_minisat->clause_decay = options::satClauseDecay();
d_minisat->restart_first = options::satRestartFirst();
d_minisat->restart_inc = options::satRestartInc();
-
- d_statistics.init(d_minisat);
}
void MinisatSatSolver::addClause(SatClause& clause, bool removable) {
@@ -153,6 +162,7 @@ SatVariable MinisatSatSolver::newVar(bool isTheoryAtom, bool preRegister, bool c
SatValue MinisatSatSolver::solve(unsigned long& resource) {
Trace("limit") << "SatSolver::solve(): have limit of " << resource << " conflicts" << std::endl;
+ setupOptions();
if(resource == 0) {
d_minisat->budgetOff();
} else {
@@ -168,6 +178,7 @@ SatValue MinisatSatSolver::solve(unsigned long& resource) {
}
SatValue MinisatSatSolver::solve() {
+ setupOptions();
d_minisat->budgetOff();
return toSatLiteralValue(d_minisat->solve());
}
diff --git a/src/prop/minisat/minisat.h b/src/prop/minisat/minisat.h
index 27258b3c2..201879eb0 100644
--- a/src/prop/minisat/minisat.h
+++ b/src/prop/minisat/minisat.h
@@ -5,7 +5,7 @@
** Major contributors:
** Minor contributors (to current version):
** This file is part of the CVC4 prototype.
- ** Copyright (c) 2009, 2010, 2011 The Analysis of Computer Systems Group (ACSys)
+ ** Copyright (c) 2009-2014 The Analysis of Computer Systems Group (ACSys)
** Courant Institute of Mathematical Sciences
** New York University
** See the file COPYING in the top-level source directory for licensing
@@ -13,7 +13,7 @@
**
** \brief SAT Solver.
**
- ** Implementation of the minisat for cvc4.
+ ** Implementation of the minisat interface for cvc4.
**/
#pragma once
@@ -36,6 +36,8 @@ class MinisatSatSolver : public DPLLSatSolverInterface {
/** Context we will be using to synchronize the sat solver */
context::Context* d_context;
+ void setupOptions();
+
public:
MinisatSatSolver();
@@ -96,11 +98,10 @@ public:
Statistics();
~Statistics();
void init(Minisat::SimpSolver* d_minisat);
- };
+ };/* class MinisatSatSolver::Statistics */
Statistics d_statistics;
-};
-
-} // prop namespace
-} // cvc4 namespace
+};/* class MinisatSatSolver */
+}/* CVC4::prop namespace */
+}/* CVC4 namespace */
diff --git a/src/prop/options b/src/prop/options
index b300c3fb6..71091d2b5 100644
--- a/src/prop/options
+++ b/src/prop/options
@@ -10,7 +10,7 @@ option - --show-sat-solvers void :handler CVC4::prop::showSatSolvers :handler-in
option satRandomFreq random-frequency --random-freq=P double :default 0.0 :predicate greater_equal(0.0) less_equal(1.0)
sets the frequency of random decisions in the sat solver (P=0.0 by default)
-option satRandomSeed random-seed --random-seed=S double :default 91648253 :read-write
+option satRandomSeed random-seed --random-seed=S uint32_t :default 0 :read-write
sets the random seed for the sat solver
option satVarDecay double :default 0.95 :predicate less_equal(1.0) greater_equal(0.0)
diff --git a/src/smt/logic_request.h b/src/smt/logic_request.h
new file mode 100644
index 000000000..4985b0e65
--- /dev/null
+++ b/src/smt/logic_request.h
@@ -0,0 +1,53 @@
+/********************* */
+/*! \file logic_request.h
+ ** \verbatim
+ ** Original author: Morgan Deters
+ ** Major contributors: none
+ ** Minor contributors (to current version): none
+ ** This file is part of the CVC4 project.
+ ** Copyright (c) 2009-2014 New York University and The University of Iowa
+ ** See the file COPYING in the top-level source directory for licensing
+ ** information.\endverbatim
+ **
+ ** \brief An object to request logic widening in the running SmtEngine
+ **
+ ** An object to request logic widening in the running SmtEngine. This
+ ** class exists as a proxy between theory code and the SmtEngine, allowing
+ ** a theory to enable another theory in the SmtEngine after initialization
+ ** (thus the usual, public setLogic() cannot be used). This is mainly to
+ ** support features like uninterpreted divide-by-zero (to support the
+ ** partial function DIVISION), where during theory expansion, the theory
+ ** of uninterpreted functions needs to be added to the logic to support
+ ** partial functions.
+ **/
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__LOGIC_REQUEST_H
+#define __CVC4__LOGIC_REQUEST_H
+
+#include "expr/kind.h"
+#include "smt/smt_engine.h"
+
+namespace CVC4 {
+
+class LogicRequest {
+ /** The SmtEngine at play. */
+ SmtEngine& d_smt;
+
+public:
+ LogicRequest(SmtEngine& smt) : d_smt(smt) { }
+
+ /** Widen the logic to include the given theory. */
+ void widenLogic(theory::TheoryId id) {
+ d_smt.d_logic.getUnlockedCopy();
+ d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
+ d_smt.d_logic.enableTheory(id);
+ d_smt.d_logic.lock();
+ }
+
+};/* class LogicRequest */
+
+}/* CVC4 namespace */
+
+#endif /* __CVC4__LOGIC_REQUEST_H */
diff --git a/src/smt/options b/src/smt/options
index b76822caf..f3429287f 100644
--- a/src/smt/options
+++ b/src/smt/options
@@ -5,11 +5,14 @@
module SMT "smt/options.h" SMT layer
-common-option - --dump=MODE argument :handler CVC4::smt::dumpMode :handler-include "smt/options_handlers.h"
+common-option - dump --dump=MODE argument :handler CVC4::smt::dumpMode :handler-include "smt/options_handlers.h"
dump preprocessed assertions, etc., see --dump=help
-common-option - --dump-to=FILE argument :handler CVC4::smt::dumpToFile :handler-include "smt/options_handlers.h"
+common-option - dump-to --dump-to=FILE argument :handler CVC4::smt::dumpToFile :handler-include "smt/options_handlers.h"
all dumping goes to FILE (instead of stdout)
+expert-option forceLogic force-logic --force-logic=LOGIC LogicInfo :include "theory/logic_info.h" :handler CVC4::smt::stringToLogicInfo :handler-include "smt/options_handlers.h" :default '""'
+ set the logic, and override all further user attempts to change it
+
option simplificationMode simplification-mode --simplification=MODE SimplificationMode :handler CVC4::smt::stringToSimplificationMode :default SIMPLIFICATION_MODE_BATCH :read-write :include "smt/simplification_mode.h" :handler-include "smt/options_handlers.h"
choose simplification mode, see --simplification=help
alias --no-simplification = --simplification=none
@@ -40,7 +43,7 @@ option produceAssignments produce-assignments --produce-assignments bool :defaul
# This could go in src/main/options, but by SMT-LIBv2 spec, "interactive"
# is a mode in which the assertion list must be kept. So it belongs here.
-common-option interactive interactive-mode --interactive bool :read-write
+common-option interactive interactive-mode --interactive bool :predicate CVC4::smt::beforeSearch :predicate-include "smt/options_handlers.h" :read-write
force interactive mode
option doITESimp --ite-simp bool :read-write
diff --git a/src/smt/options_handlers.h b/src/smt/options_handlers.h
index c9c3d6345..49f2c7943 100644
--- a/src/smt/options_handlers.h
+++ b/src/smt/options_handlers.h
@@ -257,6 +257,19 @@ inline void dumpMode(std::string option, std::string optarg, SmtEngine* smt) {
#endif /* CVC4_DUMPING */
}
+inline LogicInfo stringToLogicInfo(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
+ try {
+ LogicInfo logic(optarg);
+ if(smt != NULL) {
+ smt->setLogic(logic);
+ }
+ return logic;
+ } catch(IllegalArgumentException& e) {
+ throw OptionException(std::string("invalid logic specification for --force-logic: `") +
+ optarg + "':\n" + e.what());
+ }
+}
+
inline SimplificationMode stringToSimplificationMode(std::string option, std::string optarg, SmtEngine* smt) throw(OptionException) {
if(optarg == "batch") {
return SIMPLIFICATION_MODE_BATCH;
diff --git a/src/smt/smt_engine.cpp b/src/smt/smt_engine.cpp
index 02542b640..328a20c28 100644
--- a/src/smt/smt_engine.cpp
+++ b/src/smt/smt_engine.cpp
@@ -43,6 +43,7 @@
#include "smt/smt_engine.h"
#include "smt/smt_engine_scope.h"
#include "smt/model_postprocessor.h"
+#include "smt/logic_request.h"
#include "theory/theory_engine.h"
#include "theory/bv/theory_bv_rewriter.h"
#include "proof/proof_manager.h"
@@ -80,8 +81,10 @@
#include "util/sort_inference.h"
#include "theory/quantifiers/quant_conflict_find.h"
#include "theory/quantifiers/macros.h"
-#include "theory/datatypes/options.h"
#include "theory/quantifiers/first_order_reasoning.h"
+#include "theory/quantifiers/quantifiers_rewriter.h"
+#include "theory/quantifiers/options.h"
+#include "theory/datatypes/options.h"
#include "theory/strings/theory_strings_preprocess.h"
using namespace std;
@@ -306,44 +309,6 @@ class SmtEnginePrivate : public NodeManagerListener {
*/
hash_map<Node, Node, NodeHashFunction> d_abstractValues;
- /**
- * Function symbol used to implement uninterpreted undefined string
- * semantics. Needed to deal with partial charat/substr function.
- */
- Node d_ufSubstr;
-
- /**
- * Function symbol used to implement uninterpreted undefined string
- * semantics. Needed to deal with partial str2int function.
- */
- Node d_ufS2I;
-
- /**
- * Function symbol used to implement uninterpreted division-by-zero
- * semantics. Needed to deal with partial division function ("/").
- */
- Node d_divByZero;
-
- /**
- * Maps from bit-vector width to divison-by-zero uninterpreted
- * function symbols.
- */
- hash_map<unsigned, Node> d_BVDivByZero;
- hash_map<unsigned, Node> d_BVRemByZero;
-
- /**
- * Function symbol used to implement uninterpreted
- * int-division-by-zero semantics. Needed to deal with partial
- * function "div".
- */
- Node d_intDivByZero;
-
- /**
- * Function symbol used to implement uninterpreted mod-zero
- * semantics. Needed to deal with partial function "mod".
- */
- Node d_modZero;
-
/** Number of calls of simplify assertions active.
*/
unsigned d_simplifyAssertionsDepth;
@@ -446,9 +411,6 @@ public:
d_fakeContext(),
d_abstractValueMap(&d_fakeContext),
d_abstractValues(),
- d_divByZero(),
- d_intDivByZero(),
- d_modZero(),
d_simplifyAssertionsDepth(0),
d_iteSkolemMap(),
d_iteRemover(smt.d_userContext),
@@ -552,25 +514,6 @@ public:
throw(TypeCheckingException, LogicException);
/**
- * Return the uinterpreted function symbol corresponding to division-by-zero
- * for this particular bit-width
- * @param k should be UREM or UDIV
- * @param width
- *
- * @return
- */
- Node getBVDivByZero(Kind k, unsigned width);
-
- /**
- * Returns the node modeling the division-by-zero semantics of node n.
- *
- * @param n
- *
- * @return
- */
- Node expandBVDivByZero(TNode n);
-
- /**
* Expand definitions in n.
*/
Node expandDefinitions(TNode n, hash_map<Node, Node, NodeHashFunction>& cache)
@@ -596,11 +539,6 @@ public:
}
/**
- * Pre-skolemize quantifiers.
- */
- Node preSkolemizeQuantifiers(Node n, bool polarity, std::vector<Node>& fvs);
-
- /**
* Substitute away all AbstractValues in a node.
*/
Node substituteAbstractValues(TNode n) {
@@ -736,6 +674,9 @@ SmtEngine::SmtEngine(ExprManager* em) throw() :
}
void SmtEngine::finishInit() {
+ // ensure that our heuristics are properly set up
+ setDefaults();
+
d_decisionEngine = new DecisionEngine(d_context, d_userContext);
d_decisionEngine->init(); // enable appropriate strategies
@@ -793,24 +734,7 @@ void SmtEngine::finalOptionsAreSet() {
return;
}
- if(options::bitvectorEagerBitblast()) {
- // Eager solver should use the internal decision strategy
- options::decisionMode.set(DECISION_STRATEGY_INTERNAL);
- }
-
- if(options::checkModels()) {
- if(! options::interactive()) {
- Notice() << "SmtEngine: turning on interactive-mode to support check-models" << endl;
- setOption("interactive-mode", SExpr("true"));
- }
- }
- if(options::produceAssignments() && !options::produceModels()) {
- Notice() << "SmtEngine: turning on produce-models to support produce-assignments" << endl;
- setOption("produce-models", SExpr("true"));
- }
-
if(! d_logic.isLocked()) {
- // ensure that our heuristics are properly set up
setLogicInternal();
}
@@ -925,15 +849,68 @@ LogicInfo SmtEngine::getLogicInfo() const {
return d_logic;
}
-// This function is called when d_logic has just been changed.
-// The LogicInfo isn't passed in explicitly, because that might
-// tempt people in the code to use the (potentially unlocked)
-// version that's passed in, leading to assert-fails in certain
-// uses of the CVC4 library.
void SmtEngine::setLogicInternal() throw() {
Assert(!d_fullyInited, "setting logic in SmtEngine but the engine has already finished initializing for this run");
-
d_logic.lock();
+}
+
+void SmtEngine::setDefaults() {
+ if(options::forceLogic.wasSetByUser()) {
+ d_logic = options::forceLogic();
+ }
+
+ // set strings-exp
+ if(!d_logic.hasEverything() && d_logic.isTheoryEnabled(THEORY_STRINGS) ) {
+ if(! options::stringExp.wasSetByUser()) {
+ options::stringExp.set( true );
+ Trace("smt") << "turning on strings-exp, for the theory of strings" << std::endl;
+ }
+ }
+ // for strings
+ if(options::stringExp()) {
+ if( !d_logic.isQuantified() ) {
+ d_logic = d_logic.getUnlockedCopy();
+ d_logic.enableQuantifiers();
+ d_logic.lock();
+ Trace("smt") << "turning on quantifier logic, for strings-exp" << std::endl;
+ }
+ if(! options::finiteModelFind.wasSetByUser()) {
+ options::finiteModelFind.set( true );
+ Trace("smt") << "turning on finite-model-find, for strings-exp" << std::endl;
+ }
+ if(! options::fmfBoundInt.wasSetByUser()) {
+ options::fmfBoundInt.set( true );
+ Trace("smt") << "turning on fmf-bound-int, for strings-exp" << std::endl;
+ }
+ /*
+ if(! options::rewriteDivk.wasSetByUser()) {
+ options::rewriteDivk.set( true );
+ Trace("smt") << "turning on rewrite-divk, for strings-exp" << std::endl;
+ }*/
+ /*
+ if(! options::stringFMF.wasSetByUser()) {
+ options::stringFMF.set( true );
+ Trace("smt") << "turning on strings-fmf, for strings-exp" << std::endl;
+ }
+ */
+ }
+
+ if(options::bitvectorEagerBitblast()) {
+ // Eager solver should use the internal decision strategy
+ options::decisionMode.set(DECISION_STRATEGY_INTERNAL);
+ }
+
+ if(options::checkModels()) {
+ if(! options::interactive()) {
+ Notice() << "SmtEngine: turning on interactive-mode to support check-models" << endl;
+ setOption("interactive-mode", SExpr("true"));
+ }
+ }
+
+ if(options::produceAssignments() && !options::produceModels()) {
+ Notice() << "SmtEngine: turning on produce-models to support produce-assignments" << endl;
+ setOption("produce-models", SExpr("true"));
+ }
// Set the options for the theoryOf
if(!options::theoryOfMode.wasSetByUser()) {
@@ -966,7 +943,7 @@ void SmtEngine::setLogicInternal() throw() {
options::fmfBoundInt.set( true );
Trace("smt") << "turning on fmf-bound-int, for strings-exp" << std::endl;
}
- /*
+ /*
if(! options::rewriteDivk.wasSetByUser()) {
options::rewriteDivk.set( true );
Trace("smt") << "turning on rewrite-divk, for strings-exp" << std::endl;
@@ -1068,7 +1045,7 @@ void SmtEngine::setLogicInternal() throw() {
if(! options::unconstrainedSimp.wasSetByUser() || options::incrementalSolving()) {
// bool qf_sat = d_logic.isPure(THEORY_BOOL) && !d_logic.isQuantified();
// bool uncSimp = false && !qf_sat && !options::incrementalSolving();
- bool uncSimp = !options::incrementalSolving() && !d_logic.isQuantified() && !options::produceModels() && !options::checkModels() &&
+ bool uncSimp = !options::incrementalSolving() && !d_logic.isQuantified() && !options::produceModels() && !options::produceAssignments() && !options::checkModels() &&
(d_logic.isTheoryEnabled(THEORY_ARRAY) && d_logic.isTheoryEnabled(THEORY_BV));
Trace("smt") << "setting unconstrained simplification to " << uncSimp << endl;
options::unconstrainedSimp.set(uncSimp);
@@ -1079,6 +1056,10 @@ void SmtEngine::setLogicInternal() throw() {
Notice() << "SmtEngine: turning off produce-models to support unconstrainedSimp" << endl;
setOption("produce-models", SExpr("false"));
}
+ if (options::produceAssignments()) {
+ Notice() << "SmtEngine: turning off produce-assignments to support unconstrainedSimp" << endl;
+ setOption("produce-assignments", SExpr("false"));
+ }
if (options::checkModels()) {
Notice() << "SmtEngine: turning off check-models to support unconstrainedSimp" << endl;
setOption("check-models", SExpr("false"));
@@ -1188,7 +1169,7 @@ void SmtEngine::setLogicInternal() throw() {
//instantiate only on last call
if( options::fmfInstEngine() ){
Trace("smt") << "setting inst when mode to LAST_CALL" << endl;
- options::instWhenMode.set( INST_WHEN_LAST_CALL );
+ options::instWhenMode.set( quantifiers::INST_WHEN_LAST_CALL );
}
}
if ( options::fmfBoundInt() ){
@@ -1214,7 +1195,7 @@ void SmtEngine::setLogicInternal() throw() {
//until bugs 371,431 are fixed
if( ! options::minisatUseElim.wasSetByUser()){
- if( d_logic.isQuantified() || options::produceModels() || options::checkModels() ){
+ if( d_logic.isQuantified() || options::produceModels() || options::produceAssignments() || options::checkModels() ){
options::minisatUseElim.set( false );
}
}
@@ -1223,6 +1204,10 @@ void SmtEngine::setLogicInternal() throw() {
Notice() << "SmtEngine: turning off produce-models to support minisatUseElim" << endl;
setOption("produce-models", SExpr("false"));
}
+ if (options::produceAssignments()) {
+ Notice() << "SmtEngine: turning off produce-assignments to support minisatUseElim" << endl;
+ setOption("produce-assignments", SExpr("false"));
+ }
if (options::checkModels()) {
Notice() << "SmtEngine: turning off check-models to support minisatUseElim" << endl;
setOption("check-models", SExpr("false"));
@@ -1230,7 +1215,7 @@ void SmtEngine::setLogicInternal() throw() {
}
// For now, these array theory optimizations do not support model-building
- if (options::produceModels() || options::checkModels()) {
+ if (options::produceModels() || options::produceAssignments() || options::checkModels()) {
options::arraysOptimizeLinear.set(false);
options::arraysLazyRIntro1.set(false);
}
@@ -1242,6 +1227,10 @@ void SmtEngine::setLogicInternal() throw() {
Warning() << "SmtEngine: turning off produce-models because unsupported for nonlinear arith" << endl;
setOption("produce-models", SExpr("false"));
}
+ if (options::produceAssignments()) {
+ Warning() << "SmtEngine: turning off produce-assignments because unsupported for nonlinear arith" << endl;
+ setOption("produce-assignments", SExpr("false"));
+ }
if (options::checkModels()) {
Warning() << "SmtEngine: turning off check-models because unsupported for nonlinear arith" << endl;
setOption("check-models", SExpr("false"));
@@ -1470,55 +1459,6 @@ void SmtEngine::defineFunction(Expr func,
}
-Node SmtEnginePrivate::getBVDivByZero(Kind k, unsigned width) {
- NodeManager* nm = d_smt.d_nodeManager;
- if (k == kind::BITVECTOR_UDIV) {
- if (d_BVDivByZero.find(width) == d_BVDivByZero.end()) {
- // lazily create the function symbols
- 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;
- }
- return d_BVDivByZero[width];
- }
- else if (k == kind::BITVECTOR_UREM) {
- if (d_BVRemByZero.find(width) == d_BVRemByZero.end()) {
- 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;
- }
- return d_BVRemByZero[width];
- }
-
- Unreachable();
-}
-
-
-Node SmtEnginePrivate::expandBVDivByZero(TNode n) {
- // we only deal wioth the unsigned division operators as the signed ones should have been
- // expanded in terms of the unsigned operators
- NodeManager* nm = d_smt.d_nodeManager;
- unsigned width = n.getType().getBitVectorSize();
- Node divByZero = getBVDivByZero(n.getKind(), width);
- TNode num = n[0], den = n[1];
- Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(BitVector(width, Integer(0))));
- Node divByZeroNum = nm->mkNode(kind::APPLY_UF, divByZero, num);
- Node divTotalNumDen = nm->mkNode(n.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_UDIV_TOTAL :
- kind::BITVECTOR_UREM_TOTAL, num, den);
- Node node = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
- if(!d_smt.d_logic.isTheoryEnabled(THEORY_UF)) {
- d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
- d_smt.d_logic.enableTheory(THEORY_UF);
- d_smt.d_logic.lock();
- }
- return node;
-}
Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashFunction>& cache)
@@ -1527,31 +1467,36 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashF
stack< triple<Node, Node, bool> > worklist;
stack<Node> result;
worklist.push(make_triple(Node(n), Node(n), false));
+ // The worklist is made of triples, each is input / original node then the output / rewritten node
+ // and finally a flag tracking whether the children have been explored (i.e. if this is a downward
+ // or upward pass).
do {
- n = worklist.top().first;
- Node node = worklist.top().second;
+ n = worklist.top().first; // n is the input / original
+ Node node = worklist.top().second; // node is the output / result
bool childrenPushed = worklist.top().third;
worklist.pop();
+ // Working downwards
if(!childrenPushed) {
Kind k = n.getKind();
+ // Apart from apply, we can short circuit leaves
if(k != kind::APPLY && n.getNumChildren() == 0) {
- SmtEngine::DefinedFunctionMap::const_iterator i = d_smt.d_definedFunctions->find(n);
- if(i != d_smt.d_definedFunctions->end()) {
- // replacement must be closed
- if((*i).second.getFormals().size() > 0) {
- result.push(d_smt.d_nodeManager->mkNode(kind::LAMBDA, d_smt.d_nodeManager->mkNode(kind::BOUND_VAR_LIST, (*i).second.getFormals()), (*i).second.getFormula()));
- continue;
- }
- // don't bother putting in the cache
- result.push((*i).second.getFormula());
- continue;
- }
- // don't bother putting in the cache
- result.push(n);
- continue;
+ SmtEngine::DefinedFunctionMap::const_iterator i = d_smt.d_definedFunctions->find(n);
+ if(i != d_smt.d_definedFunctions->end()) {
+ // replacement must be closed
+ if((*i).second.getFormals().size() > 0) {
+ result.push(d_smt.d_nodeManager->mkNode(kind::LAMBDA, d_smt.d_nodeManager->mkNode(kind::BOUND_VAR_LIST, (*i).second.getFormals()), (*i).second.getFormula()));
+ continue;
+ }
+ // don't bother putting in the cache
+ result.push((*i).second.getFormula());
+ continue;
+ }
+ // don't bother putting in the cache
+ result.push(n);
+ continue;
}
// maybe it's in the cache
@@ -1563,134 +1508,7 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashF
}
// otherwise expand it
-
- NodeManager* nm = d_smt.d_nodeManager;
- // FIXME: this theory-specific code should be factored out of the
- // SmtEngine, somehow
- switch(k) {
- case kind::BITVECTOR_SDIV:
- case kind::BITVECTOR_SREM:
- case kind::BITVECTOR_SMOD:
- node = bv::TheoryBVRewriter::eliminateBVSDiv(node);
- break;
-
- case kind::BITVECTOR_UDIV:
- case kind::BITVECTOR_UREM:
- node = expandBVDivByZero(node);
- break;
-
- case kind::STRING_CHARAT: {
- if(d_ufSubstr.isNull()) {
- std::vector< TypeNode > argTypes;
- argTypes.push_back(NodeManager::currentNM()->stringType());
- argTypes.push_back(NodeManager::currentNM()->integerType());
- argTypes.push_back(NodeManager::currentNM()->integerType());
- d_ufSubstr = NodeManager::currentNM()->mkSkolem("__ufSS",
- NodeManager::currentNM()->mkFunctionType(
- argTypes, NodeManager::currentNM()->stringType()),
- "uf substr",
- NodeManager::SKOLEM_EXACT_NAME);
- }
- Node lenxgti = NodeManager::currentNM()->mkNode( kind::GT,
- NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n[0] ), n[1] );
- Node zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
- Node t1greq0 = NodeManager::currentNM()->mkNode( kind::GEQ, n[1], zero);
- Node cond = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, lenxgti, t1greq0 ));
- Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
- Node totalf = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, n[0], n[1], one);
- Node uf = NodeManager::currentNM()->mkNode(kind::APPLY_UF, d_ufSubstr, n[0], n[1], one);
- node = NodeManager::currentNM()->mkNode( kind::ITE, cond, totalf, uf );
- break;
- }
- case kind::STRING_SUBSTR: {
- if(d_ufSubstr.isNull()) {
- std::vector< TypeNode > argTypes;
- argTypes.push_back(NodeManager::currentNM()->stringType());
- argTypes.push_back(NodeManager::currentNM()->integerType());
- argTypes.push_back(NodeManager::currentNM()->integerType());
- d_ufSubstr = NodeManager::currentNM()->mkSkolem("__ufSS",
- NodeManager::currentNM()->mkFunctionType(
- argTypes, NodeManager::currentNM()->stringType()),
- "uf substr",
- NodeManager::SKOLEM_EXACT_NAME);
- }
- Node lenxgti = NodeManager::currentNM()->mkNode( kind::GEQ,
- NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n[0] ),
- NodeManager::currentNM()->mkNode( kind::PLUS, n[1], n[2] ) );
- Node zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
- Node t1geq0 = NodeManager::currentNM()->mkNode(kind::GEQ, n[1], zero);
- Node t2geq0 = NodeManager::currentNM()->mkNode(kind::GEQ, n[2], zero);
- Node cond = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, lenxgti, t1geq0, t2geq0 ));
- Node totalf = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, n[0], n[1], n[2]);
- Node uf = NodeManager::currentNM()->mkNode(kind::APPLY_UF, d_ufSubstr, n[0], n[1], n[2]);
- node = NodeManager::currentNM()->mkNode( kind::ITE, cond, totalf, uf );
- break;
- }
- case kind::DIVISION: {
- // partial function: division
- if(d_divByZero.isNull()) {
- d_divByZero = nm->mkSkolem("divByZero", nm->mkFunctionType(nm->realType(), nm->realType()),
- "partial real division", NodeManager::SKOLEM_EXACT_NAME);
- if(!d_smt.d_logic.isTheoryEnabled(THEORY_UF)) {
- d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
- d_smt.d_logic.enableTheory(THEORY_UF);
- d_smt.d_logic.lock();
- }
- }
- TNode num = n[0], den = n[1];
- Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
- Node divByZeroNum = nm->mkNode(kind::APPLY_UF, d_divByZero, num);
- Node divTotalNumDen = nm->mkNode(kind::DIVISION_TOTAL, num, den);
- node = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
- break;
- }
-
- case kind::INTS_DIVISION: {
- // partial function: integer div
- if(d_intDivByZero.isNull()) {
- d_intDivByZero = nm->mkSkolem("intDivByZero", nm->mkFunctionType(nm->integerType(), nm->integerType()),
- "partial integer division", NodeManager::SKOLEM_EXACT_NAME);
- if(!d_smt.d_logic.isTheoryEnabled(THEORY_UF)) {
- d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
- d_smt.d_logic.enableTheory(THEORY_UF);
- d_smt.d_logic.lock();
- }
- }
- TNode num = n[0], den = n[1];
- Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
- Node intDivByZeroNum = nm->mkNode(kind::APPLY_UF, d_intDivByZero, num);
- Node intDivTotalNumDen = nm->mkNode(kind::INTS_DIVISION_TOTAL, num, den);
- node = nm->mkNode(kind::ITE, den_eq_0, intDivByZeroNum, intDivTotalNumDen);
- break;
- }
-
- case kind::INTS_MODULUS: {
- // partial function: mod
- if(d_modZero.isNull()) {
- d_modZero = nm->mkSkolem("modZero", nm->mkFunctionType(nm->integerType(), nm->integerType()),
- "partial modulus", NodeManager::SKOLEM_EXACT_NAME);
- if(!d_smt.d_logic.isTheoryEnabled(THEORY_UF)) {
- d_smt.d_logic = d_smt.d_logic.getUnlockedCopy();
- d_smt.d_logic.enableTheory(THEORY_UF);
- d_smt.d_logic.lock();
- }
- }
- TNode num = n[0], den = n[1];
- Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
- Node modZeroNum = nm->mkNode(kind::APPLY_UF, d_modZero, num);
- Node modTotalNumDen = nm->mkNode(kind::INTS_MODULUS_TOTAL, num, den);
- node = nm->mkNode(kind::ITE, den_eq_0, modZeroNum, modTotalNumDen);
- break;
- }
-
- case kind::ABS: {
- Node out = nm->mkNode(kind::ITE, nm->mkNode(kind::LT, node[0], nm->mkConst(Rational(0))), nm->mkNode(kind::UMINUS, node[0]), node[0]);
- cache[n] = out;
- result.push(out);
- continue;
- }
-
- case kind::APPLY: {
+ if (k == kind::APPLY) {
// application of a user-defined symbol
TNode func = n.getOperator();
SmtEngine::DefinedFunctionMap::const_iterator i =
@@ -1729,25 +1547,35 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashF
cache[n] = (n == expanded ? Node::null() : expanded);
result.push(expanded);
continue;
- }
- default:
- // unknown kind for expansion, just iterate over the children
- node = n;
+ } else {
+ theory::Theory* t = d_smt.d_theoryEngine->theoryOf(node);
+
+ Assert(t != NULL);
+ LogicRequest req(d_smt);
+ node = t->expandDefinition(req, n);
}
// there should be children here, otherwise we short-circuited a result-push/continue, above
+ if (node.getNumChildren() == 0) {
+ Debug("expand") << "Unexpectedly no children..." << node << endl;
+ }
+ // This invariant holds at the moment but it is concievable that a new theory
+ // might introduce a kind which can have children before definition expansion but doesn't
+ // afterwards. If this happens, remove this assertion.
Assert(node.getNumChildren() > 0);
// the partial functions can fall through, in which case we still
// consider their children
- worklist.push(make_triple(Node(n), node, true));
+ worklist.push(make_triple(Node(n), node, true)); // Original and rewritten result
for(size_t i = 0; i < node.getNumChildren(); ++i) {
- worklist.push(make_triple(node[i], node[i], false));
+ worklist.push(make_triple(node[i], node[i], false)); // Rewrite the children of the result only
}
} else {
+ // Working upwards
+ // Reconstruct the node from it's (now rewritten) children on the stack
Debug("expand") << "cons : " << node << endl;
//cout << "cons : " << node << endl;
@@ -1766,7 +1594,7 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashF
nb << expanded;
}
node = nb;
- cache[n] = n == node ? Node::null() : node;
+ cache[n] = n == node ? Node::null() : node; // Only cache once all subterms are expanded
result.push(node);
}
} while(!worklist.empty());
@@ -1776,120 +1604,6 @@ Node SmtEnginePrivate::expandDefinitions(TNode n, hash_map<Node, Node, NodeHashF
return result.top();
}
-
-struct ContainsQuantAttributeId {};
-typedef expr::Attribute<ContainsQuantAttributeId, uint64_t> ContainsQuantAttribute;
-
-// check if the given node contains a universal quantifier
-static bool containsQuantifiers(Node n) {
- if( n.hasAttribute(ContainsQuantAttribute()) ){
- return n.getAttribute(ContainsQuantAttribute())==1;
- } else if(n.getKind() == kind::FORALL) {
- return true;
- } else {
- bool cq = false;
- for( unsigned i = 0; i < n.getNumChildren(); ++i ){
- if( containsQuantifiers(n[i]) ){
- cq = true;
- break;
- }
- }
- ContainsQuantAttribute cqa;
- n.setAttribute(cqa, cq ? 1 : 0);
- return cq;
- }
-}
-
-Node SmtEnginePrivate::preSkolemizeQuantifiers( Node n, bool polarity, std::vector< Node >& fvs ){
- Trace("pre-sk") << "Pre-skolem " << n << " " << polarity << " " << fvs.size() << endl;
- if( n.getKind()==kind::NOT ){
- Node nn = preSkolemizeQuantifiers( n[0], !polarity, fvs );
- return nn.negate();
- }else if( n.getKind()==kind::FORALL ){
- if( polarity ){
- vector< Node > children;
- children.push_back( n[0] );
- //add children to current scope
- vector< Node > fvss;
- fvss.insert( fvss.begin(), fvs.begin(), fvs.end() );
- for( int i=0; i<(int)n[0].getNumChildren(); i++ ){
- fvss.push_back( n[0][i] );
- }
- //process body
- children.push_back( preSkolemizeQuantifiers( n[1], polarity, fvss ) );
- if( n.getNumChildren()==3 ){
- children.push_back( n[2] );
- }
- //return processed quantifier
- return NodeManager::currentNM()->mkNode( kind::FORALL, children );
- }else{
- //process body
- Node nn = preSkolemizeQuantifiers( n[1], polarity, fvs );
- //now, substitute skolems for the variables
- vector< TypeNode > argTypes;
- for( int i=0; i<(int)fvs.size(); i++ ){
- argTypes.push_back( fvs[i].getType() );
- }
- //calculate the variables and substitution
- vector< Node > vars;
- vector< Node > subs;
- for( int i=0; i<(int)n[0].getNumChildren(); i++ ){
- vars.push_back( n[0][i] );
- }
- for( int i=0; i<(int)n[0].getNumChildren(); i++ ){
- //make the new function symbol
- if( argTypes.empty() ){
- Node s = NodeManager::currentNM()->mkSkolem( "sk_$$", n[0][i].getType(), "created during pre-skolemization" );
- subs.push_back( s );
- }else{
- TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, n[0][i].getType() );
- Node op = NodeManager::currentNM()->mkSkolem( "skop_$$", typ, "op created during pre-skolemization" );
- //DOTHIS: set attribute on op, marking that it should not be selected as trigger
- vector< Node > funcArgs;
- funcArgs.push_back( op );
- funcArgs.insert( funcArgs.end(), fvs.begin(), fvs.end() );
- subs.push_back( NodeManager::currentNM()->mkNode( kind::APPLY_UF, funcArgs ) );
- }
- }
- //apply substitution
- nn = nn.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
- return nn;
- }
- }else{
- //check if it contains a quantifier as a subterm
- //if so, we will write this node
- if( containsQuantifiers( n ) ){
- if( n.getType().isBoolean() ){
- if( n.getKind()==kind::ITE || n.getKind()==kind::IFF || n.getKind()==kind::XOR || n.getKind()==kind::IMPLIES ){
- Node nn;
- //must remove structure
- if( n.getKind()==kind::ITE ){
- nn = NodeManager::currentNM()->mkNode( kind::AND,
- NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n[1] ),
- NodeManager::currentNM()->mkNode( kind::OR, n[0], n[2] ) );
- }else if( n.getKind()==kind::IFF || n.getKind()==kind::XOR ){
- nn = NodeManager::currentNM()->mkNode( kind::AND,
- NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n.getKind()==kind::XOR ? n[1].notNode() : n[1] ),
- NodeManager::currentNM()->mkNode( kind::OR, n[0], n.getKind()==kind::XOR ? n[1] : n[1].notNode() ) );
- }else if( n.getKind()==kind::IMPLIES ){
- nn = NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n[1] );
- }
- return preSkolemizeQuantifiers( nn, polarity, fvs );
- }else if( n.getKind()==kind::AND || n.getKind()==kind::OR ){
- vector< Node > children;
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- children.push_back( preSkolemizeQuantifiers( n[i], polarity, fvs ) );
- }
- return NodeManager::currentNM()->mkNode( n.getKind(), children );
- }else{
- //must pull ite's
- }
- }
- }
- return n;
- }
-}
-
void SmtEnginePrivate::removeITEs() {
d_smt.finalOptionsAreSet();
@@ -3156,13 +2870,25 @@ void SmtEnginePrivate::processAssertions() {
dumpAssertions("post-strings-pp", d_assertionsToPreprocess);
}
if( d_smt.d_logic.isQuantified() ){
+ //remove rewrite rules
+ for( unsigned i=0; i < d_assertionsToPreprocess.size(); i++ ) {
+ if( d_assertionsToPreprocess[i].getKind() == kind::REWRITE_RULE ){
+ Node prev = d_assertionsToPreprocess[i];
+ Trace("quantifiers-rewrite-debug") << "Rewrite rewrite rule " << prev << "..." << std::endl;
+ d_assertionsToPreprocess[i] = Rewriter::rewrite( quantifiers::QuantifiersRewriter::rewriteRewriteRule( d_assertionsToPreprocess[i] ) );
+ Trace("quantifiers-rewrite") << "*** rr-rewrite " << prev << endl;
+ Trace("quantifiers-rewrite") << " ...got " << d_assertionsToPreprocess[i] << endl;
+ }
+ }
+
dumpAssertions("pre-skolem-quant", d_assertionsToPreprocess);
if( options::preSkolemQuant() ){
//apply pre-skolemization to existential quantifiers
for (unsigned i = 0; i < d_assertionsToPreprocess.size(); ++ i) {
Node prev = d_assertionsToPreprocess[i];
+ Trace("quantifiers-rewrite-debug") << "Pre-skolemize " << prev << "..." << std::endl;
vector< Node > fvs;
- d_assertionsToPreprocess[i] = Rewriter::rewrite( preSkolemizeQuantifiers( d_assertionsToPreprocess[i], true, fvs ) );
+ d_assertionsToPreprocess[i] = Rewriter::rewrite( quantifiers::QuantifiersRewriter::preSkolemizeQuantifiers( prev, true, fvs ) );
if( prev!=d_assertionsToPreprocess[i] ){
Trace("quantifiers-rewrite") << "*** Pre-skolemize " << prev << endl;
Trace("quantifiers-rewrite") << " ...got " << d_assertionsToPreprocess[i] << endl;
@@ -3174,14 +2900,14 @@ void SmtEnginePrivate::processAssertions() {
//quantifiers macro expansion
bool success;
do{
- QuantifierMacros qm;
+ quantifiers::QuantifierMacros qm;
success = qm.simplify( d_assertionsToPreprocess, true );
}while( success );
}
Trace("fo-rsn-enable") << std::endl;
if( options::foPropQuant() ){
- FirstOrderPropagation fop;
+ quantifiers::FirstOrderPropagation fop;
fop.simplify( d_assertionsToPreprocess );
}
}
@@ -3677,8 +3403,15 @@ Expr SmtEngine::getValue(const Expr& ex) const throw(ModalException, TypeCheckin
// Expand, then normalize
hash_map<Node, Node, NodeHashFunction> cache;
n = d_private->expandDefinitions(n, cache);
- n = d_private->rewriteBooleanTerms(n);
- n = Rewriter::rewrite(n);
+ // 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
+ // two are different, but they need to be unified. This ugly hack here
+ // is to fix bug 554 until we can revamp boolean-terms and models [MGD]
+ if(!n.getType().isFunction()) {
+ n = d_private->rewriteBooleanTerms(n);
+ n = Rewriter::rewrite(n);
+ }
Trace("smt") << "--- getting value of " << n << endl;
TheoryModel* m = d_theoryEngine->getModel();
@@ -3970,28 +3703,30 @@ void SmtEngine::checkModel(bool hardFailure) {
Debug("boolean-terms") << "++ got " << n << endl;
Notice() << "SmtEngine::checkModel(): -- substitutes to " << n << endl;
- if(Theory::theoryOf(n) != THEORY_REWRITERULES) {
+ //AJR : FIXME need to ignore quantifiers too?
+ if( n.getKind() != kind::REWRITE_RULE ){
// In case it's a quantifier (or contains one), look up its value before
// simplifying, or the quantifier might be irreparably altered.
n = m->getValue(n);
- }
-
- // Simplify the result.
- n = d_private->simplify(n);
- Notice() << "SmtEngine::checkModel(): -- simplifies to " << n << endl;
-
- TheoryId thy = Theory::theoryOf(n);
- if(thy == THEORY_REWRITERULES) {
+ } else {
// Note this "skip" is done here, rather than above. This is
// because (1) the quantifier could in principle simplify to false,
// which should be reported, and (2) checking for the quantifier
// above, before simplification, doesn't catch buried quantifiers
// anyway (those not at the top-level).
- Notice() << "SmtEngine::checkModel(): -- skipping rewrite-rules assertion"
+ Notice() << "SmtEngine::checkModel(): -- skipping quantifiers/rewrite-rules assertion"
<< endl;
continue;
}
+ // 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;
+
// 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.
diff --git a/src/smt/smt_engine.h b/src/smt/smt_engine.h
index c34d3ecba..2991ab21b 100644
--- a/src/smt/smt_engine.h
+++ b/src/smt/smt_engine.h
@@ -30,7 +30,6 @@
#include "util/proof.h"
#include "smt/modal_exception.h"
#include "smt/logic_exception.h"
-#include "util/hash.h"
#include "options/options.h"
#include "util/result.h"
#include "util/sexpr.h"
@@ -59,6 +58,7 @@ class TheoryEngine;
class ProofManager;
class Model;
+class LogicRequest;
class StatisticsRegistry;
namespace context {
@@ -281,6 +281,12 @@ class CVC4_PUBLIC SmtEngine {
void finalOptionsAreSet();
/**
+ * Apply heuristics settings and other defaults. Done once, at
+ * finishInit() time.
+ */
+ void setDefaults();
+
+ /**
* Create theory engine, prop engine, decision engine. Called by
* finalOptionsAreSet()
*/
@@ -331,6 +337,7 @@ class CVC4_PUBLIC SmtEngine {
friend ::CVC4::StatisticsRegistry* ::CVC4::stats::getStatisticsRegistry(SmtEngine*);
friend void ::CVC4::smt::beforeSearch(std::string, bool, SmtEngine*) throw(ModalException);
friend ProofManager* ::CVC4::smt::currentProofManager();
+ friend class ::CVC4::LogicRequest;
// to access d_modelCommands
friend class ::CVC4::Model;
friend class ::CVC4::theory::TheoryModel;
diff --git a/src/smt/smt_options_template.cpp b/src/smt/smt_options_template.cpp
index 4edd91a8d..987d2e3c7 100644
--- a/src/smt/smt_options_template.cpp
+++ b/src/smt/smt_options_template.cpp
@@ -62,11 +62,15 @@ void SmtEngine::setOption(const std::string& key, const CVC4::SExpr& value)
throw OptionException("command-verbosity value must be a tuple (command-name, integer)");
}
+ if(!value.isAtom()) {
+ throw OptionException("bad value for :" + key);
+ }
+
string optionarg = value.getValue();
${smt_setoption_handlers}
-#line 70 "${template}"
+#line 74 "${template}"
throw UnrecognizedOptionException(key);
}
@@ -126,7 +130,7 @@ CVC4::SExpr SmtEngine::getOption(const std::string& key) const
${smt_getoption_handlers}
-#line 130 "${template}"
+#line 134 "${template}"
throw UnrecognizedOptionException(key);
}
diff --git a/src/theory/arith/approx_simplex.cpp b/src/theory/arith/approx_simplex.cpp
index 1b3099842..9f6b1796e 100644
--- a/src/theory/arith/approx_simplex.cpp
+++ b/src/theory/arith/approx_simplex.cpp
@@ -20,8 +20,12 @@
#include "theory/arith/approx_simplex.h"
#include "theory/arith/normal_form.h"
#include "theory/arith/constraint.h"
+#include "theory/arith/cut_log.h"
+#include "theory/arith/matrix.h"
#include <math.h>
#include <cmath>
+#include <cfloat>
+#include <map>
using namespace std;
@@ -29,13 +33,229 @@ namespace CVC4 {
namespace theory {
namespace arith {
-ApproximateSimplex::ApproximateSimplex() :
- d_pivotLimit(std::numeric_limits<int>::max())
+struct AuxInfo {
+ TreeLog* tl;
+ int pivotLimit;
+ int branchLimit;
+ int branchDepth;
+ MipResult term; /* terminatation */
+};
+
+enum SlackReplace { SlackUndef=0, SlackLB, SlackUB, SlackVLB, SlackVUB };
+
+std::ostream& operator<<(std::ostream& out, MipResult res){
+ switch(res){
+ case MipUnknown:
+ out << "MipUnknown"; break;
+ case MipBingo:
+ out << "MipBingo"; break;
+ case MipClosed:
+ out << "MipClosed"; break;
+ case BranchesExhausted:
+ out << "BranchesExhausted"; break;
+ case PivotsExhauasted:
+ out << "PivotsExhauasted"; break;
+ case ExecExhausted:
+ out << "ExecExhausted"; break;
+ default:
+ out << "Unexpected Mip Value!"; break;
+ }
+ return out;
+}
+struct VirtualBound {
+ // Either x <= d * y or x >= d * y
+ ArithVar x; // variable being bounded
+ Kind k; // either LEQ or GEQ
+ Rational d; // the multiple on y
+ ArithVar y; // the variable that is the upper bound
+ ConstraintP c; // the original constraint relating x and y
+
+ VirtualBound()
+ : x(ARITHVAR_SENTINEL)
+ , k(kind::UNDEFINED_KIND)
+ , d()
+ , y(ARITHVAR_SENTINEL)
+ , c(NullConstraint)
+ {}
+ VirtualBound(ArithVar toBound, Kind rel, const Rational& coeff, ArithVar bounding, ConstraintP orig)
+ : x(toBound)
+ , k(rel)
+ , d(coeff)
+ , y(bounding)
+ , c(orig)
+ { Assert(k == kind::LEQ || k == kind::GEQ); }
+};
+
+struct CutScratchPad {
+ bool d_failure; // if the construction was unsuccessful
+
+ /* GOMORY CUTS Datastructures */
+ ArithVar d_basic; // a variable that is basic in the approximate solver
+ DenseVector d_tabRow; // a row in the tableau not including d_basic, equal to 0
+ DenseMap<ConstraintP> d_toBound; // each variable in toBound maps each variable in tabRow to either an upper/lower bound
+
+ /* MIR CUTS Datastructures */
+ DenseMap<SlackReplace> d_slacks;// The x'[i] selected for x[i]
+ DenseMap<VirtualBound> d_vub; // Virtual upper bounds.
+ DenseMap<VirtualBound> d_vlb; // Virtual lower bounds.
+ DenseMap<Rational> d_compRanges;
+
+ // a sum of rows in the tableau, with possible replacements for fixed
+ // sum aggLhs[i] x[i] = aggRhs;
+ DenseVector d_agg;
+ // Takes agg and replaces x[i] with a slack variable x'[i]
+ // Takes agg and replaces x[i] with a slack variable x'[i]
+ // sum modLhs[i] x'[i] = modRhs;
+ DenseVector d_mod;
+
+ // Takes mod, and performs c-Mir on it
+ // sum alpha[i] x'[i] <= beta
+ DenseVector d_alpha;
+
+ /* The constructed cut */
+ // sum cut[i] x[i] <= cutRhs
+ DenseVector d_cut;
+ Kind d_cutKind;
+
+ /* The constraints used throughout construction. */
+ std::set<ConstraintP> d_explanation; // use pointer equality
+ CutScratchPad(){
+ clear();
+ }
+ void clear(){
+ d_failure = false;
+ d_basic = ARITHVAR_SENTINEL;
+ d_tabRow.purge();
+ d_toBound.purge();
+
+ d_slacks.purge();
+ d_vub.purge();
+ d_vlb.purge();
+ d_compRanges.purge();
+
+ d_agg.purge();
+ d_mod.purge();
+ d_alpha.purge();
+
+ d_cut.purge();
+ d_cutKind = kind::UNDEFINED_KIND;
+ d_explanation.clear();
+ }
+};
+ApproximateStatistics::ApproximateStatistics()
+ // : d_relaxCalls("z::approx::relaxCalls",0)
+ // , d_relaxUnknowns("z::approx::relaxUnknowns",0)
+ // , d_relaxFeasible("z::approx::relaxFeasible",0)
+ // , d_relaxInfeasible("z::approx::relaxInfeasible",0)
+ // , d_relaxPivotsExhausted("z::approx::relaxPivotsExhausted",0)
+ // , d_mipCalls("z::approx::mipCalls",0)
+ // , d_mipUnknowns("z::approx::mipUnknowns",0)
+ // , d_mipBingo("z::approx::mipBingo",0)
+ // , d_mipClosed("z::approx::mipClosed",0)
+ // , d_mipBranchesExhausted("z::approx::mipBranchesExhausted",0)
+ // , d_mipPivotsExhausted("z::approx::mipPivotsExhausted",0)
+ // , d_mipExecExhausted("z::approx::mipExecExhausted",0)
+ // , d_gmiGen("z::approx::gmiGen",0)
+ // , d_gmiReplay("z::approx::gmiReplay",0)
+ // , d_mipGen("z::approx::mipGen",0)
+ // , d_mipReplay("z::approx::mipReplay",0)
+ : d_branchMaxDepth("z::approx::branchMaxDepth",0)
+ , d_branchesMaxOnAVar("z::approx::branchesMaxOnAVar",0)
+ //, d_branchTotal("z::approx::branchTotal",0)
+ //, d_branchCuts("z::approx::branchCuts",0)
+
+ , d_gaussianElimConstructTime("z::approx::gaussianElimConstruct::time")
+ , d_gaussianElimConstruct("z::approx::gaussianElimConstruct::calls",0)
+ , d_averageGuesses("z::approx::averageGuesses")
+{
+ // StatisticsRegistry::registerStat(&d_relaxCalls);
+ // StatisticsRegistry::registerStat(&d_relaxUnknowns);
+ // StatisticsRegistry::registerStat(&d_relaxFeasible);
+ // StatisticsRegistry::registerStat(&d_relaxInfeasible);
+ // StatisticsRegistry::registerStat(&d_relaxPivotsExhausted);
+
+ // StatisticsRegistry::registerStat(&d_mipCalls);
+ // StatisticsRegistry::registerStat(&d_mipUnknowns);
+ // StatisticsRegistry::registerStat(&d_mipBingo);
+ // StatisticsRegistry::registerStat(&d_mipClosed);
+ // StatisticsRegistry::registerStat(&d_mipBranchesExhausted);
+ // StatisticsRegistry::registerStat(&d_mipPivotsExhausted);
+ // StatisticsRegistry::registerStat(&d_mipExecExhausted);
+
+
+ // StatisticsRegistry::registerStat(&d_gmiGen);
+ // StatisticsRegistry::registerStat(&d_gmiReplay);
+ // StatisticsRegistry::registerStat(&d_mipGen);
+ // StatisticsRegistry::registerStat(&d_mipReplay);
+
+ StatisticsRegistry::registerStat(&d_branchMaxDepth);
+ //StatisticsRegistry::registerStat(&d_branchTotal);
+ //StatisticsRegistry::registerStat(&d_branchCuts);
+ StatisticsRegistry::registerStat(&d_branchesMaxOnAVar);
+
+ StatisticsRegistry::registerStat(&d_gaussianElimConstructTime);
+ StatisticsRegistry::registerStat(&d_gaussianElimConstruct);
+
+ StatisticsRegistry::registerStat(&d_averageGuesses);
+}
+
+ApproximateStatistics::~ApproximateStatistics(){
+ // StatisticsRegistry::unregisterStat(&d_relaxCalls);
+ // StatisticsRegistry::unregisterStat(&d_relaxUnknowns);
+ // StatisticsRegistry::unregisterStat(&d_relaxFeasible);
+ // StatisticsRegistry::unregisterStat(&d_relaxInfeasible);
+ // StatisticsRegistry::unregisterStat(&d_relaxPivotsExhausted);
+
+ // StatisticsRegistry::unregisterStat(&d_mipCalls);
+ // StatisticsRegistry::unregisterStat(&d_mipUnknowns);
+ // StatisticsRegistry::unregisterStat(&d_mipBingo);
+ // StatisticsRegistry::unregisterStat(&d_mipClosed);
+ // StatisticsRegistry::unregisterStat(&d_mipBranchesExhausted);
+ // StatisticsRegistry::unregisterStat(&d_mipPivotsExhausted);
+ // StatisticsRegistry::unregisterStat(&d_mipExecExhausted);
+
+
+ // StatisticsRegistry::unregisterStat(&d_gmiGen);
+ // StatisticsRegistry::unregisterStat(&d_gmiReplay);
+ // StatisticsRegistry::unregisterStat(&d_mipGen);
+ // StatisticsRegistry::unregisterStat(&d_mipReplay);
+
+ StatisticsRegistry::unregisterStat(&d_branchMaxDepth);
+ //StatisticsRegistry::unregisterStat(&d_branchTotal);
+ //StatisticsRegistry::unregisterStat(&d_branchCuts);
+ StatisticsRegistry::unregisterStat(&d_branchesMaxOnAVar);
+
+ StatisticsRegistry::unregisterStat(&d_gaussianElimConstructTime);
+ StatisticsRegistry::unregisterStat(&d_gaussianElimConstruct);
+
+ StatisticsRegistry::unregisterStat(&d_averageGuesses);
+}
+
+Integer ApproximateSimplex::s_defaultMaxDenom(1<<26);
+
+ApproximateSimplex::ApproximateSimplex(const ArithVariables& v, TreeLog& l,
+ ApproximateStatistics& s)
+ : d_vars(v)
+ , d_log(l)
+ , d_stats(s)
+ , d_pivotLimit(std::numeric_limits<int>::max())
+ , d_branchLimit(std::numeric_limits<int>::max())
+ , d_maxDepth(std::numeric_limits<int>::max())
{}
-void ApproximateSimplex::setPivotLimit(int pivotLimit){
- Assert(pivotLimit >= 0);
- d_pivotLimit = pivotLimit;
+void ApproximateSimplex::setPivotLimit(int pl){
+ Assert(pl >= 0);
+ d_pivotLimit = pl;
+}
+
+void ApproximateSimplex::setBranchingDepth(int bd){
+ Assert(bd >= 0);
+ d_maxDepth = bd;
+}
+
+void ApproximateSimplex::setBranchOnVariableLimit(int bl){
+ Assert(bl >= 0);
+ d_branchLimit = bl;
}
const double ApproximateSimplex::SMALL_FIXED_DELTA = .000000001;
@@ -77,7 +297,7 @@ std::vector<Integer> ApproximateSimplex::rationalToCfe(const Rational& q, int de
mods.push_back(Integer());
Integer& back = mods.back();
back = carry.floor();
- //cout << " cfe["<<i<<"]: " << back << endl;
+ Debug("rationalToCfe") << " cfe["<<i<<"]: " << back << endl;
carry -= back;
if(carry.isZero()){
break;
@@ -91,24 +311,85 @@ std::vector<Integer> ApproximateSimplex::rationalToCfe(const Rational& q, int de
return mods;
}
-Rational ApproximateSimplex::estimateWithCFE(const Rational& q, int depth){
- std::vector<Integer> cfe = rationalToCfe(q,depth);
- return cfeToRational(cfe);
+
+Rational ApproximateSimplex::estimateWithCFE(const Rational& r, const Integer& K){
+ Debug("estimateWithCFE") << "estimateWithCFE(" << r << ", " << K << ")" <<endl;
+ // references
+ // page 4: http://carlossicoli.free.fr/C/Cassels_J.W.S.-An_introduction_to_diophantine_approximation-University_Press(1965).pdf
+ // http://en.wikipedia.org/wiki/Continued_fraction
+ Assert(K >= Integer(1));
+ if( r.getDenominator() <= K ){
+ return r;
+ }
+
+ // current numerator and denominator that has not been resolved in the cfe
+ Integer num = r.getNumerator(), den = r.getDenominator();
+ Integer quot,rem;
+
+ unsigned t = 0;
+ // For a sequence of candidate solutions q_t/p_t
+ // we keep only 3 time steps: 0[prev], 1[current], 2[next]
+ // timesteps with a fake timestep 0 (p is 0 and q is 1)
+ // at timestep 1
+ Integer p[3]; // h
+ Integer q[3]; // k
+ // load the first 3 time steps manually
+ p[0] = 0; q[0] = 1; // timestep -2
+ p[1] = 1; q[1] = 0; // timestep -1
+
+ Integer::floorQR(quot, rem, num, den);
+ num = den; den = rem;
+
+ q[2] = q[0] + quot*q[1];
+ p[2] = p[0] + quot*p[1];
+ Debug("estimateWithCFE") << " cfe["<<t<<"]: " << p[2] <<"/"<< q[2] << endl;
+ while( q[2] <= K ){
+ p[0] = p[1]; p[1] = p[2];
+ q[0] = q[1]; q[1] = q[2];
+
+
+ Integer::floorQR(quot, rem, num, den);
+ num = den; den = rem;
+
+ p[2] = p[0]+quot*p[1];
+ q[2] = q[0]+quot*q[1];
+ ++t;
+ Debug("estimateWithCFE") << " cfe["<<t<<"]: " << p[2] <<"/"<< q[2] << endl;
+ }
+
+ Integer k = (K-q[0]).floorDivideQuotient(q[1]);
+ Rational cand_prev(p[0]+k*p[1], q[0]+k*q[1]);
+ Rational cand_curr(p[1], q[1]);
+ Rational dist_prev = (cand_prev - r).abs();
+ Rational dist_curr = (cand_curr - r).abs();
+ if(dist_prev <= dist_curr){
+ Debug("estimateWithCFE") << cand_prev << " is closer than " << cand_curr << endl;
+ return cand_prev;
+ }else{
+ Debug("estimateWithCFE") << cand_curr << " is closer than " << cand_prev << endl;
+ return cand_curr;
+ }
+}
+
+Rational ApproximateSimplex::estimateWithCFE(double d, const Integer& D) throw (RationalFromDoubleException){
+ return estimateWithCFE(Rational::fromDouble(d), D);
}
-Rational ApproximateSimplex::estimateWithCFE(double d){
- return estimateWithCFE(Rational::fromDouble(d), 10);
+Rational ApproximateSimplex::estimateWithCFE(double d) throw (RationalFromDoubleException){
+ return estimateWithCFE(d, s_defaultMaxDenom);
}
class ApproxNoOp : public ApproximateSimplex {
public:
- ApproxNoOp(const ArithVariables& vars){}
+ ApproxNoOp(const ArithVariables& v, TreeLog& l, ApproximateStatistics& s)
+ : ApproximateSimplex(v,l,s)
+ {}
~ApproxNoOp(){}
- virtual ApproxResult solveRelaxation(){
- return ApproxError;
+ virtual LinResult solveRelaxation(){
+ return LinUnknown;
}
- virtual Solution extractRelaxation() const{
+ virtual Solution extractRelaxation() const throw (RationalFromDoubleException){
return Solution();
}
@@ -116,14 +397,31 @@ public:
return ArithRatPairVec();
}
- virtual ApproxResult solveMIP(){
- return ApproxError;
+ virtual MipResult solveMIP(bool al){
+ return MipUnknown;
}
- virtual Solution extractMIP() const{
+ virtual Solution extractMIP() const throw (RationalFromDoubleException){
return Solution();
}
virtual void setOptCoeffs(const ArithRatPairVec& ref){}
+ virtual std::vector<const CutInfo*> getValidCuts(const std::set<const NodeLog*>& nodes){
+ return std::vector<const CutInfo*>();
+ }
+
+ virtual void tryCut(int nid, CutInfo& cut) throw (RationalFromDoubleException){}
+
+ virtual std::vector<const CutInfo*> getValidCuts(const NodeLog& node) throw(RationalFromDoubleException){
+ return std::vector<const CutInfo*>();
+ }
+
+ virtual ArithVar getBranchVar(const NodeLog& nl) const{
+ return ARITHVAR_SENTINEL;
+ }
+
+ virtual double sumInfeasibilities(bool mip) const{
+ return 0.0;
+ }
};
}/* CVC4::theory::arith namespace */
@@ -146,14 +444,33 @@ namespace CVC4 {
namespace theory {
namespace arith {
+Kind glpk_type_to_kind(int glpk_cut_type){
+ switch(glpk_cut_type){
+ case GLP_LO: return kind::GEQ;
+ case GLP_UP: return kind::LEQ;
+ case GLP_FX: return kind::EQUAL;
+ case GLP_DB:
+ case GLP_FR:
+ default: return kind::UNDEFINED_KIND;
+ }
+}
+
+class GmiInfo;
+class MirInfo;
+class BranchCutInfo;
+
class ApproxGLPK : public ApproximateSimplex {
private:
- glp_prob* d_prob;
- const ArithVariables& d_vars;
+ glp_prob* d_inputProb; /* a copy of the input prob */
+ glp_prob* d_realProb; /* a copy of the real relaxation output */
+ glp_prob* d_mipProb; /* a copy of the integer prob */
DenseMap<int> d_colIndices;
DenseMap<int> d_rowIndices;
+ NodeLog::RowIdMap d_rootRowIds;
+ //DenseMap<ArithVar> d_rowToArithVar;
+ DenseMap<ArithVar> d_colToArithVar;
int d_instanceID;
@@ -162,27 +479,127 @@ private:
static int s_verbosity;
+ CutScratchPad d_pad;
+
+ std::vector<Integer> d_denomGuesses;
+
public:
- ApproxGLPK(const ArithVariables& vars);
+ ApproxGLPK(const ArithVariables& v, TreeLog& l, ApproximateStatistics& s);
~ApproxGLPK();
- virtual ApproxResult solveRelaxation();
- virtual Solution extractRelaxation() const{
+ virtual LinResult solveRelaxation();
+ virtual Solution extractRelaxation() const throw (RationalFromDoubleException){
return extractSolution(false);
}
virtual ArithRatPairVec heuristicOptCoeffs() const;
- virtual ApproxResult solveMIP();
- virtual Solution extractMIP() const{
+ virtual MipResult solveMIP(bool al);
+ virtual Solution extractMIP() const throw (RationalFromDoubleException){
return extractSolution(true);
}
virtual void setOptCoeffs(const ArithRatPairVec& ref);
+ //void getValidCuts(const NodeLog& con, std::vector<const CutInfo*>& out);
+ virtual std::vector<const CutInfo*> getValidCuts(const NodeLog& nodes) throw (RationalFromDoubleException);
+ //virtual std::vector<const NodeLog*> getBranches();
+
+ //Node downBranchLiteral(const NodeLog& con) const;
+ ArithVar getBranchVar(const NodeLog& con) const;
static void printGLPKStatus(int status, std::ostream& out);
+
+
private:
- Solution extractSolution(bool mip) const;
+ Solution extractSolution(bool mip) const throw (RationalFromDoubleException);
int guessDir(ArithVar v) const;
+
+ // get this stuff out of here
+ void tryCut(int nid, CutInfo& cut) throw (RationalFromDoubleException);
+
+ ArithVar _getArithVar(int nid, int M, int ind) const;
+ ArithVar getArithVarFromRow(int nid, int ind) const {
+ if(ind >= 0){
+ const NodeLog& nl = d_log.getNode(nid);
+ return nl.lookupRowId(ind);
+ }
+ return ARITHVAR_SENTINEL;
+ }
+
+ // virtual void mapRowId(int nid, int ind, ArithVar v){
+ // NodeLog& nl = d_log.getNode(nid);
+ // nl.mapRowId(ind, v);
+ // }
+ // virtual void applyRowsDeleted(int nid, const RowsDeleted& rd){
+ // NodeLog& nl = d_log.getNode(nid);
+ // nl.applyRowsDeleted(rd);
+ // }
+
+ ArithVar getArithVarFromStructural(int ind) const{
+ if(ind >= 0){
+ unsigned u = (unsigned) ind;
+ if(d_colToArithVar.isKey(u)){
+ return d_colToArithVar[u];
+ }
+ }
+ return ARITHVAR_SENTINEL;
+ }
+
+ /**
+ * Attempts to make the row vector vec on the pad.
+ * If this is not in the row span of the original tableau this
+ * raises the failure flag.
+ */
+ bool attemptConstructTableRow(int node, int M, const PrimitiveVec& vec);
+ bool guessCoefficientsConstructTableRow(int node, int M, const PrimitiveVec& vec);
+ bool guessCoefficientsConstructTableRow(int node, int M, const PrimitiveVec& vec, const Integer& D);
+ bool gaussianElimConstructTableRow(int node, int M, const PrimitiveVec& vec);
+
+ /* This is a guess of a vector in the row span of the tableau.
+ * Attempt to cancel out all of the variables.
+ * returns true if this is constructable.
+ */
+ bool guessIsConstructable(const DenseMap<Rational>& guess) const;
+
+ /**
+ * Loads a vector of statuses into a dense map over bounds.
+ * returns true on failure.
+ */
+ bool loadToBound(int node, int M, int len, int* inds, int* statuses,
+ DenseMap<ConstraintP>& toBound) const;
+
+ /** checks the cut on the pad for whether it is sufficiently similar to cut. */
+ bool checkCutOnPad(int nid, const CutInfo& cut) const;
+
+
+ /** turns the pad into a node and creates an explanation. */
+ //std::pair<Node, Node> makeCutNodes(int nid, const CutInfo& cut) const;
+
+ // true means failure!
+ // BRANCH CUTS
+ bool attemptBranchCut(int nid, const BranchCutInfo& br);
+
+ // GOMORY CUTS
+ bool attemptGmi(int nid, const GmiInfo& gmi);
+ /** tries to turn the information on the pad into a cut. */
+ bool constructGmiCut();
+
+ // MIR CUTS
+ bool attemptMir(int nid, const MirInfo& mir);
+ bool applyCMIRRule(int nid, const MirInfo& mir);
+ bool makeRangeForComplemented(int nid, const MirInfo& mir);
+ bool loadSlacksIntoPad(int nid, const MirInfo& mir);
+ bool loadVirtualBoundsIntoPad(int nid, const MirInfo& mir);
+ bool loadRowSumIntoAgg(int nid, int M, const PrimitiveVec& mir);
+ bool buildModifiedRow(int nid, const MirInfo& mir);
+ bool constructMixedKnapsack();
+ bool replaceSlacksOnCuts();
+ bool loadVB(int nid, int M, int j, int ri, bool wantUb, VirtualBound& tmp);
+
+
+ double sumInfeasibilities(bool mip) const{
+ return sumInfeasibilities(mip? d_mipProb : d_realProb);
+ }
+ double sumInfeasibilities(glp_prob* prob, bool mip) const;
};
int ApproxGLPK::s_verbosity = 0;
@@ -197,11 +614,11 @@ int ApproxGLPK::s_verbosity = 0;
namespace CVC4 {
namespace theory {
namespace arith {
-ApproximateSimplex* ApproximateSimplex::mkApproximateSimplexSolver(const ArithVariables& vars){
+ApproximateSimplex* ApproximateSimplex::mkApproximateSimplexSolver(const ArithVariables& vars, TreeLog& l, ApproximateStatistics& s){
#ifdef CVC4_USE_GLPK
- return new ApproxGLPK(vars);
+ return new ApproxGLPK(vars, l, s);
#else
- return new ApproxNoOp(vars);
+ return new ApproxNoOp(vars, l, s);
#endif
}
bool ApproximateSimplex::enabled() {
@@ -223,16 +640,38 @@ namespace CVC4 {
namespace theory {
namespace arith {
-ApproxGLPK::ApproxGLPK(const ArithVariables& avars) :
- d_vars(avars), d_solvedRelaxation(false), d_solvedMIP(false)
+static CutInfoKlass fromGlpkClass(int klass){
+ switch(klass){
+ case GLP_RF_GMI: return GmiCutKlass;
+ case GLP_RF_MIR: return MirCutKlass;
+ case GLP_RF_COV:
+ case GLP_RF_CLQ:
+ default: return UnknownKlass;
+ }
+}
+
+ApproxGLPK::ApproxGLPK(const ArithVariables& v, TreeLog& l, ApproximateStatistics& s)
+ : ApproximateSimplex(v, l, s)
+ , d_inputProb(NULL)
+ , d_realProb(NULL)
+ , d_mipProb(NULL)
+ , d_solvedRelaxation(false)
+ , d_solvedMIP(false)
{
static int instance = 0;
++instance;
d_instanceID = instance;
- d_prob = glp_create_prob();
- glp_set_obj_dir(d_prob, GLP_MAX);
- glp_set_prob_name(d_prob, "ApproximateSimplex::approximateFindModel");
+ d_denomGuesses.push_back(Integer(1<<22));
+ d_denomGuesses.push_back(ApproximateSimplex::s_defaultMaxDenom);
+ d_denomGuesses.push_back(Integer(1ul<<29));
+ d_denomGuesses.push_back(Integer(1ul<<31));
+
+ d_inputProb = glp_create_prob();
+ d_realProb = glp_create_prob();
+ d_mipProb = glp_create_prob();
+ glp_set_obj_dir(d_inputProb, GLP_MAX);
+ glp_set_prob_name(d_inputProb, "ApproximateSimplex::approximateFindModel");
int numRows = 0;
int numCols = 0;
@@ -241,24 +680,35 @@ ApproxGLPK::ApproxGLPK(const ArithVariables& avars) :
for(ArithVariables::var_iterator vi = d_vars.var_begin(), vi_end = d_vars.var_end(); vi != vi_end; ++vi){
ArithVar v = *vi;
- if(d_vars.isSlack(v)){
+ if(d_vars.isAuxiliary(v)){
++numRows;
d_rowIndices.set(v, numRows);
+ //mapRowId(d_log.getRootId(), numRows, v);
+ d_rootRowIds.insert(make_pair(numRows, v));
+ //d_rowToArithVar.set(numRows, v);
+ Debug("approx") << "Row vars: " << v << "<->" << numRows << endl;
}else{
++numCols;
d_colIndices.set(v, numCols);
+ d_colToArithVar.set(numCols, v);
+ Debug("approx") << "Col vars: " << v << "<->" << numCols << endl;
}
}
- glp_add_rows(d_prob, numRows);
- glp_add_cols(d_prob, numCols);
+ Assert(numRows > 0);
+ Assert(numCols > 0);
+
+
+
+ glp_add_rows(d_inputProb, numRows);
+ glp_add_cols(d_inputProb, numCols);
// Assign the upper/lower bounds and types to each variable
for(ArithVariables::var_iterator vi = d_vars.var_begin(), vi_end = d_vars.var_end(); vi != vi_end; ++vi){
ArithVar v = *vi;
if(s_verbosity >= 2){
- Message() << v << " ";
- d_vars.printModel(v, Message());
+ //Message() << v << " ";
+ //d_vars.printModel(v, Message());
}
int type;
@@ -282,14 +732,15 @@ ApproxGLPK::ApproxGLPK(const ArithVariables& avars) :
type = GLP_FR;
}
- if(d_vars.isSlack(v)){
+ if(d_vars.isAuxiliary(v)){
int rowIndex = d_rowIndices[v];
- glp_set_row_bnds(d_prob, rowIndex, type, lb, ub);
+ glp_set_row_bnds(d_inputProb, rowIndex, type, lb, ub);
}else{
int colIndex = d_colIndices[v];
+ // is input is correct here
int kind = d_vars.isInteger(v) ? GLP_IV : GLP_CV;
- glp_set_col_kind(d_prob, colIndex, kind);
- glp_set_col_bnds(d_prob, colIndex, type, lb, ub);
+ glp_set_col_kind(d_inputProb, colIndex, kind);
+ glp_set_col_bnds(d_inputProb, colIndex, type, lb, ub);
}
}
@@ -333,7 +784,7 @@ ApproxGLPK::ApproxGLPK(const ArithVariables& avars) :
ar[entryCounter] = coeff;
}
}
- glp_load_matrix(d_prob, numEntries, ia, ja, ar);
+ glp_load_matrix(d_inputProb, numEntries, ia, ja, ar);
delete[] ia;
delete[] ja;
@@ -410,12 +861,12 @@ ArithRatPairVec ApproxGLPK::heuristicOptCoeffs() const{
if(type != GLP_FX && type != GLP_FR){
- if(d_vars.isSlack(v)){
+ if(d_vars.isAuxiliary(v)){
Polynomial p = Polynomial::parsePolynomial(d_vars.asNode(v));
uint32_t len = p.size();
d_rowCandidates.set(v, len);
sumRowLength += len;
- maxRowLength =std::max(maxRowLength, len);
+ maxRowLength = std::max(maxRowLength, len);
}else if(!d_vars.isInteger(v)){
d_colCandidates.set(v, BoundCounts());
}
@@ -430,7 +881,7 @@ ArithRatPairVec ApproxGLPK::heuristicOptCoeffs() const{
bool ubCap = !d_vars.hasLowerBound(v) && d_vars.hasUpperBound(v);
if(lbCap || ubCap){
- Constraint b = lbCap ? d_vars.getLowerBoundConstraint(v)
+ ConstraintP b = lbCap ? d_vars.getLowerBoundConstraint(v)
: d_vars.getUpperBoundConstraint(v);
if(!(b->getValue()).noninfinitesimalIsZero()){ continue; }
@@ -530,7 +981,7 @@ void ApproxGLPK::setOptCoeffs(const ArithRatPairVec& ref){
ArithVar v = (*i).first;
const Rational& q = (*i).second;
- if(d_vars.isSlack(v)){
+ if(d_vars.isAuxiliary(v)){
// replace the variable by its definition and multiply by q
Polynomial p = Polynomial::parsePolynomial(d_vars.asNode(v));
Polynomial pq = p * q;
@@ -563,7 +1014,7 @@ void ApproxGLPK::setOptCoeffs(const ArithRatPairVec& ref){
for(DenseMap<double>::const_iterator ci =nbCoeffs.begin(), ciend = nbCoeffs.end(); ci != ciend; ++ci){
Index colIndex = *ci;
double coeff = nbCoeffs[colIndex];
- glp_set_obj_coef(d_prob, colIndex, coeff);
+ glp_set_obj_coef(d_inputProb, colIndex, coeff);
}
}
@@ -610,11 +1061,14 @@ void ApproxGLPK::printGLPKStatus(int status, std::ostream& out){
}
ApproxGLPK::~ApproxGLPK(){
- glp_delete_prob(d_prob);
+ glp_delete_prob(d_inputProb);
+ glp_delete_prob(d_realProb);
+ glp_delete_prob(d_mipProb);
+
}
-ApproximateSimplex::Solution ApproxGLPK::extractSolution(bool mip) const{
+ApproximateSimplex::Solution ApproxGLPK::extractSolution(bool mip) const throw (RationalFromDoubleException){
Assert(d_solvedRelaxation);
Assert(!mip || d_solvedMIP);
@@ -622,12 +1076,15 @@ ApproximateSimplex::Solution ApproxGLPK::extractSolution(bool mip) const{
DenseSet& newBasis = sol.newBasis;
DenseMap<DeltaRational>& newValues = sol.newValues;
+ glp_prob* prob = mip ? d_mipProb : d_realProb;
+
for(ArithVariables::var_iterator i = d_vars.var_begin(), i_end = d_vars.var_end(); i != i_end; ++i){
ArithVar vi = *i;
- bool isSlack = d_vars.isSlack(vi);
- int glpk_index = isSlack ? d_rowIndices[vi] : d_colIndices[vi];
+ bool isAux = d_vars.isAuxiliary(vi);
+ int glpk_index = isAux ? d_rowIndices[vi] : d_colIndices[vi];
- int status = isSlack ? glp_get_row_stat(d_prob, glpk_index) : glp_get_col_stat(d_prob, glpk_index);
+ int status = isAux ? glp_get_row_stat(prob, glpk_index)
+ : glp_get_col_stat(prob, glpk_index);
if(s_verbosity >= 2){
Message() << "assignment " << vi << endl;
}
@@ -667,10 +1124,14 @@ ApproximateSimplex::Solution ApproxGLPK::extractSolution(bool mip) const{
if(useDefaultAssignment){
if(s_verbosity >= 2){ Message() << "non-basic other" << endl; }
- double newAssign =
- mip ?
- (isSlack ? glp_mip_row_val(d_prob, glpk_index) : glp_mip_col_val(d_prob, glpk_index))
- : (isSlack ? glp_get_row_prim(d_prob, glpk_index) : glp_get_col_prim(d_prob, glpk_index));
+ double newAssign;
+ if(mip){
+ newAssign = (isAux ? glp_mip_row_val(prob, glpk_index)
+ : glp_mip_col_val(prob, glpk_index));
+ }else{
+ newAssign = (isAux ? glp_get_row_prim(prob, glpk_index)
+ : glp_get_col_prim(prob, glpk_index));
+ }
const DeltaRational& oldAssign = d_vars.getAssignment(vi);
@@ -718,7 +1179,51 @@ ApproximateSimplex::Solution ApproxGLPK::extractSolution(bool mip) const{
return sol;
}
-ApproximateSimplex::ApproxResult ApproxGLPK::solveRelaxation(){
+double ApproxGLPK::sumInfeasibilities(glp_prob* prob, bool mip) const{
+ /* compute the sum of dual infeasibilities */
+ double infeas = 0.0;
+
+ for(ArithVariables::var_iterator i = d_vars.var_begin(), i_end = d_vars.var_end(); i != i_end; ++i){
+ ArithVar vi = *i;
+ bool isAux = d_vars.isAuxiliary(vi);
+ int glpk_index = isAux ? d_rowIndices[vi] : d_colIndices[vi];
+
+ double newAssign;
+ if(mip){
+ newAssign = (isAux ? glp_mip_row_val(prob, glpk_index)
+ : glp_mip_col_val(prob, glpk_index));
+ }else{
+ newAssign = (isAux ? glp_get_row_prim(prob, glpk_index)
+ : glp_get_col_prim(prob, glpk_index));
+ }
+
+
+ double ub = isAux ?
+ glp_get_row_ub(prob, glpk_index) : glp_get_col_ub(prob, glpk_index);
+
+ double lb = isAux ?
+ glp_get_row_lb(prob, glpk_index) : glp_get_col_lb(prob, glpk_index);
+
+ if(ub != +DBL_MAX){
+ if(newAssign > ub){
+ double ubinf = newAssign - ub;
+ infeas += ubinf;
+ Debug("approx::soi") << "ub inf" << vi << " " << ubinf << " " << infeas << endl;
+ }
+ }
+ if(lb != -DBL_MAX){
+ if(newAssign < lb){
+ double lbinf = lb - newAssign;
+ infeas += lbinf;
+
+ Debug("approx::soi") << "lb inf" << vi << " " << lbinf << " " << infeas << endl;
+ }
+ }
+ }
+ return infeas;
+}
+
+LinResult ApproxGLPK::solveRelaxation(){
Assert(!d_solvedRelaxation);
glp_smcp parm;
@@ -732,51 +1237,563 @@ ApproximateSimplex::ApproxResult ApproxGLPK::solveRelaxation(){
parm.msg_lev = GLP_MSG_ALL;
}
- int res = glp_simplex(d_prob, &parm);
+ glp_erase_prob(d_realProb);
+ glp_copy_prob(d_realProb, d_inputProb, GLP_OFF);
+
+ int res = glp_simplex(d_realProb, &parm);
switch(res){
case 0:
{
- int status = glp_get_status(d_prob);
+ int status = glp_get_status(d_realProb);
+ int iterationcount = glp_get_it_cnt(d_realProb);
switch(status){
case GLP_OPT:
case GLP_FEAS:
case GLP_UNBND:
d_solvedRelaxation = true;
- return ApproxSat;
+ return LinFeasible;
case GLP_INFEAS:
case GLP_NOFEAS:
d_solvedRelaxation = true;
- return ApproxUnsat;
+ return LinInfeasible;
default:
- return ApproxError;
+ {
+ if(iterationcount >= d_pivotLimit){
+ return LinExhausted;
+ }
+ return LinUnknown;
+ }
}
}
default:
- return ApproxError;
+ return LinUnknown;
+ }
+}
+
+
+struct MirInfo : public CutInfo {
+
+ /** a sum of input rows. */
+ PrimitiveVec row_sum;
+
+ /* the delta used */
+ double delta;
+
+ /* all of these are length vars == N+M*/
+ int nvars;
+ char* cset;
+ char* subst;
+ int* vlbRows;
+ int* vubRows;
+ MirInfo(int execOrd, int ord)
+ : CutInfo(MirCutKlass, execOrd, ord)
+ , nvars(0)
+ , cset(NULL)
+ , subst(NULL)
+ , vlbRows(NULL)
+ , vubRows(NULL)
+ {}
+
+ ~MirInfo(){
+ clearSets();
+ }
+ void clearSets(){
+ if(cset != NULL){
+ delete[] cset;
+ delete[] subst;
+ delete[] vlbRows;
+ delete[] vubRows;
+ cset = NULL;
+ nvars = 0;
+ }
+ }
+ void initSet(){
+ Assert(d_N >= 0);
+ Assert(d_mAtCreation >= 0);
+ clearSets();
+
+ int vars = 1 + d_N + d_mAtCreation;
+
+ cset = new char[1+vars];
+ subst = new char[1+vars];
+ vlbRows = new int[1+vars];
+ vubRows = new int[1+vars];
+ }
+};
+
+struct GmiInfo : public CutInfo {
+ int basic;
+ PrimitiveVec tab_row;
+ int* tab_statuses;
+ /* has the length tab_row.length */
+
+ GmiInfo(int execOrd, int ord)
+ : CutInfo(GmiCutKlass, execOrd, ord)
+ , basic(-1)
+ , tab_row()
+ , tab_statuses(NULL)
+ {
+ Assert(!initialized_tab());
+ }
+
+ ~GmiInfo(){
+ if(initialized_tab()){
+ clear_tab();
+ }
+ }
+
+ bool initialized_tab() const {
+ return tab_statuses != NULL;
+ }
+
+ void init_tab(int N){
+ if(initialized_tab()){
+ clear_tab();
+ }
+ tab_row.setup(N);
+ tab_statuses = new int[1+N];
+ }
+
+ void clear_tab() {
+ delete[] tab_statuses;
+ tab_statuses = NULL;
+ tab_row.clear();
+ basic = -1;
+ }
+};
+
+
+
+static void loadCut(glp_tree *tree, CutInfo* cut){
+ int ord, cut_len, cut_klass;
+ int N, M;
+ int* cut_inds;
+ double* cut_coeffs;
+ int glpk_cut_type;
+ double cut_rhs;
+ glp_prob* lp;
+
+ lp = glp_ios_get_prob(tree);
+ ord = cut->poolOrdinal();
+
+ N = glp_get_num_cols(lp);
+ M = glp_get_num_rows(lp);
+
+ cut->setDimensions(N, M);
+
+
+
+ // Get the cut
+ cut_len = glp_ios_get_cut(tree, ord, NULL, NULL, &cut_klass, NULL, NULL);
+ Assert(fromGlpkClass(cut_klass) == cut->getKlass());
+
+ PrimitiveVec& cut_vec = cut->getCutVector();
+ cut_vec.setup(cut_len);
+ cut_inds = cut_vec.inds;
+ cut_coeffs = cut_vec.coeffs;
+
+ cut_vec.len = glp_ios_get_cut(tree, ord, cut_inds, cut_coeffs, &cut_klass, &glpk_cut_type, &cut_rhs);
+ Assert(fromGlpkClass(cut_klass) == cut->getKlass());
+ Assert(cut_vec.len == cut_len);
+
+ cut->setRhs(cut_rhs);
+
+ cut->setKind( glpk_type_to_kind(glpk_cut_type) );
+}
+
+
+static MirInfo* mirCut(glp_tree *tree, int exec_ord, int cut_ord){
+ Debug("approx::mirCut") << "mirCut()" << exec_ord << endl;
+
+ MirInfo* mir;
+ mir = new MirInfo(exec_ord, cut_ord);
+ loadCut(tree, mir);
+ mir->initSet();
+
+
+ int nrows = glp_ios_cut_get_aux_nrows(tree, cut_ord);
+
+ PrimitiveVec& row_sum = mir->row_sum;
+ row_sum.setup(nrows);
+ glp_ios_cut_get_aux_rows(tree, cut_ord, row_sum.inds, row_sum.coeffs);
+
+ glp_ios_cut_get_mir_cset(tree, cut_ord, mir->cset);
+ mir->delta = glp_ios_cut_get_mir_delta(tree, cut_ord);
+ glp_ios_cut_get_mir_subst(tree, cut_ord, mir->subst);
+ glp_ios_cut_get_mir_virtual_rows(tree, cut_ord, mir->vlbRows, mir->vubRows);
+
+ if(Debug.isOn("approx::mirCut")){
+ Debug("approx::mirCut") << "mir_id: " << exec_ord << endl;
+ row_sum.print(Debug("approx::mirCut"));
+ }
+
+ return mir;
+}
+
+static GmiInfo* gmiCut(glp_tree *tree, int exec_ord, int cut_ord){
+ Debug("approx::gmiCut") << "gmiCut()" << exec_ord << endl;
+
+ int gmi_var;
+ int write_pos;
+ int read_pos;
+ int stat;
+ int ind;
+ int i;
+
+ GmiInfo* gmi;
+ glp_prob* lp;
+
+ gmi = new GmiInfo(exec_ord, cut_ord);
+ loadCut(tree, gmi);
+
+ lp = glp_ios_get_prob(tree);
+
+ int N = gmi->getN();
+ int M = gmi->getMAtCreation();
+
+ // Get the tableau row
+ int nrows CVC4_UNUSED = glp_ios_cut_get_aux_nrows(tree, gmi->poolOrdinal());
+ Assert(nrows == 1);
+ int rows[1+1];
+ glp_ios_cut_get_aux_rows(tree, gmi->poolOrdinal(), rows, NULL);
+ gmi_var = rows[1];
+
+ gmi->init_tab(N);
+ gmi->basic = M+gmi_var;
+
+ Debug("approx::gmiCut")
+ << gmi <<" " << gmi->basic << " "
+ << cut_ord<<" " << M <<" " << gmi_var << endl;
+
+ PrimitiveVec& tab_row = gmi->tab_row;
+ Debug("approx::gmiCut") << "Is N sufficient here?" << endl;
+ tab_row.len = glp_eval_tab_row(lp, gmi->basic, tab_row.inds, tab_row.coeffs);
+
+ Debug("approx::gmiCut") << "gmi_var " << gmi_var << endl;
+
+ Debug("approx::gmiCut") << "tab_pos " << tab_row.len << endl;
+ write_pos = 1;
+ for(read_pos = 1; read_pos <= tab_row.len; ++read_pos){
+ if (fabs(tab_row.coeffs[read_pos]) < 1e-10){
+ }else{
+ tab_row.coeffs[write_pos] = tab_row.coeffs[read_pos];
+ tab_row.inds[write_pos] = tab_row.inds[read_pos];
+ ++write_pos;
+ }
+ }
+ tab_row.len = write_pos-1;
+ Debug("approx::gmiCut") << "write_pos " << write_pos << endl;
+ Assert(tab_row.len > 0);
+
+ for(i = 1; i <= tab_row.len; ++i){
+ ind = tab_row.inds[i];
+ Debug("approx::gmiCut") << "ind " << i << " " << ind << endl;
+ stat = (ind <= M) ?
+ glp_get_row_stat(lp, ind) : glp_get_col_stat(lp, ind - M);
+
+ Debug("approx::gmiCut") << "ind " << i << " " << ind << " stat " << stat << endl;
+ switch (stat){
+ case GLP_NL:
+ case GLP_NU:
+ case GLP_NS:
+ gmi->tab_statuses[i] = stat;
+ break;
+ case GLP_NF:
+ default:
+ Unreachable();
+ }
}
+
+ if(Debug.isOn("approx::gmiCut")){
+ gmi->print(Debug("approx::gmiCut"));
+ }
+ return gmi;
}
-void stopAtBingoOrPivotLimit(glp_tree *tree, void *info){
- int pivotLimit = *((int*)info);
+static BranchCutInfo* branchCut(glp_tree *tree, int exec_ord, int br_var, double br_val, bool down_bad){
+ //(tree, br_var, br_val, dn < 0);
+ double rhs;
+ Kind k;
+ if(down_bad){
+ // down branch is infeasible
+ // x <= floor(v) is infeasible
+ // - so x >= ceiling(v) is implied
+ k = kind::GEQ;
+ rhs = std::ceil(br_val);
+ }else{
+ // up branch is infeasible
+ // x >= ceiling(v) is infeasible
+ // - so x <= floor(v) is implied
+ k = kind::LEQ;
+ rhs = std::floor(br_val);
+ }
+ BranchCutInfo* br_cut = new BranchCutInfo(exec_ord, br_var, k, rhs);
+ return br_cut;
+}
+
+static void glpkCallback(glp_tree *tree, void *info){
+ AuxInfo* aux = (AuxInfo*)(info);
+ TreeLog& tl = *(aux->tl);
+
+ int exec = tl.getExecutionOrd();
+ int glpk_node_p = -1;
+ int node_ord = -1;
+
+ if(tl.isActivelyLogging()){
+ switch(glp_ios_reason(tree)){
+ case GLP_LI_DELROW:
+ {
+ glpk_node_p = glp_ios_curr_node(tree);
+ node_ord = glp_ios_node_ord(tree, glpk_node_p);
+
+ int nrows = glp_ios_rows_deleted(tree, NULL);
+ int* num = new int[1+nrows];
+ glp_ios_rows_deleted(tree, num);
+
+ NodeLog& node = tl.getNode(node_ord);
+
+ RowsDeleted* rd = new RowsDeleted(exec, nrows, num);
+
+ node.addCut(rd);
+ delete num;
+ }
+ break;
+ case GLP_ICUTADDED:
+ {
+ int cut_ord = glp_ios_pool_size(tree);
+ glpk_node_p = glp_ios_curr_node(tree);
+ node_ord = glp_ios_node_ord(tree, glpk_node_p);
+ Assert(cut_ord > 0);
+ Debug("approx") << "curr node " << glpk_node_p
+ << " cut ordinal " << cut_ord
+ << " node depth " << glp_ios_node_level(tree, glpk_node_p)
+ << endl;
+ int klass;
+ glp_ios_get_cut(tree, cut_ord, NULL, NULL, &klass, NULL, NULL);
+
+ NodeLog& node = tl.getNode(node_ord);
+ switch(klass){
+ case GLP_RF_GMI:
+ {
+ GmiInfo* gmi = gmiCut(tree, exec, cut_ord);
+ node.addCut(gmi);
+ }
+ break;
+ case GLP_RF_MIR:
+ {
+ MirInfo* mir = mirCut(tree, exec, cut_ord);
+ node.addCut(mir);
+ }
+ break;
+ case GLP_RF_COV:
+ Debug("approx") << "GLP_RF_COV" << endl;
+ break;
+ case GLP_RF_CLQ:
+ Debug("approx") << "GLP_RF_CLQ" << endl;
+ break;
+ default:
+ break;
+ }
+ }
+ break;
+ case GLP_ICUTSELECT:
+ {
+ glpk_node_p = glp_ios_curr_node(tree);
+ node_ord = glp_ios_node_ord(tree, glpk_node_p);
+ int cuts = glp_ios_pool_size(tree);
+ int* ords = new int[1+cuts];
+ int* rows = new int[1+cuts];
+ int N = glp_ios_selected_cuts(tree, ords, rows);
+
+ NodeLog& nl = tl.getNode(node_ord);
+ Debug("approx") << glpk_node_p << " " << node_ord << " " << cuts << " " << N << std::endl;
+ for(int i = 1; i <= N; ++i){
+ Debug("approx") << "adding to " << node_ord <<" @ i= " << i
+ << " ords[i] = " << ords[i]
+ << " rows[i] = " << rows[i] << endl;
+ nl.addSelected(ords[i], rows[i]);
+ }
+ delete[] ords;
+ delete[] rows;
+ nl.applySelected();
+ }
+ break;
+ case GLP_LI_BRANCH:
+ {
+ // a branch was just made
+ int br_var;
+ int p, dn, up;
+ int p_ord, dn_ord, up_ord;
+ double br_val;
+ br_var = glp_ios_branch_log(tree, &br_val, &p, &dn, &up);
+ p_ord = glp_ios_node_ord(tree, p);
+
+ dn_ord = (dn >= 0) ? glp_ios_node_ord(tree, dn) : -1;
+ up_ord = (up >= 0) ? glp_ios_node_ord(tree, up) : -1;
+
+ Debug("approx::") << "branch: "<< br_var << " " << br_val << " tree " << p << " " << dn << " " << up << endl;
+ Debug("approx::") << "\t " << p_ord << " " << dn_ord << " " << up_ord << endl;
+ if(dn < 0 && up < 0){
+ Debug("approx::") << "branch close " << exec << endl;
+ NodeLog& node = tl.getNode(p_ord);
+ BranchCutInfo* cut_br = branchCut(tree, exec, br_var, br_val, dn < 0);
+ node.addCut(cut_br);
+ tl.close(p_ord);
+ }else if(dn < 0 || up < 0){
+ Debug("approx::") << "branch cut" << exec << endl;
+ NodeLog& node = tl.getNode(p_ord);
+ BranchCutInfo* cut_br = branchCut(tree, exec, br_var, br_val, dn < 0);
+ node.addCut(cut_br);
+ }else{
+ Debug("approx::") << "normal branch" << endl;
+ tl.branch(p_ord, br_var, br_val, dn_ord, up_ord);
+ }
+ }
+ break;
+ case GLP_LI_CLOSE:
+ {
+ glpk_node_p = glp_ios_curr_node(tree);
+ node_ord = glp_ios_node_ord(tree, glpk_node_p);
+ Debug("approx::") << "close " << glpk_node_p << endl;
+ tl.close(node_ord);
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
switch(glp_ios_reason(tree)){
case GLP_IBINGO:
+ Debug("approx::") << "bingo" << endl;
+ aux->term = MipBingo;
glp_ios_terminate(tree);
break;
+ case GLP_ICUTADDED:
+ {
+ tl.addCut();
+ }
+ break;
+ case GLP_LI_BRANCH:
+ {
+ int p, dn, up;
+ int br_var = glp_ios_branch_log(tree, NULL, &p, &dn, &up);
+
+ if(br_var >= 0){
+ unsigned v = br_var;
+ tl.logBranch(v);
+ int depth = glp_ios_node_level(tree, p);
+ unsigned ubl = (aux->branchLimit) >= 0 ? ((unsigned)(aux->branchLimit)) : 0u;
+ if(tl.numBranches(v) >= ubl || depth >= (aux->branchDepth)){
+ aux->term = BranchesExhausted;
+ glp_ios_terminate(tree);
+ }
+ }
+ }
+ break;
+ case GLP_LI_CLOSE:
+ break;
default:
- glp_prob* prob = glp_ios_get_prob(tree);
- int iterationcount = lpx_get_int_parm(prob, LPX_K_ITCNT);
- if(iterationcount > pivotLimit){
- glp_ios_terminate(tree);
+ {
+ glp_prob* prob = glp_ios_get_prob(tree);
+ int iterationcount = glp_get_it_cnt(prob);
+ if(exec > (aux->pivotLimit)){
+ aux->term = ExecExhausted;
+ glp_ios_terminate(tree);
+ }else if(iterationcount > (aux->pivotLimit)){
+ aux->term = PivotsExhauasted;
+ glp_ios_terminate(tree);
+ }
}
break;
}
}
-ApproximateSimplex::ApproxResult ApproxGLPK::solveMIP(){
+std::vector<const CutInfo*> ApproxGLPK::getValidCuts(const NodeLog& con) throw (RationalFromDoubleException){
+ std::vector<const CutInfo*> proven;
+ int nid = con.getNodeId();
+ for(NodeLog::const_iterator j = con.begin(), jend=con.end(); j!=jend; ++j){
+ CutInfo* cut = *j;
+
+ if(cut->getKlass() != RowsDeletedKlass){
+ if(!cut->reconstructed()){
+ Assert(!cut->reconstructed());
+ tryCut(nid, *cut);
+ }
+ }
+
+ if(cut->proven()){
+ proven.push_back(cut);
+ }
+ }
+ return proven;
+}
+
+// std::vector<const CutInfo*> ApproxGLPK::getValidCuts(const std::set<const NodeLog*>& nodes){
+// // assume selected has been applied
+// std::vector<const CutInfo*> proven;
+// std::set<const NodeLog*>::const_iterator i, iend;
+// for(i = nodes.begin(), iend=nodes.end(); i!=iend; ++i){
+// const NodeLog* nl = *i;
+// getValidCuts(*nl, proven);
+// }
+
+// return proven;
+// }
+
+ArithVar ApproxGLPK::getBranchVar(const NodeLog& con) const{
+ int br_var = con.branchVariable();
+ return getArithVarFromStructural(br_var);
+}
+
+// Node ApproxGLPK::downBranchLiteral(const NodeLog& con) const{
+// int br_var = con.branchVariable();
+// ArithVar v = getArithVarFromStructural(br_var);
+// if(v != ARITHVAR_SENTINEL){
+// if(d_vars.isIntegerInput(v) && d_vars.hasNode(v)){
+// Node var = d_vars.asNode(v);
+// double br_val = con.branchValue();
+// Rational val = estimateWithCFE(br_val);
+// if(!val.isIntegral()){
+// NodeManager* nm = NodeManager::currentNM();
+// Node ineq = nm->mkNode(kind::LEQ, var, mkRationalNode(val));
+// return Rewriter::rewrite(ineq);
+// }
+// }
+// }
+// return Node::null();
+// }
+
+// std::vector<const NodeLog*> ApproxGLPK::getBranches(){
+// std::vector<const NodeLog*> branches;
+// for(TreeLog::const_iterator i = d_log.begin(), iend=d_log.end(); i!=iend;++i){
+// const NodeLog& con = (*i).second;
+// if(con.isBranch()){
+// branches.push_back(&con);
+// }
+// }
+// return branches;
+// }
+
+MipResult ApproxGLPK::solveMIP(bool activelyLog){
Assert(d_solvedRelaxation);
// Explicitly disable presolving
// We need the basis thus the presolver must be off!
// This is default, but this is just being cautious.
+ AuxInfo aux;
+ aux.pivotLimit = d_pivotLimit;
+ aux.branchLimit = d_branchLimit;
+ aux.branchDepth = d_maxDepth;
+ aux.tl = &d_log;
+ aux.term = MipUnknown;
+
+ d_log.reset(d_rootRowIds);
+ if(activelyLog){
+ d_log.makeActive();
+ }else{
+ d_log.makeInactive();
+ }
+
glp_iocp parm;
glp_init_iocp(&parm);
parm.presolve = GLP_OFF;
@@ -785,36 +1802,1361 @@ ApproximateSimplex::ApproxResult ApproxGLPK::solveMIP(){
parm.gmi_cuts = GLP_ON;
parm.mir_cuts = GLP_ON;
parm.cov_cuts = GLP_ON;
- parm.cb_func = stopAtBingoOrPivotLimit;
- parm.cb_info = &d_pivotLimit;
+ parm.cb_func = glpkCallback;
+ parm.cb_info = &aux;
parm.msg_lev = GLP_MSG_OFF;
if(s_verbosity >= 1){
parm.msg_lev = GLP_MSG_ALL;
}
- int res = glp_intopt(d_prob, &parm);
+
+ glp_erase_prob(d_mipProb);
+ glp_copy_prob(d_mipProb, d_realProb, GLP_OFF);
+
+ int res = glp_intopt(d_mipProb, &parm);
+
+ Debug("approx::solveMIP") << "res "<<res<<" aux.term "<< aux.term << endl;
switch(res){
case 0:
case GLP_ESTOP:
{
- int status = glp_mip_status(d_prob);
+ int status = glp_mip_status(d_mipProb);
+ Debug("approx::") << "status " << status << endl;
switch(status){
case GLP_OPT:
case GLP_FEAS:
d_solvedMIP = true;
- return ApproxSat;
+ Debug("approx::") << "bingo here!" << endl;
+ return MipBingo;
case GLP_NOFEAS:
d_solvedMIP = true;
- return ApproxUnsat;
+ return MipClosed;
default:
- return ApproxError;
+ if(aux.term == MipBingo){
+ d_solvedMIP = true;
+ Debug("approx::") << "bingo here?" << endl;
+ }
+ return aux.term;
}
}
default:
- return ApproxError;
+ return MipUnknown;
+ }
+}
+
+
+
+// Node explainSet(const set<ConstraintP>& inp){
+// Assert(!inp.empty());
+// NodeBuilder<> nb(kind::AND);
+// set<ConstraintP>::const_iterator iter, end;
+// for(iter = inp.begin(), end = inp.end(); iter != end; ++iter){
+// const ConstraintP c = *iter;
+// Assert(c != NullConstraint);
+// c->explainForConflict(nb);
+// }
+// Node ret = safeConstructNary(nb);
+// Node rew = Rewriter::rewrite(ret);
+// if(rew.getNumChildren() < ret.getNumChildren()){
+// //Debug("approx::") << "explainSet " << ret << " " << rew << endl;
+// }
+// return rew;
+// }
+
+DeltaRational sumConstraints(const DenseMap<Rational>& xs, const DenseMap<ConstraintP>& cs, bool* anyinf){
+ if(anyinf != NULL){
+ *anyinf = false;
+ }
+
+ DeltaRational beta(0);
+ DenseMap<Rational>::const_iterator iter, end;
+ iter = xs.begin();
+ end = xs.end();
+
+ Debug("approx::sumConstraints") << "sumConstraints";
+ for(; iter != end; ++iter){
+ ArithVar x = *iter;
+ const Rational& psi = xs[x];
+ ConstraintP c = cs[x];
+ Assert(c != NullConstraint);
+
+ const DeltaRational& bound = c->getValue();
+ beta += bound * psi;
+ Debug("approx::sumConstraints") << " +("<<bound << "*" << psi <<")";
+ if(anyinf != NULL ){
+ *anyinf = *anyinf || !bound.infinitesimalIsZero();
+ }
+ }
+ Debug("approx::sumConstraints") << "= " << beta << endl;
+
+ return beta;
+}
+
+// remove fixed variables from the vector
+void removeFixed(const ArithVariables& vars, DenseVector& dv, set<ConstraintP>& exp){
+ DenseMap<Rational>& vec = dv.lhs;
+ Rational& removed = dv.rhs;
+ vector<ArithVar> equal;
+ DenseMap<Rational>::const_iterator vec_iter, vec_end;
+ vec_iter = vec.begin(), vec_end = vec.end();
+ for(; vec_iter != vec_end; ++vec_iter){
+ ArithVar x = *vec_iter;
+ if(vars.boundsAreEqual(x)){
+ equal.push_back(x);
+ }
+ }
+ vector<ArithVar>::const_iterator equal_iter, equal_end;
+ equal_iter = equal.begin(), equal_end = equal.end();
+ for(; equal_iter != equal_end; ++equal_iter){
+ ArithVar x = *equal_iter;
+ Assert(vars.boundsAreEqual(x));
+ const DeltaRational& lb = vars.getLowerBound(x);
+ Assert(lb.infinitesimalIsZero());
+ removed -= (vec[x]) * lb.getNoninfinitesimalPart();
+
+ vec.remove(x);
+
+ std::pair<ConstraintP, ConstraintP> p = vars.explainEqualBounds(x);
+ exp.insert(p.first);
+ Debug("removeFixed") << "remove fixed " << p.first << endl;
+ if(p.second != NullConstraint){
+ exp.insert(p.second);
+ Debug("removeFixed") << "remove fixed " << p.second << endl;
+ }
+ }
+}
+void removeZeroes(DenseMap<Rational>& v){
+ // Remove Slack variables
+ vector<ArithVar> zeroes;
+ DenseMap<Rational>::const_iterator i, iend;
+ for(i = v.begin(), iend = v.end(); i != iend; ++i){
+ ArithVar x = *i;
+ if(v[x].isZero()){
+ zeroes.push_back(x);
+ }
+ }
+
+ vector<ArithVar>::const_iterator j, jend;
+ for(j = zeroes.begin(), jend = zeroes.end(); j != jend; ++j){
+ ArithVar x = *j;
+ v.remove(x);
+ }
+}
+void removeZeroes(DenseVector& v){
+ removeZeroes(v.lhs);
+}
+
+void removeAuxillaryVariables(const ArithVariables& vars, DenseMap<Rational>& vec){
+ // Remove auxillary variables
+ vector<ArithVar> aux;
+ DenseMap<Rational>::const_iterator vec_iter, vec_end;
+ vec_iter = vec.begin(), vec_end = vec.end();
+ for(; vec_iter != vec_end; ++vec_iter){
+ ArithVar x = *vec_iter;
+ if(vars.isAuxiliary(x)){
+ aux.push_back(x);
+ }
+ }
+
+ vector<ArithVar>::const_iterator aux_iter, aux_end;
+ aux_iter = aux.begin(), aux_end = aux.end();
+ for(; aux_iter != aux_end; ++aux_iter){
+ ArithVar s = *aux_iter;
+ Rational& s_coeff = vec.get(s);
+ Assert(vars.isAuxiliary(s));
+ Assert(vars.hasNode(s));
+ Node sAsNode = vars.asNode(s);
+ Polynomial p = Polynomial::parsePolynomial(sAsNode);
+ for(Polynomial::iterator j = p.begin(), p_end=p.end(); j != p_end; ++j){
+ Monomial m = *j;
+ const Rational& ns_coeff = m.getConstant().getValue();
+ Node vl = m.getVarList().getNode();
+ ArithVar ns = vars.asArithVar(vl);
+ Rational prod = s_coeff * ns_coeff;
+ if(vec.isKey(ns)){
+ vec.get(ns) += prod;
+ }else{
+ vec.set(ns, prod);
+ }
+ }
+ s_coeff = Rational(0); // subtract s_coeff * s from vec
+ }
+ removeZeroes(vec);
+}
+
+ArithVar ApproxGLPK::_getArithVar(int nid, int M, int ind) const{
+ if(ind <= 0){
+ return ARITHVAR_SENTINEL;
+ }else if(ind <= M){
+ return getArithVarFromRow(nid, ind);
+ }else{
+ return getArithVarFromStructural(ind - M);
+ }
+}
+
+
+bool ApproxGLPK::guessIsConstructable(const DenseMap<Rational>& guess) const {
+ // basic variable
+ // sum g[i] * x_i
+ DenseMap<Rational> g = guess;
+ removeAuxillaryVariables(d_vars, g);
+
+ if(Debug.isOn("guessIsConstructable")){
+ if(!g.empty()){
+ Debug("approx::guessIsConstructable") << "guessIsConstructable failed " << g.size() << endl;
+ DenseVector::print(Debug("approx::guessIsConstructable"), g);
+ Debug("approx::guessIsConstructable") << endl;
+ }
+ }
+ return g.empty();
+}
+
+bool ApproxGLPK::loadToBound(int nid, int M, int len, int* inds, int* statuses, DenseMap<ConstraintP>& toBound) const{
+ for(int i = 1; i <= len; ++i){
+ int status = statuses[i];
+ int ind = inds[i];
+ ArithVar v = _getArithVar(nid, M, ind);
+ ConstraintP c = NullConstraint;
+ if(v == ARITHVAR_SENTINEL){ return true; }
+
+ switch(status){
+ case GLP_NL:
+ c = d_vars.getLowerBoundConstraint(v);
+ break;
+ case GLP_NU:
+ case GLP_NS: // upper bound sufficies for fixed variables
+ c = d_vars.getUpperBoundConstraint(v);
+ break;
+ case GLP_NF:
+ default:
+ return true;
+ }
+ if(c == NullConstraint){
+ Debug("approx::") << "couldn't find " << v << " @ " << nid << endl;
+ return true;
+ }
+ Assert(c != NullConstraint);
+ toBound.set(v, c);
}
+ return false;
}
+bool ApproxGLPK::checkCutOnPad(int nid, const CutInfo& cut) const{
+
+ Debug("approx::checkCutOnPad") << "checkCutOnPad(" << nid <<", " << cut.getId() <<")"<<endl;
+
+ const DenseMap<Rational>& constructedLhs = d_pad.d_cut.lhs;
+ const Rational& constructedRhs = d_pad.d_cut.rhs;
+ hash_set<ArithVar> visited;
+
+ if(constructedLhs.empty()){
+ Debug("approx::checkCutOnPad") << "its empty?" <<endl;
+ return true;
+ }
+ if(cut.getKind() != d_pad.d_cutKind) {
+ Debug("approx::checkCutOnPad") << "rel doesn't match" << endl;
+ return true;
+ }
+
+ const PrimitiveVec& cv = cut.getCutVector();
+ for(int i = 1; i <= cv.len; ++i){
+ int ind = cv.inds[i]; // this is always a structural variable
+ double coeff = cv.coeffs[i];
+
+
+
+ if(!d_colToArithVar.isKey(ind)){ return true; }
+ ArithVar x = d_colToArithVar[ind];
+ //if(x == ARITHVAR_SENTINEL){ return true; }
+ visited.insert(x);
+
+
+ if(!constructedLhs.isKey(x)){
+ if(Debug.isOn("approx::checkCutOnPad")){
+ Debug("approx::checkCutOnPad") << " didn't find key for " << x << std::endl;
+ cut.print(Debug("approx::checkCutOnPad"));
+ Debug("approx::checkCutOnPad") << endl;
+ d_pad.d_cut.print(Debug("approx::checkCutOnPad"));
+ Debug("approx::checkCutOnPad") << endl;
+ }
+ return true;
+ }
+
+ const Rational& onConstructed = constructedLhs[x];
+
+ Debug("approx::checkCutOnPad") << ind << " " << coeff << " " << endl;
+ Debug("approx::checkCutOnPad") << " " << x << " " << onConstructed << endl;
+
+ if(!roughlyEqual(coeff, onConstructed.getDouble())){
+ Debug("approx::checkCutOnPad") << "coeff failure" << endl;
+ return true;
+ }
+ }
+ if(visited.size() != constructedLhs.size()){
+ Debug("approx::checkCutOnPad") << "size mismatch" << endl;
+ return true;
+ }
+
+
+ if(!roughlyEqual(cut.getRhs(), constructedRhs.getDouble())){
+ Debug("approx::checkCutOnPad")
+ << "norm rhs is off " << cut.getRhs() << " " << constructedRhs << endl;
+ return true;
+ }
+ return false;
+}
+
+
+
+bool ApproxGLPK::attemptBranchCut(int nid, const BranchCutInfo& br_cut){
+ d_pad.clear();
+
+ const PrimitiveVec& cut_vec = br_cut.getCutVector();
+ int structural = cut_vec.inds[1];
+ Assert(roughlyEqual(cut_vec.coeffs[1], +1.0));
+
+ ArithVar x = getArithVarFromStructural(structural);
+ d_pad.d_failure = (x == ARITHVAR_SENTINEL);
+ if(d_pad.d_failure){ return true; }
+
+ Kind brKind = br_cut.getKind();
+
+ d_pad.d_failure = (brKind != kind::LEQ && brKind != kind::GEQ);
+ if(d_pad.d_failure){ return true; }
+
+ d_pad.d_cutKind = brKind;
+ d_pad.d_cut.lhs.set(x, Rational(1));
+
+ Rational& rhs = d_pad.d_cut.rhs;
+ rhs = estimateWithCFE(Rational::fromDouble(br_cut.getRhs()), Integer(1));
+ d_pad.d_failure = !rhs.isIntegral();
+ if(d_pad.d_failure) { return true; }
+
+ d_pad.d_failure = checkCutOnPad(nid, br_cut);
+ if(d_pad.d_failure){ return true; }
+
+ return false;
+}
+
+bool ApproxGLPK::attemptGmi(int nid, const GmiInfo& gmi){
+ d_pad.clear();
+
+ d_pad.d_cutKind = kind::GEQ;
+
+ int M = gmi.getMAtCreation();
+ ArithVar b = _getArithVar(nid, M, gmi.basic);
+ d_pad.d_failure = (b == ARITHVAR_SENTINEL);
+ if(d_pad.d_failure){ return true; }
+
+ d_pad.d_failure = !d_vars.isIntegerInput(b);
+ if(d_pad.d_failure){ return true; }
+
+ d_pad.d_basic = b;
+
+
+ const PrimitiveVec& tab = gmi.tab_row;
+ d_pad.d_failure = attemptConstructTableRow(nid, M, tab);
+ if(d_pad.d_failure){ return true; }
+
+ int* statuses = gmi.tab_statuses;
+ DenseMap<ConstraintP>& toBound = d_pad.d_toBound;
+ d_pad.d_failure = loadToBound(nid, M, tab.len, tab.inds, statuses, toBound);
+ if(d_pad.d_failure){ return true; }
+
+ d_pad.d_failure = constructGmiCut();
+ if(d_pad.d_failure){ return true; }
+
+ d_pad.d_failure = checkCutOnPad(nid, gmi);
+ if(d_pad.d_failure){ return true; }
+
+ return false;
+}
+
+bool ApproxGLPK::applyCMIRRule(int nid, const MirInfo& mir){
+
+ const DenseMap<Rational>& compRanges = d_pad.d_compRanges;
+
+ DenseMap<Rational>& alpha = d_pad.d_alpha.lhs;
+ Rational& b = d_pad.d_alpha.rhs;
+
+ Rational delta = estimateWithCFE(mir.delta);
+ d_pad.d_failure = (delta.sgn() <= 0);
+ if(d_pad.d_failure){ return true; }
+
+ Debug("approx::mir") << "applyCMIRRule() " << delta << " " << mir.delta << endl;
+
+ DenseMap<Rational>::const_iterator iter, iend;
+ iter = alpha.begin(), iend = alpha.end();
+ for(; iter != iend; ++iter){
+ ArithVar v = *iter;
+ const Rational& curr = alpha[v];
+ Rational next = curr / delta;
+ if(compRanges.isKey(v)){
+ b -= curr * compRanges[v];
+ alpha.set(v, - next);
+ }else{
+ alpha.set(v, next);
+ }
+ }
+ b = b / delta;
+
+ Rational roundB = (b + Rational(1,2)).floor();
+ d_pad.d_failure = (b - roundB).abs() < Rational(1,90);
+ // intensionally more generous than glpk here
+ if(d_pad.d_failure){ return true; }
+
+ Rational one(1);
+ Rational fb = b.floor_frac();
+ Rational one_sub_fb = one - fb;
+ Rational gamma = (one / one_sub_fb);
+
+ DenseMap<Rational>& cut = d_pad.d_cut.lhs;
+ Rational& beta = d_pad.d_cut.rhs;
+
+ iter = alpha.begin(), iend = alpha.end();
+ for(; iter != iend; ++iter){
+ ArithVar v = *iter;
+ const Rational& a_j = alpha[v];
+ if(d_vars.isIntegerInput(v)){
+ Rational floor_aj = a_j.floor();
+ Rational frac_aj = a_j.floor_frac();
+ if(frac_aj <= fb){
+ cut.set(v, floor_aj);
+ }else{
+ Rational tmp = ((frac_aj - fb) / one_sub_fb);
+ cut.set(v, floor_aj + tmp);
+ }
+ }else{
+ cut.set(v, a_j * gamma);
+ }
+ }
+ beta = b.floor();
+
+ iter = cut.begin(), iend = cut.end();
+ for(; iter != iend; ++iter){
+ ArithVar v = *iter;
+ if(compRanges.isKey(v)){
+ Rational neg = - cut[v];
+ beta += neg * compRanges[v];
+ cut.set(v, neg);
+ }
+ }
+
+ return false;
+}
+
+bool ApproxGLPK::attemptMir(int nid, const MirInfo& mir){
+ d_pad.clear();
+
+ d_pad.d_cutKind = kind::LEQ;
+
+ // virtual bounds must be done before slacks
+ d_pad.d_failure = loadVirtualBoundsIntoPad(nid, mir);
+ if(d_pad.d_failure){ return true; }
+
+ d_pad.d_failure = loadSlacksIntoPad(nid, mir);
+ if(d_pad.d_failure){ return true; }
+
+
+ d_pad.d_failure = loadRowSumIntoAgg(nid, mir.getMAtCreation(), mir.row_sum);
+ if(d_pad.d_failure){ return true; }
+
+ removeFixed(d_vars, d_pad.d_agg, d_pad.d_explanation);
+
+ d_pad.d_failure = buildModifiedRow(nid, mir);
+ if(d_pad.d_failure){ return true; }
+
+ d_pad.d_failure = constructMixedKnapsack();
+ if(d_pad.d_failure){ return true; }
+
+ d_pad.d_failure = makeRangeForComplemented(nid, mir);
+ if(d_pad.d_failure){ return true; }
+
+ d_pad.d_failure = applyCMIRRule(nid, mir);
+ if(d_pad.d_failure){ return true; }
+
+ d_pad.d_failure = replaceSlacksOnCuts();
+ if(d_pad.d_failure){ return true; }
+
+ removeAuxillaryVariables(d_vars, d_pad.d_cut.lhs);
+
+ d_pad.d_failure = checkCutOnPad(nid, mir);
+ if(d_pad.d_failure){ return true; }
+
+ return false;
+ //return makeCutNodes(nid, mir);
+}
+
+bool ApproxGLPK::loadVB(int nid, int M, int j, int ri, bool wantUb, VirtualBound& tmp){
+ if(ri <= 0) { return true; }
+
+ static int instance = 0;
+ ++instance;
+ Debug("glpk::loadVB") << "loadVB() " << instance << endl;
+
+ ArithVar rowVar = _getArithVar(nid, M, ri);
+ ArithVar contVar = _getArithVar(nid, M, j);
+ if(rowVar == ARITHVAR_SENTINEL){ return true; }
+ if(contVar == ARITHVAR_SENTINEL){ return true; }
+
+ if(!d_vars.isAuxiliary(rowVar)){ return true; }
+ // is integer is correct here
+ if(d_vars.isInteger(contVar)){ return true; }
+
+ ConstraintP lb = d_vars.getLowerBoundConstraint(rowVar);
+ ConstraintP ub = d_vars.getUpperBoundConstraint(rowVar);
+
+ if(lb != NullConstraint && ub != NullConstraint){ return true; }
+
+ ConstraintP rcon = lb == NullConstraint ? ub : lb;
+ if(rcon == NullConstraint) { return true; }
+
+ if(!rcon->getValue().isZero()){ return true; }
+
+ if(!d_vars.hasNode(rowVar)){ return true; }
+ Polynomial p = Polynomial::parsePolynomial(d_vars.asNode(rowVar));
+ if(p.size() != 2) { return false; }
+
+ Monomial first = p.getHead(), second = p.getTail().getHead();
+ Rational c1 = first.getConstant().getValue();
+ Rational c2 = second.getConstant().getValue();
+ Node nx1 = first.getVarList().getNode();
+ Node nx2 = second.getVarList().getNode();
+
+ if(!d_vars.hasArithVar(nx1)) { return true; }
+ if(!d_vars.hasArithVar(nx2)) { return true; }
+ ArithVar x1 = d_vars.asArithVar(nx1), x2 = d_vars.asArithVar(nx2);
+
+ Assert(x1 != x2);
+ Assert(!c1.isZero());
+ Assert(!c2.isZero());
+
+ Debug("glpk::loadVB")
+ << " lb " << lb
+ << " ub " << ub
+ << " rcon " << rcon
+ << " x1 " << x1
+ << " x2 " << x2
+ << " c1 " << c1
+ << " c2 " << c2 << endl;
+
+ ArithVar iv = (x1 == contVar) ? x2 : x1;
+ Rational& cc = (x1 == contVar) ? c1 : c2;
+ Rational& ic = (x1 == contVar) ? c2 : c1;
+
+ Debug("glpk::loadVB")
+ << " cv " << contVar
+ << " cc " << cc
+ << " iv " << iv
+ << " c2 " << ic << endl;
+
+ if(!d_vars.isIntegerInput(iv)){ return true; }
+ // cc * cv + ic * iv <= 0 or
+ // cc * cv + ic * iv <= 0
+
+ if(rcon == ub){ // multiply by -1
+ cc = -cc; ic = - ic;
+ }
+ Debug("glpk::loadVB") << " cv " << contVar
+ << " cc " << cc
+ << " iv " << iv
+ << " c2 " << ic << endl;
+
+ // cc * cv + ic * iv >= 0
+ // cc * cv >= -ic * iv
+ // if cc < 0:
+ // cv <= -ic/cc * iv
+ // elif cc > 0:
+ // cv >= -ic/cc * iv
+ Assert(!cc.isZero());
+ Rational d = -ic/cc;
+ Debug("glpk::loadVB") << d << " " << cc.sgn() << endl;
+ bool nowUb = cc.sgn() < 0;
+ if(wantUb != nowUb) { return true; }
+
+ Kind rel = wantUb ? kind::LEQ : kind::GEQ;
+
+ tmp = VirtualBound(contVar, rel, d, iv, rcon);
+ return false;
+}
+
+bool ApproxGLPK::loadVirtualBoundsIntoPad(int nid, const MirInfo& mir){
+ Assert(mir.vlbRows != NULL);
+ Assert(mir.vubRows != NULL);
+
+ int N = mir.getN();
+ int M = mir.getMAtCreation();
+
+ // Load the virtual bounds first
+ VirtualBound tmp;
+ for(int j=1; j <= N+M; ++j){
+ if(!loadVB(nid, M, j, mir.vlbRows[j], false, tmp)){
+ if(d_pad.d_vlb.isKey(tmp.x)){ return true; }
+ d_pad.d_vlb.set(tmp.x, tmp);
+ }else if(mir.vlbRows[j] > 0){
+ Debug("approx::mir") << "expected vlb to work" << endl;
+ }
+ if(!loadVB(nid, M, j, mir.vubRows[j], true, tmp)){
+ if(d_pad.d_vub.isKey(tmp.x)){ return true; }
+ d_pad.d_vub.set(tmp.x, tmp);
+ }else if(mir.vubRows[j] > 0){
+ Debug("approx::mir") << "expected vub to work" << endl;
+ }
+ }
+ return false;
+}
+
+bool ApproxGLPK::loadSlacksIntoPad(int nid, const MirInfo& mir){
+ Assert(mir.vlbRows != NULL);
+ Assert(mir.vubRows != NULL);
+
+ int N = mir.getN();
+ int M = mir.getMAtCreation();
+
+ bool useVB;
+ // Load the virtual bounds first
+ SlackReplace rep;
+ bool lb;
+ ConstraintP b;
+ Debug("approx::mir") << "loadSlacksIntoPad(): N="<<N<<", M=" << M << std::endl;
+ for(int j=1; j <= N+M; ++j){
+ ArithVar v = _getArithVar(nid, M, j);
+ if(v == ARITHVAR_SENTINEL){
+ Debug("approx::mir") << " for: " << j << " no variable" << endl;
+ continue;
+ }
+ rep = SlackUndef;
+ char sub = mir.subst[j];
+ switch(sub){
+ case 'L':
+ case 'U':
+ lb = (sub == 'L');
+ useVB = lb ? (mir.vlbRows[j] > 0) : (mir.vubRows[j] > 0);
+ if(useVB){
+ if(lb ? d_pad.d_vlb.isKey(v) : d_pad.d_vub.isKey(v)){
+ rep = lb ? SlackVLB : SlackVUB;
+ }
+ }else{
+ b = lb ? d_vars.getLowerBoundConstraint(v)
+ : d_vars.getUpperBoundConstraint(v);
+ if(b != NullConstraint){
+ if(b->getValue().infinitesimalIsZero()){
+ rep = lb ? SlackLB : SlackUB;
+ }
+ }
+ }
+
+ Debug("approx::mir") << " for: " << j << ", " << v;
+ Debug("approx::mir") << " " << ((rep != SlackUndef) ? "succ" : "fail") << " ";
+ Debug("approx::mir") << sub << " " << rep << " " << mir.vlbRows[j] << " " << mir.vubRows[j]
+ << endl;
+ if(rep != SlackUndef){
+ d_pad.d_slacks.set(v,rep);
+ }
+ break;
+ case '?':
+ continue;
+ default:
+ Debug("approx::mir") << " for: " << j << " got subst " << (int)sub << endl;
+ continue;
+ }
+ }
+ return false;
+}
+
+bool ApproxGLPK::replaceSlacksOnCuts(){
+ vector<ArithVar> virtualVars;
+
+ DenseMap<Rational>& cut = d_pad.d_cut.lhs;
+ Rational& cutRhs = d_pad.d_cut.rhs;
+
+ DenseMap<Rational>::const_iterator iter, iend;
+ iter = cut.begin(), iend = cut.end();
+ for(; iter != iend; ++iter){
+ ArithVar x = *iter;
+ SlackReplace rep = d_pad.d_slacks[x];
+ if(d_vars.isIntegerInput(x)){
+ Assert(rep == SlackLB || rep == SlackUB);
+ Rational& a = cut.get(x);
+
+ const DeltaRational& bound = (rep == SlackLB) ?
+ d_vars.getLowerBound(x) : d_vars.getUpperBound(x);
+ Assert(bound.infinitesimalIsZero());
+ Rational prod = a * bound.getNoninfinitesimalPart();
+ if(rep == SlackLB){
+ cutRhs += prod;
+ }else{
+ cutRhs -= prod;
+ a = -a;
+ }
+ }else if(rep == SlackVLB){
+ virtualVars.push_back(d_pad.d_vlb[x].y);
+ }else if(rep == SlackVUB){
+ virtualVars.push_back(d_pad.d_vub[x].y);
+ }
+ }
+
+ for(size_t i = 0; i < virtualVars.size(); ++i){
+ ArithVar x = virtualVars[i];
+ if(!cut.isKey(x)){
+ cut.set(x, Rational(0));
+ }
+ }
+
+ iter = cut.begin(), iend = cut.end();
+ for(; iter != iend; ++iter){
+ ArithVar x = *iter;
+ if(!d_vars.isIntegerInput(x)){
+ SlackReplace rep = d_pad.d_slacks[x];
+ Rational& a = cut.get(x);
+ switch(rep){
+ case SlackLB:
+ {
+ const DeltaRational& bound = d_vars.getLowerBound(x);
+ Assert(bound.infinitesimalIsZero());
+ cutRhs += a * bound.getNoninfinitesimalPart();
+ }
+ break;
+ case SlackUB:
+ {
+ const DeltaRational& bound = d_vars.getUpperBound(x);
+ Assert(bound.infinitesimalIsZero());
+ cutRhs -= a * bound.getNoninfinitesimalPart();
+ a = -a;
+ }
+ break;
+ case SlackVLB:
+ case SlackVUB:
+ {
+ bool lb = (rep == SlackVLB);
+ const VirtualBound& vb = lb ?
+ d_pad.d_vlb[x] : d_pad.d_vub[x];
+ ArithVar y = vb.y;
+ Assert(vb.x == x);
+ Assert(cut.isKey(y));
+ Rational& ycoeff = cut.get(y);
+ if(lb){
+ ycoeff -= a * vb.d;
+ }else{
+ ycoeff += a * vb.d;
+ a = -a;
+ }
+ }
+ break;
+ default:
+ return true;
+ }
+ }
+ }
+ removeZeroes(cut);
+ return false;
+}
+
+bool ApproxGLPK::loadRowSumIntoAgg(int nid, int M, const PrimitiveVec& row_sum){
+ DenseMap<Rational>& lhs = d_pad.d_agg.lhs;
+ d_pad.d_agg.rhs = Rational(0);
+
+ int len = row_sum.len;
+ for(int i = 1; i <= len; ++i){
+ int aux_ind = row_sum.inds[i]; // auxillary index
+ double coeff = row_sum.coeffs[i];
+ ArithVar x = _getArithVar(nid, M, aux_ind);
+ if(x == ARITHVAR_SENTINEL){ return true; }
+ Rational c = estimateWithCFE(coeff);
+ if(lhs.isKey(x)){
+ lhs.get(x) -= c;
+ }else{
+ lhs.set(x, -c);
+ }
+ }
+
+ Debug("approx::mir") << "beg loadRowSumIntoAgg() 1" << endl;
+ if(Debug.isOn("approx::mir")) { DenseVector::print(Debug("approx::mir"), lhs); }
+ removeAuxillaryVariables(d_vars, lhs);
+ Debug("approx::mir") << "end loadRowSumIntoAgg() 1" << endl;
+
+ if(Debug.isOn("approx::mir")){
+ Debug("approx::mir") << "loadRowSumIntoAgg() 2" << endl;
+ DenseVector::print(Debug("approx::mir"), lhs);
+ Debug("approx::mir") << "end loadRowSumIntoAgg() 2" << endl;
+ }
+
+ for(int i = 1; i <= len; ++i){
+ int aux_ind = row_sum.inds[i]; // auxillary index
+ double coeff = row_sum.coeffs[i];
+ ArithVar x = _getArithVar(nid, M, aux_ind);
+ Assert(x != ARITHVAR_SENTINEL);
+ Rational c = estimateWithCFE(coeff);
+ Assert(!lhs.isKey(x));
+ lhs.set(x, c);
+ }
+
+ if(Debug.isOn("approx::mir")){
+ Debug("approx::mir") << "loadRowSumIntoAgg() 2" << endl;
+ DenseVector::print(Debug("approx::mir"), lhs);
+ Debug("approx::mir") << "end loadRowSumIntoAgg() 3" << endl;
+ }
+ return false;
+}
+
+bool ApproxGLPK::buildModifiedRow(int nid, const MirInfo& mir){
+ const DenseMap<Rational>& agg = d_pad.d_agg.lhs;
+ const Rational& aggRhs = d_pad.d_agg.rhs;
+ DenseMap<Rational>& mod = d_pad.d_mod.lhs;
+ Rational& modRhs = d_pad.d_mod.rhs;
+
+ Debug("approx::mir")
+ << "buildModifiedRow()"
+ << " |agg|=" << d_pad.d_agg.lhs.size()
+ << " |mod|=" << d_pad.d_mod.lhs.size()
+ << " |slacks|=" << d_pad.d_slacks.size()
+ << " |vlb|=" << d_pad.d_vub.size()
+ << " |vub|=" << d_pad.d_vlb.size() << endl;
+
+ mod.addAll(agg);
+ modRhs = aggRhs;
+ DenseMap<Rational>::const_iterator iter, iend;
+ for(iter = agg.begin(), iend = agg.end(); iter != iend; ++iter){
+ ArithVar x = *iter;
+ const Rational& c = mod[x];
+ if(!d_pad.d_slacks.isKey(x)){
+ Debug("approx::mir") << "missed x: " << x << endl;
+ return true;
+ }
+ SlackReplace rep = d_pad.d_slacks[x];
+ switch(rep){
+ case SlackLB: // skip for now
+ case SlackUB:
+ break;
+ case SlackVLB: /* x[k] = lb[k] * x[kk] + x'[k] */
+ case SlackVUB: /* x[k] = ub[k] * x[kk] - x'[k] */
+ {
+ Assert(!d_vars.isIntegerInput(x));
+ bool ub = (rep == SlackVUB);
+ const VirtualBound& vb =
+ ub ? d_pad.d_vub[x] : d_pad.d_vlb[x];
+ Assert(vb.x == x);
+ ArithVar y = vb.y;
+ Rational prod = c * vb.d;
+ if(mod.isKey(y)){
+ mod.get(x) += prod;
+ }else{
+ mod.set(y, prod);
+ }
+ if(ub){
+ mod.set(x, -c);
+ }
+ Assert(vb.c != NullConstraint);
+ d_pad.d_explanation.insert(vb.c);
+ }
+ break;
+ default:
+ return true;
+ }
+ }
+ removeZeroes(mod); /* if something cancelled we don't want it in the explanation */
+ for(iter = mod.begin(), iend = mod.end(); iter != iend; ++iter){
+ ArithVar x = *iter;
+ if(!d_pad.d_slacks.isKey(x)){ return true; }
+
+ SlackReplace rep = d_pad.d_slacks[x];
+ switch(rep){
+ case SlackLB: /* x = lb + x' */
+ case SlackUB: /* x = ub - x' */
+ {
+ bool ub = (rep == SlackUB);
+ ConstraintP b = ub ? d_vars.getUpperBoundConstraint(x):
+ d_vars.getLowerBoundConstraint(x);
+
+ Assert(b != NullConstraint);
+ Assert(b->getValue().infinitesimalIsZero());
+ const Rational& c = mod.get(x);
+ modRhs -= c * b->getValue().getNoninfinitesimalPart();
+ if(ub){
+ mod.set(x, -c);
+ }
+ d_pad.d_explanation.insert(b);
+ }
+ break;
+ case SlackVLB: /* handled earlier */
+ case SlackVUB:
+ break;
+ default:
+ return true;
+ }
+ }
+ removeZeroes(mod);
+ return false;
+}
+
+bool ApproxGLPK::makeRangeForComplemented(int nid, const MirInfo& mir){
+ DenseMap<Rational>& alpha = d_pad.d_alpha.lhs;
+ int M = mir.getMAtCreation();
+ int N = mir.getN();
+ DenseMap<Rational>& compRanges = d_pad.d_compRanges;
+
+ int complemented = 0;
+
+ for(int j = 1; j <= M + N; ++j){
+ if(mir.cset[j] != 0){
+ complemented++;
+ ArithVar x = _getArithVar(nid, M, j);
+ if(!alpha.isKey(x)){ return true; }
+ if(!d_vars.isIntegerInput(x)){ return true; }
+ Assert(d_pad.d_slacks.isKey(x));
+ Assert(d_pad.d_slacks[x] == SlackLB || d_pad.d_slacks[x] == SlackUB);
+
+ ConstraintP lb = d_vars.getLowerBoundConstraint(x);
+ ConstraintP ub = d_vars.getUpperBoundConstraint(x);
+
+ if(lb == NullConstraint) { return true; }
+ if(ub == NullConstraint) { return true; }
+
+ if(!lb->getValue().infinitesimalIsZero()){
+ return true;
+ }
+ if(!ub->getValue().infinitesimalIsZero()){
+ return true;
+ }
+
+ const Rational& uval = ub->getValue().getNoninfinitesimalPart();
+ const Rational& lval = lb->getValue().getNoninfinitesimalPart();
+
+ d_pad.d_explanation.insert(lb);
+ d_pad.d_explanation.insert(ub);
+
+ Rational u = uval - lval;
+ // u is the same for both rep == LP and rep == UB
+ if(compRanges.isKey(x)) { return true; }
+ compRanges.set(x,u);
+ }
+ }
+
+ Debug("approx::mir") << "makeRangeForComplemented()" << complemented << endl;
+ return false;
+}
+
+
+bool ApproxGLPK::constructMixedKnapsack(){
+ const DenseMap<Rational>& mod = d_pad.d_mod.lhs;
+ const Rational& modRhs = d_pad.d_mod.rhs;
+ DenseMap<Rational>& alpha = d_pad.d_alpha.lhs;
+ Rational& beta = d_pad.d_alpha.rhs;
+
+ Assert(alpha.empty());
+ beta = modRhs;
+
+ unsigned intVars = 0;
+ unsigned remain = 0;
+ unsigned dropped = 0;
+ DenseMap<Rational>::const_iterator iter, iend;
+ for(iter = mod.begin(), iend = mod.end(); iter != iend; ++iter){
+ ArithVar v = *iter;
+ const Rational& c = mod[v];
+ Assert(!c.isZero());
+ if(d_vars.isIntegerInput(v)){
+ intVars++;
+ alpha.set(v, c);
+ }else if(c.sgn() < 0){
+ remain++;
+ alpha.set(v, c);
+ }else{
+ dropped++;
+ }
+ }
+
+ Debug("approx::mir")
+ << "constructMixedKnapsack() "
+ <<" dropped " << dropped
+ <<" remain " << remain
+ <<" intVars " << intVars
+ << endl;
+ return intVars == 0; // if this is 0 we have failed
+}
+
+bool ApproxGLPK::attemptConstructTableRow(int nid, int M, const PrimitiveVec& vec){
+ bool failed = guessCoefficientsConstructTableRow(nid, M, vec);
+ if(failed){
+ failed = gaussianElimConstructTableRow(nid, M, vec);
+ }
+
+ return failed;
+}
+
+bool ApproxGLPK::gaussianElimConstructTableRow(int nid, int M, const PrimitiveVec& vec){
+ TimerStat::CodeTimer codeTimer(d_stats.d_gaussianElimConstructTime);
+ ++d_stats.d_gaussianElimConstruct;
+
+ ArithVar basic = d_pad.d_basic;
+ DenseMap<Rational>& tab = d_pad.d_tabRow.lhs;
+ tab.purge();
+ d_pad.d_tabRow.rhs = Rational(0);
+ Assert(basic != ARITHVAR_SENTINEL);
+ Assert(tab.empty());
+ Assert(d_pad.d_tabRow.rhs.isZero());
+
+ if(d_vars.isAuxiliary(basic)) { return true; }
+
+ if(Debug.isOn("gaussianElimConstructTableRow")){
+ Debug("gaussianElimConstructTableRow") << "1 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+ vec.print(Debug("gaussianElimConstructTableRow"));
+ Debug("gaussianElimConstructTableRow") << "match " << basic << "("<<d_vars.asNode(basic)<<")"<<endl;
+ }
+
+ set<ArithVar> onrow;
+ for(int i = 1; i <= vec.len; ++i){
+ int ind = vec.inds[i];
+ ArithVar var = _getArithVar(nid, M, ind);
+ if(var == ARITHVAR_SENTINEL){
+ Debug("gaussianElimConstructTableRow") << "couldn't find" << ind << " " << M << " " << nid << endl;
+ return true;
+ }
+ onrow.insert(var);
+ }
+
+
+ Debug("gaussianElimConstructTableRow") << "2 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+
+ Matrix<Rational> A;
+ A.increaseSizeTo(d_vars.getNumberOfVariables());
+ std::vector< std::pair<RowIndex, ArithVar> > rows;
+ set<ArithVar>::const_iterator i, iend;
+ // load the rows for auxiliary variables into A
+ for(i=onrow.begin(), iend=onrow.end(); i!=iend; ++i){
+ ArithVar v = *i;
+ if(d_vars.isAuxiliary(v)){
+ Assert(d_vars.hasNode(v));
+
+ vector<Rational> coeffs;
+ vector<ArithVar> vars;
+
+ coeffs.push_back(Rational(-1));
+ vars.push_back(v);
+
+ Node n = d_vars.asNode(v);
+ Polynomial p = Polynomial::parsePolynomial(n);
+ Polynomial::iterator j = p.begin(), jend=p.end();
+ for(j=p.begin(), jend=p.end(); j!=jend; ++j){
+ Monomial m = *j;
+ if(m.isConstant()) { return true; }
+ VarList vl = m.getVarList();
+ if(!d_vars.hasArithVar(vl.getNode())){ return true; }
+ ArithVar x = d_vars.asArithVar(vl.getNode());
+ const Rational& q = m.getConstant().getValue();
+ coeffs.push_back(q); vars.push_back(x);
+ }
+ RowIndex rid = A.addRow(coeffs, vars);
+ rows.push_back(make_pair(rid, ARITHVAR_SENTINEL));
+ }
+ }
+ Debug("gaussianElimConstructTableRow") << "3 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+
+ for(size_t i=0; i < rows.size(); ++i){
+ RowIndex rid = rows[i].first;
+ Assert(rows[i].second == ARITHVAR_SENTINEL);
+
+ // substitute previous rows
+ for(size_t j=0; j < i; j++){
+ RowIndex prevRow = rows[j].first;
+ ArithVar other = rows[j].second;
+ Assert(other != ARITHVAR_SENTINEL);
+ const Matrix<Rational>::Entry& e = A.findEntry(rid, other);
+ if(!e.blank()){
+ // r_p : 0 = -1 * other + sum a_i x_i
+ // rid : 0 = e * other + sum b_i x_i
+ // rid += e * r_p
+ // : 0 = 0 * other + ...
+ Assert(!e.getCoefficient().isZero());
+
+ Rational cp = e.getCoefficient();
+ Debug("gaussianElimConstructTableRow")
+ << "on " << rid << " subst " << cp << "*" << prevRow << " " << other << endl;
+ A.rowPlusRowTimesConstant(rid, prevRow, cp);
+ }
+ }
+ if(Debug.isOn("gaussianElimConstructTableRow")){
+ A.printMatrix(Debug("gaussianElimConstructTableRow"));
+ }
+
+ // solve the row for anything other than non-basics
+ bool solveForBasic = (i + 1 == rows.size());
+ Rational q;
+ ArithVar s = ARITHVAR_SENTINEL;
+ Matrix<Rational>::RowIterator k = A.getRow(rid).begin();
+ Matrix<Rational>::RowIterator k_end = A.getRow(rid).end();
+ for(; k != k_end; ++k){
+ const Matrix<Rational>::Entry& e = *k;
+ ArithVar colVar = e.getColVar();
+ bool selectColVar = false;
+ if(colVar == basic){
+ selectColVar = solveForBasic;
+ }else if(onrow.find(colVar) == onrow.end()) {
+ selectColVar = true;
+ }
+ if(selectColVar){
+ s = colVar;
+ q = e.getCoefficient();
+ }
+ }
+ if(s == ARITHVAR_SENTINEL || q.isZero()){
+ Debug("gaussianElimConstructTableRow") << "3 fail gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+ return true;
+ }else{
+ // 0 = q * s + sum c_i * x_i
+ Rational mult = -(q.inverse());
+ Debug("gaussianElimConstructTableRow") << "selecting " << s << " : " << mult << endl;
+ Debug("gaussianElimConstructTableRow") << "selecting " << rid << " " << s << endl;
+ //cout << "selecting " << s << " : complexity " << mult.complexity() << " " << mult << endl;
+ //cout << "selecting " << rid << " " << s << endl;
+ A.multiplyRowByConstant(rid, mult);
+ rows[i].second = s;
+ }
+ }
+ Debug("gaussianElimConstructTableRow") << "4 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+
+ if(rows.empty()) {
+ Debug("gaussianElimConstructTableRow") << "4 fail 1 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+ return true;
+ }
+ RowIndex rid_last = rows.back().first;
+ ArithVar rid_var = rows.back().second;
+ if(rid_var != basic){
+ Debug("gaussianElimConstructTableRow") << "4 fail 2 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+ return true;
+ }
+
+ Assert(tab.empty());
+
+ Matrix<Rational>::RowIterator k = A.getRow(rid_last).begin();
+ Matrix<Rational>::RowIterator k_end = A.getRow(rid_last).end();
+ for(; k != k_end; ++k){
+ const Matrix<Rational>::Entry& e = *k;
+ tab.set(e.getColVar(), e.getCoefficient());
+ }
+ Debug("gaussianElimConstructTableRow") << "5 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+ if(!tab.isKey(basic)){
+ Debug("gaussianElimConstructTableRow") << "5 fail 1 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+ return true;
+ }
+ if(tab[basic] != Rational(-1)){
+ Debug("gaussianElimConstructTableRow") << "5 fail 2 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+ return true;
+ }
+
+ tab.remove(basic);
+ Debug("gaussianElimConstructTableRow") << "6 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+
+ if(vec.len < 0 ){
+ Debug("gaussianElimConstructTableRow") << "6 fail 1 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+ return true;
+ }
+ if(tab.size() != ((unsigned)vec.len) ) {
+ Debug("gaussianElimConstructTableRow") << "6 fail 2 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<< tab.size() << " " << vec.len << endl;
+ return true;
+ }
+
+ Debug("gaussianElimConstructTableRow") << "7 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+
+ for(int i = 1; i <= vec.len; ++i){
+ int ind = vec.inds[i];
+ double coeff = vec.coeffs[i];
+ ArithVar var = _getArithVar(nid, M, ind);
+ Assert(var != ARITHVAR_SENTINEL);
+ if(!tab.isKey(var)){
+ Debug("gaussianElimConstructTableRow") << "7 fail 1 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"<<endl;
+ return true;
+ }
+
+ double est = tab[var].getDouble();
+
+ if(!ApproximateSimplex::roughlyEqual(coeff, est)){
+ Debug("gaussianElimConstructTableRow") << "7 fail 2 gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"
+ << " boink on " << ind << " " << var << " " << est <<endl;
+ return true;
+ }
+ Debug("gaussianElimConstructTableRow") << var << " cfe " << coeff << endl;
+ }
+
+ Debug("gaussianElimConstructTableRow")
+ << "gaussianElimConstructTableRow("<<nid <<", "<< basic<< ")"
+ << " superduper" << endl;
+
+ return false;
+}
+bool ApproxGLPK::guessCoefficientsConstructTableRow(int nid, int M, const PrimitiveVec& vec){
+ for(size_t i=0; i < d_denomGuesses.size(); ++i){
+ const Integer& D = d_denomGuesses[i];
+ if(!guessCoefficientsConstructTableRow(nid, M, vec, D)){
+ d_stats.d_averageGuesses.addEntry(i+1);
+ Debug("approx::gmi") << "guesseditat " << i << " D=" << D << endl;
+ return false;
+ }
+ }
+ return true;
+}
+bool ApproxGLPK::guessCoefficientsConstructTableRow(int nid, int M, const PrimitiveVec& vec, const Integer& D){
+ ArithVar basic = d_pad.d_basic;
+ DenseMap<Rational>& tab = d_pad.d_tabRow.lhs;
+ tab.purge();
+ d_pad.d_tabRow.rhs = Rational(0);
+ Assert(basic != ARITHVAR_SENTINEL);
+ Assert(tab.empty());
+ Assert(d_pad.d_tabRow.rhs.isZero());
+
+ if(Debug.isOn("guessCoefficientsConstructTableRow")){
+ Debug("guessCoefficientsConstructTableRow") << "attemptConstructTableRow("<<nid <<", "<< basic<<",...," << D<< ")"<<endl;
+ vec.print(Debug("guessCoefficientsConstructTableRow"));
+ Debug("guessCoefficientsConstructTableRow") << "match " << basic << "("<<d_vars.asNode(basic)<<")"<<endl;
+ }
+
+ tab.set(basic, Rational(-1));
+ for(int i = 1; i <= vec.len; ++i){
+ int ind = vec.inds[i];
+ double coeff = vec.coeffs[i];
+ ArithVar var = _getArithVar(nid, M, ind);
+ if(var == ARITHVAR_SENTINEL){
+ Debug("guessCoefficientsConstructTableRow") << "couldn't find" << ind << " " << M << " " << nid << endl;
+ return true;
+ }
+ Debug("guessCoefficientsConstructTableRow") << "match " << ind << "," << var << "("<<d_vars.asNode(var)<<")"<<endl;
+
+ Rational cfe = estimateWithCFE(coeff, D);
+ tab.set(var, cfe);
+ Debug("guessCoefficientsConstructTableRow") << var << " cfe " << cfe << endl;
+ }
+ if(!guessIsConstructable(tab)){
+ Debug("guessCoefficientsConstructTableRow") << "failed to construct with " << D << endl;
+ return true;
+ }
+ tab.remove(basic);
+ return false;
+}
+
+/* Maps an ArithVar to either an upper/lower bound */
+bool ApproxGLPK::constructGmiCut(){
+ const DenseMap<Rational>& tabRow = d_pad.d_tabRow.lhs;
+ const DenseMap<ConstraintP>& toBound = d_pad.d_toBound;
+ DenseMap<Rational>& cut = d_pad.d_cut.lhs;
+ std::set<ConstraintP>& explanation = d_pad.d_explanation;
+ Rational& rhs = d_pad.d_cut.rhs;
+
+ DenseMap<Rational>::const_iterator iter, end;
+ Assert(cut.empty());
+
+ // compute beta for a "fake" assignment
+ bool anyInf;
+ DeltaRational dbeta = sumConstraints(tabRow, toBound, &anyInf);
+ const Rational& beta = dbeta.getNoninfinitesimalPart();
+ Debug("approx::gmi") << dbeta << endl;
+ if(anyInf || beta.isIntegral()){ return true; }
+
+ Rational one = Rational(1);
+ Rational fbeta = beta.floor_frac();
+ rhs = fbeta;
+ Assert(fbeta.sgn() > 0);
+ Assert(fbeta < one);
+ Rational one_sub_fbeta = one - fbeta;
+ for(iter = tabRow.begin(), end = tabRow.end(); iter != end; ++iter){
+ ArithVar x = *iter;
+ const Rational& psi = tabRow[x];
+ ConstraintP c = toBound[x];
+ const Rational& bound = c->getValue().getNoninfinitesimalPart();
+ if(d_vars.boundsAreEqual(x)){
+ // do not add a coefficient
+ // implictly substitute the variable w/ its constraint
+ std::pair<ConstraintP, ConstraintP> exp = d_vars.explainEqualBounds(x);
+ explanation.insert(exp.first);
+ if(exp.second != NullConstraint){
+ explanation.insert(exp.second);
+ }
+ }else if(d_vars.isIntegerInput(x) && psi.isIntegral()){
+ // do not add a coefficient
+ // nothing to explain
+ Debug("approx::gmi") << "skipping " << x << endl;
+ }else{
+ explanation.insert(c);
+ Rational phi;
+ Rational alpha = (c->isUpperBound() ? psi : -psi);
+
+ // x - ub <= 0 and lb - x <= 0
+ if(d_vars.isIntegerInput(x)){
+ Assert(!psi.isIntegral());
+ // alpha = slack_sgn * psi
+ Rational falpha = alpha.floor_frac();
+ Assert(falpha.sgn() > 0);
+ Assert(falpha < one);
+ phi = (falpha <= fbeta) ?
+ falpha : ((fbeta / one_sub_fbeta) * (one - falpha));
+ }else{
+ phi = (alpha >= 0) ?
+ alpha : ((fbeta / one_sub_fbeta) * (- alpha));
+ }
+ Assert(phi.sgn() != 0);
+ if(c->isUpperBound()){
+ cut.set(x, -phi);
+ rhs -= phi * bound;
+ }else{
+ cut.set(x, phi);
+ rhs += phi * bound;
+ }
+ }
+ }
+ if(Debug.isOn("approx::gmi")){
+ Debug("approx::gmi") << "pre removeSlackVariables";
+ d_pad.d_cut.print(Debug("approx::gmi"));
+ Debug("approx::gmi") << endl;
+ }
+ removeAuxillaryVariables(d_vars, cut);
+
+ if(Debug.isOn("approx::gmi")){
+ Debug("approx::gmi") << "post removeAuxillaryVariables";
+ d_pad.d_cut.print(Debug("approx::gmi"));
+ Debug("approx::gmi") << endl;
+ }
+ removeFixed(d_vars, d_pad.d_cut, explanation);
+
+ if(Debug.isOn("approx::gmi")){
+ Debug("approx::gmi") << "post removeFixed";
+ d_pad.d_cut.print(Debug("approx::gmi"));
+ Debug("approx::gmi") << endl;
+ }
+ return false;
+}
+
+void ApproxGLPK::tryCut(int nid, CutInfo& cut) throw (RationalFromDoubleException){
+ Assert(!cut.reconstructed());
+ Assert(cut.getKlass() != RowsDeletedKlass);
+ bool failure = false;
+ switch(cut.getKlass()){
+ case GmiCutKlass:
+ failure = attemptGmi(nid, static_cast<const GmiInfo&>(cut));
+ break;
+ case MirCutKlass:
+ failure = attemptMir(nid, static_cast<const MirInfo&>(cut));
+ break;
+ case BranchCutKlass:
+ failure = attemptBranchCut(nid, dynamic_cast<const BranchCutInfo&>(cut));
+ break;
+ default:
+ break;
+ }
+ Assert(failure == d_pad.d_failure);
+
+ if(!failure){
+ // move the pad to the cut
+ cut.setReconstruction(d_pad.d_cut);
+
+ if(cut.getKlass() != BranchCutKlass){
+ std::set<ConstraintP>& exp = d_pad.d_explanation;
+ ConstraintCPVec asvec(exp.begin(), exp.end());
+ cut.swapExplanation(asvec);
+ }
+ }else{
+ Debug("approx") << "failure " << cut.getKlass() << endl;
+ }
+}
+
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/arith/approx_simplex.h b/src/theory/arith/approx_simplex.h
index b32fdef2d..15996fef8 100644
--- a/src/theory/arith/approx_simplex.h
+++ b/src/theory/arith/approx_simplex.h
@@ -22,7 +22,9 @@
#include "util/statistics_registry.h"
#include "theory/arith/arithvar.h"
-#include "theory/arith/linear_equality.h"
+#include "util/rational.h"
+#include "theory/arith/delta_rational.h"
+//#include "theory/arith/linear_equality.h"
#include "util/dense_map.h"
#include <vector>
@@ -30,10 +32,81 @@ namespace CVC4 {
namespace theory {
namespace arith {
+enum LinResult {
+ LinUnknown, /* Unknown error */
+ LinFeasible, /* Relaxation is feasible */
+ LinInfeasible, /* Relaxation is infeasible/all integer branches closed */
+ LinExhausted
+};
+
+enum MipResult {
+ MipUnknown, /* Unknown error */
+ MipBingo, /* Integer feasible */
+ MipClosed, /* All integer branches closed */
+ BranchesExhausted, /* Exhausted number of branches */
+ PivotsExhauasted, /* Exhausted number of pivots */
+ ExecExhausted /* Exhausted total operations */
+};
+std::ostream& operator<<(std::ostream& out, MipResult res);
+
+class ApproximateStatistics {
+public:
+ // IntStat d_relaxCalls;
+ // IntStat d_relaxUnknowns;
+ // IntStat d_relaxFeasible;
+ // IntStat d_relaxInfeasible;
+ // IntStat d_relaxPivotsExhausted;
+
+ // IntStat d_mipCalls;
+ // IntStat d_mipUnknowns;
+ // IntStat d_mipBingo;
+ // IntStat d_mipClosed;
+ // IntStat d_mipBranchesExhausted;
+ // IntStat d_mipPivotsExhausted;
+ // IntStat d_mipExecExhausted;
+
+
+ // IntStat d_gmiGen;
+ // IntStat d_gmiReplay;
+ // IntStat d_mipGen;
+ // IntStat d_mipReplay;
+
+ IntStat d_branchMaxDepth;
+ IntStat d_branchesMaxOnAVar;
+
+ TimerStat d_gaussianElimConstructTime;
+ IntStat d_gaussianElimConstruct;
+ AverageStat d_averageGuesses;
+
+ ApproximateStatistics();
+ ~ApproximateStatistics();
+};
+
+
+class NodeLog;
+class TreeLog;
+class ArithVariables;
+class CutInfo;
+class RowsDeleted;
class ApproximateSimplex{
protected:
+ const ArithVariables& d_vars;
+ TreeLog& d_log;
+ ApproximateStatistics& d_stats;
+
int d_pivotLimit;
+ /* the maximum pivots allowed in a query. */
+
+ int d_branchLimit;
+ /* maximum branches allowed on a variable */
+
+ int d_maxDepth;
+ /* maxmimum branching depth allowed.*/
+
+ static Integer s_defaultMaxDenom;
+ /* Default denominator for diophatine approximation.
+ * 2^{26}*/
public:
@@ -43,31 +116,48 @@ public:
* If glpk is enabled, return a subclass that can do something.
* If glpk is disabled, return a subclass that does nothing.
*/
- static ApproximateSimplex* mkApproximateSimplexSolver(const ArithVariables& vars);
- ApproximateSimplex();
+ static ApproximateSimplex* mkApproximateSimplexSolver(const ArithVariables& vars, TreeLog& l, ApproximateStatistics& s);
+ ApproximateSimplex(const ArithVariables& v, TreeLog& l, ApproximateStatistics& s);
virtual ~ApproximateSimplex(){}
+ /* the maximum pivots allowed in a query. */
+ void setPivotLimit(int pl);
+
+ /* maximum branches allowed on a variable */
+ void setBranchOnVariableLimit(int bl);
+
+ /* maximum branches allowed on a variable */
+ void setBranchingDepth(int bd);
+
/** A result is either sat, unsat or unknown.*/
- enum ApproxResult {ApproxError, ApproxSat, ApproxUnsat};
+ //enum ApproxResult {ApproxError, ApproxSat, ApproxUnsat};
struct Solution {
DenseSet newBasis;
DenseMap<DeltaRational> newValues;
Solution() : newBasis(), newValues(){}
};
- /** Sets a deterministic effort limit. */
- void setPivotLimit(int pivotLimit);
+ virtual ArithVar getBranchVar(const NodeLog& nl) const = 0;
+ //virtual void mapRowId(int nid, int ind, ArithVar v) = 0;
+ //virtual void applyRowsDeleted(int nid, const RowsDeleted& rd) = 0;
/** Sets a maximization criteria for the approximate solver.*/
virtual void setOptCoeffs(const ArithRatPairVec& ref) = 0;
virtual ArithRatPairVec heuristicOptCoeffs() const = 0;
- virtual ApproxResult solveRelaxation() = 0;
- virtual Solution extractRelaxation() const = 0;
+ virtual LinResult solveRelaxation() = 0;
+ virtual Solution extractRelaxation() const throw(RationalFromDoubleException) = 0;
+
+ virtual MipResult solveMIP(bool activelyLog) = 0;
+ virtual Solution extractMIP() const throw(RationalFromDoubleException) = 0;
+
+ virtual std::vector<const CutInfo*> getValidCuts(const NodeLog& node) throw(RationalFromDoubleException) = 0;
+ //virtual std::vector<const NodeLog*> getBranches() = 0;
- virtual ApproxResult solveMIP() = 0;
- virtual Solution extractMIP() const = 0;
+ //virtual Node downBranchLiteral(const NodeLog& con) const = 0;
+
+ virtual void tryCut(int nid, CutInfo& cut) throw(RationalFromDoubleException) = 0;
/** UTILITIES FOR DEALING WITH ESTIMATES */
@@ -82,7 +172,8 @@ public:
* cuts off the estimate once the value is approximately zero.
* This is designed for removing rounding artifacts.
*/
- static Rational estimateWithCFE(double d);
+ static Rational estimateWithCFE(double d) throw(RationalFromDoubleException);
+ static Rational estimateWithCFE(double d, const Integer& D) throw(RationalFromDoubleException);
/**
* Converts a rational to a continued fraction expansion representation
@@ -95,7 +186,10 @@ public:
static Rational cfeToRational(const std::vector<Integer>& exp);
/** Estimates a rational as a continued fraction expansion.*/
- static Rational estimateWithCFE(const Rational& q, int depth);
+ //static Rational estimateWithCFE(const Rational& q, int depth);
+ static Rational estimateWithCFE(const Rational& q, const Integer& K);
+
+ virtual double sumInfeasibilities(bool mip) const = 0;
};/* class ApproximateSimplex */
diff --git a/src/theory/arith/arith_ite_utils.cpp b/src/theory/arith/arith_ite_utils.cpp
new file mode 100644
index 000000000..4f182fb69
--- /dev/null
+++ b/src/theory/arith/arith_ite_utils.cpp
@@ -0,0 +1,436 @@
+#include "theory/arith/arith_ite_utils.h"
+#include "theory/arith/normal_form.h"
+#include "theory/arith/arith_utilities.h"
+#include "theory/ite_utilities.h"
+#include "theory/theory_model.h"
+#include "theory/rewriter.h"
+#include "theory/substitutions.h"
+#include <ostream>
+
+using namespace std;
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+Node ArithIteUtils::applyReduceVariablesInItes(Node n){
+ NodeBuilder<> nb(n.getKind());
+ if(n.getMetaKind() == kind::metakind::PARAMETERIZED) {
+ nb << (n.getOperator());
+ }
+ for(Node::iterator it = n.begin(), end = n.end(); it != end; ++it){
+ nb << reduceVariablesInItes(*it);
+ }
+ Node res = nb;
+ return res;
+}
+
+Node ArithIteUtils::reduceVariablesInItes(Node n){
+ using namespace CVC4::kind;
+ if(d_reduceVar.find(n) != d_reduceVar.end()){
+ Node res = d_reduceVar[n];
+ return res.isNull() ? n : res;
+ }
+
+ switch(n.getKind()){
+ case ITE:{
+ Node c = n[0], t = n[1], e = n[2];
+ if(n.getType().isReal()){
+ Node rc = reduceVariablesInItes(c);
+ Node rt = reduceVariablesInItes(t);
+ Node re = reduceVariablesInItes(e);
+
+ Node vt = d_varParts[t];
+ Node ve = d_varParts[e];
+ Node vpite = (vt == ve) ? vt : Node::null();
+
+ if(vpite.isNull()){
+ Node rite = rc.iteNode(rt, re);
+ // do not apply
+ d_reduceVar[n] = rite;
+ d_constants[n] = mkRationalNode(Rational(0));
+ d_varParts[n] = rite; // treat the ite as a variable
+ return rite;
+ }else{
+ NodeManager* nm = NodeManager::currentNM();
+ Node constantite = rc.iteNode(d_constants[t], d_constants[e]);
+ Node sum = nm->mkNode(kind::PLUS, vpite, constantite);
+ d_reduceVar[n] = sum;
+ d_constants[n] = constantite;
+ d_varParts[n] = vpite;
+ return sum;
+ }
+ }else{ // non-arith ite
+ if(!d_contains.containsTermITE(n)){
+ // don't bother adding to d_reduceVar
+ return n;
+ }else{
+ Node newIte = applyReduceVariablesInItes(n);
+ d_reduceVar[n] = (n == newIte) ? Node::null(): newIte;
+ return newIte;
+ }
+ }
+ }break;
+ default:
+ if(n.getType().isReal() && Polynomial::isMember(n)){
+ Node newn = Node::null();
+ if(!d_contains.containsTermITE(n)){
+ newn = n;
+ }else if(n.getNumChildren() > 0){
+ newn = applyReduceVariablesInItes(n);
+ newn = Rewriter::rewrite(newn);
+ Assert(Polynomial::isMember(newn));
+ }else{
+ newn = n;
+ }
+
+ Polynomial p = Polynomial::parsePolynomial(newn);
+ if(p.isConstant()){
+ d_constants[n] = newn;
+ d_varParts[n] = mkRationalNode(Rational(0));
+ // don't bother adding to d_reduceVar
+ return newn;
+ }else if(!p.containsConstant()){
+ d_constants[n] = mkRationalNode(Rational(0));
+ d_varParts[n] = newn;
+ d_reduceVar[n] = p.getNode();
+ return p.getNode();
+ }else{
+ Monomial mc = p.getHead();
+ d_constants[n] = mc.getConstant().getNode();
+ d_varParts[n] = p.getTail().getNode();
+ d_reduceVar[n] = newn;
+ return newn;
+ }
+ }else{
+ if(!d_contains.containsTermITE(n)){
+ return n;
+ }
+ if(n.getNumChildren() > 0){
+ Node res = applyReduceVariablesInItes(n);
+ d_reduceVar[n] = res;
+ return res;
+ }else{
+ return n;
+ }
+ }
+ break;
+ }
+ Unreachable();
+ return Node::null();
+}
+
+ArithIteUtils::ArithIteUtils(ContainsTermITEVisitor& contains,
+ context::Context* uc,
+ TheoryModel* model)
+ : d_contains(contains)
+ , d_subs(NULL)
+ , d_model(model)
+ , d_one(1)
+ , d_subcount(uc, 0)
+ , d_skolems(uc)
+ , d_implies()
+ , d_skolemsAdded()
+ , d_orBinEqs()
+{
+ d_subs = new SubstitutionMap(uc);
+}
+
+ArithIteUtils::~ArithIteUtils(){
+ delete d_subs;
+ d_subs = NULL;
+}
+
+void ArithIteUtils::clear(){
+ d_reduceVar.clear();
+ d_constants.clear();
+ d_varParts.clear();
+}
+
+const Integer& ArithIteUtils::gcdIte(Node n){
+ if(d_gcds.find(n) != d_gcds.end()){
+ return d_gcds[n];
+ }
+ if(n.getKind() == kind::CONST_RATIONAL){
+ const Rational& q = n.getConst<Rational>();
+ if(q.isIntegral()){
+ d_gcds[n] = q.getNumerator();
+ return d_gcds[n];
+ }else{
+ return d_one;
+ }
+ }else if(n.getKind() == kind::ITE && n.getType().isReal()){
+ const Integer& tgcd = gcdIte(n[1]);
+ if(tgcd.isOne()){
+ d_gcds[n] = d_one;
+ return d_one;
+ }else{
+ const Integer& egcd = gcdIte(n[2]);
+ Integer ite_gcd = tgcd.gcd(egcd);
+ d_gcds[n] = ite_gcd;
+ return d_gcds[n];
+ }
+ }
+ return d_one;
+}
+
+Node ArithIteUtils::reduceIteConstantIteByGCD_rec(Node n, const Rational& q){
+ if(n.isConst()){
+ Assert(n.getKind() == kind::CONST_RATIONAL);
+ return mkRationalNode(n.getConst<Rational>() * q);
+ }else{
+ Assert(n.getKind() == kind::ITE);
+ Assert(n.getType().isInteger());
+ Node rc = reduceConstantIteByGCD(n[0]);
+ Node rt = reduceIteConstantIteByGCD_rec(n[1], q);
+ Node re = reduceIteConstantIteByGCD_rec(n[2], q);
+ return rc.iteNode(rt, re);
+ }
+}
+
+Node ArithIteUtils::reduceIteConstantIteByGCD(Node n){
+ Assert(n.getKind() == kind::ITE);
+ Assert(n.getType().isReal());
+ const Integer& gcd = gcdIte(n);
+ if(gcd.isOne()){
+ Node newIte = reduceConstantIteByGCD(n[0]).iteNode(n[1],n[2]);
+ d_reduceGcd[n] = newIte;
+ return newIte;
+ }else if(gcd.isZero()){
+ Node zeroNode = mkRationalNode(Rational(0));
+ d_reduceGcd[n] = zeroNode;
+ return zeroNode;
+ }else{
+ Rational divBy(Integer(1), gcd);
+ Node redite = reduceIteConstantIteByGCD_rec(n, divBy);
+ Node gcdNode = mkRationalNode(Rational(gcd));
+ Node multIte = NodeManager::currentNM()->mkNode(kind::MULT, gcdNode, redite);
+ d_reduceGcd[n] = multIte;
+ return multIte;
+ }
+}
+
+Node ArithIteUtils::reduceConstantIteByGCD(Node n){
+ if(d_reduceGcd.find(n) != d_reduceGcd.end()){
+ return d_reduceGcd[n];
+ }
+ if(n.getKind() == kind::ITE && n.getType().isReal()){
+ return reduceIteConstantIteByGCD(n);
+ }
+
+ if(n.getNumChildren() > 0){
+ NodeBuilder<> nb(n.getKind());
+ if(n.getMetaKind() == kind::metakind::PARAMETERIZED) {
+ nb << (n.getOperator());
+ }
+ bool anychange = false;
+ for(Node::iterator it = n.begin(), end = n.end(); it != end; ++it){
+ Node child = *it;
+ Node redchild = reduceConstantIteByGCD(child);
+ anychange = anychange || (child != redchild);
+ nb << redchild;
+ }
+ if(anychange){
+ Node res = nb;
+ d_reduceGcd[n] = res;
+ return res;
+ }else{
+ d_reduceGcd[n] = n;
+ return n;
+ }
+ }else{
+ return n;
+ }
+}
+
+unsigned ArithIteUtils::getSubCount() const{
+ return d_subcount;
+}
+
+void ArithIteUtils::addSubstitution(TNode f, TNode t){
+ Debug("arith::ite") << "adding " << f << " -> " << t << endl;
+ d_subcount = d_subcount + 1;
+ d_subs->addSubstitution(f, t);
+ d_model->addSubstitution(f, t);
+}
+
+Node ArithIteUtils::applySubstitutions(TNode f){
+ return d_subs->apply(f);
+}
+
+Node ArithIteUtils::selectForCmp(Node n) const{
+ if(n.getKind() == kind::ITE){
+ if(d_skolems.find(n[0]) != d_skolems.end()){
+ return selectForCmp(n[1]);
+ }
+ }
+ return n;
+}
+
+void ArithIteUtils::learnSubstitutions(const std::vector<Node>& assertions){
+ for(size_t i=0, N=assertions.size(); i < N; ++i){
+ collectAssertions(assertions[i]);
+ }
+ bool solvedSomething;
+ do{
+ solvedSomething = false;
+ size_t readPos = 0, writePos = 0, N = d_orBinEqs.size();
+ for(; readPos < N; readPos++){
+ Node curr = d_orBinEqs[readPos];
+ bool solved = solveBinOr(curr);
+ if(solved){
+ solvedSomething = true;
+ }else{
+ // didn't solve, push back
+ d_orBinEqs[writePos] = curr;
+ writePos++;
+ }
+ }
+ Assert(writePos <= N);
+ 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();
+}
+
+void ArithIteUtils::addImplications(Node x, Node y){
+ // (or x y)
+ // (=> (not x) y)
+ // (=> (not y) x)
+
+ Node xneg = x.negate();
+ Node yneg = y.negate();
+ d_implies[xneg].insert(y);
+ d_implies[yneg].insert(x);
+}
+
+void ArithIteUtils::collectAssertions(TNode assertion){
+ if(assertion.getKind() == kind::OR){
+ if(assertion.getNumChildren() == 2){
+ TNode left = assertion[0], right = assertion[1];
+ addImplications(left, right);
+ if(left.getKind() == kind::EQUAL && right.getKind() == kind::EQUAL){
+ if(left[0].getType().isInteger() && right[0].getType().isInteger()){
+ d_orBinEqs.push_back(assertion);
+ }
+ }
+ }
+ }else if(assertion.getKind() == kind::AND){
+ for(unsigned i=0, N=assertion.getNumChildren(); i < N; ++i){
+ collectAssertions(assertion[i]);
+ }
+ }
+}
+
+Node ArithIteUtils::findIteCnd(TNode tb, TNode fb) const{
+ Node negtb = tb.negate();
+ Node negfb = fb.negate();
+ ImpMap::const_iterator ti = d_implies.find(negtb);
+ ImpMap::const_iterator fi = d_implies.find(negfb);
+
+ if(ti != d_implies.end() && fi != d_implies.end()){
+ const std::set<Node>& negtimp = ti->second;
+ const std::set<Node>& negfimp = fi->second;
+
+ // (or (not x) y)
+ // (or x z)
+ // (or y z)
+ // ---
+ // (ite x y z) return x
+ // ---
+ // (not y) => (not x)
+ // (not z) => x
+ std::set<Node>::const_iterator ci = negtimp.begin(), cend = negtimp.end();
+ for(; ci != cend; ci++){
+ Node impliedByNotTB = *ci;
+ Node impliedByNotTBNeg = impliedByNotTB.negate();
+ if(negfimp.find(impliedByNotTBNeg) != negfimp.end()){
+ return impliedByNotTBNeg; // implies tb
+ }
+ }
+ }
+
+ return Node::null();
+}
+
+bool ArithIteUtils::solveBinOr(TNode binor){
+ Assert(binor.getKind() == kind::OR);
+ Assert(binor.getNumChildren() == 2);
+ Assert(binor[0].getKind() == kind::EQUAL);
+ Assert(binor[1].getKind() == kind::EQUAL);
+
+ Node n = applySubstitutions(binor);
+ Assert(n.getKind() == kind::OR);
+ Assert(binor.getNumChildren() == 2);
+ TNode l = n[0];
+ TNode r = n[1];
+
+ Assert(l.getKind() == kind::EQUAL);
+ Assert(r.getKind() == kind::EQUAL);
+
+ Debug("arith::ite") << "bin or " << n << endl;
+
+ bool lArithEq = l.getKind() == kind::EQUAL && l[0].getType().isInteger();
+ bool rArithEq = r.getKind() == kind::EQUAL && r[0].getType().isInteger();
+
+ if(lArithEq && rArithEq){
+ TNode sel = Node::null();
+ TNode otherL = Node::null();
+ TNode otherR = Node::null();
+ if(l[0] == r[0]) {
+ sel = l[0]; otherL = l[1]; otherR = r[1];
+ }else if(l[0] == r[1]){
+ sel = l[0]; otherL = l[1]; otherR = r[0];
+ }else if(l[1] == r[0]){
+ sel = l[1]; otherL = l[0]; otherR = r[1];
+ }else if(l[1] == r[1]){
+ sel = l[1]; otherL = l[0]; otherR = r[0];
+ }
+ Debug("arith::ite") << "selected " << sel << endl;
+ if(sel.isVar() && sel.getKind() != kind::SKOLEM){
+
+ Debug("arith::ite") << "others l:" << otherL << " r " << otherR << endl;
+ Node useForCmpL = selectForCmp(otherL);
+ Node useForCmpR = selectForCmp(otherR);
+
+ Assert(Polynomial::isMember(sel));
+ Assert(Polynomial::isMember(useForCmpL));
+ Assert(Polynomial::isMember(useForCmpR));
+ Polynomial lside = Polynomial::parsePolynomial( useForCmpL );
+ Polynomial rside = Polynomial::parsePolynomial( useForCmpR );
+ Polynomial diff = lside-rside;
+
+ Debug("arith::ite") << "diff: " << diff.getNode() << endl;
+ if(diff.isConstant()){
+ // a: (sel = otherL) or (sel = otherR), otherL-otherR = c
+
+ NodeManager* nm = NodeManager::currentNM();
+
+ Node cnd = findIteCnd(binor[0], binor[1]);
+
+ 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;
+ }
+ }
+ }
+ return false;
+}
+
+
+}/* CVC4::theory::arith namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/arith/arith_ite_utils.h b/src/theory/arith/arith_ite_utils.h
new file mode 100644
index 000000000..5bdcd52da
--- /dev/null
+++ b/src/theory/arith/arith_ite_utils.h
@@ -0,0 +1,100 @@
+
+
+
+
+
+// Pass 1: label the ite as (constant) or (+ constant variable)
+
+#include "cvc4_private.h"
+
+#ifndef __CVC4__THEORY__ARITH__ARITH_ITE_UTILS_H
+#define __CVC4__THEORY__ARITH__ARITH_ITE_UTILS_H
+
+#include "expr/node.h"
+#include <ext/hash_map>
+#include <ext/hash_set>
+#include "context/cdo.h"
+#include "context/cdtrail_hashmap.h"
+
+namespace CVC4 {
+namespace theory {
+class ContainsTermITEVisitor;
+class SubstitutionMap;
+class TheoryModel;
+
+namespace arith {
+
+class ArithIteUtils {
+ ContainsTermITEVisitor& d_contains;
+ SubstitutionMap* d_subs;
+ TheoryModel* d_model;
+
+ typedef std::hash_map<Node, Node, NodeHashFunction> NodeMap;
+ // cache for reduce vars
+ NodeMap d_reduceVar; // if reduceVars[n].isNull(), treat reduceVars[n] == n
+
+ // reduceVars[n] = d_constants[n] + d_varParts[n]
+ NodeMap d_constants; // d_constants[n] is a constant ite tree
+ NodeMap d_varParts; // d_varParts[n] is a polynomial
+
+
+ NodeMap d_reduceGcd;
+ typedef std::hash_map<Node, Integer, NodeHashFunction> NodeIntegerMap;
+ NodeIntegerMap d_gcds;
+
+ Integer d_one;
+
+ context::CDO<unsigned> d_subcount;
+ typedef context::CDTrailHashMap<Node, Node, NodeHashFunction> CDNodeMap;
+ CDNodeMap d_skolems;
+
+ typedef std::map<Node, std::set<Node> > ImpMap;
+ ImpMap d_implies;
+
+ std::vector<Node> d_skolemsAdded;
+
+ std::vector<Node> d_orBinEqs;
+
+public:
+ ArithIteUtils(ContainsTermITEVisitor& contains,
+ context::Context* userContext,
+ TheoryModel* model);
+ ~ArithIteUtils();
+
+ //(ite ?v_2 ?v_1 (ite ?v_3 (- ?v_1 128) (- ?v_1 256)))
+
+ /** removes common sums variables sums from term ites. */
+ Node reduceVariablesInItes(Node n);
+
+ Node reduceConstantIteByGCD(Node n);
+
+ void clear();
+
+ Node applySubstitutions(TNode f);
+ unsigned getSubCount() const;
+
+ void learnSubstitutions(const std::vector<Node>& assertions);
+
+private:
+ /* applies this to all children of n and constructs the result */
+ Node applyReduceVariablesInItes(Node n);
+
+ const Integer& gcdIte(Node n);
+ Node reduceIteConstantIteByGCD_rec(Node n, const Rational& q);
+ Node reduceIteConstantIteByGCD(Node n);
+
+ void addSubstitution(TNode f, TNode t);
+ Node selectForCmp(Node n) const;
+
+ void collectAssertions(TNode assertion);
+ void addImplications(Node x, Node y);
+ Node findIteCnd(TNode tb, TNode fb) const;
+ bool solveBinOr(TNode binor);
+
+}; /* class ArithIteUtils */
+
+}/* CVC4::theory::arith namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
+
+#endif /* __CVC4__THEORY__ARITH__ARITH_ITE_UTILS_H */
diff --git a/src/theory/arith/arith_rewriter.cpp b/src/theory/arith/arith_rewriter.cpp
index e1cab0356..5aa904aed 100644
--- a/src/theory/arith/arith_rewriter.cpp
+++ b/src/theory/arith/arith_rewriter.cpp
@@ -222,36 +222,94 @@ RewriteResponse ArithRewriter::postRewriteTerm(TNode t){
RewriteResponse ArithRewriter::preRewriteMult(TNode t){
Assert(t.getKind()== kind::MULT);
- // Rewrite multiplications with a 0 argument and to 0
- Rational qZero(0);
+ if(t.getNumChildren() == 2){
+ if(t[0].getKind() == kind::CONST_RATIONAL
+ && t[0].getConst<Rational>().isOne()){
+ return RewriteResponse(REWRITE_DONE, t[1]);
+ }
+ if(t[1].getKind() == kind::CONST_RATIONAL
+ && t[1].getConst<Rational>().isOne()){
+ return RewriteResponse(REWRITE_DONE, t[0]);
+ }
+ }
+ // Rewrite multiplications with a 0 argument and to 0
for(TNode::iterator i = t.begin(); i != t.end(); ++i) {
if((*i).getKind() == kind::CONST_RATIONAL) {
- if((*i).getConst<Rational>() == qZero) {
- return RewriteResponse(REWRITE_DONE, mkRationalNode(qZero));
+ if((*i).getConst<Rational>().isZero()) {
+ TNode zero = (*i);
+ return RewriteResponse(REWRITE_DONE, zero);
}
}
}
return RewriteResponse(REWRITE_DONE, t);
}
+
+static bool canFlatten(Kind k, TNode t){
+ for(TNode::iterator i = t.begin(); i != t.end(); ++i) {
+ TNode child = *i;
+ if(child.getKind() == k){
+ return true;
+ }
+ }
+ return false;
+}
+
+static void flatten(std::vector<TNode>& pb, Kind k, TNode t){
+ if(t.getKind() == k){
+ for(TNode::iterator i = t.begin(); i != t.end(); ++i) {
+ TNode child = *i;
+ if(child.getKind() == k){
+ flatten(pb, k, child);
+ }else{
+ pb.push_back(child);
+ }
+ }
+ }else{
+ pb.push_back(t);
+ }
+}
+
+static Node flatten(Kind k, TNode t){
+ std::vector<TNode> pb;
+ flatten(pb, k, t);
+ Assert(pb.size() >= 2);
+ return NodeManager::currentNM()->mkNode(k, pb);
+}
+
RewriteResponse ArithRewriter::preRewritePlus(TNode t){
Assert(t.getKind()== kind::PLUS);
- return RewriteResponse(REWRITE_DONE, t);
+ if(canFlatten(kind::PLUS, t)){
+ return RewriteResponse(REWRITE_DONE, flatten(kind::PLUS, t));
+ }else{
+ return RewriteResponse(REWRITE_DONE, t);
+ }
}
RewriteResponse ArithRewriter::postRewritePlus(TNode t){
Assert(t.getKind()== kind::PLUS);
- Polynomial res = Polynomial::mkZero();
+ std::vector<Monomial> monomials;
+ std::vector<Polynomial> polynomials;
for(TNode::iterator i = t.begin(), end = t.end(); i != end; ++i){
- Node curr = *i;
- Polynomial currPoly = Polynomial::parsePolynomial(curr);
+ TNode curr = *i;
+ if(Monomial::isMember(curr)){
+ monomials.push_back(Monomial::parseMonomial(curr));
+ }else{
+ polynomials.push_back(Polynomial::parsePolynomial(curr));
+ }
+ }
- res = res + currPoly;
+ if(!monomials.empty()){
+ Monomial::sort(monomials);
+ Monomial::combineAdjacentMonomials(monomials);
+ polynomials.push_back(Polynomial::mkPolynomial(monomials));
}
+ Polynomial res = Polynomial::sumPolynomials(polynomials);
+
return RewriteResponse(REWRITE_DONE, res.getNode());
}
diff --git a/src/theory/arith/arith_static_learner.cpp b/src/theory/arith/arith_static_learner.cpp
index 8f6f75295..b9260c906 100644
--- a/src/theory/arith/arith_static_learner.cpp
+++ b/src/theory/arith/arith_static_learner.cpp
@@ -21,6 +21,8 @@
#include "theory/arith/arith_static_learner.h"
#include "theory/arith/options.h"
+#include "theory/arith/normal_form.h"
+
#include "expr/expr.h"
#include "expr/convenience_node_builders.h"
@@ -38,7 +40,11 @@ ArithStaticLearner::ArithStaticLearner(context::Context* userContext) :
d_minMap(userContext),
d_maxMap(userContext),
d_statistics()
-{}
+{
+}
+
+ArithStaticLearner::~ArithStaticLearner(){
+}
ArithStaticLearner::Statistics::Statistics():
d_iteMinMaxApplications("theory::arith::iteMinMaxApplications", 0),
@@ -98,14 +104,17 @@ void ArithStaticLearner::staticLearning(TNode n, NodeBuilder<>& learned){
}
-
-
-
void ArithStaticLearner::process(TNode n, NodeBuilder<>& learned, const TNodeSet& defTrue){
Debug("arith::static") << "===================== looking at " << n << endl;
switch(n.getKind()){
case ITE:
+ if(n.hasBoundVar()) {
+ // Unsafe with non-ground ITEs; do nothing
+ Debug("arith::static") << "(potentially) non-ground ITE, ignoring..." << endl;
+ break;
+ }
+
if(n[0].getKind() != EQUAL &&
isRelationOperator(n[0].getKind()) ){
iteMinMax(n, learned);
@@ -116,49 +125,12 @@ void ArithStaticLearner::process(TNode n, NodeBuilder<>& learned, const TNodeSet
iteConstant(n, learned);
}
break;
+
case CONST_RATIONAL:
// Mark constants as minmax
d_minMap.insert(n, n.getConst<Rational>());
d_maxMap.insert(n, n.getConst<Rational>());
break;
- case OR: {
- // Look for things like "x = 0 OR x = 1" (that are defTrue) and
- // turn them into a pseudoboolean. We catch "x >= 0
- if(defTrue.find(n) == defTrue.end() ||
- n.getNumChildren() != 2 ||
- n[0].getKind() != EQUAL ||
- n[1].getKind() != EQUAL) {
- break;
- }
- Node var, c1, c2;
- if(n[0][0].isVar() &&
- n[0][1].isConst()) {
- var = n[0][0];
- c1 = n[0][1];
- } else if(n[0][1].isVar() &&
- n[0][0].isConst()) {
- var = n[0][1];
- c1 = n[0][0];
- } else {
- break;
- }
- if(!var.getType().isInteger() ||
- !c1.getType().isReal()) {
- break;
- }
- if(var == n[1][0]) {
- c2 = n[1][1];
- } else if(var == n[1][1]) {
- c2 = n[1][0];
- } else {
- break;
- }
- if(!c2.getType().isReal()) {
- break;
- }
-
- break;
- }
default: // Do nothing
break;
}
diff --git a/src/theory/arith/arith_static_learner.h b/src/theory/arith/arith_static_learner.h
index d8407eeba..2615cdcd6 100644
--- a/src/theory/arith/arith_static_learner.h
+++ b/src/theory/arith/arith_static_learner.h
@@ -25,7 +25,6 @@
#include "theory/arith/arith_utilities.h"
#include "context/context.h"
-#include "context/cdlist.h"
#include "context/cdtrail_hashmap.h"
#include <set>
@@ -45,6 +44,7 @@ private:
public:
ArithStaticLearner(context::Context* userContext);
+ ~ArithStaticLearner();
void staticLearning(TNode n, NodeBuilder<>& learned);
void addBound(TNode n);
diff --git a/src/theory/arith/arith_utilities.h b/src/theory/arith/arith_utilities.h
index 11626c1de..98aa43e71 100644
--- a/src/theory/arith/arith_utilities.h
+++ b/src/theory/arith/arith_utilities.h
@@ -238,6 +238,25 @@ inline Node flattenAnd(Node n){
return NodeManager::currentNM()->mkNode(kind::AND, out);
}
+inline Node getIdentity(Kind k){
+ switch(k){
+ case kind::AND:
+ return NodeManager::currentNM()->mkConst<bool>(true);
+ case kind::PLUS:
+ return NodeManager::currentNM()->mkConst(Rational(1));
+ default:
+ Unreachable();
+ }
+}
+
+inline Node safeConstructNary(NodeBuilder<>& nb){
+ switch(nb.getNumChildren()){
+ case 0: return getIdentity(nb.getKind());
+ case 1: return nb[0];
+ default: return (Node)nb;
+ }
+}
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/arith/callbacks.cpp b/src/theory/arith/callbacks.cpp
index d4a445b70..c4b64682f 100644
--- a/src/theory/arith/callbacks.cpp
+++ b/src/theory/arith/callbacks.cpp
@@ -22,6 +22,9 @@ namespace CVC4 {
namespace theory {
namespace arith {
+SetupLiteralCallBack::SetupLiteralCallBack(TheoryArithPrivate& ta)
+ : d_arith(ta)
+{}
void SetupLiteralCallBack::operator()(TNode lit){
TNode atom = (lit.getKind() == kind::NOT) ? lit[0] : lit;
if(!d_arith.isSetup(atom)){
@@ -29,30 +32,72 @@ void SetupLiteralCallBack::operator()(TNode lit){
}
}
+DeltaComputeCallback::DeltaComputeCallback(const TheoryArithPrivate& ta)
+ : d_ta(ta)
+{}
Rational DeltaComputeCallback::operator()() const{
return d_ta.deltaValueForTotalOrder();
}
+TempVarMalloc::TempVarMalloc(TheoryArithPrivate& ta)
+: d_ta(ta)
+{}
ArithVar TempVarMalloc::request(){
Node skolem = mkRealSkolem("tmpVar");
- return d_ta.requestArithVar(skolem, false);
+ return d_ta.requestArithVar(skolem, false, true);
}
void TempVarMalloc::release(ArithVar v){
d_ta.releaseArithVar(v);
}
+BasicVarModelUpdateCallBack::BasicVarModelUpdateCallBack(TheoryArithPrivate& ta)
+ : d_ta(ta)
+{}
void BasicVarModelUpdateCallBack::operator()(ArithVar x){
d_ta.signal(x);
}
-void RaiseConflict::operator()(Node n){
- d_ta.raiseConflict(n);
+RaiseConflict::RaiseConflict(TheoryArithPrivate& ta, ConstraintCPVec& buf )
+ : d_ta(ta)
+ , d_construction(buf)
+{}
+
+/* Adds a constraint to the constraint under construction. */
+void RaiseConflict::addConstraint(ConstraintCP c){
+ d_construction.push_back(c);
+}
+/* Turns the vector under construction into a conflict */
+void RaiseConflict::commitConflict(){
+ Assert(!d_construction.empty());
+ sendConflict(d_construction);
+ d_construction.clear();
+}
+
+void RaiseConflict::sendConflict(const ConstraintCPVec& vec){
+ d_ta.raiseConflict(vec);
+}
+
+/* If you are not an equality engine, don't use this! */
+void RaiseConflict::blackBoxConflict(Node n){
+ d_ta.blackBoxConflict(n);
}
+
+BoundCountingLookup::BoundCountingLookup(TheoryArithPrivate& ta)
+: d_ta(ta)
+{}
+
const BoundsInfo& BoundCountingLookup::boundsInfo(ArithVar basic) const{
return d_ta.boundsInfo(basic);
}
+BoundCounts BoundCountingLookup::atBounds(ArithVar basic) const{
+ return boundsInfo(basic).atBounds();
+}
+BoundCounts BoundCountingLookup::hasBounds(ArithVar basic) const {
+ return boundsInfo(basic).hasBounds();
+}
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/arith/callbacks.h b/src/theory/arith/callbacks.h
index fd9369bf1..c4c79ad75 100644
--- a/src/theory/arith/callbacks.h
+++ b/src/theory/arith/callbacks.h
@@ -24,6 +24,7 @@
#include "theory/arith/theory_arith_private_forward.h"
#include "theory/arith/arithvar.h"
#include "theory/arith/bound_counts.h"
+#include "theory/arith/constraint_forward.h"
namespace CVC4 {
namespace theory {
@@ -67,7 +68,7 @@ class SetupLiteralCallBack : public TNodeCallBack {
private:
TheoryArithPrivate& d_arith;
public:
- SetupLiteralCallBack(TheoryArithPrivate& ta) : d_arith(ta){}
+ SetupLiteralCallBack(TheoryArithPrivate& ta);
void operator()(TNode lit);
};
@@ -75,7 +76,7 @@ class DeltaComputeCallback : public RationalCallBack {
private:
const TheoryArithPrivate& d_ta;
public:
- DeltaComputeCallback(const TheoryArithPrivate& ta) : d_ta(ta){}
+ DeltaComputeCallback(const TheoryArithPrivate& ta);
Rational operator()() const;
};
@@ -83,7 +84,7 @@ class BasicVarModelUpdateCallBack : public ArithVarCallBack{
private:
TheoryArithPrivate& d_ta;
public:
- BasicVarModelUpdateCallBack(TheoryArithPrivate& ta) : d_ta(ta) {}
+ BasicVarModelUpdateCallBack(TheoryArithPrivate& ta);
void operator()(ArithVar x);
};
@@ -91,31 +92,37 @@ class TempVarMalloc : public ArithVarMalloc {
private:
TheoryArithPrivate& d_ta;
public:
- TempVarMalloc(TheoryArithPrivate& ta) : d_ta(ta) {}
+ TempVarMalloc(TheoryArithPrivate& ta);
ArithVar request();
void release(ArithVar v);
};
-class RaiseConflict : public NodeCallBack {
+class RaiseConflict {
private:
TheoryArithPrivate& d_ta;
+ ConstraintCPVec& d_construction;
public:
- RaiseConflict(TheoryArithPrivate& ta) : d_ta(ta) {}
- void operator()(Node n);
+ RaiseConflict(TheoryArithPrivate& ta, ConstraintCPVec& d_construction);
+
+ /* Adds a constraint to the constraint under construction. */
+ void addConstraint(ConstraintCP c);
+ /* Turns the vector under construction into a conflict */
+ void commitConflict();
+
+ void sendConflict(const ConstraintCPVec& vec);
+
+ /* If you are not an equality engine, don't use this! */
+ void blackBoxConflict(Node n);
};
class BoundCountingLookup {
private:
TheoryArithPrivate& d_ta;
public:
- BoundCountingLookup(TheoryArithPrivate& ta) : d_ta(ta) {}
+ BoundCountingLookup(TheoryArithPrivate& ta);
const BoundsInfo& boundsInfo(ArithVar basic) const;
- BoundCounts atBounds(ArithVar basic) const{
- return boundsInfo(basic).atBounds();
- }
- BoundCounts hasBounds(ArithVar basic) const {
- return boundsInfo(basic).hasBounds();
- }
+ BoundCounts atBounds(ArithVar basic) const;
+ BoundCounts hasBounds(ArithVar basic) const;
};
}/* CVC4::theory::arith namespace */
diff --git a/src/theory/arith/congruence_manager.cpp b/src/theory/arith/congruence_manager.cpp
index a828b9e7f..d1d11c86e 100644
--- a/src/theory/arith/congruence_manager.cpp
+++ b/src/theory/arith/congruence_manager.cpp
@@ -65,11 +65,105 @@ ArithCongruenceManager::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(&d_conflicts);
}
+ArithCongruenceManager::ArithCongruenceNotify::ArithCongruenceNotify(ArithCongruenceManager& acm)
+ : d_acm(acm)
+{}
+
+bool ArithCongruenceManager::ArithCongruenceNotify::eqNotifyTriggerEquality(TNode equality, bool value) {
+ Debug("arith::congruences") << "ArithCongruenceNotify::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false") << ")" << std::endl;
+ if (value) {
+ return d_acm.propagate(equality);
+ } else {
+ return d_acm.propagate(equality.notNode());
+ }
+}
+bool ArithCongruenceManager::ArithCongruenceNotify::eqNotifyTriggerPredicate(TNode predicate, bool value) {
+ Unreachable();
+}
+
+bool ArithCongruenceManager::ArithCongruenceNotify::eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) {
+ Debug("arith::congruences") << "ArithCongruenceNotify::eqNotifyTriggerTermEquality(" << t1 << ", " << t2 << ", " << (value ? "true" : "false") << ")" << std::endl;
+ if (value) {
+ return d_acm.propagate(t1.eqNode(t2));
+ } else {
+ return d_acm.propagate(t1.eqNode(t2).notNode());
+ }
+}
+void ArithCongruenceManager::ArithCongruenceNotify::eqNotifyConstantTermMerge(TNode t1, TNode t2) {
+ Debug("arith::congruences") << "ArithCongruenceNotify::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << std::endl;
+ if (t1.getKind() == kind::CONST_BOOLEAN) {
+ d_acm.propagate(t1.iffNode(t2));
+ } else {
+ d_acm.propagate(t1.eqNode(t2));
+ }
+}
+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::eqNotifyDisequal(TNode t1, TNode t2, TNode reason) {
+}
+
+void ArithCongruenceManager::raiseConflict(Node conflict){
+ Assert(!inConflict());
+ Debug("arith::conflict") << "difference manager conflict " << conflict << std::endl;
+ d_inConflict.raise();
+ d_raiseConflict.blackBoxConflict(conflict);
+}
+bool ArithCongruenceManager::inConflict() const{
+ return d_inConflict.isRaised();
+}
+
+bool ArithCongruenceManager::hasMorePropagations() const {
+ return !d_propagatations.empty();
+}
+const Node ArithCongruenceManager::getNextPropagation() {
+ Assert(hasMorePropagations());
+ Node prop = d_propagatations.front();
+ d_propagatations.dequeue();
+ return prop;
+}
+
+bool ArithCongruenceManager::canExplain(TNode n) const {
+ return d_explanationMap.find(n) != d_explanationMap.end();
+}
+
void ArithCongruenceManager::setMasterEqualityEngine(eq::EqualityEngine* eq) {
d_ee.setMasterEqualityEngine(eq);
}
-void ArithCongruenceManager::watchedVariableIsZero(Constraint lb, Constraint ub){
+Node ArithCongruenceManager::externalToInternal(TNode n) const{
+ Assert(canExplain(n));
+ ExplainMap::const_iterator iter = d_explanationMap.find(n);
+ size_t pos = (*iter).second;
+ return d_propagatations[pos];
+}
+
+void ArithCongruenceManager::pushBack(TNode n){
+ d_explanationMap.insert(n, d_propagatations.size());
+ d_propagatations.enqueue(n);
+
+ ++(d_statistics.d_propagations);
+}
+void ArithCongruenceManager::pushBack(TNode n, TNode r){
+ d_explanationMap.insert(r, d_propagatations.size());
+ d_explanationMap.insert(n, d_propagatations.size());
+ d_propagatations.enqueue(n);
+
+ ++(d_statistics.d_propagations);
+}
+void ArithCongruenceManager::pushBack(TNode n, TNode r, TNode w){
+ d_explanationMap.insert(w, d_propagatations.size());
+ d_explanationMap.insert(r, d_propagatations.size());
+ d_explanationMap.insert(n, d_propagatations.size());
+ d_propagatations.enqueue(n);
+
+ ++(d_statistics.d_propagations);
+}
+
+void ArithCongruenceManager::watchedVariableIsZero(ConstraintCP lb, ConstraintCP ub){
Assert(lb->isLowerBound());
Assert(ub->isUpperBound());
Assert(lb->getVariable() == ub->getVariable());
@@ -79,13 +173,13 @@ void ArithCongruenceManager::watchedVariableIsZero(Constraint lb, Constraint ub)
++(d_statistics.d_watchedVariableIsZero);
ArithVar s = lb->getVariable();
- Node reason = ConstraintValue::explainConflict(lb,ub);
+ Node reason = Constraint_::externalExplainByAssertions(lb,ub);
d_keepAlive.push_back(reason);
assertionToEqualityEngine(true, s, reason);
}
-void ArithCongruenceManager::watchedVariableIsZero(Constraint eq){
+void ArithCongruenceManager::watchedVariableIsZero(ConstraintCP eq){
Assert(eq->isEquality());
Assert(eq->getValue().sgn() == 0);
@@ -96,20 +190,20 @@ void ArithCongruenceManager::watchedVariableIsZero(Constraint 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->explainForConflict();
+ Node reason = eq->externalExplainByAssertions();
d_keepAlive.push_back(reason);
assertionToEqualityEngine(true, s, reason);
}
-void ArithCongruenceManager::watchedVariableCannotBeZero(Constraint c){
+void ArithCongruenceManager::watchedVariableCannotBeZero(ConstraintCP c){
++(d_statistics.d_watchedVariableIsNotZero);
ArithVar s = c->getVariable();
//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->explainForConflict();
+ Node reason = c->externalExplainByAssertions();
d_keepAlive.push_back(reason);
assertionToEqualityEngine(false, s, reason);
@@ -142,7 +236,7 @@ bool ArithCongruenceManager::propagate(TNode x){
Assert(rewritten.getKind() != kind::CONST_BOOLEAN);
- Constraint c = d_constraintDatabase.lookup(rewritten);
+ ConstraintP c = d_constraintDatabase.lookup(rewritten);
if(c == NullConstraint){
//using setup as there may not be a corresponding congruence literal yet
d_setupLiteral(rewritten);
@@ -158,7 +252,8 @@ bool ArithCongruenceManager::propagate(TNode x){
if(c->negationHasProof()){
Node expC = explainInternal(x);
- Node neg = c->getNegation()->explainForConflict();
+ ConstraintCP negC = c->getNegation();
+ Node neg = negC->externalExplainByAssertions();
Node conf = expC.andNode(neg);
Node final = flattenAnd(conf);
@@ -288,7 +383,7 @@ void ArithCongruenceManager::assertionToEqualityEngine(bool isEquality, ArithVar
}
}
-void ArithCongruenceManager::equalsConstant(Constraint c){
+void ArithCongruenceManager::equalsConstant(ConstraintCP c){
Assert(c->isEquality());
++(d_statistics.d_equalsConstantCalls);
@@ -303,13 +398,13 @@ void ArithCongruenceManager::equalsConstant(Constraint c){
Node eq = xAsNode.eqNode(asRational);
d_keepAlive.push_back(eq);
- Node reason = c->explainForConflict();
+ Node reason = c->externalExplainByAssertions();
d_keepAlive.push_back(reason);
d_ee.assertEquality(eq, true, reason);
}
-void ArithCongruenceManager::equalsConstant(Constraint lb, Constraint ub){
+void ArithCongruenceManager::equalsConstant(ConstraintCP lb, ConstraintCP ub){
Assert(lb->isLowerBound());
Assert(ub->isUpperBound());
Assert(lb->getVariable() == ub->getVariable());
@@ -319,7 +414,7 @@ void ArithCongruenceManager::equalsConstant(Constraint lb, Constraint ub){
<< ub << std::endl;
ArithVar x = lb->getVariable();
- Node reason = ConstraintValue::explainConflict(lb,ub);
+ Node reason = Constraint_::externalExplainByAssertions(lb,ub);
Node xAsNode = d_avariables.asNode(x);
Node asRational = mkRationalNode(lb->getValue().getNoninfinitesimalPart());
diff --git a/src/theory/arith/congruence_manager.h b/src/theory/arith/congruence_manager.h
index b4e009169..8e369ff9a 100644
--- a/src/theory/arith/congruence_manager.h
+++ b/src/theory/arith/congruence_manager.h
@@ -57,43 +57,19 @@ private:
private:
ArithCongruenceManager& d_acm;
public:
- ArithCongruenceNotify(ArithCongruenceManager& acm): d_acm(acm) {}
-
- bool eqNotifyTriggerEquality(TNode equality, bool value) {
- Debug("arith::congruences") << "ArithCongruenceNotify::eqNotifyTriggerEquality(" << equality << ", " << (value ? "true" : "false") << ")" << std::endl;
- if (value) {
- return d_acm.propagate(equality);
- } else {
- return d_acm.propagate(equality.notNode());
- }
- }
-
- bool eqNotifyTriggerPredicate(TNode predicate, bool value) {
- Unreachable();
- }
-
- bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value) {
- Debug("arith::congruences") << "ArithCongruenceNotify::eqNotifyTriggerTermEquality(" << t1 << ", " << t2 << ", " << (value ? "true" : "false") << ")" << std::endl;
- if (value) {
- return d_acm.propagate(t1.eqNode(t2));
- } else {
- return d_acm.propagate(t1.eqNode(t2).notNode());
- }
- }
-
- void eqNotifyConstantTermMerge(TNode t1, TNode t2) {
- Debug("arith::congruences") << "ArithCongruenceNotify::eqNotifyConstantTermMerge(" << t1 << ", " << t2 << std::endl;
- if (t1.getKind() == kind::CONST_BOOLEAN) {
- d_acm.propagate(t1.iffNode(t2));
- } else {
- d_acm.propagate(t1.eqNode(t2));
- }
- }
-
- void eqNotifyNewClass(TNode t) { }
- void eqNotifyPreMerge(TNode t1, TNode t2) { }
- void eqNotifyPostMerge(TNode t1, TNode t2) { }
- void eqNotifyDisequal(TNode t1, TNode t2, TNode reason) { }
+ ArithCongruenceNotify(ArithCongruenceManager& acm);
+
+ bool eqNotifyTriggerEquality(TNode equality, bool value);
+
+ bool eqNotifyTriggerPredicate(TNode predicate, bool value);
+
+ bool eqNotifyTriggerTermEquality(TheoryId tag, TNode t1, TNode t2, bool value);
+
+ void eqNotifyConstantTermMerge(TNode t1, TNode t2);
+ void eqNotifyNewClass(TNode t);
+ void eqNotifyPreMerge(TNode t1, TNode t2);
+ void eqNotifyPostMerge(TNode t1, TNode t2);
+ void eqNotifyDisequal(TNode t1, TNode t2, TNode reason);
};
ArithCongruenceNotify d_notify;
@@ -117,66 +93,27 @@ private:
eq::EqualityEngine d_ee;
- void raiseConflict(Node conflict){
- Assert(!inConflict());
- Debug("arith::conflict") << "difference manager conflict " << conflict << std::endl;
- d_inConflict.raise();
- d_raiseConflict(conflict);
- }
+ void raiseConflict(Node conflict);
public:
- bool inConflict() const{
- return d_inConflict.isRaised();
- };
+ bool inConflict() const;
- bool hasMorePropagations() const {
- return !d_propagatations.empty();
- }
+ bool hasMorePropagations() const;
- const Node getNextPropagation() {
- Assert(hasMorePropagations());
- Node prop = d_propagatations.front();
- d_propagatations.dequeue();
- return prop;
- }
+ const Node getNextPropagation();
- bool canExplain(TNode n) const {
- return d_explanationMap.find(n) != d_explanationMap.end();
- }
+ bool canExplain(TNode n) const;
void setMasterEqualityEngine(eq::EqualityEngine* eq);
private:
- Node externalToInternal(TNode n) const{
- Assert(canExplain(n));
- ExplainMap::const_iterator iter = d_explanationMap.find(n);
- size_t pos = (*iter).second;
- return d_propagatations[pos];
- }
-
- void pushBack(TNode n){
- d_explanationMap.insert(n, d_propagatations.size());
- d_propagatations.enqueue(n);
-
- ++(d_statistics.d_propagations);
- }
-
- void pushBack(TNode n, TNode r){
- d_explanationMap.insert(r, d_propagatations.size());
- d_explanationMap.insert(n, d_propagatations.size());
- d_propagatations.enqueue(n);
+ Node externalToInternal(TNode n) const;
- ++(d_statistics.d_propagations);
- }
+ void pushBack(TNode n);
- void pushBack(TNode n, TNode r, TNode w){
- d_explanationMap.insert(w, d_propagatations.size());
- d_explanationMap.insert(r, d_propagatations.size());
- d_explanationMap.insert(n, d_propagatations.size());
- d_propagatations.enqueue(n);
+ void pushBack(TNode n, TNode r);
- ++(d_statistics.d_propagations);
- }
+ void pushBack(TNode n, TNode r, TNode w);
bool propagate(TNode x);
void explain(TNode literal, std::vector<TNode>& assumptions);
@@ -207,21 +144,21 @@ public:
}
/** Assert an equality. */
- void watchedVariableIsZero(Constraint eq);
+ void watchedVariableIsZero(ConstraintCP eq);
/** Assert a conjunction from lb and ub. */
- void watchedVariableIsZero(Constraint lb, Constraint ub);
+ void watchedVariableIsZero(ConstraintCP lb, ConstraintCP ub);
/** Assert that the value cannot be zero. */
- void watchedVariableCannotBeZero(Constraint c);
+ void watchedVariableCannotBeZero(ConstraintCP c);
/** Assert that the value cannot be zero. */
- void watchedVariableCannotBeZero(Constraint c, Constraint d);
+ void watchedVariableCannotBeZero(ConstraintCP c, ConstraintCP d);
/** Assert that the value is congruent to a constant. */
- void equalsConstant(Constraint eq);
- void equalsConstant(Constraint lb, Constraint ub);
+ void equalsConstant(ConstraintCP eq);
+ void equalsConstant(ConstraintCP lb, ConstraintCP ub);
void addSharedTerm(Node x);
diff --git a/src/theory/arith/constraint.cpp b/src/theory/arith/constraint.cpp
index 78b9d3494..acbd4a04b 100644
--- a/src/theory/arith/constraint.cpp
+++ b/src/theory/arith/constraint.cpp
@@ -64,7 +64,7 @@ ConstraintType constraintTypeOfComparison(const Comparison& cmp){
}
}
-ConstraintValue::ConstraintValue(ArithVar x, ConstraintType t, const DeltaRational& v)
+Constraint_::Constraint_(ArithVar x, ConstraintType t, const DeltaRational& v)
: d_variable(x),
d_type(t),
d_value(v),
@@ -72,7 +72,7 @@ ConstraintValue::ConstraintValue(ArithVar x, ConstraintType t, const DeltaRatio
d_literal(Node::null()),
d_negation(NullConstraint),
d_canBePropagated(false),
- _d_assertionOrder(AssertionOrderSentinel),
+ d_assertionOrder(AssertionOrderSentinel),
d_witness(TNode::null()),
d_proof(ProofIdSentinel),
d_split(false),
@@ -82,7 +82,7 @@ ConstraintValue::ConstraintValue(ArithVar x, ConstraintType t, const DeltaRatio
}
-std::ostream& operator<<(std::ostream& o, const Constraint c){
+std::ostream& operator<<(std::ostream& o, const ConstraintP c){
if(c == NullConstraint){
return o << "NullConstraint";
}else{
@@ -105,7 +105,7 @@ std::ostream& operator<<(std::ostream& o, const ConstraintType t){
}
}
-std::ostream& operator<<(std::ostream& o, const ConstraintValue& c){
+std::ostream& operator<<(std::ostream& o, const Constraint_& c){
o << c.getVariable() << ' ' << c.getType() << ' ' << c.getValue();
if(c.hasLiteral()){
o << "(node " << c.getLiteral() << ')';
@@ -143,11 +143,67 @@ std::ostream& operator<<(std::ostream& o, const ValueCollection& vc){
return o << "}";
}
-void ConstraintValue::debugPrint() const {
+std::ostream& operator<<(std::ostream& o, const ConstraintCPVec& v){
+ o << "[" << v.size() << "x";
+ ConstraintCPVec::const_iterator i, end;
+ for(i=v.begin(), end=v.end(); i != end; ++i){
+ ConstraintCP c = *i;
+ o << ", " << (*c);
+ }
+ o << "]";
+ return o;
+}
+
+void Constraint_::debugPrint() const {
Message() << *this << endl;
}
-void ValueCollection::push_into(std::vector<Constraint>& vec) const {
+
+ValueCollection::ValueCollection()
+ : d_lowerBound(NullConstraint),
+ d_upperBound(NullConstraint),
+ d_equality(NullConstraint),
+ d_disequality(NullConstraint)
+{}
+
+bool ValueCollection::hasLowerBound() const{
+ return d_lowerBound != NullConstraint;
+}
+
+bool ValueCollection::hasUpperBound() const{
+ return d_upperBound != NullConstraint;
+}
+
+bool ValueCollection::hasEquality() const{
+ return d_equality != NullConstraint;
+}
+
+bool ValueCollection::hasDisequality() const {
+ return d_disequality != NullConstraint;
+}
+
+ConstraintP ValueCollection::getLowerBound() const {
+ Assert(hasLowerBound());
+ return d_lowerBound;
+}
+
+ConstraintP ValueCollection::getUpperBound() const {
+ Assert(hasUpperBound());
+ return d_upperBound;
+}
+
+ConstraintP ValueCollection::getEquality() const {
+ Assert(hasEquality());
+ return d_equality;
+}
+
+ConstraintP ValueCollection::getDisequality() const {
+ Assert(hasDisequality());
+ return d_disequality;
+}
+
+
+void ValueCollection::push_into(std::vector<ConstraintP>& vec) const {
Debug("arith::constraint") << "push_into " << *this << endl;
if(hasEquality()){
vec.push_back(d_equality);
@@ -163,7 +219,7 @@ void ValueCollection::push_into(std::vector<Constraint>& vec) const {
}
}
-ValueCollection ValueCollection::mkFromConstraint(Constraint c){
+ValueCollection ValueCollection::mkFromConstraint(ConstraintP c){
ValueCollection ret;
Assert(ret.empty());
switch(c->getType()){
@@ -210,7 +266,7 @@ const DeltaRational& ValueCollection::getValue() const{
return nonNull()->getValue();
}
-void ValueCollection::add(Constraint c){
+void ValueCollection::add(ConstraintP c){
Assert(c != NullConstraint);
Assert(empty() || getVariable() == c->getVariable());
@@ -238,7 +294,7 @@ void ValueCollection::add(Constraint c){
}
}
-Constraint ValueCollection::getConstraintOfType(ConstraintType t) const{
+ConstraintP ValueCollection::getConstraintOfType(ConstraintType t) const{
switch(t){
case LowerBound:
Assert(hasLowerBound());
@@ -288,7 +344,7 @@ bool ValueCollection::empty() const{
hasDisequality());
}
-Constraint ValueCollection::nonNull() const{
+ConstraintP ValueCollection::nonNull() const{
//This can be optimized by caching, but this is not necessary yet!
/* "Premature optimization is the root of all evil." */
if(hasLowerBound()){
@@ -304,18 +360,18 @@ Constraint ValueCollection::nonNull() const{
}
}
-bool ConstraintValue::initialized() const {
+bool Constraint_::initialized() const {
return d_database != NULL;
}
-void ConstraintValue::initialize(ConstraintDatabase* db, SortedConstraintMapIterator v, Constraint negation){
+void Constraint_::initialize(ConstraintDatabase* db, SortedConstraintMapIterator v, ConstraintP negation){
Assert(!initialized());
d_database = db;
d_variablePosition = v;
d_negation = negation;
}
-ConstraintValue::~ConstraintValue() {
+Constraint_::~Constraint_() {
Assert(safeToGarbageCollect());
if(initialized()){
@@ -336,12 +392,12 @@ ConstraintValue::~ConstraintValue() {
}
}
-const ValueCollection& ConstraintValue::getValueCollection() const{
+const ValueCollection& Constraint_::getValueCollection() const{
return d_variablePosition->second;
}
-Constraint ConstraintValue::getCeiling() {
- Debug("getCeiling") << "ConstraintValue::getCeiling on " << *this << endl;
+ConstraintP Constraint_::getCeiling() {
+ Debug("getCeiling") << "Constraint_::getCeiling on " << *this << endl;
Assert(getValue().getInfinitesimalPart().sgn() > 0);
DeltaRational ceiling(getValue().ceiling());
@@ -350,7 +406,7 @@ Constraint ConstraintValue::getCeiling() {
return d_database->getConstraint(getVariable(), getType(), ceiling);
}
-Constraint ConstraintValue::getFloor() {
+ConstraintP Constraint_::getFloor() {
Assert(getValue().getInfinitesimalPart().sgn() < 0);
DeltaRational floor(Rational(getValue().floor()));
@@ -359,19 +415,26 @@ Constraint ConstraintValue::getFloor() {
return d_database->getConstraint(getVariable(), getType(), floor);
}
-void ConstraintValue::setCanBePropagated() {
+void Constraint_::setCanBePropagated() {
Assert(!canBePropagated());
d_database->pushCanBePropagatedWatch(this);
}
-void ConstraintValue::setAssertedToTheTheory(TNode witness) {
+void Constraint_::setAssertedToTheTheoryWithNegationTrue(TNode witness) {
+ Assert(hasLiteral());
+ Assert(!assertedToTheTheory());
+ Assert(d_negation->hasProof());
+ d_database->pushAssertionOrderWatch(this, witness);
+}
+
+void Constraint_::setAssertedToTheTheory(TNode witness) {
Assert(hasLiteral());
Assert(!assertedToTheTheory());
Assert(!d_negation->assertedToTheTheory());
d_database->pushAssertionOrderWatch(this, witness);
}
-bool ConstraintValue::satisfiedBy(const DeltaRational& dr) const {
+bool Constraint_::satisfiedBy(const DeltaRational& dr) const {
switch(getType()){
case LowerBound:
return getValue() <= dr;
@@ -385,19 +448,19 @@ bool ConstraintValue::satisfiedBy(const DeltaRational& dr) const {
Unreachable();
}
-// bool ConstraintValue::isPsuedoConstraint() const {
-// return d_proof == d_database->d_psuedoConstraintProof;
-// }
+bool Constraint_::isInternalDecision() const {
+ return d_proof == d_database->d_internalDecisionProof;
+}
-bool ConstraintValue::isSelfExplaining() const {
+bool Constraint_::isSelfExplaining() const {
return d_proof == d_database->d_selfExplainingProof;
}
-bool ConstraintValue::hasEqualityEngineProof() const {
+bool Constraint_::hasEqualityEngineProof() const {
return d_proof == d_database->d_equalityEngineProof;
}
-bool ConstraintValue::sanityChecking(Node n) const {
+bool Constraint_::sanityChecking(Node n) const {
Comparison cmp = Comparison::parseNormalForm(n);
Kind k = cmp.comparisonKind();
Polynomial pleft = cmp.normalizedVariablePart();
@@ -441,7 +504,7 @@ bool ConstraintValue::sanityChecking(Node n) const {
}
}
-Constraint ConstraintValue::makeNegation(ArithVar v, ConstraintType t, const DeltaRational& r){
+ConstraintP Constraint_::makeNegation(ArithVar v, ConstraintType t, const DeltaRational& r){
switch(t){
case LowerBound:
{
@@ -450,12 +513,12 @@ Constraint ConstraintValue::makeNegation(ArithVar v, ConstraintType t, const Del
Assert(r.getInfinitesimalPart() == 1);
// make (not (v > r)), which is (v <= r)
DeltaRational dropInf(r.getNoninfinitesimalPart(), 0);
- return new ConstraintValue(v, UpperBound, dropInf);
+ return new Constraint_(v, UpperBound, dropInf);
}else{
Assert(r.infinitesimalSgn() == 0);
// make (not (v >= r)), which is (v < r)
DeltaRational addInf(r.getNoninfinitesimalPart(), -1);
- return new ConstraintValue(v, UpperBound, addInf);
+ return new Constraint_(v, UpperBound, addInf);
}
}
case UpperBound:
@@ -465,18 +528,18 @@ Constraint ConstraintValue::makeNegation(ArithVar v, ConstraintType t, const Del
Assert(r.getInfinitesimalPart() == -1);
// make (not (v < r)), which is (v >= r)
DeltaRational dropInf(r.getNoninfinitesimalPart(), 0);
- return new ConstraintValue(v, LowerBound, dropInf);
+ return new Constraint_(v, LowerBound, dropInf);
}else{
Assert(r.infinitesimalSgn() == 0);
// make (not (v <= r)), which is (v > r)
DeltaRational addInf(r.getNoninfinitesimalPart(), 1);
- return new ConstraintValue(v, LowerBound, addInf);
+ return new Constraint_(v, LowerBound, addInf);
}
}
case Equality:
- return new ConstraintValue(v, Disequality, r);
+ return new Constraint_(v, Disequality, r);
case Disequality:
- return new ConstraintValue(v, Equality, r);
+ return new Constraint_(v, Equality, r);
default:
Unreachable();
return NullConstraint;
@@ -500,11 +563,42 @@ ConstraintDatabase::ConstraintDatabase(context::Context* satContext, context::Co
d_equalityEngineProof = d_proofs.size();
d_proofs.push_back(NullConstraint);
- // d_pseudoConstraintProof = d_proofs.size();
- // d_proofs.push_back(NullConstraint);
+ d_internalDecisionProof = d_proofs.size();
+ d_proofs.push_back(NullConstraint);
+}
+
+SortedConstraintMap& ConstraintDatabase::getVariableSCM(ArithVar v) const{
+ Assert(variableDatabaseIsSetup(v));
+ return d_varDatabases[v]->d_constraints;
+}
+
+void ConstraintDatabase::pushSplitWatch(ConstraintP c){
+ Assert(!c->d_split);
+ c->d_split = true;
+ d_watches->d_splitWatches.push_back(c);
+}
+
+
+void ConstraintDatabase::pushCanBePropagatedWatch(ConstraintP c){
+ Assert(!c->d_canBePropagated);
+ c->d_canBePropagated = true;
+ d_watches->d_canBePropagatedWatches.push_back(c);
+}
+
+void ConstraintDatabase::pushAssertionOrderWatch(ConstraintP c, TNode witness){
+ Assert(!c->assertedToTheTheory());
+ c->d_assertionOrder = d_watches->d_assertionOrderWatches.size();
+ c->d_witness = witness;
+ d_watches->d_assertionOrderWatches.push_back(c);
}
-Constraint ConstraintDatabase::getConstraint(ArithVar v, ConstraintType t, const DeltaRational& r){
+void ConstraintDatabase::pushProofWatch(ConstraintP c, ProofId pid){
+ Assert(c->d_proof == ProofIdSentinel);
+ c->d_proof = pid;
+ d_watches->d_proofWatches.push_back(c);
+}
+
+ConstraintP ConstraintDatabase::getConstraint(ArithVar v, ConstraintType t, const DeltaRational& r){
//This must always return a constraint.
SortedConstraintMap& scm = getVariableSCM(v);
@@ -516,8 +610,8 @@ Constraint ConstraintDatabase::getConstraint(ArithVar v, ConstraintType t, const
if(vc.hasConstraintOfType(t)){
return vc.getConstraintOfType(t);
}else{
- Constraint c = new ConstraintValue(v, t, r);
- Constraint negC = ConstraintValue::makeNegation(v, t, r);
+ ConstraintP c = new Constraint_(v, t, r);
+ ConstraintP negC = Constraint_::makeNegation(v, t, r);
SortedConstraintMapIterator negPos;
if(t == Equality || t == Disequality){
@@ -539,6 +633,15 @@ Constraint ConstraintDatabase::getConstraint(ArithVar v, ConstraintType t, const
return c;
}
}
+
+ConstraintP ConstraintDatabase::ensureConstraint(ValueCollection& vc, ConstraintType t){
+ if(vc.hasConstraintOfType(t)){
+ return vc.getConstraintOfType(t);
+ }else{
+ return getConstraint(vc.getVariable(), t, vc.getValue());
+ }
+}
+
bool ConstraintDatabase::emptyDatabase(const std::vector<PerVariableDatabase>& vec){
std::vector<PerVariableDatabase>::const_iterator first = vec.begin();
std::vector<PerVariableDatabase>::const_iterator last = vec.end();
@@ -550,7 +653,7 @@ ConstraintDatabase::~ConstraintDatabase(){
delete d_watches;
- std::vector<Constraint> constraintList;
+ std::vector<ConstraintP> constraintList;
while(!d_varDatabases.empty()){
PerVariableDatabase* back = d_varDatabases.back();
@@ -561,7 +664,7 @@ ConstraintDatabase::~ConstraintDatabase(){
(i->second).push_into(constraintList);
}
while(!constraintList.empty()){
- Constraint c = constraintList.back();
+ ConstraintP c = constraintList.back();
constraintList.pop_back();
delete c;
}
@@ -586,17 +689,25 @@ ConstraintDatabase::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(&d_unatePropagateImplications);
}
+void ConstraintDatabase::deleteConstraintAndNegation(ConstraintP c){
+ Assert(c->safeToGarbageCollect());
+ ConstraintP neg = c->getNegation();
+ Assert(neg->safeToGarbageCollect());
+ delete c;
+ delete neg;
+}
+
void ConstraintDatabase::addVariable(ArithVar v){
if(d_reclaimable.isMember(v)){
SortedConstraintMap& scm = getVariableSCM(v);
- std::vector<Constraint> constraintList;
+ std::vector<ConstraintP> constraintList;
for(SortedConstraintMapIterator i = scm.begin(), end = scm.end(); i != end; ++i){
(i->second).push_into(constraintList);
}
while(!constraintList.empty()){
- Constraint c = constraintList.back();
+ ConstraintP c = constraintList.back();
constraintList.pop_back();
Assert(c->safeToGarbageCollect());
delete c;
@@ -605,6 +716,7 @@ void ConstraintDatabase::addVariable(ArithVar v){
d_reclaimable.remove(v);
}else{
+ Debug("arith::constraint") << "about to fail" << v << " " << d_varDatabases.size() << endl;
Assert(v == d_varDatabases.size());
d_varDatabases.push_back(new PerVariableDatabase(v));
}
@@ -615,20 +727,20 @@ void ConstraintDatabase::removeVariable(ArithVar v){
d_reclaimable.add(v);
}
-bool ConstraintValue::safeToGarbageCollect() const{
+bool Constraint_::safeToGarbageCollect() const{
return !isSplit()
&& !canBePropagated()
&& !hasProof()
&& !assertedToTheTheory();
}
-Node ConstraintValue::split(){
+Node Constraint_::split(){
Assert(isEquality() || isDisequality());
bool isEq = isEquality();
- Constraint eq = isEq ? this : d_negation;
- Constraint diseq = isEq ? d_negation : this;
+ ConstraintP eq = isEq ? this : d_negation;
+ ConstraintP diseq = isEq ? d_negation : this;
TNode eqNode = eq->getLiteral();
Assert(eqNode.getKind() == kind::EQUAL);
@@ -651,26 +763,26 @@ bool ConstraintDatabase::hasLiteral(TNode literal) const {
return lookup(literal) != NullConstraint;
}
-// Constraint ConstraintDatabase::addLiteral(TNode literal){
+// ConstraintP ConstraintDatabase::addLiteral(TNode literal){
// Assert(!hasLiteral(literal));
// bool isNot = (literal.getKind() == NOT);
// TNode atom = isNot ? literal[0] : literal;
-// Constraint atomC = addAtom(atom);
+// ConstraintP atomC = addAtom(atom);
// return isNot ? atomC->d_negation : atomC;
// }
-// Constraint ConstraintDatabase::allocateConstraintForComparison(ArithVar v, const Comparison cmp){
+// ConstraintP ConstraintDatabase::allocateConstraintForComparison(ArithVar v, const Comparison cmp){
// Debug("arith::constraint") << "allocateConstraintForLiteral(" << v << ", "<< cmp <<")" << endl;
// Kind kind = cmp.comparisonKind();
// ConstraintType type = constraintTypeOfLiteral(kind);
// DeltaRational dr = cmp.getDeltaRational();
-// return new ConstraintValue(v, type, dr);
+// return new Constraint_(v, type, dr);
// }
-Constraint ConstraintDatabase::addLiteral(TNode literal){
+ConstraintP ConstraintDatabase::addLiteral(TNode literal){
Assert(!hasLiteral(literal));
bool isNot = (literal.getKind() == NOT);
Node atomNode = (isNot ? literal[0] : literal);
@@ -688,7 +800,7 @@ Constraint ConstraintDatabase::addLiteral(TNode literal){
DeltaRational posDR = posCmp.normalizedDeltaRational();
- Constraint posC = new ConstraintValue(v, posType, posDR);
+ ConstraintP posC = new Constraint_(v, posType, posDR);
Debug("arith::constraint") << "addliteral( literal ->" << literal << ")" << endl;
Debug("arith::constraint") << "addliteral( posC ->" << posC << ")" << endl;
@@ -702,9 +814,9 @@ Constraint ConstraintDatabase::addLiteral(TNode literal){
// If the attempt fails, i points to a pre-existing ValueCollection
if(posI->second.hasConstraintOfType(posC->getType())){
- //This is the situation where the Constraint exists, but
+ //This is the situation where the ConstraintP exists, but
//the literal has not been associated with it.
- Constraint hit = posI->second.getConstraintOfType(posC->getType());
+ ConstraintP hit = posI->second.getConstraintOfType(posC->getType());
Debug("arith::constraint") << "hit " << hit << endl;
Debug("arith::constraint") << "posC " << posC << endl;
@@ -719,7 +831,7 @@ Constraint ConstraintDatabase::addLiteral(TNode literal){
ConstraintType negType = constraintTypeOfComparison(negCmp);
DeltaRational negDR = negCmp.normalizedDeltaRational();
- Constraint negC = new ConstraintValue(v, negType, negDR);
+ ConstraintP negC = new Constraint_(v, negType, negDR);
SortedConstraintMapIterator negI;
@@ -771,7 +883,7 @@ Constraint ConstraintDatabase::addLiteral(TNode literal){
// }
// }
-Constraint ConstraintDatabase::lookup(TNode literal) const{
+ConstraintP ConstraintDatabase::lookup(TNode literal) const{
NodetoConstraintMap::const_iterator iter = d_nodetoConstraintMap.find(literal);
if(iter == d_nodetoConstraintMap.end()){
return NullConstraint;
@@ -780,11 +892,19 @@ Constraint ConstraintDatabase::lookup(TNode literal) const{
}
}
-void ConstraintValue::selfExplaining(){
+void Constraint_::selfExplainingWithNegationTrue(){
+ Assert(!hasProof());
+ Assert(getNegation()->hasProof());
+ Assert(hasLiteral());
+ Assert(assertedToTheTheory());
+ d_database->pushProofWatch(this, d_database->d_selfExplainingProof);
+}
+
+void Constraint_::selfExplaining(){
markAsTrue();
}
-void ConstraintValue::propagate(){
+void Constraint_::propagate(){
Assert(hasProof());
Assert(canBePropagated());
Assert(!assertedToTheTheory());
@@ -793,7 +913,7 @@ void ConstraintValue::propagate(){
d_database->d_toPropagate.push(this);
}
-void ConstraintValue::propagate(Constraint a){
+void Constraint_::propagate(ConstraintCP a){
Assert(!hasProof());
Assert(canBePropagated());
@@ -801,7 +921,7 @@ void ConstraintValue::propagate(Constraint a){
propagate();
}
-void ConstraintValue::propagate(Constraint a, Constraint b){
+void Constraint_::propagate(ConstraintCP a, ConstraintCP b){
Assert(!hasProof());
Assert(canBePropagated());
@@ -809,7 +929,7 @@ void ConstraintValue::propagate(Constraint a, Constraint b){
propagate();
}
-void ConstraintValue::propagate(const std::vector<Constraint>& b){
+void Constraint_::propagate(const ConstraintCPVec& b){
Assert(!hasProof());
Assert(canBePropagated());
@@ -817,9 +937,8 @@ void ConstraintValue::propagate(const std::vector<Constraint>& b){
propagate();
}
-void ConstraintValue::impliedBy(Constraint a){
- Assert(!isTrue());
- Assert(!getNegation()->isTrue());
+void Constraint_::impliedBy(ConstraintCP a){
+ Assert(truthIsUnknown());
markAsTrue(a);
if(canBePropagated()){
@@ -827,9 +946,8 @@ void ConstraintValue::impliedBy(Constraint a){
}
}
-void ConstraintValue::impliedBy(Constraint a, Constraint b){
- Assert(!isTrue());
- Assert(!getNegation()->isTrue());
+void Constraint_::impliedBy(ConstraintCP a, ConstraintCP b){
+ Assert(truthIsUnknown());
markAsTrue(a, b);
if(canBePropagated()){
@@ -837,9 +955,8 @@ void ConstraintValue::impliedBy(Constraint a, Constraint b){
}
}
-void ConstraintValue::impliedBy(const std::vector<Constraint>& b){
- Assert(!isTrue());
- Assert(!getNegation()->isTrue());
+void Constraint_::impliedBy(const ConstraintCPVec& b){
+ Assert(truthIsUnknown());
markAsTrue(b);
if(canBePropagated()){
@@ -847,30 +964,29 @@ void ConstraintValue::impliedBy(const std::vector<Constraint>& b){
}
}
-// void ConstraintValue::setPseudoConstraint(){
-// Assert(truthIsUnknown());
-// Assert(!hasLiteral());
+void Constraint_::setInternalDecision(){
+ Assert(truthIsUnknown());
+ Assert(!assertedToTheTheory());
-// d_database->pushProofWatch(this, d_database->d_pseudoConstraintProof);
-// }
+ d_database->pushProofWatch(this, d_database->d_internalDecisionProof);
+}
-void ConstraintValue::setEqualityEngineProof(){
+void Constraint_::setEqualityEngineProof(){
Assert(truthIsUnknown());
Assert(hasLiteral());
d_database->pushProofWatch(this, d_database->d_equalityEngineProof);
}
-void ConstraintValue::markAsTrue(){
+void Constraint_::markAsTrue(){
Assert(truthIsUnknown());
Assert(hasLiteral());
Assert(assertedToTheTheory());
d_database->pushProofWatch(this, d_database->d_selfExplainingProof);
}
-void ConstraintValue::markAsTrue(Constraint imp){
+void Constraint_::markAsTrue(ConstraintCP imp){
Assert(truthIsUnknown());
Assert(imp->hasProof());
- //Assert(!imp->isPseudoConstraint());
d_database->d_proofs.push_back(NullConstraint);
d_database->d_proofs.push_back(imp);
@@ -878,12 +994,10 @@ void ConstraintValue::markAsTrue(Constraint imp){
d_database->pushProofWatch(this, proof);
}
-void ConstraintValue::markAsTrue(Constraint impA, Constraint impB){
+void Constraint_::markAsTrue(ConstraintCP impA, ConstraintCP impB){
Assert(truthIsUnknown());
Assert(impA->hasProof());
Assert(impB->hasProof());
- //Assert(!impA->isPseudoConstraint());
- //Assert(!impB->isPseudoConstraint());
d_database->d_proofs.push_back(NullConstraint);
d_database->d_proofs.push_back(impA);
@@ -893,12 +1007,12 @@ void ConstraintValue::markAsTrue(Constraint impA, Constraint impB){
d_database->pushProofWatch(this, proof);
}
-void ConstraintValue::markAsTrue(const vector<Constraint>& a){
+void Constraint_::markAsTrue(const ConstraintCPVec& a){
Assert(truthIsUnknown());
Assert(a.size() >= 1);
d_database->d_proofs.push_back(NullConstraint);
- for(vector<Constraint>::const_iterator i = a.begin(), end = a.end(); i != end; ++i){
- Constraint c_i = *i;
+ for(ConstraintCPVec::const_iterator i = a.begin(), end = a.end(); i != end; ++i){
+ ConstraintCP c_i = *i;
Assert(c_i->hasProof());
//Assert(!c_i->isPseudoConstraint());
d_database->d_proofs.push_back(c_i);
@@ -909,12 +1023,12 @@ void ConstraintValue::markAsTrue(const vector<Constraint>& a){
d_database->pushProofWatch(this, proof);
}
-SortedConstraintMap& ConstraintValue::constraintSet() const{
+SortedConstraintMap& Constraint_::constraintSet() const{
Assert(d_database->variableDatabaseIsSetup(d_variable));
return (d_database->d_varDatabases[d_variable])->d_constraints;
}
-bool ConstraintValue::proofIsEmpty() const{
+bool Constraint_::proofIsEmpty() const{
Assert(hasProof());
bool result = d_database->d_proofs[d_proof] == NullConstraint;
//Assert((!result) || isSelfExplaining() || hasEqualityEngineProof() || isPseudoConstraint());
@@ -922,32 +1036,76 @@ bool ConstraintValue::proofIsEmpty() const{
return result;
}
-Node ConstraintValue::makeImplication(const std::vector<Constraint>& b) const{
- Node antecedent = makeConjunction(b);
+Node Constraint_::externalImplication(const ConstraintCPVec& b) const{
+ Assert(hasLiteral());
+ Node antecedent = externalExplainByAssertions(b);
Node implied = getLiteral();
return antecedent.impNode(implied);
}
-Node ConstraintValue::makeConjunction(const std::vector<Constraint>& b){
- NodeBuilder<> nb(kind::AND);
- for(vector<Constraint>::const_iterator i = b.begin(), end = b.end(); i != end; ++i){
- Constraint b_i = *i;
- b_i->explainBefore(nb, AssertionOrderSentinel);
+Node Constraint_::externalExplainByAssertions(const ConstraintCPVec& b){
+ return externalExplain(b, AssertionOrderSentinel);
+}
+
+struct ConstraintCPHash {
+ /* Todo replace with an id */
+ size_t operator()(ConstraintCP c) const{
+ Assert(sizeof(ConstraintCP) > 0);
+ return ((size_t)c)/sizeof(ConstraintCP);
}
- if(nb.getNumChildren() >= 2){
- return nb;
- }else if(nb.getNumChildren() == 1){
- return nb[0];
- }else{
- return mkBoolNode(true);
+};
+
+void Constraint_::assertionFringe(ConstraintCPVec& v){
+ hash_set<ConstraintCP, ConstraintCPHash> visited;
+ size_t writePos = 0;
+
+ if(!v.empty()){
+ const ConstraintDatabase* db = v.back()->d_database;
+ const CDConstraintList& proofs = db->d_proofs;
+ for(size_t i = 0; i < v.size(); ++i){
+ ConstraintCP vi = v[i];
+ if(visited.find(vi) == visited.end()){
+ Assert(vi->hasProof());
+ visited.insert(vi);
+ if(vi->onFringe()){
+ v[writePos] = vi;
+ writePos++;
+ }else{
+ Assert(!vi->isSelfExplaining());
+ ProofId p = vi->d_proof;
+ ConstraintCP antecedent = proofs[p];
+ while(antecedent != NullConstraint){
+ v.push_back(antecedent);
+ --p;
+ antecedent = proofs[p];
+ }
+ }
+ }
+ }
+ v.resize(writePos);
+ }
+}
+
+void Constraint_::assertionFringe(ConstraintCPVec& o, const ConstraintCPVec& i){
+ o.insert(o.end(), i.begin(), i.end());
+ assertionFringe(o);
+}
+
+Node Constraint_::externalExplain(const ConstraintCPVec& v, AssertionOrder order){
+ NodeBuilder<> nb(kind::AND);
+ ConstraintCPVec::const_iterator i, end;
+ for(i = v.begin(), end = v.end(); i != end; ++i){
+ ConstraintCP v_i = *i;
+ v_i->externalExplain(nb, order);
}
+ return safeConstructNary(nb);
}
-void ConstraintValue::explainBefore(NodeBuilder<>& nb, AssertionOrder order) const{
+void Constraint_::externalExplain(NodeBuilder<>& nb, AssertionOrder order) const{
Assert(hasProof());
Assert(!isSelfExplaining() || assertedToTheTheory());
-
+ Assert(!isInternalDecision());
if(assertedBefore(order)){
nb << getWitness();
@@ -956,56 +1114,61 @@ void ConstraintValue::explainBefore(NodeBuilder<>& nb, AssertionOrder order) con
}else{
Assert(!isSelfExplaining());
ProofId p = d_proof;
- Constraint antecedent = d_database->d_proofs[p];
+ ConstraintCP antecedent = d_database->d_proofs[p];
for(; antecedent != NullConstraint; antecedent = d_database->d_proofs[--p] ){
- antecedent->explainBefore(nb, order);
+ antecedent->externalExplain(nb, order);
}
}
}
-Node ConstraintValue::explainBefore(AssertionOrder order) const{
+
+Node Constraint_::externalExplain(AssertionOrder order) const{
Assert(hasProof());
Assert(!isSelfExplaining() || assertedBefore(order));
+ Assert(!isInternalDecision());
if(assertedBefore(order)){
return getWitness();
}else if(hasEqualityEngineProof()){
return d_database->eeExplain(this);
}else{
Assert(!proofIsEmpty());
- //Force the selection of the layer above if the node is assertedToTheTheory()!
+ //Force the selection of the layer above if the node is
+ // assertedToTheTheory()!
if(d_database->d_proofs[d_proof-1] == NullConstraint){
- Constraint antecedent = d_database->d_proofs[d_proof];
- return antecedent->explainBefore(order);
+ ConstraintCP antecedent = d_database->d_proofs[d_proof];
+ return antecedent->externalExplain(order);
}else{
NodeBuilder<> nb(kind::AND);
Assert(!isSelfExplaining());
ProofId p = d_proof;
- Constraint antecedent = d_database->d_proofs[p];
- for(; antecedent != NullConstraint; antecedent = d_database->d_proofs[--p] ){
- antecedent->explainBefore(nb, order);
+ ConstraintCP antecedent = d_database->d_proofs[p];
+ while(antecedent != NullConstraint){
+ antecedent->externalExplain(nb, order);
+ --p;
+ antecedent = d_database->d_proofs[p];
}
return nb;
}
}
}
-Node ConstraintValue::explainConflict(Constraint a, Constraint b){
+Node Constraint_::externalExplainByAssertions(ConstraintCP a, ConstraintCP b){
NodeBuilder<> nb(kind::AND);
- a->explainForConflict(nb);
- b->explainForConflict(nb);
+ a->externalExplainByAssertions(nb);
+ b->externalExplainByAssertions(nb);
return nb;
}
-Node ConstraintValue::explainConflict(Constraint a, Constraint b, Constraint c){
+Node Constraint_::externalExplainByAssertions(ConstraintCP a, ConstraintCP b, ConstraintCP c){
NodeBuilder<> nb(kind::AND);
- a->explainForConflict(nb);
- b->explainForConflict(nb);
- c->explainForConflict(nb);
+ a->externalExplainByAssertions(nb);
+ b->externalExplainByAssertions(nb);
+ c->externalExplainByAssertions(nb);
return nb;
}
-Constraint ConstraintValue::getStrictlyWeakerLowerBound(bool hasLiteral, bool asserted) const {
+ConstraintP Constraint_::getStrictlyWeakerLowerBound(bool hasLiteral, bool asserted) const {
Assert(initialized());
Assert(!asserted || hasLiteral);
@@ -1016,7 +1179,7 @@ Constraint ConstraintValue::getStrictlyWeakerLowerBound(bool hasLiteral, bool as
--i;
const ValueCollection& vc = i->second;
if(vc.hasLowerBound()){
- Constraint weaker = vc.getLowerBound();
+ ConstraintP weaker = vc.getLowerBound();
// asserted -> hasLiteral
// hasLiteral -> weaker->hasLiteral()
@@ -1030,7 +1193,7 @@ Constraint ConstraintValue::getStrictlyWeakerLowerBound(bool hasLiteral, bool as
return NullConstraint;
}
-Constraint ConstraintValue::getStrictlyWeakerUpperBound(bool hasLiteral, bool asserted) const {
+ConstraintP Constraint_::getStrictlyWeakerUpperBound(bool hasLiteral, bool asserted) const {
SortedConstraintMapConstIterator i = d_variablePosition;
const SortedConstraintMap& scm = constraintSet();
SortedConstraintMapConstIterator i_end = scm.end();
@@ -1039,7 +1202,7 @@ Constraint ConstraintValue::getStrictlyWeakerUpperBound(bool hasLiteral, bool as
for(; i != i_end; ++i){
const ValueCollection& vc = i->second;
if(vc.hasUpperBound()){
- Constraint weaker = vc.getUpperBound();
+ ConstraintP weaker = vc.getUpperBound();
if((!hasLiteral || (weaker->hasLiteral())) &&
(!asserted || ( weaker->assertedToTheTheory()))){
return weaker;
@@ -1050,7 +1213,7 @@ Constraint ConstraintValue::getStrictlyWeakerUpperBound(bool hasLiteral, bool as
return NullConstraint;
}
-Constraint ConstraintDatabase::getBestImpliedBound(ArithVar v, ConstraintType t, const DeltaRational& r) const {
+ConstraintP ConstraintDatabase::getBestImpliedBound(ArithVar v, ConstraintType t, const DeltaRational& r) const {
Assert(variableDatabaseIsSetup(v));
Assert(t == UpperBound || t == LowerBound);
@@ -1110,12 +1273,12 @@ Constraint ConstraintDatabase::getBestImpliedBound(ArithVar v, ConstraintType t,
}
}
}
-Node ConstraintDatabase::eeExplain(const ConstraintValue* const c) const{
+Node ConstraintDatabase::eeExplain(const Constraint_* const c) const{
Assert(c->hasLiteral());
return d_congruenceManager.explain(c->getLiteral());
}
-void ConstraintDatabase::eeExplain(const ConstraintValue* const c, NodeBuilder<>& nb) const{
+void ConstraintDatabase::eeExplain(const Constraint_* const c, NodeBuilder<>& nb) const{
Assert(c->hasLiteral());
d_congruenceManager.explain(c->getLiteral(), nb);
}
@@ -1133,7 +1296,7 @@ ConstraintDatabase::Watches::Watches(context::Context* satContext, context::Cont
{}
-void ConstraintValue::setLiteral(Node n) {
+void Constraint_::setLiteral(Node n) {
Assert(!hasLiteral());
Assert(sanityChecking(n));
d_literal = n;
@@ -1142,7 +1305,7 @@ void ConstraintValue::setLiteral(Node n) {
map.insert(make_pair(d_literal, this));
}
-void implies(std::vector<Node>& out, Constraint a, Constraint b){
+void implies(std::vector<Node>& out, ConstraintP a, ConstraintP b){
Node la = a->getLiteral();
Node lb = b->getLiteral();
@@ -1153,7 +1316,7 @@ void implies(std::vector<Node>& out, Constraint a, Constraint b){
out.push_back(orderOr);
}
-void mutuallyExclusive(std::vector<Node>& out, Constraint a, Constraint b){
+void mutuallyExclusive(std::vector<Node>& out, ConstraintP a, ConstraintP b){
Node la = a->getLiteral();
Node lb = b->getLiteral();
@@ -1169,13 +1332,13 @@ void ConstraintDatabase::outputUnateInequalityLemmas(std::vector<Node>& out, Ari
SortedConstraintMap& scm = getVariableSCM(v);
SortedConstraintMapConstIterator scm_iter = scm.begin();
SortedConstraintMapConstIterator scm_end = scm.end();
- Constraint prev = NullConstraint;
+ ConstraintP prev = NullConstraint;
//get transitive unates
//Only lower bounds or upperbounds should be done.
for(; scm_iter != scm_end; ++scm_iter){
const ValueCollection& vc = scm_iter->second;
if(vc.hasUpperBound()){
- Constraint ub = vc.getUpperBound();
+ ConstraintP ub = vc.getUpperBound();
if(ub->hasLiteral()){
if(prev != NullConstraint){
implies(out, prev, ub);
@@ -1188,7 +1351,7 @@ void ConstraintDatabase::outputUnateInequalityLemmas(std::vector<Node>& out, Ari
void ConstraintDatabase::outputUnateEqualityLemmas(std::vector<Node>& out, ArithVar v) const{
- vector<Constraint> equalities;
+ vector<ConstraintP> equalities;
SortedConstraintMap& scm = getVariableSCM(v);
SortedConstraintMapConstIterator scm_iter = scm.begin();
@@ -1197,34 +1360,34 @@ void ConstraintDatabase::outputUnateEqualityLemmas(std::vector<Node>& out, Arith
for(; scm_iter != scm_end; ++scm_iter){
const ValueCollection& vc = scm_iter->second;
if(vc.hasEquality()){
- Constraint eq = vc.getEquality();
+ ConstraintP eq = vc.getEquality();
if(eq->hasLiteral()){
equalities.push_back(eq);
}
}
}
- vector<Constraint>::const_iterator i, j, eq_end = equalities.end();
+ vector<ConstraintP>::const_iterator i, j, eq_end = equalities.end();
for(i = equalities.begin(); i != eq_end; ++i){
- Constraint at_i = *i;
+ ConstraintP at_i = *i;
for(j= i + 1; j != eq_end; ++j){
- Constraint at_j = *j;
+ ConstraintP at_j = *j;
mutuallyExclusive(out, at_i, at_j);
}
}
for(i = equalities.begin(); i != eq_end; ++i){
- Constraint eq = *i;
+ ConstraintP eq = *i;
const ValueCollection& vc = eq->getValueCollection();
Assert(vc.hasEquality() && vc.getEquality()->hasLiteral());
bool hasLB = vc.hasLowerBound() && vc.getLowerBound()->hasLiteral();
bool hasUB = vc.hasUpperBound() && vc.getUpperBound()->hasLiteral();
- Constraint lb = hasLB ?
+ ConstraintP lb = hasLB ?
vc.getLowerBound() : eq->getStrictlyWeakerLowerBound(true, false);
- Constraint ub = hasUB ?
+ ConstraintP ub = hasUB ?
vc.getUpperBound() : eq->getStrictlyWeakerUpperBound(true, false);
if(hasUB && hasLB && !eq->isSplit()){
@@ -1251,21 +1414,20 @@ void ConstraintDatabase::outputUnateInequalityLemmas(std::vector<Node>& lemmas)
}
}
-void ConstraintDatabase::raiseUnateConflict(Constraint ant, Constraint cons){
+void ConstraintDatabase::raiseUnateConflict(ConstraintP ant, ConstraintP cons){
Assert(ant->hasProof());
- Constraint negCons = cons->getNegation();
+ ConstraintP negCons = cons->getNegation();
Assert(negCons->hasProof());
Debug("arith::unate::conf") << ant << "implies " << cons << endl;
Debug("arith::unate::conf") << negCons << " is true." << endl;
-
- Node conf = ConstraintValue::explainConflict(ant, negCons);
- Debug("arith::unate::conf") << conf << std::endl;
- d_raiseConflict(conf);
+ d_raiseConflict.addConstraint(ant);
+ d_raiseConflict.addConstraint(negCons);
+ d_raiseConflict.commitConflict();
}
-void ConstraintDatabase::unatePropLowerBound(Constraint curr, Constraint prev){
+void ConstraintDatabase::unatePropLowerBound(ConstraintP curr, ConstraintP prev){
Debug("arith::unate") << "unatePropLowerBound " << curr << " " << prev << endl;
Assert(curr != prev);
Assert(curr != NullConstraint);
@@ -1297,7 +1459,7 @@ void ConstraintDatabase::unatePropLowerBound(Constraint curr, Constraint prev){
//Don't worry about implying the negation of upperbound.
//These should all be handled by propagating the LowerBounds!
if(vc.hasLowerBound()){
- Constraint lb = vc.getLowerBound();
+ ConstraintP lb = vc.getLowerBound();
if(lb->negationHasProof()){
raiseUnateConflict(curr, lb);
return;
@@ -1309,7 +1471,7 @@ void ConstraintDatabase::unatePropLowerBound(Constraint curr, Constraint prev){
}
}
if(vc.hasDisequality()){
- Constraint dis = vc.getDisequality();
+ ConstraintP dis = vc.getDisequality();
if(dis->negationHasProof()){
raiseUnateConflict(curr, dis);
return;
@@ -1323,7 +1485,7 @@ void ConstraintDatabase::unatePropLowerBound(Constraint curr, Constraint prev){
}
}
-void ConstraintDatabase::unatePropUpperBound(Constraint curr, Constraint prev){
+void ConstraintDatabase::unatePropUpperBound(ConstraintP curr, ConstraintP prev){
Debug("arith::unate") << "unatePropUpperBound " << curr << " " << prev << endl;
Assert(curr != prev);
Assert(curr != NullConstraint);
@@ -1348,7 +1510,7 @@ void ConstraintDatabase::unatePropUpperBound(Constraint curr, Constraint prev){
//Don't worry about implying the negation of upperbound.
//These should all be handled by propagating the UpperBounds!
if(vc.hasUpperBound()){
- Constraint ub = vc.getUpperBound();
+ ConstraintP ub = vc.getUpperBound();
if(ub->negationHasProof()){
raiseUnateConflict(curr, ub);
return;
@@ -1359,7 +1521,7 @@ void ConstraintDatabase::unatePropUpperBound(Constraint curr, Constraint prev){
}
}
if(vc.hasDisequality()){
- Constraint dis = vc.getDisequality();
+ ConstraintP dis = vc.getDisequality();
if(dis->negationHasProof()){
raiseUnateConflict(curr, dis);
return;
@@ -1373,7 +1535,7 @@ void ConstraintDatabase::unatePropUpperBound(Constraint curr, Constraint prev){
}
}
-void ConstraintDatabase::unatePropEquality(Constraint curr, Constraint prevLB, Constraint prevUB){
+void ConstraintDatabase::unatePropEquality(ConstraintP curr, ConstraintP prevLB, ConstraintP prevUB){
Debug("arith::unate") << "unatePropEquality " << curr << " " << prevLB << " " << prevUB << endl;
Assert(curr != prevLB);
Assert(curr != prevUB);
@@ -1405,7 +1567,7 @@ void ConstraintDatabase::unatePropEquality(Constraint curr, Constraint prevLB, C
//Don't worry about implying the negation of upperbound.
//These should all be handled by propagating the LowerBounds!
if(vc.hasLowerBound()){
- Constraint lb = vc.getLowerBound();
+ ConstraintP lb = vc.getLowerBound();
if(lb->negationHasProof()){
raiseUnateConflict(curr, lb);
return;
@@ -1416,7 +1578,7 @@ void ConstraintDatabase::unatePropEquality(Constraint curr, Constraint prevLB, C
}
}
if(vc.hasDisequality()){
- Constraint dis = vc.getDisequality();
+ ConstraintP dis = vc.getDisequality();
if(dis->negationHasProof()){
raiseUnateConflict(curr, dis);
return;
@@ -1440,7 +1602,7 @@ void ConstraintDatabase::unatePropEquality(Constraint curr, Constraint prevLB, C
//Don't worry about implying the negation of upperbound.
//These should all be handled by propagating the UpperBounds!
if(vc.hasUpperBound()){
- Constraint ub = vc.getUpperBound();
+ ConstraintP ub = vc.getUpperBound();
if(ub->negationHasProof()){
raiseUnateConflict(curr, ub);
return;
@@ -1452,7 +1614,7 @@ void ConstraintDatabase::unatePropEquality(Constraint curr, Constraint prevLB, C
}
}
if(vc.hasDisequality()){
- Constraint dis = vc.getDisequality();
+ ConstraintP dis = vc.getDisequality();
if(dis->negationHasProof()){
raiseUnateConflict(curr, dis);
return;
diff --git a/src/theory/arith/constraint.h b/src/theory/arith/constraint.h
index 4966115d2..18e53660f 100644
--- a/src/theory/arith/constraint.h
+++ b/src/theory/arith/constraint.h
@@ -94,9 +94,9 @@ namespace arith {
enum ConstraintType {LowerBound, Equality, UpperBound, Disequality};
-typedef context::CDList<Constraint> CDConstraintList;
+typedef context::CDList<ConstraintCP> CDConstraintList;
-typedef __gnu_cxx::hash_map<Node, Constraint, NodeHashFunction> NodetoConstraintMap;
+typedef __gnu_cxx::hash_map<Node, ConstraintP, NodeHashFunction> NodetoConstraintMap;
typedef size_t ProofId;
static ProofId ProofIdSentinel = std::numeric_limits<ProofId>::max();
@@ -111,54 +111,29 @@ static AssertionOrder AssertionOrderSentinel = std::numeric_limits<AssertionOrde
class ValueCollection {
private:
- Constraint d_lowerBound;
- Constraint d_upperBound;
- Constraint d_equality;
- Constraint d_disequality;
+ ConstraintP d_lowerBound;
+ ConstraintP d_upperBound;
+ ConstraintP d_equality;
+ ConstraintP d_disequality;
public:
- ValueCollection()
- : d_lowerBound(NullConstraint),
- d_upperBound(NullConstraint),
- d_equality(NullConstraint),
- d_disequality(NullConstraint)
- {}
+ ValueCollection();
- static ValueCollection mkFromConstraint(Constraint c);
+ static ValueCollection mkFromConstraint(ConstraintP c);
- bool hasLowerBound() const{
- return d_lowerBound != NullConstraint;
- }
- bool hasUpperBound() const{
- return d_upperBound != NullConstraint;
- }
- bool hasEquality() const{
- return d_equality != NullConstraint;
- }
- bool hasDisequality() const {
- return d_disequality != NullConstraint;
- }
+ bool hasLowerBound() const;
+ bool hasUpperBound() const;
+ bool hasEquality() const;
+ bool hasDisequality() const;
bool hasConstraintOfType(ConstraintType t) const;
- Constraint getLowerBound() const {
- Assert(hasLowerBound());
- return d_lowerBound;
- }
- Constraint getUpperBound() const {
- Assert(hasUpperBound());
- return d_upperBound;
- }
- Constraint getEquality() const {
- Assert(hasEquality());
- return d_equality;
- }
- Constraint getDisequality() const {
- Assert(hasDisequality());
- return d_disequality;
- }
+ ConstraintP getLowerBound() const;
+ ConstraintP getUpperBound() const;
+ ConstraintP getEquality() const;
+ ConstraintP getDisequality() const;
- Constraint getConstraintOfType(ConstraintType t) const;
+ ConstraintP getConstraintOfType(ConstraintType t) const;
/** Returns true if any of the constraints are non-null. */
bool empty() const;
@@ -174,11 +149,11 @@ public:
* Adds a constraint to the set.
* The collection must not have a constraint of that type already.
*/
- void add(Constraint c);
+ void add(ConstraintP c);
- void push_into(std::vector<Constraint>& vec) const;
+ void push_into(std::vector<ConstraintP>& vec) const;
- Constraint nonNull() const;
+ ConstraintP nonNull() const;
ArithVar getVariable() const;
const DeltaRational& getValue() const;
@@ -220,7 +195,7 @@ struct PerVariableDatabase{
}
};
-class ConstraintValue {
+class Constraint_ {
private:
/** The ArithVar associated with the constraint. */
const ArithVar d_variable;
@@ -246,7 +221,7 @@ private:
Node d_literal;
/** Pointer to the negation of the Constraint. */
- Constraint d_negation;
+ ConstraintP d_negation;
/**
* This is true if the associated node can be propagated.
@@ -269,10 +244,11 @@ private:
* Sat Context Dependent.
* This is initially AssertionOrderSentinel.
*/
- AssertionOrder _d_assertionOrder;
+ AssertionOrder d_assertionOrder;
+
/**
* This is guaranteed to be on the fact queue.
- * For example if x + y = x + 1 is on the fact queue, then use this
+ * For example if x + y = x + 1 is on the fact queue, then use this
*/
TNode d_witness;
@@ -309,13 +285,13 @@ private:
* Because of circular dependencies a Constraint is not fully valid until
* initialize has been called on it.
*/
- ConstraintValue(ArithVar x, ConstraintType t, const DeltaRational& v);
+ Constraint_(ArithVar x, ConstraintType t, const DeltaRational& v);
/**
* Destructor for a constraint.
* This should only be called if safeToGarbageCollect() is true.
*/
- ~ConstraintValue();
+ ~Constraint_();
bool initialized() const;
@@ -323,12 +299,12 @@ private:
* This initializes the fields that cannot be set in the constructor due to
* circular dependencies.
*/
- void initialize(ConstraintDatabase* db, SortedConstraintMapIterator v, Constraint negation);
+ void initialize(ConstraintDatabase* db, SortedConstraintMapIterator v, ConstraintP negation);
class ProofCleanup {
public:
- inline void operator()(Constraint* p){
- Constraint constraint = *p;
+ inline void operator()(ConstraintP* p){
+ ConstraintP constraint = *p;
Assert(constraint->d_proof != ProofIdSentinel);
constraint->d_proof = ProofIdSentinel;
}
@@ -336,8 +312,8 @@ private:
class CanBePropagatedCleanup {
public:
- inline void operator()(Constraint* p){
- Constraint constraint = *p;
+ inline void operator()(ConstraintP* p){
+ ConstraintP constraint = *p;
Assert(constraint->d_canBePropagated);
constraint->d_canBePropagated = false;
}
@@ -345,10 +321,10 @@ private:
class AssertionOrderCleanup {
public:
- inline void operator()(Constraint* p){
- Constraint constraint = *p;
+ inline void operator()(ConstraintP* p){
+ ConstraintP constraint = *p;
Assert(constraint->assertedToTheTheory());
- constraint->_d_assertionOrder = AssertionOrderSentinel;
+ constraint->d_assertionOrder = AssertionOrderSentinel;
constraint->d_witness = TNode::null();
Assert(!constraint->assertedToTheTheory());
}
@@ -356,8 +332,8 @@ private:
class SplitCleanup {
public:
- inline void operator()(Constraint* p){
- Constraint constraint = *p;
+ inline void operator()(ConstraintP* p){
+ ConstraintP constraint = *p;
Assert(constraint->d_split);
constraint->d_split = false;
}
@@ -389,7 +365,7 @@ public:
return d_value;
}
- Constraint getNegation() const {
+ ConstraintP getNegation() const {
return d_negation;
}
@@ -421,7 +397,7 @@ public:
/**
* Splits the node in the user context.
- * Returns a lemma that is assumed to be true fro the rest of the user context.
+ * 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();
@@ -441,8 +417,8 @@ public:
}
bool assertedToTheTheory() const {
- Assert((_d_assertionOrder < AssertionOrderSentinel) != d_witness.isNull());
- return _d_assertionOrder < AssertionOrderSentinel;
+ Assert((d_assertionOrder < AssertionOrderSentinel) != d_witness.isNull());
+ return d_assertionOrder < AssertionOrderSentinel;
}
TNode getWitness() const {
Assert(assertedToTheTheory());
@@ -450,12 +426,17 @@ public:
}
bool assertedBefore(AssertionOrder time) const {
- return _d_assertionOrder < time;
+ return d_assertionOrder < time;
}
-
+ /** Sets the witness literal for a node being on the assertion stack.
+ * The negation of the node cannot be true. */
void setAssertedToTheTheory(TNode witness);
+ /** Sets the witness literal for a node being on the assertion stack.
+ * The negation of the node must be true!
+ * This is for conflict generation specificially! */
+ void setAssertedToTheTheoryWithNegationTrue(TNode witness);
bool hasLiteral() const {
return !d_literal.isNull();
@@ -474,6 +455,8 @@ public:
*/
void selfExplaining();
+ void selfExplainingWithNegationTrue();
+
/** Returns true if the node is selfExplaining.*/
bool isSelfExplaining() const;
@@ -485,12 +468,17 @@ public:
/**
- * There cannot be a literal associated with this constraint.
- * The explanation is the constant true.
- * explainInto() does nothing.
+ * A sets the constraint to be an internal decision.
+ *
+ * This does not need to have a witness or an associated literal.
+ * This is always itself in the explanation fringe for both conflicts
+ * and propagation.
+ * This cannot be converted back into a Node conflict or explanation.
+ *
+ * This cannot have a proof or be asserted to the theory!
*/
- //void setPseudoConstraint();
- //bool isPseudoConstraint() const;
+ void setInternalDecision();
+ bool isInternalDecision() const;
/**
* Returns a explanation of the constraint that is appropriate for conflicts.
@@ -500,8 +488,8 @@ public:
* This is the minimum fringe of the implication tree s.t.
* every constraint is assertedToTheTheory() or hasEqualityEngineProof().
*/
- Node explainForConflict() const{
- return explainBefore(AssertionOrderSentinel);
+ Node externalExplainByAssertions() const {
+ return externalExplain(AssertionOrderSentinel);
}
/**
@@ -515,13 +503,38 @@ public:
* This is not appropriate for propagation!
* Use explainForPropagation() instead.
*/
- void explainForConflict(NodeBuilder<>& nb) const{
- explainBefore(nb, AssertionOrderSentinel);
+ void externalExplainByAssertions(NodeBuilder<>& nb) const{
+ externalExplain(nb, AssertionOrderSentinel);
}
+ /* Equivalent to calling externalExplainByAssertions on all constraints in b */
+ static Node externalExplainByAssertions(const ConstraintCPVec& b);
+ /* utilities for calling externalExplainByAssertions on 2 constraints */
+ static Node externalExplainByAssertions(ConstraintCP a, ConstraintCP b);
+ static Node externalExplainByAssertions(ConstraintCP a, ConstraintCP b, ConstraintCP c);
+ //static Node externalExplainByAssertions(ConstraintCP a);
+
+ /**
+ * This is the minimum fringe of the implication tree s.t. every constraint is
+ * - assertedToTheTheory(),
+ * - isInternalDecision() or
+ * - hasEqualityEngineProof().
+ */
+ static void assertionFringe(ConstraintCPVec& v);
+ static void assertionFringe(ConstraintCPVec& out, const ConstraintCPVec& in);
+
/** Utility function built from explainForConflict. */
- static Node explainConflict(Constraint a, Constraint b);
- static Node explainConflict(Constraint a, Constraint b, Constraint c);
+ //static Node explainConflict(ConstraintP a, ConstraintP b);
+ //static Node explainConflict(ConstraintP a, ConstraintP b, Constraint c);
+
+ //static Node explainConflictForEE(ConstraintCP a, ConstraintCP b);
+ //static Node explainConflictForEE(ConstraintCP a);
+ //static Node explainConflictForDio(ConstraintCP a);
+ //static Node explainConflictForDio(ConstraintCP a, ConstraintCP b);
+
+ bool onFringe() const {
+ return assertedToTheTheory() || isInternalDecision() || hasEqualityEngineProof();
+ }
/**
* Returns an explanation of a propagation by the ConstraintDatabase.
@@ -531,14 +544,20 @@ public:
* This is the minimum fringe of the implication tree (excluding the constraint itself)
* s.t. every constraint is assertedToTheTheory() or hasEqualityEngineProof().
*/
- Node explainForPropagation() const {
+ Node externalExplainForPropagation() const {
Assert(hasProof());
Assert(!isSelfExplaining());
- return explainBefore(_d_assertionOrder);
+ return externalExplain(d_assertionOrder);
}
+ // void externalExplainForPropagation(NodeBuilder<>& nb) const{
+ // Assert(hasProof());
+ // Assert(!isSelfExplaining());
+ // externalExplain(nb, d_assertionOrder);
+ // }
+
private:
- Node explainBefore(AssertionOrder order) const;
+ Node externalExplain(AssertionOrder order) const;
/**
* Returns an explanation of that was assertedBefore(order).
@@ -548,7 +567,9 @@ private:
* This is the minimum fringe of the implication tree
* s.t. every constraint is assertedBefore(order) or hasEqualityEngineProof().
*/
- void explainBefore(NodeBuilder<>& nb, AssertionOrder order) const;
+ void externalExplain(NodeBuilder<>& nb, AssertionOrder order) const;
+
+ static Node externalExplain(const ConstraintCPVec& b, AssertionOrder order);
public:
bool hasProof() const {
@@ -558,26 +579,38 @@ public:
return d_negation->hasProof();
}
+ /* Neither the contraint has a proof nor the negation has a proof.*/
bool truthIsUnknown() const {
return !hasProof() && !negationHasProof();
}
+ /* This is a synonym for hasProof(). */
bool isTrue() const {
return hasProof();
}
- Constraint getCeiling();
+ /**
+ * Returns the constraint that corresponds to taking
+ * x r ceiling(getValue()) where r is the node's getType().
+ * Esstentially this is an up branch.
+ */
+ ConstraintP getCeiling();
- Constraint getFloor();
+ /**
+ * Returns the constraint that corresponds to taking
+ * x r floor(getValue()) where r is the node's getType().
+ * Esstentially this is a down branch.
+ */
+ ConstraintP getFloor();
- static Constraint makeNegation(ArithVar v, ConstraintType t, const DeltaRational& r);
+ static ConstraintP makeNegation(ArithVar v, ConstraintType t, const DeltaRational& r);
const ValueCollection& getValueCollection() const;
- Constraint getStrictlyWeakerUpperBound(bool hasLiteral, bool mustBeAsserted) const;
- Constraint getStrictlyWeakerLowerBound(bool hasLiteral, bool mustBeAsserted) const;
+ ConstraintP getStrictlyWeakerUpperBound(bool hasLiteral, bool mustBeAsserted) const;
+ ConstraintP getStrictlyWeakerLowerBound(bool hasLiteral, bool mustBeAsserted) const;
/**
* Marks the node as having a proof a.
@@ -587,19 +620,23 @@ public:
* canBePropagated()
* !assertedToTheTheory()
*/
- void propagate(Constraint a);
- void propagate(Constraint a, Constraint b);
- void propagate(const std::vector<Constraint>& b);
+ void propagate(ConstraintCP a);
+ void propagate(ConstraintCP a, ConstraintCP b);
+ //void propagate(const std::vector<Constraint>& b);
+ void propagate(const ConstraintCPVec& b);
+
/**
* The only restriction is that this is not known be true.
* This propagates if there is a node.
*/
- void impliedBy(Constraint a);
- void impliedBy(Constraint a, Constraint b);
- void impliedBy(const std::vector<Constraint>& b);
+ void impliedBy(ConstraintCP a);
+ void impliedBy(ConstraintCP a, ConstraintCP b);
+ //void impliedBy(const std::vector<Constraint>& b);
+ void impliedBy(const ConstraintCPVec& b);
- Node makeImplication(const std::vector<Constraint>& b) const;
- static Node makeConjunction(const std::vector<Constraint>& b);
+ Node externalImplication(const ConstraintCPVec& b) const;
+ static Node externalConjunction(const ConstraintCPVec& b);
+ //static Node makeConflictNode(const ConstraintCPVec& b);
/** The node must have a proof already and be eligible for propagation! */
void propagate();
@@ -617,10 +654,11 @@ private:
* Marks the node as having a proof a.
* This is safe if the node does not have
*/
- void markAsTrue(Constraint a);
+ void markAsTrue(ConstraintCP a);
- void markAsTrue(Constraint a, Constraint b);
- void markAsTrue(const std::vector<Constraint>& b);
+ void markAsTrue(ConstraintCP a, ConstraintCP b);
+ //void markAsTrue(const std::vector<Constraint>& b);
+ void markAsTrue(const ConstraintCPVec& b);
void debugPrint() const;
@@ -634,11 +672,11 @@ private:
}; /* class ConstraintValue */
-std::ostream& operator<<(std::ostream& o, const ConstraintValue& c);
-std::ostream& operator<<(std::ostream& o, const Constraint c);
+std::ostream& operator<<(std::ostream& o, const Constraint_& c);
+std::ostream& operator<<(std::ostream& o, const ConstraintP c);
std::ostream& operator<<(std::ostream& o, const ConstraintType t);
std::ostream& operator<<(std::ostream& o, const ValueCollection& c);
-
+std::ostream& operator<<(std::ostream& o, const ConstraintCPVec& v);
class ConstraintDatabase {
@@ -650,20 +688,17 @@ private:
*/
std::vector<PerVariableDatabase*> d_varDatabases;
- SortedConstraintMap& getVariableSCM(ArithVar v) const{
- Assert(variableDatabaseIsSetup(v));
- return d_varDatabases[v]->d_constraints;
- }
+ SortedConstraintMap& getVariableSCM(ArithVar v) const;
/** Maps literals to constraints.*/
NodetoConstraintMap d_nodetoConstraintMap;
/**
* A queue of propagated constraints.
- *
- * As Constraint are pointers, the elements of the queue do not require destruction.
+ * ConstraintCP are pointers.
+ * The elements of the queue do not require destruction.
*/
- context::CDQueue<Constraint> d_toPropagate;
+ context::CDQueue<ConstraintCP> d_toPropagate;
/**
* Proof Lists.
@@ -701,17 +736,16 @@ private:
ProofId d_equalityEngineProof;
/**
- * Marks a node as being true always.
- * This is only okay for purely internal things.
- *
- * This is a special proof that is always a member of the list.
+ * Marks a constraint as being proved by making an internal
+ * decision. Such nodes cannot be used in external explanations
+ * but can be used internally.
*/
- //ProofId d_pseudoConstraintProof;
+ ProofId d_internalDecisionProof;
- typedef context::CDList<Constraint, ConstraintValue::ProofCleanup> ProofCleanupList;
- typedef context::CDList<Constraint, ConstraintValue::CanBePropagatedCleanup> CBPList;
- typedef context::CDList<Constraint, ConstraintValue::AssertionOrderCleanup> AOList;
- typedef context::CDList<Constraint, ConstraintValue::SplitCleanup> SplitList;
+ typedef context::CDList<ConstraintP, Constraint_::ProofCleanup> ProofCleanupList;
+ typedef context::CDList<ConstraintP, Constraint_::CanBePropagatedCleanup> CBPList;
+ typedef context::CDList<ConstraintP, Constraint_::AssertionOrderCleanup> AOList;
+ typedef context::CDList<ConstraintP, Constraint_::SplitCleanup> SplitList;
/**
* The watch lists are collected together as they need to be garbage collected
@@ -744,30 +778,10 @@ private:
};
Watches* d_watches;
- void pushSplitWatch(Constraint c){
- Assert(!c->d_split);
- c->d_split = true;
- d_watches->d_splitWatches.push_back(c);
- }
-
- void pushCanBePropagatedWatch(Constraint c){
- Assert(!c->d_canBePropagated);
- c->d_canBePropagated = true;
- d_watches->d_canBePropagatedWatches.push_back(c);
- }
-
- void pushAssertionOrderWatch(Constraint c, TNode witness){
- Assert(!c->assertedToTheTheory());
- c->_d_assertionOrder = d_watches->d_assertionOrderWatches.size();
- c->d_witness = witness;
- d_watches->d_assertionOrderWatches.push_back(c);
- }
-
- void pushProofWatch(Constraint c, ProofId pid){
- Assert(c->d_proof == ProofIdSentinel);
- c->d_proof = pid;
- d_watches->d_proofWatches.push_back(c);
- }
+ void pushSplitWatch(ConstraintP c);
+ void pushCanBePropagatedWatch(ConstraintP c);
+ void pushAssertionOrderWatch(ConstraintP c, TNode witness);
+ void pushProofWatch(ConstraintP c, ProofId pid);
/** Returns true if all of the entries of the vector are empty. */
static bool emptyDatabase(const std::vector<PerVariableDatabase>& vec);
@@ -786,7 +800,7 @@ private:
RaiseConflict d_raiseConflict;
- friend class ConstraintValue;
+ friend class Constraint_;
public:
@@ -799,13 +813,13 @@ public:
~ConstraintDatabase();
/** Adds a literal to the database. */
- Constraint addLiteral(TNode lit);
+ ConstraintP addLiteral(TNode lit);
/**
* If hasLiteral() is true, returns the constraint.
* Otherwise, returns NullConstraint.
*/
- Constraint lookup(TNode literal) const;
+ ConstraintP lookup(TNode literal) const;
/**
* Returns true if the literal has been added to the database.
@@ -818,10 +832,10 @@ public:
return !d_toPropagate.empty();
}
- Constraint nextPropagation(){
+ ConstraintCP nextPropagation(){
Assert(hasMorePropagations());
- Constraint p = d_toPropagate.front();
+ ConstraintCP p = d_toPropagate.front();
d_toPropagate.pop();
return p;
@@ -831,8 +845,8 @@ public:
bool variableDatabaseIsSetup(ArithVar v) const;
void removeVariable(ArithVar v);
- Node eeExplain(ConstConstraint c) const;
- void eeExplain(ConstConstraint c, NodeBuilder<>& nb) const;
+ Node eeExplain(ConstraintCP c) const;
+ void eeExplain(ConstraintCP c, NodeBuilder<>& nb) const;
/**
* Returns a constraint with the variable v, the constraint type t, and a value
@@ -843,8 +857,13 @@ public:
* The returned value v is dominated:
* If t is UpperBound, r <= v
* If t is LowerBound, r >= v
+ *
+ * variableDatabaseIsSetup(v) must be true.
*/
- Constraint getBestImpliedBound(ArithVar v, ConstraintType t, const DeltaRational& r) const;
+ ConstraintP getBestImpliedBound(ArithVar v, ConstraintType t, const DeltaRational& r) const;
+
+ /** Returns the constraint, if it exists */
+ ConstraintP lookupConstraint(ArithVar v, ConstraintType t, const DeltaRational& r) const;
/**
* Returns a constraint with the variable v, the constraint type t and the value r.
@@ -852,22 +871,18 @@ public:
* If there is no such constraint, this constraint is added to the database.
*
*/
- Constraint getConstraint(ArithVar v, ConstraintType t, const DeltaRational& r);
+ ConstraintP getConstraint(ArithVar v, ConstraintType t, const DeltaRational& r);
/**
* Returns a constraint of the given type for the value and variable
* for the given ValueCollection, vc.
* This is made if there is no such constraint.
*/
- Constraint ensureConstraint(ValueCollection& vc, ConstraintType t){
- if(vc.hasConstraintOfType(t)){
- return vc.getConstraintOfType(t);
- }else{
- return getConstraint(vc.getVariable(), t, vc.getValue());
- }
- }
+ ConstraintP ensureConstraint(ValueCollection& vc, ConstraintType t);
+ void deleteConstraintAndNegation(ConstraintP c);
+
/**
* Outputs a minimal set of unate implications onto the vector for the variable.
* This outputs lemmas of the general forms
@@ -887,12 +902,12 @@ public:
void outputUnateInequalityLemmas(std::vector<Node>& lemmas, ArithVar v) const;
- void unatePropLowerBound(Constraint curr, Constraint prev);
- void unatePropUpperBound(Constraint curr, Constraint prev);
- void unatePropEquality(Constraint curr, Constraint prevLB, Constraint prevUB);
+ void unatePropLowerBound(ConstraintP curr, ConstraintP prev);
+ void unatePropUpperBound(ConstraintP curr, ConstraintP prev);
+ void unatePropEquality(ConstraintP curr, ConstraintP prevLB, ConstraintP prevUB);
private:
- void raiseUnateConflict(Constraint ant, Constraint cons);
+ void raiseUnateConflict(ConstraintP ant, ConstraintP cons);
DenseSet d_reclaimable;
@@ -907,6 +922,7 @@ private:
}; /* ConstraintDatabase */
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/arith/constraint_forward.h b/src/theory/arith/constraint_forward.h
index f01c64b60..19326c0b3 100644
--- a/src/theory/arith/constraint_forward.h
+++ b/src/theory/arith/constraint_forward.h
@@ -16,23 +16,26 @@
** minimize interaction between header files.
**/
-#include "cvc4_private.h"
-
#ifndef __CVC4__THEORY__ARITH__CONSTRAINT_FORWARD_H
#define __CVC4__THEORY__ARITH__CONSTRAINT_FORWARD_H
+#include "cvc4_private.h"
+#include <vector>
+
namespace CVC4 {
namespace theory {
namespace arith {
-class ConstraintValue;
-typedef ConstraintValue* Constraint;
-typedef const ConstraintValue* const ConstConstraint;
+class Constraint_;
+typedef Constraint_* ConstraintP;
+typedef const Constraint_* ConstraintCP;
-static const Constraint NullConstraint = NULL;
+const ConstraintP NullConstraint = NULL;
class ConstraintDatabase;
+typedef std::vector<ConstraintCP> ConstraintCPVec;
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/arith/cut_log.cpp b/src/theory/arith/cut_log.cpp
new file mode 100644
index 000000000..f933516ba
--- /dev/null
+++ b/src/theory/arith/cut_log.cpp
@@ -0,0 +1,691 @@
+#include "cvc4autoconfig.h"
+
+
+#include "theory/arith/cut_log.h"
+#include "theory/arith/approx_simplex.h"
+#include "theory/arith/normal_form.h"
+#include "theory/arith/constraint.h"
+#include <math.h>
+#include <cmath>
+#include <map>
+#include <limits.h>
+
+using namespace std;
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+NodeLog::const_iterator NodeLog::begin() const { return d_cuts.begin(); }
+NodeLog::const_iterator NodeLog::end() const { return d_cuts.end(); }
+
+NodeLog& TreeLog::getNode(int nid) {
+ ToNodeMap::iterator i = d_toNode.find(nid);
+ Assert(i != d_toNode.end());
+ return (*i).second;
+}
+
+TreeLog::const_iterator TreeLog::begin() const { return d_toNode.begin(); }
+TreeLog::const_iterator TreeLog::end() const { return d_toNode.end(); }
+
+int TreeLog::getExecutionOrd(){
+ int res = next_exec_ord;
+ ++next_exec_ord;
+ return res;
+}
+void TreeLog::makeInactive(){ d_active = false; }
+void TreeLog::makeActive(){ d_active = true; }
+bool TreeLog::isActivelyLogging() const { return d_active; }
+
+
+PrimitiveVec::PrimitiveVec()
+ : len(0)
+ , inds(NULL)
+ , coeffs(NULL)
+{}
+
+PrimitiveVec::~PrimitiveVec(){
+ clear();
+}
+bool PrimitiveVec::initialized() const {
+ return inds != NULL;
+}
+void PrimitiveVec::clear() {
+ if(initialized()){
+ delete[] inds;
+ delete[] coeffs;
+ len = 0;
+ inds = NULL;
+ coeffs = NULL;
+ }
+}
+void PrimitiveVec::setup(int l){
+ Assert(!initialized());
+ len = l;
+ inds = new int[1+len];
+ coeffs = new double[1+len];
+}
+void PrimitiveVec::print(std::ostream& out) const{
+ Assert(initialized());
+ out << len << " ";
+ out.precision(15);
+ for(int i = 1; i <= len; ++i){
+ out << "["<< inds[i] <<", " << coeffs[i]<<"]";
+ }
+}
+std::ostream& operator<<(std::ostream& os, const PrimitiveVec& pv){
+ pv.print(os);
+ return os;
+}
+
+CutInfo::CutInfo(CutInfoKlass kl, int eid, int o)
+ : d_klass(kl)
+ , d_execOrd(eid)
+ , d_poolOrd(o)
+ , d_cutType(kind::UNDEFINED_KIND)
+ , d_cutRhs()
+ , d_cutVec()
+ , d_mAtCreation(-1)
+ , d_rowId(-1)
+ , d_exactPrecision(NULL)
+ , d_explanation(NULL)
+{}
+
+CutInfo::~CutInfo(){
+ if(d_exactPrecision == NULL){ delete d_exactPrecision; }
+ if(d_explanation == NULL){ delete d_explanation; }
+}
+
+int CutInfo::getId() const {
+ return d_execOrd;
+}
+
+int CutInfo::getRowId() const{
+ return d_rowId;
+}
+
+void CutInfo::setRowId(int rid){
+ d_rowId = rid;
+}
+
+void CutInfo::print(ostream& out) const{
+ out << "[CutInfo " << d_execOrd << " " << d_poolOrd
+ << " " << d_klass << " " << d_cutType << " " << d_cutRhs
+ << " ";
+ d_cutVec.print(out);
+ out << "]" << endl;
+}
+
+PrimitiveVec& CutInfo::getCutVector(){
+ return d_cutVec;
+}
+
+const PrimitiveVec& CutInfo::getCutVector() const{
+ return d_cutVec;
+}
+
+// void CutInfo::init_cut(int l){
+// cut_vec.setup(l);
+// }
+
+Kind CutInfo::getKind() const{
+ return d_cutType;
+}
+
+void CutInfo::setKind(Kind k){
+ Assert(k == kind::LEQ || k == kind::GEQ);
+ d_cutType = k;
+}
+
+double CutInfo::getRhs() const{
+ return d_cutRhs;
+}
+
+void CutInfo::setRhs(double r){
+ d_cutRhs = r;
+}
+
+bool CutInfo::reconstructed() const{
+ return d_exactPrecision != NULL;
+}
+
+CutInfoKlass CutInfo::getKlass() const{
+ return d_klass;
+}
+
+int CutInfo::poolOrdinal() const{
+ return d_poolOrd;
+}
+
+void CutInfo::setDimensions(int N, int M){
+ d_mAtCreation = M;
+ d_N = N;
+}
+
+int CutInfo::getN() const{
+ return d_N;
+}
+
+int CutInfo::getMAtCreation() const{
+ return d_mAtCreation;
+}
+
+/* Returns true if the cut has an explanation. */
+bool CutInfo::proven() const{
+ return d_explanation != NULL;
+}
+
+bool CutInfo::operator<(const CutInfo& o) const{
+ return d_execOrd < o.d_execOrd;
+}
+
+
+void CutInfo::setReconstruction(const DenseVector& ep){
+ Assert(!reconstructed());
+ d_exactPrecision = new DenseVector(ep);
+}
+
+void CutInfo::setExplanation(const ConstraintCPVec& ex){
+ Assert(reconstructed());
+ if(d_explanation == NULL){
+ d_explanation = new ConstraintCPVec(ex);
+ }else{
+ *d_explanation = ex;
+ }
+}
+
+void CutInfo::swapExplanation(ConstraintCPVec& ex){
+ Assert(reconstructed());
+ Assert(!proven());
+ if(d_explanation == NULL){
+ d_explanation = new ConstraintCPVec();
+ }
+ d_explanation->swap(ex);
+}
+
+const DenseVector& CutInfo::getReconstruction() const {
+ Assert(reconstructed());
+ return *d_exactPrecision;
+}
+
+void CutInfo::clearReconstruction(){
+ if(proven()){
+ delete d_explanation;
+ d_explanation = NULL;
+ }
+
+ if(reconstructed()){
+ delete d_exactPrecision;
+ d_exactPrecision = NULL;
+ }
+
+ Assert(!reconstructed());
+ Assert(!proven());
+}
+
+const ConstraintCPVec& CutInfo::getExplanation() const {
+ Assert(proven());
+ return *d_explanation;
+}
+
+std::ostream& operator<<(std::ostream& os, const CutInfo& ci){
+ ci.print(os);
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& out, CutInfoKlass kl){
+ switch(kl){
+ case MirCutKlass:
+ out << "MirCutKlass"; break;
+ case GmiCutKlass:
+ out << "GmiCutKlass"; break;
+ case BranchCutKlass:
+ out << "BranchCutKlass"; break;
+ case RowsDeletedKlass:
+ out << "RowDeletedKlass"; break;
+ case UnknownKlass:
+ out << "UnknownKlass"; break;
+ default:
+ out << "unexpected CutInfoKlass"; break;
+ }
+ return out;
+}
+bool NodeLog::isBranch() const{
+ return d_brVar >= 0;
+}
+
+NodeLog::NodeLog()
+ : d_nid(-1)
+ , d_parent(NULL)
+ , d_tl(NULL)
+ , d_cuts()
+ , d_rowIdsSelected()
+ , d_stat(Open)
+ , d_brVar(-1)
+ , d_brVal(0.0)
+ , d_downId(-1)
+ , d_upId(-1)
+ , d_rowId2ArithVar()
+{}
+
+NodeLog::NodeLog(TreeLog* tl, int node, const RowIdMap& m)
+ : d_nid(node)
+ , d_parent(NULL)
+ , d_tl(tl)
+ , d_cuts()
+ , d_rowIdsSelected()
+ , d_stat(Open)
+ , d_brVar(-1)
+ , d_brVal(0.0)
+ , d_downId(-1)
+ , d_upId(-1)
+ , d_rowId2ArithVar(m)
+{}
+
+NodeLog::NodeLog(TreeLog* tl, NodeLog* parent, int node)
+ : d_nid(node)
+ , d_parent(parent)
+ , d_tl(tl)
+ , d_cuts()
+ , d_rowIdsSelected()
+ , d_stat(Open)
+ , d_brVar(-1)
+ , d_brVal(0.0)
+ , d_downId(-1)
+ , d_upId(-1)
+ , d_rowId2ArithVar()
+{}
+
+NodeLog::~NodeLog(){
+ CutSet::iterator i = d_cuts.begin(), iend = d_cuts.end();
+ for(; i != iend; ++i){
+ CutInfo* c = *i;
+ delete c;
+ }
+ d_cuts.clear();
+ Assert(d_cuts.empty());
+}
+
+std::ostream& operator<<(std::ostream& os, const NodeLog& nl){
+ nl.print(os);
+ return os;
+}
+
+void NodeLog::copyParentRowIds() {
+ Assert(d_parent != NULL);
+ d_rowId2ArithVar = d_parent->d_rowId2ArithVar;
+}
+
+int NodeLog::branchVariable() const {
+ return d_brVar;
+}
+double NodeLog::branchValue() const{
+ return d_brVal;
+}
+int NodeLog::getNodeId() const {
+ return d_nid;
+}
+int NodeLog::getDownId() const{
+ return d_downId;
+}
+int NodeLog::getUpId() const{
+ return d_upId;
+}
+void NodeLog::addSelected(int ord, int sel){
+ Assert(d_rowIdsSelected.find(ord) == d_rowIdsSelected.end());
+ d_rowIdsSelected[ord] = sel;
+ Debug("approx::nodelog") << "addSelected("<< ord << ", "<< sel << ")" << endl;
+}
+void NodeLog::applySelected() {
+ CutSet::iterator iter = d_cuts.begin(), iend = d_cuts.end(), todelete;
+ while(iter != iend){
+ CutInfo* curr = *iter;
+ int poolOrd = curr->poolOrdinal();
+ if(curr->getRowId() >= 0 ){
+ // selected previously, kip
+ ++iter;
+ }else if(curr->getKlass() == RowsDeletedKlass){
+ // skip
+ ++iter;
+ }else if(curr->getKlass() == BranchCutKlass){
+ // skip
+ ++iter;
+ }else if(d_rowIdsSelected.find(poolOrd) == d_rowIdsSelected.end()){
+ todelete = iter;
+ ++iter;
+ d_cuts.erase(todelete);
+ delete curr;
+ }else{
+ Debug("approx::nodelog") << "applySelected " << curr->getId() << " " << poolOrd << "->" << d_rowIdsSelected[poolOrd] << endl;
+ curr->setRowId( d_rowIdsSelected[poolOrd] );
+ ++iter;
+ }
+ }
+ d_rowIdsSelected.clear();
+}
+
+void NodeLog::applyRowsDeleted(const RowsDeleted& rd) {
+ std::map<int, CutInfo*> currInOrd; //sorted
+
+ const PrimitiveVec& cv = rd.getCutVector();
+ std::vector<int> sortedRemoved (cv.inds+1, cv.inds+cv.len+1);
+ sortedRemoved.push_back(INT_MAX);
+ std::sort(sortedRemoved.begin(), sortedRemoved.end());
+
+ if(Debug.isOn("approx::nodelog")){
+ Debug("approx::nodelog") << "Removing #" << sortedRemoved.size()<< "...";
+ for(unsigned k = 0; k<sortedRemoved.size(); k++){
+ Debug("approx::nodelog") << ", " << sortedRemoved[k];
+ }
+ Debug("approx::nodelog") << endl;
+ Debug("approx::nodelog") << "cv.len" << cv.len << endl;
+ }
+
+ int min = sortedRemoved.front();
+
+ CutSet::iterator iter = d_cuts.begin(), iend = d_cuts.end();
+ while(iter != iend){
+ CutInfo* curr= *iter;
+ if(curr->getId() < rd.getId()){
+ if(d_rowId2ArithVar.find(curr->getRowId()) != d_rowId2ArithVar.end()){
+ if(curr->getRowId() >= min){
+ currInOrd.insert(make_pair(curr->getRowId(), curr));
+ }
+ }
+ }
+ ++iter;
+ }
+
+ RowIdMap::const_iterator i, end;
+ i=d_rowId2ArithVar.begin(), end = d_rowId2ArithVar.end();
+ for(; i != end; ++i){
+ int key = (*i).first;
+ if(key >= min){
+ if(currInOrd.find(key) == currInOrd.end()){
+ CutInfo* null = NULL;
+ currInOrd.insert(make_pair(key, null));
+ }
+ }
+ }
+
+
+
+ std::map<int, CutInfo*>::iterator j, jend;
+
+ int posInSorted = 0;
+ for(j = currInOrd.begin(), jend=currInOrd.end(); j!=jend; ++j){
+ int origOrd = (*j).first;
+ ArithVar v = d_rowId2ArithVar[origOrd];
+ int headRemovedOrd = sortedRemoved[posInSorted];
+ while(headRemovedOrd < origOrd){
+ ++posInSorted;
+ headRemovedOrd = sortedRemoved[posInSorted];
+ }
+ // headRemoveOrd >= origOrd
+ Assert(headRemovedOrd >= origOrd);
+
+ CutInfo* ci = (*j).second;
+ if(headRemovedOrd == origOrd){
+
+ if(ci == NULL){
+ Debug("approx::nodelog") << "deleting from above because of " << rd << endl;
+ Debug("approx::nodelog") << "had " << origOrd << " <-> " << v << endl;
+ d_rowId2ArithVar.erase(origOrd);
+ }else{
+ Debug("approx::nodelog") << "deleting " << ci << " because of " << rd << endl;
+ Debug("approx::nodelog") << "had " << origOrd << " <-> " << v << endl;
+ d_rowId2ArithVar.erase(origOrd);
+ ci->setRowId(-1);
+ }
+ }else{
+ Assert(headRemovedOrd > origOrd);
+ // headRemoveOrd > origOrd
+ int newOrd = origOrd - posInSorted;
+ Assert(newOrd > 0);
+ if(ci == NULL){
+ Debug("approx::nodelog") << "shifting above down due to " << rd << endl;
+ Debug("approx::nodelog") << "had " << origOrd << " <-> " << v << endl;
+ Debug("approx::nodelog") << "now have " << newOrd << " <-> " << v << endl;
+ d_rowId2ArithVar.erase(origOrd);
+ mapRowId(newOrd, v);
+ }else{
+ Debug("approx::nodelog") << "shifting " << ci << " down due to " << rd << endl;
+ Debug("approx::nodelog") << "had " << origOrd << " <-> " << v << endl;
+ Debug("approx::nodelog") << "now have " << newOrd << " <-> " << v << endl;
+ ci->setRowId(newOrd);
+ d_rowId2ArithVar.erase(origOrd);
+ mapRowId(newOrd, v);
+ }
+ }
+ }
+
+}
+
+// void NodeLog::adjustRowId(CutInfo& ci, const RowsDeleted& rd) {
+// int origRowId = ci.getRowId();
+// int newRowId = ci.getRowId();
+// ArithVar v = d_rowId2ArithVar[origRowId];
+
+// const PrimitiveVec& cv = rd.getCutVector();
+
+// for(int j = 1, N = cv.len; j <= N; j++){
+// int ind = cv.inds[j];
+// if(ind == origRowId){
+// newRowId = -1;
+// break;
+// }else if(ind < origRowId){
+// newRowId--;
+// }
+// }
+
+// if(newRowId < 0){
+// cout << "deleting " << ci << " because of " << rd << endl;
+// cout << "had " << origRowId << " <-> " << v << endl;
+// d_rowId2ArithVar.erase(origRowId);
+// ci.setRowId(-1);
+// }else if(newRowId != origRowId){
+// cout << "adjusting " << ci << " because of " << rd << endl;
+// cout << "had " << origRowId << " <-> " << v << endl;
+// cout << "now have " << newRowId << " <-> " << v << endl;
+// d_rowId2ArithVar.erase(origRowId);
+// ci.setRowId(newRowId);
+// mapRowId(newRowId, v);
+// }else{
+// cout << "row id unchanged " << ci << " because of " << rd << endl;
+// }
+// }
+
+
+ArithVar NodeLog::lookupRowId(int rowId) const{
+ RowIdMap::const_iterator i = d_rowId2ArithVar.find(rowId);
+ if(i == d_rowId2ArithVar.end()){
+ return ARITHVAR_SENTINEL;
+ }else{
+ return (*i).second;
+ }
+}
+
+void NodeLog::mapRowId(int rowId, ArithVar v){
+ Assert(lookupRowId(rowId) == ARITHVAR_SENTINEL);
+ Debug("approx::nodelog")
+ << "On " << getNodeId()
+ << " adding row id " << rowId << " <-> " << v << endl;
+ d_rowId2ArithVar[rowId] = v;
+}
+
+
+
+void NodeLog::addCut(CutInfo* ci){
+ Assert(ci != NULL);
+ d_cuts.insert(ci);
+}
+
+void NodeLog::print(ostream& o) const{
+ o << "[n" << getNodeId();
+ for(const_iterator iter = begin(), iend = end(); iter != iend; ++iter ){
+ CutInfo* cut = *iter;
+ o << ", " << cut->poolOrdinal();
+ if(cut->getRowId() >= 0){
+ o << " " << cut->getRowId();
+ }
+ }
+ o << "]" << std::endl;
+}
+
+void NodeLog::closeNode(){
+ Assert(d_stat == Open);
+ d_stat = Closed;
+}
+
+void NodeLog::setBranch(int br, double val, int d, int u){
+ Assert(d_stat == Open);
+ d_brVar = br;
+ d_brVal = val;
+ d_downId = d;
+ d_upId = u;
+ d_stat = Branched;
+}
+
+TreeLog::TreeLog()
+ : next_exec_ord(0)
+ , d_toNode()
+ , d_branches()
+ , d_numCuts(0)
+ , d_active(false)
+{
+ NodeLog::RowIdMap empty;
+ reset(empty);
+}
+
+int TreeLog::getRootId() const{
+ return 1;
+}
+
+NodeLog& TreeLog::getRootNode(){
+ return getNode(getRootId());
+}
+
+void TreeLog::clear(){
+ next_exec_ord = 0;
+ d_toNode.clear();
+ d_branches.purge();
+
+ d_numCuts = 0;
+
+ // add root
+}
+
+void TreeLog::reset(const NodeLog::RowIdMap& m){
+ clear();
+ d_toNode.insert(make_pair(getRootId(), NodeLog(this, getRootId(), m)));
+}
+
+void TreeLog::addCut(){ d_numCuts++; }
+uint32_t TreeLog::cutCount() const { return d_numCuts; }
+void TreeLog::logBranch(uint32_t x){
+ d_branches.add(x);
+}
+uint32_t TreeLog::numBranches(uint32_t x){
+ return d_branches.count(x);
+}
+
+void TreeLog::branch(int nid, int br, double val, int dn, int up){
+ NodeLog& nl = getNode(nid);
+ nl.setBranch(br, val, dn, up);
+
+ d_toNode.insert(make_pair(dn, NodeLog(this, &nl, dn)));
+ d_toNode.insert(make_pair(up, NodeLog(this, &nl, up)));
+}
+
+void TreeLog::close(int nid){
+ NodeLog& nl = getNode(nid);
+ nl.closeNode();
+}
+
+
+
+// void TreeLog::applySelected() {
+// std::map<int, NodeLog>::iterator iter, end;
+// for(iter = d_toNode.begin(), end = d_toNode.end(); iter != end; ++iter){
+// NodeLog& onNode = (*iter).second;
+// //onNode.applySelected();
+// }
+// }
+
+void TreeLog::print(ostream& o) const{
+ o << "TreeLog: " << d_toNode.size() << std::endl;
+ for(const_iterator iter = begin(), iend = end(); iter != iend; ++iter){
+ const NodeLog& onNode = (*iter).second;
+ onNode.print(o);
+ }
+}
+
+void TreeLog::applyRowsDeleted(int nid, const RowsDeleted& rd){
+ NodeLog& nl = getNode(nid);
+ nl.applyRowsDeleted(rd);
+}
+
+void TreeLog::mapRowId(int nid, int ind, ArithVar v){
+ NodeLog& nl = getNode(nid);
+ nl.mapRowId(ind, v);
+}
+
+void DenseVector::purge() {
+ lhs.purge();
+ rhs = Rational(0);
+}
+
+RowsDeleted::RowsDeleted(int execOrd, int nrows, const int num[])
+ : CutInfo(RowsDeletedKlass, execOrd, 0)
+{
+ d_cutVec.setup(nrows);
+ for(int j=1; j <= nrows; j++){
+ d_cutVec.coeffs[j] = 0;
+ d_cutVec.inds[j] = num[j];
+ }
+}
+
+BranchCutInfo::BranchCutInfo(int execOrd, int br, Kind dir, double val)
+ : CutInfo(BranchCutKlass, execOrd, 0)
+{
+ d_cutVec.setup(1);
+ d_cutVec.inds[1] = br;
+ d_cutVec.coeffs[1] = +1.0;
+ d_cutRhs = val;
+ d_cutType = dir;
+}
+
+void TreeLog::printBranchInfo(ostream& os) const{
+ uint32_t total = 0;
+ DenseMultiset::const_iterator iter = d_branches.begin(), iend = d_branches.end();
+ for(; iter != iend; ++iter){
+ uint32_t el = *iter;
+ total += el;
+ }
+ os << "printBranchInfo() : " << total << endl;
+ iter = d_branches.begin(), iend = d_branches.end();
+ for(; iter != iend; ++iter){
+ uint32_t el = *iter;
+ os << "["<<el <<", " << d_branches.count(el) << "]";
+ }
+ os << endl;
+}
+
+
+void DenseVector::print(std::ostream& os) const {
+ os << rhs << " + ";
+ print(os, lhs);
+}
+void DenseVector::print(ostream& out, const DenseMap<Rational>& v){
+ out << "[DenseVec len " << v.size();
+ DenseMap<Rational>::const_iterator iter, end;
+ for(iter = v.begin(), end = v.end(); iter != end; ++iter){
+ ArithVar x = *iter;
+ out << ", "<< x << " " << v[x];
+ }
+ out << "]";
+}
+
+}/* CVC4::theory::arith namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/arith/cut_log.h b/src/theory/arith/cut_log.h
new file mode 100644
index 000000000..123313617
--- /dev/null
+++ b/src/theory/arith/cut_log.h
@@ -0,0 +1,281 @@
+
+#include "cvc4_private.h"
+
+#pragma once
+
+#include "expr/kind.h"
+#include "util/statistics_registry.h"
+#include "theory/arith/arithvar.h"
+#include "theory/arith/constraint_forward.h"
+#include "util/dense_map.h"
+#include <vector>
+#include <map>
+#include <set>
+#include <ext/hash_map>
+
+namespace CVC4 {
+namespace theory {
+namespace arith {
+
+/** A low level vector of indexed doubles. */
+struct PrimitiveVec {
+ int len;
+ int* inds;
+ double* coeffs;
+ PrimitiveVec();
+ ~PrimitiveVec();
+ bool initialized() const;
+ void clear();
+ void setup(int l);
+ void print(std::ostream& out) const;
+};
+std::ostream& operator<<(std::ostream& os, const PrimitiveVec& pv);
+
+struct DenseVector {
+ DenseMap<Rational> lhs;
+ Rational rhs;
+ void purge();
+ void print(std::ostream& os) const;
+
+ static void print(std::ostream& os, const DenseMap<Rational>& lhs);
+};
+
+/** The different kinds of cuts. */
+enum CutInfoKlass{ MirCutKlass, GmiCutKlass, BranchCutKlass,
+ RowsDeletedKlass,
+ UnknownKlass};
+std::ostream& operator<<(std::ostream& os, CutInfoKlass kl);
+
+/** A general class for describing a cut. */
+class CutInfo {
+protected:
+ CutInfoKlass d_klass;
+ int d_execOrd;
+
+ int d_poolOrd; /* cut's ordinal in the current node pool */
+ Kind d_cutType; /* Lowerbound, upperbound or undefined. */
+ double d_cutRhs; /* right hand side of the cut */
+ PrimitiveVec d_cutVec; /* vector of the cut */
+
+ /**
+ * The number of rows at the time the cut was made.
+ * This is required to descramble indices after the fact!
+ */
+ int d_mAtCreation;
+
+ /** This is the number of structural variables. */
+ int d_N;
+
+ /** if selected, make this non-zero */
+ int d_rowId;
+
+ /* If the cut has been successfully created,
+ * the cut is stored in exact precision in d_exactPrecision.
+ * If the cut has not yet been proven, this is null.
+ */
+ DenseVector* d_exactPrecision;
+
+ ConstraintCPVec* d_explanation;
+
+public:
+ CutInfo(CutInfoKlass kl, int cutid, int ordinal);
+
+ virtual ~CutInfo();
+
+ int getId() const;
+
+ int getRowId() const;
+ void setRowId(int rid);
+
+ void print(std::ostream& out) const;
+ //void init_cut(int l);
+ PrimitiveVec& getCutVector();
+ const PrimitiveVec& getCutVector() const;
+
+ Kind getKind() const;
+ void setKind(Kind k);
+
+
+ void setRhs(double r);
+ double getRhs() const;
+
+ CutInfoKlass getKlass() const;
+ int poolOrdinal() const;
+
+ void setDimensions(int N, int M);
+ int getN() const;
+ int getMAtCreation() const;
+
+ bool operator<(const CutInfo& o) const;
+
+ /* Returns true if the cut was successfully made in exact precision.*/
+ bool reconstructed() const;
+
+ /* Returns true if the cut has an explanation. */
+ bool proven() const;
+
+ void setReconstruction(const DenseVector& ep);
+ void setExplanation(const ConstraintCPVec& ex);
+ void swapExplanation(ConstraintCPVec& ex);
+
+ const DenseVector& getReconstruction() const;
+ const ConstraintCPVec& getExplanation() const;
+
+ void clearReconstruction();
+};
+std::ostream& operator<<(std::ostream& os, const CutInfo& ci);
+
+struct BranchCutInfo : public CutInfo {
+ BranchCutInfo(int execOrd, int br, Kind dir, double val);
+};
+
+struct RowsDeleted : public CutInfo {
+ RowsDeleted(int execOrd, int nrows, const int num[]);
+};
+
+class TreeLog;
+
+class NodeLog {
+private:
+ int d_nid;
+ NodeLog* d_parent; /* If null this is the root */
+ TreeLog* d_tl; /* TreeLog containing the node. */
+
+ struct CmpCutPointer{
+ int operator()(const CutInfo* a, const CutInfo* b) const{
+ return *a < *b;
+ }
+ };
+ typedef std::set<CutInfo*, CmpCutPointer> CutSet;
+ CutSet d_cuts;
+ std::map<int, int> d_rowIdsSelected;
+
+ enum Status {Open, Closed, Branched};
+ Status d_stat;
+
+ int d_brVar; // branching variable
+ double d_brVal;
+ int d_downId;
+ int d_upId;
+
+public:
+ typedef __gnu_cxx::hash_map<int, ArithVar> RowIdMap;
+private:
+ RowIdMap d_rowId2ArithVar;
+
+public:
+ NodeLog(); /* default constructor. */
+ NodeLog(TreeLog* tl, int node, const RowIdMap& m); /* makes a root node. */
+ NodeLog(TreeLog* tl, NodeLog* parent, int node);/* makes a non-root node. */
+
+ ~NodeLog();
+
+ int getNodeId() const;
+ void addSelected(int ord, int sel);
+ void applySelected();
+ void addCut(CutInfo* ci);
+ void print(std::ostream& o) const;
+
+ bool isRoot() const;
+ const NodeLog& getParent() const;
+
+ void copyParentRowIds();
+
+ bool isBranch() const;
+ int branchVariable() const;
+ double branchValue() const;
+
+ typedef CutSet::const_iterator const_iterator;
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ void setBranch(int br, double val, int dn, int up);
+ void closeNode();
+
+ int getDownId() const;
+ int getUpId() const;
+
+ /**
+ * Looks up a row id to the appropraite arith variable.
+ * Be careful these are deleted in context during replay!
+ * failure returns ARITHVAR_SENTINEL */
+ ArithVar lookupRowId(int rowId) const;
+
+ /**
+ * Maps a row id to an arithvar.
+ * Be careful these are deleted in context during replay!
+ */
+ void mapRowId(int rowid, ArithVar v);
+ void applyRowsDeleted(const RowsDeleted& rd);
+
+};
+std::ostream& operator<<(std::ostream& os, const NodeLog& nl);
+
+class ApproximateSimplex;
+class TreeLog {
+private:
+ ApproximateSimplex* d_generator;
+
+ int next_exec_ord;
+ typedef std::map<int, NodeLog> ToNodeMap;
+ ToNodeMap d_toNode;
+ DenseMultiset d_branches;
+
+ uint32_t d_numCuts;
+
+ bool d_active;
+
+public:
+ TreeLog();
+
+ NodeLog& getNode(int nid);
+ void branch(int nid, int br, double val, int dn, int up);
+ void close(int nid);
+
+ //void applySelected();
+ void print(std::ostream& o) const;
+
+ typedef ToNodeMap::const_iterator const_iterator;
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ int getExecutionOrd();
+
+ void reset(const NodeLog::RowIdMap& m);
+
+ // Applies rd tp to the node with id nid
+ void applyRowsDeleted(int nid, const RowsDeleted& rd);
+
+ // Synonym for getNode(nid).mapRowId(ind, v)
+ void mapRowId(int nid, int ind, ArithVar v);
+
+private:
+ void clear();
+
+public:
+ void makeInactive();
+ void makeActive();
+
+ bool isActivelyLogging() const;
+
+ void addCut();
+ uint32_t cutCount() const;
+
+ void logBranch(uint32_t x);
+ uint32_t numBranches(uint32_t x);
+
+ int getRootId() const;
+
+ uint32_t numNodes() const{
+ return d_toNode.size();
+ }
+
+ NodeLog& getRootNode();
+ void printBranchInfo(std::ostream& os) const;
+};
+
+
+
+}/* CVC4::theory::arith namespace */
+}/* CVC4::theory namespace */
+}/* CVC4 namespace */
diff --git a/src/theory/arith/dio_solver.cpp b/src/theory/arith/dio_solver.cpp
index 39c2d859b..c9f9df727 100644
--- a/src/theory/arith/dio_solver.cpp
+++ b/src/theory/arith/dio_solver.cpp
@@ -281,7 +281,7 @@ void DioSolver::moveMinimumByAbsToQueueFront(){
size_t N = d_currentF.size();
for(size_t i=1; i < N; ++i){
Monomial curr = d_trail[d_currentF[i]].d_minimalMonomial;
- if(curr.absLessThan(minMonomial)){
+ if(curr.absCmp(minMonomial) < 0){
indexInQueue = i;
minMonomial = curr;
}
diff --git a/src/theory/arith/dio_solver.h b/src/theory/arith/dio_solver.h
index 5039f826c..32b8382fa 100644
--- a/src/theory/arith/dio_solver.h
+++ b/src/theory/arith/dio_solver.h
@@ -102,17 +102,17 @@ private:
};
context::CDList<Constraint> d_trail;
- /** Compare by d_minimal. */
- struct TrailMinimalCoefficientOrder {
- const context::CDList<Constraint>& d_trail;
- TrailMinimalCoefficientOrder(const context::CDList<Constraint>& trail):
- d_trail(trail)
- {}
-
- bool operator()(TrailIndex i, TrailIndex j){
- return d_trail[i].d_minimalMonomial.absLessThan(d_trail[j].d_minimalMonomial);
- }
- };
+ // /** Compare by d_minimal. */
+ // struct TrailMinimalCoefficientOrder {
+ // const context::CDList<Constraint>& d_trail;
+ // TrailMinimalCoefficientOrder(const context::CDList<Constraint>& trail):
+ // d_trail(trail)
+ // {}
+
+ // bool operator()(TrailIndex i, TrailIndex j){
+ // return d_trail[i].d_minimalMonomial.absLessThan(d_trail[j].d_minimalMonomial);
+ // }
+ // };
/**
* A substitution is stored as a constraint in the trail together with
diff --git a/src/theory/arith/error_set.cpp b/src/theory/arith/error_set.cpp
index dea78acf7..6d341ed12 100644
--- a/src/theory/arith/error_set.cpp
+++ b/src/theory/arith/error_set.cpp
@@ -39,7 +39,7 @@ ErrorInformation::ErrorInformation()
Debug("arith::error::mem") << "def constructor " << d_variable << " " << d_amount << endl;
}
-ErrorInformation::ErrorInformation(ArithVar var, Constraint vio, int sgn)
+ErrorInformation::ErrorInformation(ArithVar var, ConstraintP vio, int sgn)
: d_variable(var)
, d_violated(vio)
, d_sgn(sgn)
@@ -105,7 +105,7 @@ ErrorInformation& ErrorInformation::operator=(const ErrorInformation& ei){
return *this;
}
-void ErrorInformation::reset(Constraint c, int sgn){
+void ErrorInformation::reset(ConstraintP c, int sgn){
Assert(!isRelaxed());
Assert(c != NullConstraint);
d_violated = c;
@@ -272,7 +272,7 @@ void ErrorSet::transitionVariableOutOfError(ArithVar v) {
ErrorInformation& ei = d_errInfo.get(v);
Assert(ei.debugInitialized());
if(ei.isRelaxed()){
- Constraint viol = ei.getViolated();
+ ConstraintP viol = ei.getViolated();
if(ei.sgn() > 0){
d_variables.setLowerBoundConstraint(viol);
}else{
@@ -293,7 +293,7 @@ void ErrorSet::transitionVariableIntoError(ArithVar v) {
Assert(inconsistent(v));
bool vilb = d_variables.cmpAssignmentLowerBound(v) < 0;
int sgn = vilb ? 1 : -1;
- Constraint c = vilb ?
+ ConstraintP c = vilb ?
d_variables.getLowerBoundConstraint(v) : d_variables.getUpperBoundConstraint(v);
d_errInfo.set(v, ErrorInformation(v, c, sgn));
ErrorInformation& ei = d_errInfo.get(v);
@@ -373,7 +373,7 @@ int ErrorSet::popSignal() {
Assert(!vilb || !viub);
int currSgn = vilb ? 1 : -1;
if(currSgn != prevSgn){
- Constraint curr = vilb ? d_variables.getLowerBoundConstraint(back)
+ ConstraintP curr = vilb ? d_variables.getLowerBoundConstraint(back)
: d_variables.getUpperBoundConstraint(back);
ei.reset(curr, currSgn);
}
diff --git a/src/theory/arith/error_set.h b/src/theory/arith/error_set.h
index d1b692cb4..b87282ba0 100644
--- a/src/theory/arith/error_set.h
+++ b/src/theory/arith/error_set.h
@@ -120,7 +120,7 @@ private:
* This needs to be saved in case that the
* violated constraint
*/
- Constraint d_violated;
+ ConstraintP d_violated;
/**
* This is the sgn of the first derivate the variable must move to satisfy
@@ -155,12 +155,12 @@ private:
public:
ErrorInformation();
- ErrorInformation(ArithVar var, Constraint vio, int sgn);
+ ErrorInformation(ArithVar var, ConstraintP vio, int sgn);
~ErrorInformation();
ErrorInformation(const ErrorInformation& ei);
ErrorInformation& operator=(const ErrorInformation& ei);
- void reset(Constraint c, int sgn);
+ void reset(ConstraintP c, int sgn);
inline ArithVar getVariable() const { return d_variable; }
@@ -192,7 +192,7 @@ public:
}
inline const FocusSetHandle& getHandle() const{ return d_handle; }
- inline Constraint getViolated() const { return d_violated; }
+ inline ConstraintP getViolated() const { return d_violated; }
bool debugInitialized() const {
return
@@ -389,7 +389,7 @@ public:
return d_errInfo[a].getMetric();
}
- Constraint getViolated(ArithVar a) const {
+ ConstraintP getViolated(ArithVar a) const {
return d_errInfo[a].getViolated();
}
diff --git a/src/theory/arith/fc_simplex.cpp b/src/theory/arith/fc_simplex.cpp
index c0bffdf07..70a322959 100644
--- a/src/theory/arith/fc_simplex.cpp
+++ b/src/theory/arith/fc_simplex.cpp
@@ -536,7 +536,7 @@ void FCSimplexDecisionProcedure::updateAndSignal(const UpdateInfo& selected, Wit
}
if(selected.describesPivot()){
- Constraint limiting = selected.limiting();
+ ConstraintP limiting = selected.limiting();
ArithVar basic = limiting->getVariable();
Assert(d_linEq.basicIsTracked(basic));
d_linEq.pivotAndUpdate(basic, nonbasic, limiting->getValue());
diff --git a/src/theory/arith/linear_equality.cpp b/src/theory/arith/linear_equality.cpp
index 5817a3629..f4c1ae10c 100644
--- a/src/theory/arith/linear_equality.cpp
+++ b/src/theory/arith/linear_equality.cpp
@@ -494,7 +494,7 @@ const Tableau::Entry* LinearEqualityModule::rowLacksBound(RowIndex ridx, bool ro
return NULL;
}
-void LinearEqualityModule::propagateBasicFromRow(Constraint c){
+void LinearEqualityModule::propagateBasicFromRow(ConstraintP c){
Assert(c != NullConstraint);
Assert(c->isUpperBound() || c->isLowerBound());
Assert(!c->assertedToTheTheory());
@@ -504,12 +504,12 @@ void LinearEqualityModule::propagateBasicFromRow(Constraint c){
ArithVar basic = c->getVariable();
RowIndex ridx = d_tableau.basicToRowIndex(basic);
- vector<Constraint> bounds;
+ ConstraintCPVec bounds;
propagateRow(bounds, ridx, upperBound, c);
c->impliedBy(bounds);
}
-void LinearEqualityModule::propagateRow(vector<Constraint>& into, RowIndex ridx, bool rowUp, Constraint c){
+void LinearEqualityModule::propagateRow(ConstraintCPVec& into, RowIndex ridx, bool rowUp, ConstraintP c){
Assert(!c->assertedToTheTheory());
Assert(c->canBePropagated());
Assert(!c->hasProof());
@@ -529,7 +529,7 @@ void LinearEqualityModule::propagateRow(vector<Constraint>& into, RowIndex ridx,
int sgn = a_ij.sgn();
Assert(sgn != 0);
bool selectUb = rowUp ? (sgn > 0) : (sgn < 0);
- Constraint bound = selectUb
+ ConstraintCP bound = selectUb
? d_variables.getUpperBoundConstraint(nonbasic)
: d_variables.getLowerBoundConstraint(nonbasic);
@@ -541,12 +541,12 @@ void LinearEqualityModule::propagateRow(vector<Constraint>& into, RowIndex ridx,
<< v << ") done" << endl;
}
-Constraint LinearEqualityModule::weakestExplanation(bool aboveUpper, DeltaRational& surplus, ArithVar v, const Rational& coeff, bool& anyWeakening, ArithVar basic) const {
+ConstraintP LinearEqualityModule::weakestExplanation(bool aboveUpper, DeltaRational& surplus, ArithVar v, const Rational& coeff, bool& anyWeakening, ArithVar basic) const {
int sgn = coeff.sgn();
bool ub = aboveUpper?(sgn < 0) : (sgn > 0);
- Constraint c = ub ?
+ ConstraintP c = ub ?
d_variables.getUpperBoundConstraint(v) :
d_variables.getLowerBoundConstraint(v);
@@ -556,7 +556,7 @@ Constraint LinearEqualityModule::weakestExplanation(bool aboveUpper, DeltaRation
weakened = false;
- Constraint weaker = ub?
+ ConstraintP weaker = ub?
c->getStrictlyWeakerUpperBound(true, true):
c->getStrictlyWeakerLowerBound(true, true);
@@ -591,7 +591,7 @@ Constraint LinearEqualityModule::weakestExplanation(bool aboveUpper, DeltaRation
return c;
}
-Node LinearEqualityModule::minimallyWeakConflict(bool aboveUpper, ArithVar basicVar) const {
+void LinearEqualityModule::minimallyWeakConflict(bool aboveUpper, ArithVar basicVar, RaiseConflict& rc) const {
TimerStat::CodeTimer codeTimer(d_statistics.d_weakenTime);
const DeltaRational& assignment = d_variables.getAssignment(basicVar);
@@ -606,29 +606,25 @@ Node LinearEqualityModule::minimallyWeakConflict(bool aboveUpper, ArithVar basic
surplus = d_variables.getLowerBound(basicVar) - assignment;
}
- NodeBuilder<> conflict(kind::AND);
bool anyWeakenings = false;
for(Tableau::RowIterator i = d_tableau.basicRowIterator(basicVar); !i.atEnd(); ++i){
const Tableau::Entry& entry = *i;
ArithVar v = entry.getColVar();
const Rational& coeff = entry.getCoefficient();
bool weakening = false;
- Constraint c = weakestExplanation(aboveUpper, surplus, v, coeff, weakening, basicVar);
+ ConstraintP c = weakestExplanation(aboveUpper, surplus, v, coeff, weakening, basicVar);
Debug("weak") << "weak : " << weakening << " "
<< c->assertedToTheTheory() << " "
<< d_variables.getAssignment(v) << " "
- << c << endl
- << c->explainForConflict() << endl;
+ << c << endl;
anyWeakenings = anyWeakenings || weakening;
- Debug("weak") << "weak : " << c->explainForConflict() << endl;
- c->explainForConflict(conflict);
+ rc.addConstraint(c);
}
++d_statistics.d_weakeningAttempts;
if(anyWeakenings){
++d_statistics.d_weakeningSuccesses;
}
- return conflict;
}
ArithVar LinearEqualityModule::minVarOrder(ArithVar x, ArithVar y) const {
@@ -787,7 +783,7 @@ bool LinearEqualityModule::basicsAtBounds(const UpdateInfo& u) const {
int coeffSgn = u.getCoefficient().sgn();
int nbdir = u.nonbasicDirection();
- Constraint c = u.limiting();
+ ConstraintP c = u.limiting();
int toUB = (c->getType() == UpperBound ||
c->getType() == Equality) ? 1 : 0;
int toLB = (c->getType() == LowerBound ||
@@ -886,7 +882,7 @@ bool LinearEqualityModule::accumulateBorder(const Tableau::Entry& entry, bool ub
Assert(basicIsTracked(currBasic));
- Constraint bound = ub ?
+ ConstraintP bound = ub ?
d_variables.getUpperBoundConstraint(currBasic):
d_variables.getLowerBoundConstraint(currBasic);
@@ -1003,7 +999,7 @@ UpdateInfo LinearEqualityModule::mkConflictUpdate(const Tableau::Entry& entry, b
ArithVar currBasic = d_tableau.rowIndexToBasic(entry.getRowIndex());
ArithVar nb = entry.getColVar();
- Constraint bound = ub ?
+ ConstraintP bound = ub ?
d_variables.getUpperBoundConstraint(currBasic):
d_variables.getLowerBoundConstraint(currBasic);
@@ -1031,14 +1027,14 @@ UpdateInfo LinearEqualityModule::speculativeUpdate(ArithVar nb, const Rational&
Debug("speculativeUpdate") << "focusCoeff " << focusCoeff << endl;
if(d_variables.hasUpperBound(nb)){
- Constraint ub = d_variables.getUpperBoundConstraint(nb);
+ ConstraintP ub = d_variables.getUpperBoundConstraint(nb);
d_upperBoundDifference = ub->getValue() - d_variables.getAssignment(nb);
Border border(ub, d_upperBoundDifference, false, NULL, true);
Debug("handleBorders") << "push back increasing " << border << endl;
d_increasing.push_back(border);
}
if(d_variables.hasLowerBound(nb)){
- Constraint lb = d_variables.getLowerBoundConstraint(nb);
+ ConstraintP lb = d_variables.getLowerBoundConstraint(nb);
d_lowerBoundDifference = lb->getValue() - d_variables.getAssignment(nb);
Border border(lb, d_lowerBoundDifference, false, NULL, false);
Debug("handleBorders") << "push back decreasing " << border << endl;
diff --git a/src/theory/arith/linear_equality.h b/src/theory/arith/linear_equality.h
index 293a0ddad..804ad29ac 100644
--- a/src/theory/arith/linear_equality.h
+++ b/src/theory/arith/linear_equality.h
@@ -46,7 +46,7 @@ namespace arith {
struct Border{
// The constraint for the border
- Constraint d_bound;
+ ConstraintP d_bound;
// The change to the nonbasic to reach the border
DeltaRational d_diff;
@@ -65,11 +65,11 @@ struct Border{
d_bound(NullConstraint) // ignore the other values
{}
- Border(Constraint l, const DeltaRational& diff, bool areFixing, const Tableau::Entry* en, bool ub):
+ Border(ConstraintP l, const DeltaRational& diff, bool areFixing, const Tableau::Entry* en, bool ub):
d_bound(l), d_diff(diff), d_areFixing(areFixing), d_entry(en), d_upperbound(ub)
{}
- Border(Constraint l, const DeltaRational& diff, bool areFixing, bool ub):
+ Border(ConstraintP l, const DeltaRational& diff, bool areFixing, bool ub):
d_bound(l), d_diff(diff), d_areFixing(areFixing), d_entry(NULL), d_upperbound(ub)
{}
bool operator<(const Border& other) const{
@@ -414,13 +414,13 @@ public:
* The constraint on a basic variable b is implied by the constraints
* on its row. This is a wrapper for propagateRow().
*/
- void propagateBasicFromRow(Constraint c);
+ void propagateBasicFromRow(ConstraintP c);
/**
* Exports either the explanation of an upperbound or a lower bound
* of the basic variable basic, using the non-basic variables in the row.
*/
- void propagateRow(std::vector<Constraint>& into, RowIndex ridx, bool rowUp, Constraint c);
+ void propagateRow(ConstraintCPVec& into, RowIndex ridx, bool rowUp, ConstraintP c);
/**
* Computes the value of a basic variable using the assignments
@@ -592,26 +592,26 @@ private:
* with the weakest possible constraint that is consistent with the surplus
* surplus.
*/
- Constraint weakestExplanation(bool aboveUpper, DeltaRational& surplus, ArithVar v,
+ ConstraintP weakestExplanation(bool aboveUpper, DeltaRational& surplus, ArithVar v,
const Rational& coeff, bool& anyWeakening, ArithVar basic) const;
public:
/**
* Constructs a minimally weak conflict for the basic variable basicVar.
*/
- Node minimallyWeakConflict(bool aboveUpper, ArithVar basicVar) const;
+ void minimallyWeakConflict(bool aboveUpper, ArithVar basicVar, RaiseConflict& rc) const;
/**
* Given a non-basic variable that is know to have a conflict on it,
* construct and return a conflict.
* Follows section 4.2 in the CAV06 paper.
*/
- inline Node generateConflictAboveUpperBound(ArithVar conflictVar) const {
- return minimallyWeakConflict(true, conflictVar);
+ inline void generateConflictAboveUpperBound(ArithVar conflictVar, RaiseConflict& rc) const {
+ minimallyWeakConflict(true, conflictVar, rc);
}
- inline Node generateConflictBelowLowerBound(ArithVar conflictVar) const {
- return minimallyWeakConflict(false, conflictVar);
+ inline void generateConflictBelowLowerBound(ArithVar conflictVar, RaiseConflict& rc) const {
+ minimallyWeakConflict(false, conflictVar, rc);
}
/**
diff --git a/src/theory/arith/matrix.h b/src/theory/arith/matrix.h
index d93b6986e..084281c04 100644
--- a/src/theory/arith/matrix.h
+++ b/src/theory/arith/matrix.h
@@ -362,16 +362,18 @@ public:
template <class T>
class Matrix {
-protected:
-
+public:
typedef MatrixEntry<T> Entry;
+protected:
typedef CVC4::theory::arith::RowVector<T> RowVectorT;
- typedef typename RowVectorT::const_iterator RowIterator;
-
typedef CVC4::theory::arith::ColumnVector<T> ColumnVectorT;
+
+public:
+ typedef typename RowVectorT::const_iterator RowIterator;
typedef typename ColumnVectorT::const_iterator ColIterator;
+protected:
// RowTable : RowID |-> RowVector
typedef std::vector< RowVectorT > RowTable;
RowTable d_rows;
@@ -532,6 +534,12 @@ public:
d_columns.push_back(ColumnVector<T>(&d_entries));
}
+ void increaseSizeTo(size_t s){
+ while(getNumColumns() < s){
+ increaseSize();
+ }
+ }
+
const RowVector<T>& getRow(RowIndex r) const {
Assert(r < d_rows.size());
return d_rows[r];
@@ -600,7 +608,33 @@ public:
d_mergeBuffer.purge();
}
- /** to += mult * buffer. */
+ /* to *= mult */
+ void multiplyRowByConstant(RowIndex to, const T& mult){
+ RowIterator i = getRow(to).begin();
+ RowIterator i_end = getRow(to).end();
+ for( ; i != i_end; ++i){
+ EntryID id = i.getID();
+ Entry& entry = d_entries.get(id);
+ T& coeff = entry.getCoefficient();
+ coeff *= mult;
+ }
+ }
+
+ /** to += mult * from.
+ * Use the more efficient rowPlusBufferTimesConstant() for
+ * repeated use.
+ */
+ void rowPlusRowTimesConstant(RowIndex to, RowIndex from, const T& mult){
+ Assert(to != from);
+ loadRowIntoBuffer(from);
+ rowPlusBufferTimesConstant(to, mult);
+ clearBuffer();
+ }
+
+ /** to += mult * buffer.
+ * Invalidates coefficients on the row.
+ * (mult should never be a direct copy of a coefficient!)
+ */
void rowPlusBufferTimesConstant(RowIndex to, const T& mult){
Assert(d_rowInMergeBuffer != ROW_INDEX_SENTINEL);
Assert(to != ROW_INDEX_SENTINEL);
diff --git a/src/theory/arith/normal_form.cpp b/src/theory/arith/normal_form.cpp
index 4edc55cca..3adb72f37 100644
--- a/src/theory/arith/normal_form.cpp
+++ b/src/theory/arith/normal_form.cpp
@@ -18,6 +18,7 @@
#include "theory/arith/normal_form.h"
#include "theory/arith/arith_utilities.h"
#include <list>
+#include "theory/theory.h"
using namespace std;
@@ -25,6 +26,47 @@ namespace CVC4 {
namespace theory {
namespace arith {
+Constant Constant::mkConstant(const Rational& rat) {
+ return Constant(mkRationalNode(rat));
+}
+
+size_t Variable::getComplexity() const{
+ return 1u;
+}
+
+size_t VarList::getComplexity() const{
+ if(empty()){
+ return 1;
+ }else if(singleton()){
+ return 1;
+ }else{
+ return size() + 1;
+ }
+}
+
+size_t Monomial::getComplexity() const{
+ return getConstant().getComplexity() + getVarList().getComplexity();
+}
+
+size_t Polynomial::getComplexity() const{
+ size_t cmp = 0;
+ iterator i = begin(), e = end();
+ for(; i != e; ++i){
+ Monomial m = *i;
+ cmp += m.getComplexity();
+ }
+ return cmp;
+}
+
+size_t Constant::getComplexity() const{
+ return getValue().complexity();
+}
+
+bool Variable::isLeafMember(Node n){
+ return (!isRelationOperator(n.getKind())) &&
+ (Theory::isLeafOf(n, theory::THEORY_ARITH));
+}
+
bool Variable::isDivMember(Node n){
switch(n.getKind()){
case kind::DIVISION:
@@ -39,6 +81,8 @@ bool Variable::isDivMember(Node n){
}
}
+
+
bool VarList::isSorted(iterator start, iterator end) {
return __gnu_cxx::is_sorted(start, end);
}
@@ -161,27 +205,76 @@ Monomial Monomial::operator*(const Monomial& mono) const {
return Monomial::mkMonomial(newConstant, newVL);
}
-vector<Monomial> Monomial::sumLikeTerms(const std::vector<Monomial> & monos) {
+// vector<Monomial> Monomial::sumLikeTerms(const std::vector<Monomial> & monos) {
+// Assert(isSorted(monos));
+// vector<Monomial> outMonomials;
+// typedef vector<Monomial>::const_iterator iterator;
+// for(iterator rangeIter = monos.begin(), end=monos.end(); rangeIter != end;) {
+// Rational constant = (*rangeIter).getConstant().getValue();
+// VarList varList = (*rangeIter).getVarList();
+// ++rangeIter;
+// while(rangeIter != end && varList == (*rangeIter).getVarList()) {
+// constant += (*rangeIter).getConstant().getValue();
+// ++rangeIter;
+// }
+// if(constant != 0) {
+// Constant asConstant = Constant::mkConstant(constant);
+// Monomial nonZero = Monomial::mkMonomial(asConstant, varList);
+// outMonomials.push_back(nonZero);
+// }
+// }
+
+// Assert(isStrictlySorted(outMonomials));
+// return outMonomials;
+// }
+
+void Monomial::sort(std::vector<Monomial>& m){
+ if(!isSorted(m)){
+ std::sort(m.begin(), m.end());
+ }
+}
+
+void Monomial::combineAdjacentMonomials(std::vector<Monomial>& monos) {
Assert(isSorted(monos));
- vector<Monomial> outMonomials;
- typedef vector<Monomial>::const_iterator iterator;
- for(iterator rangeIter = monos.begin(), end=monos.end(); rangeIter != end;) {
- Rational constant = (*rangeIter).getConstant().getValue();
- VarList varList = (*rangeIter).getVarList();
- ++rangeIter;
- while(rangeIter != end && varList == (*rangeIter).getVarList()) {
- constant += (*rangeIter).getConstant().getValue();
- ++rangeIter;
+ size_t writePos, readPos, N;
+ for(writePos = 0, readPos = 0, N = monos.size(); readPos < N;){
+ Monomial& atRead = monos[readPos];
+ const VarList& varList = atRead.getVarList();
+
+ size_t rangeEnd = readPos+1;
+ for(; rangeEnd < N; rangeEnd++){
+ if(!(varList == monos[rangeEnd].getVarList())){ break; }
}
- if(constant != 0) {
- Constant asConstant = Constant::mkConstant(constant);
- Monomial nonZero = Monomial::mkMonomial(asConstant, varList);
- outMonomials.push_back(nonZero);
+ // monos[i] for i in [readPos, rangeEnd) has the same var list
+ if(readPos+1 == rangeEnd){ // no addition needed
+ if(!atRead.getConstant().isZero()){
+ Monomial cpy = atRead; // being paranoid here
+ monos[writePos] = cpy;
+ writePos++;
+ }
+ }else{
+ Rational constant(monos[readPos].getConstant().getValue());
+ for(size_t i=readPos+1; i < rangeEnd; ++i){
+ constant += monos[i].getConstant().getValue();
+ }
+ if(!constant.isZero()){
+ Constant asConstant = Constant::mkConstant(constant);
+ Monomial nonZero = Monomial::mkMonomial(asConstant, varList);
+ monos[writePos] = nonZero;
+ writePos++;
+ }
}
+ Assert(rangeEnd>readPos);
+ readPos = rangeEnd;
}
-
- Assert(isStrictlySorted(outMonomials));
- return outMonomials;
+ if(writePos > 0 ){
+ Monomial cp = monos[0];
+ Assert(writePos <= N);
+ monos.resize(writePos, cp);
+ }else{
+ monos.clear();
+ }
+ Assert(isStrictlySorted(monos));
}
void Monomial::print() const {
@@ -199,12 +292,56 @@ Polynomial Polynomial::operator+(const Polynomial& vl) const {
std::vector<Monomial> sortedMonos;
merge_ranges(begin(), end(), vl.begin(), vl.end(), sortedMonos);
- std::vector<Monomial> combined = Monomial::sumLikeTerms(sortedMonos);
+ Monomial::combineAdjacentMonomials(sortedMonos);
+ //std::vector<Monomial> combined = Monomial::sumLikeTerms(sortedMonos);
- Polynomial result = mkPolynomial(combined);
+ Polynomial result = mkPolynomial(sortedMonos);
return result;
}
+
+Polynomial Polynomial::sumPolynomials(const std::vector<Polynomial>& ps){
+ if(ps.empty()){
+ return mkZero();
+ }else if(ps.size() <= 4){
+ // if there are few enough polynomials just add them
+ Polynomial p = ps[0];
+ for(size_t i = 1; i < ps.size(); ++i){
+ p = p + ps[i];
+ }
+ return p;
+ }else{
+ // general case
+ std::map<Node, Rational> coeffs;
+ for(size_t i = 0, N = ps.size(); i<N; ++i){
+ const Polynomial& p = ps[i];
+ for(iterator pi = p.begin(), pend = p.end(); pi != pend; ++pi) {
+ Monomial m = *pi;
+ coeffs[m.getVarList().getNode()] += m.getConstant().getValue();
+ }
+ }
+ std::vector<Monomial> monos;
+ std::map<Node, Rational>::const_iterator ci = coeffs.begin(), cend = coeffs.end();
+ for(; ci != cend; ++ci){
+ if(!(*ci).second.isZero()){
+ Constant c = Constant::mkConstant((*ci).second);
+ Node n = (*ci).first;
+ VarList vl = VarList::parseVarList(n);
+ if(vl.empty()){
+ monos.push_back(Monomial(c));
+ }else{
+ monos.push_back(Monomial(c, vl));
+ }
+ }
+ }
+ Monomial::sort(monos);
+ Monomial::combineAdjacentMonomials(monos);
+
+ Polynomial result = mkPolynomial(monos);
+ return result;
+ }
+}
+
Polynomial Polynomial::operator-(const Polynomial& vl) const {
Constant negOne = Constant::mkConstant(Rational(-1));
@@ -257,7 +394,7 @@ Polynomial Polynomial::operator*(const Monomial& mono) const {
// Suppose this = (+ x y), mono = x, (* x y).getId() < (* x x).getId()
// newMonos = <(* x x), (* x y)> after this loop.
// This is not sorted according to the current VarList order.
- std::sort(newMonos.begin(), newMonos.end());
+ Monomial::sort(newMonos);
return Polynomial::mkPolynomial(newMonos);
}
}
@@ -281,7 +418,7 @@ Monomial Polynomial::selectAbsMinimum() const {
++iter;
for(; iter != end(); ++iter){
Monomial curr = *iter;
- if(curr.absLessThan(min)){
+ if(curr.absCmp(min) < 0){
min = curr;
}
}
@@ -315,10 +452,16 @@ Integer Polynomial::numeratorGCD() const {
Assert(i!=e);
Integer d = (*i).getConstant().getValue().getNumerator().abs();
+ if(d.isOne()){
+ return d;
+ }
++i;
for(; i!=e; ++i){
Integer c = (*i).getConstant().getValue().getNumerator();
d = d.gcd(c);
+ if(d.isOne()){
+ return d;
+ }
}
return d;
}
@@ -615,6 +758,22 @@ bool Comparison::rightIsConstant() const {
}
}
+size_t Comparison::getComplexity() const{
+ switch(comparisonKind()){
+ case kind::CONST_BOOLEAN: return 1;
+ case kind::LT:
+ case kind::LEQ:
+ case kind::DISTINCT:
+ case kind::EQUAL:
+ case kind::GT:
+ case kind::GEQ:
+ return getLeft().getComplexity() + getRight().getComplexity();
+ default:
+ Unhandled(comparisonKind());
+ return -1;
+ }
+}
+
Polynomial Comparison::getLeft() const {
TNode left;
Kind k = comparisonKind();
@@ -804,10 +963,10 @@ bool Comparison::isNormalEqualityOrDisequality() const {
}else{
Monomial absMinRight = varRight.selectAbsMinimum();
Debug("nf::tmp") << mleft.getNode() << " " << absMinRight.getNode() << endl;
- if( mleft.absLessThan(absMinRight) ){
+ if( mleft.absCmp(absMinRight) < 0){
return true;
}else{
- return (!absMinRight.absLessThan(mleft)) && mleft < absMinRight;
+ return (!(absMinRight.absCmp(mleft)< 0)) && mleft < absMinRight;
}
}
}
diff --git a/src/theory/arith/normal_form.h b/src/theory/arith/normal_form.h
index cd5f047b5..f098d8b54 100644
--- a/src/theory/arith/normal_form.h
+++ b/src/theory/arith/normal_form.h
@@ -23,8 +23,8 @@
#include "expr/node.h"
#include "expr/node_self_iterator.h"
#include "util/rational.h"
-#include "theory/theory.h"
-#include "theory/arith/arith_utilities.h"
+#include "theory/arith/delta_rational.h"
+//#include "theory/arith/arith_utilities.h"
#include <list>
#include <algorithm>
@@ -247,11 +247,11 @@ public:
// by a variable.
return true;
default:
- return (!isRelationOperator(k)) &&
- (Theory::isLeafOf(n, theory::THEORY_ARITH));
+ return isLeafMember(n);
}
}
+ static bool isLeafMember(Node n);
static bool isDivMember(Node n);
bool isDivLike() const{
return isDivMember(getNode());
@@ -286,6 +286,7 @@ public:
bool operator==(const Variable& v) const { return getNode() == v.getNode();}
+ size_t getComplexity() const;
};/* class Variable */
@@ -306,9 +307,7 @@ public:
return Constant(n);
}
- static Constant mkConstant(const Rational& rat) {
- return Constant(mkRationalNode(rat));
- }
+ static Constant mkConstant(const Rational& rat);
static Constant mkZero() {
return mkConstant(Rational(0));
@@ -322,6 +321,7 @@ public:
return getNode().getConst<Rational>();
}
+ static int absCmp(const Constant& a, const Constant& b);
bool isIntegral() const { return getValue().isIntegral(); }
int sgn() const { return getValue().sgn(); }
@@ -373,6 +373,8 @@ public:
return getValue().getNumerator().length();
}
+ size_t getComplexity() const;
+
};/* class Constant */
@@ -563,6 +565,7 @@ public:
}
return true;
}
+ size_t getComplexity() const;
private:
bool isSorted(iterator start, iterator end);
@@ -687,6 +690,9 @@ public:
return isSorted(m) && std::adjacent_find(m.begin(),m.end()) == m.end();
}
+ static void sort(std::vector<Monomial>& m);
+ static void combineAdjacentMonomials(std::vector<Monomial>& m);
+
/**
* The variable product
*/
@@ -717,11 +723,14 @@ public:
* Given a sorted list of monomials, this function transforms this
* into a strictly sorted list of monomials that does not contain zero.
*/
- static std::vector<Monomial> sumLikeTerms(const std::vector<Monomial>& monos);
+ //static std::vector<Monomial> sumLikeTerms(const std::vector<Monomial>& monos);
- bool absLessThan(const Monomial& other) const{
- return getConstant().abs() < other.getConstant().abs();
+ int absCmp(const Monomial& other) const{
+ return getConstant().getValue().absCmp(other.getConstant().getValue());
}
+ // bool absLessThan(const Monomial& other) const{
+ // return getConstant().abs() < other.getConstant().abs();
+ // }
uint32_t coefficientLength() const{
return getConstant().length();
@@ -730,6 +739,7 @@ public:
void print() const;
static void printList(const std::vector<Monomial>& list);
+ size_t getComplexity() const;
};/* class Monomial */
class SumPair;
@@ -938,9 +948,12 @@ public:
return true;
}
+ static Polynomial sumPolynomials(const std::vector<Polynomial>& polynomials);
+
/** Returns true if the polynomial contains a non-linear monomial.*/
bool isNonlinear() const;
+
/**
* Selects a minimal monomial in the polynomial by the absolute value of
* the coefficient.
@@ -1058,6 +1071,8 @@ public:
return getHead().getVarList();
}
+ size_t getComplexity() const;
+
friend class SumPair;
friend class Comparison;
@@ -1173,6 +1188,10 @@ public:
return getConstant().isZero() && isConstant();
}
+ uint32_t size() const{
+ return getPolynomial().size();
+ }
+
bool isNonlinear() const{
return getPolynomial().isNonlinear();
}
@@ -1368,6 +1387,8 @@ public:
return parse.isNormalForm();
}
+ size_t getComplexity() const;
+
SumPair toSumPair() const;
Polynomial normalizedVariablePart() const;
diff --git a/src/theory/arith/options b/src/theory/arith/options
index 3fc08e18e..cf35265d6 100644
--- a/src/theory/arith/options
+++ b/src/theory/arith/options
@@ -85,8 +85,11 @@ option restrictedPivots --restrict-pivots bool :default true :read-write
option collectPivots --collect-pivot-stats bool :default false :read-write
collect the pivot history
-option fancyFinal --fancy-final bool :default false :read-write
- tuning how final check works for really hard problems
+option useApprox --use-approx bool :default false :read-write
+ attempt to use an approximate solver
+
+option maxApproxDepth --approx-branch-depth int16_t :default 200 :read-write
+ maximum branch depth the approximate solver is allowed to take
option exportDioDecompositions --dio-decomps bool :default false :read-write
let skolem variables for integer divisibility constraints leak from the dio solver
@@ -103,4 +106,46 @@ option soiQuickExplain --soi-qe bool :default false :read-write
option rewriteDivk rewrite-divk --rewrite-divk bool :default false :read-write
rewrite division and mod when by a constant into linear terms
+option trySolveIntStandardEffort --se-solve-int bool :default false
+ attempt to use the approximate solve integer method on standard effort
+
+option replayFailureLemma --lemmas-on-replay-failure bool :default false
+ attempt to use external lemmas if approximate solve integer failed
+
+option dioSolverTurns --dio-turns int :default 10
+ turns in a row dio solver cutting gets
+
+option rrTurns --rr-turns int :default 3
+ round robin turn
+
+option dioRepeat --dio-repeat bool :default false
+ handle dio solver constraints in mass or one at a time
+
+option replayEarlyCloseDepths --replay-early-close-depth int :default 1
+ multiples of the depths to try to close the approx log eagerly
+
+option replayFailurePenalty --replay-failure-penalty int :default 100
+ number of solve integer attempts to skips after a numeric failure
+
+option replayNumericFailurePenalty --replay-num-err-penalty int :default 4194304
+ number of solve integer attempts to skips after a numeric failure
+
+option replayRejectCutSize --replay-reject-cut unsigned :default 25500
+ maximum complexity of any coefficient while replaying cuts
+
+option lemmaRejectCutSize --replay-lemma-reject-cut unsigned :default 25500
+ maximum complexity of any coefficient while outputing replaying cut lemmas
+
+option soiApproxMajorFailure --replay-soi-major-threshold double :default .01
+ threshold for a major tolerance failure by the approximate solver
+
+option soiApproxMajorFailurePen --replay-soi-major-threshold-pen int :default 50
+ threshold for a major tolerance failure by the approximate solver
+
+option soiApproxMinorFailure --replay-soi-minor-threshold double :default .0001
+ threshold for a minor tolerance failure by the approximate solver
+
+option soiApproxMinorFailurePen --replay-soi-minor-threshold-pen int :default 10
+ threshold for a minor tolerance failure by the approximate solver
+
endmodule
diff --git a/src/theory/arith/partial_model.cpp b/src/theory/arith/partial_model.cpp
index 3fae3751c..8f08de36c 100644
--- a/src/theory/arith/partial_model.cpp
+++ b/src/theory/arith/partial_model.cpp
@@ -33,7 +33,6 @@ ArithVariables::ArithVariables(context::Context* c, DeltaComputeCallback deltaCo
d_numberOfVariables(0),
d_pool(),
d_released(),
- d_releasedIterator(d_released.begin()),
d_nodeToArithVarMap(),
d_boundsQueue(),
d_enqueueingBoundCounts(true),
@@ -44,6 +43,87 @@ ArithVariables::ArithVariables(context::Context* c, DeltaComputeCallback deltaCo
d_deltaComputingFunc(deltaComputingFunc)
{ }
+ArithVar ArithVariables::getNumberOfVariables() const {
+ return d_numberOfVariables;
+}
+
+
+bool ArithVariables::hasArithVar(TNode x) const {
+ return d_nodeToArithVarMap.find(x) != d_nodeToArithVarMap.end();
+}
+
+bool ArithVariables::hasNode(ArithVar a) const {
+ return d_vars.isKey(a);
+}
+
+ArithVar ArithVariables::asArithVar(TNode x) const{
+ Assert(hasArithVar(x));
+ Assert((d_nodeToArithVarMap.find(x))->second <= ARITHVAR_SENTINEL);
+ return (d_nodeToArithVarMap.find(x))->second;
+}
+
+Node ArithVariables::asNode(ArithVar a) const{
+ Assert(hasNode(a));
+ return d_vars[a].d_node;
+}
+
+ArithVariables::var_iterator::var_iterator()
+ : d_vars(NULL)
+ , d_wrapped()
+{}
+
+ArithVariables::var_iterator::var_iterator(const VarInfoVec* vars, VarInfoVec::const_iterator ci)
+ : d_vars(vars), d_wrapped(ci)
+{
+ nextInitialized();
+}
+
+ArithVariables::var_iterator& ArithVariables::var_iterator::operator++(){
+ ++d_wrapped;
+ nextInitialized();
+ return *this;
+}
+bool ArithVariables::var_iterator::operator==(const ArithVariables::var_iterator& other) const{
+ return d_wrapped == other.d_wrapped;
+}
+bool ArithVariables::var_iterator::operator!=(const ArithVariables::var_iterator& other) const{
+ return d_wrapped != other.d_wrapped;
+}
+ArithVar ArithVariables::var_iterator::operator*() const{
+ return *d_wrapped;
+}
+
+void ArithVariables::var_iterator::nextInitialized(){
+ VarInfoVec::const_iterator end = d_vars->end();
+ while(d_wrapped != end &&
+ !((*d_vars)[*d_wrapped].initialized())){
+ ++d_wrapped;
+ }
+}
+
+ArithVariables::var_iterator ArithVariables::var_begin() const {
+ return var_iterator(&d_vars, d_vars.begin());
+}
+
+ArithVariables::var_iterator ArithVariables::var_end() const {
+ return var_iterator(&d_vars, d_vars.end());
+}
+bool ArithVariables::isInteger(ArithVar x) const {
+ return d_vars[x].d_type >= ATInteger;
+}
+
+/** Is the assignment to x integral? */
+bool ArithVariables::integralAssignment(ArithVar x) const {
+ return getAssignment(x).isIntegral();
+}
+bool ArithVariables::isAuxiliary(ArithVar x) const {
+ return d_vars[x].d_auxiliary;
+}
+
+bool ArithVariables::isIntegerInput(ArithVar x) const {
+ return isInteger(x) && !isAuxiliary(x);
+}
+
ArithVariables::VarInfo::VarInfo()
: d_var(ARITHVAR_SENTINEL),
d_assignment(0),
@@ -53,14 +133,14 @@ ArithVariables::VarInfo::VarInfo()
d_cmpAssignmentUB(-1),
d_pushCount(0),
d_node(Node::null()),
- d_slack(false)
+ d_auxiliary(false)
{ }
bool ArithVariables::VarInfo::initialized() const {
return d_var != ARITHVAR_SENTINEL;
}
-void ArithVariables::VarInfo::initialize(ArithVar v, Node n, bool slack){
+void ArithVariables::VarInfo::initialize(ArithVar v, Node n, bool aux){
Assert(!initialized());
Assert(d_lb == NullConstraint);
Assert(d_ub == NullConstraint);
@@ -68,9 +148,9 @@ void ArithVariables::VarInfo::initialize(ArithVar v, Node n, bool slack){
Assert(d_cmpAssignmentUB < 0);
d_var = v;
d_node = n;
- d_slack = slack;
+ d_auxiliary = aux;
- if(d_slack){
+ if(d_auxiliary){
//The type computation is not quite accurate for Rationals that are
//integral.
//We'll use the isIntegral check from the polynomial package instead.
@@ -112,6 +192,10 @@ bool ArithVariables::VarInfo::setAssignment(const DeltaRational& a, BoundsInfo&
void ArithVariables::releaseArithVar(ArithVar v){
VarInfo& vi = d_vars.get(v);
+
+ size_t removed CVC4_UNUSED = d_nodeToArithVarMap.erase(vi.d_node);
+ Assert(removed == 1);
+
vi.uninitialize();
if(d_safeAssignment.isKey(v)){
@@ -124,7 +208,7 @@ void ArithVariables::releaseArithVar(ArithVar v){
}
}
-bool ArithVariables::VarInfo::setUpperBound(Constraint ub, BoundsInfo& prev){
+bool ArithVariables::VarInfo::setUpperBound(ConstraintP ub, BoundsInfo& prev){
Assert(initialized());
bool wasNull = d_ub == NullConstraint;
bool isNull = ub == NullConstraint;
@@ -140,7 +224,7 @@ bool ArithVariables::VarInfo::setUpperBound(Constraint ub, BoundsInfo& prev){
return ubChanged;
}
-bool ArithVariables::VarInfo::setLowerBound(Constraint lb, BoundsInfo& prev){
+bool ArithVariables::VarInfo::setLowerBound(ConstraintP lb, BoundsInfo& prev){
Assert(initialized());
bool wasNull = d_lb == NullConstraint;
bool isNull = lb == NullConstraint;
@@ -177,23 +261,22 @@ bool ArithVariables::VarInfo::canBeReclaimed() const{
return d_pushCount == 0;
}
+bool ArithVariables::canBeReleased(ArithVar v) const{
+ return d_vars[v].canBeReclaimed();
+}
+
void ArithVariables::attemptToReclaimReleased(){
- std::list<ArithVar>::iterator i_end = d_released.end();
- for(int iter = 0; iter < 20 && d_releasedIterator != i_end; ++d_releasedIterator){
- ArithVar v = *d_releasedIterator;
- VarInfo& vi = d_vars.get(v);
- if(vi.canBeReclaimed()){
+ size_t readPos = 0, writePos = 0, N = d_released.size();
+ for(; readPos < N; ++readPos){
+ ArithVar v = d_released[readPos];
+ if(canBeReleased(v)){
d_pool.push_back(v);
- std::list<ArithVar>::iterator curr = d_releasedIterator;
- ++d_releasedIterator;
- d_released.erase(curr);
}else{
- ++d_releasedIterator;
+ d_released[writePos] = v;
+ writePos++;
}
}
- if(d_releasedIterator == i_end){
- d_releasedIterator = d_released.begin();
- }
+ d_released.resize(writePos);
}
ArithVar ArithVariables::allocateVariable(){
@@ -232,6 +315,21 @@ bool ArithVariables::boundsAreEqual(ArithVar x) const{
}
}
+
+std::pair<ConstraintP, ConstraintP> ArithVariables::explainEqualBounds(ArithVar x) const{
+ Assert(boundsAreEqual(x));
+
+ ConstraintP lb = getLowerBoundConstraint(x);
+ ConstraintP ub = getUpperBoundConstraint(x);
+ if(lb->isEquality()){
+ return make_pair(lb, NullConstraint);
+ }else if(ub->isEquality()){
+ return make_pair(ub, NullConstraint);
+ }else{
+ return make_pair(lb, ub);
+ }
+}
+
void ArithVariables::setAssignment(ArithVar x, const DeltaRational& r){
Debug("partial_model") << "pm: updating the assignment to" << x
<< " now " << r <<endl;
@@ -266,15 +364,15 @@ void ArithVariables::setAssignment(ArithVar x, const DeltaRational& safe, const
}
}
-void ArithVariables::initialize(ArithVar x, Node n, bool slack){
+void ArithVariables::initialize(ArithVar x, Node n, bool aux){
VarInfo& vi = d_vars.get(x);
- vi.initialize(x, n, slack);
+ vi.initialize(x, n, aux);
d_nodeToArithVarMap[n] = x;
}
-ArithVar ArithVariables::allocate(Node n, bool slack){
+ArithVar ArithVariables::allocate(Node n, bool aux){
ArithVar v = allocateVariable();
- initialize(v, n, slack);
+ initialize(v, n, aux);
return v;
}
@@ -333,7 +431,7 @@ const DeltaRational& ArithVariables::getAssignment(ArithVar x) const{
}
-void ArithVariables::setLowerBoundConstraint(Constraint c){
+void ArithVariables::setLowerBoundConstraint(ConstraintP c){
AssertArgument(c != NullConstraint, "Cannot set a lower bound to NullConstraint.");
AssertArgument(c->isEquality() || c->isLowerBound(),
"Constraint type must be set to an equality or UpperBound.");
@@ -351,7 +449,7 @@ void ArithVariables::setLowerBoundConstraint(Constraint c){
}
}
-void ArithVariables::setUpperBoundConstraint(Constraint c){
+void ArithVariables::setUpperBoundConstraint(ConstraintP c){
AssertArgument(c != NullConstraint, "Cannot set a upper bound to NullConstraint.");
AssertArgument(c->isEquality() || c->isUpperBound(),
"Constraint type must be set to an equality or UpperBound.");
@@ -450,6 +548,14 @@ void ArithVariables::commitAssignmentChanges(){
clearSafeAssignments(false);
}
+bool ArithVariables::lowerBoundIsZero(ArithVar x){
+ return hasLowerBound(x) && getLowerBound(x).sgn() == 0;
+}
+
+bool ArithVariables::upperBoundIsZero(ArithVar x){
+ return hasUpperBound(x) && getUpperBound(x).sgn() == 0;
+}
+
void ArithVariables::printEntireModel(std::ostream& out) const{
out << "---Printing Model ---" << std::endl;
for(var_iterator i = var_begin(), iend = var_end(); i != iend; ++i){
@@ -474,6 +580,10 @@ void ArithVariables::printModel(ArithVar x, std::ostream& out) const{
out << getUpperBound(x) << " ";
out << getUpperBoundConstraint(x) << " ";
}
+
+ if(isInteger(x) && !integralAssignment(x)){
+ out << "(not an integer)" << endl;
+ }
out << endl;
}
@@ -540,10 +650,36 @@ void ArithVariables::processBoundsQueue(BoundUpdateCallback& changed){
}
}
+void ArithVariables::invalidateDelta() {
+ d_deltaIsSafe = false;
+}
+
+void ArithVariables::setDelta(const Rational& d){
+ d_delta = d;
+ d_deltaIsSafe = true;
+}
+
+void ArithVariables::startQueueingBoundCounts(){
+ d_enqueueingBoundCounts = true;
+}
+void ArithVariables::stopQueueingBoundCounts(){
+ d_enqueueingBoundCounts = false;
+}
+
+bool ArithVariables::inMaps(ArithVar x) const{
+ return x < getNumberOfVariables();
+}
+
+ArithVariables::LowerBoundCleanUp::LowerBoundCleanUp(ArithVariables* pm)
+ : d_pm(pm)
+{}
void ArithVariables::LowerBoundCleanUp::operator()(AVCPair* p){
d_pm->popLowerBound(p);
}
+ArithVariables::UpperBoundCleanUp::UpperBoundCleanUp(ArithVariables* pm)
+ : d_pm(pm)
+{}
void ArithVariables::UpperBoundCleanUp::operator()(AVCPair* p){
d_pm->popUpperBound(p);
}
diff --git a/src/theory/arith/partial_model.h b/src/theory/arith/partial_model.h
index c497adb75..33af3d4ef 100644
--- a/src/theory/arith/partial_model.h
+++ b/src/theory/arith/partial_model.h
@@ -9,10 +9,11 @@
** See the file COPYING in the top-level source directory for licensing
** information.\endverbatim
**
- ** \brief [[ Add one-line brief description here ]]
+ ** \brief Datastructures that track variable by variable information.
**
- ** [[ Add lengthier description here ]]
- ** \todo document this file
+ ** This is a datastructure that tracks variable specific information.
+ ** This is partially context dependent to back track upper/lower bounds
+ ** and information derived from these.
**/
#include "cvc4_private.h"
@@ -50,40 +51,44 @@ private:
ArithVar d_var;
DeltaRational d_assignment;
- Constraint d_lb;
- Constraint d_ub;
+ ConstraintP d_lb;
+ ConstraintP d_ub;
int d_cmpAssignmentLB;
int d_cmpAssignmentUB;
unsigned d_pushCount;
ArithType d_type;
Node d_node;
- bool d_slack;
+ bool d_auxiliary;
public:
VarInfo();
bool setAssignment(const DeltaRational& r, BoundsInfo& prev);
- bool setLowerBound(Constraint c, BoundsInfo& prev);
- bool setUpperBound(Constraint c, BoundsInfo& prev);
+ bool setLowerBound(ConstraintP c, BoundsInfo& prev);
+ bool setUpperBound(ConstraintP c, BoundsInfo& prev);
/** Returns true if this VarInfo has been initialized. */
bool initialized() const;
/**
* Initializes the VarInfo with the ArithVar index it is associated with,
- * the node that the variable represents, and whether it is a slack variable.
+ * the node that the variable represents, and whether it is an auxillary
+ * variable.
*/
- void initialize(ArithVar v, Node n, bool slack);
+ void initialize(ArithVar v, Node n, bool aux);
+
/** Uninitializes the VarInfo. */
void uninitialize();
bool canBeReclaimed() const;
- /** Indicator variables for if the assignment is equal to the upper and lower bounds. */
+ /** Indicator variables for if the assignment is equal to the upper
+ * and lower bounds. */
BoundCounts atBoundCounts() const;
- /** Combination of indicator variables for whether it has upper and lower bounds. */
+ /** Combination of indicator variables for whether it has upper and
+ * lower bounds. */
BoundCounts hasBoundCounts() const;
/** Stores both atBoundCounts() and hasBoundCounts(). */
@@ -92,21 +97,22 @@ private:
/**Maps from ArithVar -> VarInfo */
typedef DenseMap<VarInfo> VarInfoVec;
+
/** This maps an ArithVar to its Variable information.*/
VarInfoVec d_vars;
- // Partial Map from Arithvar -> PreviousAssignment
+ /** Partial Map from Arithvar -> PreviousAssignment */
DenseMap<DeltaRational> d_safeAssignment;
- // if d_vars.isKey(x), then x < d_numberOfVariables
+ /** if d_vars.isKey(x), then x < d_numberOfVariables */
ArithVar d_numberOfVariables;
/** [0, d_numberOfVariables) \intersect d_vars.keys == d_pool */
// Everything in the pool is fair game.
// There must be NO outstanding assertions
std::vector<ArithVar> d_pool;
- std::list<ArithVar> d_released;
- std::list<ArithVar>::iterator d_releasedIterator;
+ std::vector<ArithVar> d_released;
+ //std::list<ArithVar>::iterator d_releasedIterator;
// Reverse Map from Node to ArithVar
// Inverse of d_vars[x].d_node
@@ -118,36 +124,29 @@ private:
/**
* If this is true, record the incoming changes to the bound information.
- * If this is false, the responsibility of recording the changes is LinearEqualities's.
+ * If this is false, the responsibility of recording the changes is
+ * LinearEqualities's.
*/
bool d_enqueueingBoundCounts;
public:
- inline ArithVar getNumberOfVariables() const {
- return d_numberOfVariables;
- }
+ /** Returns the number of variables. */
+ ArithVar getNumberOfVariables() const;
- inline bool hasArithVar(TNode x) const {
- return d_nodeToArithVarMap.find(x) != d_nodeToArithVarMap.end();
- }
+ /** Returns true if the node has an associated variables. */
+ bool hasArithVar(TNode x) const;
- inline bool hasNode(ArithVar a) const {
- return d_vars.isKey(a);
- }
-
- inline ArithVar asArithVar(TNode x) const{
- Assert(hasArithVar(x));
- Assert((d_nodeToArithVarMap.find(x))->second <= ARITHVAR_SENTINEL);
- return (d_nodeToArithVarMap.find(x))->second;
- }
+ /** Returns true if the variable has a defining node. */
+ bool hasNode(ArithVar a) const;
+ /** Returns the ArithVar associated with a node. */
+ ArithVar asArithVar(TNode x) const;
- inline Node asNode(ArithVar a) const{
- Assert(hasNode(a));
- return d_vars[a].d_node;
- }
+ /** Returns the node associated with an ArithVar. */
+ Node asNode(ArithVar a) const;
+ /** Allocates a freshly allocated variables. */
ArithVar allocateVariable();
class var_iterator {
@@ -155,68 +154,47 @@ private:
const VarInfoVec* d_vars;
VarInfoVec::const_iterator d_wrapped;
public:
- var_iterator(){}
- var_iterator(const VarInfoVec* vars, VarInfoVec::const_iterator ci)
- : d_vars(vars), d_wrapped(ci)
- {
- nextInitialized();
- }
-
- var_iterator& operator++(){
- ++d_wrapped;
- nextInitialized();
- return *this;
- }
- bool operator==(const var_iterator& other) const{
- return d_wrapped == other.d_wrapped;
- }
- bool operator!=(const var_iterator& other) const{
- return d_wrapped != other.d_wrapped;
- }
- ArithVar operator*() const{
- return *d_wrapped;
- }
+ var_iterator();
+ var_iterator(const VarInfoVec* vars, VarInfoVec::const_iterator ci);
+ var_iterator& operator++();
+
+ bool operator==(const var_iterator& other) const;
+ bool operator!=(const var_iterator& other) const;
+ ArithVar operator*() const;
+
private:
- void nextInitialized(){
- VarInfoVec::const_iterator end = d_vars->end();
- while(d_wrapped != end &&
- !((*d_vars)[*d_wrapped].initialized())){
- ++d_wrapped;
- }
- }
+ void nextInitialized();
};
- var_iterator var_begin() const {
- return var_iterator(&d_vars, d_vars.begin());
- }
- var_iterator var_end() const {
- return var_iterator(&d_vars, d_vars.end());
- }
+ var_iterator var_begin() const;
+ var_iterator var_end() const;
bool canBeReleased(ArithVar v) const;
void releaseArithVar(ArithVar v);
void attemptToReclaimReleased();
- bool isInteger(ArithVar x) const {
- return d_vars[x].d_type >= ATInteger;
- }
- bool isSlack(ArithVar x) const {
- return d_vars[x].d_slack;
- }
+ /** Is this variable guaranteed to have an integer assignment?
+ * (Should agree with the type system.) */
+ bool isInteger(ArithVar x) const;
- bool integralAssignment(ArithVar x) const {
- return getAssignment(x).isIntegral();
- }
+ /** Is the assignment to x integral? */
+ bool integralAssignment(ArithVar x) const;
+
+ /* Is this variable defined as a linear sum of other variables? */
+ bool isAuxiliary(ArithVar x) const;
+
+ /* Is the variable both input and not auxiliary? */
+ bool isIntegerInput(ArithVar x) const;
private:
- typedef std::pair<ArithVar, Constraint> AVCPair;
+ typedef std::pair<ArithVar, ConstraintP> AVCPair;
class LowerBoundCleanUp {
private:
ArithVariables* d_pm;
public:
- LowerBoundCleanUp(ArithVariables* pm) : d_pm(pm) {}
+ LowerBoundCleanUp(ArithVariables* pm);
void operator()(AVCPair* restore);
};
@@ -224,7 +202,7 @@ private:
private:
ArithVariables* d_pm;
public:
- UpperBoundCleanUp(ArithVariables* pm) : d_pm(pm) {}
+ UpperBoundCleanUp(ArithVariables* pm);
void operator()(AVCPair* restore);
};
@@ -255,27 +233,27 @@ public:
* This sets the lower bound for a variable in the current context.
* This must be stronger the previous constraint.
*/
- void setLowerBoundConstraint(Constraint lb);
+ void setLowerBoundConstraint(ConstraintP lb);
/**
* This sets the upper bound for a variable in the current context.
* This must be stronger the previous constraint.
*/
- void setUpperBoundConstraint(Constraint ub);
+ void setUpperBoundConstraint(ConstraintP ub);
/** Returns the constraint for the upper bound of a variable. */
- inline Constraint getUpperBoundConstraint(ArithVar x) const{
+ inline ConstraintP getUpperBoundConstraint(ArithVar x) const{
return d_vars[x].d_ub;
}
/** Returns the constraint for the lower bound of a variable. */
- inline Constraint getLowerBoundConstraint(ArithVar x) const{
+ inline ConstraintP getLowerBoundConstraint(ArithVar x) const{
return d_vars[x].d_lb;
}
/* Initializes a variable to a safe value.*/
- void initialize(ArithVar x, Node n, bool slack);
+ void initialize(ArithVar x, Node n, bool aux);
- ArithVar allocate(Node n, bool slack = false);
+ ArithVar allocate(Node n, bool aux = false);
/* Gets the last assignment to a variable that is known to be consistent. */
const DeltaRational& getSafeAssignment(ArithVar x) const;
@@ -288,13 +266,8 @@ public:
void commitAssignmentChanges();
- inline bool lowerBoundIsZero(ArithVar x){
- return hasLowerBound(x) && getLowerBound(x).sgn() == 0;
- }
-
- inline bool upperBoundIsZero(ArithVar x){
- return hasUpperBound(x) && getUpperBound(x).sgn() == 0;
- }
+ bool lowerBoundIsZero(ArithVar x);
+ bool upperBoundIsZero(ArithVar x);
bool boundsAreEqual(ArithVar x) const;
@@ -393,17 +366,12 @@ public:
const Rational& getDelta();
- inline void invalidateDelta() {
- d_deltaIsSafe = false;
- }
+ void invalidateDelta();
- void setDelta(const Rational& d){
- d_delta = d;
- d_deltaIsSafe = true;
- }
+ void setDelta(const Rational& d);
- void startQueueingBoundCounts(){ d_enqueueingBoundCounts = true; }
- void stopQueueingBoundCounts(){ d_enqueueingBoundCounts = false; }
+ void startQueueingBoundCounts();
+ void stopQueueingBoundCounts();
void addToBoundQueue(ArithVar v, const BoundsInfo& prev);
BoundsInfo selectBoundsInfo(ArithVar v, bool old) const;
@@ -413,6 +381,15 @@ public:
void printEntireModel(std::ostream& out) const;
+
+ /**
+ * Precondition: assumes boundsAreEqual(x).
+ * If the either the lower/ upper bound is an equality, eq,
+ * this returns make_pair(eq, NullConstraint).
+ * Otherwise, this returns make_pair(lb, ub).
+ */
+ std::pair<ConstraintP, ConstraintP> explainEqualBounds(ArithVar x) const;
+
private:
/**
@@ -423,9 +400,7 @@ private:
bool debugEqualSizes();
- bool inMaps(ArithVar x) const{
- return x < getNumberOfVariables();
- }
+ bool inMaps(ArithVar x) const;
};/* class ArithVariables */
diff --git a/src/theory/arith/simplex.cpp b/src/theory/arith/simplex.cpp
index a160f4fe2..e67f4b9fc 100644
--- a/src/theory/arith/simplex.cpp
+++ b/src/theory/arith/simplex.cpp
@@ -77,35 +77,40 @@ bool SimplexDecisionProcedure::standardProcessSignals(TimerStat &timer, IntStat&
void SimplexDecisionProcedure::reportConflict(ArithVar basic){
Assert(!d_conflictVariables.isMember(basic));
Assert(checkBasicForConflict(basic));
- Node conflict = generateConflictForBasic(basic);
+ RaiseConflict rc( d_conflictChannel);
- static bool verbose = false;
- if(verbose) { Message() << "conflict " << basic << " " << conflict << endl; }
- Assert(!conflict.isNull());
- d_conflictChannel(conflict);
+ generateConflictForBasic(basic, rc);
+
+ // static bool verbose = false;
+ // if(verbose) { Message() << "conflict " << basic << " " << conflict << endl; }
+ // Assert(!conflict.isNull());
+ //d_conflictChannel(conflict);
+ rc.commitConflict();
d_conflictVariables.add(basic);
}
-Node SimplexDecisionProcedure::generateConflictForBasic(ArithVar basic) const {
+void SimplexDecisionProcedure::generateConflictForBasic(ArithVar basic, RaiseConflict& rc) const {
Assert(d_tableau.isBasic(basic));
Assert(checkBasicForConflict(basic));
if(d_variables.cmpAssignmentLowerBound(basic) < 0){
Assert(d_linEq.nonbasicsAtUpperBounds(basic));
- return d_linEq.generateConflictBelowLowerBound(basic);
+ return d_linEq.generateConflictBelowLowerBound(basic, rc);
}else if(d_variables.cmpAssignmentUpperBound(basic) > 0){
Assert(d_linEq.nonbasicsAtLowerBounds(basic));
- return d_linEq.generateConflictAboveUpperBound(basic);
+ return d_linEq.generateConflictAboveUpperBound(basic, rc);
}else{
Unreachable();
}
}
-Node SimplexDecisionProcedure::maybeGenerateConflictForBasic(ArithVar basic) const {
+bool SimplexDecisionProcedure::maybeGenerateConflictForBasic(ArithVar basic) const {
if(checkBasicForConflict(basic)){
- return generateConflictForBasic(basic);
+ RaiseConflict rc(d_conflictChannel);
+ generateConflictForBasic(basic, rc);
+ return true;
}else{
- return Node::null();
+ return false;
}
}
diff --git a/src/theory/arith/simplex.h b/src/theory/arith/simplex.h
index b61cadaf8..f545da51e 100644
--- a/src/theory/arith/simplex.h
+++ b/src/theory/arith/simplex.h
@@ -157,16 +157,16 @@ protected:
* If a conflict is discovered a node summarizing the conflict is returned.
* Otherwise, Node::null() is returned.
*/
- Node maybeGenerateConflictForBasic(ArithVar basic) const;
+ bool maybeGenerateConflictForBasic(ArithVar basic) const;
/** Returns true if a tracked basic variable has a conflict on it. */
bool checkBasicForConflict(ArithVar b) const;
/**
* If a basic variable has a conflict on its row,
- * this produces a minimized row.
+ * this produces a minimized row on the conflict channel.
*/
- Node generateConflictForBasic(ArithVar basic) const;
+ void generateConflictForBasic(ArithVar basic, RaiseConflict& rc) const;
/** Gets a fresh variable from TheoryArith. */
diff --git a/src/theory/arith/simplex_update.cpp b/src/theory/arith/simplex_update.cpp
index ba19d01b1..416fbe745 100644
--- a/src/theory/arith/simplex_update.cpp
+++ b/src/theory/arith/simplex_update.cpp
@@ -51,7 +51,7 @@ UpdateInfo::UpdateInfo(ArithVar nb, int dir):
Assert(dir == 1 || dir == -1);
}
-UpdateInfo::UpdateInfo(bool conflict, ArithVar nb, const DeltaRational& delta, const Rational& r, Constraint c):
+UpdateInfo::UpdateInfo(bool conflict, ArithVar nb, const DeltaRational& delta, const Rational& r, ConstraintP c):
d_nonbasic(nb),
d_nonbasicDirection(delta.sgn()),
d_nonbasicDelta(delta),
@@ -65,7 +65,7 @@ UpdateInfo::UpdateInfo(bool conflict, ArithVar nb, const DeltaRational& delta, c
Assert(conflict);
}
-UpdateInfo UpdateInfo::conflict(ArithVar nb, const DeltaRational& delta, const Rational& r, Constraint lim){
+UpdateInfo UpdateInfo::conflict(ArithVar nb, const DeltaRational& delta, const Rational& r, ConstraintP lim){
return UpdateInfo(true, nb, delta, r, lim);
}
@@ -81,7 +81,7 @@ void UpdateInfo::updateUnbounded(const DeltaRational& delta, int ec, int f){
Assert(!describesPivot());
Assert(debugSgnAgreement());
}
-void UpdateInfo::updatePureFocus(const DeltaRational& delta, Constraint c){
+void UpdateInfo::updatePureFocus(const DeltaRational& delta, ConstraintP c){
d_limiting = c;
d_nonbasicDelta = delta;
d_errorsChange.clear();
@@ -93,7 +93,7 @@ void UpdateInfo::updatePureFocus(const DeltaRational& delta, Constraint c){
Assert(debugSgnAgreement());
}
-void UpdateInfo::updatePivot(const DeltaRational& delta, const Rational& r, Constraint c){
+void UpdateInfo::updatePivot(const DeltaRational& delta, const Rational& r, ConstraintP c){
d_limiting = c;
d_nonbasicDelta = delta;
d_errorsChange.clear();
@@ -103,7 +103,7 @@ void UpdateInfo::updatePivot(const DeltaRational& delta, const Rational& r, Cons
Assert(debugSgnAgreement());
}
-void UpdateInfo::updatePivot(const DeltaRational& delta, const Rational& r, Constraint c, int ec){
+void UpdateInfo::updatePivot(const DeltaRational& delta, const Rational& r, ConstraintP c, int ec){
d_limiting = c;
d_nonbasicDelta = delta;
d_errorsChange = ec;
@@ -114,7 +114,7 @@ void UpdateInfo::updatePivot(const DeltaRational& delta, const Rational& r, Cons
Assert(debugSgnAgreement());
}
-void UpdateInfo::witnessedUpdate(const DeltaRational& delta, Constraint c, int ec, int fd){
+void UpdateInfo::witnessedUpdate(const DeltaRational& delta, ConstraintP c, int ec, int fd){
d_limiting = c;
d_nonbasicDelta = delta;
d_errorsChange = ec;
@@ -125,7 +125,7 @@ void UpdateInfo::witnessedUpdate(const DeltaRational& delta, Constraint c, int e
Assert(debugSgnAgreement());
}
-void UpdateInfo::update(const DeltaRational& delta, const Rational& r, Constraint c, int ec, int fd){
+void UpdateInfo::update(const DeltaRational& delta, const Rational& r, ConstraintP c, int ec, int fd){
d_limiting = c;
d_nonbasicDelta = delta;
d_errorsChange = ec;
diff --git a/src/theory/arith/simplex_update.h b/src/theory/arith/simplex_update.h
index 5a313e305..e223bba7f 100644
--- a/src/theory/arith/simplex_update.h
+++ b/src/theory/arith/simplex_update.h
@@ -136,7 +136,7 @@ private:
* - Pivot-And-Update: then this is not NullConstraint and the variable is not d_nonbasic.
* - Update: then this is not NullConstraint and the variable is d_nonbasic.
*/
- Constraint d_limiting;
+ ConstraintP d_limiting;
WitnessImprovement d_witness;
@@ -150,7 +150,7 @@ private:
}
/** This private constructor allows for setting conflict to true. */
- UpdateInfo(bool conflict, ArithVar nb, const DeltaRational& delta, const Rational& r, Constraint lim);
+ UpdateInfo(bool conflict, ArithVar nb, const DeltaRational& delta, const Rational& r, ConstraintP lim);
public:
@@ -170,7 +170,7 @@ public:
void updateUnbounded(const DeltaRational& d, int ec, int f);
- void updatePureFocus(const DeltaRational& d, Constraint c);
+ void updatePureFocus(const DeltaRational& d, ConstraintP c);
//void updatePureError(const DeltaRational& d, Constraint c, int e);
//void updatePure(const DeltaRational& d, Constraint c, int e, int f);
@@ -178,23 +178,23 @@ public:
* This updates the nonBasicDelta to d and limiting to c.
* This clears errorChange() and focusDir().
*/
- void updatePivot(const DeltaRational& d, const Rational& r, Constraint c);
+ void updatePivot(const DeltaRational& d, const Rational& r, ConstraintP c);
/**
* This updates the nonBasicDelta to d, limiting to c, and errorChange to e.
* This clears focusDir().
*/
- void updatePivot(const DeltaRational& d, const Rational& r, Constraint c, int e);
+ void updatePivot(const DeltaRational& d, const Rational& r, ConstraintP c, int e);
/**
* This updates the nonBasicDelta to d, limiting to c, errorChange to e and
* focusDir to f.
*/
- void witnessedUpdate(const DeltaRational& d, Constraint c, int e, int f);
- void update(const DeltaRational& d, const Rational& r, Constraint c, int e, int f);
+ void witnessedUpdate(const DeltaRational& d, ConstraintP c, int e, int f);
+ void update(const DeltaRational& d, const Rational& r, ConstraintP c, int e, int f);
- static UpdateInfo conflict(ArithVar nb, const DeltaRational& delta, const Rational& r, Constraint lim);
+ static UpdateInfo conflict(ArithVar nb, const DeltaRational& delta, const Rational& r, ConstraintP lim);
inline ArithVar nonbasic() const { return d_nonbasic; }
inline bool uninitialized() const {
@@ -283,7 +283,7 @@ public:
}
/** Returns the limiting constraint. */
- inline Constraint limiting() const {
+ inline ConstraintP limiting() const {
return d_limiting;
}
diff --git a/src/theory/arith/soi_simplex.cpp b/src/theory/arith/soi_simplex.cpp
index 2eb258d3b..ded322f18 100644
--- a/src/theory/arith/soi_simplex.cpp
+++ b/src/theory/arith/soi_simplex.cpp
@@ -383,7 +383,7 @@ void SumOfInfeasibilitiesSPD::updateAndSignal(const UpdateInfo& selected, Witnes
}
if(selected.describesPivot()){
- Constraint limiting = selected.limiting();
+ ConstraintP limiting = selected.limiting();
ArithVar basic = limiting->getVariable();
Assert(d_linEq.basicIsTracked(basic));
d_linEq.pivotAndUpdate(basic, nonbasic, limiting->getValue());
@@ -765,16 +765,17 @@ std::vector< ArithVarVec > SumOfInfeasibilitiesSPD::greedyConflictSubsets(){
return subsets;
}
-Node SumOfInfeasibilitiesSPD::generateSOIConflict(const ArithVarVec& subset){
+void SumOfInfeasibilitiesSPD::generateSOIConflict(const ArithVarVec& subset){
Assert(d_soiVar == ARITHVAR_SENTINEL);
d_soiVar = constructInfeasiblityFunction(d_statistics.d_soiConflictMinimization, subset);
- NodeBuilder<> conflict(kind::AND);
+ //NodeBuilder<> conflict(kind::AND);
for(ArithVarVec::const_iterator iter = subset.begin(), end = subset.end(); iter != end; ++iter){
ArithVar e = *iter;
- Constraint violated = d_errorSet.getViolated(e);
+ ConstraintP violated = d_errorSet.getViolated(e);
//cout << "basic error var: " << violated << endl;
- violated->explainForConflict(conflict);
+ d_conflictChannel.addConstraint(violated);
+ //violated->explainForConflict(conflict);
//d_tableau.debugPrintIsBasic(e);
//d_tableau.printBasicRow(e, cout);
@@ -785,18 +786,19 @@ Node SumOfInfeasibilitiesSPD::generateSOIConflict(const ArithVarVec& subset){
if(v == d_soiVar){ continue; }
const Rational& coeff = entry.getCoefficient();
- Constraint c = (coeff.sgn() > 0) ?
+ ConstraintP c = (coeff.sgn() > 0) ?
d_variables.getUpperBoundConstraint(v) :
d_variables.getLowerBoundConstraint(v);
//cout << "nb : " << c << endl;
- c->explainForConflict(conflict);
+ d_conflictChannel.addConstraint(c);
}
- Node conf = conflict;
+ //Node conf = conflict;
tearDownInfeasiblityFunction(d_statistics.d_soiConflictMinimization, d_soiVar);
d_soiVar = ARITHVAR_SENTINEL;
- return conf;
+ d_conflictChannel.commitConflict();
+ //return conf;
}
@@ -812,9 +814,10 @@ WitnessImprovement SumOfInfeasibilitiesSPD::SOIConflict(){
if(options::soiQuickExplain()){
quickExplain();
- Node conflict = generateSOIConflict(d_qeConflict);
+ generateSOIConflict(d_qeConflict);
+ //Node conflict = generateSOIConflict(d_qeConflict);
//cout << conflict << endl;
- d_conflictChannel(conflict);
+ //d_conflictChannel(conflict);
}else{
vector<ArithVarVec> subsets = greedyConflictSubsets();
@@ -823,11 +826,12 @@ WitnessImprovement SumOfInfeasibilitiesSPD::SOIConflict(){
Assert(!subsets.empty());
for(vector<ArithVarVec>::const_iterator i = subsets.begin(), end = subsets.end(); i != end; ++i){
const ArithVarVec& subset = *i;
- Node conflict = generateSOIConflict(subset);
+ generateSOIConflict(subset);
+ //Node conflict = generateSOIConflict(subset);
//cout << conflict << endl;
//reportConflict(conf); do not do this. We need a custom explanations!
- d_conflictChannel(conflict);
+ //d_conflictChannel(conflict);
}
}
Assert( d_soiVar == ARITHVAR_SENTINEL);
diff --git a/src/theory/arith/soi_simplex.h b/src/theory/arith/soi_simplex.h
index cee6cf81d..89df69390 100644
--- a/src/theory/arith/soi_simplex.h
+++ b/src/theory/arith/soi_simplex.h
@@ -171,7 +171,7 @@ private:
WitnessImprovement soiRound();
WitnessImprovement SOIConflict();
std::vector< ArithVarVec > greedyConflictSubsets();
- Node generateSOIConflict(const ArithVarVec& subset);
+ void generateSOIConflict(const ArithVarVec& subset);
// WitnessImprovement focusUsingSignDisagreements(ArithVar basic);
// WitnessImprovement focusDownToLastHalf();
diff --git a/src/theory/arith/tableau.h b/src/theory/arith/tableau.h
index 3e4cb819b..8cf92d075 100644
--- a/src/theory/arith/tableau.h
+++ b/src/theory/arith/tableau.h
@@ -81,7 +81,7 @@ public:
}
ArithVar rowIndexToBasic(RowIndex rid) const {
- Assert(rid < d_rowIndex2basic.size());
+ Assert(d_rowIndex2basic.isKey(rid));
return d_rowIndex2basic[rid];
}
diff --git a/src/theory/arith/theory_arith.cpp b/src/theory/arith/theory_arith.cpp
index 85d9d1f9b..960a5a066 100644
--- a/src/theory/arith/theory_arith.cpp
+++ b/src/theory/arith/theory_arith.cpp
@@ -38,6 +38,10 @@ void TheoryArith::preRegisterTerm(TNode n){
d_internal->preRegisterTerm(n);
}
+Node TheoryArith::expandDefinition(LogicRequest &logicRequest, Node node) {
+ return d_internal->expandDefinition(logicRequest, node);
+}
+
void TheoryArith::setMasterEqualityEngine(eq::EqualityEngine* eq) {
d_internal->setMasterEqualityEngine(eq);
}
diff --git a/src/theory/arith/theory_arith.h b/src/theory/arith/theory_arith.h
index 428c101a6..eaa9a98c6 100644
--- a/src/theory/arith/theory_arith.h
+++ b/src/theory/arith/theory_arith.h
@@ -53,6 +53,8 @@ public:
*/
void preRegisterTerm(TNode n);
+ Node expandDefinition(LogicRequest &logicRequest, Node node);
+
void setMasterEqualityEngine(eq::EqualityEngine* eq);
void setQuantifiersEngine(QuantifiersEngine* qe);
diff --git a/src/theory/arith/theory_arith_private.cpp b/src/theory/arith/theory_arith_private.cpp
index 40a336a4a..a63de446c 100644
--- a/src/theory/arith/theory_arith_private.cpp
+++ b/src/theory/arith/theory_arith_private.cpp
@@ -38,9 +38,11 @@
#include "util/statistics_registry.h"
#include "util/result.h"
+#include "smt/logic_request.h"
#include "smt/logic_exception.h"
#include "theory/arith/arithvar.h"
+#include "theory/arith/cut_log.h"
#include "theory/arith/delta_rational.h"
#include "theory/arith/matrix.h"
#include "theory/arith/arith_rewriter.h"
@@ -54,6 +56,9 @@
#include "theory/arith/approx_simplex.h"
#include "theory/arith/constraint.h"
+#include "theory/ite_utilities.h"
+#include "theory/arith/arith_ite_utils.h"
+
#include "theory/arith/arith_utilities.h"
#include "theory/arith/delta_rational.h"
#include "theory/arith/partial_model.h"
@@ -66,6 +71,8 @@
#include "theory/theory_model.h"
#include "theory/arith/options.h"
+#include "theory/quantifiers/options.h"
+
#include "theory/quantifiers/bounded_integers.h"
@@ -82,11 +89,17 @@ namespace CVC4 {
namespace theory {
namespace arith {
+static Node toSumNode(const ArithVariables& vars, const DenseMap<Rational>& sum);
+static double fRand(double fMin, double fMax);
+static bool complexityBelow(const DenseMap<Rational>& row, uint32_t cap);
+
+
TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing, context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo) :
d_containing(containing),
d_nlIncomplete( false),
d_rowTracking(),
- d_constraintDatabase(c, u, d_partialModel, d_congruenceManager, RaiseConflict(*this)),
+ d_conflictBuffer(),
+ d_constraintDatabase(c, u, d_partialModel, d_congruenceManager, RaiseConflict(*this, d_conflictBuffer)),
d_qflraStatus(Result::SAT_UNKNOWN),
d_unknownsInARow(0),
d_hasDoneWorkSinceCut(false),
@@ -108,26 +121,97 @@ TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing, context::Context
d_tableauResetDensity(1.6),
d_tableauResetPeriod(10),
d_conflicts(c),
- d_congruenceManager(c, d_constraintDatabase, SetupLiteralCallBack(*this), d_partialModel, RaiseConflict(*this)),
- d_dualSimplex(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
- d_fcSimplex(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
- d_soiSimplex(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
- d_attemptSolSimplex(d_linEq, d_errorSet, RaiseConflict(*this), TempVarMalloc(*this)),
+ d_blackBoxConflict(c, Node::null()),
+ d_congruenceManager(c, d_constraintDatabase, SetupLiteralCallBack(*this), d_partialModel, RaiseConflict(*this, d_conflictBuffer)),
+ d_cmEnabled(c, true),
+ d_dualSimplex(d_linEq, d_errorSet, RaiseConflict(*this, d_conflictBuffer), TempVarMalloc(*this)),
+ d_fcSimplex(d_linEq, d_errorSet, RaiseConflict(*this, d_conflictBuffer), TempVarMalloc(*this)),
+ d_soiSimplex(d_linEq, d_errorSet, RaiseConflict(*this, d_conflictBuffer), TempVarMalloc(*this)),
+ d_attemptSolSimplex(d_linEq, d_errorSet, RaiseConflict(*this, d_conflictBuffer), TempVarMalloc(*this)),
+ d_pass1SDP(NULL),
+ d_otherSDP(NULL),
+ d_lastContextIntegerAttempted(c,-1),
d_DELTA_ZERO(0),
+ d_approxCuts(c),
d_fullCheckCounter(0),
d_cutCount(c, 0),
d_cutInContext(c),
d_likelyIntegerInfeasible(c, false),
d_guessedCoeffSet(c, false),
d_guessedCoeffs(),
+ d_treeLog(NULL),
+ d_replayVariables(),
+ d_replayConstraints(),
+ d_lhsTmp(),
+ d_approxStats(NULL),
+ d_attemptSolveIntTurnedOff(u, 0),
+ d_dioSolveResources(0),
+ d_solveIntMaybeHelp(0u),
+ d_solveIntAttempts(0u),
d_statistics()
{
srand(79);
}
-TheoryArithPrivate::~TheoryArithPrivate(){ }
+TheoryArithPrivate::~TheoryArithPrivate(){
+ if(d_treeLog != NULL){ delete d_treeLog; }
+ if(d_approxStats != NULL) { delete d_approxStats; }
+}
+
+static bool contains(const ConstraintCPVec& v, ConstraintP con){
+ for(unsigned i = 0, N = v.size(); i < N; ++i){
+ if(v[i] == con){
+ return true;
+ }
+ }
+ return false;
+}
+static void drop( ConstraintCPVec& v, ConstraintP con){
+ size_t readPos, writePos, N;
+ for(readPos = 0, writePos = 0, N = v.size(); readPos < N; ++readPos){
+ ConstraintCP curr = v[readPos];
+ if(curr != con){
+ v[writePos] = curr;
+ writePos++;
+ }
+ }
+ v.resize(writePos);
+}
+static void resolve(ConstraintCPVec& buf, ConstraintP c, const ConstraintCPVec& pos, const ConstraintCPVec& neg){
+ unsigned posPos CVC4_UNUSED = pos.size();
+ for(unsigned i = 0, N = pos.size(); i < N; ++i){
+ if(pos[i] == c){
+ posPos = i;
+ }else{
+ buf.push_back(pos[i]);
+ }
+ }
+ Assert(posPos < pos.size());
+ ConstraintP negc = c->getNegation();
+ unsigned negPos CVC4_UNUSED = neg.size();
+ for(unsigned i = 0, N = neg.size(); i < N; ++i){
+ if(neg[i] == negc){
+ negPos = i;
+ }else{
+ buf.push_back(neg[i]);
+ }
+ }
+ Assert(negPos < neg.size());
+
+ // Assert(dnconf.getKind() == kind::AND);
+ // Assert(upconf.getKind() == kind::AND);
+ // Assert(dnpos < dnconf.getNumChildren());
+ // Assert(uppos < upconf.getNumChildren());
+ // Assert(equalUpToNegation(dnconf[dnpos], upconf[uppos]));
+
+ // NodeBuilder<> nb(kind::AND);
+ // dropPosition(nb, dnconf, dnpos);
+ // dropPosition(nb, upconf, uppos);
+ // return safeConstructNary(nb);
+}
+
void TheoryArithPrivate::setMasterEqualityEngine(eq::EqualityEngine* eq) {
d_congruenceManager.setMasterEqualityEngine(eq);
}
@@ -177,40 +261,79 @@ TheoryArithPrivate::ModelException::ModelException(TNode n, const char* msg) thr
TheoryArithPrivate::ModelException::~ModelException() throw (){ }
-TheoryArithPrivate::Statistics::Statistics():
- d_statAssertUpperConflicts("theory::arith::AssertUpperConflicts", 0),
- d_statAssertLowerConflicts("theory::arith::AssertLowerConflicts", 0),
- d_statUserVariables("theory::arith::UserVariables", 0),
- d_statSlackVariables("theory::arith::SlackVariables", 0),
- d_statDisequalitySplits("theory::arith::DisequalitySplits", 0),
- d_statDisequalityConflicts("theory::arith::DisequalityConflicts", 0),
- d_simplifyTimer("theory::arith::simplifyTimer"),
- d_staticLearningTimer("theory::arith::staticLearningTimer"),
- d_presolveTime("theory::arith::presolveTime"),
- d_newPropTime("theory::arith::newPropTimer"),
- d_externalBranchAndBounds("theory::arith::externalBranchAndBounds",0),
- d_initialTableauSize("theory::arith::initialTableauSize", 0),
- d_currSetToSmaller("theory::arith::currSetToSmaller", 0),
- d_smallerSetToCurr("theory::arith::smallerSetToCurr", 0),
- d_restartTimer("theory::arith::restartTimer"),
- d_boundComputationTime("theory::arith::bound::time"),
- d_boundComputations("theory::arith::bound::boundComputations",0),
- d_boundPropagations("theory::arith::bound::boundPropagations",0),
- d_unknownChecks("theory::arith::status::unknowns", 0),
- d_maxUnknownsInARow("theory::arith::status::maxUnknownsInARow", 0),
- d_avgUnknownsInARow("theory::arith::status::avgUnknownsInARow"),
- d_revertsOnConflicts("theory::arith::status::revertsOnConflicts",0),
- d_commitsOnConflicts("theory::arith::status::commitsOnConflicts",0),
- d_nontrivialSatChecks("theory::arith::status::nontrivialSatChecks",0),
- d_satPivots("pivots::sat"),
- d_unsatPivots("pivots::unsat"),
- d_unknownPivots("pivots::unkown")
+TheoryArithPrivate::Statistics::Statistics()
+ : d_statAssertUpperConflicts("theory::arith::AssertUpperConflicts", 0)
+ , d_statAssertLowerConflicts("theory::arith::AssertLowerConflicts", 0)
+ , d_statUserVariables("theory::arith::UserVariables", 0)
+ , d_statAuxiliaryVariables("theory::arith::AuxiliaryVariables", 0)
+ , d_statDisequalitySplits("theory::arith::DisequalitySplits", 0)
+ , d_statDisequalityConflicts("theory::arith::DisequalityConflicts", 0)
+ , d_simplifyTimer("theory::arith::simplifyTimer")
+ , d_staticLearningTimer("theory::arith::staticLearningTimer")
+ , d_presolveTime("theory::arith::presolveTime")
+ , d_newPropTime("theory::arith::newPropTimer")
+ , d_externalBranchAndBounds("theory::arith::externalBranchAndBounds",0)
+ , d_initialTableauSize("theory::arith::initialTableauSize", 0)
+ , d_currSetToSmaller("theory::arith::currSetToSmaller", 0)
+ , d_smallerSetToCurr("theory::arith::smallerSetToCurr", 0)
+ , d_restartTimer("theory::arith::restartTimer")
+ , d_boundComputationTime("theory::arith::bound::time")
+ , d_boundComputations("theory::arith::bound::boundComputations",0)
+ , d_boundPropagations("theory::arith::bound::boundPropagations",0)
+ , d_unknownChecks("theory::arith::status::unknowns", 0)
+ , d_maxUnknownsInARow("theory::arith::status::maxUnknownsInARow", 0)
+ , d_avgUnknownsInARow("theory::arith::status::avgUnknownsInARow")
+ , d_revertsOnConflicts("theory::arith::status::revertsOnConflicts",0)
+ , d_commitsOnConflicts("theory::arith::status::commitsOnConflicts",0)
+ , d_nontrivialSatChecks("theory::arith::status::nontrivialSatChecks",0)
+ , d_replayLogRecCount("z::approx::replay::rec",0)
+ , d_replayLogRecConflictEscalation("z::approx::replay::rec::escalation",0)
+ , d_replayLogRecEarlyExit("z::approx::replay::rec::earlyexit",0)
+ , d_replayBranchCloseFailures("z::approx::replay::rec::branch::closefailures",0)
+ , d_replayLeafCloseFailures("z::approx::replay::rec::leaf::closefailures",0)
+ , d_replayBranchSkips("z::approx::replay::rec::branch::skips",0)
+ , d_mirCutsAttempted("z::approx::cuts::mir::attempted",0)
+ , d_gmiCutsAttempted("z::approx::cuts::gmi::attempted",0)
+ , d_branchCutsAttempted("z::approx::cuts::branch::attempted",0)
+ , d_cutsReconstructed("z::approx::cuts::reconstructed",0)
+ , d_cutsReconstructionFailed("z::approx::cuts::reconstructed::failed",0)
+ , d_cutsProven("z::approx::cuts::proofs",0)
+ , d_cutsProofFailed("z::approx::cuts::proofs::failed",0)
+ , d_mipReplayLemmaCalls("z::approx::external::calls",0)
+ , d_mipExternalCuts("z::approx::external::cuts",0)
+ , d_mipExternalBranch("z::approx::external::branches",0)
+ , d_inSolveInteger("z::approx::inSolverInteger",0)
+ , d_branchesExhausted("z::approx::exhausted::branches",0)
+ , d_execExhausted("z::approx::exhausted::exec",0)
+ , d_pivotsExhausted("z::approx::exhausted::pivots",0)
+ , d_panicBranches("z::arith::paniclemmas",0)
+ , d_relaxCalls("z::arith::relax::calls",0)
+ , d_relaxLinFeas("z::arith::relax::feasible::res",0)
+ , d_relaxLinFeasFailures("z::arith::relax::feasible::failures",0)
+ , d_relaxLinInfeas("z::arith::relax::infeasible",0)
+ , d_relaxLinInfeasFailures("z::arith::relax::infeasible::failures",0)
+ , d_relaxLinExhausted("z::arith::relax::exhausted",0)
+ , d_relaxOthers("z::arith::relax::other",0)
+ , d_applyRowsDeleted("z::arith::cuts::applyRowsDeleted",0)
+ , d_replaySimplexTimer("z::approx::replay::simplex::timer")
+ , d_replayLogTimer("z::approx::replay::log::timer")
+ , d_solveIntTimer("z::solveInt::timer")
+ , d_solveRealRelaxTimer("z::solveRealRelax::timer")
+ , d_solveIntCalls("z::solveInt::calls", 0)
+ , d_solveStandardEffort("z::solveInt::calls::standardEffort", 0)
+ , d_approxDisabled("z::approxDisabled", 0)
+ , d_replayAttemptFailed("z::replayAttemptFailed",0)
+ , d_cutsRejectedDuringReplay("z::approx::replay::cuts::rejected", 0)
+ , d_cutsRejectedDuringLemmas("z::approx::external::cuts::rejected", 0)
+ , d_satPivots("pivots::sat")
+ , d_unsatPivots("pivots::unsat")
+ , d_unknownPivots("pivots::unkown")
{
StatisticsRegistry::registerStat(&d_statAssertUpperConflicts);
StatisticsRegistry::registerStat(&d_statAssertLowerConflicts);
StatisticsRegistry::registerStat(&d_statUserVariables);
- StatisticsRegistry::registerStat(&d_statSlackVariables);
+ StatisticsRegistry::registerStat(&d_statAuxiliaryVariables);
StatisticsRegistry::registerStat(&d_statDisequalitySplits);
StatisticsRegistry::registerStat(&d_statDisequalityConflicts);
StatisticsRegistry::registerStat(&d_simplifyTimer);
@@ -241,6 +364,54 @@ TheoryArithPrivate::Statistics::Statistics():
StatisticsRegistry::registerStat(&d_satPivots);
StatisticsRegistry::registerStat(&d_unsatPivots);
StatisticsRegistry::registerStat(&d_unknownPivots);
+
+ StatisticsRegistry::registerStat(&d_replayLogRecCount);
+ StatisticsRegistry::registerStat(&d_replayLogRecConflictEscalation);
+ StatisticsRegistry::registerStat(&d_replayLogRecEarlyExit);
+ StatisticsRegistry::registerStat(&d_replayBranchCloseFailures);
+ StatisticsRegistry::registerStat(&d_replayLeafCloseFailures);
+ StatisticsRegistry::registerStat(&d_replayBranchSkips);
+ StatisticsRegistry::registerStat(&d_mirCutsAttempted);
+ StatisticsRegistry::registerStat(&d_gmiCutsAttempted);
+ StatisticsRegistry::registerStat(&d_branchCutsAttempted);
+ StatisticsRegistry::registerStat(&d_cutsReconstructed);
+ StatisticsRegistry::registerStat(&d_cutsProven);
+ StatisticsRegistry::registerStat(&d_cutsProofFailed);
+ StatisticsRegistry::registerStat(&d_cutsReconstructionFailed);
+ StatisticsRegistry::registerStat(&d_mipReplayLemmaCalls);
+ StatisticsRegistry::registerStat(&d_mipExternalCuts);
+ StatisticsRegistry::registerStat(&d_mipExternalBranch);
+
+ StatisticsRegistry::registerStat(&d_inSolveInteger);
+ StatisticsRegistry::registerStat(&d_branchesExhausted);
+ StatisticsRegistry::registerStat(&d_execExhausted);
+ StatisticsRegistry::registerStat(&d_pivotsExhausted);
+ StatisticsRegistry::registerStat(&d_panicBranches);
+ StatisticsRegistry::registerStat(&d_relaxCalls);
+ StatisticsRegistry::registerStat(&d_relaxLinFeas);
+ StatisticsRegistry::registerStat(&d_relaxLinFeasFailures);
+ StatisticsRegistry::registerStat(&d_relaxLinInfeas);
+ StatisticsRegistry::registerStat(&d_relaxLinInfeasFailures);
+ StatisticsRegistry::registerStat(&d_relaxLinExhausted);
+ StatisticsRegistry::registerStat(&d_relaxOthers);
+
+ StatisticsRegistry::registerStat(&d_applyRowsDeleted);
+
+ StatisticsRegistry::registerStat(&d_replaySimplexTimer);
+ StatisticsRegistry::registerStat(&d_replayLogTimer);
+ StatisticsRegistry::registerStat(&d_solveIntTimer);
+ StatisticsRegistry::registerStat(&d_solveRealRelaxTimer);
+
+ StatisticsRegistry::registerStat(&d_solveIntCalls);
+ StatisticsRegistry::registerStat(&d_solveStandardEffort);
+
+ StatisticsRegistry::registerStat(&d_approxDisabled);
+
+ StatisticsRegistry::registerStat(&d_replayAttemptFailed);
+
+ StatisticsRegistry::registerStat(&d_cutsRejectedDuringReplay);
+ StatisticsRegistry::registerStat(&d_cutsRejectedDuringLemmas);
+
}
TheoryArithPrivate::Statistics::~Statistics(){
@@ -248,7 +419,7 @@ TheoryArithPrivate::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(&d_statAssertLowerConflicts);
StatisticsRegistry::unregisterStat(&d_statUserVariables);
- StatisticsRegistry::unregisterStat(&d_statSlackVariables);
+ StatisticsRegistry::unregisterStat(&d_statAuxiliaryVariables);
StatisticsRegistry::unregisterStat(&d_statDisequalitySplits);
StatisticsRegistry::unregisterStat(&d_statDisequalityConflicts);
StatisticsRegistry::unregisterStat(&d_simplifyTimer);
@@ -278,6 +449,66 @@ TheoryArithPrivate::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(&d_satPivots);
StatisticsRegistry::unregisterStat(&d_unsatPivots);
StatisticsRegistry::unregisterStat(&d_unknownPivots);
+
+ StatisticsRegistry::unregisterStat(&d_replayLogRecCount);
+ StatisticsRegistry::unregisterStat(&d_replayLogRecConflictEscalation);
+ StatisticsRegistry::unregisterStat(&d_replayLogRecEarlyExit);
+ StatisticsRegistry::unregisterStat(&d_replayBranchCloseFailures);
+ StatisticsRegistry::unregisterStat(&d_replayLeafCloseFailures);
+ StatisticsRegistry::unregisterStat(&d_replayBranchSkips);
+ StatisticsRegistry::unregisterStat(&d_mirCutsAttempted);
+ StatisticsRegistry::unregisterStat(&d_gmiCutsAttempted);
+ StatisticsRegistry::unregisterStat(&d_branchCutsAttempted);
+ StatisticsRegistry::unregisterStat(&d_cutsReconstructed);
+ StatisticsRegistry::unregisterStat(&d_cutsProven);
+ StatisticsRegistry::unregisterStat(&d_cutsProofFailed);
+ StatisticsRegistry::unregisterStat(&d_cutsReconstructionFailed);
+ StatisticsRegistry::unregisterStat(&d_mipReplayLemmaCalls);
+ StatisticsRegistry::unregisterStat(&d_mipExternalCuts);
+ StatisticsRegistry::unregisterStat(&d_mipExternalBranch);
+
+
+ StatisticsRegistry::unregisterStat(&d_inSolveInteger);
+ StatisticsRegistry::unregisterStat(&d_branchesExhausted);
+ StatisticsRegistry::unregisterStat(&d_execExhausted);
+ StatisticsRegistry::unregisterStat(&d_pivotsExhausted);
+ StatisticsRegistry::unregisterStat(&d_panicBranches);
+ StatisticsRegistry::unregisterStat(&d_relaxCalls);
+ StatisticsRegistry::unregisterStat(&d_relaxLinFeas);
+ StatisticsRegistry::unregisterStat(&d_relaxLinFeasFailures);
+ StatisticsRegistry::unregisterStat(&d_relaxLinInfeas);
+ StatisticsRegistry::unregisterStat(&d_relaxLinInfeasFailures);
+ StatisticsRegistry::unregisterStat(&d_relaxLinExhausted);
+ StatisticsRegistry::unregisterStat(&d_relaxOthers);
+
+ StatisticsRegistry::unregisterStat(&d_applyRowsDeleted);
+
+ StatisticsRegistry::unregisterStat(&d_replaySimplexTimer);
+ StatisticsRegistry::unregisterStat(&d_replayLogTimer);
+ StatisticsRegistry::unregisterStat(&d_solveIntTimer);
+ StatisticsRegistry::unregisterStat(&d_solveRealRelaxTimer);
+
+ StatisticsRegistry::unregisterStat(&d_solveIntCalls);
+ StatisticsRegistry::unregisterStat(&d_solveStandardEffort);
+
+ StatisticsRegistry::unregisterStat(&d_approxDisabled);
+
+ StatisticsRegistry::unregisterStat(&d_replayAttemptFailed);
+
+ StatisticsRegistry::unregisterStat(&d_cutsRejectedDuringReplay);
+ StatisticsRegistry::unregisterStat(&d_cutsRejectedDuringLemmas);
+}
+
+bool complexityBelow(const DenseMap<Rational>& row, uint32_t cap){
+ DenseMap<Rational>::const_iterator riter, rend;
+ for(riter=row.begin(), rend=row.end(); riter != rend; ++riter){
+ ArithVar v = *riter;
+ const Rational& q = row[v];
+ if(q.complexity() > cap){
+ return false;
+ }
+ }
+ return true;
}
void TheoryArithPrivate::revertOutOfConflict(){
@@ -290,25 +521,67 @@ void TheoryArithPrivate::clearUpdates(){
d_updatedBounds.purge();
}
+void TheoryArithPrivate::raiseConflict(ConstraintCP a, ConstraintCP b){
+ ConstraintCPVec v;
+ v.push_back(a);
+ v.push_back(b);
+ d_conflicts.push_back(v);
+}
+
+void TheoryArithPrivate::raiseConflict(ConstraintCP a, ConstraintCP b, ConstraintCP c){
+ ConstraintCPVec v;
+ v.push_back(a);
+ v.push_back(b);
+ v.push_back(c);
+ d_conflicts.push_back(v);
+}
+
void TheoryArithPrivate::zeroDifferenceDetected(ArithVar x){
- Assert(d_congruenceManager.isWatchedVariable(x));
- Assert(d_partialModel.upperBoundIsZero(x));
- Assert(d_partialModel.lowerBoundIsZero(x));
+ if(d_cmEnabled){
+ Assert(d_congruenceManager.isWatchedVariable(x));
+ Assert(d_partialModel.upperBoundIsZero(x));
+ Assert(d_partialModel.lowerBoundIsZero(x));
- Constraint lb = d_partialModel.getLowerBoundConstraint(x);
- Constraint ub = d_partialModel.getUpperBoundConstraint(x);
+ ConstraintP lb = d_partialModel.getLowerBoundConstraint(x);
+ ConstraintP ub = d_partialModel.getUpperBoundConstraint(x);
+
+ if(lb->isEquality()){
+ d_congruenceManager.watchedVariableIsZero(lb);
+ }else if(ub->isEquality()){
+ d_congruenceManager.watchedVariableIsZero(ub);
+ }else{
+ d_congruenceManager.watchedVariableIsZero(lb, ub);
+ }
+ }
+}
- if(lb->isEquality()){
- d_congruenceManager.watchedVariableIsZero(lb);
- }else if(ub->isEquality()){
- d_congruenceManager.watchedVariableIsZero(ub);
+bool TheoryArithPrivate::getSolveIntegerResource(){
+ if(d_attemptSolveIntTurnedOff > 0){
+ d_attemptSolveIntTurnedOff = d_attemptSolveIntTurnedOff - 1;
+ return false;
+ }else{
+ return true;
+ }
+}
+
+bool TheoryArithPrivate::getDioCuttingResource(){
+ if(d_dioSolveResources > 0){
+ d_dioSolveResources--;
+ if(d_dioSolveResources == 0){
+ d_dioSolveResources = -options::rrTurns();
+ }
+ return true;
}else{
- d_congruenceManager.watchedVariableIsZero(lb, ub);
+ d_dioSolveResources++;
+ if(d_dioSolveResources >= 0){
+ d_dioSolveResources = options::dioSolverTurns();
+ }
+ return false;
}
}
/* procedure AssertLower( x_i >= c_i ) */
-bool TheoryArithPrivate::AssertLower(Constraint constraint){
+bool TheoryArithPrivate::AssertLower(ConstraintP constraint){
Assert(constraint != NullConstraint);
Assert(constraint->isLowerBound());
@@ -326,38 +599,43 @@ bool TheoryArithPrivate::AssertLower(Constraint constraint){
int cmpToUB = d_partialModel.cmpToUpperBound(x_i, c_i);
if(cmpToUB > 0){ // c_i < \lowerbound(x_i)
- Constraint ubc = d_partialModel.getUpperBoundConstraint(x_i);
- Node conflict = ConstraintValue::explainConflict(ubc, constraint);
- Debug("arith") << "AssertLower conflict " << conflict << endl;
+ ConstraintP ubc = d_partialModel.getUpperBoundConstraint(x_i);
+ raiseConflict(ubc, constraint);
+
+ // Node conflict = ConstraintValue::explainConflict(ubc, constraint);
+ // Debug("arith") << "AssertLower conflict " << conflict << endl;
+ // raiseConflict(conflict);
++(d_statistics.d_statAssertLowerConflicts);
- raiseConflict(conflict);
return true;
}else if(cmpToUB == 0){
if(isInteger(x_i)){
d_constantIntegerVariables.push_back(x_i);
Debug("dio::push") << x_i << endl;
}
- Constraint ub = d_partialModel.getUpperBoundConstraint(x_i);
-
- if(!d_congruenceManager.isWatchedVariable(x_i) || c_i.sgn() != 0){
- // if it is not a watched variable report it
- // if it is is a watched variable and c_i == 0,
- // let zeroDifferenceDetected(x_i) catch this
- d_congruenceManager.equalsConstant(constraint, ub);
+ ConstraintP ub = d_partialModel.getUpperBoundConstraint(x_i);
+
+ if(d_cmEnabled){
+ if(!d_congruenceManager.isWatchedVariable(x_i) || c_i.sgn() != 0){
+ // if it is not a watched variable report it
+ // if it is is a watched variable and c_i == 0,
+ // let zeroDifferenceDetected(x_i) catch this
+ d_congruenceManager.equalsConstant(constraint, ub);
+ }
}
const ValueCollection& vc = constraint->getValueCollection();
if(vc.hasDisequality()){
Assert(vc.hasEquality());
- const Constraint eq = vc.getEquality();
- const Constraint diseq = vc.getDisequality();
+ ConstraintP eq = vc.getEquality();
+ ConstraintP diseq = vc.getDisequality();
if(diseq->isTrue()){
- //const Constraint ub = vc.getUpperBound();
- Node conflict = ConstraintValue::explainConflict(diseq, ub, constraint);
+ //const ConstraintP ub = vc.getUpperBound();
+ raiseConflict(diseq, ub, constraint);
+ //Node conflict = ConstraintValue::explainConflict(diseq, ub, constraint);
++(d_statistics.d_statDisequalityConflicts);
- Debug("eq") << " assert lower conflict " << conflict << endl;
- raiseConflict(conflict);
+ //Debug("eq") << " assert lower conflict " << conflict << endl;
+ //raiseConflict(conflict);
return true;
}else if(!eq->isTrue()){
Debug("eq") << "lb == ub, propagate eq" << eq << endl;
@@ -370,17 +648,19 @@ bool TheoryArithPrivate::AssertLower(Constraint constraint){
const ValueCollection& vc = constraint->getValueCollection();
if(vc.hasDisequality()){
- const Constraint diseq = vc.getDisequality();
+ const ConstraintP diseq = vc.getDisequality();
if(diseq->isTrue()){
- const Constraint ub = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), UpperBound);
+ const ConstraintP ub = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), UpperBound);
if(ub->hasProof()){
- Node conflict = ConstraintValue::explainConflict(diseq, ub, constraint);
- Debug("eq") << " assert upper conflict " << conflict << endl;
- raiseConflict(conflict);
+ raiseConflict(diseq, ub, constraint);
return true;
+ // Node conflict = ConstraintValue::explainConflict(diseq, ub, constraint);
+ // Debug("eq") << " assert upper conflict " << conflict << endl;
+ // raiseConflict(conflict);
+ // return true;
}else if(!ub->negationHasProof()){
- Constraint negUb = ub->getNegation();
+ ConstraintP negUb = ub->getNegation();
negUb->impliedBy(constraint, diseq);
d_learnedBounds.push_back(negUb);
}
@@ -393,12 +673,14 @@ bool TheoryArithPrivate::AssertLower(Constraint constraint){
d_partialModel.setLowerBoundConstraint(constraint);
- if(d_congruenceManager.isWatchedVariable(x_i)){
- int sgn = c_i.sgn();
- if(sgn > 0){
- d_congruenceManager.watchedVariableCannotBeZero(constraint);
- }else if(sgn == 0 && d_partialModel.upperBoundIsZero(x_i)){
- zeroDifferenceDetected(x_i);
+ if(d_cmEnabled){
+ if(d_congruenceManager.isWatchedVariable(x_i)){
+ int sgn = c_i.sgn();
+ if(sgn > 0){
+ d_congruenceManager.watchedVariableCannotBeZero(constraint);
+ }else if(sgn == 0 && d_partialModel.upperBoundIsZero(x_i)){
+ zeroDifferenceDetected(x_i);
+ }
}
}
@@ -428,7 +710,7 @@ bool TheoryArithPrivate::AssertLower(Constraint constraint){
}
/* procedure AssertUpper( x_i <= c_i) */
-bool TheoryArithPrivate::AssertUpper(Constraint constraint){
+bool TheoryArithPrivate::AssertUpper(ConstraintP constraint){
ArithVar x_i = constraint->getVariable();
const DeltaRational& c_i = constraint->getValue();
@@ -450,34 +732,38 @@ bool TheoryArithPrivate::AssertUpper(Constraint constraint){
// 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)
- Constraint lbc = d_partialModel.getLowerBoundConstraint(x_i);
- Node conflict = ConstraintValue::explainConflict(lbc, constraint);
- Debug("arith") << "AssertUpper conflict " << conflict << endl;
+ ConstraintP lbc = d_partialModel.getLowerBoundConstraint(x_i);
+ raiseConflict(lbc, constraint);
+ //Node conflict = ConstraintValue::explainConflict(lbc, constraint);
+ //Debug("arith") << "AssertUpper conflict " << conflict << endl;
++(d_statistics.d_statAssertUpperConflicts);
- raiseConflict(conflict);
+ //raiseConflict(conflict);
return true;
}else if(cmpToLB == 0){ // \lowerBound(x_i) == \upperbound(x_i)
if(isInteger(x_i)){
d_constantIntegerVariables.push_back(x_i);
Debug("dio::push") << x_i << endl;
}
- Constraint lb = d_partialModel.getLowerBoundConstraint(x_i);
- if(!d_congruenceManager.isWatchedVariable(x_i) || c_i.sgn() != 0){
- // if it is not a watched variable report it
- // if it is is a watched variable and c_i == 0,
- // let zeroDifferenceDetected(x_i) catch this
- d_congruenceManager.equalsConstant(lb, constraint);
+ ConstraintP lb = d_partialModel.getLowerBoundConstraint(x_i);
+ if(d_cmEnabled){
+ if(!d_congruenceManager.isWatchedVariable(x_i) || c_i.sgn() != 0){
+ // if it is not a watched variable report it
+ // if it is is a watched variable and c_i == 0,
+ // let zeroDifferenceDetected(x_i) catch this
+ d_congruenceManager.equalsConstant(lb, constraint);
+ }
}
const ValueCollection& vc = constraint->getValueCollection();
if(vc.hasDisequality()){
Assert(vc.hasEquality());
- const Constraint diseq = vc.getDisequality();
- const Constraint eq = vc.getEquality();
+ const ConstraintP diseq = vc.getDisequality();
+ const ConstraintP eq = vc.getEquality();
if(diseq->isTrue()){
- Node conflict = ConstraintValue::explainConflict(diseq, lb, constraint);
- Debug("eq") << " assert upper conflict " << conflict << endl;
- raiseConflict(conflict);
+ raiseConflict(diseq, lb, constraint);
+ //Node conflict = ConstraintValue::explainConflict(diseq, lb, constraint);
+ //Debug("eq") << " assert upper conflict " << conflict << endl;
+ //raiseConflict(conflict);
return true;
}else if(!eq->isTrue()){
Debug("eq") << "lb == ub, propagate eq" << eq << endl;
@@ -488,17 +774,18 @@ bool TheoryArithPrivate::AssertUpper(Constraint constraint){
}else if(cmpToLB > 0){
const ValueCollection& vc = constraint->getValueCollection();
if(vc.hasDisequality()){
- const Constraint diseq = vc.getDisequality();
+ const ConstraintP diseq = vc.getDisequality();
if(diseq->isTrue()){
- const Constraint lb =
+ const ConstraintP lb =
d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), LowerBound);
if(lb->hasProof()){
- Node conflict = ConstraintValue::explainConflict(diseq, lb, constraint);
- Debug("eq") << " assert upper conflict " << conflict << endl;
- raiseConflict(conflict);
+ raiseConflict(diseq, lb, constraint);
+ //Node conflict = ConstraintValue::explainConflict(diseq, lb, constraint);
+ //Debug("eq") << " assert upper conflict " << conflict << endl;
+ //raiseConflict(conflict);
return true;
}else if(!lb->negationHasProof()){
- Constraint negLb = lb->getNegation();
+ ConstraintP negLb = lb->getNegation();
negLb->impliedBy(constraint, diseq);
d_learnedBounds.push_back(negLb);
}
@@ -512,13 +799,15 @@ bool TheoryArithPrivate::AssertUpper(Constraint constraint){
d_partialModel.setUpperBoundConstraint(constraint);
- if(d_congruenceManager.isWatchedVariable(x_i)){
- int sgn = c_i.sgn();
- if(sgn < 0){
- d_congruenceManager.watchedVariableCannotBeZero(constraint);
- }else if(sgn == 0 && d_partialModel.lowerBoundIsZero(x_i)){
- zeroDifferenceDetected(x_i);
- }
+ if(d_cmEnabled){
+ if(d_congruenceManager.isWatchedVariable(x_i)){
+ int sgn = c_i.sgn();
+ if(sgn < 0){
+ d_congruenceManager.watchedVariableCannotBeZero(constraint);
+ }else if(sgn == 0 && d_partialModel.lowerBoundIsZero(x_i)){
+ zeroDifferenceDetected(x_i);
+ }
+ }
}
d_updatedBounds.softAdd(x_i);
@@ -548,7 +837,7 @@ bool TheoryArithPrivate::AssertUpper(Constraint constraint){
/* procedure AssertEquality( x_i == c_i ) */
-bool TheoryArithPrivate::AssertEquality(Constraint constraint){
+bool TheoryArithPrivate::AssertEquality(ConstraintP constraint){
AssertArgument(constraint != NullConstraint,
"AssertUpper() called on a NullConstraint.");
@@ -570,18 +859,21 @@ bool TheoryArithPrivate::AssertEquality(Constraint constraint){
}
if(cmpToUB > 0){
- Constraint ubc = d_partialModel.getUpperBoundConstraint(x_i);
- Node conflict = ConstraintValue::explainConflict(ubc, constraint);
- Debug("arith") << "AssertEquality conflicts with upper bound " << conflict << endl;
- raiseConflict(conflict);
+ ConstraintP ubc = d_partialModel.getUpperBoundConstraint(x_i);
+ raiseConflict(ubc, constraint);
+ //Node conflict = ConstraintValue::explainConflict(ubc, constraint);
+ //Debug("arith") << "AssertEquality conflicts with upper bound " << conflict << endl;
+ //raiseConflict(conflict);
return true;
}
if(cmpToLB < 0){
- Constraint lbc = d_partialModel.getLowerBoundConstraint(x_i);
- Node conflict = ConstraintValue::explainConflict(lbc, constraint);
- Debug("arith") << "AssertEquality conflicts with lower bound" << conflict << endl;
- raiseConflict(conflict);
+ ConstraintP lbc = d_partialModel.getLowerBoundConstraint(x_i);
+ raiseConflict(lbc, constraint);
+
+ // Node conflict = ConstraintValue::explainConflict(lbc, constraint);
+ // Debug("arith") << "AssertEquality conflicts with lower bound" << conflict << endl;
+ // raiseConflict(conflict);
return true;
}
@@ -604,16 +896,18 @@ bool TheoryArithPrivate::AssertEquality(Constraint constraint){
d_partialModel.setUpperBoundConstraint(constraint);
d_partialModel.setLowerBoundConstraint(constraint);
- if(d_congruenceManager.isWatchedVariable(x_i)){
- int sgn = c_i.sgn();
- if(sgn == 0){
- zeroDifferenceDetected(x_i);
+ if(d_cmEnabled){
+ if(d_congruenceManager.isWatchedVariable(x_i)){
+ int sgn = c_i.sgn();
+ if(sgn == 0){
+ zeroDifferenceDetected(x_i);
+ }else{
+ d_congruenceManager.watchedVariableCannotBeZero(constraint);
+ d_congruenceManager.equalsConstant(constraint);
+ }
}else{
- d_congruenceManager.watchedVariableCannotBeZero(constraint);
d_congruenceManager.equalsConstant(constraint);
}
- }else{
- d_congruenceManager.equalsConstant(constraint);
}
d_updatedBounds.softAdd(x_i);
@@ -643,7 +937,7 @@ bool TheoryArithPrivate::AssertEquality(Constraint constraint){
/* procedure AssertDisequality( x_i != c_i ) */
-bool TheoryArithPrivate::AssertDisequality(Constraint constraint){
+bool TheoryArithPrivate::AssertDisequality(ConstraintP constraint){
AssertArgument(constraint != NullConstraint,
"AssertUpper() called on a NullConstraint.");
@@ -655,32 +949,35 @@ bool TheoryArithPrivate::AssertDisequality(Constraint constraint){
//Should be fine in integers
Assert(!isInteger(x_i) || c_i.isIntegral());
- if(d_congruenceManager.isWatchedVariable(x_i)){
- int sgn = c_i.sgn();
- if(sgn == 0){
- d_congruenceManager.watchedVariableCannotBeZero(constraint);
+ if(d_cmEnabled){
+ if(d_congruenceManager.isWatchedVariable(x_i)){
+ int sgn = c_i.sgn();
+ if(sgn == 0){
+ d_congruenceManager.watchedVariableCannotBeZero(constraint);
+ }
}
}
const ValueCollection& vc = constraint->getValueCollection();
if(vc.hasLowerBound() && vc.hasUpperBound()){
- const Constraint lb = vc.getLowerBound();
- const Constraint ub = vc.getUpperBound();
+ const ConstraintP lb = vc.getLowerBound();
+ const ConstraintP ub = vc.getUpperBound();
if(lb->isTrue() && ub->isTrue()){
//in conflict
Debug("eq") << "explaining" << endl;
++(d_statistics.d_statDisequalityConflicts);
- Node conflict = ConstraintValue::explainConflict(constraint, lb, ub);
- raiseConflict(conflict);
+ raiseConflict(constraint, lb, ub);
+ //Node conflict = ConstraintValue::explainConflict(constraint, lb, ub);
+ //raiseConflict(conflict);
return true;
}
}
if(vc.hasLowerBound() ){
- const Constraint lb = vc.getLowerBound();
+ const ConstraintP lb = vc.getLowerBound();
if(lb->isTrue()){
- const Constraint ub = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), UpperBound);
+ const ConstraintP ub = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), UpperBound);
Debug("eq") << "propagate UpperBound " << constraint << lb << ub << endl;
- const Constraint negUb = ub->getNegation();
+ const ConstraintP negUb = ub->getNegation();
if(!negUb->isTrue()){
negUb->impliedBy(constraint, lb);
d_learnedBounds.push_back(negUb);
@@ -688,12 +985,12 @@ bool TheoryArithPrivate::AssertDisequality(Constraint constraint){
}
}
if(vc.hasUpperBound()){
- const Constraint ub = vc.getUpperBound();
+ const ConstraintP ub = vc.getUpperBound();
if(ub->isTrue()){
- const Constraint lb = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), LowerBound);
+ const ConstraintP lb = d_constraintDatabase.ensureConstraint(const_cast<ValueCollection&>(vc), LowerBound);
Debug("eq") << "propagate LowerBound " << constraint << lb << ub << endl;
- const Constraint negLb = lb->getNegation();
+ const ConstraintP negLb = lb->getNegation();
if(!negLb->isTrue()){
negLb->impliedBy(constraint, ub);
d_learnedBounds.push_back(negLb);
@@ -930,28 +1227,23 @@ Theory::PPAssertStatus TheoryArithPrivate::ppAssert(TNode in, SubstitutionMap& o
Assert(elim == Rewriter::rewrite(elim));
- static const unsigned MAX_SUB_SIZE = 2;
+ static const unsigned MAX_SUB_SIZE = 20;
if(right.size() > MAX_SUB_SIZE){
Debug("simplify") << "TheoryArithPrivate::solve(): did not substitute due to the right hand side containing too many terms: " << minVar << ":" << elim << endl;
Debug("simplify") << right.size() << endl;
- // cout << "TheoryArithPrivate::solve(): did not substitute due to the right hand side containing too many terms: " << minVar << ":" << elim << endl;
- // cout << right.size() << endl;
}else if(elim.hasSubterm(minVar)){
Debug("simplify") << "TheoryArithPrivate::solve(): can't substitute due to recursive pattern with sharing: " << minVar << ":" << elim << endl;
- // cout << "TheoryArithPrivate::solve(): can't substitute due to recursive pattern with sharing: " << minVar << ":" << elim << endl;
}else if (!minVar.getType().isInteger() || right.isIntegral()) {
Assert(!elim.hasSubterm(minVar));
// cannot eliminate integers here unless we know the resulting
// substitution is integral
Debug("simplify") << "TheoryArithPrivate::solve(): substitution " << minVar << " |-> " << elim << endl;
- //cout << "TheoryArithPrivate::solve(): substitution " << minVar << " |-> " << elim << endl;
outSubstitutions.addSubstitution(minVar, elim);
return Theory::PP_ASSERT_STATUS_SOLVED;
} else {
Debug("simplify") << "TheoryArithPrivate::solve(): can't substitute b/c it's integer: " << minVar << ":" << minVar.getType() << " |-> " << elim << ":" << elim.getType() << endl;
- //cout << "TheoryArithPrivate::solve(): can't substitute b/c it's integer: " << minVar << ":" << minVar.getType() << " |-> " << elim << ":" << elim.getType() << endl;
}
}
@@ -1010,7 +1302,7 @@ void TheoryArithPrivate::setupVariable(const Variable& x){
Assert(!isSetup(n));
++(d_statistics.d_statUserVariables);
- requestArithVar(n,false);
+ requestArithVar(n, false, false);
//ArithVar varN = requestArithVar(n,false);
//setupInitialValue(varN);
@@ -1049,7 +1341,7 @@ void TheoryArithPrivate::setupVariableList(const VarList& vl){
d_nlIncomplete = true;
++(d_statistics.d_statUserVariables);
- requestArithVar(vlNode, false);
+ requestArithVar(vlNode, false, false);
//ArithVar av = requestArithVar(vlNode, false);
//setupInitialValue(av);
@@ -1242,7 +1534,7 @@ void TheoryArithPrivate::setupPolynomial(const Polynomial& poly) {
vector<Rational> coefficients;
asVectors(poly, coefficients, variables);
- ArithVar varSlack = requestArithVar(polyNode, true);
+ ArithVar varSlack = requestArithVar(polyNode, true, false);
d_tableau.addRow(varSlack, coefficients, variables);
setupBasicValue(varSlack);
d_linEq.trackRowIndex(d_tableau.basicToRowIndex(varSlack));
@@ -1267,7 +1559,7 @@ void TheoryArithPrivate::setupPolynomial(const Polynomial& poly) {
}
}
- ++(d_statistics.d_statSlackVariables);
+ ++(d_statistics.d_statAuxiliaryVariables);
markSetup(polyNode);
}
@@ -1306,9 +1598,9 @@ void TheoryArithPrivate::preRegisterTerm(TNode n) {
if(!isSetup(n)){
setupAtom(n);
}
- Constraint c = d_constraintDatabase.lookup(n);
+ ConstraintP c = d_constraintDatabase.lookup(n);
Assert(c != NullConstraint);
-
+
Debug("arith::preregister") << "setup constraint" << c << endl;
Assert(!c->canBePropagated());
c->setPreregistered();
@@ -1323,15 +1615,15 @@ void TheoryArithPrivate::preRegisterTerm(TNode n) {
}
void TheoryArithPrivate::releaseArithVar(ArithVar v){
- Assert(d_partialModel.hasNode(v));
+ //Assert(d_partialModel.hasNode(v));
d_constraintDatabase.removeVariable(v);
d_partialModel.releaseArithVar(v);
}
-ArithVar TheoryArithPrivate::requestArithVar(TNode x, bool slack){
+ArithVar TheoryArithPrivate::requestArithVar(TNode x, bool aux, bool internal){
//TODO : The VarList trick is good enough?
- Assert(isLeaf(x) || VarList::isMember(x) || x.getKind() == PLUS);
+ 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
@@ -1342,7 +1634,7 @@ ArithVar TheoryArithPrivate::requestArithVar(TNode x, bool slack){
Assert(x.getType().isReal()); // real or integer
ArithVar max = d_partialModel.getNumberOfVariables();
- ArithVar varX = d_partialModel.allocate(x, slack);
+ ArithVar varX = d_partialModel.allocate(x, aux);
bool reclaim = max >= d_partialModel.getNumberOfVariables();;
@@ -1354,7 +1646,9 @@ ArithVar TheoryArithPrivate::requestArithVar(TNode x, bool slack){
}
d_constraintDatabase.addVariable(varX);
- Debug("arith::arithvar") << x << " |-> " << varX << endl;
+ Debug("arith::arithvar") << "@" << getSatContext()->getLevel()
+ << " " << x << " |-> " << varX
+ << "(relaiming " << reclaim << ")" << endl;
Assert(!d_partialModel.hasUpperBound(varX));
Assert(!d_partialModel.hasLowerBound(varX));
@@ -1370,7 +1664,7 @@ void TheoryArithPrivate::asVectors(const Polynomial& p, std::vector<Rational>& c
Node n = variable.getNode();
- Debug("rewriter") << "should be var: " << n << endl;
+ Debug("arith::asVectors") << "should be var: " << n << endl;
// TODO: This VarList::isMember(n) can be stronger
Assert(isLeaf(n) || VarList::isMember(n));
@@ -1471,6 +1765,9 @@ Node TheoryArithPrivate::dioCutting(){
Comparison geq = Comparison::mkComparison(GEQ, p, c);
Node lemma = NodeManager::currentNM()->mkNode(OR, leq.getNode(), geq.getNode());
Node rewrittenLemma = Rewriter::rewrite(lemma);
+ Debug("arith::dio::ex") << "dioCutting found the plane: " << plane.getNode() << endl;
+ Debug("arith::dio::ex") << "resulting in the cut: " << lemma << endl;
+ Debug("arith::dio::ex") << "rewritten " << rewrittenLemma << endl;
Debug("arith::dio") << "dioCutting found the plane: " << plane.getNode() << endl;
Debug("arith::dio") << "resulting in the cut: " << lemma << endl;
Debug("arith::dio") << "rewritten " << rewrittenLemma << endl;
@@ -1489,16 +1786,16 @@ Node TheoryArithPrivate::callDioSolver(){
Assert(d_partialModel.boundsAreEqual(v));
- Constraint lb = d_partialModel.getLowerBoundConstraint(v);
- Constraint ub = d_partialModel.getUpperBoundConstraint(v);
+ ConstraintP lb = d_partialModel.getLowerBoundConstraint(v);
+ ConstraintP ub = d_partialModel.getUpperBoundConstraint(v);
Node orig = Node::null();
if(lb->isEquality()){
- orig = lb->explainForConflict();
+ orig = lb->externalExplainByAssertions();
}else if(ub->isEquality()){
- orig = ub->explainForConflict();
+ orig = ub->externalExplainByAssertions();
}else {
- orig = ConstraintValue::explainConflict(ub, lb);
+ orig = Constraint_::externalExplainByAssertions(ub, lb);
}
Assert(d_partialModel.assignmentIsConsistent(v));
@@ -1521,7 +1818,7 @@ Node TheoryArithPrivate::callDioSolver(){
return d_diosolver.processEquationsForConflict();
}
-Constraint TheoryArithPrivate::constraintFromFactQueue(){
+ConstraintP TheoryArithPrivate::constraintFromFactQueue(){
Assert(!done());
TNode assertion = get();
@@ -1530,7 +1827,7 @@ Constraint TheoryArithPrivate::constraintFromFactQueue(){
}
Kind simpleKind = Comparison::comparisonKind(assertion);
- Constraint constraint = d_constraintDatabase.lookup(assertion);
+ ConstraintP constraint = d_constraintDatabase.lookup(assertion);
if(constraint == NullConstraint){
Assert(simpleKind == EQUAL || simpleKind == DISTINCT );
bool isDistinct = simpleKind == DISTINCT;
@@ -1542,7 +1839,7 @@ Constraint TheoryArithPrivate::constraintFromFactQueue(){
// if is (not true), or false
Assert((reEq.getConst<bool>() && isDistinct) ||
(!reEq.getConst<bool>() && !isDistinct));
- raiseConflict(assertion);
+ blackBoxConflict(assertion);
}
return NullConstraint;
}
@@ -1563,7 +1860,7 @@ Constraint TheoryArithPrivate::constraintFromFactQueue(){
Assert(constraint != NullConstraint);
if(constraint->negationHasProof()){
- Constraint negation = constraint->getNegation();
+ ConstraintP negation = constraint->getNegation();
if(negation->isSelfExplaining()){
if(Debug.isOn("whytheoryenginewhy")){
debugPrintFacts();
@@ -1572,12 +1869,21 @@ Constraint TheoryArithPrivate::constraintFromFactQueue(){
Debug("arith::eq") << constraint << endl;
Debug("arith::eq") << negation << endl;
- NodeBuilder<> nb(kind::AND);
- nb << assertion;
- negation->explainForConflict(nb);
- Node conflict = nb;
- Debug("arith::eq") << "conflict" << conflict << endl;
- raiseConflict(conflict);
+ constraint->setAssertedToTheTheoryWithNegationTrue(assertion);
+ if(!constraint->hasProof()){
+ Debug("arith::constraint") << "marking as constraint as self explaining " << endl;
+ constraint->selfExplainingWithNegationTrue();
+ }else{
+ Debug("arith::constraint") << "already has proof: " << constraint->externalExplainByAssertions() << endl;
+ }
+
+ raiseConflict(constraint, negation);
+ // NodeBuilder<> nb(kind::AND);
+ // nb << assertion;
+ // negation->explainForConflict(nb);
+ // Node conflict = nb;
+ // Debug("arith::eq") << "conflict" << conflict << endl;
+ // raiseConflict(conflict);
return NullConstraint;
}
Assert(!constraint->negationHasProof());
@@ -1593,14 +1899,14 @@ Constraint TheoryArithPrivate::constraintFromFactQueue(){
Debug("arith::constraint") << "marking as constraint as self explaining " << endl;
constraint->selfExplaining();
}else{
- Debug("arith::constraint") << "already has proof: " << constraint->explainForConflict() << endl;
+ Debug("arith::constraint") << "already has proof: " << constraint->externalExplainByAssertions() << endl;
}
return constraint;
}
}
-bool TheoryArithPrivate::assertionCases(Constraint constraint){
+bool TheoryArithPrivate::assertionCases(ConstraintP constraint){
Assert(constraint->hasProof());
Assert(!constraint->negationHasProof());
@@ -1609,11 +1915,12 @@ bool TheoryArithPrivate::assertionCases(Constraint constraint){
switch(constraint->getType()){
case UpperBound:
if(isInteger(x_i) && constraint->isStrictUpperBound()){
- Constraint floorConstraint = constraint->getFloor();
+ ConstraintP floorConstraint = constraint->getFloor();
if(!floorConstraint->isTrue()){
if(floorConstraint->negationHasProof()){
- Node conf = ConstraintValue::explainConflict(constraint, floorConstraint->getNegation());
- raiseConflict(conf);
+ raiseConflict(constraint, floorConstraint->getNegation());
+ //Node conf = Constraint_::explainConflict(constraint, floorConstraint->getNegation());
+ //raiseConflict(conf);
return true;
}else{
floorConstraint->impliedBy(constraint);
@@ -1626,11 +1933,12 @@ bool TheoryArithPrivate::assertionCases(Constraint constraint){
}
case LowerBound:
if(isInteger(x_i) && constraint->isStrictLowerBound()){
- Constraint ceilingConstraint = constraint->getCeiling();
+ ConstraintP ceilingConstraint = constraint->getCeiling();
if(!ceilingConstraint->isTrue()){
if(ceilingConstraint->negationHasProof()){
- Node conf = ConstraintValue::explainConflict(constraint, ceilingConstraint->getNegation());
- raiseConflict(conf);
+ raiseConflict(constraint, ceilingConstraint->getNegation());
+ //Node conf = Constraint_::explainConflict(constraint, ceilingConstraint->getNegation());
+ //raiseConflict(conf);
return true;
}
ceilingConstraint->impliedBy(constraint);
@@ -1649,168 +1957,1165 @@ bool TheoryArithPrivate::assertionCases(Constraint constraint){
return false;
}
}
-
/**
- * Looks for the next integer variable without an integer assignment in a round robin fashion.
- * Changes the value of d_nextIntegerCheckVar.
+ * Looks for through the variables starting at d_nextIntegerCheckVar
+ * for the first integer variable that is between its upper and lower bounds
+ * that has a non-integer assignment.
+ *
+ * If assumeBounds is true, skip the check that the variable is in bounds.
*
- * If this returns false, d_nextIntegerCheckVar does not have an integer assignment.
- * If this returns true, all integer variables have an integer assignment.
+ * If there is no such variable, returns ARITHVAR_SENTINEL;
*/
-bool TheoryArithPrivate::hasIntegerModel(){
- //if(d_variables.size() > 0){
+ArithVar TheoryArithPrivate::nextIntegerViolatation(bool assumeBounds) const {
ArithVar numVars = d_partialModel.getNumberOfVariables();
+ ArithVar v = d_nextIntegerCheckVar;
if(numVars > 0){
const ArithVar rrEnd = d_nextIntegerCheckVar;
do {
- //Do not include slack variables
- if(isInteger(d_nextIntegerCheckVar) && !isSlackVariable(d_nextIntegerCheckVar)) { // integer
- const DeltaRational& d = d_partialModel.getAssignment(d_nextIntegerCheckVar);
- if(!d.isIntegral()){
- return false;
+ if(isIntegerInput(v)){
+ if(!d_partialModel.integralAssignment(v)){
+ if( assumeBounds || d_partialModel.assignmentIsConsistent(v) ){
+ return v;
+ }
}
}
- } while((d_nextIntegerCheckVar = (1 + d_nextIntegerCheckVar == numVars ? 0 : 1 + d_nextIntegerCheckVar)) != rrEnd);
+ v= (1 + v == numVars) ? 0 : (1 + v);
+ }while(v != rrEnd);
+ }
+ return ARITHVAR_SENTINEL;
+}
+
+/**
+ * Checks the set of integer variables I to see if each variable
+ * in I has an integer assignment.
+ */
+bool TheoryArithPrivate::hasIntegerModel(){
+ ArithVar next = nextIntegerViolatation(true);
+ if(next != ARITHVAR_SENTINEL){
+ d_nextIntegerCheckVar = next;
+ if(Debug.isOn("arith::hasIntegerModel")){
+ Debug("arith::hasIntegerModel") << "has int model? " << next << endl;
+ d_partialModel.printModel(next, Debug("arith::hasIntegerModel"));
+ }
+ return false;
+ }else{
+ return true;
}
- return true;
}
/** Outputs conflicts to the output channel. */
void TheoryArithPrivate::outputConflicts(){
- Assert(!d_conflicts.empty());
- for(size_t i = 0, i_end = d_conflicts.size(); i < i_end; ++i){
- Node conflict = d_conflicts[i];
- Debug("arith::conflict") << "d_conflicts[" << i << "] " << conflict << endl;
- (d_containing.d_out)->conflict(conflict);
- }
-}
-
-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);
+ Assert(anyConflict());
+ if(!conflictQueueEmpty()){
+ Assert(!d_conflicts.empty());
+ for(size_t i = 0, i_end = d_conflicts.size(); i < i_end; ++i){
+ const ConstraintCPVec& vec = d_conflicts[i];
+ Node conflict = Constraint_::externalExplainByAssertions(vec);
+ Debug("arith::conflict") << "d_conflicts[" << i << "] " << conflict << endl;
+ (d_containing.d_out)->conflict(conflict);
+ }
+ }
+ if(!d_blackBoxConflict.get().isNull()){
+ Node bb = d_blackBoxConflict.get();
+ Debug("arith::conflict") << "black box conflict" << bb << endl;
+ (d_containing.d_out)->conflict(bb);
}
}
+void TheoryArithPrivate::outputLemma(TNode lem) {
+ (d_containing.d_out)->lemma(lem);
+}
-bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
- Assert(d_qflraStatus != Result::SAT);
+// 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")
+ << "attemptSolveInteger " << d_qflraStatus
+ << " " << emmmittedLemmaOrSplit
+ << " " << effortLevel
+ << " " << d_lastContextIntegerAttempted
+ << " " << level
+ << " " << hasIntegerModel()
+ << endl;
+
+ if(d_qflraStatus == Result::UNSAT){ return false; }
+ if(emmmittedLemmaOrSplit){ return false; }
+ if(!options::useApprox()){ return false; }
+ if(!ApproximateSimplex::enabled()){ return false; }
+
+ if(Theory::fullEffort(effortLevel)){
+ if(hasIntegerModel()){
+ return false;
+ }else{
+ return getSolveIntegerResource();
+ }
+ }
- d_partialModel.stopQueueingBoundCounts();
- UpdateTrackingCallback utcb(&d_linEq);
- d_partialModel.processBoundsQueue(utcb);
- d_linEq.startTrackingBoundCounts();
+ if(d_lastContextIntegerAttempted <= 0){
+ if(hasIntegerModel()){
+ d_lastContextIntegerAttempted = getSatContext()->getLevel();
+ return false;
+ }else{
+ return getSolveIntegerResource();
+ }
+ }
- bool noPivotLimit = Theory::fullEffort(effortLevel) ||
- !options::restrictedPivots();
- bool emmittedConflictOrSplit = false;
+ if(!options::trySolveIntStandardEffort()){ return false; }
+
+ if (d_lastContextIntegerAttempted <= (level >> 2)){
+
+ double d = (double)(d_solveIntMaybeHelp + 1) / (d_solveIntAttempts + 1 + level*level);
+ double t = fRand(0.0, 1.0);
+ if(t < d){
+ return getSolveIntegerResource();
+ }
+ }
+ return false;
+}
- SimplexDecisionProcedure& simplex =
- options::useFC() ? (SimplexDecisionProcedure&)d_fcSimplex :
- (options::useSOI() ? (SimplexDecisionProcedure&)d_soiSimplex :
- (SimplexDecisionProcedure&)d_dualSimplex);
+bool TheoryArithPrivate::replayLog(ApproximateSimplex* approx){
+ TimerStat::CodeTimer codeTimer(d_statistics.d_replayLogTimer);
- bool useFancyFinal = options::fancyFinal() && ApproximateSimplex::enabled();
+ Assert(d_replayVariables.empty());
+ Assert(d_replayConstraints.empty());
- if(!useFancyFinal){
- d_qflraStatus = simplex.findModel(noPivotLimit);
+ size_t enteringPropN = d_currentPropagationList.size();
+ Assert(conflictQueueEmpty());
+ TreeLog& tl = getTreeLog();
+ //tl.applySelected(); /* set row ids */
+
+ d_replayedLemmas = false;
+
+ std::vector<ConstraintCPVec> res;
+ try{
+ /* use the try block for the purpose of pushing the sat context */
+ context::Context::ScopedPush speculativePush(getSatContext());
+ d_cmEnabled = false;
+ res = replayLogRec(approx, tl.getRootId(), NullConstraint, 1);
+ }catch(RationalFromDoubleException& rfde){
+ turnOffApproxFor(options::replayNumericFailurePenalty());
+ }
+
+ for(size_t i =0, N = res.size(); i < N; ++i){
+ raiseConflict(res[i]);
+ }
+ if(res.empty()){
+ ++d_statistics.d_replayAttemptFailed;
+ }
+ if(d_currentPropagationList.size() > enteringPropN){
+ d_currentPropagationList.resize(enteringPropN);
+ }
+
+ Assert(d_replayVariables.empty());
+ Assert(d_replayConstraints.empty());
+
+ return !conflictQueueEmpty();
+}
+
+std::pair<ConstraintP, ArithVar> TheoryArithPrivate::replayGetConstraint(const DenseMap<Rational>& lhs, Kind k, const Rational& rhs, bool branch)
+{
+ ArithVar added = ARITHVAR_SENTINEL;
+ Node sum = toSumNode(d_partialModel, lhs);
+ if(sum.isNull()){ return make_pair(NullConstraint, added); }
+
+ Node norm = Rewriter::rewrite(sum);
+ DeltaRational dr(rhs);
+
+ ConstraintType t = (k == kind::LEQ) ? UpperBound : LowerBound;
+
+ Assert(!branch || d_partialModel.hasArithVar(norm));
+ ArithVar v = ARITHVAR_SENTINEL;
+ if(d_partialModel.hasArithVar(norm)){
+
+ v = d_partialModel.asArithVar(norm);
+ Debug("approx::constraint") << "replayGetConstraint found "
+ << norm << " |-> " << v << " @ " << getSatContext()->getLevel() << endl;
+ Assert(!branch || d_partialModel.isIntegerInput(v));
}else{
- // Fancy final tries the following strategy
- // At final check, try the preferred simplex solver with a pivot cap
- // If that failed, swap the the other simplex solver
- // If that failed, check if there are integer variables to cut
- // If that failed, do a simplex without a pivot limit
+ v = requestArithVar(norm, true, true);
+ d_replayVariables.push_back(v);
- int16_t oldCap = options::arithStandardCheckVarOrderPivots();
+ added = v;
- static const int32_t pass2Limit = 10;
- static const int32_t relaxationLimit = 10000;
- static const int32_t mipLimit = 200000;
+ Debug("approx::constraint") << "replayGetConstraint adding "
+ << norm << " |-> " << v << " @ " << getSatContext()->getLevel() << endl;
- //cout << "start" << endl;
- d_qflraStatus = simplex.findModel(false);
- //cout << "end" << endl;
- if(d_qflraStatus == Result::SAT_UNKNOWN ||
- (d_qflraStatus == Result::SAT && !hasIntegerModel() && !d_likelyIntegerInfeasible)){
+ Polynomial poly = Polynomial::parsePolynomial(norm);
+ vector<ArithVar> variables;
+ vector<Rational> coefficients;
+ asVectors(poly, coefficients, variables);
+ d_tableau.addRow(v, coefficients, variables);
+ setupBasicValue(v);
+ d_linEq.trackRowIndex(d_tableau.basicToRowIndex(v));
+ }
+ Assert(d_partialModel.hasArithVar(norm));
+ Assert(d_partialModel.asArithVar(norm) == v);
+ Assert(d_constraintDatabase.variableDatabaseIsSetup(v));
+
+ ConstraintP imp = d_constraintDatabase.getBestImpliedBound(v, t, dr);
+ if(imp != NullConstraint){
+ if(imp->getValue() == dr){
+ Assert(added == ARITHVAR_SENTINEL);
+ return make_pair(imp, added);
+ }
+ }
+ ConstraintP newc = d_constraintDatabase.getConstraint(v, t, dr);
+ d_replayConstraints.push_back(newc);
+ return make_pair(newc, added);
+}
+
+std::pair<ConstraintP, ArithVar> TheoryArithPrivate::replayGetConstraint(ApproximateSimplex* approx, const NodeLog& nl) throw(RationalFromDoubleException){
+ Assert(nl.isBranch());
+ Assert(d_lhsTmp.empty());
+
+ ArithVar v = approx->getBranchVar(nl);
+ if(v != ARITHVAR_SENTINEL && d_partialModel.isIntegerInput(v)){
+ if(d_partialModel.hasNode(v)){
+ d_lhsTmp.set(v, Rational(1));
+ double dval = nl.branchValue();
+ Rational val = ApproximateSimplex::estimateWithCFE(dval);
+ Rational fl(val.floor());
+ pair<ConstraintP, ArithVar> p;
+ p = replayGetConstraint(d_lhsTmp, kind::LEQ, fl, true);
+ d_lhsTmp.purge();
+ return p;
+ }
+ }
+ return make_pair(NullConstraint, ARITHVAR_SENTINEL);
+}
+
+std::pair<ConstraintP, ArithVar> TheoryArithPrivate::replayGetConstraint(const CutInfo& ci) {
+ Assert(ci.reconstructed());
+ const DenseMap<Rational>& lhs = ci.getReconstruction().lhs;
+ const Rational& rhs = ci.getReconstruction().rhs;
+ Kind k = ci.getKind();
+
+ return replayGetConstraint(lhs, k, rhs, ci.getKlass() == BranchCutKlass);
+}
+
+// Node denseVectorToLiteral(const ArithVariables& vars, const DenseVector& dv, Kind k){
+// NodeManager* nm = NodeManager::currentNM();
+// Node sumLhs = toSumNode(vars, dv.lhs);
+// Node ineq = nm->mkNode(k, sumLhs, mkRationalNode(dv.rhs) );
+// Node lit = Rewriter::rewrite(ineq);
+// return lit;
+// }
+
+Node toSumNode(const ArithVariables& vars, const DenseMap<Rational>& sum){
+ NodeBuilder<> nb(kind::PLUS);
+ NodeManager* nm = NodeManager::currentNM();
+ DenseMap<Rational>::const_iterator iter, end;
+ iter = sum.begin(), end = sum.end();
+ for(; iter != end; ++iter){
+ ArithVar x = *iter;
+ if(!vars.hasNode(x)){ return Node::null(); }
+ Node xNode = vars.asNode(x);
+ const Rational& q = sum[x];
+ nb << nm->mkNode(kind::MULT, mkRationalNode(q), xNode);
+ }
+ return safeConstructNary(nb);
+}
+
+
+void TheoryArithPrivate::tryBranchCut(ApproximateSimplex* approx, int nid, BranchCutInfo& bci){
+ Assert(conflictQueueEmpty());
+ std::vector< ConstraintCPVec > conflicts;
+
+ approx->tryCut(nid, bci);
+ Debug("approx::branch") << "tryBranchCut" << bci << endl;
+ Assert(bci.reconstructed());
+ Assert(!bci.proven());
+ pair<ConstraintP, ArithVar> p = replayGetConstraint(bci);
+ Assert(p.second == ARITHVAR_SENTINEL);
+ ConstraintP bc = p.first;
+ Assert(bc != NullConstraint);
+ if(bc->hasProof()){
+ return;
+ }
+
+ ConstraintP bcneg = bc->getNegation();
+ {
+ context::Context::ScopedPush speculativePush(getSatContext());
+ replayAssert(bcneg);
+ if(conflictQueueEmpty()){
+ TimerStat::CodeTimer codeTimer(d_statistics.d_replaySimplexTimer);
+
+ //test for linear feasibility
+ d_partialModel.stopQueueingBoundCounts();
+ UpdateTrackingCallback utcb(&d_linEq);
+ d_partialModel.processBoundsQueue(utcb);
+ d_linEq.startTrackingBoundCounts();
+
+ SimplexDecisionProcedure& simplex = selectSimplex(true);
+ simplex.findModel(false);
+
+ d_linEq.stopTrackingBoundCounts();
+ d_partialModel.startQueueingBoundCounts();
+ }
+ for(size_t i = 0, N = d_conflicts.size(); i < N; ++i){
+ conflicts.push_back(d_conflicts[i]);
+ // remove the floor/ceiling contraint implied by bcneg
+ Constraint_::assertionFringe(conflicts.back());
+ }
+
+ if(Debug.isOn("approx::branch")){
+ if(d_conflicts.empty()){
+ entireStateIsConsistent("branchfailure");
+ }
+ }
+ }
+
+ Debug("approx::branch") << "branch constraint " << bc << endl;
+ for(size_t i = 0, N = conflicts.size(); i < N; ++i){
+ ConstraintCPVec& conf = conflicts[i];
+
+ // make sure to be working on the assertion fringe!
+ if(!contains(conf, bcneg)){
+ Debug("approx::branch") << "reraise " << conf << endl;
+ raiseConflict(conf);
+ }else if(!bci.proven()){
+ drop(conf, bcneg);
+ bci.setExplanation(conf);
+ Debug("approx::branch") << "dropped " << bci << endl;
+ }
+ }
+}
- ApproximateSimplex* approxSolver = ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel);
- approxSolver->setPivotLimit(relaxationLimit);
+void TheoryArithPrivate::replayAssert(ConstraintP c) {
+ if(!c->assertedToTheTheory()){
+ if(c->negationHasProof()){
+ ConstraintP neg = c->getNegation();
+ raiseConflict(c, neg);
+ Debug("approx::replayAssert") << "replayAssertion conflict " << neg << " : " << c << endl;
+ }else if(!c->hasProof()){
+ c->setInternalDecision();
+ assertionCases(c);
+ Debug("approx::replayAssert") << "replayAssert " << c << " set internal" << endl;
+ }else{
+ assertionCases(c);
+ Debug("approx::replayAssert") << "replayAssert " << c << " has explanation" << endl;
+ }
+ }else{
+ Debug("approx::replayAssert") << "replayAssert " << c << " already asserted" << endl;
+ }
+}
+
+// ConstraintCPVec TheoryArithPrivate::toExplanation(Node n) const {
+// ConstraintCPVec res;
+// cout << "toExplanation" << endl;
+// if(n.getKind() == kind::AND){
+// for(unsigned i = 0; i < n.getNumChildren(); ++i){
+// ConstraintP c = d_constraintDatabase.lookup(n[i]);
+// if(c == NullConstraint){ return std::vector<Constraint>(); }
+// res.push_back(c);
+// cout << "\t"<<c << endl;
+// }
+// }else{
+// ConstraintP c = d_constraintDatabase.lookup(n);
+// if(c == NullConstraint){ return std::vector<Constraint>(); }
+// res.push_back(c);
+// }
+// return res;
+// }
+
+// void TheoryArithPrivate::enqueueConstraints(std::vector<Constraint>& out, Node n) const{
+// if(n.getKind() == kind::AND){
+// for(unsigned i = 0, N = n.getNumChildren(); i < N; ++i){
+// enqueueConstraints(out, n[i]);
+// }
+// }else{
+// ConstraintP c = d_constraintDatabase.lookup(n);
+// if(c == NullConstraint){
+// cout << "failing on " << n << endl;
+// }
+// Assert(c != NullConstraint);
+// out.push_back(c);
+// }
+// }
+
+// ConstraintCPVec TheoryArithPrivate::resolveOutPropagated(const ConstraintCPVec& v, const std::set<ConstraintCP>& propagated) const {
+// cout << "resolveOutPropagated()" << conf << endl;
+// std::set<ConstraintCP> final;
+// std::set<ConstraintCP> processed;
+// std::vector<ConstraintCP> to_process;
+// enqueueConstraints(to_process, conf);
+// while(!to_process.empty()){
+// ConstraintP c = to_process.back(); to_process.pop_back();
+// if(processed.find(c) != processed.end()){
+// continue;
+// }else{
+// if(propagated.find(c) == propagated.end()){
+// final.insert(c);
+// }else{
+// Node exp = c->explainForPropagation();
+// enqueueConstraints(to_process, exp);
+// }
+// processed.insert(c);
+// }
+// }
+// cout << "final size: " << final.size() << std::endl;
+// NodeBuilder<> nb(kind::AND);
+// std::set<Constraint>::const_iterator iter = final.begin(), end = final.end();
+// for(; iter != end; ++iter){
+// ConstraintP c = *iter;
+// c->explainForConflict(nb);
+// }
+// Node newConf = safeConstructNary(nb);
+// cout << "resolveOutPropagated("<<conf<<", ...) ->" << newConf << endl;
+// return newConf;
+// }
+
+void TheoryArithPrivate::resolveOutPropagated(std::vector<ConstraintCPVec>& confs, const std::set<ConstraintCP>& propagated) const {
+ Debug("arith::resolveOutPropagated")
+ << "starting resolveOutPropagated() " << confs.size() << endl;
+ for(size_t i =0, N = confs.size(); i < N; ++i){
+ ConstraintCPVec& conf = confs[i];
+ size_t orig = conf.size();
+ Constraint_::assertionFringe(conf);
+ Debug("arith::resolveOutPropagated")
+ << " conf["<<i<<"] " << orig << " to " << conf.size() << endl;
+ }
+ Debug("arith::resolveOutPropagated")
+ << "ending resolveOutPropagated() " << confs.size() << endl;
+}
- if(!d_guessedCoeffSet){
- d_guessedCoeffs = approxSolver->heuristicOptCoeffs();
- d_guessedCoeffSet = true;
+struct SizeOrd {
+ bool operator()(const ConstraintCPVec& a, const ConstraintCPVec& b) const{
+ return a.size() < b.size();
+ }
+};
+void TheoryArithPrivate::subsumption(std::vector<ConstraintCPVec>& confs) const {
+ int checks CVC4_UNUSED = 0;
+ int subsumed CVC4_UNUSED = 0;
+
+ for(size_t i =0, N= confs.size(); i < N; ++i){
+ ConstraintCPVec& conf = confs[i];
+ std::sort(conf.begin(), conf.end());
+ }
+
+ std::sort(confs.begin(), confs.end(), SizeOrd());
+ for(size_t i = 0; i < confs.size(); i++){
+ ConstraintCPVec& a = confs[i];
+ // i is not subsumed
+ for(size_t j = i+1; j < confs.size();){
+ ConstraintCPVec& b = confs[j];
+ checks++;
+ bool subsumes = std::includes(a.begin(), a.end(), b.begin(), b.end());
+ if(subsumes){
+ ConstraintCPVec& back = confs.back();
+ b.swap(back);
+ confs.pop_back();
+ subsumed++;
+ }else{
+ j++;
}
- if(!d_guessedCoeffs.empty()){
- approxSolver->setOptCoeffs(d_guessedCoeffs);
+ }
+ }
+ Debug("arith::subsumption") << "subsumed " << subsumed << "/" << checks << endl;
+}
+
+std::vector<ConstraintCPVec> TheoryArithPrivate::replayLogRec(ApproximateSimplex* approx, int nid, ConstraintP bc, int depth){
+ ++(d_statistics.d_replayLogRecCount);
+ Debug("approx::replayLogRec") << "replayLogRec()"
+ << d_statistics.d_replayLogRecCount.getData() << std::endl;
+
+ size_t rpvars_size = d_replayVariables.size();
+ size_t rpcons_size = d_replayConstraints.size();
+ std::vector<ConstraintCPVec> res;
+
+ { /* create a block for the purpose of pushing the sat context */
+ context::Context::ScopedPush speculativePush(getSatContext());
+ Assert(!anyConflict());
+ Assert(conflictQueueEmpty());
+ set<ConstraintCP> propagated;
+
+ TreeLog& tl = getTreeLog();
+
+ if(bc != NullConstraint){
+ replayAssert(bc);
+ }
+
+ const NodeLog& nl = tl.getNode(nid);
+ NodeLog::const_iterator iter = nl.begin(), end = nl.end();
+ for(; conflictQueueEmpty() && iter != end; ++iter){
+ CutInfo* ci = *iter;
+ bool reject = false;
+ //cout << " trying " << *ci << endl;
+ if(ci->getKlass() == RowsDeletedKlass){
+ RowsDeleted* rd = dynamic_cast<RowsDeleted*>(ci);
+
+ tl.applyRowsDeleted(nid, *rd);
+ // The previous line modifies nl
+
+ ++d_statistics.d_applyRowsDeleted;
+ }else if(ci->getKlass() == BranchCutKlass){
+ BranchCutInfo* bci = dynamic_cast<BranchCutInfo*>(ci);
+ Assert(bci != NULL);
+ tryBranchCut(approx, nid, *bci);
+
+ ++d_statistics.d_branchCutsAttempted;
+ }else{
+ approx->tryCut(nid, *ci);
+ if(ci->getKlass() == GmiCutKlass){
+ ++d_statistics.d_gmiCutsAttempted;
+ }else if(ci->getKlass() == MirCutKlass){
+ ++d_statistics.d_mirCutsAttempted;
+ }
+
+ if(ci->reconstructed() && ci->proven()){
+ const DenseMap<Rational>& row = ci->getReconstruction().lhs;
+ reject = !complexityBelow(row, options::replayRejectCutSize());
+ }
}
+ if(conflictQueueEmpty()){
+ if(reject){
+ ++d_statistics.d_cutsRejectedDuringReplay;
+ }else if(ci->reconstructed()){
+ // success
+ ++d_statistics.d_cutsReconstructed;
+
+ pair<ConstraintP, ArithVar> p = replayGetConstraint(*ci);
+ if(p.second != ARITHVAR_SENTINEL){
+ Assert(ci->getRowId() >= 1);
+ tl.mapRowId(nl.getNodeId(), ci->getRowId(), p.second);
+ }
+ ConstraintP con = p.first;
+ if(Debug.isOn("approx::replayLogRec")){
+ Debug("approx::replayLogRec") << "cut was remade " << con << " " << *ci << endl;
+ }
- ApproximateSimplex::ApproxResult relaxRes, mipRes;
- ApproximateSimplex::Solution relaxSolution, mipSolution;
- relaxRes = approxSolver->solveRelaxation();
- switch(relaxRes){
- case ApproximateSimplex::ApproxSat:
- {
- relaxSolution = approxSolver->extractRelaxation();
+ if(ci->proven()){
+ ++d_statistics.d_cutsProven;
- if(d_likelyIntegerInfeasible){
- d_qflraStatus = d_attemptSolSimplex.attempt(relaxSolution);
+ const ConstraintCPVec& exp = ci->getExplanation();
+ // success
+ Assert(!con->negationHasProof());
+ if(con->isTrue()){
+ Debug("approx::replayLogRec") << "not asserted?" << endl;
+ }else{
+ con->impliedBy(exp);
+ replayAssert(con);
+ Debug("approx::replayLogRec") << "cut prop" << endl;
+ }
}else{
- approxSolver->setPivotLimit(mipLimit);
- mipRes = approxSolver->solveMIP();
- d_errorSet.reduceToSignals();
- //Message() << "here" << endl;
- if(mipRes == ApproximateSimplex::ApproxSat){
- mipSolution = approxSolver->extractMIP();
- d_qflraStatus = d_attemptSolSimplex.attempt(mipSolution);
+ ++d_statistics.d_cutsProofFailed;
+ Debug("approx::replayLogRec") << "failed to get proof " << *ci << endl;
+ }
+ }else if(ci->getKlass() != RowsDeletedKlass){
+ ++d_statistics.d_cutsReconstructionFailed;
+ }
+ }
+ }
+
+ /* check if the system is feasible under with the cuts */
+ if(conflictQueueEmpty()){
+ Assert(options::replayEarlyCloseDepths() >= 1);
+ if(!nl.isBranch() || depth % options::replayEarlyCloseDepths() == 0 ){
+ TimerStat::CodeTimer codeTimer(d_statistics.d_replaySimplexTimer);
+ //test for linear feasibility
+ d_partialModel.stopQueueingBoundCounts();
+ UpdateTrackingCallback utcb(&d_linEq);
+ d_partialModel.processBoundsQueue(utcb);
+ d_linEq.startTrackingBoundCounts();
+
+ SimplexDecisionProcedure& simplex = selectSimplex(true);
+ simplex.findModel(false);
+
+ d_linEq.stopTrackingBoundCounts();
+ d_partialModel.startQueueingBoundCounts();
+ }
+ }else{
+ ++d_statistics.d_replayLogRecConflictEscalation;
+ }
+
+ if(!conflictQueueEmpty()){
+ /* if a conflict has been found stop */
+ for(size_t i = 0, N = d_conflicts.size(); i < N; ++i){
+ res.push_back(d_conflicts[i]);
+ }
+ ++d_statistics.d_replayLogRecEarlyExit;
+ }else if(nl.isBranch()){
+ /* if it is a branch try the branch */
+ pair<ConstraintP, ArithVar> p = replayGetConstraint(approx, nl);
+ Assert(p.second == ARITHVAR_SENTINEL);
+ ConstraintP dnc = p.first;
+ if(dnc != NullConstraint){
+ ConstraintP upc = dnc->getNegation();
+
+ int dnid = nl.getDownId();
+ int upid = nl.getUpId();
+
+ NodeLog& dnlog = tl.getNode(dnid);
+ NodeLog& uplog = tl.getNode(upid);
+ dnlog.copyParentRowIds();
+ uplog.copyParentRowIds();
+
+ std::vector<ConstraintCPVec> dnres;
+ std::vector<ConstraintCPVec> upres;
+ std::vector<size_t> containsdn;
+ std::vector<size_t> containsup;
+ if(res.empty()){
+ dnres = replayLogRec(approx, dnid, dnc, depth+1);
+ for(size_t i = 0, N = dnres.size(); i < N; ++i){
+ ConstraintCPVec& conf = dnres[i];
+ if(contains(conf, dnc)){
+ containsdn.push_back(i);
}else{
- if(mipRes == ApproximateSimplex::ApproxUnsat){
- d_likelyIntegerInfeasible = true;
- }
- d_qflraStatus = d_attemptSolSimplex.attempt(relaxSolution);
+ res.push_back(conf);
}
}
- options::arithStandardCheckVarOrderPivots.set(pass2Limit);
- if(d_qflraStatus != Result::UNSAT){ d_qflraStatus = simplex.findModel(false); }
- //Message() << "done" << endl;
+ }else{
+ Debug("approx::replayLogRec") << "replayLogRec() skipping" << dnlog << std::endl;
+ ++d_statistics.d_replayBranchSkips;
}
- break;
- case ApproximateSimplex::ApproxUnsat:
- {
- ApproximateSimplex::Solution sol = approxSolver->extractRelaxation();
- d_qflraStatus = d_attemptSolSimplex.attempt(sol);
- options::arithStandardCheckVarOrderPivots.set(pass2Limit);
+ if(res.empty()){
+ upres = replayLogRec(approx, upid, upc, depth+1);
+
+ for(size_t i = 0, N = upres.size(); i < N; ++i){
+ ConstraintCPVec& conf = upres[i];
+ if(contains(conf, upc)){
+ containsup.push_back(i);
+ }else{
+ res.push_back(conf);
+ }
+ }
+ }else{
+ Debug("approx::replayLogRec") << "replayLogRec() skipping" << uplog << std::endl;
+ ++d_statistics.d_replayBranchSkips;
+ }
+
+ if(res.empty()){
+ for(size_t i = 0, N = containsdn.size(); i < N; ++i){
+ ConstraintCPVec& dnconf = dnres[containsdn[i]];
+ for(size_t j = 0, M = containsup.size(); j < M; ++j){
+ ConstraintCPVec& upconf = upres[containsup[j]];
+
+ res.push_back(ConstraintCPVec());
+ ConstraintCPVec& back = res.back();
+ resolve(back, dnc, dnconf, upconf);
+ }
+ }
+ if(res.size() >= 2u){
+ subsumption(res);
- if(d_qflraStatus != Result::UNSAT){ d_qflraStatus = simplex.findModel(false); }
+ if(res.size() > 100u){
+ res.resize(100u);
+ }
+ }
+ }else{
+ Debug("approx::replayLogRec") << "replayLogRec() skipping resolving" << nl << std::endl;
+ }
+ Debug("approx::replayLogRec") << "found #"<<res.size()<<" conflicts on branch " << nid << endl;
+ if(res.empty()){
+ ++d_statistics.d_replayBranchCloseFailures;
+ }
+
+ }else{
+ Debug("approx::replayLogRec") << "failed to make a branch " << nid << endl;
+ }
+ }else{
+ ++d_statistics.d_replayLeafCloseFailures;
+ Debug("approx::replayLogRec") << "failed on node " << nid << endl;
+ Assert(res.empty());
+ }
+ resolveOutPropagated(res, propagated);
+ Debug("approx::replayLogRec") << "replayLogRec() ending" << std::endl;
+
+
+ if(options::replayFailureLemma()){
+ // must be done inside the sat context to get things
+ // propagated at this level
+ if(res.empty() && nid == getTreeLog().getRootId()){
+ Assert(!d_replayedLemmas);
+ d_replayedLemmas = replayLemmas(approx);
+ Assert(d_acTmp.empty());
+ while(!d_approxCuts.empty()){
+ Node lem = d_approxCuts.front();
+ d_approxCuts.pop();
+ d_acTmp.push_back(lem);
+ }
+ }
+ }
+ } /* pop the sat context */
+
+ /* move into the current context. */
+ while(!d_acTmp.empty()){
+ Node lem = d_acTmp.back();
+ d_acTmp.pop_back();
+ d_approxCuts.push_back(lem);
+ }
+ Assert(d_acTmp.empty());
+
+
+ /* Garbage collect the constraints from this call */
+ while(d_replayConstraints.size() > rpcons_size){
+ ConstraintP c = d_replayConstraints.back();
+ d_replayConstraints.pop_back();
+ d_constraintDatabase.deleteConstraintAndNegation(c);
+ }
+
+ /* Garbage collect the ArithVars made by this call */
+ if(d_replayVariables.size() > rpvars_size){
+ d_partialModel.stopQueueingBoundCounts();
+ UpdateTrackingCallback utcb(&d_linEq);
+ d_partialModel.processBoundsQueue(utcb);
+ d_linEq.startTrackingBoundCounts();
+ while(d_replayVariables.size() > rpvars_size){
+ ArithVar v = d_replayVariables.back();
+ d_replayVariables.pop_back();
+ Assert(d_partialModel.canBeReleased(v));
+ if(!d_tableau.isBasic(v)){
+ /* if it is not basic make it basic. */
+ ArithVar b = ARITHVAR_SENTINEL;
+ for(Tableau::ColIterator ci = d_tableau.colIterator(v); !ci.atEnd(); ++ci){
+ const Tableau::Entry& e = *ci;
+ b = d_tableau.rowIndexToBasic(e.getRowIndex());
+ break;
+ }
+ Assert(b != ARITHVAR_SENTINEL);
+ DeltaRational cp = d_partialModel.getAssignment(b);
+ if(d_partialModel.cmpAssignmentLowerBound(b) < 0){
+ cp = d_partialModel.getLowerBound(b);
+ }else if(d_partialModel.cmpAssignmentUpperBound(b) > 0){
+ cp = d_partialModel.getUpperBound(b);
+ }
+ d_linEq.pivotAndUpdate(b, v, cp);
+ }
+ Assert(d_tableau.isBasic(v));
+ d_linEq.stopTrackingRowIndex(d_tableau.basicToRowIndex(v));
+ d_tableau.removeBasicRow(v);
+
+ releaseArithVar(v);
+ Debug("approx::vars") << "releasing " << v << endl;
+ }
+ d_linEq.stopTrackingBoundCounts();
+ d_partialModel.startQueueingBoundCounts();
+ d_partialModel.attemptToReclaimReleased();
+ }
+ return res;
+}
+
+TreeLog& TheoryArithPrivate::getTreeLog(){
+ if(d_treeLog == NULL){
+ d_treeLog = new TreeLog();
+ }
+ return *d_treeLog;
+}
+
+ApproximateStatistics& TheoryArithPrivate::getApproxStats(){
+ if(d_approxStats == NULL){
+ d_approxStats = new ApproximateStatistics();
+ }
+ return *d_approxStats;
+}
+
+Node TheoryArithPrivate::branchToNode(ApproximateSimplex* approx, const NodeLog& bn) const throw(RationalFromDoubleException) {
+ Assert(bn.isBranch());
+ ArithVar v = approx->getBranchVar(bn);
+ if(v != ARITHVAR_SENTINEL && d_partialModel.isIntegerInput(v)){
+ if(d_partialModel.hasNode(v)){
+ Node n = d_partialModel.asNode(v);
+ double dval = bn.branchValue();
+ Rational val = ApproximateSimplex::estimateWithCFE(dval);
+ Rational fl(val.floor());
+ NodeManager* nm = NodeManager::currentNM();
+ Node leq = nm->mkNode(kind::LEQ, n, mkRationalNode(fl));
+ Node norm = Rewriter::rewrite(leq);
+ return norm;
+ }
+ }
+ return Node::null();
+}
+
+Node TheoryArithPrivate::cutToLiteral(ApproximateSimplex* approx, const CutInfo& ci) const{
+ Assert(ci.reconstructed());
+
+ const DenseMap<Rational>& lhs = ci.getReconstruction().lhs;
+ Node sum = toSumNode(d_partialModel, lhs);
+ if(!sum.isNull()){
+ Kind k = ci.getKind();
+ Assert(k == kind::LEQ || k == kind::GEQ);
+ Node rhs = mkRationalNode(ci.getReconstruction().rhs);
+
+ NodeManager* nm = NodeManager::currentNM();
+ Node ineq = nm->mkNode(k, sum, rhs);
+ return Rewriter::rewrite(ineq);
+ }
+ return Node::null();
+}
+
+bool TheoryArithPrivate::replayLemmas(ApproximateSimplex* approx){
+ try{
+ ++(d_statistics.d_mipReplayLemmaCalls);
+ bool anythingnew = false;
+
+ TreeLog& tl = getTreeLog();
+ NodeLog& root = tl.getRootNode();
+ root.applySelected(); /* set row ids */
+
+ vector<const CutInfo*> cuts = approx->getValidCuts(root);
+ for(size_t i =0, N =cuts.size(); i < N; ++i){
+ const CutInfo* cut = cuts[i];
+ Assert(cut->reconstructed());
+ Assert(cut->proven());
+
+ const DenseMap<Rational>& row = cut->getReconstruction().lhs;
+ if(!complexityBelow(row, options::lemmaRejectCutSize())){
+ ++(d_statistics.d_cutsRejectedDuringLemmas);
+ continue;
+ }
+
+ Node cutConstraint = cutToLiteral(approx, *cut);
+ if(!cutConstraint.isNull()){
+ const ConstraintCPVec& exp = cut->getExplanation();
+ Node asLemma = Constraint_::externalExplainByAssertions(exp);
+
+ Node implied = Rewriter::rewrite(cutConstraint);
+ anythingnew = anythingnew || !isSatLiteral(implied);
+
+ Node implication = asLemma.impNode(implied);
+ // DO NOT CALL OUTPUT LEMMA!
+ d_approxCuts.push_back(implication);
+ Debug("approx::lemmas") << "cut["<<i<<"] " << implication << endl;
+ ++(d_statistics.d_mipExternalCuts);
+ }
+ }
+ if(root.isBranch()){
+ Node lit = branchToNode(approx, root);
+ if(!lit.isNull()){
+ anythingnew = anythingnew || !isSatLiteral(lit);
+ Node branch = lit.orNode(lit.notNode());
+ d_approxCuts.push_back(branch);
+ ++(d_statistics.d_mipExternalBranch);
+ Debug("approx::lemmas") << "branching "<< root <<" as " << branch << endl;
+ }
+ }
+ return anythingnew;
+ }catch(RationalFromDoubleException& rfde){
+ turnOffApproxFor(options::replayNumericFailurePenalty());
+ return false;
+ }
+}
+
+void TheoryArithPrivate::turnOffApproxFor(int32_t rounds){
+ d_attemptSolveIntTurnedOff = d_attemptSolveIntTurnedOff + rounds;
+ ++(d_statistics.d_approxDisabled);
+}
+
+bool TheoryArithPrivate::safeToCallApprox() const{
+ unsigned numRows = 0;
+ unsigned numCols = 0;
+ var_iterator vi = var_begin(), vi_end = var_end();
+ // Assign each variable to a row and column variable as it appears in the input
+ for(; vi != vi_end && !(numRows > 0 && numCols > 0); ++vi){
+ ArithVar v = *vi;
+
+ if(d_partialModel.isAuxiliary(v)){
+ ++numRows;
+ }else{
+ ++numCols;
+ }
+ }
+ return (numRows > 0 && numCols > 0);
+}
+
+// solve()
+// res = solveRealRelaxation(effortLevel);
+// switch(res){
+// case LinFeas:
+// case LinInfeas:
+// return replay()
+// case Unknown:
+// case Error
+// if()
+void TheoryArithPrivate::solveInteger(Theory::Effort effortLevel){
+ if(!safeToCallApprox()) { return; }
+
+ Assert(safeToCallApprox());
+ TimerStat::CodeTimer codeTimer(d_statistics.d_solveIntTimer);
+
+ ++(d_statistics.d_solveIntCalls);
+ d_statistics.d_inSolveInteger.setData(1);
+
+ if(!Theory::fullEffort(effortLevel)){
+ d_solveIntAttempts++;
+ ++(d_statistics.d_solveStandardEffort);
+ }
+
+ // if integers are attempted,
+ Assert(options::useApprox());
+ Assert(ApproximateSimplex::enabled());
+
+ int level = getSatContext()->getLevel();
+ d_lastContextIntegerAttempted = level;
+
+
+ static const int32_t mipLimit = 200000;
+
+ TreeLog& tl = getTreeLog();
+ ApproximateStatistics& stats = getApproxStats();
+ ApproximateSimplex* approx =
+ ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel, tl, stats);
+
+ try{
+ approx->setPivotLimit(mipLimit);
+ if(!d_guessedCoeffSet){
+ d_guessedCoeffs = approx->heuristicOptCoeffs();
+ d_guessedCoeffSet = true;
+ }
+ if(!d_guessedCoeffs.empty()){
+ approx->setOptCoeffs(d_guessedCoeffs);
+ }
+ static const int32_t depthForLikelyInfeasible = 10;
+ int maxDepthPass1 = d_likelyIntegerInfeasible ?
+ depthForLikelyInfeasible : options::maxApproxDepth();
+ approx->setBranchingDepth(maxDepthPass1);
+ approx->setBranchOnVariableLimit(100);
+ LinResult relaxRes = approx->solveRelaxation();
+ if( relaxRes == LinFeasible ){
+ MipResult mipRes = approx->solveMIP(false);
+ Debug("arith::solveInteger") << "mipRes " << mipRes << endl;
+ switch(mipRes) {
+ case MipBingo:
+ // attempt the solution
+ {
+ d_partialModel.stopQueueingBoundCounts();
+ UpdateTrackingCallback utcb(&d_linEq);
+ d_partialModel.processBoundsQueue(utcb);
+ d_linEq.startTrackingBoundCounts();
+
+ ApproximateSimplex::Solution mipSolution;
+ mipSolution = approx->extractMIP();
+ importSolution(mipSolution);
+ solveRelaxationOrPanic(effortLevel);
+
+ // shutdown simplex
+ d_linEq.stopTrackingBoundCounts();
+ d_partialModel.startQueueingBoundCounts();
}
break;
- default:
+ case MipClosed:
+ /* All integer branches closed */
+ approx->setPivotLimit(2*mipLimit);
+ mipRes = approx->solveMIP(true);
+ if(mipRes == MipClosed){
+ d_likelyIntegerInfeasible = true;
+ replayLog(approx);
+ }
+ if(!(anyConflict() || !d_approxCuts.empty())){
+ turnOffApproxFor(options::replayNumericFailurePenalty());
+ }
+ break;
+ case BranchesExhausted:
+ case ExecExhausted:
+ case PivotsExhauasted:
+ if(mipRes == BranchesExhausted){
+ ++d_statistics.d_branchesExhausted;
+ }else if(mipRes == ExecExhausted){
+ ++d_statistics.d_execExhausted;
+ }else if(mipRes == PivotsExhauasted){
+ ++d_statistics.d_pivotsExhausted;
+ }
+
+ approx->setPivotLimit(2*mipLimit);
+ approx->setBranchingDepth(2);
+ mipRes = approx->solveMIP(true);
+ replayLemmas(approx);
+ break;
+ case MipUnknown:
break;
}
- delete approxSolver;
}
+ }catch(RationalFromDoubleException& rfde){
+ turnOffApproxFor(options::replayNumericFailurePenalty());
+ }
+ delete approx;
- if(d_qflraStatus == Result::SAT_UNKNOWN){
- //Message() << "got sat unknown" << endl;
- vector<ArithVar> toCut = cutAllBounded();
- if(toCut.size() > 0){
- branchVector(toCut);
- emmittedConflictOrSplit = true;
- }else{
- //Message() << "splitting" << endl;
+ if(!Theory::fullEffort(effortLevel)){
+ if(anyConflict() || !d_approxCuts.empty()){
+ d_solveIntMaybeHelp++;
+ }
+ }
+
+ d_statistics.d_inSolveInteger.setData(0);
+}
- d_qflraStatus = simplex.findModel(noPivotLimit);
+SimplexDecisionProcedure& TheoryArithPrivate::selectSimplex(bool pass1){
+ if(pass1){
+ if(d_pass1SDP == NULL){
+ if(options::useFC()){
+ d_pass1SDP = (SimplexDecisionProcedure*)(&d_fcSimplex);
+ }else if(options::useSOI()){
+ d_pass1SDP = (SimplexDecisionProcedure*)(&d_soiSimplex);
+ }else{
+ d_pass1SDP = (SimplexDecisionProcedure*)(&d_dualSimplex);
+ }
+ }
+ Assert(d_pass1SDP != NULL);
+ return *d_pass1SDP;
+ }else{
+ if(d_otherSDP == NULL){
+ if(options::useFC()){
+ d_otherSDP = (SimplexDecisionProcedure*)(&d_fcSimplex);
+ }else if(options::useSOI()){
+ d_otherSDP = (SimplexDecisionProcedure*)(&d_soiSimplex);
+ }else{
+ d_otherSDP = (SimplexDecisionProcedure*)(&d_soiSimplex);
}
}
+ Assert(d_otherSDP != NULL);
+ return *d_otherSDP;
+ }
+}
+
+void TheoryArithPrivate::importSolution(const ApproximateSimplex::Solution& solution){
+ if(Debug.isOn("arith::importSolution")){
+ Debug("arith::importSolution") << "importSolution before " << d_qflraStatus << endl;
+ d_partialModel.printEntireModel(Debug("arith::importSolution"));
+ }
+
+ d_qflraStatus = d_attemptSolSimplex.attempt(solution);
+
+ if(Debug.isOn("arith::importSolution")){
+ Debug("arith::importSolution") << "importSolution intermediate " << d_qflraStatus << endl;
+ d_partialModel.printEntireModel(Debug("arith::importSolution"));
+ }
+
+ if(d_qflraStatus != Result::UNSAT){
+ static const int32_t pass2Limit = 20;
+ int16_t oldCap = options::arithStandardCheckVarOrderPivots();
+ options::arithStandardCheckVarOrderPivots.set(pass2Limit);
+ SimplexDecisionProcedure& simplex = selectSimplex(false);
+ d_qflraStatus = simplex.findModel(false);
options::arithStandardCheckVarOrderPivots.set(oldCap);
}
+ if(Debug.isOn("arith::importSolution")){
+ Debug("arith::importSolution") << "importSolution after " << d_qflraStatus << endl;
+ d_partialModel.printEntireModel(Debug("arith::importSolution"));
+ }
+}
+
+bool TheoryArithPrivate::solveRelaxationOrPanic(Theory::Effort effortLevel){
+ // if at this point the linear relaxation is still unknown,
+ // attempt to branch an integer variable as a last ditch effort on full check
+ if(d_qflraStatus == Result::SAT_UNKNOWN){
+ d_qflraStatus = selectSimplex(true).findModel(false);
+ }
+
+ if(Theory::fullEffort(effortLevel) && d_qflraStatus == Result::SAT_UNKNOWN){
+ ArithVar canBranch = nextIntegerViolatation(false);
+ if(canBranch != ARITHVAR_SENTINEL){
+ ++d_statistics.d_panicBranches;
+ Node branch = branchIntegerVariable(canBranch);
+ Assert(branch.getKind() == kind::OR);
+ Node rwbranch = Rewriter::rewrite(branch[0]);
+ if(!isSatLiteral(rwbranch)){
+ d_approxCuts.push_back(branch);
+ return true;
+ }
+ }
+ d_qflraStatus = selectSimplex(false).findModel(true);
+ }
+ return false;
+}
+
+bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
+ TimerStat::CodeTimer codeTimer(d_statistics.d_solveRealRelaxTimer);
+ Assert(d_qflraStatus != Result::SAT);
+
+ d_partialModel.stopQueueingBoundCounts();
+ UpdateTrackingCallback utcb(&d_linEq);
+ d_partialModel.processBoundsQueue(utcb);
+ d_linEq.startTrackingBoundCounts();
+
+ bool noPivotLimit = Theory::fullEffort(effortLevel) ||
+ !options::restrictedPivots();
+
+ SimplexDecisionProcedure& simplex = selectSimplex(true);
+
+ bool useApprox = options::useApprox() && ApproximateSimplex::enabled() && getSolveIntegerResource();
+
+ bool noPivotLimitPass1 = noPivotLimit && !useApprox;
+ d_qflraStatus = simplex.findModel(noPivotLimitPass1);
+
+ if(d_qflraStatus == Result::SAT_UNKNOWN && useApprox && safeToCallApprox()){
+ // pass2: fancy-final
+ static const int32_t relaxationLimit = 10000;
+ Assert(ApproximateSimplex::enabled());
+
+ TreeLog& tl = getTreeLog();
+ ApproximateStatistics& stats = getApproxStats();
+ ApproximateSimplex* approxSolver =
+ ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel, tl, stats);
+
+ approxSolver->setPivotLimit(relaxationLimit);
+
+ if(!d_guessedCoeffSet){
+ d_guessedCoeffs = approxSolver->heuristicOptCoeffs();
+ d_guessedCoeffSet = true;
+ }
+ if(!d_guessedCoeffs.empty()){
+ approxSolver->setOptCoeffs(d_guessedCoeffs);
+ }
+
+ ++d_statistics.d_relaxCalls;
+
+ ApproximateSimplex::Solution relaxSolution;
+ LinResult relaxRes = approxSolver->solveRelaxation();
+ try{
+ Debug("solveRealRelaxation") << "solve relaxation? " << endl;
+ switch(relaxRes){
+ case LinFeasible:
+ Debug("solveRealRelaxation") << "lin feasible? " << endl;
+ ++d_statistics.d_relaxLinFeas;
+ relaxSolution = approxSolver->extractRelaxation();
+ importSolution(relaxSolution);
+ if(d_qflraStatus != Result::SAT){
+ ++d_statistics.d_relaxLinFeasFailures;
+ }
+ break;
+ case LinInfeasible:
+ // todo attempt to recreate approximate conflict
+ ++d_statistics.d_relaxLinInfeas;
+ Debug("solveRealRelaxation") << "lin infeasible " << endl;
+ relaxSolution = approxSolver->extractRelaxation();
+ importSolution(relaxSolution);
+ if(d_qflraStatus != Result::UNSAT){
+ ++d_statistics.d_relaxLinInfeasFailures;
+ }
+ break;
+ case LinExhausted:
+ ++d_statistics.d_relaxLinExhausted;
+ Debug("solveRealRelaxation") << "exhuasted " << endl;
+ break;
+ case LinUnknown:
+ default:
+ ++d_statistics.d_relaxOthers;
+ break;
+ }
+ }catch(RationalFromDoubleException& rfde){
+ turnOffApproxFor(options::replayNumericFailurePenalty());
+ }
+ delete approxSolver;
+
+ }
+
+ bool emmittedConflictOrSplit = solveRelaxationOrPanic(effortLevel);
+
// TODO Save zeroes with no conflicts
d_linEq.stopTrackingBoundCounts();
d_partialModel.startQueueingBoundCounts();
@@ -1818,8 +3123,162 @@ bool TheoryArithPrivate::solveRealRelaxation(Theory::Effort effortLevel){
return emmittedConflictOrSplit;
}
+// LinUnknown, /* Unknown error */
+// LinFeasible, /* Relaxation is feasible */
+// LinInfeasible, /* Relaxation is infeasible/all integer branches closed */
+// LinExhausted
+// // Fancy final tries the following strategy
+// // At final check, try the preferred simplex solver with a pivot cap
+// // If that failed, swap the the other simplex solver
+// // If that failed, check if there are integer variables to cut
+// // If that failed, do a simplex without a pivot limit
+
+// int16_t oldCap = options::arithStandardCheckVarOrderPivots();
+
+// static const int32_t pass2Limit = 10;
+// static const int32_t relaxationLimit = 10000;
+// static const int32_t mipLimit = 200000;
+
+// //cout << "start" << endl;
+// d_qflraStatus = simplex.findModel(false);
+// //cout << "end" << endl;
+// if(d_qflraStatus == Result::SAT_UNKNOWN ||
+// (d_qflraStatus == Result::SAT && !hasIntegerModel() && !d_likelyIntegerInfeasible)){
+
+// ApproximateSimplex* approxSolver = ApproximateSimplex::mkApproximateSimplexSolver(d_partialModel, *(getTreeLog()), *(getApproxStats()));
+// approxSolver->setPivotLimit(relaxationLimit);
+
+// if(!d_guessedCoeffSet){
+// d_guessedCoeffs = approxSolver->heuristicOptCoeffs();
+// d_guessedCoeffSet = true;
+// }
+// if(!d_guessedCoeffs.empty()){
+// approxSolver->setOptCoeffs(d_guessedCoeffs);
+// }
+
+// MipResult mipRes;
+// ApproximateSimplex::Solution relaxSolution, mipSolution;
+// LinResult relaxRes = approxSolver->solveRelaxation();
+// switch(relaxRes){
+// case LinFeasible:
+// {
+// relaxSolution = approxSolver->extractRelaxation();
+
+// /* If the approximate solver known to be integer infeasible
+// * only redo*/
+// int maxDepth =
+// d_likelyIntegerInfeasible ? 1 : options::arithMaxBranchDepth();
+
+
+// if(d_likelyIntegerInfeasible){
+// d_qflraStatus = d_attemptSolSimplex.attempt(relaxSolution);
+// }else{
+// approxSolver->setPivotLimit(mipLimit);
+// mipRes = approxSolver->solveMIP(false);
+// if(mipRes == ApproximateSimplex::ApproxUnsat){
+// mipRes = approxSolver->solveMIP(true);
+// }
+// d_errorSet.reduceToSignals();
+// //Message() << "here" << endl;
+// if(mipRes == ApproximateSimplex::ApproxSat){
+// mipSolution = approxSolver->extractMIP();
+// d_qflraStatus = d_attemptSolSimplex.attempt(mipSolution);
+// }else{
+// if(mipRes == ApproximateSimplex::ApproxUnsat){
+// d_likelyIntegerInfeasible = true;
+// }
+// vector<Node> lemmas = approxSolver->getValidCuts();
+// for(size_t i = 0; i < lemmas.size(); ++i){
+// d_approxCuts.pushback(lemmas[i]);
+// }
+// d_qflraStatus = d_attemptSolSimplex.attempt(relaxSolution);
+// }
+// }
+// options::arithStandardCheckVarOrderPivots.set(pass2Limit);
+// if(d_qflraStatus != Result::UNSAT){ d_qflraStatus = simplex.findModel(false); }
+// //Message() << "done" << endl;
+// }
+// break;
+// case ApproximateSimplex::ApproxUnsat:
+// {
+// ApproximateSimplex::Solution sol = approxSolver->extractRelaxation();
+
+// d_qflraStatus = d_attemptSolSimplex.attempt(sol);
+// options::arithStandardCheckVarOrderPivots.set(pass2Limit);
+
+// if(d_qflraStatus != Result::UNSAT){ d_qflraStatus = simplex.findModel(false); }
+// }
+// break;
+// default:
+// break;
+// }
+// delete approxSolver;
+// }
+// }
+
+// if(!useFancyFinal){
+// d_qflraStatus = simplex.findModel(noPivotLimit);
+// }else{
+
+
+// if(d_qflraStatus == Result::SAT_UNKNOWN){
+// //Message() << "got sat unknown" << endl;
+// vector<ArithVar> toCut = cutAllBounded();
+// if(toCut.size() > 0){
+// //branchVector(toCut);
+// emmittedConflictOrSplit = true;
+// }else{
+// //Message() << "splitting" << endl;
+
+// d_qflraStatus = simplex.findModel(noPivotLimit);
+// }
+// }
+// options::arithStandardCheckVarOrderPivots.set(oldCap);
+// }
+
+// // TODO Save zeroes with no conflicts
+// d_linEq.stopTrackingBoundCounts();
+// d_partialModel.startQueueingBoundCounts();
+
+// return emmittedConflictOrSplit;
+// }
+
+bool TheoryArithPrivate::hasFreshArithLiteral(Node n) const{
+ switch(n.getKind()){
+ case kind::LEQ:
+ case kind::GEQ:
+ case kind::GT:
+ case kind::LT:
+ return !isSatLiteral(n);
+ case kind::EQUAL:
+ if(n[0].getType().isReal()){
+ return !isSatLiteral(n);
+ }else if(n[0].getType().isBoolean()){
+ return hasFreshArithLiteral(n[0]) ||
+ hasFreshArithLiteral(n[1]);
+ }else{
+ return false;
+ }
+ case kind::IMPLIES:
+ // try the rhs first
+ return hasFreshArithLiteral(n[1]) ||
+ hasFreshArithLiteral(n[0]);
+ default:
+ if(n.getType().isBoolean()){
+ for(Node::iterator ni=n.begin(), nend=n.end(); ni!=nend; ++ni){
+ Node child = *ni;
+ if(hasFreshArithLiteral(child)){
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
+
void TheoryArithPrivate::check(Theory::Effort effortLevel){
Assert(d_currentPropagationList.empty());
+ //cout << "TheoryArithPrivate::check " << effortLevel << std::endl;
Debug("effortlevel") << "TheoryArithPrivate::check " << effortLevel << std::endl;
Debug("arith") << "TheoryArithPrivate::check begun " << effortLevel << std::endl;
@@ -1837,28 +3296,28 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
}
while(!done()){
- Constraint curr = constraintFromFactQueue();
+ ConstraintP curr = constraintFromFactQueue();
if(curr != NullConstraint){
bool res CVC4_UNUSED = assertionCases(curr);
- Assert(!res || inConflict());
+ Assert(!res || anyConflict());
}
- if(inConflict()){ break; }
+ if(anyConflict()){ break; }
}
- if(!inConflict()){
+ if(!anyConflict()){
while(!d_learnedBounds.empty()){
// we may attempt some constraints twice. this is okay!
- Constraint curr = d_learnedBounds.front();
+ ConstraintP curr = d_learnedBounds.front();
d_learnedBounds.pop();
Debug("arith::learned") << curr << endl;
bool res CVC4_UNUSED = assertionCases(curr);
- Assert(!res || inConflict());
+ Assert(!res || anyConflict());
- if(inConflict()){ break; }
+ if(anyConflict()){ break; }
}
}
- if(inConflict()){
+ if(anyConflict()){
d_qflraStatus = Result::UNSAT;
if(options::revertArithModels() && previous == Result::SAT){
++d_statistics.d_revertsOnConflicts;
@@ -1872,6 +3331,7 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
revertOutOfConflict();
}
outputConflicts();
+ //cout << "unate conflict 1 " << effortLevel << std::endl;
return;
}
@@ -1884,9 +3344,33 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
Assert(d_conflicts.empty());
bool useSimplex = d_qflraStatus != Result::SAT;
+ Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
+ << "pre realRelax" << endl;
+
if(useSimplex){
emmittedConflictOrSplit = solveRealRelaxation(effortLevel);
}
+ Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
+ << "post realRelax" << endl;
+
+
+ Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
+ << "pre solveInteger" << endl;
+
+ if(attemptSolveInteger(effortLevel, emmittedConflictOrSplit)){
+ solveInteger(effortLevel);
+ if(anyConflict()){
+ ++d_statistics.d_commitsOnConflicts;
+ Debug("arith::bt") << "committing here " << " " << newFacts << " " << previous << " " << d_qflraStatus << endl;
+ revertOutOfConflict();
+ d_errorSet.clear();
+ outputConflicts();
+ return;
+ }
+ }
+
+ Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
+ << "post solveInteger" << endl;
switch(d_qflraStatus){
case Result::SAT:
@@ -1944,6 +3428,7 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
}
outputConflicts();
emmittedConflictOrSplit = true;
+ Debug("arith::conflict") << "simplex conflict" << endl;
if(useSimplex && options::collectPivots()){
if(options::useFC()){
@@ -1958,6 +3443,26 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
}
d_statistics.d_avgUnknownsInARow.addEntry(d_unknownsInARow);
+ Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
+ << "pre approx cuts" << endl;
+ if(!d_approxCuts.empty()){
+ bool anyFresh = false;
+ while(!d_approxCuts.empty()){
+ Node lem = d_approxCuts.front();
+ d_approxCuts.pop();
+ Debug("arith::approx::cuts") << "approximate cut:" << lem << endl;
+ anyFresh = anyFresh || hasFreshArithLiteral(lem);
+ Debug("arith::lemma") << "approximate cut:" << lem << endl;
+ outputLemma(lem);
+ }
+ if(anyFresh){
+ emmittedConflictOrSplit = true;
+ }
+ }
+
+ Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
+ << "post approx cuts" << endl;
+
// This should be fine if sat or unknown
if(!emmittedConflictOrSplit &&
(options::arithPropagationMode() == UNATE_PROP ||
@@ -1965,8 +3470,8 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
TimerStat::CodeTimer codeTimer(d_statistics.d_newPropTime);
Assert(d_qflraStatus != Result::UNSAT);
- while(!d_currentPropagationList.empty() && !inConflict()){
- Constraint curr = d_currentPropagationList.front();
+ while(!d_currentPropagationList.empty() && !anyConflict()){
+ ConstraintP curr = d_currentPropagationList.front();
d_currentPropagationList.pop_front();
ConstraintType t = curr->getType();
@@ -1976,23 +3481,23 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
switch(t){
case LowerBound:
{
- Constraint prev = d_currentPropagationList.front();
+ ConstraintP prev = d_currentPropagationList.front();
d_currentPropagationList.pop_front();
d_constraintDatabase.unatePropLowerBound(curr, prev);
break;
}
case UpperBound:
{
- Constraint prev = d_currentPropagationList.front();
+ ConstraintP prev = d_currentPropagationList.front();
d_currentPropagationList.pop_front();
d_constraintDatabase.unatePropUpperBound(curr, prev);
break;
}
case Equality:
{
- Constraint prevLB = d_currentPropagationList.front();
+ ConstraintP prevLB = d_currentPropagationList.front();
d_currentPropagationList.pop_front();
- Constraint prevUB = d_currentPropagationList.front();
+ ConstraintP prevUB = d_currentPropagationList.front();
d_currentPropagationList.pop_front();
d_constraintDatabase.unatePropEquality(curr, prevLB, prevUB);
break;
@@ -2002,14 +3507,16 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
}
}
- if(inConflict()){
+ if(anyConflict()){
Debug("arith::unate") << "unate conflict" << endl;
revertOutOfConflict();
d_qflraStatus = Result::UNSAT;
outputConflicts();
emmittedConflictOrSplit = true;
+ //cout << "unate conflict " << endl;
Debug("arith::bt") << "committing on unate conflict" << " " << newFacts << " " << previous << " " << d_qflraStatus << endl;
+ Debug("arith::conflict") << "unate arith conflict" << endl;
}
}else{
TimerStat::CodeTimer codeTimer(d_statistics.d_newPropTime);
@@ -2017,12 +3524,23 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
}
Assert( d_currentPropagationList.empty());
+ Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
+ << "post unate" << endl;
+
if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel)){
++d_fullCheckCounter;
}
if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel)){
emmittedConflictOrSplit = splitDisequalities();
}
+ Debug("arith::ems") << "ems: " << emmittedConflictOrSplit
+ << "pos splitting" << endl;
+
+
+ Debug("arith") << "integer? "
+ << " conf/split " << emmittedConflictOrSplit
+ << " fulleffort " << Theory::fullEffort(effortLevel)
+ << " hasintmodel " << hasIntegerModel() << endl;
if(!emmittedConflictOrSplit && Theory::fullEffort(effortLevel) && !hasIntegerModel()){
Node possibleConflict = Node::null();
@@ -2031,22 +3549,22 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
if(possibleConflict != Node::null()){
revertOutOfConflict();
Debug("arith::conflict") << "dio conflict " << possibleConflict << endl;
- //cout << "dio conflict " << possibleConflict << endl;
- raiseConflict(possibleConflict);
+ blackBoxConflict(possibleConflict);
outputConflicts();
emmittedConflictOrSplit = true;
}
}
if(!emmittedConflictOrSplit && d_hasDoneWorkSinceCut && options::arithDioSolver()){
- Node possibleLemma = dioCutting();
- if(!possibleLemma.isNull()){
- Debug("arith") << "dio cut " << possibleLemma << endl;
- //cout << "dio cut " << possibleLemma << endl;
- emmittedConflictOrSplit = true;
- d_hasDoneWorkSinceCut = false;
- d_cutCount = d_cutCount + 1;
- outputLemma(possibleLemma);
+ if(getDioCuttingResource()){
+ Node possibleLemma = dioCutting();
+ if(!possibleLemma.isNull()){
+ emmittedConflictOrSplit = true;
+ d_hasDoneWorkSinceCut = false;
+ d_cutCount = d_cutCount + 1;
+ Debug("arith::lemma") << "dio cut " << possibleLemma << endl;
+ outputLemma(possibleLemma);
+ }
}
}
@@ -2056,7 +3574,10 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
++(d_statistics.d_externalBranchAndBounds);
d_cutCount = d_cutCount + 1;
emmittedConflictOrSplit = true;
+ Debug("arith::lemma") << "rrbranch lemma"
+ << possibleLemma << endl;
outputLemma(possibleLemma);
+
}
}
@@ -2064,10 +3585,12 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
if(d_diosolver.hasMoreDecompositionLemmas()){
while(d_diosolver.hasMoreDecompositionLemmas()){
Node decompositionLemma = d_diosolver.nextDecompositionLemma();
- Debug("arith") << "dio decomposition lemma " << decompositionLemma << endl;
+ Debug("arith::lemma") << "dio decomposition lemma "
+ << decompositionLemma << endl;
outputLemma(decompositionLemma);
}
}else{
+ Debug("arith::restart") << "arith restart!" << endl;
outputRestart();
}
}
@@ -2077,6 +3600,15 @@ void TheoryArithPrivate::check(Theory::Effort effortLevel){
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(); }
if(Debug.isOn("arith::print_model")) {
debugPrintModel(Debug("arith::print_model"));
@@ -2127,7 +3659,7 @@ std::vector<ArithVar> TheoryArithPrivate::cutAllBounded() const{
for(ArithVar iter = 0; iter != max; ++iter){
//Do not include slack variables
const DeltaRational& d = d_partialModel.getAssignment(iter);
- if(isInteger(iter) && !isSlackVariable(iter) &&
+ if(isIntegerInput(iter) &&
!d_cutInContext.contains(iter) &&
d_partialModel.hasUpperBound(iter) &&
d_partialModel.hasLowerBound(iter) &&
@@ -2147,7 +3679,7 @@ Node TheoryArithPrivate::roundRobinBranch(){
ArithVar v = d_nextIntegerCheckVar;
Assert(isInteger(v));
- Assert(!isSlackVariable(v));
+ Assert(!isAuxiliaryVariable(v));
return branchIntegerVariable(v);
}
}
@@ -2155,10 +3687,10 @@ Node TheoryArithPrivate::roundRobinBranch(){
bool TheoryArithPrivate::splitDisequalities(){
bool splitSomething = false;
- vector<Constraint> save;
+ vector<ConstraintP> save;
while(!d_diseqQueue.empty()){
- Constraint front = d_diseqQueue.front();
+ ConstraintP front = d_diseqQueue.front();
d_diseqQueue.pop();
if(front->isSplit()){
@@ -2179,6 +3711,7 @@ bool TheoryArithPrivate::splitDisequalities(){
Debug("arith::lemma") << "Now " << Rewriter::rewrite(lemma) << endl;
outputLemma(lemma);
+ //cout << "Now " << Rewriter::rewrite(lemma) << endl;
splitSomething = true;
}else if(d_partialModel.strictlyLessThanLowerBound(lhsVar, rhsValue)){
Debug("eq") << "can drop as less than lb" << front << endl;
@@ -2190,7 +3723,7 @@ bool TheoryArithPrivate::splitDisequalities(){
}
}
}
- vector<Constraint>::const_iterator i=save.begin(), i_end = save.end();
+ vector<ConstraintP>::const_iterator i=save.begin(), i_end = save.end();
for(; i != i_end; ++i){
d_diseqQueue.push(*i);
}
@@ -2206,17 +3739,17 @@ void TheoryArithPrivate::debugPrintAssertions(std::ostream& out) const {
for (var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
ArithVar i = *vi;
if (d_partialModel.hasLowerBound(i)) {
- Constraint lConstr = d_partialModel.getLowerBoundConstraint(i);
+ ConstraintP lConstr = d_partialModel.getLowerBoundConstraint(i);
out << lConstr << endl;
}
if (d_partialModel.hasUpperBound(i)) {
- Constraint uConstr = d_partialModel.getUpperBoundConstraint(i);
+ ConstraintP uConstr = d_partialModel.getUpperBoundConstraint(i);
out << uConstr << endl;
}
}
- context::CDQueue<Constraint>::const_iterator it = d_diseqQueue.begin();
- context::CDQueue<Constraint>::const_iterator it_end = d_diseqQueue.end();
+ context::CDQueue<ConstraintP>::const_iterator it = d_diseqQueue.begin();
+ context::CDQueue<ConstraintP>::const_iterator it_end = d_diseqQueue.end();
for(; it != it_end; ++ it) {
out << *it << endl;
}
@@ -2243,16 +3776,16 @@ Node TheoryArithPrivate::explain(TNode n) {
Debug("arith::explain") << "explain @" << getSatContext()->getLevel() << ": " << n << endl;
- Constraint c = d_constraintDatabase.lookup(n);
+ ConstraintP c = d_constraintDatabase.lookup(n);
if(c != NullConstraint){
Assert(!c->isSelfExplaining());
- Node exp = c->explainForPropagation();
+ Node 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->isSelfExplaining()){
- Node exp = c->explainForPropagation();
+ Node exp = c->externalExplainForPropagation();
Debug("arith::explain") << "assertions explanation" << n << ":" << exp << endl;
return exp;
}else{
@@ -2285,12 +3818,13 @@ void TheoryArithPrivate::propagate(Theory::Effort e) {
}
while(d_constraintDatabase.hasMorePropagations()){
- Constraint c = d_constraintDatabase.nextPropagation();
+ ConstraintCP c = d_constraintDatabase.nextPropagation();
Debug("arith::prop") << "next prop" << getSatContext()->getLevel() << ": " << c << endl;
if(c->negationHasProof()){
- Debug("arith::prop") << "negation has proof " << c->getNegation() << endl
- << c->getNegation()->explainForConflict() << endl;
+ Debug("arith::prop") << "negation has proof " << c->getNegation() << endl;
+ Debug("arith::prop") << c->getNegation()->externalExplainByAssertions()
+ << endl;
}
Assert(!c->negationHasProof(), "A constraint has been propagated on the constraint propagation queue, but the negation has been set to true. Contact Tim now!");
@@ -2311,7 +3845,7 @@ void TheoryArithPrivate::propagate(Theory::Effort e) {
//equality engine in the the difference manager.
Node normalized = Rewriter::rewrite(toProp);
- Constraint constraint = d_constraintDatabase.lookup(normalized);
+ ConstraintP constraint = d_constraintDatabase.lookup(normalized);
if(constraint == NullConstraint){
Debug("arith::prop") << "propagating on non-constraint? " << toProp << endl;
@@ -2322,7 +3856,7 @@ void TheoryArithPrivate::propagate(Theory::Effort e) {
normalized[0] : normalized.notNode();
Node lp = flattenAnd(exp.andNode(notNormalized));
Debug("arith::prop") << "propagate conflict" << lp << endl;
- raiseConflict(lp);
+ blackBoxConflict(lp);
outputConflicts();
return;
}else{
@@ -2427,11 +3961,11 @@ DeltaRational TheoryArithPrivate::getDeltaValue(TNode n) const throw (DeltaRatio
Rational TheoryArithPrivate::deltaValueForTotalOrder() const{
Rational min(2);
std::set<DeltaRational> relevantDeltaValues;
- context::CDQueue<Constraint>::const_iterator qiter = d_diseqQueue.begin();
- context::CDQueue<Constraint>::const_iterator qiter_end = d_diseqQueue.end();
+ context::CDQueue<ConstraintP>::const_iterator qiter = d_diseqQueue.begin();
+ context::CDQueue<ConstraintP>::const_iterator qiter_end = d_diseqQueue.end();
for(; qiter != qiter_end; ++qiter){
- Constraint curr = *qiter;
+ ConstraintP curr = *qiter;
const DeltaRational& rhsValue = curr->getValue();
relevantDeltaValues.insert(rhsValue);
@@ -2503,7 +4037,7 @@ void TheoryArithPrivate::collectModelInfo( TheoryModel* m, bool fullModel ){
for(var_iterator vi = var_begin(), vend = var_end(); vi != vend; ++vi){
ArithVar v = *vi;
- if(!isSlackVariable(v)){
+ if(!isAuxiliaryVariable(v)){
Node term = d_partialModel.asNode(v);
if(theoryOf(term) == THEORY_ARITH || shared.find(term) != shared.end()){
@@ -2550,6 +4084,8 @@ void TheoryArithPrivate::notifyRestart(){
if(Debug.isOn("paranoid:check_tableau")){ d_linEq.debugCheckTableau(); }
++d_restartsCounter;
+ d_solveIntMaybeHelp = 0;
+ d_solveIntAttempts = 0;
}
bool TheoryArithPrivate::entireStateIsConsistent(const string& s){
@@ -2679,7 +4215,7 @@ bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound
//implies an unknown fact.
ConstraintType t = upperBound ? UpperBound : LowerBound;
- Constraint bestImplied = d_constraintDatabase.getBestImpliedBound(basic, t, bound);
+ ConstraintP bestImplied = d_constraintDatabase.getBestImpliedBound(basic, t, bound);
// Node bestImplied = upperBound ?
// d_apm.getBestImpliedUpperBound(basic, bound):
@@ -2694,7 +4230,7 @@ bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound
Assert( upperBound || d_partialModel.greaterThanLowerBound(basic, bestImplied->getValue()));
//slightly changed
- // Constraint c = d_constraintDatabase.lookup(bestImplied);
+ // ConstraintP c = d_constraintDatabase.lookup(bestImplied);
// Assert(c != NullConstraint);
bool assertedToTheTheory = bestImplied->assertedToTheTheory();
@@ -2710,7 +4246,8 @@ bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound
if(bestImplied->negationHasProof()){
Warning() << "the negation of " << bestImplied << " : " << endl
<< "has proof " << bestImplied->getNegation() << endl
- << bestImplied->getNegation()->explainForConflict() << endl;
+ << bestImplied->getNegation()->externalExplainByAssertions()
+ << endl;
}
if(!assertedToTheTheory && canBePropagated && !hasProof ){
@@ -2724,8 +4261,11 @@ bool TheoryArithPrivate::propagateCandidateBound(ArithVar basic, bool upperBound
return true;
}
if(Debug.isOn("arith::prop")){
- Debug("arith::prop") << "failed " << basic << " " << bound << assertedToTheTheory << " " <<
- canBePropagated << " " << hasProof << endl;
+ Debug("arith::prop") << "failed " << basic
+ << " " << bound
+ << " " << assertedToTheTheory
+ << " " << canBePropagated
+ << " " << hasProof << endl;
d_partialModel.printModel(basic, Debug("arith::prop"));
}
}
@@ -2848,7 +4388,7 @@ bool TheoryArithPrivate::propagateMightSucceed(ArithVar v, bool ub) const{
return true;
}
- Constraint strongestPossible = d_constraintDatabase.getBestImpliedBound(v, t, a);
+ ConstraintP strongestPossible = d_constraintDatabase.getBestImpliedBound(v, t, a);
if(strongestPossible == NullConstraint){
return false;
}else{
@@ -2944,11 +4484,7 @@ bool TheoryArithPrivate::tryToPropagate(RowIndex ridx, bool rowUp, ArithVar v, b
if(weaker){
ConstraintType t = vUb ? UpperBound : LowerBound;
- if(isInteger(v)){
- //cout << "maybe" << endl;
- //cout << bound << endl;
- }
- Constraint implied = d_constraintDatabase.getBestImpliedBound(v, t, bound);
+ ConstraintP implied = d_constraintDatabase.getBestImpliedBound(v, t, bound);
if(implied != NullConstraint){
return rowImplicationCanBeApplied(ridx, rowUp, implied);
}
@@ -2980,7 +4516,7 @@ Node flattenImplication(Node imp){
return nb;
}
-bool TheoryArithPrivate::rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, Constraint implied){
+bool TheoryArithPrivate::rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, ConstraintP implied){
Assert(implied != NullConstraint);
ArithVar v = implied->getVariable();
@@ -2997,14 +4533,14 @@ bool TheoryArithPrivate::rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, C
if(implied->negationHasProof()){
Warning() << "the negation of " << implied << " : " << endl
<< "has proof " << implied->getNegation() << endl
- << implied->getNegation()->explainForConflict() << endl;
+ << implied->getNegation()->externalExplainByAssertions() << endl;
}
if(!assertedToTheTheory && canBePropagated && !hasProof ){
- vector<Constraint> explain;
+ ConstraintCPVec explain;
d_linEq.propagateRow(explain, ridx, rowUp, implied);
if(d_tableau.getRowLength(ridx) <= options::arithPropAsLemmaLength()){
- Node implication = implied->makeImplication(explain);
+ Node implication = implied->externalImplication(explain);
Node clause = flattenImplication(implication);
outputLemma(clause);
}else{
@@ -3085,6 +4621,69 @@ const BoundsInfo& TheoryArithPrivate::boundsInfo(ArithVar basic) const{
return d_rowTracking[ridx];
}
+Node TheoryArithPrivate::expandDefinition(LogicRequest &logicRequest, Node node) {
+ NodeManager* nm = NodeManager::currentNM();
+
+ switch(node.getKind()) {
+ case kind::DIVISION: {
+ // partial function: division
+ if(d_divByZero.isNull()) {
+ d_divByZero = nm->mkSkolem("divByZero", nm->mkFunctionType(nm->realType(), nm->realType()),
+ "partial real division", NodeManager::SKOLEM_EXACT_NAME);
+ logicRequest.widenLogic(THEORY_UF);
+ }
+ TNode num = node[0], den = node[1];
+ Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
+ Node divByZeroNum = nm->mkNode(kind::APPLY_UF, d_divByZero, num);
+ Node divTotalNumDen = nm->mkNode(kind::DIVISION_TOTAL, num, den);
+ return nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
+ break;
+ }
+
+ case kind::INTS_DIVISION: {
+ // partial function: integer div
+ if(d_intDivByZero.isNull()) {
+ d_intDivByZero = nm->mkSkolem("intDivByZero", nm->mkFunctionType(nm->integerType(), nm->integerType()),
+ "partial integer division", NodeManager::SKOLEM_EXACT_NAME);
+ logicRequest.widenLogic(THEORY_UF);
+ }
+ TNode num = node[0], den = node[1];
+ Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
+ Node intDivByZeroNum = nm->mkNode(kind::APPLY_UF, d_intDivByZero, num);
+ Node intDivTotalNumDen = nm->mkNode(kind::INTS_DIVISION_TOTAL, num, den);
+ return nm->mkNode(kind::ITE, den_eq_0, intDivByZeroNum, intDivTotalNumDen);
+ break;
+ }
+
+ case kind::INTS_MODULUS: {
+ // partial function: mod
+ if(d_modZero.isNull()) {
+ d_modZero = nm->mkSkolem("modZero", nm->mkFunctionType(nm->integerType(), nm->integerType()),
+ "partial modulus", NodeManager::SKOLEM_EXACT_NAME);
+ logicRequest.widenLogic(THEORY_UF);
+ }
+ TNode num = node[0], den = node[1];
+ Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(Rational(0)));
+ Node modZeroNum = nm->mkNode(kind::APPLY_UF, d_modZero, num);
+ Node modTotalNumDen = nm->mkNode(kind::INTS_MODULUS_TOTAL, num, den);
+ return nm->mkNode(kind::ITE, den_eq_0, modZeroNum, modTotalNumDen);
+ break;
+ }
+
+ case kind::ABS: {
+ return nm->mkNode(kind::ITE, nm->mkNode(kind::LT, node[0], nm->mkConst(Rational(0))), nm->mkNode(kind::UMINUS, node[0]), node[0]);
+ break;
+ }
+
+ default:
+ return node;
+ break;
+ }
+
+ Unreachable();
+}
+
+
}/* CVC4::theory::arith namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/arith/theory_arith_private.h b/src/theory/arith/theory_arith_private.h
index 7ff93b021..68e839ef8 100644
--- a/src/theory/arith/theory_arith_private.h
+++ b/src/theory/arith/theory_arith_private.h
@@ -88,6 +88,10 @@ namespace quantifiers {
}
namespace arith {
+class BranchCutInfo;
+class TreeLog;
+class ApproximateStatistics;
+
/**
* Implementation of QF_LRA.
* Based upon:
@@ -107,6 +111,8 @@ private:
BoundInfoMap d_rowTracking;
+ ConstraintCPVec d_conflictBuffer;
+
/**
* The constraint database associated with the theory.
* This must be declared before ArithPartialModel.
@@ -122,6 +128,7 @@ private:
// if unknown, the simplex priority queue cannot be emptied
int d_unknownsInARow;
+ bool d_replayedLemmas;
/**
* This counter is false if nothing has been done since the last cut.
@@ -174,22 +181,22 @@ private:
* A superset of all of the assertions that currently are not the literal for
* their constraint do not match constraint literals. Not just the witnesses.
*/
- context::CDInsertHashMap<Node, Constraint, NodeHashFunction> d_assertionsThatDoNotMatchTheirLiterals;
+ context::CDInsertHashMap<Node, ConstraintP, NodeHashFunction> d_assertionsThatDoNotMatchTheirLiterals;
/** Returns true if x is of type Integer. */
inline bool isInteger(ArithVar x) const {
return d_partialModel.isInteger(x);
- //return d_variableTypes[x] >= ATInteger;
}
- /** This is the set of variables initially introduced as slack variables. */
- //std::vector<bool> d_slackVars;
- /** Returns true if the variable was initially introduced as a slack variable. */
- inline bool isSlackVariable(ArithVar x) const{
- return d_partialModel.isSlack(x);
- //return d_slackVars[x];
+ /** Returns true if the variable was initially introduced as an auxiliary variable. */
+ inline bool isAuxiliaryVariable(ArithVar x) const{
+ return d_partialModel.isAuxiliary(x);
+ }
+
+ inline bool isIntegerInput(ArithVar x) const {
+ return d_partialModel.isIntegerInput(x);
}
/**
@@ -215,7 +222,7 @@ private:
* List of all of the disequalities asserted in the current context that are not known
* to be satisfied.
*/
- context::CDQueue<Constraint> d_diseqQueue;
+ context::CDQueue<ConstraintP> d_diseqQueue;
/**
* Constraints that have yet to be processed by proagation work list.
@@ -231,9 +238,9 @@ private:
* then d_cPL[1] is the previous lowerBound in d_partialModel,
* and d_cPL[2] is the previous upperBound in d_partialModel.
*/
- std::deque<Constraint> d_currentPropagationList;
+ std::deque<ConstraintP> d_currentPropagationList;
- context::CDQueue<Constraint> d_learnedBounds;
+ context::CDQueue<ConstraintP> d_learnedBounds;
/**
@@ -277,15 +284,31 @@ private:
/** This is only used by simplex at the moment. */
- context::CDList<Node> d_conflicts;
+ context::CDList<ConstraintCPVec> d_conflicts;
+ context::CDO<Node> d_blackBoxConflict;
public:
- inline void raiseConflict(Node n){ d_conflicts.push_back(n); }
+ inline void raiseConflict(const ConstraintCPVec& cv){
+ d_conflicts.push_back(cv);
+ }
+
+ void raiseConflict(ConstraintCP a, ConstraintCP b);
+ void raiseConflict(ConstraintCP a, ConstraintCP b, ConstraintCP c);
+
+ inline void blackBoxConflict(Node bb){
+ if(d_blackBoxConflict.get().isNull()){
+ d_blackBoxConflict = bb;
+ }
+ }
private:
+ inline bool conflictQueueEmpty() const {
+ return d_conflicts.empty();
+ }
+
/** Returns true iff a conflict has been raised. */
- inline bool inConflict() const {
- return !d_conflicts.empty();
+ inline bool anyConflict() const {
+ return !conflictQueueEmpty() || !d_blackBoxConflict.get().isNull();
}
/**
@@ -314,6 +337,7 @@ private:
/** This keeps track of difference equalities. Mostly for sharing. */
ArithCongruenceManager d_congruenceManager;
+ context::CDO<bool> d_cmEnabled;
/** This implements the Simplex decision procedure. */
DualSimplexDecisionProcedure d_dualSimplex;
@@ -323,6 +347,22 @@ private:
bool solveRealRelaxation(Theory::Effort effortLevel);
+ /* Returns true if this is heuristically a good time to try
+ * to solve the integers.
+ */
+ bool attemptSolveInteger(Theory::Effort effortLevel, bool emmmittedLemmaOrSplit);
+ bool replayLemmas(ApproximateSimplex* approx);
+ void solveInteger(Theory::Effort effortLevel);
+ bool safeToCallApprox() const;
+ SimplexDecisionProcedure& selectSimplex(bool pass1);
+ SimplexDecisionProcedure* d_pass1SDP;
+ SimplexDecisionProcedure* d_otherSDP;
+ /* Sets d_qflraStatus */
+ void importSolution(const ApproximateSimplex::Solution& solution);
+ bool solveRelaxationOrPanic(Theory::Effort effortLevel);
+ context::CDO<int> d_lastContextIntegerAttempted;
+ bool replayLog(ApproximateSimplex* approx);
+
class ModelException : public Exception {
public:
ModelException(TNode n, const char* msg) throw ();
@@ -357,6 +397,7 @@ public:
* Does non-context dependent setup for a node connected to a theory.
*/
void preRegisterTerm(TNode n);
+ Node expandDefinition(LogicRequest &logicRequest, Node node);
void setMasterEqualityEngine(eq::EqualityEngine* eq);
void setQuantifiersEngine(QuantifiersEngine* qe);
@@ -412,16 +453,28 @@ private:
/**
- * Looks for the next integer variable without an integer assignment in a round robin fashion.
- * Changes the value of d_nextIntegerCheckVar.
+ * Looks for the next integer variable without an integer assignment in a
+ * round-robin fashion. Changes the value of d_nextIntegerCheckVar.
*
- * If this returns false, d_nextIntegerCheckVar does not have an integer assignment.
- * If this returns true, all integer variables have an integer assignment.
+ * This returns true if all integer variables have integer assignments.
+ * If this returns false, d_nextIntegerCheckVar does not have an integer
+ * assignment.
*/
bool hasIntegerModel();
/**
- * Issues branches for non-slack integer variables with non-integer assignments.
+ * Looks for through the variables starting at d_nextIntegerCheckVar
+ * for the first integer variable that is between its upper and lower bounds
+ * that has a non-integer assignment.
+ *
+ * If assumeBounds is true, skip the check that the variable is in bounds.
+ *
+ * If there is no such variable, returns ARITHVAR_SENTINEL;
+ */
+ ArithVar nextIntegerViolatation(bool assumeBounds) const;
+
+ /**
+ * Issues branches for non-auxiliary integer variables with non-integer assignments.
* Returns a cut for a lemma.
* If there is an integer model, this returns Node::null().
*/
@@ -432,8 +485,11 @@ public:
* This requests a new unique ArithVar value for x.
* This also does initial (not context dependent) set up for a variable,
* except for setting up the initial.
+ *
+ * If aux is true, this is an auxiliary variable.
+ * If internal is true, x might not be unique up to a constant multiple.
*/
- ArithVar requestArithVar(TNode x, bool slack);
+ ArithVar requestArithVar(TNode x, bool aux, bool internal);
public:
const BoundsInfo& boundsInfo(ArithVar basic) const;
@@ -443,8 +499,8 @@ private:
/** Initial (not context dependent) sets up for a variable.*/
void setupBasicValue(ArithVar x);
- /** Initial (not context dependent) sets up for a new slack variable.*/
- void setupSlack(TNode left);
+ /** Initial (not context dependent) sets up for a new auxiliary variable.*/
+ void setupAuxiliary(TNode left);
/**
@@ -462,10 +518,10 @@ private:
* a node describing this conflict is returned.
* If this new bound is not in conflict, Node::null() is returned.
*/
- bool AssertLower(Constraint constraint);
- bool AssertUpper(Constraint constraint);
- bool AssertEquality(Constraint constraint);
- bool AssertDisequality(Constraint constraint);
+ bool AssertLower(ConstraintP constraint);
+ bool AssertUpper(ConstraintP constraint);
+ bool AssertEquality(ConstraintP constraint);
+ bool AssertDisequality(ConstraintP constraint);
/** Tracks the bounds that were updated in the current round. */
DenseSet d_updatedBounds;
@@ -488,7 +544,14 @@ private:
/** Attempt to perform a row propagation where every variable is a potential candidate.*/
bool attemptFull(RowIndex ridx, bool rowUp);
bool tryToPropagate(RowIndex ridx, bool rowUp, ArithVar v, bool vUp, const DeltaRational& bound);
- bool rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, Constraint bestImplied);
+ bool rowImplicationCanBeApplied(RowIndex ridx, bool rowUp, ConstraintP bestImplied);
+ //void enqueueConstraints(std::vector<ConstraintCP>& out, Node n) const;
+ //ConstraintCPVec resolveOutPropagated(const ConstraintCPVec& v, const std::set<ConstraintCP>& propagated) const;
+ void resolveOutPropagated(std::vector<ConstraintCPVec>& confs, const std::set<ConstraintCP>& propagated) const;
+ void subsumption(std::vector<ConstraintCPVec>& confs) const;
+
+ Node cutToLiteral(ApproximateSimplex* approx, const CutInfo& cut) const;
+ Node branchToNode(ApproximateSimplex* approx, const NodeLog& cut) const throw(RationalFromDoubleException);
void propagateCandidates();
@@ -512,8 +575,8 @@ private:
* Returns a conflict if one was found.
* Returns Node::null if no conflict was found.
*/
- Constraint constraintFromFactQueue();
- bool assertionCases(Constraint c);
+ ConstraintP constraintFromFactQueue();
+ bool assertionCases(ConstraintP c);
/**
* Returns the basic variable with the shorted row containing a non-basic variable.
@@ -554,7 +617,7 @@ private:
(d_containing.d_out)->setIncomplete();
d_nlIncomplete = true;
}
- inline void outputLemma(TNode lem) { (d_containing.d_out)->lemma(lem); }
+ void outputLemma(TNode lem);
inline void outputPropagate(TNode lit) { (d_containing.d_out)->propagate(lit); }
inline void outputRestart() { (d_containing.d_out)->demandRestart(); }
@@ -565,6 +628,8 @@ private:
return (d_containing.d_valuation).getSatValue(n);
}
+ context::CDQueue<Node> d_approxCuts;
+ std::vector<Node> d_acTmp;
/** Counts the number of fullCheck calls to arithmetic. */
uint32_t d_fullCheckCounter;
@@ -581,12 +646,49 @@ private:
context::CDO<bool> d_guessedCoeffSet;
ArithRatPairVec d_guessedCoeffs;
+
+ TreeLog* d_treeLog;
+ TreeLog& getTreeLog();
+
+
+ ArithVarVec d_replayVariables;
+ std::vector<ConstraintP> d_replayConstraints;
+ DenseMap<Rational> d_lhsTmp;
+
+ /* Approximate simpplex solvers are given a copy of their stats */
+ ApproximateStatistics* d_approxStats;
+ ApproximateStatistics& getApproxStats();
+ context::CDO<int32_t> d_attemptSolveIntTurnedOff;
+ void turnOffApproxFor(int32_t rounds);
+ bool getSolveIntegerResource();
+
+ void tryBranchCut(ApproximateSimplex* approx, int nid, BranchCutInfo& bl);
+ std::vector<ConstraintCPVec> replayLogRec(ApproximateSimplex* approx, int nid, ConstraintP bc, int depth);
+
+ std::pair<ConstraintP, ArithVar> replayGetConstraint(const CutInfo& info);
+ std::pair<ConstraintP, ArithVar> replayGetConstraint(ApproximateSimplex* approx, const NodeLog& nl) throw(RationalFromDoubleException);
+ std::pair<ConstraintP, ArithVar> replayGetConstraint(const DenseMap<Rational>& lhs, Kind k, const Rational& rhs, bool branch);
+
+ void replayAssert(ConstraintP c);
+ //ConstConstraintVec toExplanation(Node n) const;
+
+ // Returns true if the node contains a literal
+ // that is an arithmetic literal and is not a sat literal
+ // No caching is done so this should likely only
+ // be called carefully!
+ bool hasFreshArithLiteral(Node n) const;
+
+ int32_t d_dioSolveResources;
+ bool getDioCuttingResource();
+
+ uint32_t d_solveIntMaybeHelp, d_solveIntAttempts;
+
/** These fields are designed to be accessible to TheoryArith methods. */
class Statistics {
public:
IntStat d_statAssertUpperConflicts, d_statAssertLowerConflicts;
- IntStat d_statUserVariables, d_statSlackVariables;
+ IntStat d_statUserVariables, d_statAuxiliaryVariables;
IntStat d_statDisequalitySplits;
IntStat d_statDisequalityConflicts;
TimerStat d_simplifyTimer;
@@ -614,6 +716,51 @@ private:
IntStat d_commitsOnConflicts;
IntStat d_nontrivialSatChecks;
+ IntStat d_replayLogRecCount,
+ d_replayLogRecConflictEscalation,
+ d_replayLogRecEarlyExit,
+ d_replayBranchCloseFailures,
+ d_replayLeafCloseFailures,
+ d_replayBranchSkips,
+ d_mirCutsAttempted,
+ d_gmiCutsAttempted,
+ d_branchCutsAttempted,
+ d_cutsReconstructed,
+ d_cutsReconstructionFailed,
+ d_cutsProven,
+ d_cutsProofFailed,
+ d_mipReplayLemmaCalls,
+ d_mipExternalCuts,
+ d_mipExternalBranch;
+
+ IntStat d_inSolveInteger,
+ d_branchesExhausted,
+ d_execExhausted,
+ d_pivotsExhausted,
+ d_panicBranches,
+ d_relaxCalls,
+ d_relaxLinFeas,
+ d_relaxLinFeasFailures,
+ d_relaxLinInfeas,
+ d_relaxLinInfeasFailures,
+ d_relaxLinExhausted,
+ d_relaxOthers;
+
+ IntStat d_applyRowsDeleted;
+ TimerStat d_replaySimplexTimer;
+
+ TimerStat d_replayLogTimer,
+ d_solveIntTimer,
+ d_solveRealRelaxTimer;
+
+ IntStat d_solveIntCalls,
+ d_solveStandardEffort;
+
+ IntStat d_approxDisabled;
+ IntStat d_replayAttemptFailed;
+
+ IntStat d_cutsRejectedDuringReplay;
+ IntStat d_cutsRejectedDuringLemmas;
HistogramStat<uint32_t> d_satPivots;
HistogramStat<uint32_t> d_unsatPivots;
@@ -626,6 +773,26 @@ private:
Statistics d_statistics;
+ /**
+ * Function symbol used to implement uninterpreted division-by-zero
+ * semantics. Needed to deal with partial division function ("/").
+ */
+ Node d_divByZero;
+
+ /**
+ * Function symbol used to implement uninterpreted
+ * int-division-by-zero semantics. Needed to deal with partial
+ * function "div".
+ */
+ Node d_intDivByZero;
+
+ /**
+ * Function symbol used to implement uninterpreted mod-zero
+ * semantics. Needed to deal with partial function "mod".
+ */
+ Node d_modZero;
+
+
};/* class TheoryArithPrivate */
}/* CVC4::theory::arith namespace */
diff --git a/src/theory/arrays/theory_arrays.cpp b/src/theory/arrays/theory_arrays.cpp
index b82216378..cd9fd2497 100644
--- a/src/theory/arrays/theory_arrays.cpp
+++ b/src/theory/arrays/theory_arrays.cpp
@@ -374,11 +374,17 @@ void TheoryArrays::explain(TNode literal, std::vector<TNode>& assumptions) {
// 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 || atom.getKind() == kind::IFF) {
- d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions);
+ d_equalityEngine.explainEquality(atom[0], atom[1], polarity, assumptions, eqp);
} else {
d_equalityEngine.explainPredicate(atom, polarity, assumptions);
}
+ if( eqp ){
+ Debug("array-pf") << " Proof is : " << std::endl;
+ eqp->debug_print("array-pf");
+ }
}
@@ -435,7 +441,7 @@ void TheoryArrays::preRegisterTermInternal(TNode node)
if (ni != node) {
preRegisterTermInternal(ni);
}
- d_equalityEngine.assertEquality(ni.eqNode(s[2]), true, d_true);
+ d_equalityEngine.assertEquality(ni.eqNode(s[2]), true, d_true, eq::MERGED_ARRAYS_ROW1);
Assert(++it == stores->end());
}
}
@@ -482,7 +488,7 @@ void TheoryArrays::preRegisterTermInternal(TNode node)
}
// Apply RIntro1 Rule
- d_equalityEngine.assertEquality(ni.eqNode(v), true, d_true);
+ d_equalityEngine.assertEquality(ni.eqNode(v), true, d_true, eq::MERGED_ARRAYS_ROW1);
}
d_infoMap.addStore(node, node);
@@ -1892,7 +1898,7 @@ void TheoryArrays::checkRIntro1(TNode a, TNode b)
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_equalityEngine.assertEquality(ni.eqNode(s[2]), true, d_true, eq::MERGED_ARRAYS_ROW1);
}
}
@@ -2283,7 +2289,7 @@ void TheoryArrays::queueRowLemma(RowLemmaType lem)
if (!bjExists) {
preRegisterTermInternal(bj);
}
- d_equalityEngine.assertEquality(aj_eq_bj, true, reason);
+ d_equalityEngine.assertEquality(aj_eq_bj, true, reason, eq::MERGED_ARRAYS_ROW);
++d_numProp;
return;
}
@@ -2293,7 +2299,7 @@ void TheoryArrays::queueRowLemma(RowLemmaType lem)
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_equalityEngine.assertEquality(i_eq_j, true, reason, eq::MERGED_ARRAYS_ROW);
++d_numProp;
return;
}
diff --git a/src/theory/bv/theory_bv.cpp b/src/theory/bv/theory_bv.cpp
index 6daf99c8b..5d5e0a97c 100644
--- a/src/theory/bv/theory_bv.cpp
+++ b/src/theory/bv/theory_bv.cpp
@@ -25,6 +25,7 @@
#include "theory/bv/bv_subtheory_core.h"
#include "theory/bv/bv_subtheory_inequality.h"
#include "theory/bv/bv_subtheory_bitblast.h"
+#include "theory/bv/theory_bv_rewriter.h"
#include "theory/theory_model.h"
using namespace CVC4;
@@ -102,6 +103,69 @@ TheoryBV::Statistics::~Statistics() {
StatisticsRegistry::unregisterStat(&d_weightComputationTimer);
}
+Node TheoryBV::getBVDivByZero(Kind k, unsigned width) {
+ NodeManager* nm = NodeManager::currentNM();
+ if (k == kind::BITVECTOR_UDIV) {
+ if (d_BVDivByZero.find(width) == d_BVDivByZero.end()) {
+ // lazily create the function symbols
+ 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;
+ }
+ return d_BVDivByZero[width];
+ }
+ else if (k == kind::BITVECTOR_UREM) {
+ if (d_BVRemByZero.find(width) == d_BVRemByZero.end()) {
+ 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;
+ }
+ return d_BVRemByZero[width];
+ }
+
+ Unreachable();
+}
+
+
+Node TheoryBV::expandDefinition(LogicRequest &logicRequest, Node node) {
+ Debug("bitvector-expandDefinition") << "TheoryBV::expandDefinition(" << node << ")" << std::endl;
+
+ switch (node.getKind()) {
+ case kind::BITVECTOR_SDIV:
+ case kind::BITVECTOR_SREM:
+ case kind::BITVECTOR_SMOD:
+ return TheoryBVRewriter::eliminateBVSDiv(node);
+ break;
+
+ case kind::BITVECTOR_UDIV:
+ case kind::BITVECTOR_UREM: {
+ NodeManager* nm = NodeManager::currentNM();
+ unsigned width = node.getType().getBitVectorSize();
+ Node divByZero = getBVDivByZero(node.getKind(), width);
+ TNode num = node[0], den = node[1];
+ Node den_eq_0 = nm->mkNode(kind::EQUAL, den, nm->mkConst(BitVector(width, Integer(0))));
+ Node divByZeroNum = nm->mkNode(kind::APPLY_UF, divByZero, num);
+ Node divTotalNumDen = nm->mkNode(node.getKind() == kind::BITVECTOR_UDIV ? kind::BITVECTOR_UDIV_TOTAL :
+ kind::BITVECTOR_UREM_TOTAL, num, den);
+ node = nm->mkNode(kind::ITE, den_eq_0, divByZeroNum, divTotalNumDen);
+ logicRequest.widenLogic(THEORY_UF);
+ return node;
+ }
+ break;
+
+ default:
+ return node;
+ break;
+ }
+
+ Unreachable();
+}
void TheoryBV::preRegisterTerm(TNode node) {
diff --git a/src/theory/bv/theory_bv.h b/src/theory/bv/theory_bv.h
index 3d093c861..a5e2ac9ea 100644
--- a/src/theory/bv/theory_bv.h
+++ b/src/theory/bv/theory_bv.h
@@ -25,6 +25,7 @@
#include "context/cdhashset.h"
#include "theory/bv/theory_bv_utils.h"
#include "util/statistics_registry.h"
+#include "util/hash.h"
#include "theory/bv/bv_subtheory.h"
namespace CVC4 {
@@ -46,6 +47,8 @@ class TheoryBV : public Theory {
std::vector<SubtheorySolver*> d_subtheories;
__gnu_cxx::hash_map<SubTheory, SubtheorySolver*, std::hash<int> > d_subtheoryMap;
+
+
public:
TheoryBV(context::Context* c, context::UserContext* u, OutputChannel& out, Valuation valuation, const LogicInfo& logicInfo);
@@ -53,6 +56,8 @@ public:
void setMasterEqualityEngine(eq::EqualityEngine* eq);
+ Node expandDefinition(LogicRequest &logicRequest, Node node);
+
void preRegisterTerm(TNode n);
void check(Effort e);
@@ -85,6 +90,25 @@ private:
Statistics d_statistics;
+
+ /**
+ * Return the uinterpreted function symbol corresponding to division-by-zero
+ * for this particular bit-width
+ * @param k should be UREM or UDIV
+ * @param width
+ *
+ * @return
+ */
+ Node getBVDivByZero(Kind k, unsigned width);
+
+ /**
+ * Maps from bit-vector width to divison-by-zero uninterpreted
+ * function symbols.
+ */
+ __gnu_cxx::hash_map<unsigned, Node> d_BVDivByZero;
+ __gnu_cxx::hash_map<unsigned, Node> d_BVRemByZero;
+
+
context::CDO<bool> d_lemmasAdded;
// Are we in conflict?
diff --git a/src/theory/ite_utilities.cpp b/src/theory/ite_utilities.cpp
index 1b4e096f2..a4af4f26f 100644
--- a/src/theory/ite_utilities.cpp
+++ b/src/theory/ite_utilities.cpp
@@ -28,6 +28,7 @@ namespace CVC4 {
namespace theory {
namespace ite {
+
inline static bool isTermITE(TNode e) {
return (e.getKind() == kind::ITE && !e.getType().isBoolean());
}
@@ -77,9 +78,7 @@ struct CTIVStackElement {
} /* CVC4::theory::ite */
-
-
-ITEUtilities::ITEUtilities(ContainsTermITEVistor* containsVisitor)
+ITEUtilities::ITEUtilities(ContainsTermITEVisitor* containsVisitor)
: d_containsVisitor(containsVisitor)
, d_compressor(NULL)
, d_simplifier(NULL)
@@ -144,11 +143,11 @@ void ITEUtilities::clear(){
}
/********************* */
-/* ContainsTermITEVistor
+/* ContainsTermITEVisitor
*/
-ContainsTermITEVistor::ContainsTermITEVistor(): d_cache() {}
-ContainsTermITEVistor::~ContainsTermITEVistor(){}
-bool ContainsTermITEVistor::containsTermITE(TNode e){
+ContainsTermITEVisitor::ContainsTermITEVisitor(): d_cache() {}
+ContainsTermITEVisitor::~ContainsTermITEVisitor(){}
+bool ContainsTermITEVisitor::containsTermITE(TNode e){
/* throughout execution skip through NOT nodes. */
e = (e.getKind() == kind::NOT) ? e[0] : e;
if(ite::triviallyContainsNoTermITEs(e)){ return false; }
@@ -197,7 +196,7 @@ bool ContainsTermITEVistor::containsTermITE(TNode e){
}
return foundTermIte;
}
-void ContainsTermITEVistor::garbageCollect() {
+void ContainsTermITEVisitor::garbageCollect() {
d_cache.clear();
}
@@ -249,7 +248,7 @@ void IncomingArcCounter::clear() {
/********************* */
/* ITECompressor
*/
-ITECompressor::ITECompressor(ContainsTermITEVistor* contains)
+ITECompressor::ITECompressor(ContainsTermITEVisitor* contains)
: d_contains(contains)
, d_assertions(NULL)
, d_incoming(true, true)
@@ -547,7 +546,7 @@ uint32_t TermITEHeightCounter::termITEHeight(TNode e){
-ITESimplifier::ITESimplifier(ContainsTermITEVistor* contains)
+ITESimplifier::ITESimplifier(ContainsTermITEVisitor* contains)
: d_containsVisitor(contains)
, d_termITEHeight()
, d_constantLeaves()
@@ -1608,6 +1607,5 @@ Node ITECareSimplifier::simplifyWithCare(TNode e)
return substitute(e, substTable, cache);
}
-
} /* namespace theory */
} /* namespace CVC4 */
diff --git a/src/theory/ite_utilities.h b/src/theory/ite_utilities.h
index d9e6120aa..7f0986ecb 100644
--- a/src/theory/ite_utilities.h
+++ b/src/theory/ite_utilities.h
@@ -31,7 +31,7 @@
namespace CVC4 {
namespace theory {
-class ContainsTermITEVistor;
+class ContainsTermITEVisitor;
class IncomingArcCounter;
class TermITEHeightCounter;
class ITECompressor;
@@ -40,7 +40,7 @@ class ITECareSimplifier;
class ITEUtilities {
public:
- ITEUtilities(ContainsTermITEVistor* containsVisitor);
+ ITEUtilities(ContainsTermITEVisitor* containsVisitor);
~ITEUtilities();
Node simpITE(TNode assertion);
@@ -55,7 +55,7 @@ public:
void clear();
private:
- ContainsTermITEVistor* d_containsVisitor;
+ ContainsTermITEVisitor* d_containsVisitor;
ITECompressor* d_compressor;
ITESimplifier* d_simplifier;
ITECareSimplifier* d_careSimp;
@@ -64,10 +64,10 @@ private:
/**
* A caching visitor that computes whether a node contains a term ite.
*/
-class ContainsTermITEVistor {
+class ContainsTermITEVisitor {
public:
- ContainsTermITEVistor();
- ~ContainsTermITEVistor();
+ ContainsTermITEVisitor();
+ ~ContainsTermITEVisitor();
/** returns true if a node contains a term ite. */
bool containsTermITE(TNode n);
@@ -140,7 +140,7 @@ private:
*/
class ITECompressor {
public:
- ITECompressor(ContainsTermITEVistor* contains);
+ ITECompressor(ContainsTermITEVisitor* contains);
~ITECompressor();
/* returns false if an assertion is discovered to be equal to false. */
@@ -153,7 +153,7 @@ private:
Node d_true; /* Copy of true. */
Node d_false; /* Copy of false. */
- ContainsTermITEVistor* d_contains;
+ ContainsTermITEVisitor* d_contains;
std::vector<Node>* d_assertions;
IncomingArcCounter d_incoming;
@@ -180,7 +180,7 @@ private:
class ITESimplifier {
public:
- ITESimplifier(ContainsTermITEVistor* d_containsVisitor);
+ ITESimplifier(ContainsTermITEVisitor* d_containsVisitor);
~ITESimplifier();
Node simpITE(TNode assertion);
@@ -192,7 +192,7 @@ private:
Node d_true;
Node d_false;
- ContainsTermITEVistor* d_containsVisitor;
+ ContainsTermITEVisitor* d_containsVisitor;
inline bool containsTermITE(TNode n) {
return d_containsVisitor->containsTermITE(n);
}
diff --git a/src/theory/logic_info.h b/src/theory/logic_info.h
index 2448898c0..a0777ae70 100644
--- a/src/theory/logic_info.h
+++ b/src/theory/logic_info.h
@@ -64,7 +64,6 @@ class CVC4_PUBLIC LogicInfo {
case theory::THEORY_BUILTIN:
case theory::THEORY_BOOL:
case theory::THEORY_QUANTIFIERS:
- case theory::THEORY_REWRITERULES:
return false;
default:
return true;
@@ -117,7 +116,7 @@ public:
/** Is this a quantified logic? */
bool isQuantified() const {
CheckArgument(d_locked, *this, "This LogicInfo isn't locked yet, and cannot be queried");
- return isTheoryEnabled(theory::THEORY_QUANTIFIERS) || isTheoryEnabled(theory::THEORY_REWRITERULES);
+ return isTheoryEnabled(theory::THEORY_QUANTIFIERS);
}
/** Is this the all-inclusive logic? */
@@ -214,7 +213,6 @@ public:
*/
void enableQuantifiers() {
enableTheory(theory::THEORY_QUANTIFIERS);
- enableTheory(theory::THEORY_REWRITERULES);
}
/**
@@ -222,7 +220,6 @@ public:
*/
void disableQuantifiers() {
disableTheory(theory::THEORY_QUANTIFIERS);
- disableTheory(theory::THEORY_REWRITERULES);
}
// these are for arithmetic
diff --git a/src/theory/quantifiers/bounded_integers.cpp b/src/theory/quantifiers/bounded_integers.cpp
index 78f989807..bec8ea350 100644
--- a/src/theory/quantifiers/bounded_integers.cpp
+++ b/src/theory/quantifiers/bounded_integers.cpp
@@ -18,6 +18,7 @@
#include "theory/quantifiers/quant_util.h"
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/model_engine.h"
+#include "theory/quantifiers/term_database.h"
using namespace CVC4;
using namespace std;
@@ -274,7 +275,7 @@ void BoundedIntegers::registerQuantifier( Node f ) {
for( unsigned i=0; i<d_set[f].size(); i++) {
Node v = d_set[f][i];
Node r = d_range[f][v];
- if( quantifiers::TermDb::hasBoundVarAttr(r) ){
+ if( r.hasBoundVar() ){
//introduce a new bound
Node new_range = NodeManager::currentNM()->mkSkolem( "bir_$$", r.getType(), "bound for term" );
d_nground_range[f][v] = d_range[f][v];
@@ -384,5 +385,5 @@ void BoundedIntegers::getBoundValues( Node f, Node v, RepSetIterator * rsi, Node
}
bool BoundedIntegers::isGroundRange(Node f, Node v) {
- return isBoundVar(f,v) && !quantifiers::TermDb::hasBoundVarAttr(getLowerBound(f,v)) && !quantifiers::TermDb::hasBoundVarAttr(getUpperBound(f,v));
+ return isBoundVar(f,v) && !getLowerBound(f,v).hasBoundVar() && !getUpperBound(f,v).hasBoundVar();
}
diff --git a/src/theory/quantifiers/candidate_generator.cpp b/src/theory/quantifiers/candidate_generator.cpp
index 1e89bb1ea..9b5e506ea 100644
--- a/src/theory/quantifiers/candidate_generator.cpp
+++ b/src/theory/quantifiers/candidate_generator.cpp
@@ -18,6 +18,7 @@
#include "theory/quantifiers/term_database.h"
#include "theory/quantifiers/inst_match.h"
#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/options.h"
using namespace std;
using namespace CVC4;
@@ -62,7 +63,7 @@ CandidateGeneratorQE::CandidateGeneratorQE( QuantifiersEngine* qe, Node op ) :
Assert( !d_op.isNull() );
}
void CandidateGeneratorQE::resetInstantiationRound(){
- d_term_iter_limit = d_qe->getTermDatabase()->d_op_map[d_op].size();
+ d_term_iter_limit = d_qe->getTermDatabase()->getNumGroundTerms( d_op );
}
void CandidateGeneratorQE::reset( Node eqc ){
diff --git a/src/theory/quantifiers/first_order_model.cpp b/src/theory/quantifiers/first_order_model.cpp
index 8c00c5af4..f3203da4b 100644
--- a/src/theory/quantifiers/first_order_model.cpp
+++ b/src/theory/quantifiers/first_order_model.cpp
@@ -18,6 +18,7 @@
#include "theory/quantifiers/quantifiers_attributes.h"
#include "theory/quantifiers/full_model_check.h"
#include "theory/quantifiers/qinterval_builder.h"
+#include "theory/quantifiers/options.h"
#define USE_INDEX_ORDERING
diff --git a/src/theory/quantifiers/first_order_reasoning.cpp b/src/theory/quantifiers/first_order_reasoning.cpp
index a696af3c2..1c87dad7b 100644
--- a/src/theory/quantifiers/first_order_reasoning.cpp
+++ b/src/theory/quantifiers/first_order_reasoning.cpp
@@ -19,10 +19,11 @@
#include "theory/rewriter.h"
using namespace CVC4;
-using namespace CVC4::kind;
using namespace std;
-
-namespace CVC4 {
+using namespace CVC4::theory;
+using namespace CVC4::theory::quantifiers;
+using namespace CVC4::kind;
+using namespace CVC4::context;
void FirstOrderPropagation::collectLits( Node n, std::vector<Node> & lits ){
@@ -167,5 +168,3 @@ Node FirstOrderPropagation::simplify( Node n ) {
return NodeManager::currentNM()->mkNode( n.getKind(), children );
}
}
-
-}
diff --git a/src/theory/quantifiers/first_order_reasoning.h b/src/theory/quantifiers/first_order_reasoning.h
index 6bc5c21c1..92898eff5 100644
--- a/src/theory/quantifiers/first_order_reasoning.h
+++ b/src/theory/quantifiers/first_order_reasoning.h
@@ -25,6 +25,8 @@
#include "expr/type_node.h"
namespace CVC4 {
+namespace theory {
+namespace quantifiers {
class FirstOrderPropagation {
private:
@@ -41,5 +43,7 @@ public:
};
}
+}
+}
#endif
diff --git a/src/theory/quantifiers/full_model_check.cpp b/src/theory/quantifiers/full_model_check.cpp
index d542e878c..6c889781d 100644
--- a/src/theory/quantifiers/full_model_check.cpp
+++ b/src/theory/quantifiers/full_model_check.cpp
@@ -15,6 +15,7 @@
#include "theory/quantifiers/full_model_check.h"
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/options.h"
+#include "theory/quantifiers/term_database.h"
using namespace std;
using namespace CVC4;
diff --git a/src/theory/quantifiers/inst_gen.cpp b/src/theory/quantifiers/inst_gen.cpp
index 27b87e6a4..aaa65e630 100644
--- a/src/theory/quantifiers/inst_gen.cpp
+++ b/src/theory/quantifiers/inst_gen.cpp
@@ -16,6 +16,7 @@
#include "theory/quantifiers/model_engine.h"
#include "theory/quantifiers/model_builder.h"
#include "theory/quantifiers/first_order_model.h"
+#include "theory/quantifiers/term_database.h"
//#define CHILD_USE_CONSIDER
diff --git a/src/theory/quantifiers/inst_match_generator.cpp b/src/theory/quantifiers/inst_match_generator.cpp
index e1d301c09..13186c7cc 100644
--- a/src/theory/quantifiers/inst_match_generator.cpp
+++ b/src/theory/quantifiers/inst_match_generator.cpp
@@ -18,6 +18,7 @@
#include "theory/quantifiers/term_database.h"
#include "theory/quantifiers/candidate_generator.h"
#include "theory/quantifiers_engine.h"
+#include "theory/quantifiers/options.h"
using namespace std;
using namespace CVC4;
diff --git a/src/theory/quantifiers/inst_strategy_e_matching.cpp b/src/theory/quantifiers/inst_strategy_e_matching.cpp
index dee8192c1..0353b0b5f 100644
--- a/src/theory/quantifiers/inst_strategy_e_matching.cpp
+++ b/src/theory/quantifiers/inst_strategy_e_matching.cpp
@@ -97,22 +97,11 @@ void InstStrategyUserPatterns::addUserPattern( Node f, Node pat ){
//extend to literal matching
d_quantEngine->getPhaseReqTerms( f, nodes );
//check match option
- int matchOption = options::efficientEMatching() ? InstMatchGenerator::MATCH_GEN_EFFICIENT_E_MATCH : 0;
+ int matchOption = 0;
d_user_gen[f].push_back( Trigger::mkTrigger( d_quantEngine, f, nodes, matchOption, true, Trigger::TR_MAKE_NEW,
options::smartTriggers() ) );
}
}
-/*
-InstStrategyUserPatterns::Statistics::Statistics():
- d_instantiations("InstStrategyUserPatterns::Instantiations", 0)
-{
- StatisticsRegistry::registerStat(&d_instantiations);
-}
-
-InstStrategyUserPatterns::Statistics::~Statistics(){
- StatisticsRegistry::unregisterStat(&d_instantiations);
-}
-*/
void InstStrategyAutoGenTriggers::processResetInstantiationRound( Theory::Effort effort ){
//reset triggers
@@ -400,6 +389,14 @@ int InstStrategyFreeVariable::process( Node f, Theory::Effort effort, int e ){
}else{
Assert( index==(int)(childIndex.size())-1 );
unsigned nv = childIndex[index]+1;
+ if( options::cbqi() ){
+ //skip inst constant nodes
+ while( nv<maxs[index] && nv<=max_i &&
+ r==1 && quantifiers::TermDb::hasInstConstAttr( d_quantEngine->getTermDatabase()->d_type_map[f[0][index].getType()][nv] ) ){
+ childIndex[index]++;
+ nv = childIndex[index]+1;
+ }
+ }
if( nv<maxs[index] && nv<=max_i ){
childIndex[index]++;
index++;
diff --git a/src/theory/quantifiers/instantiation_engine.cpp b/src/theory/quantifiers/instantiation_engine.cpp
index 99dc29bf8..e5705882a 100644
--- a/src/theory/quantifiers/instantiation_engine.cpp
+++ b/src/theory/quantifiers/instantiation_engine.cpp
@@ -209,7 +209,7 @@ void InstantiationEngine::check( Theory::Effort e ){
for( int i=0; i<(int)d_quantEngine->getModel()->getNumAssertedQuantifiers(); i++ ){
Node n = d_quantEngine->getModel()->getAssertedQuantifier( i );
//it is not active if we have found the skolemized negation is unsat
- if( n.hasAttribute(QRewriteRuleAttribute()) ){
+ if( TermDb::isRewriteRule( n ) ){
d_quant_active[n] = false;
}else if( options::cbqi() && hasAddedCbqiLemma( n ) ){
Node cel = d_quantEngine->getTermDatabase()->getCounterexampleLiteral( n );
@@ -292,19 +292,23 @@ void InstantiationEngine::check( Theory::Effort e ){
}
void InstantiationEngine::registerQuantifier( Node f ){
- //Notice() << "do cbqi " << f << " ? " << std::endl;
- Node ceBody = d_quantEngine->getTermDatabase()->getInstConstantBody( f );
- if( !doCbqi( f ) ){
- d_quantEngine->addTermToDatabase( ceBody, true );
- }
+ if( !TermDb::isRewriteRule( f ) ){
+ //Notice() << "do cbqi " << f << " ? " << std::endl;
+ if( options::cbqi() ){
+ Node ceBody = d_quantEngine->getTermDatabase()->getInstConstantBody( f );
+ if( !doCbqi( f ) ){
+ d_quantEngine->addTermToDatabase( ceBody, true );
+ }
+ }
- //take into account user patterns
- if( f.getNumChildren()==3 ){
- Node subsPat = d_quantEngine->getTermDatabase()->getInstConstantNode( f[2], f );
- //add patterns
- for( int i=0; i<(int)subsPat.getNumChildren(); i++ ){
- //Notice() << "Add pattern " << subsPat[i] << " for " << f << std::endl;
- addUserPattern( f, subsPat[i] );
+ //take into account user patterns
+ if( f.getNumChildren()==3 ){
+ Node subsPat = d_quantEngine->getTermDatabase()->getInstConstantNode( f[2], f );
+ //add patterns
+ for( int i=0; i<(int)subsPat.getNumChildren(); i++ ){
+ //Notice() << "Add pattern " << subsPat[i] << " for " << f << std::endl;
+ addUserPattern( f, subsPat[i] );
+ }
}
}
}
diff --git a/src/theory/quantifiers/kinds b/src/theory/quantifiers/kinds
index ab0e9d934..795bc1ab4 100644
--- a/src/theory/quantifiers/kinds
+++ b/src/theory/quantifiers/kinds
@@ -48,4 +48,25 @@ typerule BOUND_VAR_LIST ::CVC4::theory::quantifiers::QuantifierBoundVarListTypeR
typerule INST_PATTERN ::CVC4::theory::quantifiers::QuantifierInstPatternTypeRule
typerule INST_PATTERN_LIST ::CVC4::theory::quantifiers::QuantifierInstPatternListTypeRule
+# for rewrite rules
+# types...
+sort RRHB_TYPE \
+ Cardinality::INTEGERS \
+ not-well-founded \
+ "head and body of the rule type"
+
+# operators...
+
+# variables, guards, RR_REWRITE/REDUCTION_RULE/DEDUCTION_RULE
+operator REWRITE_RULE 3 "general rewrite rule"
+#HEAD/BODY/TRIGGER
+operator RR_REWRITE 2:3 "actual rewrite rule"
+operator RR_REDUCTION 2:3 "actual reduction rule"
+operator RR_DEDUCTION 2:3 "actual deduction rule"
+
+typerule REWRITE_RULE ::CVC4::theory::quantifiers::RewriteRuleTypeRule
+typerule RR_REWRITE ::CVC4::theory::quantifiers::RRRewriteTypeRule
+typerule RR_REDUCTION ::CVC4::theory::quantifiers::RRRedDedTypeRule
+typerule RR_DEDUCTION ::CVC4::theory::quantifiers::RRRedDedTypeRule
+
endtheory
diff --git a/src/theory/quantifiers/model_builder.cpp b/src/theory/quantifiers/model_builder.cpp
index 502a34176..a12fc7ca2 100644
--- a/src/theory/quantifiers/model_builder.cpp
+++ b/src/theory/quantifiers/model_builder.cpp
@@ -24,6 +24,7 @@
#include "theory/quantifiers/quantifiers_attributes.h"
#include "theory/quantifiers/inst_gen.h"
#include "theory/quantifiers/trigger.h"
+#include "theory/quantifiers/options.h"
using namespace std;
using namespace CVC4;
@@ -39,7 +40,7 @@ TheoryEngineModelBuilder( qe->getTheoryEngine() ), d_curr_model( c, NULL ), d_qe
}
bool QModelBuilder::isQuantifierActive( Node f ) {
- return !f.hasAttribute(QRewriteRuleAttribute());
+ return !TermDb::isRewriteRule( f );
}
@@ -381,7 +382,7 @@ QModelBuilderIG::Statistics::~Statistics(){
}
bool QModelBuilderIG::isQuantifierActive( Node f ){
- return !f.hasAttribute(QRewriteRuleAttribute()) &&
+ return !TermDb::isRewriteRule( f ) &&
( d_considerAxioms || !f.getAttribute(AxiomAttribute()) ) && d_quant_sat.find( f )==d_quant_sat.end();
}
@@ -1038,7 +1039,7 @@ int QModelBuilderInstGen::getSelectionFormulaScore( Node fn ){
if( fn.getKind()==APPLY_UF ){
Node op = fn.getOperator();
//return total number of terms
- return d_qe->getTermDatabase()->d_op_count[op];
+ return d_qe->getTermDatabase()->d_op_nonred_count[op];
}else{
int score = 0;
for( size_t i=0; i<fn.getNumChildren(); i++ ){
diff --git a/src/theory/quantifiers/options b/src/theory/quantifiers/options
index 6d333521b..0865f2c0b 100644
--- a/src/theory/quantifiers/options
+++ b/src/theory/quantifiers/options
@@ -42,8 +42,6 @@ option clauseSplit --clause-split bool :default false
# forall x. P( x ) => f( S( x ) ) = x
option preSkolemQuant --pre-skolem-quant bool :read-write :default false
apply skolemization eagerly to bodies of quantified formulas
-option iteRemoveQuant --ite-remove-quant bool :default false
- apply ite removal to bodies of quantifiers
# Whether to perform agressive miniscoping
option aggressiveMiniscopeQuant --ag-miniscope-quant bool :default false
perform aggressive miniscoping for quantifiers
@@ -127,5 +125,9 @@ option qcfMode --quant-cf-mode=MODE CVC4::theory::quantifiers::QcfMode :default
option qcfWhenMode --quant-cf-when=MODE CVC4::theory::quantifiers::QcfWhenMode :default CVC4::theory::quantifiers::QCF_WHEN_MODE_DEFAULT :include "theory/quantifiers/modes.h" :handler CVC4::theory::quantifiers::stringToQcfWhenMode :handler-include "theory/quantifiers/options_handlers.h"
when to invoke conflict find mechanism for quantifiers
+option quantRewriteRules --rewrite-rules bool :default true
+ use rewrite rules module
+option rrOneInstPerRound --rr-one-inst-per-round bool :default false
+ add one instance of rewrite rule per round
endmodule
diff --git a/src/theory/quantifiers/options_handlers.h b/src/theory/quantifiers/options_handlers.h
index 9892009a3..e9c754d4a 100644
--- a/src/theory/quantifiers/options_handlers.h
+++ b/src/theory/quantifiers/options_handlers.h
@@ -131,6 +131,9 @@ conflict \n\
partial \n\
+ Apply QCF algorithm to instantiate heuristically as well. \n\
\n\
+partial \n\
++ Apply QCF to instantiate heuristically as well. \n\
+\n\
mc \n\
+ Apply QCF algorithm in a complete way, so that a model is ensured when it fails. \n\
\n\
diff --git a/src/theory/quantifiers/qinterval_builder.cpp b/src/theory/quantifiers/qinterval_builder.cpp
index ece519d1c..285834e96 100755
--- a/src/theory/quantifiers/qinterval_builder.cpp
+++ b/src/theory/quantifiers/qinterval_builder.cpp
@@ -14,6 +14,8 @@
#include "theory/quantifiers/qinterval_builder.h"
+#include "theory/quantifiers/term_database.h"
+
using namespace std;
using namespace CVC4;
diff --git a/src/theory/quantifiers/quant_conflict_find.cpp b/src/theory/quantifiers/quant_conflict_find.cpp
index ced4e1997..c0b318f23 100755
--- a/src/theory/quantifiers/quant_conflict_find.cpp
+++ b/src/theory/quantifiers/quant_conflict_find.cpp
@@ -18,6 +18,8 @@
#include "theory/quantifiers/quant_conflict_find.h"
#include "theory/quantifiers/quant_util.h"
#include "theory/theory_engine.h"
+#include "theory/quantifiers/options.h"
+#include "theory/quantifiers/term_database.h"
using namespace CVC4;
using namespace CVC4::kind;
@@ -93,7 +95,7 @@ void QuantInfo::initialize( Node q, Node qn ) {
if( d_vars[j].getKind()!=BOUND_VARIABLE ){
bool beneathQuant = d_nbeneathQuant.find( d_vars[j] )==d_nbeneathQuant.end();
d_var_mg[j] = new MatchGen( this, d_vars[j], true, beneathQuant );
- if( !d_var_mg[j]->isValid() && options::qcfMode()<QCF_PARTIAL ){
+ if( !d_var_mg[j]->isValid() ){
d_mg->setInvalid();
break;
}else{
@@ -107,28 +109,17 @@ void QuantInfo::initialize( Node q, Node qn ) {
std::vector< int > bvars;
d_mg->determineVariableOrder( this, bvars );
}
-
- //must also contain all variables?
- if( d_isPartial ){
- for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
- if( d_has_var.find( q[0][i] )==d_has_var.end() ){
- d_isPartial = false;
- d_mg->setInvalid();
- break;
- }
- }
- }
}
- Trace("qcf-qregister-summary") << "QCF register : " << ( d_mg->isValid() ? ( isPartial() ? "PARTIAL " : "VALID " ) : "INVALID" ) << " : " << q << std::endl;
+ Trace("qcf-qregister-summary") << "QCF register : " << ( d_mg->isValid() ? "VALID " : "INVALID" ) << " : " << q << std::endl;
}
void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant ) {
Trace("qcf-qregister-debug2") << "Register : " << n << std::endl;
if( n.getKind()==FORALL ){
registerNode( n[1], hasPol, pol, true );
- }else{
- if( n.getKind()!=OR && n.getKind()!=AND && n.getKind()!=IFF && n.getKind()!=NOT ){
- if( quantifiers::TermDb::hasBoundVarAttr( n ) ){
+ }else{
+ if( !MatchGen::isHandledBoolConnective( n ) ){
+ if( n.hasBoundVar() ){
//literals
if( n.getKind()==EQUAL ){
for( unsigned i=0; i<n.getNumChildren(); i++ ){
@@ -136,11 +127,9 @@ void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant )
}
}else if( MatchGen::isHandledUfTerm( n ) ){
flatten( n, beneathQuant );
- }else if( n.getKind()==ITE ){
- if( !n[1].getType().isBoolean() ){
- for( unsigned i=1; i<=2; i++ ){
- flatten( n[i], beneathQuant );
- }
+ }else if( n.getKind()==ITE ){
+ for( unsigned i=1; i<=2; i++ ){
+ flatten( n[i], beneathQuant );
}
}
}
@@ -162,7 +151,7 @@ void QuantInfo::registerNode( Node n, bool hasPol, bool pol, bool beneathQuant )
void QuantInfo::flatten( Node n, bool beneathQuant ) {
Trace("qcf-qregister-debug2") << "Flatten : " << n << std::endl;
- if( quantifiers::TermDb::hasBoundVarAttr( n ) ){
+ if( n.hasBoundVar() ){
if( d_var_num.find( n )==d_var_num.end() ){
Trace("qcf-qregister-debug2") << "Add FLATTEN VAR : " << n << std::endl;
d_var_num[n] = d_vars.size();
@@ -220,6 +209,8 @@ void QuantInfo::reset_round( QuantConflictFind * p ) {
for( std::map< int, MatchGen * >::iterator it = d_var_mg.begin(); it != d_var_mg.end(); ++it ){
it->second->reset_round( p );
}
+ //now, reset for matching
+ d_mg->reset( p, false, this );
}
int QuantInfo::getCurrentRepVar( int v ) {
@@ -249,6 +240,24 @@ TNode QuantInfo::getCurrentValue( TNode n ) {
}
}
+TNode QuantInfo::getCurrentExpValue( TNode n ) {
+ int v = getVarNum( n );
+ if( v==-1 ){
+ return n;
+ }else{
+ if( d_match[v].isNull() ){
+ return n;
+ }else{
+ Assert( getVarNum( d_match[v] )!=v );
+ if( d_match_term[v].isNull() ){
+ return getCurrentValue( d_match[v] );
+ }else{
+ return d_match_term[v];
+ }
+ }
+ }
+}
+
bool QuantInfo::getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq ) {
//check disequalities
std::map< int, std::map< TNode, int > >::iterator itd = d_curr_var_deq.find( v );
@@ -453,109 +462,113 @@ bool QuantInfo::isMatchSpurious( QuantConflictFind * p ) {
return false;
}
-bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assigned ) {
+bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue ) {
//assign values for variables that were unassigned (usually not necessary, but handles corner cases)
- Trace("qcf-check") << std::endl;
- std::vector< int > unassigned[2];
- std::vector< TypeNode > unassigned_tn[2];
- for( int i=0; i<getNumVars(); i++ ){
- if( d_match[i].isNull() ){
- //Assert( i<(int)q[0].getNumChildren() );
- int rindex = d_var_mg.find( i )==d_var_mg.end() ? 1 : 0;
- unassigned[rindex].push_back( i );
- unassigned_tn[rindex].push_back( getVar( i ).getType() );
- assigned.push_back( i );
+ bool doFail = false;
+ bool success = true;
+ if( doContinue ){
+ doFail = true;
+ success = false;
+ }else{
+ d_unassigned.clear();
+ d_unassigned_tn.clear();
+ std::vector< int > unassigned[2];
+ std::vector< TypeNode > unassigned_tn[2];
+ for( int i=0; i<getNumVars(); i++ ){
+ if( d_match[i].isNull() ){
+ int rindex = d_var_mg.find( i )==d_var_mg.end() ? 1 : 0;
+ unassigned[rindex].push_back( i );
+ unassigned_tn[rindex].push_back( getVar( i ).getType() );
+ assigned.push_back( i );
+ }
}
+ d_unassigned_nvar = unassigned[0].size();
+ for( unsigned i=0; i<2; i++ ){
+ d_unassigned.insert( d_unassigned.end(), unassigned[i].begin(), unassigned[i].end() );
+ d_unassigned_tn.insert( d_unassigned_tn.end(), unassigned_tn[i].begin(), unassigned_tn[i].end() );
+ }
+ d_una_eqc_count.clear();
+ d_una_index = 0;
}
- bool success = true;
- for( unsigned r=0; r<2; r++ ){
- if( success && !unassigned[r].empty() ){
- Trace("qcf-check") << "Assign to unassigned, rep = " << r << "..." << std::endl;
- int index = 0;
- std::vector< int > eqc_count;
- bool doFail = false;
- do {
- if( doFail ){
- Trace("qcf-check-unassign") << "Failure, try again..." << std::endl;
- }
- bool invalidMatch = false;
- while( ( index>=0 && (int)index<(int)unassigned[r].size() ) || invalidMatch || doFail ){
- invalidMatch = false;
- if( !doFail && index==(int)eqc_count.size() ){
- //check if it has now been assigned
- if( r==0 ){
- if( !isConstrainedVar( unassigned[r][index] ) ){
- eqc_count.push_back( -1 );
- }else{
- d_var_mg[ unassigned[r][index] ]->reset( p, true, this );
- eqc_count.push_back( 0 );
- }
+ if( !d_unassigned.empty() ){
+ Trace("qcf-check") << "Assign to unassigned..." << std::endl;
+ do {
+ if( doFail ){
+ Trace("qcf-check-unassign") << "Failure, try again..." << std::endl;
+ }
+ bool invalidMatch = false;
+ while( ( d_una_index>=0 && (int)d_una_index<(int)d_unassigned.size() ) || invalidMatch || doFail ){
+ invalidMatch = false;
+ if( !doFail && d_una_index==(int)d_una_eqc_count.size() ){
+ //check if it has now been assigned
+ if( d_una_index<d_unassigned_nvar ){
+ if( !isConstrainedVar( d_unassigned[d_una_index] ) ){
+ d_una_eqc_count.push_back( -1 );
}else{
- eqc_count.push_back( 0 );
+ d_var_mg[ d_unassigned[d_una_index] ]->reset( p, true, this );
+ d_una_eqc_count.push_back( 0 );
}
}else{
- if( r==0 ){
- if( !doFail && !isConstrainedVar( unassigned[r][index] ) ){
- Trace("qcf-check-unassign") << "Succeeded, variable unconstrained at " << index << std::endl;
- index++;
- }else if( !doFail && d_var_mg[unassigned[r][index]]->getNextMatch( p, this ) ){
- Trace("qcf-check-unassign") << "Succeeded match with mg at " << index << std::endl;
- index++;
+ d_una_eqc_count.push_back( 0 );
+ }
+ }else{
+ bool failed = false;
+ if( !doFail ){
+ if( d_una_index<d_unassigned_nvar ){
+ if( !isConstrainedVar( d_unassigned[d_una_index] ) ){
+ Trace("qcf-check-unassign") << "Succeeded, variable unconstrained at " << d_una_index << std::endl;
+ d_una_index++;
+ }else if( d_var_mg[d_unassigned[d_una_index]]->getNextMatch( p, this ) ){
+ Trace("qcf-check-unassign") << "Succeeded match with mg at " << d_una_index << std::endl;
+ d_una_index++;
}else{
- Trace("qcf-check-unassign") << "Failed match with mg at " << index << std::endl;
- do{
- if( !doFail ){
- eqc_count.pop_back();
- }else{
- doFail = false;
- }
- index--;
- }while( index>=0 && eqc_count[index]==-1 );
+ failed = true;
+ Trace("qcf-check-unassign") << "Failed match with mg at " << d_una_index << std::endl;
}
}else{
- Assert( doFail || index==(int)eqc_count.size()-1 );
- if( !doFail && eqc_count[index]<(int)p->d_eqcs[unassigned_tn[r][index]].size() ){
- int currIndex = eqc_count[index];
- eqc_count[index]++;
- Trace("qcf-check-unassign") << unassigned[r][index] << "->" << p->d_eqcs[unassigned_tn[r][index]][currIndex] << std::endl;
- if( setMatch( p, unassigned[r][index], p->d_eqcs[unassigned_tn[r][index]][currIndex] ) ){
- //if( currIndex==0 ){
- // Assert( p->areEqual( p->d_model_basis[unassigned_tn[r][index]], p->d_eqcs[unassigned_tn[r][index]][currIndex] ) );
- // d_match_term[unassigned[r][index]] = p->d_model_basis[unassigned_tn[r][index]];
- //}else{
- d_match_term[unassigned[r][index]] = TNode::null();
- //}
- Trace("qcf-check-unassign") << "Succeeded match " << index << std::endl;
- index++;
+ Assert( doFail || d_una_index==(int)d_una_eqc_count.size()-1 );
+ if( d_una_eqc_count[d_una_index]<(int)p->d_eqcs[d_unassigned_tn[d_una_index]].size() ){
+ int currIndex = d_una_eqc_count[d_una_index];
+ d_una_eqc_count[d_una_index]++;
+ Trace("qcf-check-unassign") << d_unassigned[d_una_index] << "->" << p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] << std::endl;
+ if( setMatch( p, d_unassigned[d_una_index], p->d_eqcs[d_unassigned_tn[d_una_index]][currIndex] ) ){
+ d_match_term[d_unassigned[d_una_index]] = TNode::null();
+ Trace("qcf-check-unassign") << "Succeeded match " << d_una_index << std::endl;
+ d_una_index++;
}else{
- Trace("qcf-check-unassign") << "Failed match " << index << std::endl;
+ Trace("qcf-check-unassign") << "Failed match " << d_una_index << std::endl;
invalidMatch = true;
}
}else{
- Trace("qcf-check-unassign") << "No more matches " << index << std::endl;
- if( !doFail ){
- eqc_count.pop_back();
- }else{
- doFail = false;
- }
- index--;
+ failed = true;
+ Trace("qcf-check-unassign") << "No more matches " << d_una_index << std::endl;
}
}
}
+ if( doFail || failed ){
+ do{
+ if( !doFail ){
+ d_una_eqc_count.pop_back();
+ }else{
+ doFail = false;
+ }
+ d_una_index--;
+ }while( d_una_index>=0 && d_una_eqc_count[d_una_index]==-1 );
+ }
}
- success = index>=0;
- if( success ){
- doFail = true;
- Trace("qcf-check-unassign") << " Try: " << std::endl;
- for( unsigned i=0; i<unassigned[r].size(); i++ ){
- int ui = unassigned[r][i];
- if( !d_match[ui].isNull() ){
- Trace("qcf-check-unassign") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl;
- }
+ }
+ success = d_una_index>=0;
+ if( success ){
+ doFail = true;
+ Trace("qcf-check-unassign") << " Try: " << std::endl;
+ for( unsigned i=0; i<d_unassigned.size(); i++ ){
+ int ui = d_unassigned[i];
+ if( !d_match[ui].isNull() ){
+ Trace("qcf-check-unassign") << " Assigned #" << ui << " : " << d_vars[ui] << " -> " << d_match[ui] << std::endl;
}
}
- }while( success && isMatchSpurious( p ) );
- }
+ }
+ }while( success && isMatchSpurious( p ) );
}
if( success ){
return true;
@@ -568,6 +581,28 @@ bool QuantInfo::completeMatch( QuantConflictFind * p, std::vector< int >& assign
}
}
+void QuantInfo::getMatch( std::vector< Node >& terms ){
+ for( unsigned i=0; i<d_q[0].getNumChildren(); i++ ){
+ //Node cv = qi->getCurrentValue( qi->d_match[i] );
+ int repVar = getCurrentRepVar( i );
+ Node cv;
+ //std::map< int, TNode >::iterator itmt = qi->d_match_term.find( repVar );
+ if( !d_match_term[repVar].isNull() ){
+ cv = d_match_term[repVar];
+ }else{
+ cv = d_match[repVar];
+ }
+ Debug("qcf-check-inst") << "INST : " << i << " -> " << cv << ", from " << d_match[i] << std::endl;
+ terms.push_back( cv );
+ }
+}
+
+void QuantInfo::revertMatch( std::vector< int >& assigned ) {
+ for( unsigned i=0; i<assigned.size(); i++ ){
+ d_match[ assigned[i] ] = TNode::null();
+ }
+}
+
void QuantInfo::debugPrintMatch( const char * c ) {
for( int i=0; i<getNumVars(); i++ ){
Trace(c) << " " << d_vars[i] << " -> ";
@@ -583,7 +618,10 @@ void QuantInfo::debugPrintMatch( const char * c ) {
}
Trace(c) << "}";
}
- Trace(c) << std::endl;
+ if( !d_match_term[i].isNull() && d_match_term[i]!=d_match[i] ){
+ Trace(c) << ", EXP : " << d_match_term[i];
+ }
+ Trace(c) << std::endl;
}
}
@@ -614,9 +652,6 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar, bool beneathQuant ){
Trace("qcf-qregister-debug") << " is var #" << v << std::endl;
d_qni_var_num[d_qni_size] = v;
//qi->addFuncParent( v, f, j );
- if( nn.getKind()==BOUND_VARIABLE && !beneathQuant ){
- qi->d_has_var[nn] = true;
- }
}else{
Trace("qcf-qregister-debug") << " is gterm " << nn << std::endl;
d_qni_gterm[d_qni_size] = nn;
@@ -634,7 +669,7 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar, bool beneathQuant ){
Node nn = n.eqNode( n[i] );
d_children.push_back( MatchGen( qi, nn ) );
d_children[d_children.size()-1].d_qni_bound_except.push_back( 0 );
- if( !d_children[d_children.size()-1].isValid() && options::qcfMode()<QCF_PARTIAL ){
+ if( !d_children[d_children.size()-1].isValid() ){
setInvalid();
break;
}
@@ -647,7 +682,7 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar, bool beneathQuant ){
d_type = typ_invalid;
}
}else{
- if( quantifiers::TermDb::hasBoundVarAttr( n ) ){
+ if( n.hasBoundVar() ){
d_type_not = false;
d_n = n;
if( d_n.getKind()==NOT ){
@@ -655,14 +690,14 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar, bool beneathQuant ){
d_type_not = !d_type_not;
}
- if( d_n.getKind()==OR || d_n.getKind()==AND || d_n.getKind()==IFF || d_n.getKind()==ITE || d_n.getKind()==FORALL ){
+ if( isHandledBoolConnective( d_n ) ){
//non-literals
d_type = typ_formula;
bool nBeneathQuant = beneathQuant || d_n.getKind()==FORALL;
for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
if( d_n.getKind()!=FORALL || i==1 ){
d_children.push_back( MatchGen( qi, d_n[i], false, nBeneathQuant ) );
- if( !d_children[d_children.size()-1].isValid() && options::qcfMode()<QCF_PARTIAL ){
+ if( !d_children[d_children.size()-1].isValid() ){
setInvalid();
break;
}
@@ -693,11 +728,9 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar, bool beneathQuant ){
//literals
if( d_n.getKind()==EQUAL ){
for( unsigned i=0; i<2; i++ ){
- if( quantifiers::TermDb::hasBoundVarAttr( d_n[i] ) ){
+ if( d_n[i].hasBoundVar() ){
if( !qi->isVar( d_n[i] ) ){
Trace("qcf-qregister-debug") << "ERROR : not var " << d_n[i] << std::endl;
- }else if( d_n[i].getKind()==BOUND_VARIABLE && !beneathQuant ){
- qi->d_has_var[d_n[i]] = true;
}
Assert( qi->isVar( d_n[i] ) );
}else{
@@ -708,6 +741,8 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar, bool beneathQuant ){
}else if( isHandledUfTerm( d_n ) ){
Assert( qi->isVar( d_n ) );
d_type = typ_pred;
+ }else if( d_n.getKind()==BOUND_VARIABLE ){
+ d_type = typ_bool_var;
}else{
Trace("qcf-invalid") << "Unhandled : " << d_n << std::endl;
}
@@ -737,9 +772,6 @@ MatchGen::MatchGen( QuantInfo * qi, Node n, bool isVar, bool beneathQuant ){
Trace("qcf-qregister-debug") << std::endl;
//Assert( d_children.size()==d_children_order.size() );
- if( !isValid() && options::qcfMode()>=QCF_PARTIAL ){
- qi->d_isPartial = true;
- }
}
void MatchGen::collectBoundVar( QuantInfo * qi, Node n, std::vector< int >& cbvars ) {
@@ -829,6 +861,7 @@ void MatchGen::determineVariableOrder( QuantInfo * qi, std::vector< int >& bvars
void MatchGen::reset_round( QuantConflictFind * p ) {
+ d_wasSet = false;
for( unsigned i=0; i<d_children.size(); i++ ){
d_children[i].reset_round( p );
}
@@ -844,11 +877,14 @@ void MatchGen::reset_round( QuantConflictFind * p ) {
}
}else if( d_type==typ_eq ){
for( unsigned i=0; i<d_n.getNumChildren(); i++ ){
- if( !quantifiers::TermDb::hasBoundVarAttr( d_n[i] ) ){
+ if( !d_n[i].hasBoundVar() ){
d_ground_eval[i] = p->evaluateTerm( d_n[i] );
}
}
}
+ d_qni_bound_cons.clear();
+ d_qni_bound_cons_var.clear();
+ d_qni_bound.clear();
}
void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
@@ -860,16 +896,34 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
d_qni.clear();
d_qni_bound.clear();
d_child_counter = -1;
+ d_tgt_orig = d_tgt;
//set up processing matches
if( d_type==typ_invalid ){
- if( p->d_effort==QuantConflictFind::effort_partial ){
- d_child_counter = 0;
- }
+ //do nothing : return success once?
}else if( d_type==typ_ground ){
if( d_ground_eval[0]==( d_tgt ? p->d_true : p->d_false ) ){
d_child_counter = 0;
}
+ }else if( d_type==typ_bool_var ){
+ //get current value of the variable
+ TNode n = qi->getCurrentValue( d_n );
+ int vn = qi->getCurrentRepVar( qi->getVarNum( n ) );
+ if( vn==-1 ){
+ //evaluate the value, see if it is compatible
+ int e = p->evaluate( n );
+ if( ( e==1 && d_tgt ) || ( e==0 && !d_tgt ) ){
+ d_child_counter = 0;
+ }
+ }else{
+ //unassigned, set match to true/false
+ d_qni_bound[0] = vn;
+ qi->setMatch( p, vn, d_tgt ? p->d_true : p->d_false );
+ d_child_counter = 0;
+ }
+ if( d_child_counter==0 ){
+ d_qn.push_back( NULL );
+ }
}else if( d_type==typ_var ){
Assert( isHandledUfTerm( d_n ) );
Node f = getOperator( p, d_n );
@@ -904,6 +958,7 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
}
bool success;
if( vn[0]==-1 && vn[1]==-1 ){
+ //Trace("qcf-explain") << " reset : " << d_n << " check ground values " << nn[0] << " " << nn[1] << " (tgt=" << d_tgt << ")" << std::endl;
Debug("qcf-match-debug") << " reset: check ground values " << nn[0] << " " << nn[1] << " (" << d_tgt << ")" << std::endl;
//just compare values
if( d_tgt ){
@@ -931,6 +986,7 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
success = addc!=-1;
//if successful and non-redundant, store that we need to cleanup this
if( addc==1 ){
+ //Trace("qcf-explain") << " reset: " << d_n << " add constraint " << vn[0] << " -> " << nn[1] << " (vn=" << vn[1] << ")" << ", d_tgt = " << d_tgt << std::endl;
for( unsigned i=0; i<2; i++ ){
if( vn[i]!=-1 && std::find( d_qni_bound_except.begin(), d_qni_bound_except.end(), i )==d_qni_bound_except.end() ){
d_qni_bound[vn[i]] = vn[i];
@@ -950,10 +1006,7 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
d_qn.push_back( NULL );
}else{
if( d_tgt && d_n.getKind()==FORALL ){
- //return success once
- if( p->d_effort==QuantConflictFind::effort_partial ){
- d_child_counter = -2;
- }
+ //do nothing
}else{
//reset the first child to d_tgt
d_child_counter = 0;
@@ -962,6 +1015,7 @@ void MatchGen::reset( QuantConflictFind * p, bool tgt, QuantInfo * qi ) {
}
}
d_binding = false;
+ d_wasSet = true;
Debug("qcf-match") << " reset: Finished reset for " << d_n << ", success = " << ( !d_qn.empty() || d_child_counter!=-1 ) << std::endl;
}
@@ -974,9 +1028,10 @@ bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {
d_child_counter = -1;
return true;
}else{
+ d_wasSet = false;
return false;
}
- }else if( d_type==typ_var || d_type==typ_eq || d_type==typ_pred ){
+ }else if( d_type==typ_var || d_type==typ_eq || d_type==typ_pred || d_type==typ_bool_var ){
bool success = false;
bool terminate = false;
do {
@@ -1020,8 +1075,8 @@ bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {
Debug("qcf-match-debug") << " failed." << std::endl;
success = false;
}else{
- Debug("qcf-match-debug") << " decrement..." << std::endl;
--d_binding_it;
+ Debug("qcf-match-debug") << " decrement..." << std::endl;
}
}while( success && ( d_binding_it->first==0 || qi->d_var_mg.find( d_binding_it->second )==qi->d_var_mg.end() ) );
doReset = false;
@@ -1056,6 +1111,7 @@ bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {
Debug("qcf-match") << " Clean up bound var " << it->first << (d_tgt ? "!" : "") << " = " << it->second << std::endl;
std::map< int, int >::iterator itb = d_qni_bound_cons_var.find( it->first );
int vn = itb!=d_qni_bound_cons_var.end() ? itb->second : -1;
+ //Trace("qcf-explain") << " cleanup: " << d_n << " remove constraint " << it->first << " -> " << it->second << " (vn=" << vn << ")" << ", d_tgt = " << d_tgt << std::endl;
qi->addConstraint( p, it->first, it->second, vn, d_tgt, true );
}
}
@@ -1085,6 +1141,7 @@ bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {
*/
}
Debug("qcf-match") << " ...finished matching for " << d_n << ", success = " << success << std::endl;
+ d_wasSet = success;
return success;
}else if( d_type==typ_formula || d_type==typ_ite_var ){
bool success = false;
@@ -1096,7 +1153,7 @@ bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {
}else{
while( !success && d_child_counter>=0 ){
//transition system based on d_child_counter
- if( d_type==typ_top || d_n.getKind()==OR || d_n.getKind()==AND ){
+ if( d_n.getKind()==OR || d_n.getKind()==AND ){
if( (d_n.getKind()==AND)==d_tgt ){
//all children must match simultaneously
if( getChild( d_child_counter )->getNextMatch( p, qi ) ){
@@ -1181,6 +1238,7 @@ bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {
}
}
}
+ d_wasSet = success;
Debug("qcf-match") << " ...finished construct match for " << d_n << ", success = " << success << std::endl;
return success;
}
@@ -1189,6 +1247,84 @@ bool MatchGen::getNextMatch( QuantConflictFind * p, QuantInfo * qi ) {
return false;
}
+bool MatchGen::getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp ) {
+ if( d_type==typ_eq ){
+ Node n[2];
+ for( unsigned i=0; i<2; i++ ){
+ Trace("qcf-explain") << "Explain term " << d_n[i] << "..." << std::endl;
+ n[i] = getExplanationTerm( p, qi, d_n[i], exp );
+ }
+ Node eq = n[0].eqNode( n[1] );
+ if( !d_tgt_orig ){
+ eq = eq.negate();
+ }
+ exp.push_back( eq );
+ Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << eq << ", set = " << d_wasSet << std::endl;
+ return true;
+ }else if( d_type==typ_pred ){
+ Trace("qcf-explain") << "Explain term " << d_n << "..." << std::endl;
+ Node n = getExplanationTerm( p, qi, d_n, exp );
+ if( !d_tgt_orig ){
+ n = n.negate();
+ }
+ exp.push_back( n );
+ Trace("qcf-explain") << "Explanation for " << d_n << " (tgt=" << d_tgt_orig << ") is " << n << ", set = " << d_wasSet << std::endl;
+ return true;
+ }else if( d_type==typ_formula ){
+ Trace("qcf-explain") << "Explanation get for " << d_n << ", counter = " << d_child_counter << ", tgt = " << d_tgt_orig << ", set = " << d_wasSet << std::endl;
+ if( d_n.getKind()==OR || d_n.getKind()==AND ){
+ if( (d_n.getKind()==AND)==d_tgt ){
+ for( unsigned i=0; i<getNumChildren(); i++ ){
+ if( !getChild( i )->getExplanation( p, qi, exp ) ){
+ return false;
+ }
+ }
+ }else{
+ return getChild( d_child_counter )->getExplanation( p, qi, exp );
+ }
+ }else if( d_n.getKind()==IFF ){
+ for( unsigned i=0; i<2; i++ ){
+ if( !getChild( i )->getExplanation( p, qi, exp ) ){
+ return false;
+ }
+ }
+ }else if( d_n.getKind()==ITE ){
+ for( unsigned i=0; i<3; i++ ){
+ bool isActive = ( ( i==0 && d_child_counter!=5 ) ||
+ ( i==1 && d_child_counter!=( d_tgt ? 3 : 1 ) ) ||
+ ( i==2 && d_child_counter!=( d_tgt ? 1 : 3 ) ) );
+ if( isActive ){
+ if( !getChild( i )->getExplanation( p, qi, exp ) ){
+ return false;
+ }
+ }
+ }
+ }else{
+ return false;
+ }
+ return true;
+ }else{
+ return false;
+ }
+}
+
+Node MatchGen::getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp ) {
+ Node v = qi->getCurrentExpValue( t );
+ if( isHandledUfTerm( t ) ){
+ for( unsigned i=0; i<t.getNumChildren(); i++ ){
+ Node vi = getExplanationTerm( p, qi, t[i], exp );
+ if( vi!=v[i] ){
+ Node eq = vi.eqNode( v[i] );
+ if( std::find( exp.begin(), exp.end(), eq )==exp.end() ){
+ Trace("qcf-explain") << " add : " << eq << "." << std::endl;
+ exp.push_back( eq );
+ }
+ }
+ }
+ }
+ return v;
+}
+
bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) {
if( !d_qn.empty() ){
if( d_qn[0]==NULL ){
@@ -1297,14 +1433,17 @@ bool MatchGen::doMatching( QuantConflictFind * p, QuantInfo * qi ) {
Assert( !d_qni[d_qni.size()-1]->second.d_children.empty() );
TNode t = d_qni[d_qni.size()-1]->second.d_children.begin()->first;
Debug("qcf-match-debug") << " " << d_n << " matched " << t << std::endl;
+ qi->d_match_term[d_qni_var_num[0]] = t;
//set the match terms
for( std::map< int, int >::iterator it = d_qni_bound.begin(); it != d_qni_bound.end(); ++it ){
Debug("qcf-match-debug") << " position " << it->first << " bounded " << it->second << " / " << qi->d_q[0].getNumChildren() << std::endl;
- if( it->second<(int)qi->d_q[0].getNumChildren() && it->first>0 ){ //if it is an actual variable, we are interested in knowing the actual term
+ //if( it->second<(int)qi->d_q[0].getNumChildren() ){ //if it is an actual variable, we are interested in knowing the actual term
+ if( it->first>0 ){
Assert( !qi->d_match[ it->second ].isNull() );
Assert( p->areEqual( t[it->first-1], qi->d_match[ it->second ] ) );
qi->d_match_term[it->second] = t[it->first-1];
}
+ //}
}
}
}
@@ -1322,7 +1461,7 @@ void MatchGen::debugPrintType( const char * c, short typ, bool isTrace ) {
case typ_formula: Trace(c) << "formula";break;
case typ_var: Trace(c) << "var";break;
case typ_ite_var: Trace(c) << "ite_var";break;
- case typ_top: Trace(c) << "top";break;
+ case typ_bool_var: Trace(c) << "bool_var";break;
}
}else{
switch( typ ){
@@ -1333,7 +1472,7 @@ void MatchGen::debugPrintType( const char * c, short typ, bool isTrace ) {
case typ_formula: Debug(c) << "formula";break;
case typ_var: Debug(c) << "var";break;
case typ_ite_var: Debug(c) << "ite_var";break;
- case typ_top: Debug(c) << "top";break;
+ case typ_bool_var: Debug(c) << "bool_var";break;
}
}
}
@@ -1343,18 +1482,37 @@ void MatchGen::setInvalid() {
d_children.clear();
}
+bool MatchGen::isHandledBoolConnective( TNode n ) {
+ return n.getType().isBoolean() && ( n.getKind()==OR || n.getKind()==AND || n.getKind()==IFF || n.getKind()==ITE || n.getKind()==FORALL || n.getKind()==NOT );
+}
+
bool MatchGen::isHandledUfTerm( TNode n ) {
- return n.getKind()==APPLY_UF;// || n.getKind()==GEQ;
+ return n.getKind()==APPLY_UF || n.getKind()==STORE || n.getKind()==SELECT ||
+ n.getKind()==APPLY_CONSTRUCTOR || n.getKind()==APPLY_SELECTOR || n.getKind()==APPLY_TESTER;// || n.getKind()==GEQ;
}
Node MatchGen::getOperator( QuantConflictFind * p, Node n ) {
if( isHandledUfTerm( n ) ){
- return n.getOperator();
+ return p->getQuantifiersEngine()->getTermDatabase()->getOperator( n );
}else{
return Node::null();
}
}
+bool MatchGen::isHandled( TNode n ) {
+ if( n.getKind()!=BOUND_VARIABLE && n.hasBoundVar() ){
+ if( !isHandledBoolConnective( n ) && !isHandledUfTerm( n ) && n.getKind()!=EQUAL && n.getKind()!=ITE ){
+ return false;
+ }
+ for( unsigned i=0; i<n.getNumChildren(); i++ ){
+ if( !isHandled( n[i] ) ){
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
QuantConflictFind::QuantConflictFind( QuantifiersEngine * qe, context::Context* c ) :
QuantifiersModule( qe ),
@@ -1377,30 +1535,32 @@ Node QuantConflictFind::mkEqNode( Node a, Node b ) {
//-------------------------------------------------- registration
void QuantConflictFind::registerQuantifier( Node q ) {
- d_quants.push_back( q );
- d_quant_id[q] = d_quants.size();
- Trace("qcf-qregister") << "Register ";
- debugPrintQuant( "qcf-qregister", q );
- Trace("qcf-qregister") << " : " << q << std::endl;
- //make QcfNode structure
- Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl;
- d_qinfo[q].initialize( q, q[1] );
-
- //debug print
- Trace("qcf-qregister") << "- Flattened structure is :" << std::endl;
- Trace("qcf-qregister") << " ";
- debugPrintQuantBody( "qcf-qregister", q, q[1] );
- Trace("qcf-qregister") << std::endl;
- if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){
- Trace("qcf-qregister") << " with additional constraints : " << std::endl;
- for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){
- Trace("qcf-qregister") << " ?x" << j << " = ";
- debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false );
- Trace("qcf-qregister") << std::endl;
+ if( !TermDb::isRewriteRule( q ) ){
+ d_quants.push_back( q );
+ d_quant_id[q] = d_quants.size();
+ Trace("qcf-qregister") << "Register ";
+ debugPrintQuant( "qcf-qregister", q );
+ Trace("qcf-qregister") << " : " << q << std::endl;
+ //make QcfNode structure
+ Trace("qcf-qregister") << "- Get relevant equality/disequality pairs, calculate flattening..." << std::endl;
+ d_qinfo[q].initialize( q, q[1] );
+
+ //debug print
+ Trace("qcf-qregister") << "- Flattened structure is :" << std::endl;
+ Trace("qcf-qregister") << " ";
+ debugPrintQuantBody( "qcf-qregister", q, q[1] );
+ Trace("qcf-qregister") << std::endl;
+ if( d_qinfo[q].d_vars.size()>q[0].getNumChildren() ){
+ Trace("qcf-qregister") << " with additional constraints : " << std::endl;
+ for( unsigned j=q[0].getNumChildren(); j<d_qinfo[q].d_vars.size(); j++ ){
+ Trace("qcf-qregister") << " ?x" << j << " = ";
+ debugPrintQuantBody( "qcf-qregister", q, d_qinfo[q].d_vars[j], false );
+ Trace("qcf-qregister") << std::endl;
+ }
}
- }
- Trace("qcf-qregister") << "Done registering quantifier." << std::endl;
+ Trace("qcf-qregister") << "Done registering quantifier." << std::endl;
+ }
}
int QuantConflictFind::evaluate( Node n, bool pref, bool hasPref ) {
@@ -1481,6 +1641,18 @@ int QuantConflictFind::evaluate( Node n, bool pref, bool hasPref ) {
return ret;
}
+short QuantConflictFind::getMaxQcfEffort() {
+ if( options::qcfMode()==QCF_CONFLICT_ONLY ){
+ return effort_conflict;
+ }else if( options::qcfMode()==QCF_PROP_EQ ){
+ return effort_prop_eq;
+ }else if( options::qcfMode()==QCF_MC ){
+ return effort_mc;
+ }else{
+ return 0;
+ }
+}
+
bool QuantConflictFind::areMatchEqual( TNode n1, TNode n2 ) {
//if( d_effort==QuantConflictFind::effort_mc ){
// return n1==n2 || !areDisequal( n1, n2 );
@@ -1500,14 +1672,16 @@ bool QuantConflictFind::areMatchDisequal( TNode n1, TNode n2 ) {
//-------------------------------------------------- handling assertions / eqc
void QuantConflictFind::assertNode( Node q ) {
- Trace("qcf-proc") << "QCF : assertQuantifier : ";
- debugPrintQuant("qcf-proc", q);
- Trace("qcf-proc") << std::endl;
- d_qassert.push_back( q );
- //set the eqRegistries that this depends on to true
- //for( std::map< EqRegistry *, bool >::iterator it = d_qinfo[q].d_rel_eqr.begin(); it != d_qinfo[q].d_rel_eqr.end(); ++it ){
- // it->first->d_active.set( true );
- //}
+ if( !TermDb::isRewriteRule( q ) ){
+ Trace("qcf-proc") << "QCF : assertQuantifier : ";
+ debugPrintQuant("qcf-proc", q);
+ Trace("qcf-proc") << std::endl;
+ d_qassert.push_back( q );
+ //set the eqRegistries that this depends on to true
+ //for( std::map< EqRegistry *, bool >::iterator it = d_qinfo[q].d_rel_eqr.begin(); it != d_qinfo[q].d_rel_eqr.end(); ++it ){
+ // it->first->d_active.set( true );
+ //}
+ }
}
eq::EqualityEngine * QuantConflictFind::getEqualityEngine() {
@@ -1518,7 +1692,7 @@ bool QuantConflictFind::areEqual( Node n1, Node n2 ) {
return getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areEqual( n1,n2 );
}
bool QuantConflictFind::areDisequal( Node n1, Node n2 ) {
- return getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areDisequal( n1,n2, false );
+ return n1!=n2 && getEqualityEngine()->hasTerm( n1 ) && getEqualityEngine()->hasTerm( n2 ) && getEqualityEngine()->areDisequal( n1,n2, false );
}
Node QuantConflictFind::getRepresentative( Node n ) {
if( getEqualityEngine()->hasTerm( n ) ){
@@ -1677,6 +1851,10 @@ void QuantConflictFind::assertDisequal( Node a, Node b ) {
//-------------------------------------------------- check function
+void QuantConflictFind::reset_round( Theory::Effort level ) {
+ d_needs_computeRelEqr = true;
+}
+
/** check */
void QuantConflictFind::check( Theory::Effort level ) {
Trace("qcf-check") << "QCF : check : " << level << std::endl;
@@ -1695,7 +1873,6 @@ void QuantConflictFind::check( Theory::Effort level ) {
clSet = double(clock())/double(CLOCKS_PER_SEC);
Trace("qcf-engine") << "---Conflict Find Engine Round, effort = " << level << "---" << std::endl;
}
- Trace("qcf-check") << "Compute relevant equalities..." << std::endl;
computeRelevantEqr();
//determine order for quantified formulas
@@ -1722,23 +1899,12 @@ void QuantConflictFind::check( Theory::Effort level ) {
}
}
-
-
if( Trace.isOn("qcf-debug") ){
Trace("qcf-debug") << std::endl;
debugPrint("qcf-debug");
Trace("qcf-debug") << std::endl;
- }
- short end_e;
- if( options::qcfMode()==QCF_CONFLICT_ONLY ){
- end_e = effort_conflict;
- }else if( options::qcfMode()==QCF_PROP_EQ ){
- end_e = effort_prop_eq;
- }else if( options::qcfMode()==QCF_PARTIAL ){
- end_e = effort_partial;
- }else{
- end_e = effort_mc;
- }
+ }
+ short end_e = getMaxQcfEffort();
for( short e = effort_conflict; e<=end_e; e++ ){
d_effort = e;
Trace("qcf-check") << "Checking quantified formulas at effort " << e << "..." << std::endl;
@@ -1748,79 +1914,106 @@ void QuantConflictFind::check( Theory::Effort level ) {
Assert( d_qinfo.find( q )!=d_qinfo.end() );
if( qi->d_mg->isValid() ){
- if( qi->isPartial()==(e==effort_partial) ){
- Trace("qcf-check") << "Check quantified formula ";
- debugPrintQuant("qcf-check", q);
- Trace("qcf-check") << " : " << q << "..." << std::endl;
-
- Trace("qcf-check-debug") << "Reset round..." << std::endl;
- qi->reset_round( this );
- //try to make a matches making the body false
- Trace("qcf-check-debug") << "Reset..." << std::endl;
- qi->d_mg->reset( this, false, qi );
- Trace("qcf-check-debug") << "Get next match..." << std::endl;
- while( qi->d_mg->getNextMatch( this, qi ) ){
-
- Trace("qcf-check") << "*** Produced match at effort " << e << " : " << std::endl;
- qi->debugPrintMatch("qcf-check");
- Trace("qcf-check") << std::endl;
-
- if( !qi->isMatchSpurious( this ) ){
- std::vector< int > assigned;
- if( qi->completeMatch( this, assigned ) ){
- std::vector< Node > terms;
- for( unsigned i=0; i<q[0].getNumChildren(); i++ ){
- //Node cv = qi->getCurrentValue( qi->d_match[i] );
- int repVar = qi->getCurrentRepVar( i );
- Node cv;
- //std::map< int, TNode >::iterator itmt = qi->d_match_term.find( repVar );
- if( !qi->d_match_term[repVar].isNull() ){
- cv = qi->d_match_term[repVar];
- }else{
- cv = qi->d_match[repVar];
+ Trace("qcf-check") << "Check quantified formula ";
+ debugPrintQuant("qcf-check", q);
+ Trace("qcf-check") << " : " << q << "..." << std::endl;
+
+ Trace("qcf-check-debug") << "Reset round..." << std::endl;
+ qi->reset_round( this );
+ //try to make a matches making the body false
+ Trace("qcf-check-debug") << "Get next match..." << std::endl;
+ while( qi->d_mg->getNextMatch( this, qi ) ){
+ Trace("qcf-check") << "*** Produced match at effort " << e << " : " << std::endl;
+ qi->debugPrintMatch("qcf-check");
+ Trace("qcf-check") << std::endl;
+ std::vector< int > assigned;
+ if( !qi->isMatchSpurious( this ) ){
+ if( qi->completeMatch( this, assigned ) ){
+ /*
+ if( options::qcfExp() && d_effort==effort_conflict ){
+ std::vector< Node > exp;
+ if( qi->d_mg->getExplanation( this, qi, exp ) ){
+ Trace("qcf-check-exp") << "Base explanation is : " << std::endl;
+ for( unsigned c=0; c<exp.size(); c++ ){
+ Trace("qcf-check-exp") << " " << exp[c] << std::endl;
}
- Debug("qcf-check-inst") << "INST : " << i << " -> " << cv << ", from " << qi->d_match[i] << std::endl;
- terms.push_back( cv );
- }
- if( Debug.isOn("qcf-check-inst") ){
- //if( e==effort_conflict ){
- Node inst = d_quantEngine->getInstantiation( q, terms );
- Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl;
- Assert( evaluate( inst )!=1 );
- Assert( evaluate( inst )==-1 || e>effort_conflict );
- //}
- }
- if( d_quantEngine->addInstantiation( q, terms ) ){
- Trace("qcf-check") << " ... Added instantiation" << std::endl;
- ++addedLemmas;
- if( e==effort_conflict ){
- d_quant_order.insert( d_quant_order.begin(), q );
- d_conflict.set( true );
- ++(d_statistics.d_conflict_inst);
- break;
- }else if( e==effort_prop_eq ){
- ++(d_statistics.d_prop_inst);
- }else if( e==effort_partial ){
- ++(d_statistics.d_partial_inst);
+ std::vector< TNode > c_exp;
+ eq::EqualityEngine* ee = ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getEqualityEngine() ;
+ for( unsigned c=0; c<exp.size(); c++ ){
+ bool pol = exp[c].getKind()!=NOT;
+ TNode lit = pol ? exp[c] : exp[c][0];
+ Trace("qcf-check-exp") << "Explain " << lit << ", polarity " << pol << std::endl;
+ if( lit.getKind()==EQUAL ){
+ if( !pol && !ee->areDisequal( lit[0], lit[1], true ) ){
+ exit( 98 );
+ }else if( pol && !ee->areEqual( lit[0], lit[1] ) ){
+ exit( 99 );
+ }
+ ee->explainEquality( lit[0], lit[1], pol, c_exp );
+ }else{
+ if( !ee->areEqual( lit, pol ? d_true : d_false ) ){
+ exit( pol ? 96 : 97 );
+ }
+ ee->explainPredicate( lit, pol, c_exp );
+ }
}
- }else{
- Trace("qcf-check") << " ... Failed to add instantiation" << std::endl;
- //Assert( false );
+ std::vector< Node > c_lem;
+ Trace("qcf-check-exp") << "Actual explanation is : " << std::endl;
+ for( unsigned c=0; c<c_exp.size(); c++ ){
+ Trace("qcf-check-exp") << " " << c_exp[c] << std::endl;
+ Node ccc = c_exp[c].negate();
+ if( std::find( c_lem.begin(), c_lem.end(), ccc )==c_lem.end() ){
+ c_lem.push_back( ccc );
+ }
+ }
+
+ c_lem.push_back( q.negate() );
+ Node conf = NodeManager::currentNM()->mkNode( OR, c_lem );
+ Trace("qcf-conflict") << "QCF conflict : " << conf << std::endl;
+ d_quantEngine->addLemma( conf, false );
+ d_conflict.set( true );
+ ++(d_statistics.d_conflict_inst);
+ ++addedLemmas;
+ break;
}
- //clean up assigned
- for( unsigned i=0; i<assigned.size(); i++ ){
- qi->d_match[ assigned[i] ] = TNode::null();
+ }
+ */
+ std::vector< Node > terms;
+ qi->getMatch( terms );
+ if( Debug.isOn("qcf-check-inst") ){
+ //if( e==effort_conflict ){
+ Node inst = d_quantEngine->getInstantiation( q, terms );
+ Debug("qcf-check-inst") << "Check instantiation " << inst << "..." << std::endl;
+ Assert( evaluate( inst )!=1 );
+ Assert( evaluate( inst )==-1 || e>effort_conflict );
+ //}
+ }
+ if( d_quantEngine->addInstantiation( q, terms ) ){
+ Trace("qcf-check") << " ... Added instantiation" << std::endl;
+ ++addedLemmas;
+ if( e==effort_conflict ){
+ d_quant_order.insert( d_quant_order.begin(), q );
+ d_conflict.set( true );
+ ++(d_statistics.d_conflict_inst);
+ break;
+ }else if( e==effort_prop_eq ){
+ ++(d_statistics.d_prop_inst);
}
}else{
- Trace("qcf-check") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl;
+ Trace("qcf-check") << " ... Failed to add instantiation" << std::endl;
+ //Assert( false );
}
+ //clean up assigned
+ qi->revertMatch( assigned );
}else{
- Trace("qcf-check") << " ... Spurious instantiation (does not meet variable constraints)" << std::endl;
+ Trace("qcf-check") << " ... Spurious instantiation (cannot assign unassigned variables)" << std::endl;
}
- }
- if( d_conflict ){
- break;
- }
+ }else{
+ Trace("qcf-check") << " ... Spurious instantiation (match is inconsistent)" << std::endl;
+ }
+ }
+ if( d_conflict ){
+ break;
}
}
}
@@ -1833,7 +2026,7 @@ void QuantConflictFind::check( Theory::Effort level ) {
double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
Trace("qcf-engine") << "Finished conflict find engine, time = " << (clSet2-clSet);
if( addedLemmas>0 ){
- Trace("qcf-engine") << ", effort = " << ( d_effort==effort_conflict ? "conflict" : ( d_effort==effort_prop_eq ? "prop_eq" : (d_effort==effort_partial ? "partial" : "mc" ) ) );
+ Trace("qcf-engine") << ", effort = " << ( d_effort==effort_conflict ? "conflict" : ( d_effort==effort_prop_eq ? "prop_eq" : "mc" ) );
Trace("qcf-engine") << ", addedLemmas = " << addedLemmas;
}
Trace("qcf-engine") << std::endl;
@@ -1845,7 +2038,7 @@ void QuantConflictFind::check( Theory::Effort level ) {
bool QuantConflictFind::needsCheck( Theory::Effort level ) {
d_performCheck = false;
- if( !d_conflict ){
+ if( options::quantConflictFind() && !d_conflict ){
if( level==Theory::EFFORT_LAST_CALL ){
d_performCheck = options::qcfWhenMode()==QCF_WHEN_MODE_LAST_CALL;
}else if( level==Theory::EFFORT_FULL ){
@@ -1858,131 +2051,135 @@ bool QuantConflictFind::needsCheck( Theory::Effort level ) {
}
void QuantConflictFind::computeRelevantEqr() {
- d_uf_terms.clear();
- d_eqc_uf_terms.clear();
- d_eqcs.clear();
- d_model_basis.clear();
- d_arg_reps.clear();
- //double clSet = 0;
- //if( Trace.isOn("qcf-opt") ){
- // clSet = double(clock())/double(CLOCKS_PER_SEC);
- //}
-
- //long nTermst = 0;
- //long nTerms = 0;
- //long nEqc = 0;
+ if( d_needs_computeRelEqr ){
+ d_needs_computeRelEqr = false;
+ Trace("qcf-check") << "Compute relevant equalities..." << std::endl;
+ d_uf_terms.clear();
+ d_eqc_uf_terms.clear();
+ d_eqcs.clear();
+ d_model_basis.clear();
+ d_arg_reps.clear();
+ //double clSet = 0;
+ //if( Trace.isOn("qcf-opt") ){
+ // clSet = double(clock())/double(CLOCKS_PER_SEC);
+ //}
- //which nodes are irrelevant for disequality matches
- std::map< TNode, bool > irrelevant_dnode;
- //now, store matches
- eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
- while( !eqcs_i.isFinished() ){
- //nEqc++;
- Node r = (*eqcs_i);
- TypeNode rtn = r.getType();
- if( options::qcfMode()==QCF_MC ){
- std::map< TypeNode, std::vector< TNode > >::iterator itt = d_eqcs.find( rtn );
- if( itt==d_eqcs.end() ){
- Node mb = getQuantifiersEngine()->getTermDatabase()->getModelBasisTerm( rtn );
- if( !getEqualityEngine()->hasTerm( mb ) ){
- Trace("qcf-warn") << "WARNING: Model basis term does not exist!" << std::endl;
- Assert( false );
- }
- Node mbr = getRepresentative( mb );
- if( mbr!=r ){
- d_eqcs[rtn].push_back( mbr );
+ //long nTermst = 0;
+ //long nTerms = 0;
+ //long nEqc = 0;
+
+ //which nodes are irrelevant for disequality matches
+ std::map< TNode, bool > irrelevant_dnode;
+ //now, store matches
+ eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( getEqualityEngine() );
+ while( !eqcs_i.isFinished() ){
+ //nEqc++;
+ Node r = (*eqcs_i);
+ TypeNode rtn = r.getType();
+ if( options::qcfMode()==QCF_MC ){
+ std::map< TypeNode, std::vector< TNode > >::iterator itt = d_eqcs.find( rtn );
+ if( itt==d_eqcs.end() ){
+ Node mb = getQuantifiersEngine()->getTermDatabase()->getModelBasisTerm( rtn );
+ if( !getEqualityEngine()->hasTerm( mb ) ){
+ Trace("qcf-warn") << "WARNING: Model basis term does not exist!" << std::endl;
+ Assert( false );
+ }
+ Node mbr = getRepresentative( mb );
+ if( mbr!=r ){
+ d_eqcs[rtn].push_back( mbr );
+ }
+ d_eqcs[rtn].push_back( r );
+ d_model_basis[rtn] = mb;
+ }else{
+ itt->second.push_back( r );
}
- d_eqcs[rtn].push_back( r );
- d_model_basis[rtn] = mb;
}else{
- itt->second.push_back( r );
- }
- }else{
- d_eqcs[rtn].push_back( r );
- }
- /*
- eq::EqClassIterator eqc_i = eq::EqClassIterator( r, getEqualityEngine() );
- while( !eqc_i.isFinished() ){
- TNode n = (*eqc_i);
- if( quantifiers::TermDb::hasBoundVarAttr( n ) ){
- std::cout << "BAD TERM IN DB : " << n << std::endl;
- exit( 199 );
- }
- ++eqc_i;
- }
- */
-
- //if( r.getType().isInteger() ){
- // Trace("qcf-mv") << "Model value for eqc(" << r << ") : " << d_quantEngine->getValuation().getModelValue( r ) << std::endl;
- //}
- //EqcInfo * eqcir = getEqcInfo( r, false );
- //get relevant nodes that we are disequal from
- /*
- std::vector< Node > deqc;
- if( eqcir ){
- for( NodeBoolMap::iterator it = eqcir->d_diseq.begin(); it != eqcir->d_diseq.end(); ++it ){
- if( (*it).second ){
- //Node rd = (*it).first;
- //if( rd!=getRepresentative( rd ) ){
- // std::cout << "Bad rep!" << std::endl;
- // exit( 0 );
- //}
- deqc.push_back( (*it).first );
+ d_eqcs[rtn].push_back( r );
+ }
+ /*
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( r, getEqualityEngine() );
+ while( !eqc_i.isFinished() ){
+ TNode n = (*eqc_i);
+ if( n.hasBoundVar() ){
+ std::cout << "BAD TERM IN DB : " << n << std::endl;
+ exit( 199 );
+ }
+ ++eqc_i;
+ }
+ */
+
+ //if( r.getType().isInteger() ){
+ // Trace("qcf-mv") << "Model value for eqc(" << r << ") : " << d_quantEngine->getValuation().getModelValue( r ) << std::endl;
+ //}
+ //EqcInfo * eqcir = getEqcInfo( r, false );
+ //get relevant nodes that we are disequal from
+ /*
+ std::vector< Node > deqc;
+ if( eqcir ){
+ for( NodeBoolMap::iterator it = eqcir->d_diseq.begin(); it != eqcir->d_diseq.end(); ++it ){
+ if( (*it).second ){
+ //Node rd = (*it).first;
+ //if( rd!=getRepresentative( rd ) ){
+ // std::cout << "Bad rep!" << std::endl;
+ // exit( 0 );
+ //}
+ deqc.push_back( (*it).first );
+ }
}
}
- }
- */
- //process disequalities
- /*
- eq::EqClassIterator eqc_i = eq::EqClassIterator( r, getEqualityEngine() );
- while( !eqc_i.isFinished() ){
- TNode n = (*eqc_i);
- if( n.getKind()!=EQUAL ){
- nTermst++;
- //node_to_rep[n] = r;
- //if( n.getNumChildren()>0 ){
- // if( n.getKind()!=APPLY_UF ){
- // std::cout << n.getKind() << " " << n.getOperator() << " " << n << std::endl;
- // }
- //}
- if( !quantifiers::TermDb::hasBoundVarAttr( n ) ){ //temporary
-
- bool isRedundant;
- std::map< TNode, std::vector< TNode > >::iterator it_na;
- TNode fn;
- if( MatchGen::isHandledUfTerm( n ) ){
- Node f = MatchGen::getOperator( this, n );
- computeArgReps( n );
- it_na = d_arg_reps.find( n );
- Assert( it_na!=d_arg_reps.end() );
- Node nadd = d_eqc_uf_terms[f].d_children[r].addTerm( n, d_arg_reps[n] );
- isRedundant = (nadd!=n);
- d_uf_terms[f].addTerm( n, d_arg_reps[n] );
+ */
+ //process disequalities
+ /*
+ eq::EqClassIterator eqc_i = eq::EqClassIterator( r, getEqualityEngine() );
+ while( !eqc_i.isFinished() ){
+ TNode n = (*eqc_i);
+ if( n.getKind()!=EQUAL ){
+ nTermst++;
+ //node_to_rep[n] = r;
+ //if( n.getNumChildren()>0 ){
+ // if( n.getKind()!=APPLY_UF ){
+ // std::cout << n.getKind() << " " << n.getOperator() << " " << n << std::endl;
+ // }
+ //}
+ if( !quantifiers::TermDb::hasBoundVarAttr( n ) ){ //temporary
+
+ bool isRedundant;
+ std::map< TNode, std::vector< TNode > >::iterator it_na;
+ TNode fn;
+ if( MatchGen::isHandledUfTerm( n ) ){
+ Node f = MatchGen::getOperator( this, n );
+ computeArgReps( n );
+ it_na = d_arg_reps.find( n );
+ Assert( it_na!=d_arg_reps.end() );
+ Node nadd = d_eqc_uf_terms[f].d_children[r].addTerm( n, d_arg_reps[n] );
+ isRedundant = (nadd!=n);
+ d_uf_terms[f].addTerm( n, d_arg_reps[n] );
+ }else{
+ isRedundant = false;
+ }
+ nTerms += isRedundant ? 0 : 1;
}else{
- isRedundant = false;
- }
- nTerms += isRedundant ? 0 : 1;
- }else{
- if( Debug.isOn("qcf-nground") ){
- Debug("qcf-nground") << "Non-ground term in eqc : " << n << std::endl;
- Assert( false );
+ if( Debug.isOn("qcf-nground") ){
+ Debug("qcf-nground") << "Non-ground term in eqc : " << n << std::endl;
+ Assert( false );
+ }
}
}
+ ++eqc_i;
}
- ++eqc_i;
+ */
+ ++eqcs_i;
+ }
+ /*
+ if( Trace.isOn("qcf-opt") ){
+ double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
+ Trace("qcf-opt") << "Compute rel eqc : " << std::endl;
+ Trace("qcf-opt") << " " << nEqc << " equivalence classes. " << std::endl;
+ Trace("qcf-opt") << " " << nTerms << " / " << nTermst << " terms." << std::endl;
+ Trace("qcf-opt") << " Time : " << (clSet2-clSet) << std::endl;
}
*/
- ++eqcs_i;
- }
- /*
- if( Trace.isOn("qcf-opt") ){
- double clSet2 = double(clock())/double(CLOCKS_PER_SEC);
- Trace("qcf-opt") << "Compute rel eqc : " << std::endl;
- Trace("qcf-opt") << " " << nEqc << " equivalence classes. " << std::endl;
- Trace("qcf-opt") << " " << nTerms << " / " << nTermst << " terms." << std::endl;
- Trace("qcf-opt") << " Time : " << (clSet2-clSet) << std::endl;
}
- */
}
void QuantConflictFind::computeArgReps( TNode n ) {
@@ -1997,11 +2194,10 @@ void QuantConflictFind::computeArgReps( TNode n ) {
void QuantConflictFind::computeUfTerms( TNode f ) {
if( d_uf_terms.find( f )==d_uf_terms.end() ){
d_uf_terms[f].clear();
- unsigned nt = d_quantEngine->getTermDatabase()->d_op_map[f].size();
+ unsigned nt = d_quantEngine->getTermDatabase()->getNumGroundTerms( f );
for( unsigned i=0; i<nt; i++ ){
Node n = d_quantEngine->getTermDatabase()->d_op_map[f][i];
- if( !n.getAttribute(NoMatchAttribute()) ){
- Assert( getEqualityEngine()->hasTerm( n ) );
+ if( getEqualityEngine()->hasTerm( n ) && !n.getAttribute(NoMatchAttribute()) ){
Node r = getRepresentative( n );
computeArgReps( n );
d_eqc_uf_terms[f].d_children[r].addTerm( n, d_arg_reps[n] );
@@ -2079,20 +2275,17 @@ void QuantConflictFind::debugPrintQuantBody( const char * c, Node q, Node n, boo
QuantConflictFind::Statistics::Statistics():
d_inst_rounds("QuantConflictFind::Inst_Rounds", 0),
d_conflict_inst("QuantConflictFind::Instantiations_Conflict_Find", 0 ),
- d_prop_inst("QuantConflictFind::Instantiations_Prop", 0 ),
- d_partial_inst("QuantConflictFind::Instantiations_Partial", 0 )
+ d_prop_inst("QuantConflictFind::Instantiations_Prop", 0 )
{
StatisticsRegistry::registerStat(&d_inst_rounds);
StatisticsRegistry::registerStat(&d_conflict_inst);
StatisticsRegistry::registerStat(&d_prop_inst);
- StatisticsRegistry::registerStat(&d_partial_inst);
}
QuantConflictFind::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(&d_inst_rounds);
StatisticsRegistry::unregisterStat(&d_conflict_inst);
StatisticsRegistry::unregisterStat(&d_prop_inst);
- StatisticsRegistry::unregisterStat(&d_partial_inst);
}
-} \ No newline at end of file
+}
diff --git a/src/theory/quantifiers/quant_conflict_find.h b/src/theory/quantifiers/quant_conflict_find.h
index 944cfa584..62bd347c7 100755
--- a/src/theory/quantifiers/quant_conflict_find.h
+++ b/src/theory/quantifiers/quant_conflict_find.h
@@ -83,13 +83,15 @@ public:
typ_formula,
typ_var,
typ_ite_var,
- typ_top,
+ typ_bool_var,
};
void debugPrintType( const char * c, short typ, bool isTrace = false );
public:
MatchGen() : d_type( typ_invalid ){}
MatchGen( QuantInfo * qi, Node n, bool isVar = false, bool beneathQuant = false );
bool d_tgt;
+ bool d_tgt_orig;
+ bool d_wasSet;
Node d_n;
std::vector< MatchGen > d_children;
short d_type;
@@ -97,21 +99,32 @@ public:
void reset_round( QuantConflictFind * p );
void reset( QuantConflictFind * p, bool tgt, QuantInfo * qi );
bool getNextMatch( QuantConflictFind * p, QuantInfo * qi );
+ bool getExplanation( QuantConflictFind * p, QuantInfo * qi, std::vector< Node >& exp );
+ Node getExplanationTerm( QuantConflictFind * p, QuantInfo * qi, Node t, std::vector< Node >& exp );
bool isValid() { return d_type!=typ_invalid; }
void setInvalid();
// is this term treated as UF application?
+ static bool isHandledBoolConnective( TNode n );
static bool isHandledUfTerm( TNode n );
static Node getOperator( QuantConflictFind * p, Node n );
+ //can this node be handled by the algorithm
+ static bool isHandled( TNode n );
};
//info for quantifiers
class QuantInfo {
private:
void registerNode( Node n, bool hasPol, bool pol, bool beneathQuant = false );
- void flatten( Node n, bool beneathQuant );
+ void flatten( Node n, bool beneathQuant );
+private: //for completing match
+ std::vector< int > d_unassigned;
+ std::vector< TypeNode > d_unassigned_tn;
+ int d_unassigned_nvar;
+ int d_una_index;
+ std::vector< int > d_una_eqc_count;
public:
- QuantInfo() : d_mg( NULL ), d_isPartial( false ) {}
+ QuantInfo() : d_mg( NULL ) {}
std::vector< TNode > d_vars;
std::map< TNode, int > d_var_num;
std::map< TNode, bool > d_nbeneathQuant;
@@ -120,6 +133,7 @@ public:
bool isVar( TNode v ) { return d_var_num.find( v )!=d_var_num.end(); }
int getNumVars() { return (int)d_vars.size(); }
TNode getVar( int i ) { return d_vars[i]; }
+
MatchGen * d_mg;
Node d_q;
std::map< int, MatchGen * > d_var_mg;
@@ -133,20 +147,18 @@ public:
std::map< int, std::map< TNode, int > > d_curr_var_deq;
int getCurrentRepVar( int v );
TNode getCurrentValue( TNode n );
+ TNode getCurrentExpValue( TNode n );
bool getCurrentCanBeEqual( QuantConflictFind * p, int v, TNode n, bool chDiseq = false );
int addConstraint( QuantConflictFind * p, int v, TNode n, bool polarity );
int addConstraint( QuantConflictFind * p, int v, TNode n, int vn, bool polarity, bool doRemove );
bool setMatch( QuantConflictFind * p, int v, TNode n );
bool isMatchSpurious( QuantConflictFind * p );
- bool completeMatch( QuantConflictFind * p, std::vector< int >& assigned );
+ bool completeMatch( QuantConflictFind * p, std::vector< int >& assigned, bool doContinue = false );
+ void revertMatch( std::vector< int >& assigned );
void debugPrintMatch( const char * c );
- bool isConstrainedVar( int v );
-public:
- // is partial
- bool d_isPartial;
- //the variables that this quantified formula has not beneath nested quantifiers
- std::map< TNode, bool > d_has_var;
- bool isPartial() { return d_isPartial; }
+ bool isConstrainedVar( int v );
+public:
+ void getMatch( std::vector< Node >& terms );
};
class QuantConflictFind : public QuantifiersModule
@@ -214,10 +226,11 @@ public:
enum {
effort_conflict,
effort_prop_eq,
- effort_partial,
effort_mc,
};
short d_effort;
+ void setEffort( int e ) { d_effort = e; }
+ static short getMaxQcfEffort();
bool areMatchEqual( TNode n1, TNode n2 );
bool areMatchDisequal( TNode n1, TNode n2 );
public:
@@ -233,11 +246,15 @@ public:
void merge( Node a, Node b );
/** assert disequal */
void assertDisequal( Node a, Node b );
+ /** reset round */
+ void reset_round( Theory::Effort level );
/** check */
void check( Theory::Effort level );
/** needs check */
bool needsCheck( Theory::Effort level );
private:
+ bool d_needs_computeRelEqr;
+public:
void computeRelevantEqr();
private:
void debugPrint( const char * c );
@@ -253,7 +270,6 @@ public:
IntStat d_inst_rounds;
IntStat d_conflict_inst;
IntStat d_prop_inst;
- IntStat d_partial_inst;
Statistics();
~Statistics();
};
diff --git a/src/theory/quantifiers/quantifiers_rewriter.cpp b/src/theory/quantifiers/quantifiers_rewriter.cpp
index ac847678d..a079dbaab 100644
--- a/src/theory/quantifiers/quantifiers_rewriter.cpp
+++ b/src/theory/quantifiers/quantifiers_rewriter.cpp
@@ -14,6 +14,7 @@
#include "theory/quantifiers/quantifiers_rewriter.h"
#include "theory/quantifiers/options.h"
+#include "theory/quantifiers/term_database.h"
using namespace std;
using namespace CVC4;
@@ -90,19 +91,29 @@ void QuantifiersRewriter::addNodeToOrBuilder( Node n, NodeBuilder<>& t ){
}
}
-void QuantifiersRewriter::computeArgs( std::vector< Node >& args, std::vector< Node >& activeArgs, Node n ){
+void QuantifiersRewriter::computeArgs( std::vector< Node >& args, std::map< Node, bool >& activeMap, Node n ){
if( n.getKind()==BOUND_VARIABLE ){
- if( std::find( args.begin(), args.end(), n )!=args.end() &&
- std::find( activeArgs.begin(), activeArgs.end(), n )==activeArgs.end() ){
- activeArgs.push_back( n );
+ if( std::find( args.begin(), args.end(), n )!=args.end() ){
+ activeMap[ n ] = true;
}
}else{
for( int i=0; i<(int)n.getNumChildren(); i++ ){
- computeArgs( args, activeArgs, n[i] );
+ computeArgs( args, activeMap, n[i] );
}
}
}
+void QuantifiersRewriter::computeArgVec( std::vector< Node >& args, std::vector< Node >& activeArgs, Node n ) {
+ std::map< Node, bool > activeMap;
+ computeArgs( args, activeMap, n );
+ for( unsigned i=0; i<args.size(); i++ ){
+ if( activeMap[args[i]] ){
+ activeArgs.push_back( args[i] );
+ }
+ }
+}
+
+
bool QuantifiersRewriter::hasArg( std::vector< Node >& args, Node n ){
if( std::find( args.begin(), args.end(), n )!=args.end() ){
return true;
@@ -135,7 +146,6 @@ void QuantifiersRewriter::setNestedQuantifiers2( Node n, Node q, std::vector< No
}
}
-
RewriteResponse QuantifiersRewriter::preRewrite(TNode in) {
Trace("quantifiers-rewrite-debug") << "pre-rewriting " << in << " " << in.hasAttribute(NestedQuantAttribute()) << std::endl;
if( in.getKind()==kind::EXISTS || in.getKind()==kind::FORALL ){
@@ -164,9 +174,7 @@ RewriteResponse QuantifiersRewriter::preRewrite(TNode in) {
}
Node n = NodeManager::currentNM()->mkNode( in.getKind(), children );
if( in!=n ){
- if( in.hasAttribute(NestedQuantAttribute()) ){
- setNestedQuantifiers( n, in.getAttribute(NestedQuantAttribute()) );
- }
+ setAttributes( in, n );
Trace("quantifiers-pre-rewrite") << "*** pre-rewrite " << in << std::endl;
Trace("quantifiers-pre-rewrite") << " to " << std::endl;
Trace("quantifiers-pre-rewrite") << n << std::endl;
@@ -178,8 +186,9 @@ RewriteResponse QuantifiersRewriter::preRewrite(TNode in) {
}
RewriteResponse QuantifiersRewriter::postRewrite(TNode in) {
- Trace("quantifiers-rewrite-debug") << "post-rewriting " << in << " " << in.hasAttribute(NestedQuantAttribute()) << std::endl;
- if( in.getKind()==kind::EXISTS || in.getKind()==kind::FORALL ){
+ Trace("quantifiers-rewrite-debug") << "post-rewriting " << in << std::endl;
+ Trace("quantifiers-rewrite-debug") << "Attributes : " << in.hasAttribute(NestedQuantAttribute()) << std::endl;
+ if( !options::quantRewriteRules() || !TermDb::isRewriteRule( in ) ){
RewriteStatus status = REWRITE_DONE;
Node ret = in;
//get the arguments
@@ -217,12 +226,13 @@ RewriteResponse QuantifiersRewriter::postRewrite(TNode in) {
}
//print if changed
if( in!=ret ){
- if( in.hasAttribute(NestedQuantAttribute()) ){
- setNestedQuantifiers( ret, in.getAttribute(NestedQuantAttribute()) );
- }
+ setAttributes( in, ret );
Trace("quantifiers-rewrite") << "*** rewrite " << in << std::endl;
Trace("quantifiers-rewrite") << " to " << std::endl;
Trace("quantifiers-rewrite") << ret << std::endl;
+ Trace("quantifiers-rewrite-debug") << "Attributes : " << ret.hasAttribute(NestedQuantAttribute()) << std::endl;
+
+
}
return RewriteResponse( status, ret );
}
@@ -409,6 +419,15 @@ Node QuantifiersRewriter::computeClause( Node n ){
}
}
+void QuantifiersRewriter::setAttributes( Node in, Node n ) {
+ if( in.hasAttribute(NestedQuantAttribute()) ){
+ setNestedQuantifiers( n, in.getAttribute(NestedQuantAttribute()) );
+ }
+ //if( in.hasAttribute(QRewriteRuleAttribute()) ){
+ // n.setAttribute(QRewriteRuleAttribute(), in.getAttribute(QRewriteRuleAttribute()));
+ //}
+}
+
Node QuantifiersRewriter::computeCNF( Node n, std::vector< Node >& args, NodeBuilder<>& defs, bool forcePred ){
if( isLiteral( n ) ){
return n;
@@ -432,7 +451,7 @@ Node QuantifiersRewriter::computeCNF( Node n, std::vector< Node >& args, NodeBui
//compute the free variables
Node nt = t;
std::vector< Node > activeArgs;
- computeArgs( args, activeArgs, nt );
+ computeArgVec( args, activeArgs, nt );
std::vector< TypeNode > argTypes;
for( int i=0; i<(int)activeArgs.size(); i++ ){
argTypes.push_back( activeArgs[i].getType() );
@@ -581,7 +600,7 @@ Node QuantifiersRewriter::computeSplit( Node f, Node body, std::vector< Node >&
//get variables contained in the literal
Node n = body[i];
std::vector<Node> lit_vars;
- computeArgs( vars, lit_vars, n);
+ computeArgVec( vars, lit_vars, n);
//collectVars( n, vars, lit_vars );
if (lit_vars.empty()) {
lits.push_back(n);
@@ -689,7 +708,7 @@ Node QuantifiersRewriter::computeOperation( Node f, int computeOption ){
n = computeElimSymbols( n );
}else if( computeOption==COMPUTE_MINISCOPING ){
//return directly
- return computeMiniscoping( args, n, ipl, f.hasAttribute(NestedQuantAttribute()) );
+ return computeMiniscoping( f, args, n, ipl, f.hasAttribute(NestedQuantAttribute()) );
}else if( computeOption==COMPUTE_AGGRESSIVE_MINISCOPING ){
return computeAggressiveMiniscoping( args, n, f.hasAttribute(NestedQuantAttribute()) );
}else if( computeOption==COMPUTE_NNF ){
@@ -735,7 +754,7 @@ Node QuantifiersRewriter::computeOperation( Node f, int computeOption ){
Node QuantifiersRewriter::mkForAll( std::vector< Node >& args, Node body, Node ipl ){
std::vector< Node > activeArgs;
- computeArgs( args, activeArgs, body );
+ computeArgVec( args, activeArgs, body );
if( activeArgs.empty() ){
return body;
}else{
@@ -749,7 +768,7 @@ Node QuantifiersRewriter::mkForAll( std::vector< Node >& args, Node body, Node i
}
}
-Node QuantifiersRewriter::computeMiniscoping( std::vector< Node >& args, Node body, Node ipl, bool isNested ){
+Node QuantifiersRewriter::computeMiniscoping( Node f, std::vector< Node >& args, Node body, Node ipl, bool isNested ){
//Notice() << "rewrite quant " << body << std::endl;
if( body.getKind()==FORALL ){
//combine arguments
@@ -763,21 +782,21 @@ Node QuantifiersRewriter::computeMiniscoping( std::vector< Node >& args, Node bo
if( body.getKind()==NOT ){
//push not downwards
if( body[0].getKind()==NOT ){
- return computeMiniscoping( args, body[0][0], ipl );
+ return computeMiniscoping( f, args, body[0][0], ipl );
}else if( body[0].getKind()==AND ){
if( doMiniscopingNoFreeVar() ){
NodeBuilder<> t(kind::OR);
for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
t << ( body[0][i].getKind()==NOT ? body[0][i][0] : body[0][i].notNode() );
}
- return computeMiniscoping( args, t.constructNode(), ipl );
+ return computeMiniscoping( f, args, t.constructNode(), ipl );
}
}else if( body[0].getKind()==OR ){
if( doMiniscopingAnd() ){
NodeBuilder<> t(kind::AND);
for( int i=0; i<(int)body[0].getNumChildren(); i++ ){
Node trm = body[0][i].negate();
- t << computeMiniscoping( args, trm, ipl );
+ t << computeMiniscoping( f, args, trm, ipl );
}
return t.constructNode();
}
@@ -787,7 +806,7 @@ Node QuantifiersRewriter::computeMiniscoping( std::vector< Node >& args, Node bo
//break apart
NodeBuilder<> t(kind::AND);
for( int i=0; i<(int)body.getNumChildren(); i++ ){
- t << computeMiniscoping( args, body[i], ipl );
+ t << computeMiniscoping( f, args, body[i], ipl );
}
Node retVal = t;
return retVal;
@@ -815,7 +834,11 @@ Node QuantifiersRewriter::computeMiniscoping( std::vector< Node >& args, Node bo
}
}
}
+ //if( body==f[1] ){
+ // return f;
+ //}else{
return mkForAll( args, body, ipl );
+ //}
}
Node QuantifiersRewriter::computeAggressiveMiniscoping( std::vector< Node >& args, Node body, bool isNested ){
@@ -826,7 +849,7 @@ Node QuantifiersRewriter::computeAggressiveMiniscoping( std::vector< Node >& arg
Trace("ag-miniscope") << "compute aggressive miniscoping on " << body << std::endl;
for( size_t i=0; i<body.getNumChildren(); i++ ){
std::vector< Node > activeArgs;
- computeArgs( args, activeArgs, body[i] );
+ computeArgVec( args, activeArgs, body[i] );
for (unsigned j=0; j<activeArgs.size(); j++ ){
varLits[activeArgs[j]].push_back( body[i] );
}
@@ -964,3 +987,220 @@ bool QuantifiersRewriter::doOperation( Node f, bool isNested, int computeOption
return false;
}
}
+
+
+
+
+Node QuantifiersRewriter::rewriteRewriteRule( Node r ) {
+ Kind rrkind = r[2].getKind();
+
+ //guards, pattern, body
+
+ // Replace variables by Inst_* variable and tag the terms that contain them
+ std::vector<Node> vars;
+ vars.reserve(r[0].getNumChildren());
+ for( Node::const_iterator v = r[0].begin(); v != r[0].end(); ++v ){
+ vars.push_back(*v);
+ };
+
+ // Body/Remove_term/Guards/Triggers
+ Node body = r[2][1];
+ TNode new_terms = r[2][1];
+ std::vector<Node> guards;
+ std::vector<Node> pattern;
+ Node true_node = NodeManager::currentNM()->mkConst(true);
+ // shortcut
+ TNode head = r[2][0];
+ switch(rrkind){
+ case kind::RR_REWRITE:
+ // Equality
+ pattern.push_back( head );
+ if( head.getType().isBoolean() ){
+ body = head.iffNode(body);
+ }else{
+ body = head.eqNode(body);
+ }
+ break;
+ case kind::RR_REDUCTION:
+ case kind::RR_DEDUCTION:
+ // Add head to guards and pattern
+ switch(head.getKind()){
+ case kind::AND:
+ for( unsigned i = 0; i<head.getNumChildren(); i++ ){
+ guards.push_back(head[i]);
+ pattern.push_back(head[i]);
+ }
+ break;
+ default:
+ if( head!=true_node ){
+ guards.push_back(head);
+ pattern.push_back( head );
+ }
+ break;
+ }
+ break;
+ default:
+ Unreachable("RewriteRules can be of only three kinds");
+ break;
+ }
+ // Add the other guards
+ TNode g = r[1];
+ switch(g.getKind()){
+ case kind::AND:
+ for( unsigned i = 0; i<g.getNumChildren(); i++ ){
+ guards.push_back(g[i]);
+ }
+ break;
+ default:
+ if( g != true_node ){
+ guards.push_back( g );
+ }
+ break;
+ }
+ // Add the other triggers
+ if( r[2].getNumChildren() >= 3 ){
+ for( unsigned i=0; i<r[2][2][0].getNumChildren(); i++ ) {
+ pattern.push_back( r[2][2][0][i] );
+ }
+ }
+
+ Trace("rr-rewrite") << "Rule is " << r << std::endl;
+ Trace("rr-rewrite") << "Head is " << head << std::endl;
+ Trace("rr-rewrite") << "Patterns are ";
+ for( unsigned i=0; i<pattern.size(); i++ ){
+ Trace("rr-rewrite") << pattern[i] << " ";
+ }
+ Trace("rr-rewrite") << std::endl;
+
+ NodeBuilder<> forallB(kind::FORALL);
+ forallB << r[0];
+ Node gg = guards.size()==0 ? true_node : ( guards.size()==1 ? guards[0] : NodeManager::currentNM()->mkNode( AND, guards ) );
+ gg = NodeManager::currentNM()->mkNode( OR, gg.negate(), body );
+ gg = Rewriter::rewrite( gg );
+ forallB << gg;
+ NodeBuilder<> patternB(kind::INST_PATTERN);
+ patternB.append(pattern);
+ NodeBuilder<> patternListB(kind::INST_PATTERN_LIST);
+ //the entire rewrite rule is the first pattern
+ if( options::quantRewriteRules() ){
+ patternListB << NodeManager::currentNM()->mkNode( INST_PATTERN, r );
+ }
+ patternListB << static_cast<Node>(patternB);
+ forallB << static_cast<Node>(patternListB);
+ Node rn = (Node) forallB;
+
+ return rn;
+}
+
+struct ContainsQuantAttributeId {};
+typedef expr::Attribute<ContainsQuantAttributeId, uint64_t> ContainsQuantAttribute;
+
+// check if the given node contains a universal quantifier
+bool QuantifiersRewriter::containsQuantifiers(Node n) {
+ if( n.hasAttribute(ContainsQuantAttribute()) ){
+ return n.getAttribute(ContainsQuantAttribute())==1;
+ } else if(n.getKind() == kind::FORALL) {
+ return true;
+ } else {
+ bool cq = false;
+ for( unsigned i = 0; i < n.getNumChildren(); ++i ){
+ if( containsQuantifiers(n[i]) ){
+ cq = true;
+ break;
+ }
+ }
+ ContainsQuantAttribute cqa;
+ n.setAttribute(cqa, cq ? 1 : 0);
+ return cq;
+ }
+}
+
+Node QuantifiersRewriter::preSkolemizeQuantifiers( Node n, bool polarity, std::vector< Node >& fvs ){
+ Trace("pre-sk") << "Pre-skolem " << n << " " << polarity << " " << fvs.size() << endl;
+ if( n.getKind()==kind::NOT ){
+ Node nn = preSkolemizeQuantifiers( n[0], !polarity, fvs );
+ return nn.negate();
+ }else if( n.getKind()==kind::FORALL ){
+ if( polarity ){
+ vector< Node > children;
+ children.push_back( n[0] );
+ //add children to current scope
+ vector< Node > fvss;
+ fvss.insert( fvss.begin(), fvs.begin(), fvs.end() );
+ for( int i=0; i<(int)n[0].getNumChildren(); i++ ){
+ fvss.push_back( n[0][i] );
+ }
+ //process body
+ children.push_back( preSkolemizeQuantifiers( n[1], polarity, fvss ) );
+ if( n.getNumChildren()==3 ){
+ children.push_back( n[2] );
+ }
+ //return processed quantifier
+ return NodeManager::currentNM()->mkNode( kind::FORALL, children );
+ }else{
+ //process body
+ Node nn = preSkolemizeQuantifiers( n[1], polarity, fvs );
+ //now, substitute skolems for the variables
+ vector< TypeNode > argTypes;
+ for( int i=0; i<(int)fvs.size(); i++ ){
+ argTypes.push_back( fvs[i].getType() );
+ }
+ //calculate the variables and substitution
+ vector< Node > vars;
+ vector< Node > subs;
+ for( int i=0; i<(int)n[0].getNumChildren(); i++ ){
+ vars.push_back( n[0][i] );
+ }
+ for( int i=0; i<(int)n[0].getNumChildren(); i++ ){
+ //make the new function symbol
+ if( argTypes.empty() ){
+ Node s = NodeManager::currentNM()->mkSkolem( "sk_$$", n[0][i].getType(), "created during pre-skolemization" );
+ subs.push_back( s );
+ }else{
+ TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, n[0][i].getType() );
+ Node op = NodeManager::currentNM()->mkSkolem( "skop_$$", typ, "op created during pre-skolemization" );
+ //DOTHIS: set attribute on op, marking that it should not be selected as trigger
+ vector< Node > funcArgs;
+ funcArgs.push_back( op );
+ funcArgs.insert( funcArgs.end(), fvs.begin(), fvs.end() );
+ subs.push_back( NodeManager::currentNM()->mkNode( kind::APPLY_UF, funcArgs ) );
+ }
+ }
+ //apply substitution
+ nn = nn.substitute( vars.begin(), vars.end(), subs.begin(), subs.end() );
+ return nn;
+ }
+ }else{
+ //check if it contains a quantifier as a subterm
+ //if so, we will write this node
+ if( containsQuantifiers( n ) ){
+ if( n.getType().isBoolean() ){
+ if( n.getKind()==kind::ITE || n.getKind()==kind::IFF || n.getKind()==kind::XOR || n.getKind()==kind::IMPLIES ){
+ Node nn;
+ //must remove structure
+ if( n.getKind()==kind::ITE ){
+ nn = NodeManager::currentNM()->mkNode( kind::AND,
+ NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n[1] ),
+ NodeManager::currentNM()->mkNode( kind::OR, n[0], n[2] ) );
+ }else if( n.getKind()==kind::IFF || n.getKind()==kind::XOR ){
+ nn = NodeManager::currentNM()->mkNode( kind::AND,
+ NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n.getKind()==kind::XOR ? n[1].notNode() : n[1] ),
+ NodeManager::currentNM()->mkNode( kind::OR, n[0], n.getKind()==kind::XOR ? n[1] : n[1].notNode() ) );
+ }else if( n.getKind()==kind::IMPLIES ){
+ nn = NodeManager::currentNM()->mkNode( kind::OR, n[0].notNode(), n[1] );
+ }
+ return preSkolemizeQuantifiers( nn, polarity, fvs );
+ }else if( n.getKind()==kind::AND || n.getKind()==kind::OR ){
+ vector< Node > children;
+ for( int i=0; i<(int)n.getNumChildren(); i++ ){
+ children.push_back( preSkolemizeQuantifiers( n[i], polarity, fvs ) );
+ }
+ return NodeManager::currentNM()->mkNode( n.getKind(), children );
+ }else{
+ //must pull ite's
+ }
+ }
+ }
+ return n;
+ }
+}
diff --git a/src/theory/quantifiers/quantifiers_rewriter.h b/src/theory/quantifiers/quantifiers_rewriter.h
index e97d84701..4cbdb0cd1 100644
--- a/src/theory/quantifiers/quantifiers_rewriter.h
+++ b/src/theory/quantifiers/quantifiers_rewriter.h
@@ -38,14 +38,16 @@ public:
private:
static void addNodeToOrBuilder( Node n, NodeBuilder<>& t );
static Node mkForAll( std::vector< Node >& args, Node body, Node ipl );
- static void computeArgs( std::vector< Node >& args, std::vector< Node >& activeArgs, Node n );
+ static void computeArgs( std::vector< Node >& args, std::map< Node, bool >& activeMap, Node n );
+ static void computeArgVec( std::vector< Node >& args, std::vector< Node >& activeArgs, Node n );
static bool hasArg( std::vector< Node >& args, Node n );
static void setNestedQuantifiers( Node n, Node q );
static void setNestedQuantifiers2( Node n, Node q, std::vector< Node >& processed );
static Node computeClause( Node n );
+ static void setAttributes( Node in, Node n );
private:
static Node computeElimSymbols( Node body );
- static Node computeMiniscoping( std::vector< Node >& args, Node body, Node ipl, bool isNested = false );
+ static Node computeMiniscoping( Node f, std::vector< Node >& args, Node body, Node ipl, bool isNested = false );
static Node computeAggressiveMiniscoping( std::vector< Node >& args, Node body, bool isNested = false );
static Node computeNNF( Node body );
static Node computeSimpleIteLift( Node body );
@@ -79,6 +81,10 @@ private:
static bool doMiniscopingAnd();
static bool doOperation( Node f, bool isNested, int computeOption );
public:
+ static Node rewriteRewriteRule( Node r );
+ static bool containsQuantifiers(Node n);
+ static Node preSkolemizeQuantifiers(Node n, bool polarity, std::vector<Node>& fvs);
+public:
//static Node rewriteQuants( Node n, bool isNested = false );
//static Node rewriteQuant( Node n, bool isNested = false );
};/* class QuantifiersRewriter */
diff --git a/src/theory/quantifiers/relevant_domain.cpp b/src/theory/quantifiers/relevant_domain.cpp
index 952f3409a..914141995 100644
--- a/src/theory/quantifiers/relevant_domain.cpp
+++ b/src/theory/quantifiers/relevant_domain.cpp
@@ -111,13 +111,15 @@ void RelevantDomain::compute(){
TermDb * db = d_qe->getTermDatabase();
for( std::map< Node, std::vector< Node > >::iterator it = db->d_op_map.begin(); it != db->d_op_map.end(); ++it ){
Node op = it->first;
- for( unsigned i=0; i<it->second.size(); i++ ){
+ unsigned sz = db->getNumGroundTerms( op );
+ for( unsigned i=0; i<sz; i++ ){
Node n = it->second[i];
//if it is a non-redundant term
if( !n.getAttribute(NoMatchAttribute()) ){
for( unsigned j=0; j<n.getNumChildren(); j++ ){
RDomain * rf = getRDomain( op, j );
rf->addTerm( n[j] );
+ Trace("rel-dom-debug") << "...add ground term " << n[j] << " to rel dom " << op << "[" << j << "]" << std::endl;
}
}
}
@@ -188,6 +190,7 @@ void RelevantDomain::computeRelevantDomain( Node n, bool hasPol, bool pol ) {
}else if( varCount==1 ){
int oCh = varCh==0 ? 1 : 0;
bool ng = d_qe->getTermDatabase()->hasInstConstAttr( n[oCh] );
+ Trace("rel-dom-debug") << "...add term " << n[oCh] << ", is ground = " << (!ng) << std::endl;
//the negative occurrence adds the term to the domain
if( !hasPol || !pol ){
rds[varCh]->addTerm( n[oCh], ng );
@@ -219,6 +222,7 @@ void RelevantDomain::computeRelevantDomainOpCh( RDomain * rf, Node n ) {
rq->merge( rf );
}
}else if( !d_qe->getTermDatabase()->hasInstConstAttr( n ) ){
+ Trace("rel-dom-debug") << "...add ground term to rel dom " << n << std::endl;
//term to add
rf->addTerm( n );
}
diff --git a/src/theory/quantifiers/rewrite_engine.cpp b/src/theory/quantifiers/rewrite_engine.cpp
index 81de1e11d..59ba40ca7 100644
--- a/src/theory/quantifiers/rewrite_engine.cpp
+++ b/src/theory/quantifiers/rewrite_engine.cpp
@@ -21,6 +21,7 @@
#include "theory/quantifiers/options.h"
#include "theory/quantifiers/inst_match_generator.h"
#include "theory/theory_engine.h"
+#include "theory/quantifiers/term_database.h"
using namespace CVC4;
using namespace std;
@@ -37,14 +38,15 @@ struct PrioritySort {
RewriteEngine::RewriteEngine( context::Context* c, QuantifiersEngine* qe ) : QuantifiersModule(qe) {
-
+ d_true = NodeManager::currentNM()->mkConst( true );
}
double RewriteEngine::getPriority( Node f ) {
- Node rr = f.getAttribute(QRewriteRuleAttribute());
+ Node rr = TermDb::getRewriteRule( f );
Node rrr = rr[2];
Trace("rr-priority") << "Get priority : " << rrr << " " << rrr.getKind() << std::endl;
bool deterministic = rrr[1].getKind()!=OR;
+
if( rrr.getKind()==RR_REWRITE ){
return deterministic ? 0.0 : 3.0;
}else if( rrr.getKind()==RR_DEDUCTION ){
@@ -54,26 +56,31 @@ double RewriteEngine::getPriority( Node f ) {
}else{
return 6.0;
}
+
+ //return deterministic ? 0.0 : 1.0;
}
void RewriteEngine::check( Theory::Effort e ) {
- if( e==Theory::EFFORT_LAST_CALL ){
- if( !d_quantEngine->getModel()->isModelSet() ){
- d_quantEngine->getTheoryEngine()->getModelBuilder()->buildModel( d_quantEngine->getModel(), true );
- }
- if( d_true.isNull() ){
- d_true = NodeManager::currentNM()->mkConst( true );
- }
- std::vector< Node > priority_order;
- PrioritySort ps;
- std::vector< int > indicies;
- for( int i=0; i<(int)d_rr_quant.size(); i++ ){
- ps.d_priority.push_back( getPriority( d_rr_quant[i] ) );
- indicies.push_back( i );
- }
- std::sort( indicies.begin(), indicies.end(), ps );
- for( unsigned i=0; i<indicies.size(); i++ ){
- priority_order.push_back( d_rr_quant[indicies[i]] );
+ if( e==Theory::EFFORT_FULL ){
+ Trace("rewrite-engine") << "---Rewrite Engine Round, effort = " << e << "---" << std::endl;
+ //if( e==Theory::EFFORT_LAST_CALL ){
+ // if( !d_quantEngine->getModel()->isModelSet() ){
+ // d_quantEngine->getTheoryEngine()->getModelBuilder()->buildModel( d_quantEngine->getModel(), true );
+ // }
+ //}
+ if( d_needsSort ){
+ d_priority_order.clear();
+ PrioritySort ps;
+ std::vector< int > indicies;
+ for( int i=0; i<(int)d_rr_quant.size(); i++ ){
+ ps.d_priority.push_back( getPriority( d_rr_quant[i] ) );
+ indicies.push_back( i );
+ }
+ std::sort( indicies.begin(), indicies.end(), ps );
+ for( unsigned i=0; i<indicies.size(); i++ ){
+ d_priority_order.push_back( d_rr_quant[indicies[i]] );
+ }
+ d_needsSort = false;
}
//apply rewrite rules
@@ -81,16 +88,17 @@ void RewriteEngine::check( Theory::Effort e ) {
//per priority level
int index = 0;
bool success = true;
- while( success && index<(int)priority_order.size() ) {
- addedLemmas += checkRewriteRule( priority_order[index] );
+ while( success && index<(int)d_priority_order.size() ) {
+ addedLemmas += checkRewriteRule( d_priority_order[index], e );
index++;
- if( index<(int)priority_order.size() ){
- success = addedLemmas==0 || getPriority( priority_order[index] )==getPriority( priority_order[index-1] );
+ if( index<(int)d_priority_order.size() ){
+ success = addedLemmas==0 || getPriority( d_priority_order[index] )==getPriority( d_priority_order[index-1] );
}
}
- Trace("inst-engine") << "Rewrite engine added " << addedLemmas << " lemmas." << std::endl;
+ Trace("rewrite-engine") << "Finished rewrite engine, added " << addedLemmas << " lemmas." << std::endl;
if (addedLemmas==0) {
+
}else{
//otherwise, the search will continue
d_quantEngine->flushLemmas( &d_quantEngine->getOutputChannel() );
@@ -98,85 +106,185 @@ void RewriteEngine::check( Theory::Effort e ) {
}
}
-int RewriteEngine::checkRewriteRule( Node f ) {
- Trace("rewrite-engine-inst") << "Check " << f << ", priority = " << getPriority( f ) << "..." << std::endl;
+int RewriteEngine::checkRewriteRule( Node f, Theory::Effort e ) {
int addedLemmas = 0;
- //reset triggers
- Node rr = f.getAttribute(QRewriteRuleAttribute());
- if( d_rr_triggers.find(f)==d_rr_triggers.end() ){
- std::vector< inst::Trigger * > triggers;
- if( f.getNumChildren()==3 ){
- for(unsigned i=0; i<f[2].getNumChildren(); i++ ){
- Node pat = f[2][i];
- std::vector< Node > nodes;
- Trace("rewrite-engine-trigger") << "Trigger is : ";
- for( int j=0; j<(int)pat.getNumChildren(); j++ ){
- Node p = d_quantEngine->getTermDatabase()->getInstConstantNode( pat[j], f );
- nodes.push_back( p );
- Trace("rewrite-engine-trigger") << p << " " << p.getKind() << " ";
- }
- Trace("rewrite-engine-trigger") << std::endl;
- Assert( inst::Trigger::isUsableTrigger( nodes, f ) );
- inst::Trigger * tr = inst::Trigger::mkTrigger( d_quantEngine, f, nodes, 0, true, inst::Trigger::TR_MAKE_NEW, false );
- tr->getGenerator()->setActiveAdd(false);
- triggers.push_back( tr );
- }
- }
- d_rr_triggers[f].insert( d_rr_triggers[f].end(), triggers.begin(), triggers.end() );
- }
- for( unsigned i=0; i<d_rr_triggers[f].size(); i++ ){
- Trace("rewrite-engine-inst") << "Try trigger " << *d_rr_triggers[f][i] << std::endl;
- d_rr_triggers[f][i]->resetInstantiationRound();
- d_rr_triggers[f][i]->reset( Node::null() );
- bool success;
- do
- {
- InstMatch m( f );
- success = d_rr_triggers[f][i]->getNextMatch( f, m );
- if( success ){
- //see if instantiation is true in the model
- Node rr = f.getAttribute(QRewriteRuleAttribute());
- Node rrg = rr[1];
- std::vector< Node > vars;
- std::vector< Node > terms;
- d_quantEngine->computeTermVector( f, m, vars, terms );
- Trace("rewrite-engine-inst-debug") << "Instantiation : " << m << std::endl;
- Node inst = d_rr_guard[f];
- inst = inst.substitute( vars.begin(), vars.end(), terms.begin(), terms.end() );
- Trace("rewrite-engine-inst-debug") << "Try instantiation, guard : " << inst << std::endl;
- FirstOrderModel * fm = d_quantEngine->getModel();
- Node v = fm->getValue( inst );
- Trace("rewrite-engine-inst-debug") << "Evaluated to " << v << std::endl;
- if( v==d_true ){
- Trace("rewrite-engine-inst-debug") << "Add instantiation : " << m << std::endl;
- if( d_quantEngine->addInstantiation( f, m ) ){
- addedLemmas++;
- Trace("rewrite-engine-inst-debug") << "success" << std::endl;
- //set the no-match attribute (the term is rewritten and can be ignored)
- //Trace("rewrite-engine-inst-debug") << "We matched on : " << m.d_matched << std::endl;
- //if( !m.d_matched.isNull() ){
- // NoMatchAttribute nma;
- // m.d_matched.setAttribute(nma,true);
+ Trace("rewrite-engine-inst") << "Check " << d_qinfo_n[f] << ", priority = " << getPriority( f ) << ", effort = " << e << "..." << std::endl;
+ QuantConflictFind * qcf = d_quantEngine->getConflictFind();
+ if( qcf ){
+ //reset QCF module
+ qcf->computeRelevantEqr();
+ qcf->setEffort( QuantConflictFind::effort_conflict );
+ //get the proper quantifiers info
+ std::map< Node, QuantInfo >::iterator it = d_qinfo.find( f );
+ if( it!=d_qinfo.end() ){
+ QuantInfo * qi = &it->second;
+ if( qi->d_mg->isValid() ){
+ Node rr = TermDb::getRewriteRule( f );
+ Trace("rewrite-engine-inst-debug") << " Reset round..." << std::endl;
+ qi->reset_round( qcf );
+ Trace("rewrite-engine-inst-debug") << " Get matches..." << std::endl;
+ while( qi->d_mg->getNextMatch( qcf, qi ) && ( addedLemmas==0 || !options::rrOneInstPerRound() ) ){
+ Trace("rewrite-engine-inst-debug") << " Got match to complete..." << std::endl;
+ qi->debugPrintMatch( "rewrite-engine-inst-debug" );
+ std::vector< int > assigned;
+ if( !qi->isMatchSpurious( qcf ) ){
+ bool doContinue = false;
+ bool success = true;
+ int tempAddedLemmas = 0;
+ while( tempAddedLemmas==0 && success && ( addedLemmas==0 || !options::rrOneInstPerRound() ) ){
+ success = qi->completeMatch( qcf, assigned, doContinue );
+ doContinue = true;
+ if( success ){
+ Trace("rewrite-engine-inst-debug") << " Construct match..." << std::endl;
+ std::vector< Node > inst;
+ qi->getMatch( inst );
+ Trace("rewrite-engine-inst-debug") << " Add instantiation..." << std::endl;
+ for( unsigned i=0; i<f[0].getNumChildren(); i++ ){
+ Trace("rewrite-engine-inst-debug") << " " << f[0][i] << " -> ";
+ if( i<inst.size() ){
+ Trace("rewrite-engine-inst-debug") << inst[i] << std::endl;
+ }else{
+ Trace("rewrite-engine-inst-debug") << "OUT_OF_RANGE" << std::endl;
+ Assert( false );
+ }
+ }
+ //resize to remove auxiliary variables
+ if( inst.size()>f[0].getNumChildren() ){
+ inst.resize( f[0].getNumChildren() );
+ }
+ if( d_quantEngine->addInstantiation( f, inst ) ){
+ addedLemmas++;
+ tempAddedLemmas++;
+ /*
+ //remove rewritten terms from consideration
+ std::vector< Node > to_remove;
+ switch( rr[2].getKind() ){
+ case kind::RR_REWRITE:
+ to_remove.push_back( rr[2][0] );
+ break;
+ case kind::RR_REDUCTION:
+ for( unsigned i=0; i<rr[2][0].getNumChildren(); i++ ){
+ to_remove.push_back( rr[2][0][i] );
+ }
+ break;
+ default:
+ break;
+ }
+ for( unsigned j=0; j<to_remove.size(); j++ ){
+ Node ns = d_quantEngine->getSubstitute( to_remove[j], inst );
+ Trace("rewrite-engine-inst-debug") << "Will remove : " << ns << std::endl;
+ ns.setAttribute(NoMatchAttribute(),true);
+ }
+ */
+ }else{
+ Trace("rewrite-engine-inst-debug") << " - failed." << std::endl;
+ }
+ Trace("rewrite-engine-inst-debug") << " Get next completion..." << std::endl;
+ }
+ }
+ //Trace("rewrite-engine-inst-debug") << " Reverted assigned variables : ";
+ //for( unsigned a=0; a<assigned.size(); a++ ) {
+ // Trace("rewrite-engine-inst-debug") << assigned[a] << " ";
//}
+ //Trace("rewrite-engine-inst-debug") << std::endl;
+ //qi->revertMatch( assigned );
+ //Assert( assigned.empty() );
+ Trace("rewrite-engine-inst-debug") << " - failed to complete." << std::endl;
}else{
- Trace("rewrite-engine-inst-debug") << "failure." << std::endl;
+ Trace("rewrite-engine-inst-debug") << " - match is spurious." << std::endl;
}
+ Trace("rewrite-engine-inst-debug") << " Get next match..." << std::endl;
}
+ }else{
+ Trace("rewrite-engine-inst-debug") << "...Invalid qinfo." << std::endl;
}
- }while(success);
+ }else{
+ Trace("rewrite-engine-inst-debug") << "...No qinfo." << std::endl;
+ }
}
- Trace("rewrite-engine-inst") << "Rule " << f << " generated " << addedLemmas << " lemmas." << std::endl;
+ Trace("rewrite-engine-inst") << "-> Generated " << addedLemmas << " lemmas." << std::endl;
return addedLemmas;
}
void RewriteEngine::registerQuantifier( Node f ) {
- if( f.hasAttribute(QRewriteRuleAttribute()) ){
- Trace("rewrite-engine") << "Register quantifier " << f << std::endl;
- Node rr = f.getAttribute(QRewriteRuleAttribute());
- Trace("rewrite-engine") << " rewrite rule is : " << rr << std::endl;
+ Node rr = TermDb::getRewriteRule( f );
+ if( !rr.isNull() ){
+ Trace("rr-register") << "Register quantifier " << f << std::endl;
+ Trace("rr-register") << " rewrite rule is : " << rr << std::endl;
d_rr_quant.push_back( f );
- d_rr_guard[f] = rr[1];
- Trace("rewrite-engine") << " guard is : " << d_rr_guard[f] << std::endl;
+ d_rr[f] = rr;
+ d_needsSort = true;
+ Trace("rr-register") << " guard is : " << d_rr[f][1] << std::endl;
+
+ QuantConflictFind * qcf = d_quantEngine->getConflictFind();
+ if( qcf ){
+ std::vector< Node > qcfn_c;
+
+ std::vector< Node > bvl;
+ for( unsigned i=0; i<f[0].getNumChildren(); i++ ){
+ bvl.push_back( f[0][i] );
+ }
+
+ std::vector< Node > cc;
+ //Node head = rr[2][0];
+ //if( head!=d_true ){
+ //Node head_eq = head.getType().isBoolean() ? head.iffNode( head ) : head.eqNode( head );
+ //head_eq = head_eq.negate();
+ //cc.push_back( head_eq );
+ //Trace("rr-register-debug") << " head eq is " << head_eq << std::endl;
+ //}
+ //add patterns
+ for( unsigned i=1; i<f[2].getNumChildren(); i++ ){
+ std::vector< Node > nc;
+ for( unsigned j=0; j<f[2][i].getNumChildren(); j++ ){
+ Node nn;
+ Node nbv = NodeManager::currentNM()->mkBoundVar( f[2][i][j].getType() );
+ if( f[2][i][j].getType().isBoolean() ){
+ if( f[2][i][j].getKind()!=APPLY_UF ){
+ nn = f[2][i][j].negate();
+ }else{
+ nn = f[2][i][j].iffNode( nbv ).negate();
+ bvl.push_back( nbv );
+ }
+ //nn = f[2][i][j].negate();
+ }else{
+ nn = f[2][i][j].eqNode( nbv ).negate();
+ bvl.push_back( nbv );
+ }
+ nc.push_back( nn );
+ }
+ if( !nc.empty() ){
+ Node n = nc.size()==1 ? nc[0] : NodeManager::currentNM()->mkNode( AND, nc );
+ Trace("rr-register-debug") << " pattern is " << n << std::endl;
+ if( std::find( cc.begin(), cc.end(), n )==cc.end() ){
+ cc.push_back( n );
+ }
+ }
+ }
+ qcfn_c.push_back( NodeManager::currentNM()->mkNode( BOUND_VAR_LIST, bvl ) );
+
+ std::vector< Node > body_c;
+ //add the guards
+ if( d_rr[f][1].getKind()==AND ){
+ for( unsigned j=0; j<d_rr[f][1].getNumChildren(); j++ ){
+ if( MatchGen::isHandled( d_rr[f][1][j] ) ){
+ body_c.push_back( d_rr[f][1][j].negate() );
+ }
+ }
+ }else if( d_rr[f][1]!=d_true ){
+ if( MatchGen::isHandled( d_rr[f][1] ) ){
+ body_c.push_back( d_rr[f][1].negate() );
+ }
+ }
+ //add the patterns to the body
+ body_c.push_back( cc.size()==1 ? cc[0] : NodeManager::currentNM()->mkNode( AND, cc ) );
+ //make the body
+ qcfn_c.push_back( body_c.size()==1 ? body_c[0] : NodeManager::currentNM()->mkNode( OR, body_c ) );
+ //make the quantified formula
+ d_qinfo_n[f] = NodeManager::currentNM()->mkNode( FORALL, qcfn_c );
+ Trace("rr-register") << " qcf formula is : " << d_qinfo_n[f] << std::endl;
+ d_qinfo[f].initialize( d_qinfo_n[f], d_qinfo_n[f][1] );
+ }
}
}
@@ -184,3 +292,13 @@ void RewriteEngine::assertNode( Node n ) {
}
+Node RewriteEngine::getInstConstNode( Node n, Node q ) {
+ std::map< Node, Node >::iterator it = d_inst_const_node[q].find( n );
+ if( it==d_inst_const_node[q].end() ){
+ Node nn = d_quantEngine->getTermDatabase()->getInstConstantNode( n, q );
+ d_inst_const_node[q][n] = nn;
+ return nn;
+ }else{
+ return it->second;
+ }
+} \ No newline at end of file
diff --git a/src/theory/quantifiers/rewrite_engine.h b/src/theory/quantifiers/rewrite_engine.h
index a9a2f9b46..f85803617 100644
--- a/src/theory/quantifiers/rewrite_engine.h
+++ b/src/theory/quantifiers/rewrite_engine.h
@@ -29,19 +29,28 @@ namespace CVC4 {
namespace theory {
namespace quantifiers {
+class QuantInfo;
+
class RewriteEngine : public QuantifiersModule
{
typedef context::CDHashMap<Node, bool, NodeHashFunction> NodeBoolMap;
typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
typedef context::CDHashMap<Node, Node, NodeHashFunction> NodeNodeMap;
std::vector< Node > d_rr_quant;
- std::map< Node, Node > d_rr_guard;
+ std::vector< Node > d_priority_order;
+ std::map< Node, Node > d_rr;
Node d_true;
/** explicitly provided patterns */
std::map< Node, std::vector< inst::Trigger* > > d_rr_triggers;
+ /** get the quantifer info object */
+ std::map< Node, Node > d_qinfo_n;
+ std::map< Node, QuantInfo > d_qinfo;
double getPriority( Node f );
+ bool d_needsSort;
+ std::map< Node, std::map< Node, Node > > d_inst_const_node;
+ Node getInstConstNode( Node n, Node q );
private:
- int checkRewriteRule( Node f );
+ int checkRewriteRule( Node f, Theory::Effort e );
public:
RewriteEngine( context::Context* c, QuantifiersEngine* qe );
diff --git a/src/theory/quantifiers/symmetry_breaking.cpp b/src/theory/quantifiers/symmetry_breaking.cpp
index 0023b05bc..900db62d0 100644
--- a/src/theory/quantifiers/symmetry_breaking.cpp
+++ b/src/theory/quantifiers/symmetry_breaking.cpp
@@ -21,6 +21,7 @@
#include "theory/theory_engine.h"
#include "util/sort_inference.h"
#include "theory/uf/theory_uf_strong_solver.h"
+#include "theory/uf/theory_uf.h"
using namespace CVC4;
using namespace CVC4::kind;
diff --git a/src/theory/quantifiers/term_database.cpp b/src/theory/quantifiers/term_database.cpp
index 39ba3e8af..ea1231e7a 100644
--- a/src/theory/quantifiers/term_database.cpp
+++ b/src/theory/quantifiers/term_database.cpp
@@ -18,7 +18,6 @@
#include "theory/theory_engine.h"
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/options.h"
-#include "theory/rewriterules/efficient_e_matching.h"
#include "theory/quantifiers/theory_quantifiers.h"
using namespace std;
@@ -47,19 +46,20 @@ bool TermArgTrie::addTerm2( QuantifiersEngine* qe, Node n, int argIndex ){
}
}
-void TermDb::addTermEfficient( Node n, std::set< Node >& added){
- static AvailableInTermDb aitdi;
- if (inst::Trigger::isAtomicTrigger( n ) && !n.getAttribute(aitdi)){
- //Already processed but new in this branch
- n.setAttribute(aitdi,true);
- added.insert( n );
- for( size_t i=0; i< n.getNumChildren(); i++ ){
- addTermEfficient(n[i],added);
- }
- }
+TermDb::TermDb( context::Context* c, context::UserContext* u, QuantifiersEngine* qe ) : d_quantEngine( qe ), d_op_ccount( u ) {
}
+/** ground terms */
+unsigned TermDb::getNumGroundTerms( Node f ) {
+ std::map< Node, std::vector< Node > >::iterator it = d_op_map.find( f );
+ if( it!=d_op_map.end() ){
+ return it->second.size();
+ }else{
+ return 0;
+ }
+ //return d_op_ccount[f];
+}
Node TermDb::getOperator( Node n ) {
//return n.getOperator();
@@ -94,10 +94,8 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
return;
}
if( d_processed.find( n )==d_processed.end() ){
- ++(d_quantEngine->d_statistics.d_term_in_termdb);
d_processed.insert(n);
d_type_map[ n.getType() ].push_back( n );
- n.setAttribute(AvailableInTermDb(),true);
//if this is an atomic trigger, consider adding it
//Call the children?
if( inst::Trigger::isAtomicTrigger( n ) ){
@@ -105,27 +103,20 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
Trace("term-db") << "register term in db " << n << std::endl;
//std::cout << "register trigger term " << n << std::endl;
Node op = getOperator( n );
+ /*
+ int occ = d_op_ccount[op];
+ if( occ<(int)d_op_map[op].size() ){
+ d_op_map[op][occ] = n;
+ }else{
+ d_op_map[op].push_back( n );
+ }
+ d_op_ccount[op].set( occ + 1 );
+ */
d_op_map[op].push_back( n );
added.insert( n );
for( size_t i=0; i<n.getNumChildren(); i++ ){
addTerm( n[i], added, withinQuant );
- if( options::efficientEMatching() ){
- EfficientEMatcher* eem = d_quantEngine->getEfficientEMatcher();
- if( d_parents[n[i]][op].empty() ){
- //must add parent to equivalence class info
- Node nir = d_quantEngine->getEqualityQuery()->getRepresentative( n[i] );
- EqClassInfo* eci_nir = eem->getEquivalenceClassInfo( nir );
- if( eci_nir ){
- eci_nir->d_pfuns[ op ] = true;
- }
- }
- //add to parent structure
- if( std::find( d_parents[n[i]][op][i].begin(), d_parents[n[i]][op][i].end(), n )==d_parents[n[i]][op][i].end() ){
- d_parents[n[i]][op][i].push_back( n );
- Assert(!getParents(n[i],op,i).empty());
- }
- }
if( options::eagerInstQuant() ){
if( !n.hasAttribute(InstLevelAttribute()) && n.getAttribute(InstLevelAttribute())==0 ){
int addedLemmas = 0;
@@ -143,13 +134,6 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
addTerm( n[i], added, withinQuant );
}
}
- }else{
- if( options::efficientEMatching() && !TermDb::hasInstConstAttr(n)){
- //Efficient e-matching must be notified
- //The term in triggers are not important here
- Debug("term-db") << "New in this branch term " << n << std::endl;
- addTermEfficient(n,added);
- }
}
}
@@ -159,7 +143,7 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
int alreadyCongruentCount = 0;
//rebuild d_func/pred_map_trie for each operation, this will calculate all congruent terms
for( std::map< Node, std::vector< Node > >::iterator it = d_op_map.begin(); it != d_op_map.end(); ++it ){
- d_op_count[ it->first ] = 0;
+ d_op_nonred_count[ it->first ] = 0;
if( !it->second.empty() ){
if( it->second[0].getType().isBoolean() ){
d_pred_map_trie[ 0 ][ it->first ].d_data.clear();
@@ -177,7 +161,7 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
congruentCount++;
}else{
nonCongruentCount++;
- d_op_count[ it->first ]++;
+ d_op_nonred_count[ it->first ]++;
}
}else{
congruentCount++;
@@ -205,7 +189,7 @@ void TermDb::addTerm( Node n, std::set< Node >& added, bool withinQuant ){
congruentCount++;
}else{
nonCongruentCount++;
- d_op_count[ op ]++;
+ d_op_nonred_count[ op ]++;
}
}else{
alreadyCongruentCount++;
@@ -348,28 +332,6 @@ bool TermDb::hasInstConstAttr( Node n ) {
return !getInstConstAttr(n).isNull();
}
-bool TermDb::hasBoundVarAttr( Node n ) {
- if( !n.getAttribute(HasBoundVarComputedAttribute()) ){
- bool hasBv = false;
- if( n.getKind()==BOUND_VARIABLE ){
- hasBv = true;
- }else{
- for (unsigned i=0; i<n.getNumChildren(); i++) {
- if( hasBoundVarAttr(n[i]) ){
- hasBv = true;
- break;
- }
- }
- }
- HasBoundVarAttribute hbva;
- n.setAttribute(hbva, hasBv);
- HasBoundVarComputedAttribute hbvca;
- n.setAttribute(hbvca, true);
- Trace("bva") << n << " has bva : " << n.getAttribute(HasBoundVarAttribute()) << std::endl;
- }
- return n.getAttribute(HasBoundVarAttribute());
-}
-
void TermDb::getBoundVars( Node n, std::vector< Node >& bvs) {
if (n.getKind()==BOUND_VARIABLE ){
if ( std::find( bvs.begin(), bvs.end(), n)==bvs.end() ){
@@ -669,3 +631,15 @@ void TermDb::registerTrigger( theory::inst::Trigger* tr, Node op ){
d_op_triggers[op].push_back( tr );
}
}
+
+bool TermDb::isRewriteRule( Node q ) {
+ return !getRewriteRule( q ).isNull();
+}
+
+Node TermDb::getRewriteRule( Node q ) {
+ if( q.getKind()==FORALL && q.getNumChildren()==3 && q[2].getNumChildren()>0 && q[2][0][0].getKind()==REWRITE_RULE ){
+ return q[2][0][0];
+ }else{
+ return Node::null();
+ }
+}
diff --git a/src/theory/quantifiers/term_database.h b/src/theory/quantifiers/term_database.h
index 860f087dd..41108bc2a 100644
--- a/src/theory/quantifiers/term_database.h
+++ b/src/theory/quantifiers/term_database.h
@@ -44,15 +44,6 @@ typedef expr::Attribute<InstLevelAttributeId, uint64_t> InstLevelAttribute;
struct InstVarNumAttributeId {};
typedef expr::Attribute<InstVarNumAttributeId, uint64_t> InstVarNumAttribute;
-// Attribute that tell if a node have been asserted in this branch
-struct AvailableInTermDbId {};
-/** use the special for boolean flag */
-typedef expr::Attribute<AvailableInTermDbId,
- bool,
- expr::attr::NullCleanupStrategy,
- true // context dependent
- > AvailableInTermDb;
-
struct ModelBasisAttributeId {};
typedef expr::Attribute<ModelBasisAttributeId, bool> ModelBasisAttribute;
//for APPLY_UF terms, 1 : term has direct child with model basis attribute,
@@ -60,15 +51,6 @@ typedef expr::Attribute<ModelBasisAttributeId, bool> ModelBasisAttribute;
struct ModelBasisArgAttributeId {};
typedef expr::Attribute<ModelBasisArgAttributeId, uint64_t> ModelBasisArgAttribute;
-struct HasBoundVarAttributeId {};
-typedef expr::Attribute<HasBoundVarAttributeId, bool> HasBoundVarAttribute;
-struct HasBoundVarComputedAttributeId {};
-typedef expr::Attribute<HasBoundVarComputedAttributeId, bool> HasBoundVarComputedAttribute;
-
-//for rewrite rules
-struct QRewriteRuleAttributeId {};
-typedef expr::Attribute<QRewriteRuleAttributeId, Node> QRewriteRuleAttribute;
-
//for bounded integers
struct BoundIntLitAttributeId {};
typedef expr::Attribute<BoundIntLitAttributeId, uint64_t> BoundIntLitAttribute;
@@ -106,6 +88,7 @@ class TermDb {
friend class ::CVC4::theory::inst::Trigger;
friend class ::CVC4::theory::rrinst::Trigger;
friend class ::CVC4::theory::quantifiers::fmcheck::FullModelChecker;
+ typedef context::CDHashMap<Node, int, NodeHashFunction> NodeIntMap;
private:
/** reference to the quantifiers engine */
QuantifiersEngine* d_quantEngine;
@@ -114,13 +97,17 @@ private:
private:
/** select op map */
std::map< Node, std::map< TypeNode, std::map< TypeNode, Node > > > d_par_op_map;
+ /** count number of ground terms per operator (user-context dependent) */
+ NodeIntMap d_op_ccount;
public:
- TermDb( QuantifiersEngine* qe ) : d_quantEngine( qe ){}
+ TermDb( context::Context* c, context::UserContext* u, QuantifiersEngine* qe );
~TermDb(){}
+ /** ground terms */
+ unsigned getNumGroundTerms( Node f );
+ /** count number of non-redundant ground terms per operator */
+ std::map< Node, int > d_op_nonred_count;
/** map from APPLY_UF operators to ground terms for that operator */
std::map< Node, std::vector< Node > > d_op_map;
- /** count number of APPLY_UF terms per operator */
- std::map< Node, int > d_op_count;
/** map from APPLY_UF functions to trie */
std::map< Node, TermArgTrie > d_func_map_trie;
/** map from APPLY_UF predicates to trie */
@@ -133,9 +120,6 @@ public:
void reset( Theory::Effort effort );
/** get operation */
Node getOperator( Node n );
-private:
- /** for efficient e-matching */
- void addTermEfficient( Node n, std::set< Node >& added);
public:
/** parent structure (for efficient E-matching):
n -> op -> index -> L
@@ -210,8 +194,6 @@ public:
static bool hasInstConstAttr( Node n );
//for bound variables
public:
- //does n have bound variables?
- static bool hasBoundVarAttr( Node n );
//get bound variables in n
static void getBoundVars( Node n, std::vector< Node >& bvs);
//for skolem
@@ -259,6 +241,11 @@ public:
int isInstanceOf( Node n1, Node n2 );
/** filter all nodes that have instances */
void filterInstances( std::vector< Node >& nodes );
+public:
+ /** is quantifier treated as a rewrite rule? */
+ static bool isRewriteRule( Node q );
+ /** get the rewrite rule associated with the quanfied formula */
+ static Node getRewriteRule( Node q );
};/* class TermDb */
}/* 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 b13d8601e..93bd2c012 100644
--- a/src/theory/quantifiers/theory_quantifiers_type_rules.h
+++ b/src/theory/quantifiers/theory_quantifiers_type_rules.h
@@ -104,6 +104,92 @@ struct QuantifierInstPatternListTypeRule {
}
};/* struct QuantifierInstPatternListTypeRule */
+
+class RewriteRuleTypeRule {
+public:
+
+ /**
+ * Compute the type for (and optionally typecheck) a term belonging
+ * to the theory of rewriterules.
+ *
+ * @param nodeManager the NodeManager in use
+ * @param n the node to compute the type of
+ * @param check if true, the node's type should be checked as well
+ * as computed.
+ */
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n,
+ bool check)
+ throw(TypeCheckingExceptionPrivate) {
+ Debug("typecheck-r") << "type check for rr " << n << std::endl;
+ Assert(n.getKind() == kind::REWRITE_RULE && n.getNumChildren()==3 );
+ if( check ){
+ if( n[ 0 ].getType(check)!=nodeManager->boundVarListType() ){
+ throw TypeCheckingExceptionPrivate(n[0],
+ "first argument of rewrite rule is not bound var list");
+ }
+ if( n[ 1 ].getType(check)!=nodeManager->booleanType() ){
+ throw TypeCheckingExceptionPrivate(n[1],
+ "guard of rewrite rule is not an actual guard");
+ }
+ if( n[2].getType(check) !=
+ TypeNode(nodeManager->mkTypeConst<TypeConstant>(RRHB_TYPE))){
+ throw TypeCheckingExceptionPrivate(n[2],
+ "not a correct rewrite rule");
+ }
+ }
+ return nodeManager->booleanType();
+ }
+};/* class RewriteRuleTypeRule */
+
+
+class RRRewriteTypeRule {
+public:
+
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw(TypeCheckingExceptionPrivate) {
+ Assert(n.getKind() == kind::RR_REWRITE );
+ if( check ){
+ if( n[0].getType(check)!=n[1].getType(check) ){
+ throw TypeCheckingExceptionPrivate(n,
+ "terms of rewrite rule are not equal");
+ }
+ if( n.getNumChildren() == 3 && n[2].getType(check)!=nodeManager->instPatternListType() ){
+ throw TypeCheckingExceptionPrivate(n, "third argument of rewrite rule is not instantiation pattern list");
+ }
+ if( n[0].getKind()!=kind::APPLY_UF ){
+ throw TypeCheckingExceptionPrivate(n[0], "head of rewrite rules must start with an uninterpreted symbols. If you want to write a propagation rule, add the guard [true] for disambiguation");
+ }
+ }
+ return TypeNode(nodeManager->mkTypeConst<TypeConstant>(RRHB_TYPE));
+ }
+};/* struct QuantifierReductionRuleRule */
+
+class RRRedDedTypeRule {
+public:
+
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw(TypeCheckingExceptionPrivate) {
+ Assert(n.getKind() == kind::RR_REDUCTION ||
+ n.getKind() == kind::RR_DEDUCTION );
+ if( check ){
+ if( n[ 0 ].getType(check)!=nodeManager->booleanType() ){
+ throw TypeCheckingExceptionPrivate(n, "head of reduction rule is not boolean");
+ }
+ if( n[ 1 ].getType(check)!=nodeManager->booleanType() ){
+ throw TypeCheckingExceptionPrivate(n, "body of reduction rule is not boolean");
+ }
+ if( n.getNumChildren() == 3 && n[2].getType(check)!=nodeManager->instPatternListType() ){
+ throw TypeCheckingExceptionPrivate(n, "third argument of rewrite rule is not instantiation pattern list");
+ }
+ if( n.getNumChildren() < 3 && n[ 0 ] == nodeManager->mkConst<bool>(true) ){
+ throw TypeCheckingExceptionPrivate(n, "A rewrite rule must have one head or one trigger at least");
+ }
+ }
+ return TypeNode(nodeManager->mkTypeConst<TypeConstant>(RRHB_TYPE));
+ }
+};/* struct QuantifierReductionRuleRule */
+
+
}/* CVC4::theory::quantifiers namespace */
}/* CVC4::theory namespace */
}/* CVC4 namespace */
diff --git a/src/theory/quantifiers_engine.cpp b/src/theory/quantifiers_engine.cpp
index 41f53740a..7fa61477f 100644
--- a/src/theory/quantifiers_engine.cpp
+++ b/src/theory/quantifiers_engine.cpp
@@ -25,13 +25,14 @@
#include "theory/quantifiers/first_order_model.h"
#include "theory/quantifiers/term_database.h"
#include "theory/quantifiers/trigger.h"
-#include "theory/rewriterules/efficient_e_matching.h"
-#include "theory/rewriterules/rr_trigger.h"
+//#include "theory/rewriterules/efficient_e_matching.h"
+//#include "theory/rewriterules/rr_trigger.h"
#include "theory/quantifiers/bounded_integers.h"
#include "theory/quantifiers/rewrite_engine.h"
#include "theory/quantifiers/quant_conflict_find.h"
#include "theory/quantifiers/relevant_domain.h"
#include "theory/uf/options.h"
+#include "theory/uf/theory_uf.h"
using namespace std;
using namespace CVC4;
@@ -44,10 +45,10 @@ QuantifiersEngine::QuantifiersEngine(context::Context* c, context::UserContext*
d_te( te ),
d_lemmas_produced_c(u){
d_eq_query = new EqualityQueryQuantifiersEngine( this );
- d_term_db = new quantifiers::TermDb( this );
+ d_term_db = new quantifiers::TermDb( c, u, this );
d_tr_trie = new inst::TriggerTrie;
- d_rr_tr_trie = new rrinst::TriggerTrie;
- d_eem = new EfficientEMatcher( this );
+ //d_rr_tr_trie = new rrinst::TriggerTrie;
+ //d_eem = new EfficientEMatcher( this );
d_hasAddedLemma = false;
Trace("quant-engine-debug") << "Initialize model, mbqi : " << options::mbqiMode() << std::endl;
@@ -74,7 +75,7 @@ d_lemmas_produced_c(u){
}
//add quantifiers modules
- if( options::quantConflictFind() ){
+ if( options::quantConflictFind() || options::quantRewriteRules() ){
d_qcf = new quantifiers::QuantConflictFind( this, c);
d_modules.push_back( d_qcf );
}else{
@@ -100,7 +101,7 @@ d_lemmas_produced_c(u){
d_model_engine = NULL;
d_bint = NULL;
}
- if( options::rewriteRulesAsAxioms() ){
+ if( options::quantRewriteRules() ){
d_rr_engine = new quantifiers::RewriteEngine( c, this );
d_modules.push_back(d_rr_engine);
}else{
@@ -129,10 +130,6 @@ EqualityQueryQuantifiersEngine* QuantifiersEngine::getEqualityQuery() {
return d_eq_query;
}
-//Instantiator* QuantifiersEngine::getInstantiator( theory::TheoryId id ){
-// return d_te->theoryOf( id )->getInstantiator();
-//}
-
context::Context* QuantifiersEngine::getSatContext(){
return d_te->theoryOf( THEORY_QUANTIFIERS )->getSatContext();
}
@@ -176,6 +173,9 @@ void QuantifiersEngine::check( Theory::Effort e ){
if( d_rel_dom ){
d_rel_dom->reset();
}
+ for( int i=0; i<(int)d_modules.size(); i++ ){
+ d_modules[i]->reset_round( e );
+ }
if( e==Theory::EFFORT_LAST_CALL ){
//if effort is last call, try to minimize model first
if( options::finiteModelFind() ){
@@ -216,7 +216,11 @@ void QuantifiersEngine::check( Theory::Effort e ){
void QuantifiersEngine::registerQuantifier( Node f ){
if( std::find( d_quants.begin(), d_quants.end(), f )==d_quants.end() ){
- Trace("quant") << "Register quantifier : " << f << std::endl;
+ Trace("quant") << "QuantifiersEngine : Register quantifier ";
+ if( d_term_db->isRewriteRule( f ) ){
+ Trace("quant") << " (rewrite rule)";
+ }
+ Trace("quant") << " : " << f << std::endl;
d_quants.push_back( f );
++(d_statistics.d_num_quant);
@@ -277,9 +281,6 @@ Node QuantifiersEngine::getNextDecisionRequest(){
void QuantifiersEngine::addTermToDatabase( Node n, bool withinQuant ){
std::set< Node > added;
getTermDatabase()->addTerm( n, added, withinQuant );
- if( options::efficientEMatching() ){
- d_eem->newTerms( added );
- }
//added contains also the Node that just have been asserted in this branch
if( d_quant_rel ){
for( std::set< Node >::iterator i=added.begin(), end=added.end(); i!=end; i++ ){
@@ -361,7 +362,7 @@ void QuantifiersEngine::setInstantiationLevelAttr( Node n, uint64_t level ){
}
}
-Node QuantifiersEngine::doSubstitute( Node n, std::vector< Node >& terms ){
+Node QuantifiersEngine::getSubstitute( Node n, std::vector< Node >& terms ){
if( n.getKind()==INST_CONSTANT ){
Debug("check-inst") << "Substitute inst constant : " << n << std::endl;
return terms[n.getAttribute(InstVarNumAttribute())];
@@ -377,7 +378,7 @@ Node QuantifiersEngine::doSubstitute( Node n, std::vector< Node >& terms ){
}
bool changed = false;
for( unsigned i=0; i<n.getNumChildren(); i++ ){
- Node c = doSubstitute( n[i], terms );
+ Node c = getSubstitute( n[i], terms );
cc.push_back( c );
changed = changed || c!=n[i];
}
@@ -410,7 +411,7 @@ Node QuantifiersEngine::getInstantiation( Node f, std::vector< Node >& vars, std
}else{
//do optimized version
Node icb = d_term_db->getInstConstantBody( f );
- body = doSubstitute( icb, terms );
+ body = getSubstitute( icb, terms );
if( Debug.isOn("check-inst") ){
Node body2 = f[ 1 ].substitute( vars.begin(), vars.end(), terms.begin(), terms.end() );
if( body!=body2 ){
@@ -612,15 +613,7 @@ QuantifiersEngine::Statistics::Statistics():
d_triggers("QuantifiersEngine::Triggers", 0),
d_simple_triggers("QuantifiersEngine::Triggers_Simple", 0),
d_multi_triggers("QuantifiersEngine::Triggers_Multi", 0),
- d_multi_trigger_instantiations("QuantifiersEngine::Multi_Trigger_Instantiations", 0),
- d_term_in_termdb("QuantifiersEngine::Term_in_TermDb", 0),
- d_num_mono_candidates("QuantifiersEngine::NumMonoCandidates", 0),
- d_num_mono_candidates_new_term("QuantifiersEngine::NumMonoCandidatesNewTerm", 0),
- d_num_multi_candidates("QuantifiersEngine::NumMultiCandidates", 0),
- d_mono_candidates_cache_hit("QuantifiersEngine::MonoCandidatesCacheHit", 0),
- d_mono_candidates_cache_miss("QuantifiersEngine::MonoCandidatesCacheMiss", 0),
- d_multi_candidates_cache_hit("QuantifiersEngine::MultiCandidatesCacheHit", 0),
- d_multi_candidates_cache_miss("QuantifiersEngine::MultiCandidatesCacheMiss", 0)
+ d_multi_trigger_instantiations("QuantifiersEngine::Multi_Trigger_Instantiations", 0)
{
StatisticsRegistry::registerStat(&d_num_quant);
StatisticsRegistry::registerStat(&d_instantiation_rounds);
@@ -634,14 +627,6 @@ QuantifiersEngine::Statistics::Statistics():
StatisticsRegistry::registerStat(&d_simple_triggers);
StatisticsRegistry::registerStat(&d_multi_triggers);
StatisticsRegistry::registerStat(&d_multi_trigger_instantiations);
- StatisticsRegistry::registerStat(&d_term_in_termdb);
- StatisticsRegistry::registerStat(&d_num_mono_candidates);
- StatisticsRegistry::registerStat(&d_num_mono_candidates_new_term);
- StatisticsRegistry::registerStat(&d_num_multi_candidates);
- StatisticsRegistry::registerStat(&d_mono_candidates_cache_hit);
- StatisticsRegistry::registerStat(&d_mono_candidates_cache_miss);
- StatisticsRegistry::registerStat(&d_multi_candidates_cache_hit);
- StatisticsRegistry::registerStat(&d_multi_candidates_cache_miss);
}
QuantifiersEngine::Statistics::~Statistics(){
@@ -657,14 +642,6 @@ QuantifiersEngine::Statistics::~Statistics(){
StatisticsRegistry::unregisterStat(&d_simple_triggers);
StatisticsRegistry::unregisterStat(&d_multi_triggers);
StatisticsRegistry::unregisterStat(&d_multi_trigger_instantiations);
- StatisticsRegistry::unregisterStat(&d_term_in_termdb);
- StatisticsRegistry::unregisterStat(&d_num_mono_candidates);
- StatisticsRegistry::unregisterStat(&d_num_mono_candidates_new_term);
- StatisticsRegistry::unregisterStat(&d_num_multi_candidates);
- StatisticsRegistry::unregisterStat(&d_mono_candidates_cache_hit);
- StatisticsRegistry::unregisterStat(&d_mono_candidates_cache_miss);
- StatisticsRegistry::unregisterStat(&d_multi_candidates_cache_hit);
- StatisticsRegistry::unregisterStat(&d_multi_candidates_cache_miss);
}
eq::EqualityEngine* QuantifiersEngine::getMasterEqualityEngine(){
diff --git a/src/theory/quantifiers_engine.h b/src/theory/quantifiers_engine.h
index fbc501aec..858093543 100644
--- a/src/theory/quantifiers_engine.h
+++ b/src/theory/quantifiers_engine.h
@@ -20,8 +20,8 @@
#include "theory/theory.h"
#include "util/hash.h"
#include "theory/quantifiers/inst_match.h"
-#include "theory/rewriterules/rr_inst_match.h"
#include "theory/quantifiers/quant_util.h"
+#include "expr/attribute.h"
#include "util/statistics_registry.h"
@@ -49,6 +49,8 @@ public:
virtual void finishInit() {}
/* whether this module needs to check this round */
virtual bool needsCheck( Theory::Effort e ) { return e>=Theory::EFFORT_LAST_CALL; }
+ /* reset at a round */
+ virtual void reset_round( Theory::Effort e ){}
/* Call during quantifier engine's check */
virtual void check( Theory::Effort e ) = 0;
/* Called for new quantifiers */
@@ -75,11 +77,7 @@ namespace inst {
class TriggerTrie;
}/* CVC4::theory::inst */
-namespace rrinst {
- class TriggerTrie;
-}/* CVC4::theory::inst */
-
-class EfficientEMatcher;
+//class EfficientEMatcher;
class EqualityQueryQuantifiersEngine;
class QuantifiersEngine {
@@ -102,8 +100,6 @@ private:
quantifiers::RelevantDomain* d_rel_dom;
/** phase requirements for each quantifier for each instantiation literal */
std::map< Node, QuantPhaseReq* > d_phase_reqs;
- /** efficient e-matcher */
- EfficientEMatcher* d_eem;
/** instantiation engine */
quantifiers::InstantiationEngine* d_inst_engine;
/** model engine */
@@ -131,8 +127,6 @@ private:
quantifiers::TermDb* d_term_db;
/** all triggers will be stored in this trie */
inst::TriggerTrie* d_tr_trie;
- /** all triggers for rewrite rules will be stored in this trie */
- rrinst::TriggerTrie* d_rr_tr_trie;
/** extended model object */
quantifiers::FirstOrderModel* d_model;
/** statistics for debugging */
@@ -144,8 +138,6 @@ private:
public:
QuantifiersEngine(context::Context* c, context::UserContext* u, TheoryEngine* te);
~QuantifiersEngine();
- /** get instantiator for id */
- //Instantiator* getInstantiator( theory::TheoryId id );
/** get theory engine */
TheoryEngine* getTheoryEngine() { return d_te; }
/** get equality query object for the given type. The default is the
@@ -171,8 +163,6 @@ public:
QuantPhaseReq* getPhaseRequirements( Node f ) { return d_phase_reqs.find( f )==d_phase_reqs.end() ? NULL : d_phase_reqs[f]; }
/** get phase requirement terms */
void getPhaseReqTerms( Node f, std::vector< Node >& nodes );
- /** get efficient e-matching utility */
- EfficientEMatcher* getEfficientEMatcher() { return d_eem; }
/** get bounded integers utility */
quantifiers::BoundedIntegers * getBoundedIntegers() { return d_bint; }
/** Conflict find mechanism for quantifiers */
@@ -199,8 +189,6 @@ private:
bool addInstantiation( Node f, std::vector< Node >& vars, std::vector< Node >& terms );
/** set instantiation level attr */
void setInstantiationLevelAttr( Node n, uint64_t level );
- /** do substitution */
- Node doSubstitute( Node n, std::vector< Node >& terms );
public:
/** get instantiation */
Node getInstantiation( Node f, std::vector< Node >& vars, std::vector< Node >& terms );
@@ -208,6 +196,8 @@ public:
Node getInstantiation( Node f, InstMatch& m );
/** get instantiation */
Node getInstantiation( Node f, std::vector< Node >& terms );
+ /** do substitution */
+ Node getSubstitute( Node n, std::vector< Node >& terms );
/** exist instantiation ? */
bool existsInstantiation( Node f, InstMatch& m, bool modEq = true, bool modInst = false );
/** add lemma lem */
@@ -238,8 +228,6 @@ public:
quantifiers::TermDb* getTermDatabase() { return d_term_db; }
/** get trigger database */
inst::TriggerTrie* getTriggerDatabase() { return d_tr_trie; }
- /** get rewrite trigger database */
- rrinst::TriggerTrie* getRRTriggerDatabase() { return d_rr_tr_trie; }
/** add term to database */
void addTermToDatabase( Node n, bool withinQuant = false );
/** get the master equality engine */
@@ -260,14 +248,6 @@ public:
IntStat d_simple_triggers;
IntStat d_multi_triggers;
IntStat d_multi_trigger_instantiations;
- IntStat d_term_in_termdb;
- IntStat d_num_mono_candidates;
- IntStat d_num_mono_candidates_new_term;
- IntStat d_num_multi_candidates;
- IntStat d_mono_candidates_cache_hit;
- IntStat d_mono_candidates_cache_miss;
- IntStat d_multi_candidates_cache_hit;
- IntStat d_multi_candidates_cache_miss;
Statistics();
~Statistics();
};/* class QuantifiersEngine::Statistics */
diff --git a/src/theory/rewriterules/efficient_e_matching.cpp b/src/theory/rewriterules/efficient_e_matching.cpp
deleted file mode 100644
index 05934fc8b..000000000
--- a/src/theory/rewriterules/efficient_e_matching.cpp
+++ /dev/null
@@ -1,680 +0,0 @@
-/********************* */
-/*! \file efficient_e_matching.cpp
- ** \verbatim
- ** Original author: Andrew Reynolds
- ** Major contributors: Morgan Deters
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Implementation of theory uf instantiator class
- **/
-
-#include "theory/rewriterules/efficient_e_matching.h"
-#include "theory/rewriterules/rr_candidate_generator.h"
-#include "theory/quantifiers/candidate_generator.h"
-#include "theory/quantifiers/options.h"
-#include "theory/rewriterules/options.h"
-#include "theory/quantifiers/term_database.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::inst;
-
-namespace CVC4 {
-namespace theory {
-
-inline std::ostream& operator<<(std::ostream& out, const EfficientEMatcher::Ips& ips) {
- return out;
-};
-
-EqClassInfo::EqClassInfo( context::Context* c ) : d_funs( c ), d_pfuns( c ), d_disequal( c ){
-
-}
-
-//set member
-void EqClassInfo::setMember( Node n, quantifiers::TermDb* db ){
- if( n.hasOperator() ){
- d_funs.insertAtContextLevelZero(n.getOperator(),true);
- }
- //add parent functions
- for( std::hash_map< Node, std::hash_map< int, std::vector< Node > >, NodeHashFunction >::iterator it = db->d_parents[n].begin();
- it != db->d_parents[n].end(); ++it ){
- //TODO Is it true to do it at level 0? That depend when SetMember is called
- // At worst it is a good overapproximation
- d_pfuns.insertAtContextLevelZero( it->first, true);
- }
-}
-
-//get has function
-bool EqClassInfo::hasFunction( Node op ){
- return d_funs.find( op )!=d_funs.end();
-}
-
-bool EqClassInfo::hasParent( Node op ){
- return d_pfuns.find( op )!=d_pfuns.end();
-}
-
-//merge with another eq class info
-void EqClassInfo::merge( EqClassInfo* eci ){
- for( BoolMap::iterator it = eci->d_funs.begin(); it != eci->d_funs.end(); it++ ) {
- d_funs[ (*it).first ] = true;
- }
- for( BoolMap::iterator it = eci->d_pfuns.begin(); it != eci->d_pfuns.end(); it++ ) {
- d_pfuns[ (*it).first ] = true;
- }
-}
-
-inline void outputEqClassInfo( const char* c, const EqClassInfo* eci){
- Debug(c) << " funs:";
- for( EqClassInfo::BoolMap::iterator it = eci->d_funs.begin(); it != eci->d_funs.end(); it++ ) {
- Debug(c) << (*it).first << ",";
- }
- Debug(c) << std::endl << "pfuns:";
- for( EqClassInfo::BoolMap::iterator it = eci->d_pfuns.begin(); it != eci->d_pfuns.end(); it++ ) {
- Debug(c) << (*it).first << ",";
- }
- Debug(c) << std::endl;
-}
-
-
-
-EfficientEMatcher::EfficientEMatcher( CVC4::theory::QuantifiersEngine* qe ) : d_quantEngine( qe )
-{
-
-}
-
-eq::EqualityEngine* EfficientEMatcher::getEqualityEngine(){
- //return ((uf::TheoryUF*)d_quantEngine->getTheoryEngine()->theoryOf( THEORY_UF ))->getEqualityEngine();
- return d_quantEngine->getMasterEqualityEngine();
-}
-
-/** new node */
-void EfficientEMatcher::newEqClass( TNode n ){
-
-}
-
-void EfficientEMatcher::newTerms(SetNode& s){
- static NoMatchAttribute rewrittenNodeAttribute;
- /* op -> nodes (if the set is empty, the op is not interesting) */
- std::hash_map< TNode, SetNode, TNodeHashFunction > h;
- /* types -> nodes (if the set is empty, the type is not interesting) */
- std::hash_map< TypeNode, SetNode, TypeNodeHashFunction > tyh;
- for(SetNode::iterator i=s.begin(), end=s.end(); i != end; ++i){
- if (i->getAttribute(rewrittenNodeAttribute)) continue; /* skip it */
- if( !d_cand_gens.empty() ){
- // op
- TNode op = i->getOperator();
- std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator
- is = h.find(op);
- if(is == h.end()){
- std::pair<std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator,bool>
- p = h.insert(make_pair(op,SetNode()));
- is = p.first;
- if(d_cand_gens.find(op) != d_cand_gens.end()){
- is->second.insert(*i);
- } /* else we have inserted an empty set */
- }else if(!is->second.empty()){
- is->second.insert(*i);
- }
- }
- if( !d_cand_gen_types.empty() ){
- //type
- TypeNode ty = i->getType();
- std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator
- is = tyh.find(ty);
- if(is == tyh.end()){
- std::pair<std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator,bool>
- p = tyh.insert(make_pair(ty,SetNode()));
- is = p.first;
- if(d_cand_gen_types.find(ty) != d_cand_gen_types.end()){
- is->second.insert(*i);
- } /* else we have inserted an empty set */
- }else if(!is->second.empty()){
- is->second.insert(*i);
- }
- }
- }
- //op
- for(std::hash_map< TNode, SetNode, TNodeHashFunction >::iterator i=h.begin(), end=h.end();
- i != end; ++i){
- //new term, add n to candidate generators
- if(i->second.empty()) continue;
- std::map< Node, NodeNewTermDispatcher >::iterator
- inpc = d_cand_gens.find(i->first);
- //we know that this op exists
- Assert(inpc != d_cand_gens.end());
- inpc->second.send(i->second);
- }
- //type
- for(std::hash_map< TypeNode, SetNode, TypeNodeHashFunction >::iterator i=tyh.begin(), end=tyh.end();
- i != end; ++i){
- //new term, add n to candidate generators
- if(i->second.empty()) continue;
- std::map< TypeNode, NodeNewTermDispatcher >::iterator
- inpc = d_cand_gen_types.find(i->first);
- //we know that this op exists
- Assert(inpc != d_cand_gen_types.end());
- inpc->second.send(i->second);
- }
-
-}
-
-
-/** merge */
-void EfficientEMatcher::merge( TNode a, TNode b ){
- if( options::efficientEMatching() ){
- //merge eqc_ops of b into a
- EqClassInfo* eci_a = getOrCreateEquivalenceClassInfo( a );
- EqClassInfo* eci_b = getOrCreateEquivalenceClassInfo( b );
-
- if( a.getKind()!=IFF && a.getKind()!=EQUAL && b.getKind()!=IFF && b.getKind()!=EQUAL ){
- Debug("efficient-e-match") << "Merging " << a << " with " << b << std::endl;
-
- //determine new candidates for instantiation
- computeCandidatesPcPairs( a, eci_a, b, eci_b );
- computeCandidatesPcPairs( b, eci_b, a, eci_a );
- computeCandidatesPpPairs( a, eci_a, b, eci_b );
- computeCandidatesPpPairs( b, eci_b, a, eci_a );
- }
- computeCandidatesConstants( a, eci_a, b, eci_b);
- computeCandidatesConstants( b, eci_b, a, eci_a);
-
- eci_a->merge( eci_b );
- }
-}
-
-/** assert terms are disequal */
-void EfficientEMatcher::assertDisequal( TNode a, TNode b, TNode reason ){
-
-}
-
-EqClassInfo* EfficientEMatcher::getEquivalenceClassInfo( Node n ) {
- return d_eqc_ops.find( n )==d_eqc_ops.end() ? NULL : d_eqc_ops[n];
-}
-EqClassInfo* EfficientEMatcher::getOrCreateEquivalenceClassInfo( Node n ){
- Assert( n==getEqualityEngine()->getRepresentative( n ) );
- if( d_eqc_ops.find( n )==d_eqc_ops.end() ){
- EqClassInfo* eci = new EqClassInfo( d_quantEngine->getSatContext() );
- eci->setMember( n, d_quantEngine->getTermDatabase() );
- d_eqc_ops[n] = eci;
- }
- return d_eqc_ops[n];
-}
-
-void EfficientEMatcher::computeCandidatesPcPairs( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){
- Debug("efficient-e-match") << "Compute candidates for pc pairs..." << std::endl;
- Debug("efficient-e-match") << " Eq class = [";
- outputEqClass( "efficient-e-match", a);
- Debug("efficient-e-match") << "]" << std::endl;
- outputEqClassInfo("efficient-e-match",eci_a);
- for( EqClassInfo::BoolMap::iterator it = eci_a->d_funs.begin(); it != eci_a->d_funs.end(); it++ ) {
- //the child function: a member of eq_class( a ) has top symbol g, in other words g is in funs( a )
- Node g = (*it).first;
- Debug("efficient-e-match") << " Checking application " << g << std::endl;
- //look at all parent/child pairs
- for( std::map< Node, std::vector< std::pair< NodePcDispatcher*, Ips > > >::iterator itf = d_pc_pairs[g].begin();
- itf != d_pc_pairs[g].end(); ++itf ){
- //f/g is a parent/child pair
- Node f = itf->first;
- if( eci_b->hasParent( f ) ){
- //DO_THIS: determine if f in pfuns( b ), only do the follow if so
- Debug("efficient-e-match") << " Checking parent application " << f << std::endl;
- //scan through the list of inverted path strings/candidate generators
- for( std::vector< std::pair< NodePcDispatcher*, Ips > >::iterator cit = itf->second.begin();
- cit != itf->second.end(); ++cit ){
-#ifdef CVC4_DEBUG
- Debug("efficient-e-match") << " Checking pattern " << cit->first->pat << std::endl;
-#endif
- Debug("efficient-e-match") << " Check inverted path string for pattern ";
- outputIps( "efficient-e-match", cit->second );
- Debug("efficient-e-match") << std::endl;
-
- //collect all new relevant terms
- SetNode terms;
- terms.insert( b );
- collectTermsIps( cit->second, terms );
- if( terms.empty() ) continue;
- Debug("efficient-e-match") << " -> Added terms (" << terms.size() << "): ";
- for( SetNode::const_iterator t=terms.begin(), end=terms.end();
- t!=end; ++t ){
- Debug("efficient-e-match") << (*t) << " ";
- }
- Debug("efficient-e-match") << std::endl;
- //add them as candidates to the candidate generator
- cit->first->send(terms);
- }
- }
- }
- }
-}
-
-void EfficientEMatcher::computeCandidatesPpPairs( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){
- Debug("efficient-e-match") << "Compute candidates for pp pairs..." << std::endl;
- for( std::map< Node, std::map< Node, std::vector< triple< NodePpDispatcher*, Ips, Ips > > > >::iterator it = d_pp_pairs.begin();
- it != d_pp_pairs.end(); ++it ){
- Node f = it->first;
- if( eci_a->hasParent( f ) ){
- Debug("efficient-e-match") << " Checking parent application " << f << std::endl;
- for( std::map< Node, std::vector< triple<NodePpDispatcher*, Ips, Ips> > >::iterator it2 = it->second.begin();
- it2 != it->second.end(); ++it2 ){
- Node g = it2->first;
- if( eci_b->hasParent( g ) ){
- Debug("efficient-e-match") << " Checking parent application " << g << std::endl;
- //if f in pfuns( a ) and g is in pfuns( b ), only do the follow if so
- for( std::vector< triple<NodePpDispatcher*, Ips, Ips> > ::iterator cit = it2->second.begin();
- cit != it2->second.end(); ++cit ){
-#ifdef CVC4_DEBUG
- Debug("efficient-e-match") << " Checking pattern " << cit->first->pat1 << " and " << cit->first->pat2 << std::endl;
-#endif
- Debug("efficient-e-match") << " Check inverted path string ";
- outputIps( "efficient-e-match", cit->second );
- SetNode a_terms;
- a_terms.insert( a );
- collectTermsIps( cit->second, a_terms );
- if( a_terms.empty() ) continue;
- Debug("efficient-e-match") << " And check inverted path string ";
- outputIps( "efficient-e-match", cit->third );
- SetNode b_terms;
- b_terms.insert( b );
- collectTermsIps( cit->third, b_terms );
- if( b_terms.empty() ) continue;
- //Start debug
- Debug("efficient-e-match") << " -> Possibly Added termsA (" << a_terms.size() << "): ";
- for( SetNode::const_iterator t=a_terms.begin(), end=a_terms.end();
- t!=end; ++t ){
- Debug("efficient-e-match") << (*t) << " ";
- }
- Debug("efficient-e-match") << std::endl;
- Debug("efficient-e-match") << " -> Possibly Added termsB (" << b_terms.size() << "): ";
- for( SetNode::const_iterator t=b_terms.begin(), end=b_terms.end();
- t!=end; ++t ){
- Debug("efficient-e-match") << (*t) << " ";
- }
- Debug("efficient-e-match") << std::endl;
- //End debug
-
- cit->first->send(a_terms,b_terms);
- }
- }
- }
- }
- }
-}
-
-
-void EfficientEMatcher::computeCandidatesConstants( Node a, EqClassInfo* eci_a, Node b, EqClassInfo* eci_b ){
- Debug("efficient-e-match") << "Compute candidates constants for cc pairs..." << std::endl;
- Debug("efficient-e-match") << " Eq class = [";
- outputEqClass( "efficient-e-match", a);
- Debug("efficient-e-match") << "]" << std::endl;
- outputEqClassInfo("efficient-e-match",eci_a);
- for( std::map< Node, std::map< Node, NodePcDispatcher* > >::iterator
- it = d_cc_pairs.begin(), end = d_cc_pairs.end();
- it != end; ++it ) {
- Debug("efficient-e-match") << " Checking application " << it->first << std::endl;
- if( !eci_b->hasFunction(it->first) ) continue;
- for( std::map< Node, NodePcDispatcher* >::iterator
- itc = it->second.begin(), end = it->second.end();
- itc != end; ++itc ) {
- //The constant
- Debug("efficient-e-match") << " Checking constant " << a << std::endl;
- if(getEqualityEngine()->getRepresentative(itc->first) != a) continue;
- SetNode s;
- eq::EqClassIterator eqc_iter( b, getEqualityEngine() );
- while( !eqc_iter.isFinished() ){
- Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter)
- << std::endl;
- if( (*eqc_iter).hasOperator() && (*eqc_iter).getOperator() == it->first ) s.insert(*eqc_iter);
- eqc_iter++;
- }
-
- if( s.empty() ) continue;
- Debug("efficient-e-match") << " -> Added terms (" << s.size() << "): ";
- for( SetNode::const_iterator t=s.begin(), end=s.end();
- t!=end; ++t ){
- Debug("efficient-e-match") << (*t) << " ";
- }
- Debug("efficient-e-match") << std::endl;
- itc->second->send(s);
- }
- }
-}
-
-void EfficientEMatcher::collectTermsIps( Ips& ips, SetNode & terms ){
- Assert( ips.size() > 0);
- return collectTermsIps( ips, terms, ips.size() - 1);
-}
-
-void EfficientEMatcher::collectTermsIps( Ips& ips, SetNode& terms, int index ){
- if( !terms.empty() ){
- Debug("efficient-e-match-debug") << "> Process " << index << std::endl;
- Node f = ips[index].first;
- int arg = ips[index].second;
-
- //for each term in terms, determine if any term (modulo equality) has parent "f" from position "arg"
- bool addRep = ( index!=0 ); // We want to keep the top symbol for the last
- SetNode newTerms;
- for( SetNode::const_iterator t=terms.begin(), end=terms.end();
- t!=end; ++t ){
- collectParentsTermsIps( *t, f, arg, newTerms, addRep );
- }
- terms.swap(newTerms);
-
- Debug("efficient-e-match-debug") << "> Terms are now: ";
- for( SetNode::const_iterator t=terms.begin(), end=terms.end();
- t!=end; ++t ){
- Debug("efficient-e-match-debug") << *t << " ";
- }
- Debug("efficient-e-match-debug") << std::endl;
-
- if(index!=0) collectTermsIps( ips, terms, index-1 );
- }
-}
-
-bool EfficientEMatcher::collectParentsTermsIps( Node n, Node f, int arg, SetNode & terms, bool addRep, bool modEq ){ //modEq default true
- bool addedTerm = false;
-
- if( modEq && getEqualityEngine()->hasTerm( n )){
- Assert( getEqualityEngine()->getRepresentative( n )==n );
- //collect modulo equality
- //DO_THIS: this should (if necessary) compute a current set of (f, arg) parents for n and cache it
- eq::EqClassIterator eqc_iter( n, getEqualityEngine() );
- while( !eqc_iter.isFinished() ){
- Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter)
- << std::endl;
- if( collectParentsTermsIps( (*eqc_iter), f, arg, terms, addRep, false ) ){
- //if only one argument, we know we can stop (since all others added will be congruent)
- if( f.getType().getNumChildren()==2 ){
- return true;
- }
- addedTerm = true;
- }
- eqc_iter++;
- }
- }else{
- quantifiers::TermDb* db = d_quantEngine->getTermDatabase();
- //see if parent f exists from argument arg
- const std::vector<Node> & parents = db->getParents(n,f,arg);
- for( size_t i=0; i<parents.size(); ++i ){
- TNode t = parents[i];
- if(!CandidateGenerator::isLegalCandidate(t)) continue;
- if( addRep ) t = getEqualityEngine()->getRepresentative( t );
- terms.insert(t);
- addedTerm = true;
- }
- }
- return addedTerm;
-}
-
-void EfficientEMatcher::registerPatternElementPairs2( Node pat, Ips& ips, PpIpsMap & pp_ips_map, NodePcDispatcher* npc ){
- Assert( pat.hasOperator() );
- //add information for possible pp-pair
- ips.push_back( std::pair< Node, int >( pat.getOperator(), 0 ) ); //0 is just a dumb value
-
- for( int i=0; i<(int)pat.getNumChildren(); i++ ){
- if( pat[i].getKind()==INST_CONSTANT ){
- ips.back().second = i;
- pp_ips_map[ pat[i] ].push_back( make_pair( pat.getOperator(), Ips( ips ) ) );
- }
- }
-
- for( int i=0; i<(int)pat.getNumChildren(); i++ ){
- if( pat[i].getKind()==APPLY_UF ){
- ips.back().second = i;
- registerPatternElementPairs2( pat[i], ips, pp_ips_map, npc );
- Debug("pattern-element-opt") << "Found pc-pair ( " << pat.getOperator() << ", " << pat[i].getOperator() << " )" << std::endl;
- Debug("pattern-element-opt") << " Path = ";
- outputIps( "pattern-element-opt", ips );
- Debug("pattern-element-opt") << std::endl;
- //pat.getOperator() and pat[i].getOperator() are a pc-pair
- d_pc_pairs[ pat[i].getOperator() ][ pat.getOperator() ]
- .push_back( make_pair(npc,Ips(ips)) );
- }
- }
- ips.pop_back();
-}
-
-void EfficientEMatcher::registerPatternElementPairs( Node pat, PpIpsMap & pp_ips_map,
- NodePcDispatcher* npc,
- NodePpDispatcher* npp){
- Ips ips;
- registerPatternElementPairs2( pat, ips, pp_ips_map, npc );
- for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){
- // for each variable construct all the pp-pair
- for( size_t j=0; j<it->second.size(); j++ ){
- for( size_t k=j+1; k<it->second.size(); k++ ){
- //found a pp-pair
- Debug("pattern-element-opt") << "Found pp-pair ( " << it->second[j].first << ", " << it->second[k].first << " )" << std::endl;
- Debug("pattern-element-opt") << " Paths = ";
- outputIps( "pattern-element-opt", it->second[j].second );
- Debug("pattern-element-opt") << " and ";
- outputIps( "pattern-element-opt", it->second[k].second );
- Debug("pattern-element-opt") << std::endl;
- d_pp_pairs[ it->second[j].first ][ it->second[k].first ]
- .push_back( make_triple( npp, it->second[j].second, it->second[k].second ));
- }
- }
- }
-};
-
-void findPpSite(Node pat, EfficientEMatcher::Ips& ips, EfficientEMatcher::PpIpsMap & pp_ips_map){
- Assert( pat.getKind()==APPLY_UF );
- //add information for possible pp-pair
-
- ips.push_back( make_pair( pat.getOperator(), 0) );
- for( size_t i=0; i<pat.getNumChildren(); i++ ){
- if( pat[i].getKind()==INST_CONSTANT ){
- ips.back().second = i;
- pp_ips_map[ pat[i] ].push_back( make_pair( pat.getOperator(), EfficientEMatcher::Ips( ips ) ) );
- }
- }
-
- for( size_t i=0; i<pat.getNumChildren(); i++ ){
- if( pat[i].getKind()==APPLY_UF ){
- ips.back().second = i;
- findPpSite( pat[i], ips, pp_ips_map );
- }
- }
- ips.pop_back();
-}
-
-void EfficientEMatcher::combineMultiPpIpsMap(PpIpsMap & pp_ips_map, MultiPpIpsMap & multi_pp_ips_map,
- EfficientHandler& eh, size_t index2,const std::vector<Node> & pats){
- hash_map<size_t,NodePpDispatcher*> npps;
- for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){
- MultiPpIpsMap::iterator mit = multi_pp_ips_map.find(it->first);
- if(mit == multi_pp_ips_map.end()) continue;
- // for each variable construct all the pp-pair
- // j the last pattern treated
- for( std::vector< std::pair< Node, Ips > >::iterator j=it->second.begin(), jend = it->second.end() ;
- j != jend; ++j){
- // k one of the previous one
- for( std::vector< triple< size_t, Node, Ips > >::iterator k=mit->second.begin(), kend = mit->second.end() ;
- k != kend; ++k){
- //found a pp-pair
- Debug("pattern-element-opt") << "Found multi-pp-pair ( " << j->first
- << ", " << k->second << " in "<< k->first
- << " )" << std::endl;
- Debug("pattern-element-opt") << " Paths = ";
- outputIps( "pattern-element-opt", j->second );
- Debug("pattern-element-opt") << " and ";
- outputIps( "pattern-element-opt", k->third );
- Debug("pattern-element-opt") << std::endl;
- NodePpDispatcher* dispatcher;
- hash_map<size_t,NodePpDispatcher*>::iterator inpp = npps.find(k->first);
- if( inpp != npps.end() ) dispatcher = inpp->second;
- else{
- dispatcher = new NodePpDispatcher();
-#ifdef CVC4_DEBUG
- dispatcher->pat1 = pats[index2];
- dispatcher->pat2 = pats[k->first];
-#endif
- dispatcher->addPpDispatcher(&eh,index2,k->first);
- };
- d_pp_pairs[ j->first ][ k->second ].push_back( make_triple( dispatcher, j->second, k->third ));
- }
- }
- }
-
- /** Put pp_ips_map to multi_pp_ips_map */
- for( PpIpsMap::iterator it = pp_ips_map.begin(); it != pp_ips_map.end(); ++it ){
- for( std::vector< std::pair< Node, Ips > >::iterator j=it->second.begin(), jend = it->second.end() ;
- j != jend; ++j){
- multi_pp_ips_map[it->first].push_back(make_triple(index2, j->first, j->second));
- }
- }
-
-}
-
-
-void EfficientEMatcher::registerEfficientHandler( EfficientHandler& handler,
- const std::vector< Node > & pats ){
- Assert(pats.size() > 0);
-
- MultiPpIpsMap multi_pp_ips_map;
- PpIpsMap pp_ips_map;
- //In a multi-pattern Pattern that is only a variable are specials,
- //if the variable appears in another pattern, it can be discarded.
- //Otherwise new term of this term can be candidate. So we stock them
- //here before adding them.
- std::vector< size_t > patVars;
-
- Debug("pattern-element-opt") << "Register patterns" << pats << std::endl;
- for(size_t i = 0; i < pats.size(); ++i){
- if( pats[i].getKind() == kind::INST_CONSTANT){
- patVars.push_back(i);
- continue;
- }
- //to complete
- if( pats[i].getKind() == kind::NOT && pats[i][0].getKind() == kind::EQUAL){
- Node cst = NodeManager::currentNM()->mkConst<bool>(false);
- TNode op = pats[i][0].getOperator();
- if(d_cc_pairs[op][cst] == NULL){
- d_cc_pairs[op][cst] = new NodePcDispatcher();
- }
- d_cc_pairs[op][cst]->addPcDispatcher(&handler,i);
- continue;
- }
- //end to complete
- Debug("pattern-element-opt") << " Register candidate generator..." << pats[i] << std::endl;
- /* Has the pattern already been seen */
- if( d_pat_cand_gens.find( pats[i] )==d_pat_cand_gens.end() ){
- NodePcDispatcher* npc = new NodePcDispatcher();
- NodePpDispatcher* npp = new NodePpDispatcher();
-#ifdef CVC4_DEBUG
- npc->pat = pats[i];
- npp->pat1 = pats[i];
- npp->pat2 = pats[i];
-#endif
- d_pat_cand_gens[pats[i]] = make_pair(npc,npp);
- registerPatternElementPairs( pats[i], pp_ips_map, npc, npp );
- }else{
- Ips ips;
- findPpSite(pats[i],ips,pp_ips_map);
- }
- //Has the top operator already been seen */
- TNode op = pats[i].getOperator();
- d_pat_cand_gens[pats[i]].first->addPcDispatcher(&handler,i);
- d_pat_cand_gens[pats[i]].second->addPpDispatcher(&handler,i,i);
- d_cand_gens[op].addNewTermDispatcher(&handler,i);
-
- combineMultiPpIpsMap(pp_ips_map,multi_pp_ips_map,handler,i,pats);
-
- pp_ips_map.clear();
- }
-
- for(size_t i = 0; i < patVars.size(); ++i){
- TNode var = pats[patVars[i]];
- Assert( var.getKind() == kind::INST_CONSTANT );
- if( multi_pp_ips_map.find(var) != multi_pp_ips_map.end() ){
- //The variable appear in another pattern, skip it
- continue;
- };
- d_cand_gen_types[var.getType()].addNewTermDispatcher(&handler,patVars[i]);
- }
-
- //take all terms from the uf term db and add to candidate generator
- if( pats[0].getKind() == kind::INST_CONSTANT ){
- TypeNode ty = pats[0].getType();
- rrinst::CandidateGenerator* cg = new GenericCandidateGeneratorClasses(d_quantEngine);
- cg->reset(Node::null());
- TNode c;
- SetNode ele;
- while( !(c = cg->getNextCandidate()).isNull() ){
- if( c.getType() == ty ) ele.insert(c);
- }
- if( !ele.empty() ){
- if(Debug.isOn("efficient-e-match-stats")){
- Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl;
- }
- handler.addMonoCandidate(ele, 0);
- }
-
- } else if( pats[0].getKind() == kind::NOT && pats[0][0].getKind() == kind::EQUAL){
- Node cst = NodeManager::currentNM()->mkConst<bool>(false);
- TNode op = pats[0][0].getOperator();
- cst = getEqualityEngine()->getRepresentative(cst);
- SetNode ele;
- eq::EqClassIterator eqc_iter( cst, getEqualityEngine() );
- while( !eqc_iter.isFinished() ){
- Debug("efficient-e-match-debug") << "> look at " << (*eqc_iter)
- << std::endl;
- if( (*eqc_iter).hasOperator() && (*eqc_iter).getOperator() == op ) ele.insert(*eqc_iter);
- eqc_iter++;
- }
- if( !ele.empty() ){
- if(Debug.isOn("efficient-e-match-stats")){
- Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl;
- }
- handler.addMonoCandidate(ele, 0);
- }
-
- } else {
- TermDb* db = d_quantEngine->getTermDatabase();
- Node op = db->getOperator( pats[0] );
- if(db->d_op_map[op].begin() != db->d_op_map[op].end()){
- SetNode ele;
- ele.insert(db->d_op_map[op].begin(), db->d_op_map[op].end());
- if(Debug.isOn("efficient-e-match-stats")){
- Debug("efficient-e-match-stats") << "pattern " << pats << " initialized with " << ele.size() << " terms"<< std::endl;
- }
- handler.addMonoCandidate(ele, 0);
- }
- }
- Debug("efficient-e-match") << "Done." << std::endl;
-}
-
-void EfficientEMatcher::outputEqClass( const char* c, Node n ){
- if( getEqualityEngine()->hasTerm( n ) ){
- eq::EqClassIterator eqc_iter( getEqualityEngine()->getRepresentative( n ),
- getEqualityEngine() );
- bool firstTime = true;
- while( !eqc_iter.isFinished() ){
- if( !firstTime ){ Debug(c) << ", "; }
- Debug(c) << (*eqc_iter);
- firstTime = false;
- eqc_iter++;
- }
- }else{
- Debug(c) << n;
- }
-}
-
-void EfficientEMatcher::outputIps( const char* c, Ips& ips ){
- for( int i=0; i<(int)ips.size(); i++ ){
- if( i>0 ){ Debug( c ) << "."; }
- Debug( c ) << ips[i].first << "." << ips[i].second;
- }
-}
-
-
-} /* namespace theory */
-} /* namespace cvc4 */
diff --git a/src/theory/rewriterules/efficient_e_matching.h b/src/theory/rewriterules/efficient_e_matching.h
deleted file mode 100644
index b02d465fc..000000000
--- a/src/theory/rewriterules/efficient_e_matching.h
+++ /dev/null
@@ -1,450 +0,0 @@
-/********************* */
-/*! \file efficient_e_matching.h
- ** \verbatim
- ** Original author: Andrew Reynolds
- ** Major contributors: Morgan Deters
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief efficient e-matching
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__EFFICIENT_E_MATCHING_H
-#define __CVC4__EFFICIENT_E_MATCHING_H
-
-#include "expr/node.h"
-#include "context/context.h"
-#include "context/context_mm.h"
-#include "context/cdchunk_list.h"
-
-#include "util/statistics_registry.h"
-#include "util/ntuple.h"
-#include "context/cdqueue.h"
-#include "context/cdo.h"
-
-#include "theory/uf/equality_engine.h"
-
-namespace CVC4 {
-namespace theory {
-
-class QuantifiersEngine;
-
-namespace quantifiers{
- class TermDb;
-}
-
-class EfficientEMatcher;
-class HandlerPcDispatcher;
-class HandlerPpDispatcher;
-
-typedef std::set<Node> SetNode;
-
-template<class T>
-class CleanUpPointer{
-public:
- inline void operator()(T** e){
- delete(*e);
- };
-};
-
-class EfficientHandler{
-public:
- typedef std::pair< Node, size_t > MonoCandidate;
- typedef std::pair< MonoCandidate, MonoCandidate > MultiCandidate;
- typedef std::pair< SetNode, size_t > MonoCandidates;
- typedef std::pair< MonoCandidates, MonoCandidates > MultiCandidates;
-private:
- /* Queue of candidates */
- typedef context::CDQueue< MonoCandidates *, CleanUpPointer<MonoCandidates> > MonoCandidatesQueue;
- typedef context::CDQueue< MultiCandidates *, CleanUpPointer<MultiCandidates> > MultiCandidatesQueue;
- MonoCandidatesQueue d_monoCandidates;
- typedef SetNode::iterator SetNodeIter;
- context::CDO<SetNodeIter> d_si;
- context::CDO<bool> d_mono_not_first;
-
- MonoCandidatesQueue d_monoCandidatesNewTerm;
- context::CDO<SetNodeIter> d_si_new_term;
- context::CDO<bool> d_mono_not_first_new_term;
-
-
- MultiCandidatesQueue d_multiCandidates;
- context::CDO<SetNodeIter> d_si1;
- context::CDO<SetNodeIter> d_si2;
- context::CDO<bool> d_multi_not_first;
-
-
- friend class EfficientEMatcher;
- friend class HandlerPcDispatcher;
- friend class HandlerPpDispatcher;
- friend class HandlerNewTermDispatcher;
-protected:
- void addMonoCandidate(SetNode & s, size_t index){
- Assert(!s.empty());
- d_monoCandidates.push(new MonoCandidates(s,index));
- }
- void addMonoCandidateNewTerm(SetNode & s, size_t index){
- Assert(!s.empty());
- d_monoCandidatesNewTerm.push(new MonoCandidates(s,index));
- }
- void addMultiCandidate(SetNode & s1, size_t index1, SetNode & s2, size_t index2){
- Assert(!s1.empty() && !s2.empty());
- d_multiCandidates.push(new MultiCandidates(MonoCandidates(s1,index1),
- MonoCandidates(s2,index2)));
- }
-public:
- EfficientHandler(context::Context * c):
- //false for d_mono_not_first beacause its the default constructor
- d_monoCandidates(c), d_si(c), d_mono_not_first(c,false),
- d_monoCandidatesNewTerm(c), d_si_new_term(c),
- d_mono_not_first_new_term(c,false),
- d_multiCandidates(c) , d_si1(c), d_si2(c), d_multi_not_first(c,false) {};
-
- bool getNextMonoCandidate(MonoCandidate & candidate){
- if(d_monoCandidates.empty()) return false;
- const MonoCandidates * front = d_monoCandidates.front();
- SetNodeIter si_tmp;
- if(!d_mono_not_first){
- Assert(front->first.begin() != front->first.end());
- d_mono_not_first = true;
- si_tmp=front->first.begin();
- }else{
- si_tmp = d_si;
- ++si_tmp;
- };
- if(si_tmp != front->first.end()){
- candidate.first = (*si_tmp);
- candidate.second = front->second;
- d_si = si_tmp;
- Debug("efficienthandler") << "Mono produces " << candidate.first << " for " << candidate.second << std::endl;
- return true;
- };
- d_monoCandidates.pop();
- d_mono_not_first = false;
- return getNextMonoCandidate(candidate);
- };
-
- bool getNextMonoCandidateNewTerm(MonoCandidate & candidate){
- if(d_monoCandidatesNewTerm.empty()) return false;
- const MonoCandidates * front = d_monoCandidatesNewTerm.front();
- SetNodeIter si_tmp;
- if(!d_mono_not_first_new_term){
- Assert(front->first.begin() != front->first.end());
- d_mono_not_first_new_term = true;
- si_tmp=front->first.begin();
- }else{
- si_tmp = d_si_new_term;
- ++si_tmp;
- };
- if(si_tmp != front->first.end()){
- candidate.first = (*si_tmp);
- candidate.second = front->second;
- d_si_new_term = si_tmp;
- Debug("efficienthandler") << "Mono produces " << candidate.first << " for " << candidate.second << std::endl;
- return true;
- };
- d_monoCandidatesNewTerm.pop();
- d_mono_not_first_new_term = false;
- return getNextMonoCandidateNewTerm(candidate);
- };
-
- bool getNextMultiCandidate(MultiCandidate & candidate){
- if(d_multiCandidates.empty()) return false;
- const MultiCandidates* front = d_multiCandidates.front();
- SetNodeIter si1_tmp;
- SetNodeIter si2_tmp;
- if(!d_multi_not_first){
- Assert(front->first.first.begin() != front->first.first.end());
- Assert(front->second.first.begin() != front->second.first.end());
- si1_tmp = front->first.first.begin();
- si2_tmp = front->second.first.begin();
- }else{
- si1_tmp = d_si1;
- si2_tmp = d_si2;
- ++si2_tmp;
- };
- if(si2_tmp != front->second.first.end()){
- candidate.first.first = *si1_tmp;
- candidate.first.second = front->first.second;
- candidate.second.first = *si2_tmp;
- candidate.second.second = front->second.second;
- if(!d_multi_not_first){d_si1 = si1_tmp; d_multi_not_first = true; };
- d_si2 = si2_tmp;
- Debug("efficienthandler") << "Multi1 produces "
- << candidate.first.first << " for "
- << candidate.first.second << " and "
- << candidate.second.first << " for "
- << candidate.second.second << " and "
- << std::endl;
- return true;
- }; // end of the second set
- si2_tmp = front->second.first.begin();
- ++si1_tmp;
- if(si1_tmp != front->first.first.end()){
- candidate.first.first = *si1_tmp;
- candidate.first.second = front->first.second;
- candidate.second.first = *si2_tmp;
- candidate.second.second = front->second.second;
- d_si1 = si1_tmp;
- d_si2 = si2_tmp;
- Debug("efficienthandler") << "Multi2 produces "
- << candidate.first.first << " for "
- << candidate.first.second << " and "
- << candidate.second.first << " for "
- << candidate.second.second << " and "
- << std::endl;
- return true;
- }; // end of the first set
- d_multiCandidates.pop();
- d_multi_not_first = false;
- return getNextMultiCandidate(candidate);
- }
-};
-
-class PcDispatcher{
-public:
- virtual ~PcDispatcher(){};
- /* Send the node to the dispatcher */
- virtual void send(SetNode & s) = 0;
-};
-
-
-class HandlerPcDispatcher: public PcDispatcher{
- EfficientHandler* d_handler;
- size_t d_index;
-public:
- HandlerPcDispatcher(EfficientHandler* handler, size_t index):
- d_handler(handler), d_index(index) {};
- void send(SetNode & s){
- d_handler->addMonoCandidate(s,d_index);
- }
-};
-
-
-/** All the dispatcher that correspond to this node */
-class NodePcDispatcher: public PcDispatcher{
-#ifdef CVC4_DEBUG
-public:
- Node pat;
-#endif/* CVC4_DEBUG*/
-private:
- std::vector<HandlerPcDispatcher> d_dis;
-public:
- void send(SetNode & s){
- Assert(!s.empty());
- for(std::vector<HandlerPcDispatcher>::iterator i = d_dis.begin(), end = d_dis.end();
- i != end; ++i){
- (*i).send(s);
- }
- }
- void addPcDispatcher(EfficientHandler* handler, size_t index){
- d_dis.push_back(HandlerPcDispatcher(handler,index));
- }
-};
-
-
-class HandlerNewTermDispatcher: public PcDispatcher{
- EfficientHandler* d_handler;
- size_t d_index;
-public:
- HandlerNewTermDispatcher(EfficientHandler* handler, size_t index):
- d_handler(handler), d_index(index) {};
- void send(SetNode & s){
- d_handler->addMonoCandidateNewTerm(s,d_index);
- }
-};
-
-/** All the dispatcher that correspond to this node */
-class NodeNewTermDispatcher: public PcDispatcher{
-#ifdef CVC4_DEBUG
-public:
- Node pat;
-#endif/* CVC4_DEBUG*/
-private:
- std::vector<HandlerNewTermDispatcher> d_dis;
-public:
- void send(SetNode & s){
- Assert(!s.empty());
- for(std::vector<HandlerNewTermDispatcher>::iterator i = d_dis.begin(), end = d_dis.end();
- i != end; ++i){
- (*i).send(s);
- }
- }
- void addNewTermDispatcher(EfficientHandler* handler, size_t index){
- d_dis.push_back(HandlerNewTermDispatcher(handler,index));
- }
-};
-
-class PpDispatcher{
-public:
- virtual ~PpDispatcher(){};
- /* Send the node to the dispatcher */
- virtual void send(SetNode & s1, SetNode & s2, SetNode & sinter) = 0;
-};
-
-
-class HandlerPpDispatcher: public PpDispatcher{
- EfficientHandler* d_handler;
- size_t d_index1;
- size_t d_index2;
-public:
- HandlerPpDispatcher(EfficientHandler* handler, size_t index1, size_t index2):
- d_handler(handler), d_index1(index1), d_index2(index2) {};
- void send(SetNode & s1, SetNode & s2, SetNode & sinter){
- if(d_index1 == d_index2){
- if(!sinter.empty())
- d_handler->addMonoCandidate(sinter,d_index1);
- }else{
- d_handler->addMultiCandidate(s1,d_index1,s2,d_index2);
- }
- }
-};
-
-
-/** All the dispatcher that correspond to this node */
-class NodePpDispatcher: public PpDispatcher{
-#ifdef CVC4_DEBUG
-public:
- Node pat1;
- Node pat2;
-#endif/* CVC4_DEBUG */
-private:
- std::vector<HandlerPpDispatcher> d_dis;
- void send(SetNode & s1, SetNode & s2, SetNode & inter){
- for(std::vector<HandlerPpDispatcher>::iterator i = d_dis.begin(), end = d_dis.end();
- i != end; ++i){
- (*i).send(s1,s2,inter);
- }
- }
-public:
- void send(SetNode & s1, SetNode & s2){
- // can be done in HandlerPpDispatcher lazily
- Assert(!s1.empty() && !s2.empty());
- SetNode inter;
- std::set_intersection( s1.begin(), s1.end(), s2.begin(), s2.end(),
- std::inserter( inter, inter.begin() ) );
- send(s1,s2,inter);
- }
- void addPpDispatcher(EfficientHandler* handler, size_t index1, size_t index2){
- d_dis.push_back(HandlerPpDispatcher(handler,index1,index2));
- }
-};
-
-//equivalence class info
-class EqClassInfo
-{
-public:
- typedef context::CDHashMap<Node, bool, NodeHashFunction> BoolMap;
- typedef context::CDChunkList<Node> NodeList;
-public:
- //a list of operators that occur as top symbols in this equivalence class
- // Efficient E-Matching for SMT Solvers: "funs"
- BoolMap d_funs;
- //a list of operators f for which a term of the form f( ... t ... ) exists
- // Efficient E-Matching for SMT Solvers: "pfuns"
- BoolMap d_pfuns;
- //a list of equivalence classes that are disequal
- BoolMap d_disequal;
-public:
- EqClassInfo( context::Context* c );
- ~EqClassInfo(){}
- //set member
- void setMember( Node n, quantifiers::TermDb* db );
- //has function "funs"
- bool hasFunction( Node op );
- //has parent "pfuns"
- bool hasParent( Node op );
- //merge with another eq class info
- void merge( EqClassInfo* eci );
-};
-
-class EfficientEMatcher{
-protected:
- /** reference to the quantifiers engine */
- QuantifiersEngine* d_quantEngine;
-public:
- EfficientEMatcher(CVC4::theory::QuantifiersEngine* qe);
- ~EfficientEMatcher() {
- for(std::map< Node, std::pair<NodePcDispatcher*, NodePpDispatcher*> >::iterator
- i = d_pat_cand_gens.begin(), end = d_pat_cand_gens.end();
- i != end; i++){
- delete(i->second.first);
- delete(i->second.second);
- }
- }
- /** get equality engine we are using */
- eq::EqualityEngine* getEqualityEngine();
-private:
- //information for each equivalence class
- std::map< Node, EqClassInfo* > d_eqc_ops;
-public:
- /** new node */
- void newEqClass( TNode n );
- /** merge */
- void merge( TNode a, TNode b );
- /** assert terms are disequal */
- void assertDisequal( TNode a, TNode b, TNode reason );
- /** get equivalence class info */
- EqClassInfo* getEquivalenceClassInfo( Node n );
- EqClassInfo* getOrCreateEquivalenceClassInfo( Node n );
- typedef std::vector< std::pair< Node, int > > Ips;
- typedef std::map< Node, std::vector< std::pair< Node, Ips > > > PpIpsMap;
- typedef std::map< Node, std::vector< triple< size_t, Node, Ips > > > MultiPpIpsMap;
-private:
- /** Parent/Child Pairs (for efficient E-matching)
- So, for example, if we have the pattern f( g( x ) ), then d_pc_pairs[g][f][f( g( x ) )] = { f.0 }.
- */
- std::map< Node, std::map< Node, std::vector< std::pair< NodePcDispatcher*, Ips > > > > d_pc_pairs;
- /** Parent/Parent Pairs (for efficient E-matching) */
- std::map< Node, std::map< Node, std::vector< triple< NodePpDispatcher*, Ips, Ips > > > > d_pp_pairs;
- /** Constants/Child Pairs
- So, for example, if we have the pattern f( x ) = c, then d_pc_pairs[f][c] = ..., pcdispatcher, ...
- */
- //TODO constant in pattern can use the same thing just add an Ips
- std::map< Node, std::map< Node, NodePcDispatcher* > > d_cc_pairs;
- /** list of all candidate generators for each operator */
- std::map< Node, NodeNewTermDispatcher > d_cand_gens;
- /** list of all candidate generators for each type */
- std::map< TypeNode, NodeNewTermDispatcher > d_cand_gen_types;
- /** map from patterns to candidate generators */
- std::map< Node, std::pair<NodePcDispatcher*, NodePpDispatcher*> > d_pat_cand_gens;
- /** helper functions */
- void registerPatternElementPairs2( Node pat, Ips& ips,
- PpIpsMap & pp_ips_map, NodePcDispatcher* npc);
- void registerPatternElementPairs( Node pat, PpIpsMap & pp_ips_map,
- NodePcDispatcher* npc, NodePpDispatcher* npp);
- /** find the pp-pair between pattern inside multi-pattern*/
- void combineMultiPpIpsMap(PpIpsMap & pp_ips_map, MultiPpIpsMap & multi_pp_ips_map,
- EfficientHandler& eh, size_t index2,
- const std::vector<Node> & pats); //pats for debug
- /** compute candidates for pc pairs */
- void computeCandidatesPcPairs( Node a, EqClassInfo*, Node b, EqClassInfo* );
- /** compute candidates for pp pairs */
- void computeCandidatesPpPairs( Node a, EqClassInfo*, Node b, EqClassInfo* );
- /** compute candidates for cc pairs */
- void computeCandidatesConstants( Node a, EqClassInfo*, Node b, EqClassInfo* );
- /** collect terms based on inverted path string */
- void collectTermsIps( Ips& ips, SetNode& terms, int index);
- bool collectParentsTermsIps( Node n, Node f, int arg, SetNode& terms, bool addRep, bool modEq = true );
-public:
- void collectTermsIps( Ips& ips, SetNode& terms);
-public:
- void registerEfficientHandler( EfficientHandler& eh, const std::vector<Node> & pat );
-public:
- void newTerms(SetNode& s);
-public:
- /** output eq class */
- void outputEqClass( const char* c, Node n );
- /** output inverted path string */
- void outputIps( const char* c, Ips& ips );
-};/* class EfficientEMatcher */
-
-
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__EFFICIENT_E_MATCHING_H */
diff --git a/src/theory/rewriterules/kinds b/src/theory/rewriterules/kinds
deleted file mode 100644
index 490c8f100..000000000
--- a/src/theory/rewriterules/kinds
+++ /dev/null
@@ -1,37 +0,0 @@
-# kinds -*- sh -*-
-#
-# For documentation on this file format, please refer to
-# src/theory/builtin/kinds.
-#
-
-theory THEORY_REWRITERULES ::CVC4::theory::rewriterules::TheoryRewriteRules "theory/rewriterules/theory_rewriterules.h"
-typechecker "theory/rewriterules/theory_rewriterules_type_rules.h"
-rewriter ::CVC4::theory::rewriterules::TheoryRewriterulesRewriter "theory/rewriterules/theory_rewriterules_rewriter.h"
-
-properties check
-
-# Theory content goes here.
-
-# constants...
-
-# types...
-sort RRHB_TYPE \
- Cardinality::INTEGERS \
- not-well-founded \
- "head and body of the rule type"
-
-# operators...
-
-# variables, guards, RR_REWRITE/REDUCTION_RULE/DEDUCTION_RULE
-operator REWRITE_RULE 3 "general rewrite rule"
-#HEAD/BODY/TRIGGER
-operator RR_REWRITE 2:3 "actual rewrite rule"
-operator RR_REDUCTION 2:3 "actual reduction rule"
-operator RR_DEDUCTION 2:3 "actual deduction rule"
-
-typerule REWRITE_RULE ::CVC4::theory::rewriterules::RewriteRuleTypeRule
-typerule RR_REWRITE ::CVC4::theory::rewriterules::RRRewriteTypeRule
-typerule RR_REDUCTION ::CVC4::theory::rewriterules::RRRedDedTypeRule
-typerule RR_DEDUCTION ::CVC4::theory::rewriterules::RRRedDedTypeRule
-
-endtheory
diff --git a/src/theory/rewriterules/options b/src/theory/rewriterules/options
deleted file mode 100644
index 285e489be..000000000
--- a/src/theory/rewriterules/options
+++ /dev/null
@@ -1,14 +0,0 @@
-#
-# Option specification file for CVC4
-# See src/options/base_options for a description of this file format
-#
-
-module REWRITE_RULES "theory/rewriterules/options.h" Rewrite Rules
-
-option efficientEMatching --efficient-e-matching bool :default false
- use efficient E-matching (only for rewrite rules)
-
-option rewriteRulesAsAxioms --rewrite-rules-as-axioms bool :default false
- whether to convert rewrite rules to usual axioms (for debugging only)
-
-endmodule
diff --git a/src/theory/rewriterules/rr_candidate_generator.cpp b/src/theory/rewriterules/rr_candidate_generator.cpp
deleted file mode 100644
index 3ebb3547c..000000000
--- a/src/theory/rewriterules/rr_candidate_generator.cpp
+++ /dev/null
@@ -1,67 +0,0 @@
-/********************* */
-/*! \file rr_candidate_generator.cpp
- ** \verbatim
- ** Original author: Morgan Deters
- ** Major contributors: Andrew Reynolds
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Implementation of rr candidate generator class
- **/
-
-#include "theory/rewriterules/rr_candidate_generator.h"
-#include "theory/theory_engine.h"
-#include "theory/uf/theory_uf.h"
-#include "theory/quantifiers/term_database.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::rrinst;
-
-GenericCandidateGeneratorClasses::GenericCandidateGeneratorClasses(QuantifiersEngine * qe) : d_qe(qe){
- d_master_can_gen = new eq::rrinst::CandidateGeneratorTheoryEeClasses(d_qe->getMasterEqualityEngine());
-}
-
-GenericCandidateGeneratorClasses::~GenericCandidateGeneratorClasses(){
- delete d_master_can_gen;
-}
-
-void GenericCandidateGeneratorClasses::resetInstantiationRound(){
- d_master_can_gen->resetInstantiationRound();
-}
-
-void GenericCandidateGeneratorClasses::reset(TNode eqc){
- d_master_can_gen->reset(eqc);
-}
-
-TNode GenericCandidateGeneratorClasses::getNextCandidate(){
- return d_master_can_gen->getNextCandidate();
-}
-
-
-GenericCandidateGeneratorClass::GenericCandidateGeneratorClass(QuantifiersEngine * qe): d_qe(qe) {
- d_master_can_gen = new eq::rrinst::CandidateGeneratorTheoryEeClass(d_qe->getMasterEqualityEngine());
-}
-
-GenericCandidateGeneratorClass::~GenericCandidateGeneratorClass(){
- delete d_master_can_gen;
-}
-
-void GenericCandidateGeneratorClass::resetInstantiationRound(){
- d_master_can_gen->resetInstantiationRound();
-}
-
-void GenericCandidateGeneratorClass::reset(TNode eqc){
- d_master_can_gen->reset(eqc);
-}
-
-TNode GenericCandidateGeneratorClass::getNextCandidate(){
- return d_master_can_gen->getNextCandidate();
-}
-
diff --git a/src/theory/rewriterules/rr_candidate_generator.h b/src/theory/rewriterules/rr_candidate_generator.h
deleted file mode 100644
index d00c8ab83..000000000
--- a/src/theory/rewriterules/rr_candidate_generator.h
+++ /dev/null
@@ -1,199 +0,0 @@
-/********************* */
-/*! \file rr_candidate_generator.h
- ** \verbatim
- ** Original author: Morgan Deters
- ** Major contributors: Andrew Reynolds, Francois Bobot
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief rr candidate generator
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__REWRITERULES__RR_CANDIDATE_GENERATOR_H
-#define __CVC4__THEORY__REWRITERULES__RR_CANDIDATE_GENERATOR_H
-
-#include "theory/quantifiers_engine.h"
-#include "theory/quantifiers/term_database.h"
-#include "theory/rewriterules/rr_inst_match.h"
-
-using namespace CVC4::theory::quantifiers;
-
-namespace CVC4 {
-namespace theory {
-namespace eq {
-
-namespace rrinst{
-typedef CVC4::theory::rrinst::CandidateGenerator CandidateGenerator;
-
-//New CandidateGenerator. They have a simpler semantic than the old one
-
-// Just iterate among the equivalence classes
-// node::Null() must be given to reset
-class CandidateGeneratorTheoryEeClasses : public CandidateGenerator{
-private:
- //the equality classes iterator
- eq::EqClassesIterator d_eq;
- //equalityengine pointer
- EqualityEngine* d_ee;
-public:
- CandidateGeneratorTheoryEeClasses( EqualityEngine * ee): d_ee( ee ){}
- ~CandidateGeneratorTheoryEeClasses(){}
- void resetInstantiationRound(){};
- void reset( TNode eqc ){
- Assert(eqc.isNull());
- d_eq = eq::EqClassesIterator( d_ee );
- }; //* the argument is not used
- TNode getNextCandidate(){
- if( !d_eq.isFinished() ) return (*(d_eq++));
- else return Node::null();
- };
-};
-
-// Just iterate among the equivalence class of the given node
-// node::Null() *can't* be given to reset
-class CandidateGeneratorTheoryEeClass : public CandidateGenerator{
-private:
- //instantiator pointer
- EqualityEngine* d_ee;
- //the equality class iterator
- eq::EqClassIterator d_eqc;
- /* For the case where the given term doesn't exists in uf */
- Node d_retNode;
-public:
- CandidateGeneratorTheoryEeClass( EqualityEngine* ee): d_ee( ee ){}
- ~CandidateGeneratorTheoryEeClass(){}
- void resetInstantiationRound(){};
- void reset( TNode eqc ){
- Assert(!eqc.isNull());
- if( d_ee->hasTerm( eqc ) ){
- /* eqc is in uf */
- eqc = d_ee->getRepresentative( eqc );
- d_eqc = eq::EqClassIterator( eqc, d_ee );
- d_retNode = Node::null();
- }else{
- /* If eqc if not a term known by uf, it is the only one in its
- equivalence class. So we will return only it */
- d_retNode = eqc;
- d_eqc = eq::EqClassIterator();
- }
- }; //* the argument is not used
- TNode getNextCandidate(){
- if(d_retNode.isNull()){
- if( !d_eqc.isFinished() ) return (*(d_eqc++));
- else return Node::null();
- }else{
- /* the case where eqc not in uf */
- Node ret = d_retNode;
- d_retNode = Node::null(); /* d_eqc.isFinished() must be true */
- return ret;
- }
- };
-};
-
-
-} /* namespace rrinst */
-} /* namespace eq */
-
-namespace uf{
-namespace rrinst {
-
-typedef CVC4::theory::rrinst::CandidateGenerator CandidateGenerator;
-
-class CandidateGeneratorTheoryUfOp : public CandidateGenerator{
-private:
- Node d_op;
- //instantiator pointer
- TermDb* d_tdb;
- // Since new term can appears we restrict ourself to the one that
- // exists at resetInstantiationRound
- size_t d_term_iter_limit;
- size_t d_term_iter;
-public:
- CandidateGeneratorTheoryUfOp(Node op, TermDb* tdb): d_op(op), d_tdb( tdb ){}
- ~CandidateGeneratorTheoryUfOp(){}
- void resetInstantiationRound(){
- d_term_iter_limit = d_tdb->d_op_map[d_op].size();
- };
- void reset( TNode eqc ){
- Assert(eqc.isNull());
- d_term_iter = 0;
- }; //* the argument is not used
- TNode getNextCandidate(){
- if( d_term_iter<d_term_iter_limit ){
- TNode n = d_tdb->d_op_map[d_op][d_term_iter];
- ++d_term_iter;
- return n;
- } else return Node::null();
- };
-};
-
-class CandidateGeneratorTheoryUfType : public CandidateGenerator{
-private:
- TypeNode d_type;
- //instantiator pointer
- TermDb* d_tdb;
- // Since new term can appears we restrict ourself to the one that
- // exists at resetInstantiationRound
- size_t d_term_iter_limit;
- size_t d_term_iter;
-public:
- CandidateGeneratorTheoryUfType(TypeNode type, TermDb* tdb): d_type(type), d_tdb( tdb ){}
- ~CandidateGeneratorTheoryUfType(){}
- void resetInstantiationRound(){
- d_term_iter_limit = d_tdb->d_type_map[d_type].size();
- };
- void reset( TNode eqc ){
- Assert(eqc.isNull());
- d_term_iter = 0;
- }; //* the argument is not used
- TNode getNextCandidate(){
- if( d_term_iter<d_term_iter_limit ){
- TNode n = d_tdb->d_type_map[d_type][d_term_iter];
- ++d_term_iter;
- return n;
- } else return Node::null();
- };
-};
-
-} /* namespace rrinst */
-} /* namespace uf */
-
-class GenericCandidateGeneratorClasses: public rrinst::CandidateGenerator{
-
- /** The candidate generators */
- rrinst::CandidateGenerator* d_master_can_gen;
- /** QuantifierEngine */
- QuantifiersEngine* d_qe;
-public:
- GenericCandidateGeneratorClasses(QuantifiersEngine * qe);
- ~GenericCandidateGeneratorClasses();
-
- void resetInstantiationRound();
- void reset(TNode eqc);
- TNode getNextCandidate();
- void lookForNextTheory();
-};
-
-class GenericCandidateGeneratorClass: public rrinst::CandidateGenerator{
-
- /** The candidate generators */
- rrinst::CandidateGenerator* d_master_can_gen;
- /** QuantifierEngine */
- QuantifiersEngine* d_qe;
-public:
- GenericCandidateGeneratorClass(QuantifiersEngine * qe);
- ~GenericCandidateGeneratorClass();
- void resetInstantiationRound();
- void reset(TNode eqc);
- TNode getNextCandidate();
-};
-
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__REWRITERULES__RR_CANDIDATE_GENERATOR_H */
diff --git a/src/theory/rewriterules/rr_inst_match.cpp b/src/theory/rewriterules/rr_inst_match.cpp
deleted file mode 100644
index 2d7cf85fd..000000000
--- a/src/theory/rewriterules/rr_inst_match.cpp
+++ /dev/null
@@ -1,1596 +0,0 @@
-/********************* */
-/*! \file rr_inst_match.cpp
- ** \verbatim
- ** Original author: Morgan Deters
- ** Major contributors: Francois Bobot
- ** Minor contributors (to current version): Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Implementation of inst match class
- **/
-
-#include "theory/quantifiers/inst_match.h"
-#include "theory/theory_engine.h"
-#include "theory/quantifiers_engine.h"
-#include "theory/uf/equality_engine.h"
-#include "theory/arrays/theory_arrays.h"
-#include "theory/datatypes/theory_datatypes.h"
-#include "theory/rewriterules/rr_inst_match.h"
-#include "theory/rewriterules/rr_trigger.h"
-#include "theory/rewriterules/rr_inst_match_impl.h"
-#include "theory/rewriterules/rr_candidate_generator.h"
-#include "theory/quantifiers/candidate_generator.h"
-#include "theory/rewriterules/efficient_e_matching.h"
-
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::rrinst;
-using namespace CVC4::theory::uf::rrinst;
-using namespace CVC4::theory::eq::rrinst;
-
-namespace CVC4{
-namespace theory{
-namespace rrinst{
-
-
-
-
-InstMatch::InstMatch() {
-}
-
-InstMatch::InstMatch( InstMatch* m ) {
- d_map = m->d_map;
-}
-
-bool InstMatch::setMatch( EqualityQuery* q, TNode v, TNode m, bool & set ){
- std::map< Node, Node >::iterator vn = d_map.find( v );
- if( !m.isNull() && !m.getType().isSubtypeOf( v.getType() ) ){
- set = false;
- return false;
- }else if( vn==d_map.end() || vn->second.isNull() ){
- set = true;
- this->set(v,m);
- Debug("matching-debug") << "Add partial " << v << "->" << m << std::endl;
- return true;
- }else{
- set = false;
- return q->areEqual( vn->second, m );
- }
-}
-
-bool InstMatch::setMatch( EqualityQuery* q, TNode v, TNode m ){
- bool set;
- return setMatch(q,v,m,set);
-}
-
-bool InstMatch::add( InstMatch& m ){
- for( std::map< Node, Node >::iterator it = m.d_map.begin(); it != m.d_map.end(); ++it ){
- if( !it->second.isNull() ){
- std::map< Node, Node >::iterator itf = d_map.find( it->first );
- if( itf==d_map.end() || itf->second.isNull() ){
- d_map[it->first] = it->second;
- }
- }
- }
- return true;
-}
-
-bool InstMatch::merge( EqualityQuery* q, InstMatch& m ){
- for( std::map< Node, Node >::iterator it = m.d_map.begin(); it != m.d_map.end(); ++it ){
- if( !it->second.isNull() ){
- std::map< Node, Node >::iterator itf = d_map.find( it->first );
- if( itf==d_map.end() || itf->second.isNull() ){
- d_map[ it->first ] = it->second;
- }else{
- if( !q->areEqual( it->second, itf->second ) ){
- d_map.clear();
- return false;
- }
- }
- }
- }
- return true;
-}
-
-void InstMatch::debugPrint( const char* c ){
- for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){
- Debug( c ) << " " << it->first << " -> " << it->second << std::endl;
- }
- //if( !d_splits.empty() ){
- // Debug( c ) << " Conditions: ";
- // for( std::map< Node, Node >::iterator it = d_splits.begin(); it !=d_splits.end(); ++it ){
- // Debug( c ) << it->first << " = " << it->second << " ";
- // }
- // Debug( c ) << std::endl;
- //}
-}
-
-void InstMatch::makeComplete( Node f, QuantifiersEngine* qe ){
- for( size_t i=0; i<f[0].getNumChildren(); i++ ){
- Node ic = qe->getTermDatabase()->getInstantiationConstant( f, i );
- if( d_map.find( ic )==d_map.end() ){
- d_map[ ic ] = qe->getTermDatabase()->getFreeVariableForInstConstant( ic );
- }
- }
-}
-
-//void InstMatch::makeInternalRepresentative( QuantifiersEngine* qe ){
-// EqualityQueryQuantifiersEngine* eqqe = (EqualityQueryQuantifiersEngine*)qe->getEqualityQuery();
-// for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){
-// d_map[ it->first ] = eqqe->getInternalRepresentative( it->second );
-// }
-//}
-
-void InstMatch::makeRepresentative( QuantifiersEngine* qe ){
- for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){
- if( qe->getEqualityQuery()->getEngine()->hasTerm( it->second ) ){
- d_map[ it->first ] = qe->getEqualityQuery()->getEngine()->getRepresentative( it->second );
- }
- }
-}
-
-void InstMatch::applyRewrite(){
- for( std::map< Node, Node >::iterator it = d_map.begin(); it != d_map.end(); ++it ){
- it->second = Rewriter::rewrite(it->second);
- }
-}
-
-/** get value */
-Node InstMatch::getValue( Node var ) const{
- std::map< Node, Node >::const_iterator it = d_map.find( var );
- if( it!=d_map.end() ){
- return it->second;
- }else{
- return Node::null();
- }
-}
-
-Node InstMatch::get( QuantifiersEngine* qe, Node f, int i ) {
- return get( qe->getTermDatabase()->getInstantiationConstant( f, i ) );
-}
-
-void InstMatch::set(TNode var, TNode n){
- Assert( !var.isNull() );
- if (Trace.isOn("inst-match-warn")) {
- // For a strange use in inst_match.cpp InstMatchGeneratorSimple::addInstantiations
- if( !n.isNull() && !n.getType().isSubtypeOf( var.getType() ) ){
- Trace("inst-match-warn") << quantifiers::TermDb::getInstConstAttr(var) << std::endl;
- Trace("inst-match-warn") << var << " " << var.getType() << " " << n << " " << n.getType() << std::endl ;
- }
- }
- Assert( n.isNull() || n.getType().isSubtypeOf( var.getType() ) );
- d_map[var] = n;
-}
-
-void InstMatch::set( QuantifiersEngine* qe, Node f, int i, TNode n ) {
- set( qe->getTermDatabase()->getInstantiationConstant( f, i ), n );
-}
-
-
-
-
-
-
-typedef CVC4::theory::rrinst::InstMatch InstMatch;
-typedef CVC4::theory::inst::CandidateGeneratorQueue CandidateGeneratorQueue;
-
-template<bool modEq>
-class InstMatchTrie2Pairs
-{
- typename std::vector< std::vector < typename InstMatchTrie2Gen<modEq>::Tree > > d_data;
- InstMatchTrie2Gen<modEq> d_backtrack;
-public:
- InstMatchTrie2Pairs(context::Context* c, QuantifiersEngine* q, size_t n):
- d_backtrack(c,q) {
- // resize to a triangle
- //
- // | *
- // | * *
- // | * * *
- // | -----> i
- d_data.resize(n);
- for(size_t i=0; i < n; ++i){
- d_data[i].resize(i+1,typename InstMatchTrie2Gen<modEq>::Tree(0));
- }
- };
- InstMatchTrie2Pairs(const InstMatchTrie2Pairs &) CVC4_UNDEFINED;
- const InstMatchTrie2Pairs & operator =(const InstMatchTrie2Pairs & e) CVC4_UNDEFINED;
- /** add match m in the trie,
- return true if it was never seen */
- inline bool addInstMatch( size_t i, size_t j, InstMatch& m){
- size_t k = std::min(i,j);
- size_t l = std::max(i,j);
- return d_backtrack.addInstMatch(m,&(d_data[l][k]));
- };
- inline bool addInstMatch( size_t i, InstMatch& m){
- return d_backtrack.addInstMatch(m,&(d_data[i][i]));
- };
-
-};
-
-
-// Currently the implementation doesn't take into account that
-// variable should have the same value given.
-// TODO use the d_children way perhaps
-// TODO replace by a real dictionnary
-// We should create a real substitution? slower more precise
-// We don't do that often
-bool nonunifiable( TNode t0, TNode pat, const std::vector<Node> & vars){
- if(pat.isNull()) return true;
-
- typedef std::vector<std::pair<TNode,TNode> > tstack;
- tstack stack(1,std::make_pair(t0,pat)); // t * pat
-
- while(!stack.empty()){
- const std::pair<TNode,TNode> p = stack.back(); stack.pop_back();
- const TNode & t = p.first;
- const TNode & pat = p.second;
-
- // t or pat is a variable currently we consider that can match anything
- if( find(vars.begin(),vars.end(),t) != vars.end() ) continue;
- if( pat.getKind() == INST_CONSTANT ) continue;
-
- // t and pat are nonunifiable
- if( !Trigger::isAtomicTrigger( t ) || !Trigger::isAtomicTrigger( pat ) ) {
- if(t == pat) continue;
- else return true;
- };
- if( t.getOperator() != pat.getOperator() ) return true;
-
- //put the children on the stack
- for( size_t i=0; i < pat.getNumChildren(); i++ ){
- stack.push_back(std::make_pair(t[i],pat[i]));
- };
- }
- // The heuristic can't find non-unifiability
- return false;
-};
-
-/** New things */
-class DumbMatcher: public Matcher{
- void resetInstantiationRound( QuantifiersEngine* qe ){};
- bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ){
- return false;
- }
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- return false;
- }
-};
-
-class DumbPatMatcher: public PatMatcher{
- void resetInstantiationRound( QuantifiersEngine* qe ){};
- bool reset( InstMatch& m, QuantifiersEngine* qe ){
- return false;
- }
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- return false;
- }
-};
-
-
-/* The order of the matching is:
- reset arg1, nextMatch arg1, reset arg2, nextMatch arg2, ... */
-ApplyMatcher::ApplyMatcher( Node pat, QuantifiersEngine* qe): d_pattern(pat){
-
- //set-up d_variables, d_constants, d_childrens
- for( size_t i=0; i< d_pattern.getNumChildren(); ++i ){
- //EqualityQuery* q = qe->getEqualityQuery(d_pattern[i].getType());
- EqualityQuery* q = qe->getEqualityQuery();
- Assert( q != NULL );
- if( quantifiers::TermDb::hasInstConstAttr(d_pattern[i]) ){
- if( d_pattern[i].getKind()==INST_CONSTANT ){
- //It's a variable
- d_variables.push_back(make_triple((TNode)d_pattern[i],i,q));
- }else{
- //It's neither a constant argument neither a variable
- //we create the matcher for the subpattern
- d_childrens.push_back(make_triple(mkMatcher((TNode)d_pattern[i], qe),i,q));
- };
- }else{
- // It's a constant
- d_constants.push_back(make_triple((TNode)d_pattern[i],i,q));
- }
- }
-}
-
-void ApplyMatcher::resetInstantiationRound( QuantifiersEngine* qe ){
- for( size_t i=0; i< d_childrens.size(); i++ ){
- d_childrens[i].first->resetInstantiationRound( qe );
- }
-}
-
-bool ApplyMatcher::reset(TNode t, InstMatch & m, QuantifiersEngine* qe){
- Debug("matching") << "Matching " << t << " against pattern " << d_pattern << " ("
- << m.size() << ")" << std::endl;
-
- //if t is null
- Assert( !t.isNull() );
- Assert( !quantifiers::TermDb::hasInstConstAttr(t) );
- Assert( t.getKind()==d_pattern.getKind() );
- Assert( (t.getKind()!=APPLY_UF && t.getKind()!=APPLY_CONSTRUCTOR)
- || t.getOperator()==d_pattern.getOperator() );
-
- typedef std::vector< triple<TNode,size_t,EqualityQuery*> >::iterator iterator;
- for(iterator i = d_constants.begin(), end = d_constants.end();
- i != end; ++i){
- if( !i->third->areEqual( i->first, t[i->second] ) ){
- Debug("matching-fail") << "Match fail arg: " << i->first << " and " << t[i->second] << std::endl;
- //setMatchFail( qe, d_pattern[i], t[i] );
- //ground arguments are not equal
- return false;
- }
- }
-
- d_binded.clear();
- bool set;
- for(iterator i = d_variables.begin(), end = d_variables.end();
- i != end; ++i){
- if( !m.setMatch( i->third, i->first, t[i->second], set) ){
- //match is in conflict
- Debug("matching-debug") << "Match in conflict " << t[i->second] << " and "
- << i->first << " because "
- << m.get(i->first)
- << std::endl;
- Debug("matching-fail") << "Match fail: " << m.get(i->first) << " and " << t[i->second] << std::endl;
- //setMatchFail( qe, partial[0].d_map[d_pattern[i]], t[i] );
- m.erase(d_binded.begin(), d_binded.end());
- return false;
- }else{
- if(set){ //The variable has just been set
- d_binded.push_back(i->first);
- }
- }
- }
-
- //now, fit children into match
- //we will be requesting candidates for matching terms for each child
- d_reps.clear();
- for( size_t i=0; i< d_childrens.size(); i++ ){
- Debug("matching-debug") << "Take the representative of " << t[ d_childrens[i].second ] << std::endl;
- Assert( d_childrens[i].third->hasTerm(t[ d_childrens[i].second ]) );
- Node rep = d_childrens[i].third->getRepresentative( t[ d_childrens[i].second ] );
- d_reps.push_back( rep );
- }
-
- if(d_childrens.size() == 0) return true;
- else return getNextMatch(m, qe, true);
-}
-
-bool ApplyMatcher::getNextMatch(InstMatch& m, QuantifiersEngine* qe, bool reset){
- Assert(d_childrens.size() > 0);
- const size_t max = d_childrens.size() - 1;
- size_t index = reset ? 0 : max;
- Assert(d_childrens.size() == d_reps.size());
- while(true){
- if(reset ?
- d_childrens[index].first->reset( d_reps[index], m, qe ) :
- d_childrens[index].first->getNextMatch( m, qe )){
- if(index==max) return true;
- ++index;
- reset=true;
- }else{
- if(index==0){
- m.erase(d_binded.begin(), d_binded.end());
- return false;
- }
- --index;
- reset=false;
- };
- }
-}
-
-bool ApplyMatcher::getNextMatch(InstMatch& m, QuantifiersEngine* qe){
- if(d_childrens.size() == 0){
- m.erase(d_binded.begin(), d_binded.end());
- return false;
- } else return getNextMatch(m, qe, false);
-}
-
-/** Proxy that call the sub-matcher on the result return by the given candidate generator */
-template <class CG, class M>
-class CandidateGeneratorMatcher: public Matcher{
- /** candidate generator */
- CG d_cg;
- /** the sub-matcher */
- M d_m;
-public:
- CandidateGeneratorMatcher(CG cg, M m): d_cg(cg), d_m(m)
- {/* last is Null */};
- void resetInstantiationRound( QuantifiersEngine* qe ){
- d_cg.resetInstantiationRound();
- d_m.resetInstantiationRound(qe);
- };
- bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ){
- d_cg.reset(n);
- return findMatch(m,qe);
- }
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- // The sub-matcher has another match
- return d_m.getNextMatch(m, qe) || findMatch(m,qe);
- }
-private:
- bool findMatch( InstMatch& m, QuantifiersEngine* qe ){
- // Otherwise try to find a new candidate that has at least one match
- while(true){
- TNode n = d_cg.getNextCandidate();//kept somewhere Term-db
- Debug("matching") << "GenCand " << n << " (" << this << ")" << std::endl;
- if(n.isNull()) return false;
- if(d_m.reset(n,m,qe)) return true;
- };
- }
-};
-
-/** Proxy that call the sub-matcher on the result return by the given candidate generator */
-template<class M>
-class PatOfMatcher: public PatMatcher{
- M d_m;
-public:
- inline PatOfMatcher(M m): d_m(m){}
- void resetInstantiationRound(QuantifiersEngine* qe){
- d_m.resetInstantiationRound(qe);
- }
- bool reset(InstMatch& m, QuantifiersEngine* qe){
- return d_m.reset(Node::null(),m,qe);
- };
- bool getNextMatch(InstMatch& m, QuantifiersEngine* qe){
- return d_m.getNextMatch(m,qe);
- };
-};
-
-class ArithMatcher: public Matcher{
-private:
- /** for arithmetic matching */
- std::map< Node, Node > d_arith_coeffs;
- /** get the match against ground term or formula t.
- d_match_mattern and t should have the same shape.
- only valid for use where !d_match_pattern.isNull().
- */
- /** the variable that are set by this matcher */
- std::vector< TNode > d_binded; /* TNode because the variables are already in d_arith_coeffs */
- Node d_pattern; //for debugging
-public:
- ArithMatcher(Node pat, QuantifiersEngine* qe);
- void resetInstantiationRound( QuantifiersEngine* qe ){};
- bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe );
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe );
-};
-
-/** Match just a variable */
-class VarMatcher: public Matcher{
- Node d_var;
- bool d_binded; /* True if the reset bind the variable to some value */
- EqualityQuery* d_q;
-public:
- VarMatcher(Node var, QuantifiersEngine* qe): d_var(var), d_binded(false){
- //d_q = qe->getEqualityQuery(var.getType());
- d_q = qe->getEqualityQuery();
- }
- void resetInstantiationRound( QuantifiersEngine* qe ){};
- bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ){
- if(!m.setMatch( d_q, d_var, n, d_binded )){
- //match is in conflict
- Debug("matching-fail") << "Match fail: " << m.get(d_var)
- << " and " << n << std::endl;
- return false;
- } else return true;
- };
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- //match is in conflict
- if (d_binded) m.erase(d_var);
- return false;
- }
-};
-
-template <class M, class Test >
-class TestMatcher: public Matcher{
- M d_m;
- Test d_test;
-public:
- inline TestMatcher(M m, Test test): d_m(m), d_test(test){}
- inline void resetInstantiationRound(QuantifiersEngine* qe){
- d_m.resetInstantiationRound(qe);
- }
- inline bool reset(TNode n, InstMatch& m, QuantifiersEngine* qe){
- return d_test(n) && d_m.reset(n, m, qe);
- }
- inline bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- return d_m.getNextMatch(m, qe);
- }
-};
-
-class LegalOpTest/*: public unary_function<TNode,bool>*/ {
- Node d_op;
-public:
- inline LegalOpTest(Node op): d_op(op){}
- inline bool operator() (TNode n) {
- return
- CandidateGenerator::isLegalCandidate(n) &&
- // ( // n.getKind()==SELECT || n.getKind()==STORE ||
- // n.getKind()==APPLY_UF || n.getKind()==APPLY_CONSTRUCTOR) &&
- n.hasOperator() &&
- n.getOperator()==d_op;
- };
-};
-
-class LegalKindTest/* : public unary_function<TNode,bool>*/ {
- Kind d_kind;
-public:
- inline LegalKindTest(Kind kind): d_kind(kind){}
- inline bool operator() (TNode n) {
- return
- CandidateGenerator::isLegalCandidate(n) &&
- n.getKind()==d_kind;
- };
-};
-
-class LegalTypeTest/* : public unary_function<TNode,bool>*/ {
- TypeNode d_type;
-public:
- inline LegalTypeTest(TypeNode type): d_type(type){}
- inline bool operator() (TNode n) {
- return
- CandidateGenerator::isLegalCandidate(n) &&
- n.getType()==d_type;
- };
-};
-
-class LegalTest/* : public unary_function<TNode,bool>*/ {
-public:
- inline bool operator() (TNode n) {
- return CandidateGenerator::isLegalCandidate(n);
- };
-};
-
-size_t numFreeVar(TNode t){
- size_t n = 0;
- for( size_t i=0, size =t.getNumChildren(); i < size; ++i ){
- if( quantifiers::TermDb::hasInstConstAttr(t[i]) ){
- if( t[i].getKind()==INST_CONSTANT ){
- //variable
- ++n;
- }else{
- //neither variable nor constant
- n += numFreeVar(t[i]);
- }
- }
- }
- return n;
-}
-
-class OpMatcher: public Matcher{
- /* The matcher */
- typedef ApplyMatcher AuxMatcher3;
- typedef TestMatcher< AuxMatcher3, LegalOpTest > AuxMatcher2;
- typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, AuxMatcher2> AuxMatcher1;
- AuxMatcher1 d_cgm;
- static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){
- Assert( pat.getKind() == kind::APPLY_UF );
- /** In reverse order of matcher sequence */
- AuxMatcher3 am3(pat,qe);
- /** Keep only the one that have the good operator */
- AuxMatcher2 am2(am3,LegalOpTest(pat.getOperator()));
- /** Iter on the equivalence class of the given term */
- uf::TheoryUF* uf = static_cast<uf::TheoryUF *>(qe->getTheoryEngine()->theoryOf( theory::THEORY_UF ));
- eq::EqualityEngine* ee = static_cast<eq::EqualityEngine*>(uf->getEqualityEngine());
- CandidateGeneratorTheoryEeClass cdtUfEq(ee);
- /* Create a matcher from the candidate generator */
- AuxMatcher1 am1(cdtUfEq,am2);
- return am1;
- }
- size_t d_num_var;
- Node d_pat;
-public:
- OpMatcher( Node pat, QuantifiersEngine* qe ):
- d_cgm(createCgm(pat, qe)),d_num_var(numFreeVar(pat)),
- d_pat(pat) {}
-
- void resetInstantiationRound( QuantifiersEngine* qe ){
- d_cgm.resetInstantiationRound(qe);
- };
- bool reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){
- // size_t m_size = m.d_map.size();
- // if(m_size == d_num_var){
- // uf::EqualityEngine<uf::TheoryUF::NotifyClass>* ee = (static_cast<uf::TheoryUF*>(qe->getTheoryEngine()->theoryOf( theory::THEORY_UF )))->getEqualityEngine();
- // std::cout << "!";
- // return ee->areEqual(m.subst(d_pat),t);
- // }else{
- // std::cout << m.d_map.size() << std::endl;
- return d_cgm.reset(t, m, qe);
- // }
- }
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- return d_cgm.getNextMatch(m, qe);
- }
-};
-
-class DatatypesMatcher: public Matcher{
- /* The matcher */
- typedef ApplyMatcher AuxMatcher3;
- typedef TestMatcher< AuxMatcher3, LegalOpTest > AuxMatcher2;
- typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, AuxMatcher2> AuxMatcher1;
- AuxMatcher1 d_cgm;
- static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){
- Assert( pat.getKind() == kind::APPLY_CONSTRUCTOR,
- "For datatypes only constructor are accepted in pattern" );
- /** In reverse order of matcher sequence */
- AuxMatcher3 am3(pat,qe);
- /** Keep only the one that have the good operator */
- AuxMatcher2 am2(am3,LegalOpTest(pat.getOperator()));
- /** Iter on the equivalence class of the given term */
- datatypes::TheoryDatatypes* dt = static_cast<datatypes::TheoryDatatypes *>(qe->getTheoryEngine()->theoryOf( theory::THEORY_DATATYPES ));
- eq::EqualityEngine* ee = static_cast<eq::EqualityEngine*>(dt->getEqualityEngine());
- CandidateGeneratorTheoryEeClass cdtDtEq(ee);
- /* Create a matcher from the candidate generator */
- AuxMatcher1 am1(cdtDtEq,am2);
- return am1;
- }
- Node d_pat;
-public:
- DatatypesMatcher( Node pat, QuantifiersEngine* qe ):
- d_cgm(createCgm(pat, qe)),
- d_pat(pat) {}
-
- void resetInstantiationRound( QuantifiersEngine* qe ){
- d_cgm.resetInstantiationRound(qe);
- };
- bool reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){
- Debug("matching") << "datatypes: " << t << " matches " << d_pat << std::endl;
- return d_cgm.reset(t, m, qe);
- }
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- return d_cgm.getNextMatch(m, qe);
- }
-};
-
-class ArrayMatcher: public Matcher{
- /* The matcher */
- typedef ApplyMatcher AuxMatcher3;
- typedef TestMatcher< AuxMatcher3, LegalKindTest > AuxMatcher2;
- typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, AuxMatcher2> AuxMatcher1;
- AuxMatcher1 d_cgm;
- static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){
- Assert( pat.getKind() == kind::SELECT || pat.getKind() == kind::STORE );
- /** In reverse order of matcher sequence */
- AuxMatcher3 am3(pat,qe);
- /** Keep only the one that have the good operator */
- AuxMatcher2 am2(am3, LegalKindTest(pat.getKind()));
- /** Iter on the equivalence class of the given term */
- arrays::TheoryArrays* ar = static_cast<arrays::TheoryArrays *>(qe->getTheoryEngine()->theoryOf( theory::THEORY_ARRAY ));
- eq::EqualityEngine* ee =
- static_cast<eq::EqualityEngine*>(ar->getEqualityEngine());
- CandidateGeneratorTheoryEeClass cdtUfEq(ee);
- /* Create a matcher from the candidate generator */
- AuxMatcher1 am1(cdtUfEq,am2);
- return am1;
- }
- size_t d_num_var;
- Node d_pat;
-public:
- ArrayMatcher( Node pat, QuantifiersEngine* qe ):
- d_cgm(createCgm(pat, qe)),d_num_var(numFreeVar(pat)),
- d_pat(pat) {}
-
- void resetInstantiationRound( QuantifiersEngine* qe ){
- d_cgm.resetInstantiationRound(qe);
- };
- bool reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){
- // size_t m_size = m.d_map.size();
- // if(m_size == d_num_var){
- // uf::EqualityEngine<uf::TheoryUF::NotifyClass>* ee = (static_cast<uf::TheoryUF*>(qe->getTheoryEngine()->theoryOf( theory::THEORY_UF )))->getEqualityEngine();
- // std::cout << "!";
- // return ee->areEqual(m.subst(d_pat),t);
- // }else{
- // std::cout << m.d_map.size() << std::endl;
- return d_cgm.reset(t, m, qe);
- // }
- }
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- return d_cgm.getNextMatch(m, qe);
- }
-};
-
-class AllOpMatcher: public PatMatcher{
- /* The matcher */
- typedef ApplyMatcher AuxMatcher3;
- typedef TestMatcher< AuxMatcher3, LegalTest > AuxMatcher2;
- typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryUfOp, AuxMatcher2> AuxMatcher1;
- AuxMatcher1 d_cgm;
- static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){
- Assert( pat.hasOperator() );
- /** In reverse order of matcher sequence */
- AuxMatcher3 am3(pat,qe);
- /** Keep only the one that have the good operator */
- AuxMatcher2 am2(am3,LegalTest());
- /** Iter on the equivalence class of the given term */
- TermDb* tdb = qe->getTermDatabase();
- Node op = tdb->getOperator( pat );
- CandidateGeneratorTheoryUfOp cdtUfEq(op,tdb);
- /* Create a matcher from the candidate generator */
- AuxMatcher1 am1(cdtUfEq,am2);
- return am1;
- }
- size_t d_num_var;
- Node d_pat;
-public:
- AllOpMatcher( TNode pat, QuantifiersEngine* qe ):
- d_cgm(createCgm(pat, qe)), d_num_var(numFreeVar(pat)),
- d_pat(pat) {}
-
- void resetInstantiationRound( QuantifiersEngine* qe ){
- d_cgm.resetInstantiationRound(qe);
- };
- bool reset( InstMatch& m, QuantifiersEngine* qe ){
- // std::cout << m.d_map.size() << "/" << d_num_var << std::endl;
- return d_cgm.reset(Node::null(), m, qe);
- }
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- return d_cgm.getNextMatch(m, qe);
- }
-};
-
-template <bool classes> /** true classes | false class */
-class GenericCandidateGeneratorClasses: public CandidateGenerator{
-private:
- CandidateGenerator* d_cg;
- QuantifiersEngine* d_qe;
-
-public:
- void mkCandidateGenerator(){
- if(classes)
- d_cg = new GenericCandidateGeneratorClasses(d_qe);
- else
- d_cg = new GenericCandidateGeneratorClass(d_qe);
- }
-
- GenericCandidateGeneratorClasses(QuantifiersEngine* qe):
- d_qe(qe) {
- mkCandidateGenerator();
- }
- ~GenericCandidateGeneratorClasses(){
- delete(d_cg);
- }
- const GenericCandidateGeneratorClasses & operator =(const GenericCandidateGeneratorClasses & m){
- mkCandidateGenerator();
- return m;
- };
- GenericCandidateGeneratorClasses(const GenericCandidateGeneratorClasses & m):
- d_qe(m.d_qe){
- mkCandidateGenerator();
- }
- void resetInstantiationRound(){
- d_cg->resetInstantiationRound();
- };
- void reset( TNode eqc ){
- Assert( !classes || eqc.isNull() );
- d_cg->reset(eqc);
- }; //* the argument is not used
- TNode getNextCandidate(){
- return d_cg->getNextCandidate();
- };
-}; /* MetaCandidateGeneratorClasses */
-
-
-class GenericMatcher: public Matcher{
- /* The matcher */
- typedef ApplyMatcher AuxMatcher3;
- typedef TestMatcher< AuxMatcher3, LegalOpTest > AuxMatcher2;
- typedef CandidateGeneratorMatcher< GenericCandidateGeneratorClasses<false>, AuxMatcher2> AuxMatcher1;
- AuxMatcher1 d_cgm;
- static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){
- /** In reverse order of matcher sequence */
- AuxMatcher3 am3(pat,qe);
- /** Keep only the one that have the good operator */
- AuxMatcher2 am2(am3,LegalOpTest(pat.getOperator()));
- /** Iter on the equivalence class of the given term */
- GenericCandidateGeneratorClasses<false> cdtG(qe);
- /* Create a matcher from the candidate generator */
- AuxMatcher1 am1(cdtG,am2);
- return am1;
- }
- Node d_pat;
-public:
- GenericMatcher( Node pat, QuantifiersEngine* qe ):
- d_cgm(createCgm(pat, qe)),
- d_pat(pat) {}
-
- void resetInstantiationRound( QuantifiersEngine* qe ){
- d_cgm.resetInstantiationRound(qe);
- };
- bool reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){
- return d_cgm.reset(t, m, qe);
- }
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- return d_cgm.getNextMatch(m, qe);
- }
-};
-
-
-class GenericPatMatcher: public PatMatcher{
- /* The matcher */
- typedef ApplyMatcher AuxMatcher3;
- typedef TestMatcher< AuxMatcher3, LegalOpTest > AuxMatcher2;
- typedef CandidateGeneratorMatcher< GenericCandidateGeneratorClasses<true>, AuxMatcher2> AuxMatcher1;
- AuxMatcher1 d_cgm;
- static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){
- /** In reverse order of matcher sequence */
- AuxMatcher3 am3(pat,qe);
- /** Keep only the one that have the good operator */
- AuxMatcher2 am2(am3,LegalOpTest(pat.getOperator()));
- /** Iter on the equivalence class of the given term */
- GenericCandidateGeneratorClasses<true> cdtG(qe);
- /* Create a matcher from the candidate generator */
- AuxMatcher1 am1(cdtG,am2);
- return am1;
- }
- Node d_pat;
-public:
- GenericPatMatcher( Node pat, QuantifiersEngine* qe ):
- d_cgm(createCgm(pat, qe)),
- d_pat(pat) {}
-
- void resetInstantiationRound( QuantifiersEngine* qe ){
- d_cgm.resetInstantiationRound(qe);
- };
- bool reset( InstMatch& m, QuantifiersEngine* qe ){
- return d_cgm.reset(Node::null(), m, qe);
- }
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- return d_cgm.getNextMatch(m, qe);
- }
-};
-
-class MetaCandidateGeneratorClasses: public CandidateGenerator{
-private:
- CandidateGenerator* d_cg;
- TypeNode d_ty;
- TheoryEngine* d_te;
-
-public:
- CandidateGenerator* mkCandidateGenerator(TypeNode ty, TheoryEngine* te){
- Debug("inst-match-gen") << "MetaCandidateGenerator for type: " << ty
- << " Theory : " << Theory::theoryOf(ty) << std::endl;
- if( Theory::theoryOf(ty) == theory::THEORY_DATATYPES ){
- // datatypes::TheoryDatatypes* dt = static_cast<datatypes::TheoryDatatypes *>(te->theoryOf( theory::THEORY_DATATYPES ));
- // return new datatypes::rrinst::CandidateGeneratorTheoryClasses(dt);
- Unimplemented("MetaCandidateGeneratorClasses for THEORY_DATATYPES");
- }else if ( Theory::theoryOf(ty) == theory::THEORY_ARRAY ){
- arrays::TheoryArrays* ar = static_cast<arrays::TheoryArrays *>(te->theoryOf( theory::THEORY_ARRAY ));
- eq::EqualityEngine* ee =
- static_cast<eq::EqualityEngine*>(ar->getEqualityEngine());
- return new CandidateGeneratorTheoryEeClasses(ee);
- } else {
- uf::TheoryUF* uf = static_cast<uf::TheoryUF*>(te->theoryOf( theory::THEORY_UF ));
- eq::EqualityEngine* ee =
- static_cast<eq::EqualityEngine*>(uf->getEqualityEngine());
- return new CandidateGeneratorTheoryEeClasses(ee);
- }
- }
- MetaCandidateGeneratorClasses(TypeNode ty, TheoryEngine* te):
- d_ty(ty), d_te(te) {
- d_cg = mkCandidateGenerator(ty,te);
- }
- ~MetaCandidateGeneratorClasses(){
- delete(d_cg);
- }
- const MetaCandidateGeneratorClasses & operator =(const MetaCandidateGeneratorClasses & m){
- d_cg = mkCandidateGenerator(m.d_ty, m.d_te);
- return m;
- };
- MetaCandidateGeneratorClasses(const MetaCandidateGeneratorClasses & m):
- d_ty(m.d_ty), d_te(m.d_te){
- d_cg = mkCandidateGenerator(m.d_ty, m.d_te);
- }
- void resetInstantiationRound(){
- d_cg->resetInstantiationRound();
- };
- void reset( TNode eqc ){
- d_cg->reset(eqc);
- }; //* the argument is not used
- TNode getNextCandidate(){
- return d_cg->getNextCandidate();
- };
-}; /* MetaCandidateGeneratorClasses */
-
-/** Match just a variable */
-class AllVarMatcher: public PatMatcher{
-private:
- /* generator */
- typedef VarMatcher AuxMatcher3;
- typedef TestMatcher< AuxMatcher3, LegalTypeTest > AuxMatcher2;
- typedef CandidateGeneratorMatcher< MetaCandidateGeneratorClasses, AuxMatcher2 > AuxMatcher1;
- AuxMatcher1 d_cgm;
- static inline AuxMatcher1 createCgm(TNode pat, QuantifiersEngine* qe){
- Assert( pat.getKind()==INST_CONSTANT );
- TypeNode ty = pat.getType();
- Debug("inst-match-gen") << "create AllVarMatcher for type: " << ty << std::endl;
- /** In reverse order of matcher sequence */
- /** Distribute it to all the pattern */
- AuxMatcher3 am3(pat,qe);
- /** Keep only the one that have the good type */
- AuxMatcher2 am2(am3,LegalTypeTest(ty));
- /** Generate one term by eq classes */
- MetaCandidateGeneratorClasses mcdt(ty,qe->getTheoryEngine());
- /* Create a matcher from the candidate generator */
- AuxMatcher1 am1(mcdt,am2);
- return am1;
- }
-public:
- AllVarMatcher( TNode pat, QuantifiersEngine* qe ):
- d_cgm(createCgm(pat, qe)){}
-
- void resetInstantiationRound( QuantifiersEngine* qe ){
- d_cgm.resetInstantiationRound(qe);
- };
- bool reset( InstMatch& m, QuantifiersEngine* qe ){
- return d_cgm.reset(Node::null(), m, qe); //cdtUfEq doesn't use it's argument for reset
- }
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- return d_cgm.getNextMatch(m, qe);
- }
-};
-
-/** Match all the pattern with the same term */
-class SplitMatcher: public Matcher{
-private:
- const size_t size;
- ApplyMatcher d_m; /** Use ApplyMatcher by creating a fake application */
-public:
- SplitMatcher(std::vector< Node > pats, QuantifiersEngine* qe):
- size(pats.size()),
- d_m(NodeManager::currentNM()->mkNode(kind::INST_PATTERN,pats), qe) {}
- void resetInstantiationRound( QuantifiersEngine* qe ){
- d_m.resetInstantiationRound(qe);
- };
- bool reset( TNode ex, InstMatch& m, QuantifiersEngine* qe ){
- NodeBuilder<> n(kind::INST_PATTERN);
- for(size_t i = 0; i < size; ++i) n << ex;
- Node nn = n;
- return d_m.reset(nn,m,qe);
- };
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- return getNextMatch(m, qe);
- }
-};
-
-
-/** Match uf term in a fixed equivalence class */
-class UfCstEqMatcher: public PatMatcher{
-private:
- /* equivalence class to match */
- Node d_cst;
- /* generator */
- OpMatcher d_cgm;
-public:
- UfCstEqMatcher( Node pat, Node cst, QuantifiersEngine* qe ):
- d_cst(cst),
- d_cgm(OpMatcher(pat,qe)) {};
- void resetInstantiationRound( QuantifiersEngine* qe ){
- d_cgm.resetInstantiationRound(qe);
- };
- bool reset( InstMatch& m, QuantifiersEngine* qe ){
- return d_cgm.reset(d_cst, m, qe);
- }
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- return d_cgm.getNextMatch(m, qe);
- }
-};
-
-/** Match equalities */
-class UfEqMatcher: public PatMatcher{
-private:
- /* generator */
- typedef SplitMatcher AuxMatcher3;
- typedef TestMatcher< AuxMatcher3, LegalTypeTest > AuxMatcher2;
- typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClasses, AuxMatcher2 > AuxMatcher1;
- AuxMatcher1 d_cgm;
- static inline AuxMatcher1 createCgm(std::vector<Node> & pat, QuantifiersEngine* qe){
- Assert( pat.size() > 0);
- TypeNode ty = pat[0].getType();
- for(size_t i = 1; i < pat.size(); ++i){
- Assert(pat[i].getType() == ty);
- }
- /** In reverse order of matcher sequence */
- /** Distribute it to all the pattern */
- AuxMatcher3 am3(pat,qe);
- /** Keep only the one that have the good type */
- AuxMatcher2 am2(am3,LegalTypeTest(ty));
- /** Generate one term by eq classes */
- uf::TheoryUF* uf = static_cast<uf::TheoryUF*>(qe->getTheoryEngine()->theoryOf( theory::THEORY_UF ));
- eq::EqualityEngine* ee =
- static_cast<eq::EqualityEngine*>(uf->getEqualityEngine());
- CandidateGeneratorTheoryEeClasses cdtUfEq(ee);
- /* Create a matcher from the candidate generator */
- AuxMatcher1 am1(cdtUfEq,am2);
- return am1;
- }
-public:
- UfEqMatcher( std::vector<Node> & pat, QuantifiersEngine* qe ):
- d_cgm(createCgm(pat, qe)){}
-
- void resetInstantiationRound( QuantifiersEngine* qe ){
- d_cgm.resetInstantiationRound(qe);
- };
- bool reset( InstMatch& m, QuantifiersEngine* qe ){
- return d_cgm.reset(Node::null(), m, qe); //cdtUfEq doesn't use it's argument for reset
- }
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- return d_cgm.getNextMatch(m, qe);
- }
-};
-
-
-/** Match dis-equalities */
-class UfDeqMatcher: public PatMatcher{
-private:
- /* generator */
- typedef ApplyMatcher AuxMatcher3;
-
- class EqTest/* : public unary_function<Node,bool>*/ {
- TypeNode d_type;
- public:
- inline EqTest(TypeNode type): d_type(type){};
- inline bool operator() (Node n) {
- return
- CandidateGenerator::isLegalCandidate(n) &&
- n.getKind() == kind::EQUAL &&
- n[0].getType()==d_type;
- };
- };
- typedef TestMatcher< AuxMatcher3, EqTest > AuxMatcher2;
- typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass, AuxMatcher2 > AuxMatcher1;
- AuxMatcher1 d_cgm;
- Node false_term;
- static inline AuxMatcher1 createCgm(Node pat, QuantifiersEngine* qe){
- Assert( pat.getKind() == kind::NOT);
- TNode eq = pat[0];
- Assert( eq.getKind() == kind::EQUAL);
- TypeNode ty = eq[0].getType();
- /** In reverse order of matcher sequence */
- /** Distribute it to all the pattern */
- AuxMatcher3 am3(eq,qe);
- /** Keep only the one that have the good type */
- AuxMatcher2 am2(am3,EqTest(ty));
- /** Will generate all the terms of the eq class of false */
- uf::TheoryUF* uf = static_cast<uf::TheoryUF*>(qe->getTheoryEngine()->theoryOf( theory::THEORY_UF ));
- eq::EqualityEngine* ee =
- static_cast<eq::EqualityEngine*>(uf->getEqualityEngine());
- CandidateGeneratorTheoryEeClass cdtUfEq(ee);
- /* Create a matcher from the candidate generator */
- AuxMatcher1 am1(cdtUfEq,am2);
- return am1;
- }
-public:
- UfDeqMatcher( Node pat, QuantifiersEngine* qe ):
- d_cgm(createCgm(pat, qe)),
- false_term((static_cast<uf::TheoryUF*>(qe->getTheoryEngine()->theoryOf( theory::THEORY_UF )))->getEqualityEngine()->
- getRepresentative(NodeManager::currentNM()->mkConst<bool>(false) )){};
- void resetInstantiationRound( QuantifiersEngine* qe ){
- d_cgm.resetInstantiationRound(qe);
- };
- bool reset( InstMatch& m, QuantifiersEngine* qe ){
- return d_cgm.reset(false_term, m, qe);
- }
- bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- return d_cgm.getNextMatch(m, qe);
- }
-};
-
-Matcher* mkMatcher( Node pat, QuantifiersEngine* qe ){
- Debug("inst-match-gen") << "mkMatcher: Pattern term is " << pat << std::endl;
-
- // if( pat.getKind() == kind::APPLY_UF){
- // return new OpMatcher(pat, qe);
- // } else if( pat.getKind() == kind::APPLY_CONSTRUCTOR ){
- // return new DatatypesMatcher(pat, qe);
- // } else if( pat.getKind() == kind::SELECT || pat.getKind() == kind::STORE ){
- // return new ArrayMatcher(pat, qe);
- if( pat.getKind() == kind::APPLY_UF ||
- pat.getKind() == kind::APPLY_CONSTRUCTOR ||
- pat.getKind() == kind::SELECT || pat.getKind() == kind::STORE ){
- return new GenericMatcher(pat, qe);
- } else { /* Arithmetic? */
- /** TODO: something simpler to see if the pattern is a good
- arithmetic pattern */
- std::map< Node, Node > d_arith_coeffs;
- if( !Trigger::getPatternArithmetic( quantifiers::TermDb::getInstConstAttr(pat), pat, d_arith_coeffs ) ){
- Message() << "(?) Unknown matching pattern is " << pat << std::endl;
- Unimplemented("pattern not implemented");
- return new DumbMatcher();
- }else{
- Debug("matching-arith") << "Generated arithmetic pattern for " << pat << ": " << std::endl;
- for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){
- Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl;
- }
- ArithMatcher am3 (pat, qe);
- TestMatcher<ArithMatcher, LegalTypeTest>
- am2(am3,LegalTypeTest(pat.getType()));
- /* generator */
- uf::TheoryUF* uf = static_cast<uf::TheoryUF*>(qe->getTheoryEngine()->theoryOf( theory::THEORY_UF ));
- eq::EqualityEngine* ee =
- static_cast<eq::EqualityEngine*> (uf->getEqualityEngine());
- CandidateGeneratorTheoryEeClass cdtUfEq(ee);
- return new CandidateGeneratorMatcher< CandidateGeneratorTheoryEeClass,
- TestMatcher<ArithMatcher, LegalTypeTest> > (cdtUfEq,am2);
- }
- }
-};
-
-PatMatcher* mkPattern( Node pat, QuantifiersEngine* qe ){
- Debug("inst-match-gen") << "Pattern term is " << pat << std::endl;
- Assert( quantifiers::TermDb::hasInstConstAttr(pat) );
-
- if( pat.getKind()==kind::NOT && pat[0].getKind() == kind::EQUAL){
- /* Difference */
- return new UfDeqMatcher(pat, qe);
- } else if (pat.getKind() == kind::EQUAL){
- if( !quantifiers::TermDb::hasInstConstAttr(pat[0])){
- Assert(quantifiers::TermDb::hasInstConstAttr(pat[1]));
- return new UfCstEqMatcher(pat[1], pat[0], qe);
- }else if( !quantifiers::TermDb::hasInstConstAttr(pat[1] )){
- Assert(quantifiers::TermDb::hasInstConstAttr(pat[0]));
- return new UfCstEqMatcher(pat[0], pat[1], qe);
- }else{
- std::vector< Node > pats(pat.begin(),pat.end());
- return new UfEqMatcher(pats,qe);
- }
- } else if( Trigger::isAtomicTrigger( pat ) ){
- return new AllOpMatcher(pat, qe);
- // return new GenericPatMatcher(pat, qe);
- } else if( pat.getKind()==INST_CONSTANT ){
- // just a variable
- return new AllVarMatcher(pat, qe);
- } else { /* Arithmetic? */
- /** TODO: something simpler to see if the pattern is a good
- arithmetic pattern */
- std::map< Node, Node > d_arith_coeffs;
- if( !Trigger::getPatternArithmetic( quantifiers::TermDb::getInstConstAttr(pat), pat, d_arith_coeffs ) ){
- Debug("inst-match-gen") << "(?) Unknown matching pattern is " << pat << std::endl;
- Message() << "(?) Unknown matching pattern is " << pat << std::endl;
- return new DumbPatMatcher();
- }else{
- Debug("matching-arith") << "Generated arithmetic pattern for " << pat << ": " << std::endl;
- for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){
- Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl;
- }
- ArithMatcher am3 (pat, qe);
- TestMatcher<ArithMatcher, LegalTest>
- am2(am3,LegalTest());
- /* generator */
- TermDb* tdb = qe->getTermDatabase();
- CandidateGeneratorTheoryUfType cdtUfEq(pat.getType(),tdb);
- typedef CandidateGeneratorMatcher< CandidateGeneratorTheoryUfType,
- TestMatcher<ArithMatcher, LegalTest> > AuxMatcher1;
- return new PatOfMatcher<AuxMatcher1>(AuxMatcher1(cdtUfEq,am2));
- }
- }
-};
-
-ArithMatcher::ArithMatcher(Node pat, QuantifiersEngine* qe): d_pattern(pat){
-
- if(Trigger::getPatternArithmetic(quantifiers::TermDb::getInstConstAttr(pat), pat, d_arith_coeffs ) )
- {
- Debug("inst-match-gen") << "(?) Unknown matching pattern is " << d_pattern << std::endl;
- Assert(false);
- }else{
- Debug("matching-arith") << "Generated arithmetic pattern for " << d_pattern << ": " << std::endl;
- for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){
- Debug("matching-arith") << " " << it->first << " -> " << it->second << std::endl;
- }
- }
-
-};
-
-bool ArithMatcher::reset( TNode t, InstMatch& m, QuantifiersEngine* qe ){
- Debug("matching-arith") << "Matching " << t << " " << d_pattern << std::endl;
- d_binded.clear();
- if( !d_arith_coeffs.empty() ){
- NodeBuilder<> tb(kind::PLUS);
- Node ic = Node::null();
- for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){
- Debug("matching-arith") << it->first << " -> " << it->second << std::endl;
- if( !it->first.isNull() ){
- if( m.find( it->first )==m.end() ){
- //see if we can choose this to set
- if( ic.isNull() && ( it->second.isNull() || !it->first.getType().isInteger() ) ){
- ic = it->first;
- }
- }else{
- Debug("matching-arith") << "already set " << m.get( it->first ) << std::endl;
- Node tm = m.get( it->first );
- if( !it->second.isNull() ){
- tm = NodeManager::currentNM()->mkNode( MULT, it->second, tm );
- }
- tb << tm;
- }
- }else{
- tb << it->second;
- }
- }
- if( !ic.isNull() ){
- Node tm;
- if( tb.getNumChildren()==0 ){
- tm = t;
- }else{
- tm = tb.getNumChildren()==1 ? tb.getChild( 0 ) : tb;
- tm = NodeManager::currentNM()->mkNode( MINUS, t, tm );
- }
- if( !d_arith_coeffs[ ic ].isNull() ){
- Assert( !ic.getType().isInteger() );
- Node coeff = NodeManager::currentNM()->mkConst( Rational(1) / d_arith_coeffs[ ic ].getConst<Rational>() );
- tm = NodeManager::currentNM()->mkNode( MULT, coeff, tm );
- }
- m.set( ic, Rewriter::rewrite( tm ));
- d_binded.push_back(ic);
- //set the rest to zeros
- for( std::map< Node, Node >::iterator it = d_arith_coeffs.begin(); it != d_arith_coeffs.end(); ++it ){
- if( !it->first.isNull() ){
- if( m.find( it->first )==m.end() ){
- m.set( it->first, NodeManager::currentNM()->mkConst( Rational(0) ));
- d_binded.push_back(ic);
- }
- }
- }
- Debug("matching-arith") << "Setting " << ic << " to " << tm << std::endl;
- return true;
- }else{
- m.erase(d_binded.begin(), d_binded.end());
- return false;
- }
- }else{
- m.erase(d_binded.begin(), d_binded.end());
- return false;
- }
-};
-
-bool ArithMatcher::getNextMatch( InstMatch& m, QuantifiersEngine* qe ){
- m.erase(d_binded.begin(), d_binded.end());
- return false;
-};
-
-
-class MultiPatsMatcher: public PatsMatcher{
-private:
- bool d_reset_done;
- std::vector< PatMatcher* > d_patterns;
- InstMatch d_im;
- bool reset( QuantifiersEngine* qe ){
- d_im.clear();
- d_reset_done = true;
-
- return getNextMatch(qe,true);
- };
-
- bool getNextMatch(QuantifiersEngine* qe, bool reset){
- const size_t max = d_patterns.size() - 1;
- size_t index = reset ? 0 : max;
- while(true){
- Debug("matching") << "MultiPatsMatcher::index " << index << "/"
- << max << (reset ? " reset_phase" : "") << std::endl;
- if(reset ?
- d_patterns[index]->reset( d_im, qe ) :
- d_patterns[index]->getNextMatch( d_im, qe )){
- if(index==max) return true;
- ++index;
- reset=true;
- }else{
- if(index==0) return false;
- --index;
- reset=false;
- };
- }
- }
-
-public:
- MultiPatsMatcher(std::vector< Node > & pats, QuantifiersEngine* qe):
- d_reset_done(false){
- Assert(pats.size() > 0);
- for( size_t i=0; i< pats.size(); i++ ){
- d_patterns.push_back(mkPattern(pats[i],qe));
- };
- };
- void resetInstantiationRound( QuantifiersEngine* qe ){
- for( size_t i=0; i< d_patterns.size(); i++ ){
- d_patterns[i]->resetInstantiationRound( qe );
- };
- d_reset_done = false;
- d_im.clear();
- };
- bool getNextMatch( QuantifiersEngine* qe ){
- Assert(d_patterns.size()>0);
- if(d_reset_done) return getNextMatch(qe,false);
- else return reset(qe);
- }
- const InstMatch& getInstMatch(){return d_im;};
-
- int addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe);
-};
-
-enum EffiStep{
- ES_STOP,
- ES_GET_MONO_CANDIDATE,
- ES_GET_MULTI_CANDIDATE,
- ES_RESET1,
- ES_RESET2,
- ES_NEXT1,
- ES_NEXT2,
- ES_RESET_OTHER,
- ES_NEXT_OTHER,
-};
-static inline std::ostream& operator<<(std::ostream& out, const EffiStep& step) {
- switch(step){
- case ES_STOP: out << "STOP"; break;
- case ES_GET_MONO_CANDIDATE: out << "GET_MONO_CANDIDATE"; break;
- case ES_GET_MULTI_CANDIDATE: out << "GET_MULTI_CANDIDATE"; break;
- case ES_RESET1: out << "RESET1"; break;
- case ES_RESET2: out << "RESET2"; break;
- case ES_NEXT1: out << "NEXT1"; break;
- case ES_NEXT2: out << "NEXT2"; break;
- case ES_RESET_OTHER: out << "RESET_OTHER"; break;
- case ES_NEXT_OTHER: out << "NEXT_OTHER"; break;
- }
- return out;
-}
-
-
-int MultiPatsMatcher::addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe){
- //now, try to add instantiation for each match produced
- int addedLemmas = 0;
- resetInstantiationRound( qe );
- d_im.add( baseMatch );
- while( getNextMatch( qe ) ){
- InstMatch im_copy = getInstMatch();
- std::vector< Node > terms;
- for( unsigned i=0; i<quant[0].getNumChildren(); i++ ){
- terms.push_back( im_copy.get( qe, quant, i ) );
- }
-
- //m.makeInternal( d_quantEngine->getEqualityQuery() );
- if( qe->addInstantiation( quant, terms ) ){
- addedLemmas++;
- }
- }
- //return number of lemmas added
- return addedLemmas;
-}
-
-PatsMatcher* mkPatterns( std::vector< Node > pat, QuantifiersEngine* qe ){
- return new MultiPatsMatcher( pat, qe);
-}
-
-class MultiEfficientPatsMatcher: public PatsMatcher{
-private:
- bool d_phase_mono;
- bool d_phase_new_term;
- std::vector< PatMatcher* > d_patterns;
- std::vector< Matcher* > d_direct_patterns;
- InstMatch d_im;
- EfficientHandler d_eh;
- EfficientHandler::MultiCandidate d_mc;
- InstMatchTrie2Pairs<true> d_cache;
- std::vector<Node> d_pats;
- // bool indexDone( size_t i){
- // return i == d_c.first.second ||
- // ( i == d_c.second.second && d_c.second.first.empty());
- // }
-
-
-
- static const EffiStep ES_START = ES_GET_MONO_CANDIDATE;
- EffiStep d_step;
-
- //return true if it becomes bigger than d_patterns.size() - 1
- bool incrIndex(size_t & index){
- if(index == d_patterns.size() - 1) return true;
- ++index;
- if(index == d_mc.first.second
- || (!d_phase_mono && index == d_mc.second.second))
- return incrIndex(index);
- else return false;
- }
-
- //return true if it becomes smaller than 0
- bool decrIndex(size_t & index){
- if(index == 0) return true;
- --index;
- if(index == d_mc.first.second
- || (!d_phase_mono && index == d_mc.second.second))
- return decrIndex(index);
- else return false;
- }
-
- bool resetOther( QuantifiersEngine* qe ){
- return getNextMatchOther(qe,true);
- };
-
-
- bool getNextMatchOther(QuantifiersEngine* qe, bool reset){
- size_t index = reset ? 0 : d_patterns.size();
- if(!reset && decrIndex(index)) return false;
- if( reset &&
- (index == d_mc.first.second
- || (!d_phase_mono && index == d_mc.second.second))
- && incrIndex(index)) return true;
- while(true){
- Debug("matching") << "MultiEfficientPatsMatcher::index " << index << "/"
- << d_patterns.size() - 1 << std::endl;
- if(reset ?
- d_patterns[index]->reset( d_im, qe ) :
- d_patterns[index]->getNextMatch( d_im, qe )){
- if(incrIndex(index)) return true;
- reset=true;
- }else{
- if(decrIndex(index)) return false;
- reset=false;
- };
- }
- }
-
- inline EffiStep TestMonoCache(QuantifiersEngine* qe){
- if( //!d_phase_new_term ||
- d_pats.size() == 1) return ES_RESET_OTHER;
- if(d_cache.addInstMatch(d_mc.first.second,d_im)){
- Debug("inst-match::cache") << "Cache miss" << d_im << std::endl;
- ++qe->d_statistics.d_mono_candidates_cache_miss;
- return ES_RESET_OTHER;
- } else {
- Debug("inst-match::cache") << "Cache hit" << d_im << std::endl;
- ++qe->d_statistics.d_mono_candidates_cache_hit;
- return ES_NEXT1;
- }
- // ++qe->d_statistics.d_mono_candidates_cache_miss;
- // return ES_RESET_OTHER;
- }
-
- inline EffiStep TestMultiCache(QuantifiersEngine* qe){
- if(d_cache.addInstMatch(d_mc.first.second,d_mc.second.second,d_im)){
- ++qe->d_statistics.d_multi_candidates_cache_miss;
- return ES_RESET_OTHER;
- } else {
- ++qe->d_statistics.d_multi_candidates_cache_hit;
- return ES_NEXT2;
- }
- }
-
-
-public:
-
- bool getNextMatch( QuantifiersEngine* qe ){
- Assert( d_step == ES_START || d_step == ES_NEXT_OTHER || d_step == ES_STOP );
- while(true){
- Debug("matching") << "d_step=" << d_step << " "
- << "d_im=" << d_im << std::endl;
- switch(d_step){
- case ES_GET_MONO_CANDIDATE:
- Assert(d_im.empty());
- if(d_phase_new_term ? d_eh.getNextMonoCandidate(d_mc.first) : d_eh.getNextMonoCandidateNewTerm(d_mc.first)){
- if(d_phase_new_term) ++qe->d_statistics.d_num_mono_candidates_new_term;
- else ++qe->d_statistics.d_num_mono_candidates;
- d_phase_mono = true;
- d_step = ES_RESET1;
- } else if (!d_phase_new_term){
- d_phase_new_term = true;
- d_step = ES_GET_MONO_CANDIDATE;
- } else {
- d_phase_new_term = false;
- d_step = ES_GET_MULTI_CANDIDATE;
- }
- break;
- case ES_GET_MULTI_CANDIDATE:
- Assert(d_im.empty());
- if(d_eh.getNextMultiCandidate(d_mc)){
- ++qe->d_statistics.d_num_multi_candidates;
- d_phase_mono = false;
- d_step = ES_RESET1;
- } else d_step = ES_STOP;
- break;
- case ES_RESET1:
- if(d_direct_patterns[d_mc.first.second]->reset(d_mc.first.first,d_im,qe))
- d_step = d_phase_mono ? TestMonoCache(qe) : ES_RESET2;
- else d_step = d_phase_mono ? ES_GET_MONO_CANDIDATE : ES_GET_MULTI_CANDIDATE;
- break;
- case ES_RESET2:
- Assert(!d_phase_mono);
- if(d_direct_patterns[d_mc.second.second]->reset(d_mc.second.first,d_im,qe))
- d_step = TestMultiCache(qe);
- else d_step = ES_NEXT1;
- break;
- case ES_NEXT1:
- if(d_direct_patterns[d_mc.first.second]->getNextMatch(d_im,qe))
- d_step = d_phase_mono ? TestMonoCache(qe) : ES_RESET2;
- else d_step = d_phase_mono ? ES_GET_MONO_CANDIDATE : ES_GET_MULTI_CANDIDATE;
- break;
- case ES_NEXT2:
- if(d_direct_patterns[d_mc.second.second]->getNextMatch(d_im,qe))
- d_step = TestMultiCache(qe);
- else d_step = ES_NEXT1;
- break;
- case ES_RESET_OTHER:
- if(resetOther(qe)){
- d_step = ES_NEXT_OTHER;
- return true;
- } else d_step = d_phase_mono ? ES_NEXT1 : ES_NEXT2;
- break;
- case ES_NEXT_OTHER:
- {
- if(!getNextMatchOther(qe,false)){
- d_step = d_phase_mono ? ES_NEXT1 : ES_NEXT2;
- }else{
- d_step = ES_NEXT_OTHER;
- return true;
- }
- }
- break;
- case ES_STOP:
- Assert(d_im.empty());
- return false;
- }
- }
- }
-
- MultiEfficientPatsMatcher(std::vector< Node > & pats, QuantifiersEngine* qe):
- d_eh(qe->getTheoryEngine()->getSatContext()),
- d_cache(qe->getTheoryEngine()->getSatContext(),qe,pats.size()),
- d_pats(pats), d_step(ES_START) {
- Assert(pats.size() > 0);
- for( size_t i=0; i< pats.size(); i++ ){
- d_patterns.push_back(mkPattern(pats[i],qe));
- if(pats[i].getKind()==kind::INST_CONSTANT){
- d_direct_patterns.push_back(new VarMatcher(pats[i],qe));
- } else if( pats[i].getKind() == kind::NOT && pats[i][0].getKind() == kind::EQUAL){
- d_direct_patterns.push_back(new ApplyMatcher(pats[i][0],qe));
- } else {
- d_direct_patterns.push_back(new ApplyMatcher(pats[i],qe));
- }
- };
- EfficientEMatcher* eem = qe->getEfficientEMatcher();
- eem->registerEfficientHandler(d_eh, pats);
- };
- void resetInstantiationRound( QuantifiersEngine* qe ){
- Assert(d_step == ES_START || d_step == ES_STOP);
- for( size_t i=0; i< d_patterns.size(); i++ ){
- d_patterns[i]->resetInstantiationRound( qe );
- d_direct_patterns[i]->resetInstantiationRound( qe );
- };
- d_step = ES_START;
- d_phase_new_term = false;
- Assert(d_im.empty());
- };
-
- const InstMatch& getInstMatch(){return d_im;};
-
- int addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe);
-};
-
-int MultiEfficientPatsMatcher::addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe){
- //now, try to add instantiation for each match produced
- int addedLemmas = 0;
- Assert(baseMatch.empty());
- resetInstantiationRound( qe );
- while( getNextMatch( qe ) ){
- InstMatch im_copy = getInstMatch();
- std::vector< Node > terms;
- for( unsigned i=0; i<quant[0].getNumChildren(); i++ ){
- terms.push_back( im_copy.get( qe, quant, i ) );
- }
-
- //m.makeInternal( d_quantEngine->getEqualityQuery() );
- if( qe->addInstantiation( quant, terms ) ){
- addedLemmas++;
- }
- }
- //return number of lemmas added
- return addedLemmas;
-};
-
-PatsMatcher* mkPatternsEfficient( std::vector< Node > pat, QuantifiersEngine* qe ){
- return new MultiEfficientPatsMatcher( pat, qe);
-}
-
-} /* CVC4::theory::rrinst */
-} /* CVC4::theory */
-} /* CVC4 */
diff --git a/src/theory/rewriterules/rr_inst_match.h b/src/theory/rewriterules/rr_inst_match.h
deleted file mode 100644
index c42dd8914..000000000
--- a/src/theory/rewriterules/rr_inst_match.h
+++ /dev/null
@@ -1,341 +0,0 @@
-/********************* */
-/*! \file rr_inst_match.h
- ** \verbatim
- ** Original author: Morgan Deters
- ** Major contributors: Francois Bobot
- ** Minor contributors (to current version): Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief inst match class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__REWRITERULES__RR_INST_MATCH_H
-#define __CVC4__THEORY__REWRITERULES__RR_INST_MATCH_H
-
-#include "theory/theory.h"
-#include "util/hash.h"
-#include "util/ntuple.h"
-
-#include <ext/hash_set>
-#include <iostream>
-#include <map>
-
-#include "theory/uf/equality_engine.h"
-#include "theory/uf/theory_uf.h"
-#include "context/cdlist.h"
-
-#include "theory/quantifiers/term_database.h"
-#include "expr/node_manager.h"
-#include "expr/node_builder.h"
-
-#include "theory/quantifiers/options.h"
-#include "theory/rewriterules/options.h"
-
-//#define USE_EFFICIENT_E_MATCHING
-
-namespace CVC4 {
-namespace theory {
-
-class EqualityQuery;
-
-namespace rrinst{
-
-/** basic class defining an instantiation */
-class InstMatch {
- /* map from variable to ground terms */
- std::map< Node, Node > d_map;
-public:
- InstMatch();
- InstMatch( InstMatch* m );
-
- /** set the match of v to m */
- bool setMatch( EqualityQuery* q, TNode v, TNode m );
- /* This version tell if the variable has been set */
- bool setMatch( EqualityQuery* q, TNode v, TNode m, bool & set);
- /** fill all unfilled values with m */
- bool add( InstMatch& m );
- /** if compatible, fill all unfilled values with m and return true
- return false otherwise */
- bool merge( EqualityQuery* q, InstMatch& m );
- /** debug print method */
- void debugPrint( const char* c );
- /** is complete? */
- bool isComplete( Node f ) { return d_map.size()==f[0].getNumChildren(); }
- /** make complete */
- void makeComplete( Node f, QuantifiersEngine* qe );
- /** make internal representative */
- //void makeInternalRepresentative( QuantifiersEngine* qe );
- /** make representative */
- void makeRepresentative( QuantifiersEngine* qe );
- /** get value */
- Node getValue( Node var ) const;
- /** clear */
- void clear(){ d_map.clear(); }
- /** is_empty */
- bool empty(){ return d_map.empty(); }
- /** to stream */
- inline void toStream(std::ostream& out) const {
- out << "INST_MATCH( ";
- for( std::map< Node, Node >::const_iterator it = d_map.begin(); it != d_map.end(); ++it ){
- if( it != d_map.begin() ){ out << ", "; }
- out << it->first << " -> " << it->second;
- }
- out << " )";
- }
-
-
- //for rewrite rules
-
- /** apply rewrite */
- void applyRewrite();
- /** erase */
- template<class Iterator>
- void erase(Iterator begin, Iterator end){
- for(Iterator i = begin; i != end; ++i){
- d_map.erase(*i);
- };
- }
- void erase(Node node){ d_map.erase(node); }
- /** get */
- Node get( TNode var ) { return d_map[var]; }
- Node get( QuantifiersEngine* qe, Node f, int i );
- /** set */
- void set(TNode var, TNode n);
- void set( QuantifiersEngine* qe, Node f, int i, TNode n );
- /** size */
- size_t size(){ return d_map.size(); }
- /* iterator */
- std::map< Node, Node >::iterator begin(){ return d_map.begin(); };
- std::map< Node, Node >::iterator end(){ return d_map.end(); };
- std::map< Node, Node >::iterator find(Node var){ return d_map.find(var); };
- /* Node used for matching the trigger only for mono-trigger (just for
- efficiency because I need only that) */
- Node d_matched;
-};/* class InstMatch */
-
-
-
-class CandidateGenerator
-{
-public:
- CandidateGenerator(){}
- virtual ~CandidateGenerator(){};
-
- /** Get candidates functions. These set up a context to get all match candidates.
- cg->reset( eqc );
- do{
- Node cand = cg->getNextCandidate();
- //.......
- }while( !cand.isNull() );
-
- eqc is the equivalence class you are searching in
- */
- virtual void reset( TNode eqc ) = 0;
- virtual TNode getNextCandidate() = 0;
- /** call this at the beginning of each instantiation round */
- virtual void resetInstantiationRound() = 0;
-public:
- /** legal candidate */
- static inline bool isLegalCandidate( TNode n ){
- return !n.getAttribute(NoMatchAttribute()) &&
- ( !options::cbqi() || !quantifiers::TermDb::hasInstConstAttr(n)) &&
- ( !options::efficientEMatching() || n.hasAttribute(AvailableInTermDb()) );
-}
-
-};
-
-
-inline std::ostream& operator<<(std::ostream& out, const InstMatch& m) {
- m.toStream(out);
- return out;
-}
-
-template<bool modEq = false> class InstMatchTrie2;
-template<bool modEq = false> class InstMatchTrie2Pairs;
-
-template<bool modEq = false>
-class InstMatchTrie2Gen
-{
- friend class InstMatchTrie2<modEq>;
- friend class InstMatchTrie2Pairs<modEq>;
-
-private:
-
- class Tree {
- public:
- typedef std::hash_map< Node, Tree *, NodeHashFunction > MLevel;
- MLevel e;
- const size_t level; //context level of creation
- Tree() CVC4_UNDEFINED;
- const Tree & operator =(const Tree & t){
- Assert(t.e.empty()); Assert(e.empty());
- Assert(t.level == level);
- return t;
- }
- Tree(size_t l): level(l) {};
- ~Tree(){
- for(typename MLevel::iterator i = e.begin(); i!=e.end(); ++i)
- delete(i->second);
- };
- };
-
-
- typedef std::pair<Tree *, TNode> Mod;
-
- class CleanUp{
- public:
- inline void operator()(Mod * m){
- typename Tree::MLevel::iterator i = m->first->e.find(m->second);
- Assert (i != m->first->e.end()); //should not have been already removed
- m->first->e.erase(i);
- };
- };
-
- EqualityQuery* d_eQ;
- CandidateGenerator * d_cG;
-
- context::Context* d_context;
- context::CDList<Mod, CleanUp, std::allocator<Mod> > d_mods;
-
-
- typedef std::map<Node, Node>::const_iterator mapIter;
-
- /** add the substitution given by the iterator*/
- void addSubTree( Tree * root, mapIter current, mapIter end, size_t currLevel);
- /** test if it exists match, modulo uf-equations if modEq is true if
- * return false the deepest point of divergence is put in [e] and
- * [diverge].
- */
- bool existsInstMatch( Tree * root,
- mapIter & current, mapIter & end,
- Tree * & e, mapIter & diverge) const;
-
- /** add match m in the trie root
- return true if it was never seen */
- bool addInstMatch( InstMatch& m, Tree * root);
-
-public:
- InstMatchTrie2Gen(context::Context* c, QuantifiersEngine* q);
- InstMatchTrie2Gen(const InstMatchTrie2Gen &) CVC4_UNDEFINED;
- const InstMatchTrie2Gen & operator =(const InstMatchTrie2Gen & e) CVC4_UNDEFINED;
-};
-
-template<bool modEq>
-class InstMatchTrie2
-{
- typename InstMatchTrie2Gen<modEq>::Tree d_data;
- InstMatchTrie2Gen<modEq> d_backtrack;
-public:
- InstMatchTrie2(context::Context* c, QuantifiersEngine* q): d_data(0),
- d_backtrack(c,q) {};
- InstMatchTrie2(const InstMatchTrie2 &) CVC4_UNDEFINED;
- const InstMatchTrie2 & operator =(const InstMatchTrie2 & e) CVC4_UNDEFINED;
- /** add match m in the trie,
- return true if it was never seen */
- inline bool addInstMatch( InstMatch& m){
- return d_backtrack.addInstMatch(m,&d_data);
- };
-
-};/* class InstMatchTrie2 */
-
-class Matcher
-{
-public:
- /** reset instantiation round (call this whenever equivalence classes have changed) */
- virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0;
- /** reset the term to match, return false if there is no such term */
- virtual bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe ) = 0;
- /** get the next match. If it return false once you shouldn't call
- getNextMatch again before doing a reset */
- virtual bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) = 0;
- /** If reset, or getNextMatch return false they remove from the
- InstMatch the binding that they have previously created */
-
- /** virtual Matcher in order to have defined behavior */
- virtual ~Matcher(){};
-};
-
-
-class ApplyMatcher: public Matcher{
-private:
- /** What to check first: constant and variable */
- std::vector< triple< TNode,size_t,EqualityQuery* > > d_constants;
- std::vector< triple< TNode,size_t,EqualityQuery* > > d_variables;
- /** children generators, only the sub-pattern which are
- neither a variable neither a constant appears */
- std::vector< triple< Matcher*, size_t, EqualityQuery* > > d_childrens;
- /** the variable that have been set by this matcher (during its own reset) */
- std::vector< TNode > d_binded; /* TNode because the variable are already in d_pattern */
- /** the representative of the argument of the term given by the last reset */
- std::vector< Node > d_reps;
-public:
- /** The pattern we are producing matches for */
- Node d_pattern;
-public:
- /** constructors */
- ApplyMatcher( Node pat, QuantifiersEngine* qe);
- /** destructor */
- ~ApplyMatcher(){/*TODO delete dandling pointers? */}
- /** reset instantiation round (call this whenever equivalence classes have changed) */
- void resetInstantiationRound( QuantifiersEngine* qe );
- /** reset the term to match */
- bool reset( TNode n, InstMatch& m, QuantifiersEngine* qe );
- /** get the next match. */
- bool getNextMatch(InstMatch& m, QuantifiersEngine* qe);
-private:
- bool getNextMatch(InstMatch& m, QuantifiersEngine* qe, bool reset);
-};
-
-
-/* Match literal so you don't choose the equivalence class( */
-class PatMatcher
-{
-public:
- /** reset instantiation round (call this whenever equivalence classes have changed) */
- virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0;
- /** reset the matcher, return false if there is no such term */
- virtual bool reset( InstMatch& m, QuantifiersEngine* qe ) = 0;
- /** get the next match. If it return false once you shouldn't call
- getNextMatch again before doing a reset */
- virtual bool getNextMatch( InstMatch& m, QuantifiersEngine* qe ) = 0;
- /** If reset, or getNextMatch return false they remove from the
- InstMatch the binding that they have previously created */
-};
-
-Matcher* mkMatcher( Node pat, QuantifiersEngine* qe );
-PatMatcher* mkPattern( Node pat, QuantifiersEngine* qe );
-
-/* Match literal so you don't choose the equivalence class( */
-class PatsMatcher
-{
-public:
- /** reset instantiation round (call this whenever equivalence classes have changed) */
- virtual void resetInstantiationRound( QuantifiersEngine* qe ) = 0;
- /** reset the matcher, return false if there is no such term */
- virtual bool getNextMatch( QuantifiersEngine* qe ) = 0;
- virtual const InstMatch& getInstMatch() = 0;
- /** Add directly the instantiation to quantifiers engine */
- virtual int addInstantiations( InstMatch& baseMatch, Node quant, QuantifiersEngine* qe) = 0;
-};
-
-PatsMatcher* mkPatterns( std::vector< Node > pat, QuantifiersEngine* qe );
-PatsMatcher* mkPatternsEfficient( std::vector< Node > pat, QuantifiersEngine* qe );
-
-/** return true if whatever Node is substituted for the variables the
- given Node can't match the pattern */
-bool nonunifiable( TNode t, TNode pat, const std::vector<Node> & vars);
-
-class InstMatchGenerator;
-
-}/* CVC4::theory rrinst */
-
-}/* CVC4::theory namespace */
-
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__REWRITERULES__RR_INST_MATCH_H */
diff --git a/src/theory/rewriterules/rr_inst_match_impl.h b/src/theory/rewriterules/rr_inst_match_impl.h
deleted file mode 100644
index c0dea3ba2..000000000
--- a/src/theory/rewriterules/rr_inst_match_impl.h
+++ /dev/null
@@ -1,126 +0,0 @@
-/********************* */
-/*! \file rr_inst_match_impl.h
- ** \verbatim
- ** Original author: Morgan Deters
- ** Major contributors: Francois Bobot
- ** Minor contributors (to current version): Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief inst match class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__REWRITERULES__RR_INST_MATCH_IMPL_H
-#define __CVC4__THEORY__REWRITERULES__RR_INST_MATCH_IMPL_H
-
-#include "theory/rewriterules/rr_inst_match.h"
-#include "theory/theory_engine.h"
-#include "theory/quantifiers_engine.h"
-#include "theory/rewriterules/rr_candidate_generator.h"
-#include "theory/uf/equality_engine.h"
-
-namespace CVC4 {
-namespace theory {
-namespace rrinst {
-
-template<bool modEq>
-InstMatchTrie2Gen<modEq>::InstMatchTrie2Gen(context::Context* c, QuantifiersEngine* qe):
- d_context(c), d_mods(c) {
- d_eQ = qe->getEqualityQuery();
- d_cG = new GenericCandidateGeneratorClass(qe);
-};
-
-/** add match m for quantifier f starting at index, take into account equalities q, return true if successful */
-template<bool modEq>
-void InstMatchTrie2Gen<modEq>::addSubTree( Tree * root, mapIter current, mapIter end, size_t currLevel ) {
- if( current == end ) return;
-
- Assert(root->e.find(current->second) == root->e.end());
- Tree * root2 = new Tree(currLevel);
- root->e.insert(std::make_pair(current->second, root2));
- addSubTree(root2, ++current, end, currLevel );
-}
-
-/** exists match */
-template<bool modEq>
-bool InstMatchTrie2Gen<modEq>::existsInstMatch(InstMatchTrie2Gen<modEq>::Tree * root,
- mapIter & current, mapIter & end,
- Tree * & e, mapIter & diverge) const{
- if( current == end ) {
- Debug("Trie2") << "Trie2 Bottom " << std::endl;
- --current;
- return true;
- }; //Already their
-
- if (current->first > diverge->first){
- // this point is the deepest point currently seen map are ordered
- e = root;
- diverge = current;
- };
-
- TNode n = current->second;
- typename InstMatchTrie2Gen<modEq>::Tree::MLevel::iterator it =
- root->e.find( n );
- if( it!=root->e.end() &&
- existsInstMatch( (*it).second, ++current, end, e, diverge) ){
- Debug("Trie2") << "Trie2 Directly here " << n << std::endl;
- --current;
- return true;
- }
- Assert( it==root->e.end() || e != root );
-
- // Even if n is in the trie others of the equivalence class
- // can also be in it since the equality can have appeared
- // after they have been added
- if( modEq && d_eQ->hasTerm( n ) ){
- //check modulo equality if any other instantiation match exists
- d_cG->reset( d_eQ->getRepresentative( n ) );
- for(TNode en = d_cG->getNextCandidate() ; !en.isNull() ;
- en = d_cG->getNextCandidate() ){
- if( en == n ) continue; // already tested
- typename InstMatchTrie2Gen<modEq>::Tree::MLevel::iterator itc =
- root->e.find( en );
- if( itc!=root->e.end() &&
- existsInstMatch( (*itc).second, ++current, end, e, diverge) ){
- Debug("Trie2") << "Trie2 Indirectly here by equality " << n << " = " << en << std::endl;
- --current;
- return true;
- }
- Assert( itc==root->e.end() || e != root );
- }
- }
- --current;
- return false;
-}
-
-template<bool modEq>
-bool InstMatchTrie2Gen<modEq>::
-addInstMatch( InstMatch& m, InstMatchTrie2Gen<modEq>::Tree* e ) {
- d_cG->resetInstantiationRound();
- mapIter begin = m.begin();
- mapIter end = m.end();
- mapIter diverge = begin;
- if( !existsInstMatch(e, begin, end, e, diverge ) ){
- Assert(!diverge->second.isNull());
- size_t currLevel = d_context->getLevel();
- addSubTree( e, diverge, end, currLevel );
- if(e->level != currLevel)
- //If same level that e, will be removed at the same time than e
- d_mods.push_back(std::make_pair(e,diverge->second));
- return true;
- }else{
- return false;
- }
-}
-
-}/* CVC4::theory::rrinst namespace */
-
-}/* CVC4::theory namespace */
-
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__REWRITERULES__RR_INST_MATCH_IMPL_H */
diff --git a/src/theory/rewriterules/rr_trigger.cpp b/src/theory/rewriterules/rr_trigger.cpp
deleted file mode 100644
index 13250cf1b..000000000
--- a/src/theory/rewriterules/rr_trigger.cpp
+++ /dev/null
@@ -1,385 +0,0 @@
-/********************* */
-/*! \file rr_trigger.cpp
- ** \verbatim
- ** Original author: Morgan Deters
- ** Major contributors: Andrew Reynolds, Francois Bobot
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Implementation of trigger class
- **/
-
-#include "theory/rewriterules/rr_trigger.h"
-#include "theory/theory_engine.h"
-#include "theory/quantifiers_engine.h"
-#include "theory/rewriterules/rr_candidate_generator.h"
-#include "theory/uf/equality_engine.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::rrinst;
-
-/** trigger class constructor */
-Trigger::Trigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool smartTriggers ) :
-d_quantEngine( qe ), d_f( f ){
- d_nodes.insert( d_nodes.begin(), nodes.begin(), nodes.end() );
- Debug("trigger") << "Trigger for " << f << ": " << d_nodes << std::endl;
- if(matchOption == MATCH_GEN_DEFAULT) d_mg = mkPatterns( d_nodes, qe );
- else d_mg = mkPatternsEfficient( d_nodes, qe );
- if( d_nodes.size()==1 ){
- if( isSimpleTrigger( d_nodes[0] ) ){
- ++(qe->d_statistics.d_triggers);
- }else{
- ++(qe->d_statistics.d_simple_triggers);
- }
- }else{
- Debug("multi-trigger") << "Multi-trigger " << (*this) << std::endl;
- //std::cout << "Multi-trigger for " << f << " : " << std::endl;
- //std::cout << " " << (*this) << std::endl;
- ++(qe->d_statistics.d_multi_triggers);
- }
-}
-
-void Trigger::resetInstantiationRound(){
- d_mg->resetInstantiationRound( d_quantEngine );
-}
-
-
-bool Trigger::getNextMatch(){
- bool retVal = d_mg->getNextMatch( d_quantEngine );
- //m.makeInternal( d_quantEngine->getEqualityQuery() );
- return retVal;
-}
-
-// bool Trigger::getMatch( Node t, InstMatch& m ){
-// //FIXME: this assumes d_mg is an inst match generator
-// return ((InstMatchGenerator*)d_mg)->getMatch( t, m, d_quantEngine );
-// }
-
-
-int Trigger::addInstantiations( InstMatch& baseMatch ){
- int addedLemmas = d_mg->addInstantiations( baseMatch,
- quantifiers::TermDb::getInstConstAttr(d_nodes[0]),
- d_quantEngine);
- if( addedLemmas>0 ){
- Debug("inst-trigger") << "Added " << addedLemmas << " lemmas, trigger was ";
- for( int i=0; i<(int)d_nodes.size(); i++ ){
- Debug("inst-trigger") << d_nodes[i] << " ";
- }
- Debug("inst-trigger") << std::endl;
- }
- return addedLemmas;
-}
-
-Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes, int matchOption, bool keepAll, int trOption,
- bool smartTriggers ){
- std::vector< Node > trNodes;
- if( !keepAll ){
- //only take nodes that contribute variables to the trigger when added
- std::vector< Node > temp;
- temp.insert( temp.begin(), nodes.begin(), nodes.end() );
- std::map< Node, bool > vars;
- std::map< Node, std::vector< Node > > patterns;
- for( int i=0; i<(int)temp.size(); i++ ){
- bool foundVar = false;
- qe->getTermDatabase()->computeVarContains( temp[i] );
- for( int j=0; j<(int)qe->getTermDatabase()->d_var_contains[ temp[i] ].size(); j++ ){
- Node v = qe->getTermDatabase()->d_var_contains[ temp[i] ][j];
- if( quantifiers::TermDb::getInstConstAttr(v)==f ){
- if( vars.find( v )==vars.end() ){
- vars[ v ] = true;
- foundVar = true;
- }
- }
- }
- if( foundVar ){
- trNodes.push_back( temp[i] );
- for( int j=0; j<(int)qe->getTermDatabase()->d_var_contains[ temp[i] ].size(); j++ ){
- Node v = qe->getTermDatabase()->d_var_contains[ temp[i] ][j];
- patterns[ v ].push_back( temp[i] );
- }
- }
- }
- //now, minimalize the trigger
- for( int i=0; i<(int)trNodes.size(); i++ ){
- bool keepPattern = false;
- Node n = trNodes[i];
- for( int j=0; j<(int)qe->getTermDatabase()->d_var_contains[ n ].size(); j++ ){
- Node v = qe->getTermDatabase()->d_var_contains[ n ][j];
- if( patterns[v].size()==1 ){
- keepPattern = true;
- break;
- }
- }
- if( !keepPattern ){
- //remove from pattern vector
- for( int j=0; j<(int)qe->getTermDatabase()->d_var_contains[ n ].size(); j++ ){
- Node v = qe->getTermDatabase()->d_var_contains[ n ][j];
- for( int k=0; k<(int)patterns[v].size(); k++ ){
- if( patterns[v][k]==n ){
- patterns[v].erase( patterns[v].begin() + k, patterns[v].begin() + k + 1 );
- break;
- }
- }
- }
- //remove from trigger nodes
- trNodes.erase( trNodes.begin() + i, trNodes.begin() + i + 1 );
- i--;
- }
- }
- }else{
- trNodes.insert( trNodes.begin(), nodes.begin(), nodes.end() );
- }
-
- //check for duplicate?
- if( trOption==TR_MAKE_NEW ){
- //static int trNew = 0;
- //static int trOld = 0;
- //Trigger* t = qe->getTriggerDatabase()->getTrigger( trNodes );
- //if( t ){
- // trOld++;
- //}else{
- // trNew++;
- //}
- //if( (trNew+trOld)%100==0 ){
- // std::cout << "Trigger new old = " << trNew << " " << trOld << std::endl;
- //}
- }else{
- Trigger* t = qe->getRRTriggerDatabase()->getTrigger( trNodes );
- if( t ){
- if( trOption==TR_GET_OLD ){
- //just return old trigger
- return t;
- }else{
- return NULL;
- }
- }
- }
- Trigger* t = new Trigger( qe, f, trNodes, matchOption, smartTriggers );
- qe->getRRTriggerDatabase()->addTrigger( trNodes, t );
- return t;
-}
-Trigger* Trigger::mkTrigger( QuantifiersEngine* qe, Node f, Node n, int matchOption, bool keepAll, int trOption, bool smartTriggers ){
- std::vector< Node > nodes;
- nodes.push_back( n );
- return mkTrigger( qe, f, nodes, matchOption, keepAll, trOption, smartTriggers );
-}
-
-bool Trigger::isUsableTrigger( std::vector< Node >& nodes, Node f ){
- for( int i=0; i<(int)nodes.size(); i++ ){
- if( !isUsableTrigger( nodes[i], f ) ){
- return false;
- }
- }
- return true;
-}
-
-bool Trigger::isUsable( Node n, Node f ){
- if( quantifiers::TermDb::getInstConstAttr(n)==f ){
- if( !isAtomicTrigger( n ) && n.getKind()!=INST_CONSTANT ){
- std::map< Node, Node > coeffs;
- return getPatternArithmetic( f, n, coeffs );
- }else{
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( !isUsable( n[i], f ) ){
- return false;
- }
- }
- return true;
- }
- }else{
- return true;
- }
-}
-
-bool Trigger::isSimpleTrigger( Node n ){
- if( isAtomicTrigger( n ) ){
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( n[i].getKind()!=INST_CONSTANT && quantifiers::TermDb::hasInstConstAttr(n[i]) ){
- return false;
- }
- }
- return true;
- }else{
- return false;
- }
-}
-
-
-bool Trigger::collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt ){
- if( patMap.find( n )==patMap.end() ){
- patMap[ n ] = false;
- if( tstrt==TS_MIN_TRIGGER ){
- if( n.getKind()==FORALL ){
-#ifdef NESTED_PATTERN_SELECTION
- //return collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt );
- return collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt );
-#else
- return false;
-#endif
- }else{
- bool retVal = false;
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){
- retVal = true;
- }
- }
- if( retVal ){
- return true;
- }else if( isUsableTrigger( n, f ) ){
- patMap[ n ] = true;
- return true;
- }else{
- return false;
- }
- }
- }else{
- bool retVal = false;
- if( isUsableTrigger( n, f ) ){
- patMap[ n ] = true;
- if( tstrt==TS_MAX_TRIGGER ){
- return true;
- }else{
- retVal = true;
- }
- }
- if( n.getKind()==FORALL ){
-#ifdef NESTED_PATTERN_SELECTION
- //if( collectPatTerms2( qe, f, qe->getOrCreateCounterexampleBody( n ), patMap, tstrt ) ){
- // retVal = true;
- //}
- if( collectPatTerms2( qe, f, qe->getBoundBody( n ), patMap, tstrt ) ){
- retVal = true;
- }
-#endif
- }else{
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( collectPatTerms2( qe, f, n[i], patMap, tstrt ) ){
- retVal = true;
- }
- }
- }
- return retVal;
- }
- }else{
- return patMap[ n ];
- }
-}
-
-void Trigger::collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst ){
- std::map< Node, bool > patMap;
- if( filterInst ){
- //immediately do not consider any term t for which another term is an instance of t
- std::vector< Node > patTerms2;
- collectPatTerms( qe, f, n, patTerms2, TS_ALL, false );
- std::vector< Node > temp;
- temp.insert( temp.begin(), patTerms2.begin(), patTerms2.end() );
- qe->getTermDatabase()->filterInstances( temp );
- if( temp.size()!=patTerms2.size() ){
- Debug("trigger-filter-instance") << "Filtered an instance: " << std::endl;
- Debug("trigger-filter-instance") << "Old: ";
- for( int i=0; i<(int)patTerms2.size(); i++ ){
- Debug("trigger-filter-instance") << patTerms2[i] << " ";
- }
- Debug("trigger-filter-instance") << std::endl << "New: ";
- for( int i=0; i<(int)temp.size(); i++ ){
- Debug("trigger-filter-instance") << temp[i] << " ";
- }
- Debug("trigger-filter-instance") << std::endl;
- }
- if( tstrt==TS_ALL ){
- patTerms.insert( patTerms.begin(), temp.begin(), temp.end() );
- return;
- }else{
- //do not consider terms that have instances
- for( int i=0; i<(int)patTerms2.size(); i++ ){
- if( std::find( temp.begin(), temp.end(), patTerms2[i] )==temp.end() ){
- patMap[ patTerms2[i] ] = false;
- }
- }
- }
- }
- collectPatTerms2( qe, f, n, patMap, tstrt );
- for( std::map< Node, bool >::iterator it = patMap.begin(); it != patMap.end(); ++it ){
- if( it->second ){
- patTerms.push_back( it->first );
- }
- }
-}
-
-bool Trigger::getPatternArithmetic( Node f, Node n, std::map< Node, Node >& coeffs ){
- if( n.getKind()==PLUS ){
- Assert( coeffs.empty() );
- NodeBuilder<> t(kind::PLUS);
- for( int i=0; i<(int)n.getNumChildren(); i++ ){
- if( quantifiers::TermDb::hasInstConstAttr(n[i]) ){
- if( n[i].getKind()==INST_CONSTANT ){
- if( quantifiers::TermDb::getInstConstAttr(n[i])==f ){
- coeffs[ n[i] ] = Node::null();
- }else{
- coeffs.clear();
- return false;
- }
- }else if( !getPatternArithmetic( f, n[i], coeffs ) ){
- coeffs.clear();
- return false;
- }
- }else{
- t << n[i];
- }
- }
- if( t.getNumChildren()==0 ){
- coeffs[ Node::null() ] = NodeManager::currentNM()->mkConst( Rational(0) );
- }else if( t.getNumChildren()==1 ){
- coeffs[ Node::null() ] = t.getChild( 0 );
- }else{
- coeffs[ Node::null() ] = t;
- }
- return true;
- }else if( n.getKind()==MULT ){
- if( n[0].getKind()==INST_CONSTANT && quantifiers::TermDb::getInstConstAttr(n[0])==f ){
- Assert( !quantifiers::TermDb::hasInstConstAttr(n[1]) );
- coeffs[ n[0] ] = n[1];
- return true;
- }else if( n[1].getKind()==INST_CONSTANT && quantifiers::TermDb::getInstConstAttr(n[1])==f ){
- Assert( !quantifiers::TermDb::hasInstConstAttr(n[0]) );
- coeffs[ n[1] ] = n[0];
- return true;
- }
- }
- return false;
-}
-
-
-
-Trigger* TriggerTrie::getTrigger2( std::vector< Node >& nodes ){
- if( nodes.empty() ){
- return d_tr;
- }else{
- Node n = nodes.back();
- nodes.pop_back();
- if( d_children.find( n )!=d_children.end() ){
- return d_children[n]->getTrigger2( nodes );
- }else{
- return NULL;
- }
- }
-}
-void TriggerTrie::addTrigger2( std::vector< Node >& nodes, Trigger* t ){
- if( nodes.empty() ){
- d_tr = t;
- }else{
- Node n = nodes.back();
- nodes.pop_back();
- if( d_children.find( n )==d_children.end() ){
- d_children[n] = new TriggerTrie;
- }
- d_children[n]->addTrigger2( nodes, t );
- }
-}
diff --git a/src/theory/rewriterules/rr_trigger.h b/src/theory/rewriterules/rr_trigger.h
deleted file mode 100644
index f02f38d0e..000000000
--- a/src/theory/rewriterules/rr_trigger.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/********************* */
-/*! \file rr_trigger.h
- ** \verbatim
- ** Original author: Morgan Deters
- ** Major contributors: Andrew Reynolds, Francois Bobot
- ** Minor contributors (to current version): Tianyi Liang
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief trigger class
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__REWRITERULES__RR_TRIGGER_H
-#define __CVC4__THEORY__REWRITERULES__RR_TRIGGER_H
-
-#include "theory/rewriterules/rr_inst_match.h"
-
-namespace CVC4 {
-namespace theory {
-namespace rrinst {
-
-//a collect of nodes representing a trigger
-class Trigger {
-private:
- /** the quantifiers engine */
- QuantifiersEngine* d_quantEngine;
- /** the quantifier this trigger is for */
- Node d_f;
- /** match generators */
- PatsMatcher * d_mg;
-private:
- /** trigger constructor */
- Trigger( QuantifiersEngine* ie, Node f, std::vector< Node >& nodes, int matchOption = 0, bool smartTriggers = false );
-public:
- ~Trigger(){}
-public:
- std::vector< Node > d_nodes;
-public:
- void debugPrint( const char* c );
- PatsMatcher* getGenerator() { return d_mg; }
-public:
- /** reset instantiation round (call this whenever equivalence classes have changed) */
- void resetInstantiationRound();
- /** get next match. must call reset( eqc ) once before this function. */
- bool getNextMatch();
- const InstMatch & getInstMatch(){return d_mg->getInstMatch();};
- /** return whether this is a multi-trigger */
- bool isMultiTrigger() { return d_nodes.size()>1; }
-public:
- /** add all available instantiations exhaustively, in any equivalence class
- if limitInst>0, limitInst is the max # of instantiations to try */
- int addInstantiations( InstMatch& baseMatch);
- /** mkTrigger method
- ie : quantifier engine;
- f : forall something ....
- nodes : (multi-)trigger
- matchOption : which policy to use for creating matches (one of InstMatchGenerator::MATCH_GEN_* )
- keepAll: don't remove unneeded patterns;
- trOption : policy for dealing with triggers that already existed (see below)
- */
- enum {
- //options for producing matches
- MATCH_GEN_DEFAULT = 0,
- MATCH_GEN_EFFICIENT_E_MATCH, //generate matches via Efficient E
- };
- enum{
- TR_MAKE_NEW, //make new trigger even if it already may exist
- TR_GET_OLD, //return a previous trigger if it had already been created
- TR_RETURN_NULL //return null if a duplicate is found
- };
- static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, std::vector< Node >& nodes,
- int matchOption = 0, bool keepAll = true, int trOption = TR_MAKE_NEW,
- bool smartTriggers = false );
- static Trigger* mkTrigger( QuantifiersEngine* qe, Node f, Node n,
- int matchOption = 0, bool keepAll = true, int trOption = TR_MAKE_NEW,
- bool smartTriggers = false );
-private:
- /** is subterm of trigger usable */
- static bool isUsable( Node n, Node f );
- /** collect all APPLY_UF pattern terms for f in n */
- static bool collectPatTerms2( QuantifiersEngine* qe, Node f, Node n, std::map< Node, bool >& patMap, int tstrt );
-public:
- //different strategies for choosing trigger terms
- enum {
- TS_MAX_TRIGGER = 0,
- TS_MIN_TRIGGER,
- TS_ALL,
- };
- static void collectPatTerms( QuantifiersEngine* qe, Node f, Node n, std::vector< Node >& patTerms, int tstrt, bool filterInst = false );
-public:
- /** is usable trigger */
- static inline bool isUsableTrigger( TNode n, TNode f ){
- return quantifiers::TermDb::getInstConstAttr(n)==f && isAtomicTrigger( n ) && isUsable( n, f );
- }
- static inline bool isAtomicTrigger( TNode n ){
- return
- n.getKind()==kind::APPLY_UF ||
- n.getKind() == kind::APPLY_CONSTRUCTOR ||
- n.getKind()==kind::SELECT ||
- n.getKind()==kind::STORE;
- }
- static bool isUsableTrigger( std::vector< Node >& nodes, Node f );
- static bool isSimpleTrigger( Node n );
- /** get pattern arithmetic */
- static bool getPatternArithmetic( Node f, Node n, std::map< Node, Node >& coeffs );
-
- inline void toStream(std::ostream& out) const {
- out << "TRIGGER( ";
- for( int i=0; i<(int)d_nodes.size(); i++ ){
- if( i>0 ){ out << ", "; }
- out << d_nodes[i];
- }
- out << " )";
- }
-};
-
-inline std::ostream& operator<<(std::ostream& out, const Trigger & tr) {
- tr.toStream(out);
- return out;
-}
-
-/** a trie of triggers */
-class TriggerTrie
-{
-private:
- Trigger* getTrigger2( std::vector< Node >& nodes );
- void addTrigger2( std::vector< Node >& nodes, Trigger* t );
-public:
- TriggerTrie() : d_tr( NULL ){}
- Trigger* d_tr;
- std::map< Node, TriggerTrie* > d_children;
- Trigger* getTrigger( std::vector< Node >& nodes ){
- std::vector< Node > temp;
- temp.insert( temp.begin(), nodes.begin(), nodes.end() );
- std::sort( temp.begin(), temp.end() );
- return getTrigger2( temp );
- }
- void addTrigger( std::vector< Node >& nodes, Trigger* t ){
- std::vector< Node > temp;
- temp.insert( temp.begin(), nodes.begin(), nodes.end() );
- std::sort( temp.begin(), temp.end() );
- return addTrigger2( temp, t );
- }
-};
-
-
-}/* CVC4::theory::rrinst namespace */
-
-}/* CVC4::theory namespace */
-
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__REWRITERULES__RR_TRIGGER_H */
diff --git a/src/theory/rewriterules/theory_rewriterules.cpp b/src/theory/rewriterules/theory_rewriterules.cpp
deleted file mode 100644
index 7fe625da1..000000000
--- a/src/theory/rewriterules/theory_rewriterules.cpp
+++ /dev/null
@@ -1,640 +0,0 @@
-/********************* */
-/*! \file theory_rewriterules.cpp
- ** \verbatim
- ** Original author: Morgan Deters
- ** Major contributors: Francois Bobot
- ** Minor contributors (to current version): Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief [[ Deals with rewrite rules ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#include "theory/rewriterules/theory_rewriterules.h"
-#include "theory/rewriterules/theory_rewriterules_rules.h"
-#include "theory/rewriterules/theory_rewriterules_params.h"
-
-#include "theory/rewriterules/theory_rewriterules_preprocess.h"
-#include "theory/rewriter.h"
-#include "theory/rewriterules/options.h"
-
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::rewriterules;
-using namespace CVC4::theory::rrinst;
-
-
-namespace CVC4 {
-namespace theory {
-namespace rewriterules {
-
-
-inline std::ostream& operator <<(std::ostream& stream, const RuleInst& ri) {
- ri.toStream(stream);
- return stream;
-}
-
-static const RuleInst* RULEINST_TRUE = (RuleInst*) 1;
-static const RuleInst* RULEINST_FALSE = (RuleInst*) 2;
-
- /** Rule an instantiation with the given match */
-RuleInst::RuleInst(TheoryRewriteRules & re, const RewriteRule * r,
- std::vector<Node> & inst_subst,
- Node matched):
- rule(r), d_matched(matched)
-{
- Assert(r != NULL);
- Assert(!r->directrr || !d_matched.isNull());
- subst.swap(inst_subst);
-};
-
-Node RuleInst::substNode(const TheoryRewriteRules & re, TNode r,
- TCache cache ) const {
- Assert(this != RULEINST_TRUE && this != RULEINST_FALSE);
- return r.substitute (rule->free_vars.begin(),rule->free_vars.end(),
- subst.begin(),subst.end(),cache);
-};
-size_t RuleInst::findGuard(TheoryRewriteRules & re, size_t start)const{
- TCache cache;
- Assert(this != RULEINST_TRUE && this != RULEINST_FALSE);
- while (start < (rule->guards).size()){
- Node g = substNode(re,rule->guards[start],cache);
- switch(re.addWatchIfDontKnow(g,this,start)){
- case ATRUE:
- Debug("rewriterules::guards") << g << "is true" << std::endl;
- ++start;
- continue;
- case AFALSE:
- Debug("rewriterules::guards") << g << "is false" << std::endl;
- return -1;
- case ADONTKNOW:
- Debug("rewriterules::guards") << g << "is unknown" << std::endl;
- return start;
- }
- }
- /** All the guards are verified */
- re.propagateRule(this,cache);
- return start;
-};
-
-bool RuleInst::alreadyRewritten(TheoryRewriteRules & re) const{
- Assert(this != RULEINST_TRUE && this != RULEINST_FALSE);
- static NoMatchAttribute rewrittenNodeAttribute;
- TCache cache;
- for(std::vector<Node>::const_iterator
- iter = rule->to_remove.begin();
- iter != rule->to_remove.end(); ++iter){
- if (substNode(re,*iter,cache).getAttribute(rewrittenNodeAttribute))
- return true;
- };
- return false;
-}
-
-void RuleInst::toStream(std::ostream& out) const{
- if(this == RULEINST_TRUE){ out << "TRUE"; return;};
- if(this == RULEINST_FALSE){ out << "FALSE"; return;};
- out << "(" << *rule << ") ";
- for(std::vector<Node>::const_iterator
- iter = subst.begin(); iter != subst.end(); ++iter){
- out << *iter << " ";
- };
-}
-
-
-void Guarded::nextGuard(TheoryRewriteRules & re)const{
- Assert(inst != RULEINST_TRUE && inst != RULEINST_FALSE);
- if(simulateRewritting && inst->alreadyRewritten(re)) return;
- inst->findGuard(re,d_guard+1);
-};
-
-/** start indicate the first guard which is not true */
-Guarded::Guarded(const RuleInst* ri, const size_t start) :
- d_guard(start),inst(ri) {};
-Guarded::Guarded(const Guarded & g) :
- d_guard(g.d_guard),inst(g.inst) {};
-Guarded::Guarded() :
- //dumb value
- d_guard(-1),inst(RULEINST_TRUE) {};
-
-TheoryRewriteRules::TheoryRewriteRules(context::Context* c,
- context::UserContext* u,
- OutputChannel& out,
- Valuation valuation,
- const LogicInfo& logicInfo) :
- Theory(THEORY_REWRITERULES, c, u, out, valuation, logicInfo),
- d_rules(c), d_ruleinsts(c), d_guardeds(c), d_checkLevel(c,0),
- d_explanations(c), d_ruleinsts_to_add(), d_ppAssert_on(false)
-{
- d_true = NodeManager::currentNM()->mkConst<bool>(true);
- d_false = NodeManager::currentNM()->mkConst<bool>(false);
-}
-
-void TheoryRewriteRules::addMatchRuleTrigger(const RewriteRule * r,
- rrinst::InstMatch & im,
- bool delay){
- ++r->nb_matched;
- ++d_statistics.d_match_found;
- if(rewrite_instantiation) im.applyRewrite();
- if(representative_instantiation)
- im.makeRepresentative( getQuantifiersEngine() );
-
- if(!cache_match || !r->inCache(*this,im)){
- ++r->nb_applied;
- ++d_statistics.d_cache_miss;
- std::vector<Node> subst;
- //AJR: replaced computeTermVec with this
- for( size_t i=0; i<r->inst_vars.size(); i++ ){
- Node n = im.getValue( r->inst_vars[i] );
- Assert( !n.isNull() );
- subst.push_back( n );
- }
- RuleInst * ri = new RuleInst(*this,r,subst,
- r->directrr ? im.d_matched : Node::null());
- Debug("rewriterules::matching") << "One matching found"
- << (delay? "(delayed)":"")
- << ":" << *ri << std::endl;
- // Find the first non verified guard, don't save the rule if the
- // rule can already be fired In fact I save it otherwise strange
- // things append.
- Assert(ri->rule != NULL);
- if(delay) d_ruleinsts_to_add.push_back(ri);
- else{
- if(simulateRewritting && ri->alreadyRewritten(*this)) return;
- if(ri->findGuard(*this, 0) != (r->guards).size())
- d_ruleinsts.push_back(ri);
- else delete(ri);
- };
- }else{
- ++d_statistics.d_cache_hit;
- };
-}
-
-void TheoryRewriteRules::check(Effort level) {
- CodeTimer codeTimer(d_theoryTime);
-
- Assert(d_ruleinsts_to_add.empty());
-
- while(!done()) {
- // Get all the assertions
- // TODO: Test that it have already been ppAsserted
-
- //if we are here and ppAssert has not been done
- // that means that ppAssert is off so we need to assert now
- if(!d_ppAssert_on) addRewriteRule(get());
- else get();
- // Assertion assertion = get();
- // TNode fact = assertion.assertion;
-
- // Debug("rewriterules") << "TheoryRewriteRules::check(): processing " << fact << std::endl;
- // if (getValuation().getDecisionLevel()>0)
- // Unhandled(getValuation().getDecisionLevel());
- // addRewriteRule(fact);
-
- };
-
- Debug("rewriterules::check") << "RewriteRules::Check start " << d_checkLevel << (level==EFFORT_FULL? " EFFORT_FULL":"") << std::endl;
-
- /** Test each rewrite rule */
- for(size_t rid = 0, end = d_rules.size(); rid < end; ++rid) {
- RewriteRule * r = d_rules[rid];
- if (level!=EFFORT_FULL && r->d_split) continue;
- Debug("rewriterules::check") << "RewriteRules::Check rule: " << *r << std::endl;
- Trigger & tr = r->trigger;
- //reset instantiation round for trigger (set up match production)
- tr.resetInstantiationRound();
-
- /** Test the possible matching one by one */
- while(tr.getNextMatch()){
- rrinst::InstMatch im = tr.getInstMatch();
- addMatchRuleTrigger(r, im, true);
- }
- }
-
- const bool do_notification = d_checkLevel == 0 || level==EFFORT_FULL;
- bool polldone = false;
-
- if(level==EFFORT_FULL) ++d_statistics.d_full_check;
- else ++d_statistics.d_check;
-
- GuardedMap::const_iterator p = d_guardeds.begin();
- do{
-
-
- //dequeue instantiated rules
- for(; !d_ruleinsts_to_add.empty();){
- RuleInst * ri = d_ruleinsts_to_add.back(); d_ruleinsts_to_add.pop_back();
- if(simulateRewritting && ri->alreadyRewritten(*this)) continue;
- if(ri->findGuard(*this, 0) != ri->rule->guards.size())
- d_ruleinsts.push_back(ri);
- else delete(ri);
- };
-
- if(do_notification)
- /** Temporary way. Poll value */
- for (; p != d_guardeds.end(); ++p){
- TNode g = (*p).first;
- const GList * const l = (*p).second;
- const Guarded & glast = l->back();
- // Notice() << "Polled?:" << g << std::endl;
- if(glast.inst == RULEINST_TRUE||glast.inst == RULEINST_FALSE) continue;
- // Notice() << "Polled!:" << g << "->" << (glast.inst == RULEINST_TRUE||glast.inst == RULEINST_FALSE) << std::endl;
- bool value;
- if(getValuation().hasSatValue(g,value)){
- if(value) polldone = true; //One guard is true so pass n check
- Debug("rewriterules::guards") << "Poll value:" << g
- << " is " << (value ? "true" : "false") << std::endl;
- notification(g,value);
- //const Guarded & glast2 = (*l)[l->size()-1];
- // Notice() << "Polled!!:" << g << "->" << (glast2.inst == RULEINST_TRUE||glast2.inst == RULEINST_FALSE) << std::endl;
- };
- };
-
- }while(!d_ruleinsts_to_add.empty() ||
- (p != d_guardeds.end() && do_notification));
-
- if(polldone) d_checkLevel = checkSlowdown;
- else d_checkLevel = d_checkLevel > 0 ? (d_checkLevel - 1) : 0;
-
- /** Narrowing by splitting on the guards */
- /** Perhaps only when no notification? */
- if(narrowing_full_effort && level==EFFORT_FULL){
- for (GuardedMap::const_iterator p = d_guardeds.begin();
- p != d_guardeds.end(); ++p){
- TNode g = (*p).first;
- const GList * const l = (*p).second;
- const Guarded & glast = (*l)[l->size()-1];
- if(glast.inst == RULEINST_TRUE||glast.inst == RULEINST_FALSE)
- continue;
- // If it has a value it should already has been notified
- bool value CVC4_UNUSED;
- Assert(!getValuation().hasSatValue(g,value));
- Debug("rewriterules::check") << "RewriteRules::Check Narrowing on:" << g << std::endl;
- /** Can split on already rewritten instrule... but... */
- getOutputChannel().split(g);
- }
- }
-
- Assert(d_ruleinsts_to_add.empty());
- Debug("rewriterules::check") << "RewriteRules::Check done " << d_checkLevel << std::endl;
-
-};
-
-void TheoryRewriteRules::registerQuantifier( Node n ){};
-
-Trigger TheoryRewriteRules::createTrigger( TNode n, std::vector<Node> & pattern ) {
- // Debug("rewriterules") << "createTrigger:";
- getQuantifiersEngine()->registerPattern(pattern);
- return *Trigger::mkTrigger(getQuantifiersEngine(),n,pattern,
- options::efficientEMatching()?
- Trigger::MATCH_GEN_EFFICIENT_E_MATCH :
- Trigger::MATCH_GEN_DEFAULT,
- true,
- Trigger::TR_MAKE_NEW,
- false);
- // options::smartMultiTriggers());
-};
-
-bool TheoryRewriteRules::notifyIfKnown(const GList * const ltested,
- GList * const lpropa) {
- Assert(ltested->size() > 0);
- const Guarded & glast = (*ltested)[ltested->size()-1];
- if(glast.inst == RULEINST_TRUE || glast.inst == RULEINST_FALSE){
- notification(lpropa,glast.inst == RULEINST_TRUE);
- return true;
- };
- return false;
-};
-
-void TheoryRewriteRules::notification(GList * const lpropa, bool b){
- if (b){
- for(size_t ig = 0;
- ig != lpropa->size(); ++ig) {
- (*lpropa)[ig].nextGuard(*this);
- };
- lpropa->push_back(Guarded(RULEINST_TRUE,0));
- }else{
- lpropa->push_back(Guarded(RULEINST_FALSE,0));
- };
- Assert(lpropa->back().inst == RULEINST_TRUE ||
- lpropa->back().inst == RULEINST_FALSE);
-};
-
-
-
-Answer TheoryRewriteRules::addWatchIfDontKnow(Node g0, const RuleInst* ri,
- const size_t gid){
- /** Currently create a node with a literal */
- Node g = getValuation().ensureLiteral(g0);
- GuardedMap::iterator l_i = d_guardeds.find(g);
- GList* l;
- if( l_i == d_guardeds.end() ) {
- /** Normally Not watched so IDONTNOW but since we poll, we can poll now */
- bool value;
- if(getValuation().hasSatValue(g,value)){
- if(value) return ATRUE;
- else return AFALSE;
- };
- //Not watched so IDONTNOW
- l = new(getSatContext()->getCMM())
- GList(true, getSatContext());//,
- //ContextMemoryAllocator<Guarded>(getContext()->getCMM()));
- d_guardeds.insert(g ,l);//.insertDataFromContextMemory(g, l);
- /* TODO Add register propagation */
- } else {
- l = (*l_i).second;
- Assert(l->size() > 0);
- const Guarded & glast = (*l)[l->size()-1];
- if(glast.inst == RULEINST_TRUE) return ATRUE;
- if(glast.inst == RULEINST_FALSE) return AFALSE;
-
- };
- /** I DONT KNOW because not watched or because not true nor false */
- l->push_back(Guarded(ri,gid));
- return ADONTKNOW;
-};
-
-void TheoryRewriteRules::notification(Node g, bool b){
- GuardedMap::const_iterator l = d_guardeds.find(g);
- /** Should be a propagated node already known */
- Assert(l != d_guardeds.end());
- notification((*l).second,b);
-}
-
-
-void TheoryRewriteRules::notifyEq(TNode lhs, TNode rhs) {
- GuardedMap::const_iterator ilhs = d_guardeds.find(lhs);
- GuardedMap::const_iterator irhs = d_guardeds.find(rhs);
- /** Should be a propagated node already known */
- Assert(ilhs != d_guardeds.end());
- if( irhs == d_guardeds.end() ) {
- /** Not watched so points to the list directly */
- d_guardeds.insertDataFromContextMemory(rhs, (*ilhs).second);
- } else {
- GList * const llhs = (*ilhs).second;
- GList * const lrhs = (*irhs).second;
- if(!(notifyIfKnown(llhs,lrhs) || notifyIfKnown(lrhs,llhs))){
- /** If none of the two is known */
- for(GList::const_iterator g = llhs->begin(); g != llhs->end(); ++g){
- lrhs->push_back(*g);
- };
- };
- };
-};
-
-
-Node TheoryRewriteRules::normalizeConjunction(NodeBuilder<> & conjunction){
- Assert(conjunction.getKind() == kind::AND);
- switch(conjunction.getNumChildren()){
- case 0:
- return d_true;
- case 1:
- return conjunction[0];
- default:
- return conjunction;
- }
-
-}
-
-void explainInstantiation(const RuleInst *inst, TNode substHead, NodeBuilder<> & conjunction ){
- TypeNode booleanType = NodeManager::currentNM()->booleanType();
- // if the rule is directly applied by the rewriter,
- // we should take care to use the representative that can't be directly rewritable:
- // If "car(a)" is somewhere and we know that "a = cons(x,l)" we shouldn't
- // add the constraint car(cons(x,l) = x because it is rewritten to x = x.
- // But we should say cons(a) = x
- Assert(!inst->d_matched.isNull());
- Assert( inst->d_matched.getKind() == kind::APPLY_UF);
- Assert( substHead.getKind() == kind::APPLY_UF );
- Assert( inst->d_matched.getOperator() == substHead.getOperator() );
- Assert(conjunction.getKind() == kind::AND);
- // replace the left hand side by the term really matched
- NodeBuilder<2> nb;
- for(size_t i = 0,
- iend = inst->d_matched.getNumChildren(); i < iend; ++i){
- nb.clear( inst->d_matched[i].getType(false) == booleanType ?
- kind::IFF : kind::EQUAL );
- nb << inst->d_matched[i] << substHead[i];
- conjunction << static_cast<Node>(nb);
- }
-}
-
-Node skolemizeBody( Node f ){
- /*TODO skolemize the subformula of s with constant or skolemize
- directly in the body of the rewrite rule with an uninterpreted
- function.
- */
- if ( f.getKind()!=EXISTS ) return f;
- std::vector< Node > vars;
- std::vector< Node > csts;
- for( int i=0; i<(int)f[0].getNumChildren(); i++ ){
- csts.push_back( NodeManager::currentNM()->mkSkolem( "skolem_$$", f[0][i].getType(), "is from skolemizing the body of a rewrite rule" ) );
- vars.push_back( f[0][i] );
- }
- return f[ 1 ].substitute( vars.begin(), vars.end(),
- csts.begin(), csts.end() );
-}
-
-
-void TheoryRewriteRules::propagateRule(const RuleInst * inst, TCache cache){
- // Debug("rewriterules") << "A rewrite rules is verified. Add lemma:";
- Debug("rewriterules::propagate") << "propagateRule" << *inst << std::endl;
- const RewriteRule * rule = inst->rule;
- ++rule->nb_applied;
- // Can be more something else than an equality in fact (eg. propagation rule)
- Node equality = skolemizeBody(inst->substNode(*this,rule->body,cache));
- if(propagate_as_lemma){
- Node lemma = equality;
- if(rule->directrr){
- NodeBuilder<> conjunction(kind::AND);
- explainInstantiation(inst,
- rule->guards.size() > 0?
- inst->substNode(*this,rule->guards[0],cache) : equality[0],
- conjunction);
- Debug("rewriterules-directrr") << "lemma:" << lemma << " :: " << inst->d_matched;
- //rewrite rule
- TypeNode booleanType = NodeManager::currentNM()->booleanType();
- if(equality[1].getType(false) == booleanType)
- equality = inst->d_matched.iffNode(equality[1]);
- else equality = inst->d_matched.eqNode(equality[1]);
- lemma = normalizeConjunction(conjunction).impNode(equality);
- Debug("rewriterules-directrr") << " -> " << lemma << std::endl;
- }
- else if(rule->guards.size() > 0){
- // We can use implication for reduction rules since the head is known
- // to be true
- NodeBuilder<> conjunction(kind::AND);
- substGuards(inst,cache,conjunction);
- lemma = normalizeConjunction(conjunction).impNode(equality);
- }
- Debug("rewriterules::propagate") << "propagated " << lemma << std::endl;
- getOutputChannel().lemma(lemma);
- }else{
- Node lemma_lit = equality;
- if(rule->directrr && rule->guards.size() == 0)
- lemma_lit = inst->d_matched.eqNode(equality[1]); // rewrite rules
- lemma_lit = getValuation().ensureLiteral(lemma_lit);
- ExplanationMap::const_iterator p = d_explanations.find(lemma_lit);
- if(p!=d_explanations.end()) return; //Already propagated
- bool value;
- if(getValuation().hasSatValue(lemma_lit,value)){
- /* Already assigned */
- if (!value){
- NodeBuilder<> conflict(kind::AND);
-
- if(rule->directrr){
- explainInstantiation(inst,
- rule->guards.size() > 0?
- inst->substNode(*this,rule->guards[0],cache) : equality[0],
- conflict);
- if(rule->guards.size() > 0){
- //reduction rule
- Assert(rule->guards.size() == 1);
- conflict << inst->d_matched; //this one will be two times
- }
- }
- substGuards(inst,cache,conflict);
- conflict << lemma_lit;
- getOutputChannel().conflict(normalizeConjunction(conflict));
- };
- }else{
- getOutputChannel().propagate(lemma_lit);
- d_explanations.insert(lemma_lit, *inst);
- };
- };
-
- if(simulateRewritting){
- static NoMatchAttribute rewrittenNodeAttribute;
- // Tag the rewritted terms
- // for(std::vector<Node>::iterator i = rule->to_remove.begin();
- // i == rule->to_remove.end(); ++i){
- // (*i).setAttribute(rewrittenNodeAttribute,true);
- // };
- for(size_t i = 0; i < rule->to_remove.size(); ++i){
- Node rewritten = inst->substNode(*this,rule->to_remove[i],cache);
- Debug("rewriterules::simulateRewriting") << "tag " << rewritten << " as rewritten" << std::endl;
- rewritten.setAttribute(rewrittenNodeAttribute,true);
- };
-
- };
-
- if ( compute_opt && !rule->body_match.empty() ){
-
- uf::TheoryUF* uf = static_cast<uf::TheoryUF *>(getQuantifiersEngine()->getTheoryEngine()->theoryOf( theory::THEORY_UF ));
- eq::EqualityEngine* ee =
- static_cast<eq::EqualityEngine*>(uf->getEqualityEngine());
-
- //Verify that this instantiation can't immediately fire another rule
- for(RewriteRule::BodyMatch::const_iterator p = rule->body_match.begin();
- p != rule->body_match.end(); ++p){
- RewriteRule * r = (*p).second;
- // Use trigger2 since we can be in check
- ApplyMatcher * tr = r->trigger_for_body_match;
- Assert(tr != NULL);
- tr->resetInstantiationRound(getQuantifiersEngine());
- rrinst::InstMatch im;
- TNode m = inst->substNode(*this,(*p).first, cache);
- Assert( m.getKind() == kind::APPLY_UF );
- ee->addTerm(m);
- if( tr->reset(m,im,getQuantifiersEngine()) ){
- im.d_matched = m;
- Debug("rewriterules::matching") << "SimulatedRewrite: " << std::endl;
- addMatchRuleTrigger(r, im);
- }
- }
-
- }
-};
-
-void TheoryRewriteRules::substGuards(const RuleInst *inst,
- TCache cache,
- NodeBuilder<> & conjunction){
- const RewriteRule * r = inst->rule;
- /** Guards */ /* TODO remove the duplicate with a set like in uf? */
- for(std::vector<Node>::const_iterator p = r->guards.begin();
- p != r->guards.end(); ++p) {
- Assert(!p->isNull());
- conjunction << inst->substNode(*this,*p,cache);
- };
-}
-
-Node TheoryRewriteRules::explain(TNode n){
- ExplanationMap::const_iterator p = d_explanations.find(n);
- Assert(p!=d_explanations.end(),"I forget the explanation...");
- RuleInst inst = (*p).second;
- const RewriteRule * rule = inst.rule;
- TCache cache;
- NodeBuilder<> explanation(kind::AND);
- if(rule->directrr){
- explainInstantiation(&inst,
- rule->guards.size() > 0?
- inst.substNode(*this,rule->guards[0],cache):
- inst.substNode(*this,rule->body[0] ,cache),
- explanation);
- if(rule->guards.size() > 0){
- //reduction rule
- Assert(rule->guards.size() == 1);
- explanation << inst.d_matched; //this one will be two times
- }
- };
- substGuards(&inst, cache ,explanation);
- return normalizeConjunction(explanation);
-}
-
-void TheoryRewriteRules::collectModelInfo( TheoryModel* m, bool fullModel ){
-
-}
-
-Theory::PPAssertStatus TheoryRewriteRules::ppAssert(TNode in, SubstitutionMap& outSubstitutions) {
- //TODO: here add only to the rewriterules database for ppRewrite,
- //and not for the general one. Otherwise rewriting that occur latter
- //on this rewriterules will be lost. But if the rewriting of the
- //body is not done in "in", will it be done latter after
- //substitution? Perhaps we should add the rewriterules to the
- //database for ppRewrite also after the subtitution at the levvel of check
-
- // addRewriteRule(in);
- // d_ppAssert_on = true;
- return PP_ASSERT_STATUS_UNSOLVED;
-}
-
-TheoryRewriteRules::Statistics::Statistics():
- d_num_rewriterules("TheoryRewriteRules::Num_RewriteRules", 0),
- d_check("TheoryRewriteRules::Check", 0),
- d_full_check("TheoryRewriteRules::FullCheck", 0),
- d_poll("TheoryRewriteRules::Poll", 0),
- d_match_found("TheoryRewriteRules::MatchFound", 0),
- d_cache_hit("TheoryRewriteRules::CacheHit", 0),
- d_cache_miss("TheoryRewriteRules::CacheMiss", 0)
-{
- StatisticsRegistry::registerStat(&d_num_rewriterules);
- StatisticsRegistry::registerStat(&d_check);
- StatisticsRegistry::registerStat(&d_full_check);
- StatisticsRegistry::registerStat(&d_poll);
- StatisticsRegistry::registerStat(&d_match_found);
- StatisticsRegistry::registerStat(&d_cache_hit);
- StatisticsRegistry::registerStat(&d_cache_miss);
-}
-
-TheoryRewriteRules::Statistics::~Statistics(){
- StatisticsRegistry::unregisterStat(&d_num_rewriterules);
- StatisticsRegistry::unregisterStat(&d_check);
- StatisticsRegistry::unregisterStat(&d_full_check);
- StatisticsRegistry::unregisterStat(&d_poll);
- StatisticsRegistry::unregisterStat(&d_match_found);
- StatisticsRegistry::unregisterStat(&d_cache_hit);
- StatisticsRegistry::unregisterStat(&d_cache_miss);
-}
-
-
-}/* CVC4::theory::rewriterules namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
diff --git a/src/theory/rewriterules/theory_rewriterules.h b/src/theory/rewriterules/theory_rewriterules.h
deleted file mode 100644
index 2cefe7f07..000000000
--- a/src/theory/rewriterules/theory_rewriterules.h
+++ /dev/null
@@ -1,288 +0,0 @@
-/********************* */
-/*! \file theory_rewriterules.h
- ** \verbatim
- ** Original author: Morgan Deters
- ** Major contributors: none
- ** Minor contributors (to current version): Andrew Reynolds, Francois Bobot
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Rewrite Engine classes
- **/
-
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_H
-#define __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_H
-
-#include "context/cdlist.h"
-#include "context/cdqueue.h"
-#include "theory/valuation.h"
-#include "theory/theory.h"
-#include "theory/theory_engine.h"
-#include "theory/quantifiers_engine.h"
-#include "context/context_mm.h"
-#include "theory/rewriterules/rr_inst_match_impl.h"
-#include "theory/rewriterules/rr_trigger.h"
-#include "theory/rewriterules/rr_inst_match.h"
-#include "util/statistics_registry.h"
-#include "theory/rewriterules/theory_rewriterules_preprocess.h"
-
-namespace CVC4 {
-namespace theory {
-namespace rewriterules {
-using namespace CVC4::theory::rrinst;
-typedef CVC4::theory::rrinst::Trigger Trigger;
-
-typedef std::hash_map<TNode, TNode, TNodeHashFunction> TCache;
-
- enum Answer {ATRUE, AFALSE, ADONTKNOW};
-
- class TheoryRewriteRules; /** forward */
-
- class RewriteRule{
- public:
- // constant
- const size_t id; //for debugging
- const bool d_split;
- mutable Trigger trigger;
- std::vector<Node> guards;
- mutable std::vector<Node> to_remove; /** terms to remove */
- const Node body;
- const TNode new_terms; /** new terms included in the body */
- std::vector<Node> free_vars; /* free variable in the rule */
- std::vector<Node> inst_vars; /* corresponding vars in the triggers */
- /* After instantiating the body new match can appear (TNode
- because is a subterm of a body on the assicaited rewrite
- rule) */
- typedef context::CDList< std::pair<TNode,RewriteRule* > > BodyMatch;
- mutable BodyMatch body_match;
- mutable ApplyMatcher * trigger_for_body_match; // used because we can be matching
- // trigger when we need new match.
- // So currently we use another
- // trigger for that.
-
- //context dependent
- typedef InstMatchTrie2<true> CacheNode;
- mutable CacheNode d_cache;
-
- const bool directrr;
-
- RewriteRule(TheoryRewriteRules & re,
- Trigger & tr, ApplyMatcher * tr2,
- std::vector<Node> & g, Node b, TNode nt,
- std::vector<Node> & fv,std::vector<Node> & iv,
- std::vector<Node> & to_r, bool drr);
- RewriteRule(const RewriteRule & r) CVC4_UNUSED;
- RewriteRule& operator=(const RewriteRule &) CVC4_UNUSED;
- ~RewriteRule();
-
- bool noGuard()const throw () { return guards.size() == 0; };
- bool inCache(TheoryRewriteRules & re, rrinst::InstMatch & im)const;
-
- void toStream(std::ostream& out) const;
-
- /* statistics */
- mutable size_t nb_matched;
- mutable size_t nb_applied;
- mutable size_t nb_propagated;
-
- };
-
- class RuleInst{
- public:
- /** The rule has at least one guard */
- const RewriteRule* rule;
-
- /** the substitution */
- std::vector<Node> subst;
-
- /** the term matched (not null if mono-pattern and direct-rr) */
- Node d_matched;
-
- /** Rule an instantiation with the given match */
- RuleInst(TheoryRewriteRules & re, const RewriteRule* r,
- std::vector<Node> & inst_subst,
- Node matched);
- RuleInst():rule(NULL){} // Dumb
-
- Node substNode(const TheoryRewriteRules & re, TNode r, TCache cache) const;
- size_t findGuard(TheoryRewriteRules & re, size_t start)const;
-
- void toStream(std::ostream& out) const;
-
- bool alreadyRewritten(TheoryRewriteRules & re) const;
- };
-
-/** A pair? */
- class Guarded {
- public:
- /** The backtracking is done somewhere else */
- const size_t d_guard; /* the id of the guard */
-
- /** The shared instantiation data */
- const RuleInst* inst;
-
- void nextGuard(TheoryRewriteRules & re)const;
-
- /** start indicate the first guard which is not true */
- Guarded(const RuleInst* ri, const size_t start);
- Guarded(const Guarded & g);
- /** Should be ssigned by a good garded after */
- Guarded();
-
- ~Guarded(){};
- void destroy(){};
- };
-
-template<class T>
-class CleanUpPointer{
-public:
- inline void operator()(T** e){
- delete(*e);
- };
-};
-
-class TheoryRewriteRules : public Theory {
-private:
-
- KEEP_STATISTIC(TimerStat, d_theoryTime, "theory::rewriterules::theoryTime");
-
- /** list of all rewrite rules */
- /* std::vector< Node > d_rules; */
- // typedef std::vector< std::pair<Node, Trigger > > Rules;
- typedef context::CDList< RewriteRule *,
- CleanUpPointer<RewriteRule >,
- std::allocator< RewriteRule * > > Rules;
- Rules d_rules;
- typedef context::CDList< RuleInst *,
- CleanUpPointer<RuleInst>,
- std::allocator< RuleInst * > > RuleInsts;
- RuleInsts d_ruleinsts;
-
- /** The GList* will lead too memory leaks since that doesn't use
- CDChunckList */
- typedef context::CDList< Guarded > GList;
- typedef context::CDHashMap<Node, GList *, NodeHashFunction> GuardedMap;
- GuardedMap d_guardeds;
-
- /* In order to not monopolize, the system slow down himself: If a
- guard stored in d_guardeds become true or false, it waits
- checkSlowdown(=10) checks before checking again if some guard take a
- value. At FULL_EFFORT regardless of d_checkLevel it check the
- guards
- */
- context::CDO<size_t> d_checkLevel;
-
- /** explanation */
- typedef context::CDHashMap<Node, RuleInst , NodeHashFunction> ExplanationMap;
- ExplanationMap d_explanations;
-
- /** new instantiation must be cleared at each conflict used only
- inside check */
- typedef std::vector< RuleInst* > QRuleInsts;
- QRuleInsts d_ruleinsts_to_add;
- bool d_ppAssert_on; //Indicate if a ppAssert have been done
-
- public:
- /** true and false for predicate */
- Node d_true;
- Node d_false;
-
- /** Constructs a new instance of TheoryRewriteRules
- w.r.t. the provided context.*/
- TheoryRewriteRules(context::Context* c,
- context::UserContext* u,
- OutputChannel& out,
- Valuation valuation,
- const LogicInfo& logicInfo);
-
- /** Usual function for theories */
- void check(Theory::Effort e);
- Node explain(TNode n);
- void collectModelInfo( TheoryModel* m, bool fullModel );
- void notifyEq(TNode lhs, TNode rhs);
- std::string identify() const {
- return "THEORY_REWRITERULES";
- }
-
- Theory::PPAssertStatus ppAssert(TNode in, SubstitutionMap& outSubstitutions);
-
- bool ppDontRewriteSubterm(TNode atom) { return true; }
-
-
- private:
- void registerQuantifier( Node n );
-
- public:
- /* TODO modify when notification will be available */
- void notification( Node n, bool b);
-
- Trigger createTrigger( TNode n, std::vector<Node> & pattern );
-
- /** return if the guard (already substituted) is known true or false
- or unknown. In the last case it add the Guarded(rid,gid) to the watch
- list of this guard */
- Answer addWatchIfDontKnow(Node g, const RuleInst* r, const size_t gid);
-
- /** An instantiation of a rule is fired (all guards true) we
- propagate the body. That can be done by theory propagation if
- possible or by lemmas.
- */
- void propagateRule(const RuleInst * r, TCache cache);
-
- /** Auxiliary functions */
-private:
- /** A guard is verify, notify the Guarded */
- void notification(GList * const lpropa, bool b);
- /* If two guards becomes equals we should notify if one of them is
- already true */
- bool notifyIfKnown(const GList * const ltested, GList * const lpropa);
-
- void substGuards(const RuleInst * inst,
- TCache cache,
- NodeBuilder<> & conjunction);
-
- void addRewriteRule(const Node r);
- void computeMatchBody ( const RewriteRule * r, size_t start = 0);
- void addMatchRuleTrigger(const RewriteRule* r,
- rrinst::InstMatch & im, bool delay = true);
-
- Node normalizeConjunction(NodeBuilder<> & conjunction);
-
- /* rewrite pattern */
- typedef std::hash_map< Node, rewriter::RRPpRewrite*, NodeHashFunction > RegisterRRPpRewrite;
- RegisterRRPpRewrite d_registeredRRPpRewrite;
-
- bool addRewritePattern(TNode pattern, TNode body,
- rewriter::Subst & pvars,
- rewriter::Subst & vars);
-
- //create inst variable
- std::vector<Node> createInstVariable( Node r, std::vector<Node> & vars );
-
- /** statistics class */
- class Statistics {
- public:
- IntStat d_num_rewriterules;
- IntStat d_check;
- IntStat d_full_check;
- IntStat d_poll;
- IntStat d_match_found;
- IntStat d_cache_hit;
- IntStat d_cache_miss;
- Statistics();
- ~Statistics();
- };
- Statistics d_statistics;
-
-};/* class TheoryRewriteRules */
-
-}/* CVC4::theory::rewriterules namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_H */
diff --git a/src/theory/rewriterules/theory_rewriterules_params.h b/src/theory/rewriterules/theory_rewriterules_params.h
deleted file mode 100644
index e20556ef3..000000000
--- a/src/theory/rewriterules/theory_rewriterules_params.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/********************* */
-/*! \file theory_rewriterules_params.h
- ** \verbatim
- ** Original author: Morgan Deters
- ** Major contributors: none
- ** Minor contributors (to current version): Francois Bobot
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Parameters for the rewrite rules theory
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_PARAMS_H
-#define __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_PARAMS_H
-
-namespace CVC4 {
-namespace theory {
-namespace rewriterules {
-
-/**
- Specify if the propagation is done by lemma or by real theory propagation
- */
-static const bool propagate_as_lemma = true;
-
-/**
- Cache the instantiation of rules in order to remove duplicate
- */
-static const bool cache_match = true;
-
-/**
- Compute when the rules are created which terms in the body can lead
- to new instantiation (try only single trigger). During propagation
- we check if the instantiation of these terms are known terms.
- */
-static const bool compute_opt = true;
-
-/**
- rewrite the matching found
- */
-static const bool rewrite_instantiation = true;
-
-/**
- use the representative for the matching found
- */
-static const bool representative_instantiation = false;
-
-/**
- Wait the specified number of check after a new propagation (a
- previous unknown guards becomes true) is found before verifying again the guards.
-
- Allow to break loop with other theories.
- */
-static const size_t checkSlowdown = 0;
-
-/**
- Use the current model to eliminate guard before asking for notification
- */
-static const bool useCurrentModel = false;
-
-/**
- Simulate rewriting by tagging rewritten terms.
- */
-static const bool simulateRewritting = true;
-
-/**
- Do narrowing at full effort
-*/
-static const bool narrowing_full_effort = false;
-
-/**
- Direct rewrite: Add rewrite rules directly in the rewriter.
- */
-static const bool direct_rewrite = false;
-
-}/* CVC4::theory::rewriterules namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_PARAMS_H */
diff --git a/src/theory/rewriterules/theory_rewriterules_preprocess.h b/src/theory/rewriterules/theory_rewriterules_preprocess.h
deleted file mode 100644
index cc24357c6..000000000
--- a/src/theory/rewriterules/theory_rewriterules_preprocess.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/********************* */
-/*! \file theory_rewriterules_preprocess.h
- ** \verbatim
- ** Original author: Morgan Deters
- ** Major contributors: none
- ** Minor contributors (to current version): Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief One utilitise for rewriterules definition
- **
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_PREPROCESS_H
-#define __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_PREPROCESS_H
-
-#include <vector>
-#include <ext/hash_set>
-#include <ext/hash_map>
-#include "expr/expr.h"
-#include "expr/node.h"
-#include "theory/rewriterules/theory_rewriterules_params.h"
-#include "theory/uf/theory_uf.h"
-
-namespace CVC4 {
-namespace theory {
-namespace rewriterules {
-
-namespace rewriter {
-
- typedef Node TMPNode;
- typedef std::vector<Node> Subst;
- typedef std::vector<Expr> ESubst;
- typedef std::vector<TMPNode> TSubst;
-
- struct Step{
-
- /** match the node and add in Vars the found variables */
- virtual Node run(TMPNode node) = 0;
- virtual bool add(TMPNode pattern, TMPNode body, Subst & pvars, Subst & vars) = 0;
- };/* struct Step */
-
- struct FinalStep : Step {
- Node body;
- TSubst vars;
-
- Node subst(Subst & subst){
- return body.substitute(vars.begin(), vars.end(),
- subst.begin(), subst.end());
- }
-
- };/* struct FinalStep */
-
- typedef std::hash_map< Node, int, NodeHashFunction > PVars;
-
- struct Pattern : FinalStep{
- Node pattern;
- PVars pattern_vars;
-
- Node run(TMPNode node){
- Subst vars = Subst(pattern_vars.size(),Node::null());
-
- typedef std::vector<std::pair<TMPNode,TMPNode> > tstack;
- tstack stack(1,std::make_pair(node,pattern)); // t * pat
-
- while(!stack.empty()){
- const std::pair<TMPNode,TMPNode> p = stack.back(); stack.pop_back();
- const TMPNode & t = p.first;
- const TMPNode & pat = p.second;
-
- // pat is a variable
- if( pat.getKind() == kind::INST_CONSTANT ||
- pat.getKind() == kind::VARIABLE){
- PVars::iterator i = pattern_vars.find(pat);
- Assert(i != pattern_vars.end());
- if(vars[i->second].isNull()) vars[i->second] = t;
- if(vars[i->second] == t) continue;
- return Node::null();
- };
-
- // t is not an UF application
- if( t.getKind() != kind::APPLY_UF ){
- if (t == pat) continue;
- else return Node::null();
- };
-
- //different UF_application
- if( t.getOperator() != pat.getOperator() ) return Node::null();
-
- //put the children on the stack
- for( size_t i=0; i < pat.getNumChildren(); i++ ){
- stack.push_back(std::make_pair(t[i],pat[i]));
- };
- }
-
- // Matching is done
- return subst(vars);
- }
-
- bool add(TMPNode pattern, TMPNode body, Subst & pvars, Subst & vars){
- return false;
- }
-
- };/* struct Pattern */
-
-
- struct Args : Step {
- typedef std::vector<Pattern> Patterns;
- Patterns d_matches;
-
- Node run(TMPNode node){
- Node n;
- for (Patterns::iterator i = d_matches.begin();
- i != d_matches.end() && n.isNull(); ++i){
- Debug("rewriterules-rewrite") << "test?" << i->pattern << std::endl;
- n = i->run(node);
- }
- return n;
- }
-
- bool add(TMPNode pattern, TMPNode body, Subst & pvars, Subst & vars){
- Debug("rewriterules-rewrite") << "theoryrewrite::Args::add" << "("
- << d_matches.size() << ")"
- << pattern << "->" << body << std::endl;
- d_matches.push_back(Pattern());
- Pattern & p = d_matches.back();
- p.body = body;
- p.vars.reserve(vars.size());
- for( size_t i=0; i < vars.size(); i++ ){
- p.vars.push_back(vars[i]);
- };
- p.pattern = pattern;
- for( size_t i=0; i < pvars.size(); i++ ){
- p.pattern_vars[pvars[i]] = i;
- };
- return true;
- };
-
- void clear(){
- d_matches.clear();
- }
- };/* struct Args */
-
-class RRPpRewrite : public uf::TheoryUF::PpRewrite {
- Args d_pattern;
-public:
- Node ppRewrite(TNode node){
- Debug("rewriterules-rewrite") << "rewrite?" << node << std::endl;
- Node t = d_pattern.run(node);
- Debug("rewriterules-rewrite") << "rewrite:" << node
- << (t.isNull()? " to": " to ")
- << t << std::endl;
- if (t.isNull()) return node;
- else return t;
- }
-
- bool addRewritePattern(TMPNode pattern, TMPNode body,
- Subst & pvars, Subst & vars){
- return d_pattern.add(pattern,body,pvars,vars);
- }
-
-};/* class RRPpRewrite */
-
-
-
-}/* CVC4::theory::rewriterules::rewriter namespace */
-
-}/* CVC4::theory::rewriterules namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_PREPROCESS_H */
diff --git a/src/theory/rewriterules/theory_rewriterules_rewriter.h b/src/theory/rewriterules/theory_rewriterules_rewriter.h
deleted file mode 100644
index 511ef3515..000000000
--- a/src/theory/rewriterules/theory_rewriterules_rewriter.h
+++ /dev/null
@@ -1,115 +0,0 @@
-/********************* */
-/*! \file theory_rewriterules_rewriter.h
- ** \verbatim
- ** Original author: Morgan Deters
- ** Major contributors: none
- ** Minor contributors (to current version): Tim King
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_REWRITER_H
-#define __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_REWRITER_H
-
-#include "theory/rewriter.h"
-#include "theory/rewriter_attributes.h"
-
-namespace CVC4 {
-namespace theory {
-namespace rewriterules {
-
-class TheoryRewriterulesRewriter {
-public:
-
- /**
- * Rewrite a node into the normal form for the theory of rewriterules.
- * Called in post-order (really reverse-topological order) when
- * traversing the expression DAG during rewriting. This is the
- * main function of the rewriter, and because of the ordering,
- * it can assume its children are all rewritten already.
- *
- * This function can return one of three rewrite response codes
- * along with the rewritten node:
- *
- * REWRITE_DONE indicates that no more rewriting is needed.
- * REWRITE_AGAIN means that the top-level expression should be
- * rewritten again, but that its children are in final form.
- * REWRITE_AGAIN_FULL means that the entire returned expression
- * should be rewritten again (top-down with preRewrite(), then
- * bottom-up with postRewrite()).
- *
- * Even if this function returns REWRITE_DONE, if the returned
- * expression belongs to a different theory, it will be fully
- * rewritten by that theory's rewriter.
- */
- static RewriteResponse postRewrite(TNode node) {
-
- // Implement me!
-
- // This default implementation
- return RewriteResponse(REWRITE_DONE, node);
- }
-
- /**
- * Rewrite a node into the normal form for the theory of rewriterules
- * in pre-order (really topological order)---meaning that the
- * children may not be in the normal form. This is an optimization
- * for theories with cancelling terms (e.g., 0 * (big-nasty-expression)
- * in arithmetic rewrites to 0 without the need to look at the big
- * nasty expression). Since it's only an optimization, the
- * implementation here can do nothing.
- */
- static RewriteResponse preRewrite(TNode node) {
- // do nothing
- return RewriteResponse(REWRITE_DONE, node);
- }
-
- /**
- * Initialize the rewriter.
- */
- static inline void init() {
- // nothing to do
- }
-
- /**
- * Shut down the rewriter.
- */
- static inline void shutdown() {
- // nothing to do
- }
-
-};/* class TheoryRewriterulesRewriter */
-
-}/* CVC4::theory::rewriterules namespace */
-
-template<>
-struct RewriteAttibute<THEORY_REWRITERULES> {
- static Node getPreRewriteCache(TNode node) throw() {
- return node;
- }
-
- static void setPreRewriteCache(TNode node, TNode cache) throw() { }
-
- static Node getPostRewriteCache(TNode node) throw() {
- return node;
- }
-
- static void setPostRewriteCache(TNode node, TNode cache) throw() { }
-
- typedef expr::Attribute< RewriteCacheTag<true, THEORY_REWRITERULES>, Node> pre_rewrite;
- typedef expr::Attribute< RewriteCacheTag<false, THEORY_REWRITERULES>, Node> post_rewrite;
-};
-
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_REWRITER_H */
diff --git a/src/theory/rewriterules/theory_rewriterules_rules.cpp b/src/theory/rewriterules/theory_rewriterules_rules.cpp
deleted file mode 100644
index 38e22ed64..000000000
--- a/src/theory/rewriterules/theory_rewriterules_rules.cpp
+++ /dev/null
@@ -1,403 +0,0 @@
-/********************* */
-/*! \file theory_rewriterules_rules.cpp
- ** \verbatim
- ** Original author: Morgan Deters
- ** Major contributors: Francois Bobot
- ** Minor contributors (to current version): Andrew Reynolds
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief [[ Deals with rewrite rules ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#include "theory/rewriterules/theory_rewriterules_rules.h"
-#include "theory/rewriterules/theory_rewriterules_params.h"
-#include "theory/rewriterules/theory_rewriterules_preprocess.h"
-#include "theory/rewriterules/theory_rewriterules.h"
-#include "theory/rewriterules/options.h"
-
-#include "theory/quantifiers/term_database.h"
-
-using namespace std;
-using namespace CVC4;
-using namespace CVC4::kind;
-using namespace CVC4::context;
-using namespace CVC4::theory;
-using namespace CVC4::theory::rewriterules;
-using namespace CVC4::theory::rrinst;
-
-
-namespace CVC4 {
-namespace theory {
-namespace rewriterules {
-
-// TODO replace by a real dictionnary
-// We should create a real substitution? slower more precise
-// We don't do that often
-bool nonunifiable( TNode t0, TNode pattern, const std::vector<Node> & vars){
- typedef std::vector<std::pair<TNode,TNode> > tstack;
- tstack stack(1,std::make_pair(t0,pattern)); // t * pat
-
- while(!stack.empty()){
- const std::pair<TNode,TNode> p = stack.back(); stack.pop_back();
- const TNode & t = p.first;
- const TNode & pat = p.second;
-
- // t or pat is a variable currently we consider that can match anything
- if( find(vars.begin(),vars.end(),t) != vars.end() ) continue;
- if( pat.getKind() == INST_CONSTANT ) continue;
-
- // t and pat are nonunifiable
- if( !Trigger::isAtomicTrigger( t ) || !Trigger::isAtomicTrigger( pat ) ) {
- if(t == pat) continue;
- else return true;
- };
- if( t.getOperator() != pat.getOperator() ) return true;
-
- //put the children on the stack
- for( size_t i=0; i < pat.getNumChildren(); i++ ){
- stack.push_back(std::make_pair(t[i],pat[i]));
- };
- }
- // The heuristic can't find non-unifiability
- return false;
-}
-
-
-void TheoryRewriteRules::computeMatchBody ( const RewriteRule * rule,
- size_t start){
- std::vector<TNode> stack(1,rule->new_terms);
-
- while(!stack.empty()){
- Node t = stack.back(); stack.pop_back();
-
- // We don't want to consider variable in t
- if( std::find(rule->free_vars.begin(), rule->free_vars.end(), t)
- != rule->free_vars.end()) continue;
- // t we want to consider only UF function
- if( t.getKind() == APPLY_UF ){
- for(size_t rid = start, end = d_rules.size(); rid < end; ++rid) {
- RewriteRule * r = d_rules[rid];
- if(r->d_split || r->trigger_for_body_match == NULL) continue;
- //the split rules are not computed and the one with multi-pattern
- if( !nonunifiable(t, r->trigger_for_body_match->d_pattern, rule->free_vars)){
- rule->body_match.push_back(std::make_pair(t,r));
- }
- }
- }
-
- //put the children on the stack
- for( size_t i=0; i < t.getNumChildren(); i++ ){
- stack.push_back(t[i]);
- };
-
- }
-}
-
-inline void addPattern(TheoryRewriteRules & re,
- TNode tri,
- std::vector<Node> & pattern,
- std::vector<Node> & vars,
- std::vector<Node> & inst_constants,
- TNode r){
- if (tri.getKind() == kind::NOT && tri[0].getKind() == kind::APPLY_UF)
- tri = tri[0];
- pattern.push_back(
- options::rewriteRulesAsAxioms()?
- static_cast<Node>(tri):
- re.getQuantifiersEngine()->getTermDatabase()->
- convertNodeToPattern(tri,r,vars,inst_constants));
-}
-
-/*** Check that triggers contains all the variables */
-void checkPatternVarsAux(TNode pat,const std::vector<Node> & vars,
- std::vector<bool> & seen){
- for(size_t id=0;id < vars.size(); ++id){
- if(pat == vars[id]){
- seen[id]=true;
- break;
- };
- };
- for(Node::iterator i = pat.begin(); i != pat.end(); ++i) {
- checkPatternVarsAux(*i,vars,seen);
- };
-}
-
-bool checkPatternVars(const std::vector<Node> & pattern,
- const std::vector<Node> & vars){
- std::vector<bool> seen(vars.size(),false);
- for(std::vector<Node>::const_iterator i = pattern.begin();
- i != pattern.end(); ++i) {
- checkPatternVarsAux(*i,vars,seen);
- };
- return (find(seen.begin(),seen.end(),false) == seen.end());
-}
-
-/** Main function for construction of RewriteRule */
-void TheoryRewriteRules::addRewriteRule(const Node r)
-{
- Assert(r.getKind() == kind::REWRITE_RULE);
- Kind rrkind = r[2].getKind();
- /* Replace variables by Inst_* variable and tag the terms that
- contain them */
- std::vector<Node> vars;
- vars.reserve(r[0].getNumChildren());
- for( Node::const_iterator v = r[0].begin(); v != r[0].end(); ++v ){
- vars.push_back(*v);
- };
- /* Instantiation version */
- std::vector<Node> inst_constants = createInstVariable(r,vars);
- /* Body/Remove_term/Guards/Triggers */
- Node body = r[2][1];
- TNode new_terms = r[2][1];
- std::vector<Node> guards;
- std::vector<Node> pattern;
- std::vector<Node> to_remove; /* "remove" the terms from the database
- when fired */
- /* shortcut */
- TNode head = r[2][0];
- TypeNode booleanType = NodeManager::currentNM()->booleanType();
- switch(rrkind){
- case kind::RR_REWRITE:
- /* Equality */
- to_remove.push_back(head);
- addPattern(*this,head,pattern,vars,inst_constants,r);
- if(head.getType(false) == booleanType) body = head.iffNode(body);
- else body = head.eqNode(body);
- break;
- case kind::RR_REDUCTION:
- /** Add head to remove */
- for(Node::iterator i = head.begin(); i != head.end(); ++i) {
- to_remove.push_back(*i);
- };
- case kind::RR_DEDUCTION:
- /** Add head to guards and pattern */
- switch(head.getKind()){
- case kind::AND:
- guards.reserve(head.getNumChildren());
- for(Node::iterator i = head.begin(); i != head.end(); ++i) {
- guards.push_back(*i);
- addPattern(*this,*i,pattern,vars,inst_constants,r);
- };
- break;
- default:
- if (head != d_true){
- guards.push_back(head);
- addPattern(*this,head,pattern,vars,inst_constants,r);
- };
- /** otherwise guards is empty */
- };
- break;
- default:
- Unreachable("RewriteRules can be of only three kinds");
- };
- /* Add the other guards */
- TNode g = r[1];
- switch(g.getKind()){
- case kind::AND:
- guards.reserve(g.getNumChildren());
- for(Node::iterator i = g.begin(); i != g.end(); ++i) {
- guards.push_back(*i);
- };
- break;
- default:
- if (g != d_true) guards.push_back(g);
- /** otherwise guards is empty */
- };
- /* Add the other triggers */
- if( r[2].getNumChildren() >= 3 )
- for(Node::iterator i = r[2][2][0].begin(); i != r[2][2][0].end(); ++i) {
- // todo test during typing that its a good term (no not, atom, or term...)
- addPattern(*this,*i,pattern,vars,inst_constants,r);
- };
- // Assert(pattern.size() == 1, "currently only single pattern are supported");
-
-
-
-
- //If we convert to usual axioms
- if(options::rewriteRulesAsAxioms()){
- NodeBuilder<> forallB(kind::FORALL);
- forallB << r[0];
- NodeBuilder<> guardsB(kind::AND);
- guardsB.append(guards);
- forallB << normalizeConjunction(guardsB).impNode(body);
- NodeBuilder<> patternB(kind::INST_PATTERN);
- patternB.append(pattern);
- NodeBuilder<> patternListB(kind::INST_PATTERN_LIST);
- patternListB << static_cast<Node>(patternB);
- forallB << static_cast<Node>(patternListB);
- Node lem = (Node) forallB;
- lem = Rewriter::rewrite(lem);
- QRewriteRuleAttribute qra;
- lem.setAttribute(qra,r);
- getOutputChannel().lemma(lem);
- return;
- }
-
- //turn all to propagate
- // if(true){
- // NodeBuilder<> guardsB(kind::AND);
- // guardsB.append(guards);
- // body = normalizeConjunction(guardsB).impNode(body);
- // guards.clear();
- // rrkind = kind::RR_DEDUCTION;
- // }
-
-
- //Every variable must be seen in the pattern
- if (!checkPatternVars(pattern,inst_constants)){
- Warning() << Node::setdepth(-1) << "The rule" << r <<
- " has been removed since it doesn't contain every variables."
- << std::endl;
- return;
- }
-
-
- //Add to direct rewrite rule
- bool directrr = false;
- if(direct_rewrite &&
- guards.size() == 0 && rrkind == kind::RR_REWRITE
- && pattern.size() == 1){
- directrr = addRewritePattern(pattern[0],new_terms, inst_constants, vars);
- }
-
-
- // final construction
- Trigger trigger = createTrigger(r,pattern);
- ApplyMatcher * applymatcher =
- pattern.size() == 1 && pattern[0].getKind() == kind::APPLY_UF?
- new ApplyMatcher(pattern[0],getQuantifiersEngine()) : NULL;
- RewriteRule * rr = new RewriteRule(*this, trigger, applymatcher,
- guards, body, new_terms,
- vars, inst_constants, to_remove,
- directrr);
- /** other -> rr */
- if(compute_opt && !rr->d_split) computeMatchBody(rr);
- d_rules.push_back(rr);
- /** rr -> all (including himself) */
- if(compute_opt && !rr->d_split)
- for(size_t rid = 0, end = d_rules.size(); rid < end; ++rid)
- computeMatchBody(d_rules[rid],
- d_rules.size() - 1);
-
- Debug("rewriterules::new") << "created rewriterule"<< (rr->d_split?"(split)":"") << ":(" << d_rules.size() - 1 << ")"
- << *rr << std::endl;
-
-}
-
-
-bool willDecide(TNode node, bool positive = true){
- /* TODO something better */
- switch(node.getKind()) {
- case AND:
- return !positive;
- case OR:
- return positive;
- case IFF:
- return true;
- case XOR:
- return true;
- case IMPLIES:
- return true;
- case ITE:
- return true;
- case NOT:
- return willDecide(node[0],!positive);
- default:
- return false;
- }
-}
-
-static size_t id_next = 0;
-RewriteRule::RewriteRule(TheoryRewriteRules & re,
- Trigger & tr, ApplyMatcher * applymatcher,
- std::vector<Node> & g, Node b, TNode nt,
- std::vector<Node> & fv,std::vector<Node> & iv,
- std::vector<Node> & to_r, bool drr) :
- id(++id_next), d_split(willDecide(b)),
- trigger(tr), body(b), new_terms(nt), free_vars(), inst_vars(),
- body_match(re.getSatContext()),trigger_for_body_match(applymatcher),
- d_cache(re.getSatContext(),re.getQuantifiersEngine()), directrr(drr){
- free_vars.swap(fv); inst_vars.swap(iv); guards.swap(g); to_remove.swap(to_r);
-};
-
-
-bool RewriteRule::inCache(TheoryRewriteRules & re, rrinst::InstMatch & im)const{
- bool res = !d_cache.addInstMatch(im);
- Debug("rewriterules::matching") << "rewriterules::cache " << im
- << (res ? " HIT" : " MISS") << std::endl;
- return res;
-};
-
-/** A rewrite rule */
-void RewriteRule::toStream(std::ostream& out) const{
- out << "[" << id << "] ";
- for(std::vector<Node>::const_iterator
- iter = guards.begin(); iter != guards.end(); ++iter){
- out << *iter;
- };
- out << "=>" << body << std::endl;
- out << "{";
- for(BodyMatch::const_iterator
- iter = body_match.begin(); iter != body_match.end(); ++iter){
- out << (*iter).first << "[" << (*iter).second->id << "]" << ",";
- };
- out << "}" << (directrr?"*":"") << std::endl;
-}
-
-RewriteRule::~RewriteRule(){
- Debug("rewriterule::stats") << *this
- << " (" << nb_matched
- << "," << nb_applied
- << "," << nb_propagated
- << ")" << std::endl;
- delete(trigger_for_body_match);
-}
-
-bool TheoryRewriteRules::addRewritePattern(TNode pattern, TNode body,
- rewriter::Subst & pvars,
- rewriter::Subst & vars){
- Assert(pattern.getKind() == kind::APPLY_UF);
- TNode op = pattern.getOperator();
- TheoryRewriteRules::RegisterRRPpRewrite::iterator i =
- d_registeredRRPpRewrite.find(op);
-
- rewriter::RRPpRewrite * p;
- if (i == d_registeredRRPpRewrite.end()){
- p = new rewriter::RRPpRewrite();
- d_registeredRRPpRewrite.insert(std::make_pair(op,p));
- ((uf::TheoryUF*)getQuantifiersEngine()->getTheoryEngine()->theoryOf( THEORY_UF ))->
- registerPpRewrite(op,p);
- } else p = i->second;
-
- return p->addRewritePattern(pattern,body,pvars,vars);
-
-}
-
-std::vector<Node> TheoryRewriteRules::createInstVariable( Node r, std::vector<Node> & vars ){
- std::vector<Node> inst_constant;
- inst_constant.reserve(vars.size());
- for( std::vector<Node>::const_iterator v = vars.begin();
- v != vars.end(); ++v ){
- //make instantiation constants
- Node ic = NodeManager::currentNM()->mkInstConstant( (*v).getType() );
- inst_constant.push_back( ic );
- InstConstantAttribute ica;
- ic.setAttribute(ica,r);
- //also set the no-match attribute
- NoMatchAttribute nma;
- ic.setAttribute(nma,true);
- };
- return inst_constant;
-}
-
-
-}/* CVC4::theory::rewriterules namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
diff --git a/src/theory/rewriterules/theory_rewriterules_rules.h b/src/theory/rewriterules/theory_rewriterules_rules.h
deleted file mode 100644
index 308194667..000000000
--- a/src/theory/rewriterules/theory_rewriterules_rules.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/********************* */
-/*! \file theory_rewriterules_rules.h
- ** \verbatim
- ** Original author: Morgan Deters
- ** Major contributors: none
- ** Minor contributors (to current version): none
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Rewrite Engine classes
- **/
-
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_RULES_H
-#define __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_RULES_H
-
-#include "theory/rewriterules/theory_rewriterules.h"
-#include "theory/rewriterules/theory_rewriterules_params.h"
-
-namespace CVC4 {
-namespace theory {
-namespace rewriterules {
-
-inline std::ostream& operator <<(std::ostream& stream, const RewriteRule& r) {
- r.toStream(stream);
- return stream;
-}
-
-}/* CVC4::theory::rewriterules namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_RULES_H */
diff --git a/src/theory/rewriterules/theory_rewriterules_type_rules.h b/src/theory/rewriterules/theory_rewriterules_type_rules.h
deleted file mode 100644
index fa6bb2227..000000000
--- a/src/theory/rewriterules/theory_rewriterules_type_rules.h
+++ /dev/null
@@ -1,117 +0,0 @@
-/********************* */
-/*! \file theory_rewriterules_type_rules.h
- ** \verbatim
- ** Original author: Morgan Deters
- ** Major contributors: none
- ** Minor contributors (to current version): Francois Bobot
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2013 New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief [[ Add one-line brief description here ]]
- **
- ** [[ Add lengthier description here ]]
- ** \todo document this file
- **/
-
-#include "cvc4_private.h"
-
-#ifndef __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_TYPE_RULES_H
-#define __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_TYPE_RULES_H
-
-#include "node_manager.h"
-
-namespace CVC4 {
-namespace theory {
-namespace rewriterules {
-
-class RewriteRuleTypeRule {
-public:
-
- /**
- * Compute the type for (and optionally typecheck) a term belonging
- * to the theory of rewriterules.
- *
- * @param nodeManager the NodeManager in use
- * @param n the node to compute the type of
- * @param check if true, the node's type should be checked as well
- * as computed.
- */
- inline static TypeNode computeType(NodeManager* nodeManager, TNode n,
- bool check)
- throw(TypeCheckingExceptionPrivate) {
- Debug("typecheck-r") << "type check for rr " << n << std::endl;
- Assert(n.getKind() == kind::REWRITE_RULE && n.getNumChildren()==3 );
- if( check ){
- if( n[ 0 ].getType(check)!=nodeManager->boundVarListType() ){
- throw TypeCheckingExceptionPrivate(n[0],
- "first argument of rewrite rule is not bound var list");
- }
- if( n[ 1 ].getType(check)!=nodeManager->booleanType() ){
- throw TypeCheckingExceptionPrivate(n[1],
- "guard of rewrite rule is not an actual guard");
- }
- if( n[2].getType(check) !=
- TypeNode(nodeManager->mkTypeConst<TypeConstant>(RRHB_TYPE))){
- throw TypeCheckingExceptionPrivate(n[2],
- "not a correct rewrite rule");
- }
- }
- return nodeManager->booleanType();
- }
-};/* class RewriteRuleTypeRule */
-
-
-class RRRewriteTypeRule {
-public:
-
- inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
- throw(TypeCheckingExceptionPrivate) {
- Assert(n.getKind() == kind::RR_REWRITE );
- if( check ){
- if( n[0].getType(check)!=n[1].getType(check) ){
- throw TypeCheckingExceptionPrivate(n,
- "terms of rewrite rule are not equal");
- }
- if( n.getNumChildren() == 3 && n[2].getType(check)!=nodeManager->instPatternListType() ){
- throw TypeCheckingExceptionPrivate(n, "third argument of rewrite rule is not instantiation pattern list");
- }
- if( n[0].getKind()!=kind::APPLY_UF ){
- throw TypeCheckingExceptionPrivate(n[0], "head of rewrite rules must start with an uninterpreted symbols. If you want to write a propagation rule, add the guard [true] for disambiguation");
- }
- }
- return TypeNode(nodeManager->mkTypeConst<TypeConstant>(RRHB_TYPE));
- }
-};/* struct QuantifierReductionRuleRule */
-
-class RRRedDedTypeRule {
-public:
-
- inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
- throw(TypeCheckingExceptionPrivate) {
- Assert(n.getKind() == kind::RR_REDUCTION ||
- n.getKind() == kind::RR_DEDUCTION );
- if( check ){
- if( n[ 0 ].getType(check)!=nodeManager->booleanType() ){
- throw TypeCheckingExceptionPrivate(n, "head of reduction rule is not boolean");
- }
- if( n[ 1 ].getType(check)!=nodeManager->booleanType() ){
- throw TypeCheckingExceptionPrivate(n, "body of reduction rule is not boolean");
- }
- if( n.getNumChildren() == 3 && n[2].getType(check)!=nodeManager->instPatternListType() ){
- throw TypeCheckingExceptionPrivate(n, "third argument of rewrite rule is not instantiation pattern list");
- }
- if( n.getNumChildren() < 3 && n[ 0 ] == nodeManager->mkConst<bool>(true) ){
- throw TypeCheckingExceptionPrivate(n, "A rewrite rule must have one head or one trigger at least");
- }
- }
- return TypeNode(nodeManager->mkTypeConst<TypeConstant>(RRHB_TYPE));
- }
-};/* struct QuantifierReductionRuleRule */
-
-}/* CVC4::theory::rewriterules namespace */
-}/* CVC4::theory namespace */
-}/* CVC4 namespace */
-
-#endif /* __CVC4__THEORY__REWRITERULES__THEORY_REWRITERULES_TYPE_RULES_H */
diff --git a/src/theory/strings/theory_strings.cpp b/src/theory/strings/theory_strings.cpp
index fd9605e59..c44d2d334 100644
--- a/src/theory/strings/theory_strings.cpp
+++ b/src/theory/strings/theory_strings.cpp
@@ -42,15 +42,17 @@ TheoryStrings::TheoryStrings(context::Context* c, context::UserContext* u, Outpu
d_infer_exp(c),
d_nf_pairs(c),
d_loop_antec(u),
+ d_length_intro_vars(u),
+ d_prereg_cached(u),
+ d_length_nodes(u),
d_length_inst(u),
- d_length_nodes(c),
d_str_pos_ctn(c),
d_str_neg_ctn(c),
d_neg_ctn_eqlen(u),
d_neg_ctn_ulen(u),
d_pos_ctn_cached(u),
d_neg_ctn_cached(u),
- d_reg_exp_mem(c),
+ d_regexp_memberships(c),
d_regexp_ucached(u),
d_regexp_ccached(c),
d_regexp_ant(c),
@@ -400,9 +402,10 @@ void TheoryStrings::collectModelInfo( TheoryModel* m, bool fullModel ) {
/////////////////////////////////////////////////////////////////////////////
void TheoryStrings::preRegisterTerm(TNode n) {
- Debug("strings-prereg") << "TheoryStrings::preRegisterTerm() " << n << endl;
- //collectTerms( n );
- switch (n.getKind()) {
+ if(d_prereg_cached.find(n) == d_prereg_cached.end()) {
+ Debug("strings-prereg") << "TheoryStrings::preRegisterTerm() " << n << endl;
+ //collectTerms( n );
+ switch (n.getKind()) {
case kind::EQUAL:
d_equalityEngine.addTriggerEquality(n);
break;
@@ -432,16 +435,18 @@ void TheoryStrings::preRegisterTerm(TNode n) {
}
default: {
if(n.getType().isString() && n.getKind()!=kind::STRING_CONCAT && n.getKind()!=kind::CONST_STRING ) {
- Node n_len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n);
- Node n_len_eq_z = n.eqNode(d_emptyString); //n_len.eqNode( d_zero );
- n_len_eq_z = Rewriter::rewrite( n_len_eq_z );
- Node n_len_geq_zero = NodeManager::currentNM()->mkNode( kind::OR, n_len_eq_z,
- NodeManager::currentNM()->mkNode( kind::GT, n_len, d_zero) );
- Trace("strings-lemma") << "Strings::Lemma LENGTH >= 0 : " << n_len_geq_zero << std::endl;
- d_out->lemma(n_len_geq_zero);
- d_out->requirePhase( n_len_eq_z, true );
+ if( d_length_intro_vars.find(n)==d_length_intro_vars.end() ) {
+ Node n_len = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n);
+ Node n_len_eq_z = n_len.eqNode( d_zero );
+ n_len_eq_z = Rewriter::rewrite( n_len_eq_z );
+ Node n_len_geq_zero = NodeManager::currentNM()->mkNode( kind::OR, n_len_eq_z,
+ NodeManager::currentNM()->mkNode( kind::GT, n_len, d_zero) );
+ Trace("strings-lemma") << "Strings::Lemma LENGTH >= 0 : " << n_len_geq_zero << std::endl;
+ d_out->lemma(n_len_geq_zero);
+ d_out->requirePhase( n_len_eq_z, true );
+ }
// FMF
- if( n.getKind() == kind::VARIABLE ) {//options::stringFMF() &&
+ if( n.getKind() == kind::VARIABLE && options::stringFMF() ) {
d_input_vars.insert(n);
}
}
@@ -453,9 +458,71 @@ void TheoryStrings::preRegisterTerm(TNode n) {
d_equalityEngine.addTerm(n);
}
}
+ }
+ d_prereg_cached.insert(n);
}
}
+Node TheoryStrings::expandDefinition(LogicRequest &logicRequest, Node node) {
+ switch (node.getKind()) {
+ case kind::STRING_CHARAT: {
+ if(d_ufSubstr.isNull()) {
+ std::vector< TypeNode > argTypes;
+ argTypes.push_back(NodeManager::currentNM()->stringType());
+ argTypes.push_back(NodeManager::currentNM()->integerType());
+ argTypes.push_back(NodeManager::currentNM()->integerType());
+ d_ufSubstr = NodeManager::currentNM()->mkSkolem("__ufSS",
+ NodeManager::currentNM()->mkFunctionType(
+ argTypes, NodeManager::currentNM()->stringType()),
+ "uf substr",
+ NodeManager::SKOLEM_EXACT_NAME);
+ }
+ Node lenxgti = NodeManager::currentNM()->mkNode( kind::GT,
+ NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, node[0] ), node[1] );
+ Node zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
+ Node t1greq0 = NodeManager::currentNM()->mkNode( kind::GEQ, node[1], zero);
+ Node cond = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, lenxgti, t1greq0 ));
+ Node one = NodeManager::currentNM()->mkConst( ::CVC4::Rational(1) );
+ Node totalf = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, node[0], node[1], one);
+ Node uf = NodeManager::currentNM()->mkNode(kind::APPLY_UF, d_ufSubstr, node[0], node[1], one);
+ return NodeManager::currentNM()->mkNode( kind::ITE, cond, totalf, uf );
+ }
+ break;
+
+ case kind::STRING_SUBSTR: {
+ if(d_ufSubstr.isNull()) {
+ std::vector< TypeNode > argTypes;
+ argTypes.push_back(NodeManager::currentNM()->stringType());
+ argTypes.push_back(NodeManager::currentNM()->integerType());
+ argTypes.push_back(NodeManager::currentNM()->integerType());
+ d_ufSubstr = NodeManager::currentNM()->mkSkolem("__ufSS",
+ NodeManager::currentNM()->mkFunctionType(
+ argTypes, NodeManager::currentNM()->stringType()),
+ "uf substr",
+ NodeManager::SKOLEM_EXACT_NAME);
+ }
+ Node lenxgti = NodeManager::currentNM()->mkNode( kind::GEQ,
+ NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, node[0] ),
+ NodeManager::currentNM()->mkNode( kind::PLUS, node[1], node[2] ) );
+ Node zero = NodeManager::currentNM()->mkConst( ::CVC4::Rational(0) );
+ Node t1geq0 = NodeManager::currentNM()->mkNode(kind::GEQ, node[1], zero);
+ Node t2geq0 = NodeManager::currentNM()->mkNode(kind::GEQ, node[2], zero);
+ Node cond = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::AND, lenxgti, t1geq0, t2geq0 ));
+ Node totalf = NodeManager::currentNM()->mkNode(kind::STRING_SUBSTR_TOTAL, node[0], node[1], node[2]);
+ Node uf = NodeManager::currentNM()->mkNode(kind::APPLY_UF, d_ufSubstr, node[0], node[1], node[2]);
+ return NodeManager::currentNM()->mkNode( kind::ITE, cond, totalf, uf );
+ }
+ break;
+
+ default :
+ return node;
+ break;
+ }
+
+ Unreachable();
+}
+
+
void TheoryStrings::check(Effort e) {
//Assert( d_pending.empty() );
@@ -485,7 +552,7 @@ void TheoryStrings::check(Effort e) {
atom = polarity ? fact : fact[0];
//must record string in regular expressions
if ( atom.getKind() == kind::STRING_IN_REGEXP ) {
- d_reg_exp_mem.push_back( assertion );
+ d_regexp_memberships.push_back( assertion );
//d_equalityEngine.assertPredicate(atom, polarity, fact);
} else if (atom.getKind() == kind::STRING_STRCTN) {
if(polarity) {
@@ -1785,39 +1852,41 @@ bool TheoryStrings::checkSimple() {
//then, add lemma
if( n.getKind() == kind::CONST_STRING || n.getKind() == kind::STRING_CONCAT ) {
if( d_length_nodes.find(n)==d_length_nodes.end() ) {
- if( d_length_inst.find(n)==d_length_inst.end() ) {
+ Trace("strings-debug") << "get n: " << n << endl;
+ Node sk;
+ //if( d_length_inst.find(n)==d_length_inst.end() ) {
//Node nr = d_equalityEngine.getRepresentative( n );
- //if( d_length_nodes.find(nr)==d_length_nodes.end() ) {
- d_length_inst.insert(n);
- Trace("strings-debug") << "get n: " << n << endl;
- Node sk = NodeManager::currentNM()->mkSkolem( "lsym_$$", n.getType(), "created for length" );
- d_statistics.d_new_skolems += 1;
- Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, sk, n );
- eq = Rewriter::rewrite(eq);
- Trace("strings-lemma") << "Strings::Lemma LENGTH Term : " << eq << std::endl;
- d_out->lemma(eq);
- Node skl = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk );
- Node lsum;
- if( n.getKind() == kind::STRING_CONCAT ) {
- //add lemma
- std::vector<Node> node_vec;
- for( unsigned i=0; i<n.getNumChildren(); i++ ) {
- Node lni = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n[i] );
- node_vec.push_back(lni);
- }
- lsum = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::PLUS, node_vec ) );
- } else if( n.getKind() == kind::CONST_STRING ) {
- //add lemma
- lsum = NodeManager::currentNM()->mkConst( ::CVC4::Rational( n.getConst<String>().size() ) );
- }
- Node ceq = NodeManager::currentNM()->mkNode( kind::EQUAL, skl, lsum );
- ceq = Rewriter::rewrite(ceq);
- Trace("strings-lemma") << "Strings::Lemma LENGTH : " << ceq << std::endl;
- d_out->lemma(ceq);
- addedLemma = true;
- //}
+ sk = NodeManager::currentNM()->mkSkolem( "lsym_$$", n.getType(), "created for length" );
+ d_statistics.d_new_skolems += 1;
+ d_length_intro_vars.insert( sk );
+ Node eq = sk.eqNode(n);
+ eq = Rewriter::rewrite(eq);
+ Trace("strings-lemma") << "Strings::Lemma LENGTH Term : " << eq << std::endl;
+ d_out->lemma(eq);
+ //} else {
+ // sk = d_length_inst[n];
+ //}
+ Node skl = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk );
+ Node lsum;
+ if( n.getKind() == kind::STRING_CONCAT ) {
+ //add lemma
+ std::vector<Node> node_vec;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ) {
+ Node lni = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n[i] );
+ node_vec.push_back(lni);
+ }
+ lsum = Rewriter::rewrite( NodeManager::currentNM()->mkNode( kind::PLUS, node_vec ) );
+ } else if( n.getKind() == kind::CONST_STRING ) {
+ //add lemma
+ lsum = NodeManager::currentNM()->mkConst( ::CVC4::Rational( n.getConst<String>().size() ) );
}
- d_length_nodes[n] = true;
+ Node ceq = NodeManager::currentNM()->mkNode( kind::EQUAL, skl, lsum );
+ ceq = Rewriter::rewrite(ceq);
+ Trace("strings-lemma") << "Strings::Lemma LENGTH : " << ceq << std::endl;
+ d_out->lemma(ceq);
+ addedLemma = true;
+
+ d_length_nodes.insert(n);
}
}
++eqc_i;
@@ -2229,9 +2298,9 @@ bool TheoryStrings::checkMemberships() {
bool addedLemma = false;
std::vector< Node > processed;
std::vector< Node > cprocessed;
- for( unsigned i=0; i<d_reg_exp_mem.size(); i++ ){
+ for( unsigned i=0; i<d_regexp_memberships.size(); i++ ){
//check regular expression membership
- Node assertion = d_reg_exp_mem[i];
+ Node assertion = d_regexp_memberships[i];
if( d_regexp_ucached.find(assertion) == d_regexp_ucached.end()
&& d_regexp_ccached.find(assertion) == d_regexp_ccached.end() ) {
Trace("strings-regexp") << "We have regular expression assertion : " << assertion << std::endl;
@@ -2730,9 +2799,13 @@ void TheoryStrings::assertNode( Node lit ) {
}
Node TheoryStrings::mkSplitEq( const char * c, const char * info, Node lhs, Node rhs, bool lgtZero ) {
- Node sk = NodeManager::currentNM()->mkSkolem( c, lhs.getType(), info );
+ Node sk = NodeManager::currentNM()->mkSkolem( c, NodeManager::currentNM()->stringType(), info );
d_statistics.d_new_skolems += 1;
- Node eq = lhs.eqNode( mkConcat( rhs, sk ) );
+ Node cc = mkConcat( rhs, sk );
+ //if(rhs.isConst()) {
+ // d_length_inst[cc] = lhs;
+ //}
+ Node eq = lhs.eqNode( cc );
eq = Rewriter::rewrite( eq );
if( lgtZero ) {
Node sk_gt_zero = NodeManager::currentNM()->mkNode( kind::EQUAL, sk, d_emptyString).negate();
diff --git a/src/theory/strings/theory_strings.h b/src/theory/strings/theory_strings.h
index cbfa481c3..e07c61a19 100644
--- a/src/theory/strings/theory_strings.h
+++ b/src/theory/strings/theory_strings.h
@@ -112,6 +112,18 @@ public:
};/* class TheoryStrings::NotifyClass */
private:
+ /**
+ * Function symbol used to implement uninterpreted undefined string
+ * semantics. Needed to deal with partial charat/substr function.
+ */
+ Node d_ufSubstr;
+
+ /**
+ * Function symbol used to implement uninterpreted undefined string
+ * semantics. Needed to deal with partial str2int function.
+ */
+ Node d_ufS2I;
+
// Constants
Node d_emptyString;
Node d_emptyRegexp;
@@ -156,6 +168,9 @@ private:
bool isNormalFormPair2( Node n1, Node n2 );
// loop ant
NodeSet d_loop_antec;
+ NodeSet d_length_intro_vars;
+ // preReg cache
+ NodeSet d_prereg_cached;
/////////////////////////////////////////////////////////////////////////////
// MODEL GENERATION
@@ -193,8 +208,8 @@ private:
std::map< Node, EqcInfo* > d_eqc_info;
EqcInfo * getOrMakeEqcInfo( Node eqc, bool doMake = true );
//maintain which concat terms have the length lemma instantiated
- NodeSet d_length_inst;
- NodeBoolMap d_length_nodes;
+ NodeSet d_length_nodes;
+ NodeNodeMap d_length_inst;
private:
void mergeCstVec(std::vector< Node > &vec_strings);
bool getNormalForms(Node &eqc, std::vector< Node > & visited, std::vector< Node > & nf,
@@ -238,6 +253,7 @@ private:
public:
void preRegisterTerm(TNode n);
+ Node expandDefinition(LogicRequest &logicRequest, Node n);
void check(Effort e);
/** Conflict when merging two constants */
@@ -295,7 +311,7 @@ private:
// Regular Expression
private:
// regular expression memberships
- NodeList d_reg_exp_mem;
+ NodeList d_regexp_memberships;
NodeSet d_regexp_ucached;
NodeSet d_regexp_ccached;
// antecedant for why regexp membership must be true
diff --git a/src/theory/theory.h b/src/theory/theory.h
index e8d53e539..ff648e1f2 100644
--- a/src/theory/theory.h
+++ b/src/theory/theory.h
@@ -22,6 +22,7 @@
#include "expr/node.h"
//#include "expr/attribute.h"
#include "expr/command.h"
+#include "smt/logic_request.h"
#include "theory/valuation.h"
#include "theory/output_channel.h"
#include "theory/logic_info.h"
@@ -481,7 +482,23 @@ public:
virtual void finishInit() { }
/**
- * Pre-register a term. Done one time for a Node, ever.
+ * Some theories have kinds that are effectively definitions and
+ * should be expanded before they are handled. Definitions allow
+ * a much wider range of actions than the normal forms given by the
+ * rewriter; they can enable other theories and create new terms.
+ * However no assumptions can be made about subterms having been
+ * expanded or rewritten. Where possible rewrite rules should be
+ * used, definitions should only be used when rewrites are not
+ * possible, for example in handling under-specified operations
+ * using partially defined functions.
+ */
+ virtual Node expandDefinition(LogicRequest &logicRequest, Node node) {
+ // by default, do nothing
+ return node;
+ }
+
+ /**
+ * Pre-register a term. Done one time for a Node per SAT context level.
*/
virtual void preRegisterTerm(TNode) { }
diff --git a/src/theory/theory_engine.cpp b/src/theory/theory_engine.cpp
index c67a7c4bb..33ff18126 100644
--- a/src/theory/theory_engine.cpp
+++ b/src/theory/theory_engine.cpp
@@ -17,6 +17,8 @@
#include <vector>
#include <list>
+#include "theory/arith/arith_ite_utils.h"
+
#include "decision/decision_engine.h"
#include "expr/attribute.h"
@@ -50,7 +52,7 @@
#include "theory/uf/equality_engine.h"
-#include "theory/rewriterules/efficient_e_matching.h"
+//#include "theory/rewriterules/efficient_e_matching.h"
#include "proof/proof_manager.h"
@@ -93,7 +95,7 @@ void TheoryEngine::eqNotifyNewClass(TNode t){
void TheoryEngine::eqNotifyPreMerge(TNode t1, TNode t2){
//TODO: add notification to efficient E-matching
if( d_logicInfo.isQuantified() ){
- d_quantEngine->getEfficientEMatcher()->merge( t1, t2 );
+ //d_quantEngine->getEfficientEMatcher()->merge( t1, t2 );
if( options::quantConflictFind() ){
d_quantEngine->getConflictFind()->merge( t1, t2 );
}
@@ -149,7 +151,8 @@ TheoryEngine::TheoryEngine(context::Context* context,
d_preRegistrationVisitor(this, context),
d_sharedTermsVisitor(d_sharedTerms),
d_unconstrainedSimp(new UnconstrainedSimplifier(context, logicInfo)),
- d_bvToBoolPreprocessor()
+ d_bvToBoolPreprocessor(),
+ d_arithSubstitutionsAdded("zzz::arith::substitutions", 0)
{
for(TheoryId theoryId = theory::THEORY_FIRST; theoryId != theory::THEORY_LAST; ++ theoryId) {
d_theoryTable[theoryId] = NULL;
@@ -167,6 +170,8 @@ TheoryEngine::TheoryEngine(context::Context* context,
PROOF (ProofManager::currentPM()->initTheoryProof(); );
d_iteUtilities = new ITEUtilities(d_iteRemover.getContainsVisitor());
+
+ StatisticsRegistry::registerStat(&d_arithSubstitutionsAdded);
}
TheoryEngine::~TheoryEngine() {
@@ -191,6 +196,8 @@ TheoryEngine::~TheoryEngine() {
delete d_unconstrainedSimp;
delete d_iteUtilities;
+
+ StatisticsRegistry::unregisterStat(&d_arithSubstitutionsAdded);
}
void TheoryEngine::interrupt() throw(ModalException) {
@@ -1461,7 +1468,8 @@ Node TheoryEngine::ppSimpITE(TNode assertion)
bool TheoryEngine::donePPSimpITE(std::vector<Node>& assertions){
bool result = true;
- if(d_iteUtilities->simpIteDidALotOfWorkHeuristic()){
+ bool simpDidALotOfWork = d_iteUtilities->simpIteDidALotOfWorkHeuristic();
+ if(simpDidALotOfWork){
if(options::compressItes()){
result = d_iteUtilities->compress(assertions);
}
@@ -1480,6 +1488,57 @@ bool TheoryEngine::donePPSimpITE(std::vector<Node>& assertions){
}
}
}
+
+ // Do theory specific preprocessing passes
+ if(d_logicInfo.isTheoryEnabled(theory::THEORY_ARITH)){
+ if(!simpDidALotOfWork){
+ ContainsTermITEVisitor& contains = *d_iteRemover.getContainsVisitor();
+ arith::ArithIteUtils aiteu(contains, d_userContext, getModel());
+ bool anyItes = false;
+ for(size_t i = 0; i < assertions.size(); ++i){
+ Node curr = assertions[i];
+ if(contains.containsTermITE(curr)){
+ anyItes = true;
+ Node res = aiteu.reduceVariablesInItes(curr);
+ Debug("arith::ite::red") << "@ " << i << " ... " << curr << endl << " ->" << res << endl;
+ if(curr != res){
+ Node more = aiteu.reduceConstantIteByGCD(res);
+ Debug("arith::ite::red") << " gcd->" << more << endl;
+ assertions[i] = more;
+ }
+ }
+ }
+ if(!anyItes){
+ unsigned prevSubCount = aiteu.getSubCount();
+ aiteu.learnSubstitutions(assertions);
+ if(prevSubCount < aiteu.getSubCount()){
+ d_arithSubstitutionsAdded += aiteu.getSubCount() - prevSubCount;
+ bool anySuccess = false;
+ for(size_t i = 0, N = assertions.size(); i < N; ++i){
+ Node curr = assertions[i];
+ Node next = Rewriter::rewrite(aiteu.applySubstitutions(curr));
+ Node res = aiteu.reduceVariablesInItes(next);
+ Debug("arith::ite::red") << "@ " << i << " ... " << next << endl << " ->" << res << endl;
+ Node more = aiteu.reduceConstantIteByGCD(res);
+ Debug("arith::ite::red") << " gcd->" << more << endl;
+ if(more != next){
+ anySuccess = true;
+ break;
+ }
+ }
+ for(size_t i = 0, N = assertions.size(); anySuccess && i < N; ++i){
+ Node curr = assertions[i];
+ Node next = Rewriter::rewrite(aiteu.applySubstitutions(curr));
+ Node res = aiteu.reduceVariablesInItes(next);
+ Debug("arith::ite::red") << "@ " << i << " ... " << next << endl << " ->" << res << endl;
+ Node more = aiteu.reduceConstantIteByGCD(res);
+ Debug("arith::ite::red") << " gcd->" << more << endl;
+ assertions[i] = Rewriter::rewrite(more);
+ }
+ }
+ }
+ }
+ }
return result;
}
@@ -1580,22 +1639,20 @@ void TheoryEngine::handleUserAttribute(const char* attr, Theory* t) {
void TheoryEngine::checkTheoryAssertionsWithModel() {
for(TheoryId theoryId = THEORY_FIRST; theoryId < THEORY_LAST; ++theoryId) {
- if(theoryId != THEORY_REWRITERULES) {
- Theory* theory = d_theoryTable[theoryId];
- if(theory && d_logicInfo.isTheoryEnabled(theoryId)) {
- for(context::CDList<Assertion>::const_iterator it = theory->facts_begin(),
- it_end = theory->facts_end();
- it != it_end;
- ++it) {
- Node assertion = (*it).assertion;
- Node val = getModel()->getValue(assertion);
- if(val != d_true) {
- stringstream ss;
- ss << theoryId << " has an asserted fact that the model doesn't satisfy." << endl
- << "The fact: " << assertion << endl
- << "Model value: " << val << endl;
- InternalError(ss.str());
- }
+ Theory* theory = d_theoryTable[theoryId];
+ if(theory && d_logicInfo.isTheoryEnabled(theoryId)) {
+ for(context::CDList<Assertion>::const_iterator it = theory->facts_begin(),
+ it_end = theory->facts_end();
+ it != it_end;
+ ++it) {
+ Node assertion = (*it).assertion;
+ Node val = getModel()->getValue(assertion);
+ if(val != d_true) {
+ stringstream ss;
+ ss << theoryId << " has an asserted fact that the model doesn't satisfy." << endl
+ << "The fact: " << assertion << endl
+ << "Model value: " << val << endl;
+ InternalError(ss.str());
}
}
}
diff --git a/src/theory/theory_engine.h b/src/theory/theory_engine.h
index db31ef9b7..9a987c9d7 100644
--- a/src/theory/theory_engine.h
+++ b/src/theory/theory_engine.h
@@ -818,6 +818,9 @@ public:
*/
void checkTheoryAssertionsWithModel();
+private:
+ IntStat d_arithSubstitutionsAdded;
+
};/* class TheoryEngine */
}/* CVC4 namespace */
diff --git a/src/theory/uf/equality_engine.cpp b/src/theory/uf/equality_engine.cpp
index df1d2ebde..0fb42231f 100644
--- a/src/theory/uf/equality_engine.cpp
+++ b/src/theory/uf/equality_engine.cpp
@@ -3,7 +3,7 @@
** \verbatim
** Original author: Dejan Jovanovic
** Major contributors: none
- ** Minor contributors (to current version): Dejan Jovanovic, Tim King, Francois Bobot, Morgan Deters
+ ** Minor contributors (to current version): Dejan Jovanovic, Tim King, Francois Bobot, Morgan Deters, Andrew Reynolds
** This file is part of the CVC4 project.
** Copyright (c) 2009-2013 New York University and The University of Iowa
** See the file COPYING in the top-level source directory for licensing
@@ -364,9 +364,9 @@ const EqualityNode& EqualityEngine::getEqualityNode(EqualityNodeId nodeId) const
return d_equalityNodes[nodeId];
}
-void EqualityEngine::assertEqualityInternal(TNode t1, TNode t2, TNode reason) {
+void EqualityEngine::assertEqualityInternal(TNode t1, TNode t2, TNode reason, MergeReasonType pid) {
- Debug("equality") << d_name << "::eq::addEqualityInternal(" << t1 << "," << t2 << ")" << std::endl;
+ Debug("equality") << d_name << "::eq::addEqualityInternal(" << t1 << "," << t2 << "), pid = " << pid << std::endl;
if (d_done) {
return;
@@ -379,13 +379,13 @@ void EqualityEngine::assertEqualityInternal(TNode t1, TNode t2, TNode reason) {
// Add to the queue and propagate
EqualityNodeId t1Id = getNodeId(t1);
EqualityNodeId t2Id = getNodeId(t2);
- enqueue(MergeCandidate(t1Id, t2Id, MERGED_THROUGH_EQUALITY, reason));
+ enqueue(MergeCandidate(t1Id, t2Id, pid, reason));
}
-void EqualityEngine::assertPredicate(TNode t, bool polarity, TNode reason) {
+void EqualityEngine::assertPredicate(TNode t, bool polarity, TNode reason, MergeReasonType 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);
+ assertEqualityInternal(t, polarity ? d_true : d_false, reason, pid);
propagate();
}
@@ -395,7 +395,7 @@ void EqualityEngine::mergePredicates(TNode p, TNode q, TNode reason) {
propagate();
}
-void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason) {
+void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason, MergeReasonType 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
@@ -403,7 +403,7 @@ void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason) {
return;
}
// Add equality between terms
- assertEqualityInternal(eq[0], eq[1], reason);
+ assertEqualityInternal(eq[0], eq[1], reason, pid);
propagate();
} else {
// If two terms are already dis-equal, don't assert anything
@@ -418,7 +418,7 @@ void EqualityEngine::assertEquality(TNode eq, bool polarity, TNode reason) {
Debug("equality::trigger") << d_name << "::eq::addEquality(" << eq << "," << (polarity ? "true" : "false") << ")" << std::endl;
- assertEqualityInternal(eq, d_false, reason);
+ assertEqualityInternal(eq, d_false, reason, pid);
propagate();
if (d_done) {
@@ -1028,14 +1028,6 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
Debug("equality") << pop;
break;
}
- case MERGED_THROUGH_EQUALITY:
- // Construct the equality
- Debug("equality") << d_name << "::eq::getExplanation(): adding: " << d_equalityEdges[currentEdge].getReason() << std::endl;
- if( eqpc ){
- eqpc->d_node = d_equalityEdges[currentEdge].getReason();
- }
- equalities.push_back(d_equalityEdges[currentEdge].getReason());
- break;
case MERGED_THROUGH_REFLEXIVITY: {
// x1 == x1
Debug("equality") << d_name << "::eq::getExplanation(): due to reflexivity, going deeper" << std::endl;
@@ -1080,8 +1072,21 @@ void EqualityEngine::getExplanation(EqualityNodeId t1Id, EqualityNodeId t2Id, st
break;
}
- default:
- Unreachable();
+ default: {
+ // Construct the equality
+ Debug("equality") << d_name << "::eq::getExplanation(): adding: " << d_equalityEdges[currentEdge].getReason() << std::endl;
+ if( eqpc ){
+ if( reasonType==MERGED_THROUGH_EQUALITY ){
+ eqpc->d_node = d_equalityEdges[currentEdge].getReason();
+ }else{
+ //theory-specific proof rule : TODO
+ eqpc->d_id = reasonType;
+ //eqpc->d_node = d_equalityEdges[currentEdge].getNodeId();
+ }
+ }
+ equalities.push_back(d_equalityEdges[currentEdge].getReason());
+ break;
+ }
}
// Go to the previous
@@ -2054,7 +2059,7 @@ void EqProof::debug_print( const char * c, unsigned tb ){
}
for( unsigned i=0; i<d_children.size(); i++ ){
if( i>0 || !d_node.isNull() ) Debug( c ) << ",";
- std::cout << std::endl;
+ Debug( c ) << std::endl;
d_children[i]->debug_print( c, tb+1 );
}
}
diff --git a/src/theory/uf/equality_engine.h b/src/theory/uf/equality_engine.h
index 8bb849496..2961b510a 100644
--- a/src/theory/uf/equality_engine.h
+++ b/src/theory/uf/equality_engine.h
@@ -521,7 +521,7 @@ private:
/**
* Adds an equality of terms t1 and t2 to the database.
*/
- void assertEqualityInternal(TNode t1, TNode t2, TNode reason);
+ void assertEqualityInternal(TNode t1, TNode t2, TNode reason, MergeReasonType pid = MERGED_THROUGH_EQUALITY);
/**
* Adds a trigger equality to the database with the trigger node and polarity for notification.
@@ -751,7 +751,7 @@ public:
* asserting the negated predicate
* @param reason the reason to keep for building explanations
*/
- void assertPredicate(TNode p, bool polarity, TNode reason);
+ void assertPredicate(TNode p, bool polarity, TNode reason, MergeReasonType pid = MERGED_THROUGH_EQUALITY);
/**
* Adds predicate p and q and makes them equal.
@@ -766,7 +766,7 @@ public:
* asserting the negated equality
* @param reason the reason to keep for building explanations
*/
- void assertEquality(TNode eq, bool polarity, TNode reason);
+ void assertEquality(TNode eq, bool polarity, TNode reason, MergeReasonType pid = MERGED_THROUGH_EQUALITY);
/**
* Returns the current representative of the term t.
diff --git a/src/theory/uf/equality_engine_types.h b/src/theory/uf/equality_engine_types.h
index 435a1ece5..0ee50c74d 100644
--- a/src/theory/uf/equality_engine_types.h
+++ b/src/theory/uf/equality_engine_types.h
@@ -70,6 +70,10 @@ enum MergeReasonType {
/** (for proofs only) Equality was merged due to transitivity */
MERGED_THROUGH_TRANS,
+
+ /** Theory specific proof rules */
+ MERGED_ARRAYS_ROW,
+ MERGED_ARRAYS_ROW1,
};
inline std::ostream& operator << (std::ostream& out, MergeReasonType reason) {
@@ -91,7 +95,8 @@ inline std::ostream& operator << (std::ostream& out, MergeReasonType reason) {
out << "transitivity";
break;
default:
- Unreachable();
+ out << "[theory]";
+ break;
}
return out;
}
diff --git a/src/util/dump.h b/src/util/dump.h
index 0bde68d76..a85062af1 100644
--- a/src/util/dump.h
+++ b/src/util/dump.h
@@ -14,7 +14,7 @@
** Dump utility classes and functions.
**/
-#include "cvc4_public.h"
+#include "cvc4_private.h"
#ifndef __CVC4__DUMP_H
#define __CVC4__DUMP_H
diff --git a/src/util/ite_removal.cpp b/src/util/ite_removal.cpp
index 0dfea4399..1b29f9ef8 100644
--- a/src/util/ite_removal.cpp
+++ b/src/util/ite_removal.cpp
@@ -18,7 +18,6 @@
#include "util/ite_removal.h"
#include "expr/command.h"
-#include "theory/quantifiers/options.h"
#include "theory/ite_utilities.h"
using namespace CVC4;
@@ -29,7 +28,7 @@ namespace CVC4 {
RemoveITE::RemoveITE(context::UserContext* u)
: d_iteCache(u)
{
- d_containsVisitor = new theory::ContainsTermITEVistor();
+ d_containsVisitor = new theory::ContainsTermITEVisitor();
}
RemoveITE::~RemoveITE(){
@@ -40,7 +39,7 @@ void RemoveITE::garbageCollect(){
d_containsVisitor->garbageCollect();
}
-theory::ContainsTermITEVistor* RemoveITE::getContainsVisitor(){
+theory::ContainsTermITEVisitor* RemoveITE::getContainsVisitor() {
return d_containsVisitor;
}
@@ -51,22 +50,20 @@ size_t RemoveITE::collectedCacheSizes() const{
void RemoveITE::run(std::vector<Node>& output, IteSkolemMap& iteSkolemMap)
{
for (unsigned i = 0, i_end = output.size(); i < i_end; ++ i) {
- std::vector<Node> quantVar;
// Do this in two steps to avoid Node problems(?)
// Appears related to bug 512, splitting this into two lines
// fixes the bug on clang on Mac OS
- Node itesRemoved = run(output[i], output, iteSkolemMap, quantVar);
+ Node itesRemoved = run(output[i], output, iteSkolemMap, false);
output[i] = itesRemoved;
}
}
-bool RemoveITE::containsTermITE(TNode e){
+bool RemoveITE::containsTermITE(TNode e) const {
return d_containsVisitor->containsTermITE(e);
}
Node RemoveITE::run(TNode node, std::vector<Node>& output,
- IteSkolemMap& iteSkolemMap,
- std::vector<Node>& quantVar) {
+ IteSkolemMap& iteSkolemMap, bool inQuant) {
// Current node
Debug("ite") << "removeITEs(" << node << ")" << endl;
@@ -76,35 +73,27 @@ Node RemoveITE::run(TNode node, std::vector<Node>& output,
}
// The result may be cached already
+ std::pair<Node, bool> cacheKey(node, inQuant);
NodeManager *nodeManager = NodeManager::currentNM();
- ITECache::const_iterator i = d_iteCache.find(node);
+ ITECache::const_iterator i = d_iteCache.find(cacheKey);
if(i != d_iteCache.end()) {
Node cached = (*i).second;
Debug("ite") << "removeITEs: in-cache: " << cached << endl;
return cached.isNull() ? Node(node) : cached;
}
+ // Remember that we're inside a quantifier
+ if(node.getKind() == kind::FORALL || node.getKind() == kind::EXISTS) {
+ inQuant = true;
+ }
+
// If an ITE replace it
if(node.getKind() == kind::ITE) {
TypeNode nodeType = node.getType();
- if(!nodeType.isBoolean()) {
+ if(!nodeType.isBoolean() && (!inQuant || !node.hasBoundVar())) {
Node skolem;
// Make the skolem to represent the ITE
- if( quantVar.empty() ){
- skolem = nodeManager->mkSkolem("termITE_$$", nodeType, "a variable introduced due to term-level ITE removal");
- }else{
- //if in the scope of free variables, make a skolem operator
- vector< TypeNode > argTypes;
- for( size_t i=0; i<quantVar.size(); i++ ){
- argTypes.push_back( quantVar[i].getType() );
- }
- TypeNode typ = NodeManager::currentNM()->mkFunctionType( argTypes, nodeType );
- Node op = NodeManager::currentNM()->mkSkolem( "termITEop_$$", typ, "a function variable introduced due to term-level ITE removal" );
- vector< Node > funcArgs;
- funcArgs.push_back( op );
- funcArgs.insert( funcArgs.end(), quantVar.begin(), quantVar.end() );
- skolem = NodeManager::currentNM()->mkNode( kind::APPLY_UF, funcArgs );
- }
+ skolem = nodeManager->mkSkolem("termITE_$$", nodeType, "a variable introduced due to term-level ITE removal");
// The new assertion
Node newAssertion =
@@ -113,18 +102,10 @@ Node RemoveITE::run(TNode node, std::vector<Node>& output,
Debug("ite") << "removeITEs(" << node << ") => " << newAssertion << endl;
// Attach the skolem
- d_iteCache.insert(node, skolem);
+ d_iteCache.insert(cacheKey, skolem);
// Remove ITEs from the new assertion, rewrite it and push it to the output
- newAssertion = run(newAssertion, output, iteSkolemMap, quantVar);
-
- if( !quantVar.empty() ){
- //if in the scope of free variables, it is a quantified assertion
- vector< Node > children;
- children.push_back( NodeManager::currentNM()->mkNode( kind::BOUND_VAR_LIST, quantVar ) );
- children.push_back( newAssertion );
- newAssertion = NodeManager::currentNM()->mkNode( kind::FORALL, children );
- }
+ newAssertion = run(newAssertion, output, iteSkolemMap, inQuant);
iteSkolemMap[skolem] = output.size();
output.push_back(newAssertion);
@@ -135,42 +116,66 @@ Node RemoveITE::run(TNode node, std::vector<Node>& output,
}
// If not an ITE, go deep
- if( ( node.getKind() != kind::FORALL || options::iteRemoveQuant() ) &&
- node.getKind() != kind::EXISTS &&
- node.getKind() != kind::REWRITE_RULE ) {
- std::vector< Node > newQuantVar;
- newQuantVar.insert( newQuantVar.end(), quantVar.begin(), quantVar.end() );
- if( node.getKind()==kind::FORALL ){
- for( size_t i=0; i<node[0].getNumChildren(); i++ ){
- newQuantVar.push_back( node[0][i] );
- }
- }
- 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, newQuantVar);
- somethingChanged |= (newChild != *it);
- newChildren.push_back(newChild);
- }
+ 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);
+ somethingChanged |= (newChild != *it);
+ newChildren.push_back(newChild);
+ }
- // If changes, we rewrite
- if(somethingChanged) {
- Node cached = nodeManager->mkNode(node.getKind(), newChildren);
- d_iteCache.insert(node, cached);
- return cached;
- } else {
- d_iteCache.insert(node, Node::null());
- return node;
- }
+ // If changes, we rewrite
+ if(somethingChanged) {
+ Node cached = nodeManager->mkNode(node.getKind(), newChildren);
+ d_iteCache.insert(cacheKey, cached);
+ return cached;
} else {
- d_iteCache.insert(node, Node::null());
+ d_iteCache.insert(cacheKey, Node::null());
return node;
}
}
+Node RemoveITE::replace(TNode node, bool inQuant) const {
+ if(node.isVar() || node.isConst() ||
+ (options::biasedITERemoval() && !containsTermITE(node))){
+ return Node(node);
+ }
+
+ // Check the cache
+ NodeManager *nodeManager = NodeManager::currentNM();
+ ITECache::const_iterator i = d_iteCache.find(make_pair(node, inQuant));
+ if(i != d_iteCache.end()) {
+ Node cached = (*i).second;
+ return cached.isNull() ? Node(node) : cached;
+ }
+
+ // Remember that we're inside a quantifier
+ if(node.getKind() == kind::FORALL || node.getKind() == kind::EXISTS) {
+ inQuant = 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);
+ somethingChanged |= (newChild != *it);
+ newChildren.push_back(newChild);
+ }
+
+ // If changes, we rewrite
+ if(somethingChanged) {
+ return nodeManager->mkNode(node.getKind(), newChildren);
+ } else {
+ return node;
+ }
+}
}/* CVC4 namespace */
diff --git a/src/util/ite_removal.h b/src/util/ite_removal.h
index c2464636e..de5f83f27 100644
--- a/src/util/ite_removal.h
+++ b/src/util/ite_removal.h
@@ -23,17 +23,19 @@
#include "util/dump.h"
#include "context/context.h"
#include "context/cdinsert_hashmap.h"
+#include "util/hash.h"
+#include "util/bool.h"
namespace CVC4 {
namespace theory {
-class ContainsTermITEVistor;
-}
+ class ContainsTermITEVisitor;
+}/* CVC4::theory namespace */
typedef std::hash_map<Node, unsigned, NodeHashFunction> IteSkolemMap;
class RemoveITE {
- typedef context::CDInsertHashMap<Node, Node, NodeHashFunction> ITECache;
+ typedef context::CDInsertHashMap< std::pair<Node, bool>, Node, PairHashFunction<Node, bool, NodeHashFunction, BoolHashFunction> > ITECache;
ITECache d_iteCache;
@@ -59,22 +61,28 @@ public:
* ite created in conjunction with that skolem variable.
*/
Node run(TNode node, std::vector<Node>& additionalAssertions,
- IteSkolemMap& iteSkolemMap, std::vector<Node>& quantVar);
+ IteSkolemMap& iteSkolemMap, bool inQuant);
- /** Returns true if e contains a term ite.*/
- bool containsTermITE(TNode e);
+ /**
+ * Substitute under node using pre-existing cache. Do not remove
+ * any ITEs not seen during previous runs.
+ */
+ Node replace(TNode node, bool inQuant = false) const;
+
+ /** Returns true if e contains a term ite. */
+ bool containsTermITE(TNode e) const;
- /** Returns the collected size of the caches.*/
+ /** Returns the collected size of the caches. */
size_t collectedCacheSizes() const;
- /** Garbage collects non-context dependent data-structures.*/
+ /** Garbage collects non-context dependent data-structures. */
void garbageCollect();
- /** Return the RemoveITE's containsVisitor.*/
- theory::ContainsTermITEVistor* getContainsVisitor();
+ /** Return the RemoveITE's containsVisitor. */
+ theory::ContainsTermITEVisitor* getContainsVisitor();
private:
- theory::ContainsTermITEVistor* d_containsVisitor;
+ theory::ContainsTermITEVisitor* d_containsVisitor;
};/* class RemoveTTE */
diff --git a/src/util/rational.i b/src/util/rational.i
index a65c78327..a9e3e23f8 100644
--- a/src/util/rational.i
+++ b/src/util/rational.i
@@ -2,6 +2,8 @@
#include "util/rational.h"
%}
+%ignore CVC4::RationalFromDoubleException::RationalFromDoubleException(double);
+
%ignore CVC4::Rational::Rational(int);
%ignore CVC4::Rational::Rational(unsigned int);
%ignore CVC4::Rational::Rational(int, int);
diff --git a/src/util/rational_cln_imp.cpp b/src/util/rational_cln_imp.cpp
index 2b29ece22..f674481de 100644
--- a/src/util/rational_cln_imp.cpp
+++ b/src/util/rational_cln_imp.cpp
@@ -17,6 +17,7 @@
#include "cvc4autoconfig.h"
#include "util/rational.h"
#include <string>
+#include <sstream>
#ifndef CVC4_CLN_IMP
# error "This source should only ever be built if CVC4_CLN_IMP is on !"
@@ -50,3 +51,56 @@ std::ostream& CVC4::operator<<(std::ostream& os, const Rational& q){
return os << q.toString();
}
+
+
+/** Equivalent to calling (this->abs()).cmp(b.abs()) */
+int Rational::absCmp(const Rational& q) const{
+ const Rational& r = *this;
+ int rsgn = r.sgn();
+ int qsgn = q.sgn();
+ if(rsgn == 0){
+ return (qsgn == 0) ? 0 : -1;
+ }else if(qsgn == 0){
+ Assert(rsgn != 0);
+ return 1;
+ }else if((rsgn > 0) && (qsgn > 0)){
+ return r.cmp(q);
+ }else if((rsgn < 0) && (qsgn < 0)){
+ // if r < q < 0, q.cmp(r) = +1, (r.abs()).cmp(q.abs()) = +1
+ // if q < r < 0, q.cmp(r) = -1, (r.abs()).cmp(q.abs()) = -1
+ // if q = r < 0, q.cmp(r) = 0, (r.abs()).cmp(q.abs()) = 0
+ return q.cmp(r);
+ }else if((rsgn < 0) && (qsgn > 0)){
+ Rational rpos = -r;
+ return rpos.cmp(q);
+ }else {
+ Assert(rsgn > 0 && (qsgn < 0));
+ Rational qpos = -q;
+ return r.cmp(qpos);
+ }
+}
+
+Rational Rational::fromDouble(double d) throw(RationalFromDoubleException){
+ try{
+ cln::cl_DF fromD = d;
+ Rational q;
+ q.d_value = cln::rationalize(fromD);
+ return q;
+ }catch(cln::floating_point_underflow_exception& fpue){
+ throw RationalFromDoubleException(d);
+ }catch(cln::floating_point_nan_exception& fpne){
+ throw RationalFromDoubleException(d);
+ }catch(cln::floating_point_overflow_exception& fpoe){
+ throw RationalFromDoubleException(d);
+ }
+}
+
+RationalFromDoubleException::RationalFromDoubleException(double d) throw()
+ : Exception()
+{
+ std::stringstream ss;
+ ss << "RationalFromDoubleException(";
+ ss << d;
+ ss << ")";
+ setMessage(ss.str());
+}
diff --git a/src/util/rational_cln_imp.h b/src/util/rational_cln_imp.h
index da2af6c1f..b144ab419 100644
--- a/src/util/rational_cln_imp.h
+++ b/src/util/rational_cln_imp.h
@@ -38,6 +38,11 @@
namespace CVC4 {
+class CVC4_PUBLIC RationalFromDoubleException : public Exception {
+public:
+ RationalFromDoubleException(double d) throw();
+};
+
/**
** A multi-precision rational constant.
** This stores the rational as a pair of multi-precision integers,
@@ -189,12 +194,7 @@ public:
}
/** Return an exact rational for a double d. */
- static Rational fromDouble(double d){
- cln::cl_DF fromD = d;
- Rational q;
- q.d_value = cln::rationalize(fromD);
- return q;
- }
+ static Rational fromDouble(double d) throw(RationalFromDoubleException);
/**
* Get a double representation of this Rational, which is
@@ -259,6 +259,10 @@ public:
return Integer(cln::ceiling1(d_value));
}
+ Rational floor_frac() const {
+ return (*this) - Rational(floor());
+ }
+
Rational& operator=(const Rational& x){
if(this == &x) return *this;
d_value = x.d_value;
@@ -349,6 +353,9 @@ public:
return getNumerator().length() + getDenominator().length();
}
+ /** Equivalent to calling (this->abs()).cmp(b.abs()) */
+ int absCmp(const Rational& q) const;
+
};/* class Rational */
struct RationalHashFunction {
diff --git a/src/util/rational_gmp_imp.cpp b/src/util/rational_gmp_imp.cpp
index d496803dc..25c7dab59 100644
--- a/src/util/rational_gmp_imp.cpp
+++ b/src/util/rational_gmp_imp.cpp
@@ -17,6 +17,8 @@
#include "cvc4autoconfig.h"
#include "util/rational.h"
#include <string>
+#include <sstream>
+#include <cmath>
#ifndef CVC4_GMP_IMP
# error "This source should only ever be built if CVC4_GMP_IMP is on !"
@@ -50,3 +52,52 @@ std::ostream& CVC4::operator<<(std::ostream& os, const Rational& q){
return os << q.toString();
}
+
+/** Equivalent to calling (this->abs()).cmp(b.abs()) */
+int Rational::absCmp(const Rational& q) const{
+ const Rational& r = *this;
+ int rsgn = r.sgn();
+ int qsgn = q.sgn();
+ if(rsgn == 0){
+ return (qsgn == 0) ? 0 : -1;
+ }else if(qsgn == 0){
+ Assert(rsgn != 0);
+ return 1;
+ }else if((rsgn > 0) && (qsgn > 0)){
+ return r.cmp(q);
+ }else if((rsgn < 0) && (qsgn < 0)){
+ // if r < q < 0, q.cmp(r) = +1, (r.abs()).cmp(q.abs()) = +1
+ // if q < r < 0, q.cmp(r) = -1, (r.abs()).cmp(q.abs()) = -1
+ // if q = r < 0, q.cmp(r) = 0, (r.abs()).cmp(q.abs()) = 0
+ return q.cmp(r);
+ }else if((rsgn < 0) && (qsgn > 0)){
+ Rational rpos = -r;
+ return rpos.cmp(q);
+ }else {
+ Assert(rsgn > 0 && (qsgn < 0));
+ Rational qpos = -q;
+ return r.cmp(qpos);
+ }
+}
+
+
+/** Return an exact rational for a double d. */
+Rational Rational::fromDouble(double d) throw(RationalFromDoubleException){
+ if(std::isfinite(d)){
+ Rational q;
+ mpq_set_d(q.d_value.get_mpq_t(), d);
+ return q;
+ }
+
+ throw RationalFromDoubleException(d);
+}
+
+RationalFromDoubleException::RationalFromDoubleException(double d) throw()
+ : Exception()
+{
+ std::stringstream ss;
+ ss << "RationalFromDoubleException(";
+ ss << d;
+ ss << ")";
+ setMessage(ss.str());
+}
diff --git a/src/util/rational_gmp_imp.h b/src/util/rational_gmp_imp.h
index 02ccc273c..273b3072d 100644
--- a/src/util/rational_gmp_imp.h
+++ b/src/util/rational_gmp_imp.h
@@ -28,6 +28,11 @@
namespace CVC4 {
+class CVC4_PUBLIC RationalFromDoubleException : public Exception {
+public:
+ RationalFromDoubleException(double d) throw();
+};
+
/**
** A multi-precision rational constant.
** This stores the rational as a pair of multi-precision integers,
@@ -172,12 +177,7 @@ public:
return Integer(d_value.get_den());
}
- /** Return an exact rational for a double d. */
- static Rational fromDouble(double d){
- Rational q;
- mpq_set_d(q.d_value.get_mpq_t(), d);
- return q;
- }
+ static Rational fromDouble(double d) throw(RationalFromDoubleException);
/**
* Get a double representation of this Rational, which is
@@ -234,6 +234,10 @@ public:
return Integer(q);
}
+ Rational floor_frac() const {
+ return (*this) - Rational(floor());
+ }
+
Rational& operator=(const Rational& x){
if(this == &x) return *this;
d_value = x.d_value;
@@ -326,6 +330,10 @@ public:
uint32_t denLen = getDenominator().length();
return numLen + denLen;
}
+
+ /** Equivalent to calling (this->abs()).cmp(b.abs()) */
+ int absCmp(const Rational& q) const;
+
};/* class Rational */
struct RationalHashFunction {
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback