summaryrefslogtreecommitdiff
path: root/src/theory
diff options
context:
space:
mode:
authorAndrew Reynolds <andrew.j.reynolds@gmail.com>2020-09-23 22:13:35 -0500
committerGitHub <noreply@github.com>2020-09-23 22:13:35 -0500
commit3075a8e20dba6a784316714543c8a1b262459d9a (patch)
tree1ef809c91de2f1a944331ea0cb93959c35126bcf /src/theory
parentaacc90c1234c488f49814fae6dbf0e720e2dfa88 (diff)
Modify lemma vs fact policy for datatype equalities (#5115)
This changes the lemma vs fact policy for datatype equalities. Previously, datatype equalities were sent as lemmas unless they were over datatypes that were composed of datatypes only. This is now changed so that equalities that do not involve direct subterms with finite non-datatype types are kept internal. The primary type of equality that this targets are "Instantiate" equalities, e.g. the conclusion of: (is-cons x) => x = (cons (head x) (tail x)) These equalities have been observed to generate large amounts of new terms for many benchmarks. With this PR, the the challenging Facebook benchmark goes from 2 min 45 sec -> 29 sec. If the instantiate rule is disabled altogether, it still correctly solves, and is faster (~14 seconds), which however is not correct in general. This change triggered two other issues: (1) A relations benchmark involving transitive closure now times out. This has been a common issue for the relations solver and should be revisited. (2) A potential issue with doPendingLemmas in InferenceManagerBuffer was uncovered. In rare cases, we can be re-entrant into this method since OutputChannel::lemma may trigger further preregistration of terms, which can trigger a recursive call to doPendingLemmas in the case of datatypes, which causes a segfault due to corrupting an iterator. This PR adds a simple guard for this method. This PR also fixes some existing issues in computing cardinality for parametric datatypes.
Diffstat (limited to 'src/theory')
-rw-r--r--src/theory/datatypes/inference_manager.cpp33
-rw-r--r--src/theory/datatypes/inference_manager.h12
-rw-r--r--src/theory/datatypes/theory_datatypes.cpp18
-rw-r--r--src/theory/inference_manager_buffered.cpp9
-rw-r--r--src/theory/inference_manager_buffered.h6
5 files changed, 58 insertions, 20 deletions
diff --git a/src/theory/datatypes/inference_manager.cpp b/src/theory/datatypes/inference_manager.cpp
index 45406a9b0..f056b9c5d 100644
--- a/src/theory/datatypes/inference_manager.cpp
+++ b/src/theory/datatypes/inference_manager.cpp
@@ -42,16 +42,13 @@ bool DatatypesInference::mustCommunicateFact(Node n, Node exp)
}
else if (n.getKind() == EQUAL)
{
+ // Note that equalities due to instantiate are forced as lemmas if
+ // necessary as they are created. This ensures that terms are shared with
+ // external theories when necessary. We send the lemma here only if
+ // the equality is not for datatype terms, which can happen for collapse
+ // selector / term size or unification.
TypeNode tn = n[0].getType();
- if (!tn.isDatatype())
- {
- addLemma = true;
- }
- else
- {
- const DType& dt = tn.getDType();
- addLemma = dt.involvesExternalType();
- }
+ addLemma = !tn.isDatatype();
}
else if (n.getKind() == LEQ || n.getKind() == OR)
{
@@ -68,8 +65,10 @@ bool DatatypesInference::mustCommunicateFact(Node n, Node exp)
bool DatatypesInference::process(TheoryInferenceManager* im, bool asLemma)
{
- // check to see if we have to communicate it to the rest of the system
- if (mustCommunicateFact(d_conc, d_exp))
+ // Check to see if we have to communicate it to the rest of the system.
+ // The flag asLemma is true when the inference was marked that it must be
+ // sent as a lemma in addPendingInference below.
+ if (asLemma || mustCommunicateFact(d_conc, d_exp))
{
// send it as an (explained) lemma
std::vector<Node> exp;
@@ -95,9 +94,17 @@ InferenceManager::InferenceManager(Theory& t,
void InferenceManager::addPendingInference(Node conc,
Node exp,
- ProofGenerator* pg)
+ ProofGenerator* pg,
+ bool forceLemma)
{
- d_pendingFact.emplace_back(new DatatypesInference(conc, exp, pg));
+ if (forceLemma)
+ {
+ d_pendingLem.emplace_back(new DatatypesInference(conc, exp, pg));
+ }
+ else
+ {
+ d_pendingFact.emplace_back(new DatatypesInference(conc, exp, pg));
+ }
}
void InferenceManager::process()
diff --git a/src/theory/datatypes/inference_manager.h b/src/theory/datatypes/inference_manager.h
index 91536baab..06c6ff2b5 100644
--- a/src/theory/datatypes/inference_manager.h
+++ b/src/theory/datatypes/inference_manager.h
@@ -72,8 +72,18 @@ class InferenceManager : public InferenceManagerBuffered
/**
* Add pending inference, which may be processed as either a fact or
* a lemma based on mustCommunicateFact in DatatypesInference above.
+ *
+ * @param conc The conclusion of the inference
+ * @param exp The explanation of the inference
+ * @param pg The proof generator who can provide a proof of (conc => exp)
+ * @param forceLemma Whether this inference *must* be processed as a lemma.
+ * Otherwise, it may be processed as a fact or lemma based on
+ * mustCommunicateFact.
*/
- void addPendingInference(Node conc, Node exp, ProofGenerator* pg = nullptr);
+ void addPendingInference(Node conc,
+ Node exp,
+ ProofGenerator* pg = nullptr,
+ bool forceLemma = false);
/**
* Process the current lemmas and facts. This is a custom method that can
* be seen as overriding the behavior of calling both doPendingLemmas and
diff --git a/src/theory/datatypes/theory_datatypes.cpp b/src/theory/datatypes/theory_datatypes.cpp
index 9cecb6f27..376dbb1db 100644
--- a/src/theory/datatypes/theory_datatypes.cpp
+++ b/src/theory/datatypes/theory_datatypes.cpp
@@ -1541,7 +1541,8 @@ void TheoryDatatypes::instantiate( EqcInfo* eqc, Node n ){
exp = getLabel(n);
tt = exp[0];
}
- const DType& dt = tt.getType().getDType();
+ TypeNode ttn = tt.getType();
+ const DType& dt = ttn.getDType();
// instantiate this equivalence class
eqc->d_inst = true;
Node tt_cons = getInstantiateCons(tt, dt, index);
@@ -1551,10 +1552,17 @@ void TheoryDatatypes::instantiate( EqcInfo* eqc, Node n ){
return;
}
eq = tt.eqNode(tt_cons);
- Debug("datatypes-inst") << "DtInstantiate : " << eqc << " " << eq
- << std::endl;
- d_im.addPendingInference(eq, exp);
- Trace("datatypes-infer-debug") << "inst : " << eqc << " " << n << std::endl;
+ // Determine if the equality must be sent out as a lemma. Notice that
+ // we can keep new equalities from the instantiate rule internal as long as
+ // they are for datatype constructors that have no arguments that have
+ // finite external type. Such equalities must be sent because they introduce
+ // selector terms that may contribute to conflicts due to cardinality (good
+ // examples of this are regress0/datatypes/dt-param-card4-bool-sat.smt2 and
+ // regress0/datatypes/list-bool.smt2).
+ bool forceLemma = dt[index].hasFiniteExternalArgType(ttn);
+ Trace("datatypes-infer-debug") << "DtInstantiate : " << eqc << " " << eq
+ << " forceLemma = " << forceLemma << std::endl;
+ d_im.addPendingInference(eq, exp, nullptr, forceLemma);
Trace("datatypes-infer") << "DtInfer : instantiate : " << eq << " by " << exp
<< std::endl;
}
diff --git a/src/theory/inference_manager_buffered.cpp b/src/theory/inference_manager_buffered.cpp
index 1da814116..5699e75ad 100644
--- a/src/theory/inference_manager_buffered.cpp
+++ b/src/theory/inference_manager_buffered.cpp
@@ -25,7 +25,7 @@ namespace theory {
InferenceManagerBuffered::InferenceManagerBuffered(Theory& t,
TheoryState& state,
ProofNodeManager* pnm)
- : TheoryInferenceManager(t, state, pnm)
+ : TheoryInferenceManager(t, state, pnm), d_processingPendingLemmas(false)
{
}
@@ -94,12 +94,19 @@ void InferenceManagerBuffered::doPendingFacts()
void InferenceManagerBuffered::doPendingLemmas()
{
+ if (d_processingPendingLemmas)
+ {
+ // already processing
+ return;
+ }
+ d_processingPendingLemmas = true;
for (const std::unique_ptr<TheoryInference>& plem : d_pendingLem)
{
// process this lemma
plem->process(this, true);
}
d_pendingLem.clear();
+ d_processingPendingLemmas = false;
}
void InferenceManagerBuffered::doPendingPhaseRequirements()
diff --git a/src/theory/inference_manager_buffered.h b/src/theory/inference_manager_buffered.h
index 3d249ea80..74bbcc375 100644
--- a/src/theory/inference_manager_buffered.h
+++ b/src/theory/inference_manager_buffered.h
@@ -134,6 +134,12 @@ class InferenceManagerBuffered : public TheoryInferenceManager
std::vector<std::unique_ptr<TheoryInference>> d_pendingFact;
/** A map from literals to their pending phase requirement */
std::map<Node, bool> d_pendingReqPhase;
+ /**
+ * Whether we are currently processing pending lemmas. This flag ensures
+ * that we do not call pending lemmas recursively, which may lead to
+ * segfaults.
+ */
+ bool d_processingPendingLemmas;
};
} // namespace theory
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback