This fixes a subtle issue with non-linear and theory combination.
It currently could use irrelevant terms preregistered to the ExtTheory for its model-based refinement. This means that the non-linear extension could accidentally modify values for terms that are not included in its term set, violating theory combination.
In particular, in the minimized example from #5662, (* a k) was a stale term in ExtTheory, and non-linear extension falsely believed that a was a term whose model value could be modified, since moreover a was not a shared term. In reality, a was not a shared term since it only was registered to UF.
Fixes #5662.
}
}
-bool NonlinearExtension::modelBasedRefinement()
+bool NonlinearExtension::modelBasedRefinement(const std::set<Node>& termSet)
{
++(d_stats.d_mbrRuns);
d_checkCounter++;
Trace("nl-ext") << "# false asserts = " << false_asserts.size() << std::endl;
// get the extended terms belonging to this theory
+ std::vector<Node> xtsAll;
+ d_extTheory.getTerms(xtsAll);
+ // only consider those that are currently relevant based on the current
+ // assertions, i.e. those contained in termSet
std::vector<Node> xts;
- d_extTheory.getTerms(xts);
+ for (const Node& x : xtsAll)
+ {
+ if (termSet.find(x) != termSet.end())
+ {
+ xts.push_back(x);
+ }
+ }
if (Trace.isOn("nl-ext-debug"))
{
return false;
}
-void NonlinearExtension::interceptModel(std::map<Node, Node>& arithModel)
+void NonlinearExtension::interceptModel(std::map<Node, Node>& arithModel,
+ const std::set<Node>& termSet)
{
if (!needsCheckLastEffort())
{
if (!d_builtModel.get())
{
Trace("nl-ext") << "interceptModel: do model-based refinement" << std::endl;
- modelBasedRefinement();
+ modelBasedRefinement(termSet);
}
if (d_builtModel.get())
{
* arithModel so that it satisfies certain nonlinear constraints. This may
* involve e.g. solving for variables in nonlinear equations.
*/
- void interceptModel(std::map<Node, Node>& arithModel);
+ void interceptModel(std::map<Node, Node>& arithModel,
+ const std::set<Node>& termSet);
/** Does this class need a call to check(...) at last call effort? */
bool needsCheckLastEffort() const { return d_needsLastCall; }
/** presolve
* may have information regarding how to construct a model, in the case that
* we determined the problem is satisfiable.
*/
- bool modelBasedRefinement();
+ bool modelBasedRefinement(const std::set<Node>& termSet);
/** get assertions
*
{
// Non-linear may repair values to satisfy non-linear constraints (see
// documentation for NonlinearExtension::interceptModel).
- d_nonlinearExtension->interceptModel(arithModel);
+ d_nonlinearExtension->interceptModel(arithModel, termSet);
}
// We are now ready to assert the model.
for (const std::pair<const Node, Node>& p : arithModel)
regress1/nl/issue3803-nl-check-model.smt2
regress1/nl/issue3955-ee-double-notify.smt2
regress1/nl/issue5372-2-no-m-presolve.smt2
+ regress1/nl/issue5662-nl-tc.smt2
+ regress1/nl/issue5662-nl-tc-min.smt2
regress1/nl/metitarski-1025.smt2
regress1/nl/metitarski-3-4.smt2
regress1/nl/metitarski_3_4_2e.smt2
--- /dev/null
+(set-logic NRA)
+(set-info :status sat)
+(declare-fun a () Real)
+(declare-fun j () Real)
+(declare-fun k () Real)
+(declare-fun h () Real)
+(assert (< 0 k))
+(assert (= 1 (* k j)))
+(assert
+ (or
+ (= h 0)
+ (= 0.0 (* a k))
+ )
+)
+(assert (distinct a h))
+(check-sat)
--- /dev/null
+(set-logic NRA)
+(set-info :status sat)
+(declare-fun a () Real)
+(declare-fun b () Real)
+(declare-fun c () Real)
+(declare-fun d () Real)
+(declare-fun j () Real)
+(declare-fun e () Real)
+(declare-fun f () Real)
+(declare-fun k () Real)
+(declare-fun g () Real)
+(declare-fun h () Real)
+(assert (forall ((i Real)) (xor (and (or (and (or (and (or (and (or
+ (and (> 0.0 (* a e) (* c e)) (>= 0 k)) (<= g 0)) (= (* b j)
+ 2.0))))) (> f k)) (>= 0.0 k))) (>= 0 k))))
+(assert (distinct a (* d h)))
+(check-sat)