namespace theory {
namespace arith {
-namespace {
-
-RealAlgebraicNumber evaluate(TNode expr,
- const std::map<Node, RealAlgebraicNumber>& rans)
-{
- switch (expr.getKind())
- {
- case Kind::PLUS:
- {
- RealAlgebraicNumber aggr;
- for (const auto& n : expr)
- {
- aggr += evaluate(n, rans);
- }
- return aggr;
- }
- case Kind::MULT:
- case Kind::NONLINEAR_MULT:
- {
- RealAlgebraicNumber aggr(Integer(1));
- for (const auto& n : expr)
- {
- aggr *= evaluate(n, rans);
- }
- return aggr;
- }
- case Kind::MINUS:
- Assert(expr.getNumChildren() == 2);
- return evaluate(expr[0], rans) - evaluate(expr[1], rans);
- case Kind::UMINUS: return -evaluate(expr[0], rans);
- case Kind::CONST_RATIONAL:
- return RealAlgebraicNumber(expr.getConst<Rational>());
- default:
- auto it = rans.find(expr);
- if (it != rans.end())
- {
- return it->second;
- }
- Assert(false) << "Unsupported expression kind for RAN evaluation: "
- << expr.getKind();
- return RealAlgebraicNumber();
- }
-}
-
-} // namespace
-
-bool isExpressionZero(Env& env, Node expr, const std::map<Node, Node>& model)
+std::optional<bool> isExpressionZero(Env& env,
+ Node expr,
+ const std::map<Node, Node>& model)
{
// Substitute constants and rewrite
expr = env.getRewriter()->rewrite(expr);
{
return expr.getConst<Rational>().isZero();
}
- std::map<Node, RealAlgebraicNumber> rans;
std::vector<TNode> nodes;
std::vector<TNode> repls;
for (const auto& [node, repl] : model)
nodes.emplace_back(node);
repls.emplace_back(repl);
}
- else
- {
- rans.emplace(node, nl::node_to_ran(repl, node));
- }
}
expr =
expr.substitute(nodes.begin(), nodes.end(), repls.begin(), repls.end());
{
return expr.getConst<Rational>().isZero();
}
- return isZero(evaluate(expr, rans));
+ Assert(expr.getKind() != Kind::REAL_ALGEBRAIC_NUMBER);
+ return std::nullopt;
}
} // namespace arith
#ifndef CVC5__THEORY__ARITH__ARITH_EVALUATOR_H
#define CVC5__THEORY__ARITH__ARITH_EVALUATOR_H
+#include <optional>
+
#include "expr/node.h"
#include "smt/env.h"
* Check if the expression `expr` is zero over the given model.
* The model may contain real algebraic numbers in standard witness form.
* The environment is used for rewriting.
+ *
+ * The result is true or false, if the expression could be evaluated. If it
+ * could not, possibly in the presence of a transcendental model, the result is
+ * std::nullopt.
*/
-bool isExpressionZero(Env& env, Node expr, const std::map<Node, Node>& model);
-
+std::optional<bool> isExpressionZero(Env& env,
+ Node expr,
+ const std::map<Node, Node>& model);
}
} // namespace theory
} // namespace cvc5
-#endif
\ No newline at end of file
+#endif
Assert(!is_none(v)) << "Can not convert none.";
Assert(!is_plus_infinity(v)) << "Can not convert plus infinity.";
+ auto* nm = NodeManager::currentNM();
if (is_algebraic_number(v))
{
- return ran_to_node(as_algebraic_number(v), ran_variable);
+ auto ran = as_algebraic_number(v);
+ return nm->mkRealAlgebraicNumber(RealAlgebraicNumber(std::move(ran)));
}
- auto* nm = NodeManager::currentNM();
if (is_dyadic_rational(v))
{
return nm->mkConst(CONST_RATIONAL,
return d_internal->getEqualityStatus(a,b);
}
Node diff = d_env.getNodeManager()->mkNode(Kind::MINUS, a, b);
- if (isExpressionZero(d_env, diff, d_arithModelCache))
+ std::optional<bool> isZero = isExpressionZero(d_env, diff, d_arithModelCache);
+ if (isZero)
{
- return EQUALITY_TRUE_IN_MODEL;
+ return *isZero ? EQUALITY_TRUE_IN_MODEL : EQUALITY_FALSE_IN_MODEL;
}
- return EQUALITY_FALSE_IN_MODEL;
+ return EQUALITY_UNKNOWN;
}
Node TheoryArith::getModelValue(TNode var) {