We try to rewrite real algebraic numbers to rationals. This is important to, e.g., allow the linear solver to see rational constants at all. Refining real algebraic numbers is done lazily, and (almost) any operation may trigger a refinement that makes libpoly realize it actually is rational. Thus, even the mere act of creating a node out of a real algebraic number may do this (it hashes it).
This PR thus introduces a fixed-point loop into the RAN node constructor that defends against this case.
Fixes #8226.
{
return mkConstReal(ran.toRational());
}
- return mkNode(Kind::REAL_ALGEBRAIC_NUMBER,
- mkConst(Kind::REAL_ALGEBRAIC_NUMBER_OP, ran));
+ // Creating this node may refine the ran to the point where isRational returns
+ // true
+ Node inner = mkConst(Kind::REAL_ALGEBRAIC_NUMBER_OP, ran);
+
+ // Keep doing this until it either is rational or we have a fixed point.
+ while (true)
+ {
+ const RealAlgebraicNumber& cur = inner.getConst<RealAlgebraicNumber>();
+ if (cur.isRational())
+ {
+ return mkConstReal(cur.toRational());
+ }
+ if (cur == ran) break;
+ inner = mkConst(Kind::REAL_ALGEBRAIC_NUMBER_OP, cur);
+ }
+ return mkNode(Kind::REAL_ALGEBRAIC_NUMBER, inner);
}
} // namespace cvc5
regress0/nl/issue6619-ran-model.smt2
regress0/nl/issue8135-icp-candidates.smt2
regress0/nl/issue8161-var-elim.smt2
+ regress0/nl/issue8226-ran-refinement.smt2
regress0/nl/lazard-spurious-root.smt2
regress0/nl/magnitude-wrong-1020-m.smt2
regress0/nl/mult-po.smt2
--- /dev/null
+;; needs --check-models, as --debug-check-models does not trigger the issue
+; COMMAND-LINE: --check-models
+; EXPECT: sat
+(set-logic QF_NRA)
+(declare-fun r1 () Real)
+(declare-fun r2 () Real)
+(declare-fun r10 () Real)
+(assert (= r1 (- 0.0 (- 1 r1) (* r2 r2 0.059 (- 1.0)))))
+(assert (< 1.0 (+ 34 (- r1) (- 1.0 (- r1) (* r10 r2 r2)))))
+(check-sat)