summaryrefslogtreecommitdiff
path: root/src/theory
diff options
context:
space:
mode:
authorGereon Kremer <gereon.kremer@cs.rwth-aachen.de>2021-03-24 16:24:25 +0100
committerGitHub <noreply@github.com>2021-03-24 15:24:25 +0000
commitcfe207563479a1e9e13d52bdd93446a8c816636a (patch)
treeb627d7b238df9ba500cc63ef7ddee62f3bc96d3f /src/theory
parent31bba4ba83354f41c756e9800489672ff1c9711c (diff)
Only consider relevant terms for integer branches (#6181)
Linear arithmetic simply tried to branch on the first integer variable that had a non-integral assignment. If it holds stale variables that are not part of the current input, these branches can be emitted and are processed by the solver, but the resulting new assertions will not be considered relevant and thus not added to the theory. As it still triggers a new theory check, linear arithmetic repeats the same procedure and causes an infinite loop. This PR explicitly tracks the currently relevant nodes by storing all preregistered nodes and only allows branching on variables from this set. Fixes #6146.
Diffstat (limited to 'src/theory')
-rw-r--r--src/theory/arith/theory_arith_private.cpp67
-rw-r--r--src/theory/arith/theory_arith_private.h13
2 files changed, 54 insertions, 26 deletions
diff --git a/src/theory/arith/theory_arith_private.cpp b/src/theory/arith/theory_arith_private.cpp
index f6278d3a1..b85aeb135 100644
--- a/src/theory/arith/theory_arith_private.cpp
+++ b/src/theory/arith/theory_arith_private.cpp
@@ -113,6 +113,7 @@ TheoryArithPrivate::TheoryArithPrivate(TheoryArith& containing,
d_diseqQueue(c, false),
d_currentPropagationList(),
d_learnedBounds(c),
+ d_preregisteredNodes(u),
d_partialModel(c, DeltaComputeCallback(*this)),
d_errorSet(
d_partialModel, TableauSizes(&d_tableau), BoundCountingLookup(*this)),
@@ -1380,6 +1381,8 @@ void TheoryArithPrivate::setupAtom(TNode atom) {
void TheoryArithPrivate::preRegisterTerm(TNode n) {
Debug("arith::preregister") <<"begin arith::preRegisterTerm("<< n <<")"<< endl;
+ d_preregisteredNodes.insert(n);
+
try {
if(isRelationOperator(n.getKind())){
if(!isSetup(n)){
@@ -1793,21 +1796,27 @@ bool TheoryArithPrivate::assertionCases(ConstraintP constraint){
*
* If there is no such variable, returns ARITHVAR_SENTINEL;
*/
-ArithVar TheoryArithPrivate::nextIntegerViolatation(bool assumeBounds) const {
+ArithVar TheoryArithPrivate::nextIntegerViolation(bool assumeBounds) const
+{
ArithVar numVars = d_partialModel.getNumberOfVariables();
ArithVar v = d_nextIntegerCheckVar;
- if(numVars > 0){
+ if (numVars > 0)
+ {
const ArithVar rrEnd = d_nextIntegerCheckVar;
- do {
- if(isIntegerInput(v)){
- if(!d_partialModel.integralAssignment(v)){
- if( assumeBounds || d_partialModel.assignmentIsConsistent(v) ){
+ do
+ {
+ if (isIntegerInput(v))
+ {
+ if (!d_partialModel.integralAssignment(v))
+ {
+ if (assumeBounds || d_partialModel.assignmentIsConsistent(v))
+ {
return v;
}
}
}
- v= (1 + v == numVars) ? 0 : (1 + v);
- }while(v != rrEnd);
+ v = (1 + v == numVars) ? 0 : (1 + v);
+ } while (v != rrEnd);
}
return ARITHVAR_SENTINEL;
}
@@ -1816,21 +1825,25 @@ ArithVar TheoryArithPrivate::nextIntegerViolatation(bool assumeBounds) const {
* 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){
+bool TheoryArithPrivate::hasIntegerModel()
+{
+ ArithVar next = nextIntegerViolation(true);
+ if (next != ARITHVAR_SENTINEL)
+ {
d_nextIntegerCheckVar = next;
- if(Debug.isOn("arith::hasIntegerModel")){
+ if (Debug.isOn("arith::hasIntegerModel"))
+ {
Debug("arith::hasIntegerModel") << "has int model? " << next << endl;
d_partialModel.printModel(next, Debug("arith::hasIntegerModel"));
}
return false;
- }else{
+ }
+ else
+ {
return true;
}
}
-
Node flattenAndSort(Node n){
Kind k = n.getKind();
switch(k){
@@ -2894,9 +2907,12 @@ void TheoryArithPrivate::solveInteger(Theory::Effort effortLevel){
importSolution(mipSolution);
solveRelaxationOrPanic(effortLevel);
- if(d_qflraStatus == Result::SAT){
- if(!anyConflict()){
- if(ARITHVAR_SENTINEL == nextIntegerViolatation(false)){
+ if (d_qflraStatus == Result::SAT)
+ {
+ if (!anyConflict())
+ {
+ if (ARITHVAR_SENTINEL == nextIntegerViolation(false))
+ {
++(d_statistics.d_solveIntModelsSuccessful);
}
}
@@ -3019,21 +3035,26 @@ void TheoryArithPrivate::importSolution(const ApproximateSimplex::Solution& solu
}
}
-bool TheoryArithPrivate::solveRelaxationOrPanic(Theory::Effort effortLevel){
+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){
+ 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){
+ if (Theory::fullEffort(effortLevel) && d_qflraStatus == Result::SAT_UNKNOWN)
+ {
+ ArithVar canBranch = nextIntegerViolation(false);
+ if (canBranch != ARITHVAR_SENTINEL)
+ {
++d_statistics.d_panicBranches;
TrustNode branch = branchIntegerVariable(canBranch);
Assert(branch.getNode().getKind() == kind::OR);
Node rwbranch = Rewriter::rewrite(branch.getNode()[0]);
- if(!isSatLiteral(rwbranch)){
+ if (!isSatLiteral(rwbranch))
+ {
d_approxCuts.push_back(branch);
return true;
}
diff --git a/src/theory/arith/theory_arith_private.h b/src/theory/arith/theory_arith_private.h
index 181861b00..4b2fcf8a8 100644
--- a/src/theory/arith/theory_arith_private.h
+++ b/src/theory/arith/theory_arith_private.h
@@ -212,8 +212,10 @@ private:
return d_partialModel.isAuxiliary(x);
}
- inline bool isIntegerInput(ArithVar x) const {
- return d_partialModel.isIntegerInput(x);
+ inline bool isIntegerInput(ArithVar x) const
+ {
+ return d_partialModel.isIntegerInput(x)
+ && d_preregisteredNodes.contains(d_partialModel.asNode(x));
}
/**
@@ -267,6 +269,11 @@ private:
context::CDQueue<ConstraintP> d_learnedBounds;
+ /**
+ * Contains all nodes that have been preregistered
+ */
+ context::CDHashSet<Node, NodeHashFunction> d_preregisteredNodes;
+
/**
* Manages information about the assignment and upper and lower bounds on
@@ -544,7 +551,7 @@ private:
*
* If there is no such variable, returns ARITHVAR_SENTINEL;
*/
- ArithVar nextIntegerViolatation(bool assumeBounds) const;
+ ArithVar nextIntegerViolation(bool assumeBounds) const;
/**
* Issues branches for non-auxiliary integer variables with non-integer assignments.
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback