// substitution is integral
Trace("simplify") << "TheoryArithPrivate::solve(): substitution "
<< minVar << " |-> " << elim << endl;
-
outSubstitutions.addSubstitutionSolved(minVar, elim, tin);
return Theory::PP_ASSERT_STATUS_SOLVED;
}
return belowMin;
}
-void TheoryArithPrivate::collectModelValues(const std::set<Node>& termSet,
- std::map<Node, Node>& arithModel)
+void TheoryArithPrivate::collectModelValues(
+ const std::set<Node>& termSet,
+ std::map<Node, Node>& arithModel,
+ std::map<Node, Node>& arithModelIllTyped)
{
AlwaysAssert(d_qflraStatus == Result::SAT);
// integer variables in rare cases. We construct real in this case;
// this will be corrected in TheoryArith::sanityCheckIntegerModel.
qNode = nm->mkConstReal(qmodel);
+ if (term.getType().isInteger())
+ {
+ Trace("arith::collectModelInfo")
+ << "add to arithModelIllTyped " << term << " -> " << qNode
+ << std::endl;
+ // in this case, we add to the ill-typed map instead of the main map
+ arithModelIllTyped[term] = qNode;
+ continue;
+ }
}
else
{
qNode = nm->mkConstRealOrInt(term.getType(), qmodel);
}
- Trace("arith::collectModelInfo") << "m->assertEquality(" << term << ", "
- << qNode << ", true)" << endl;
+ Trace("arith::collectModelInfo")
+ << "add to arithModel " << term << " -> " << qNode << std::endl;
// Add to the map
arithModel[term] = qNode;
}else{
* non-linear extension) can modify arithModel before it is sent to the model.
*
* @param termSet The set of relevant terms
- * @param arithModel Mapping from terms (of real type) to their values. The
- * caller should assert equalities to the model for each entry in this map.
+ * @param arithModel Mapping from terms (of int/real type) to their values.
+ * The caller should assert equalities to the model for each entry in this
+ * map.
+ * @param arithModelIllTyped Mapping from terms (of int type) to real values.
+ * This is used for catching cases where this solver mistakenly set an
+ * integer variable to a real.
*/
void collectModelValues(const std::set<Node>& termSet,
- std::map<Node, Node>& arithModel);
+ std::map<Node, Node>& arithModel,
+ std::map<Node, Node>& arithModelIllTyped);
void shutdown(){ }
if (Theory::fullEffort(level))
{
d_arithModelCache.clear();
+ d_arithModelCacheIllTyped.clear();
d_arithModelCacheSet = false;
std::set<Node> termSet;
if (d_nonlinearExtension != nullptr)
{
d_arithModelCacheSet = true;
collectAssertedTerms(termSet);
- d_internal->collectModelValues(termSet, d_arithModelCache);
+ d_internal->collectModelValues(
+ termSet, d_arithModelCache, d_arithModelCacheIllTyped);
}
}
void TheoryArith::updateModelCache(const std::set<Node>& termSet)
if (!d_arithModelCacheSet)
{
d_arithModelCacheSet = true;
- d_internal->collectModelValues(termSet, d_arithModelCache);
+ d_internal->collectModelValues(
+ termSet, d_arithModelCache, d_arithModelCacheIllTyped);
}
}
bool TheoryArith::sanityCheckIntegerModel()
{
-
- // Double check that the model from the linear solver respects integer types,
- // if it does not, add a branch and bound lemma. This typically should never
- // be necessary, but is needed in rare cases.
- bool addedLemma = false;
- bool badAssignment = false;
- Trace("arith-check") << "model:" << std::endl;
- for (const auto& p : d_arithModelCache)
+ // Double check that the model from the linear solver respects integer types,
+ // if it does not, add a branch and bound lemma. This typically should never
+ // be necessary, but is needed in rare cases.
+ if (Configuration::isAssertionBuild())
+ {
+ for (CVC5_UNUSED const auto& p : d_arithModelCache)
{
- Trace("arith-check") << p.first << " -> " << p.second << std::endl;
- if (p.first.getType().isInteger() && !p.second.getType().isInteger())
- {
- warning() << "TheoryArithPrivate generated a bad model value for "
- "integer variable "
- << p.first << " : " << p.second << std::endl;
- // must branch and bound
- TrustNode lem =
- d_bab.branchIntegerVariable(p.first, p.second.getConst<Rational>());
- if (d_im.trustedLemma(lem, InferenceId::ARITH_BB_LEMMA))
- {
- addedLemma = true;
- }
- badAssignment = true;
- }
+ // will change to strict type equal
+ Assert(p.second.getType().isSubtypeOf(p.second.getType()));
}
- if (addedLemma)
+ }
+ bool addedLemma = false;
+ bool badAssignment = false;
+ Trace("arith-check") << "model:" << std::endl;
+ for (const auto& p : d_arithModelCacheIllTyped)
+ {
+ Trace("arith-check") << p.first << " -> " << p.second << std::endl;
+ Assert(p.first.getType().isInteger() && !p.second.getType().isInteger());
+ warning() << "TheoryArithPrivate generated a bad model value for "
+ "integer variable "
+ << p.first << " : " << p.second << std::endl;
+ // must branch and bound
+ TrustNode lem =
+ d_bab.branchIntegerVariable(p.first, p.second.getConst<Rational>());
+ if (d_im.trustedLemma(lem, InferenceId::ARITH_BB_LEMMA))
{
- // we had to add a branch and bound lemma since the linear solver assigned
- // a non-integer value to an integer variable.
- return true;
+ addedLemma = true;
}
- // this would imply that linear arithmetic's model failed to satisfy a branch
- // and bound lemma
- AlwaysAssert(!badAssignment)
- << "Bad assignment from TheoryArithPrivate::collectModelValues, and no "
- "branching lemma was sent";
- return false;
+ badAssignment = true;
+ }
+ if (addedLemma)
+ {
+ // we had to add a branch and bound lemma since the linear solver assigned
+ // a non-integer value to an integer variable.
+ return true;
+ }
+ // this would imply that linear arithmetic's model failed to satisfy a branch
+ // and bound lemma
+ AlwaysAssert(!badAssignment)
+ << "Bad assignment from TheoryArithPrivate::collectModelValues, and no "
+ "branching lemma was sent";
+ return false;
}
} // namespace arith