/*** * Bitwuzla: Satisfiability Modulo Theories (SMT) solver. * * Copyright (C) 2022 by the authors listed in the AUTHORS file at * https://github.com/bitwuzla/bitwuzla/blob/main/AUTHORS * * This file is part of Bitwuzla under the MIT license. See COPYING for more * information at https://github.com/bitwuzla/bitwuzla/blob/main/COPYING */ #include "bv/bitvector.h" #include "node/node.h" #include "node/node_manager.h" #include "solver/fp/floating_point.h" #include "solver/fp/rounding_mode.h" #include "test/unit/test.h" namespace bzla::test { using namespace bzla::node; using namespace bzla::type; class TestNodeManager : public TestCommon { }; TEST_F(TestNodeManager, mk_const) { NodeManager nm; Type bool_type = nm.mk_bool_type(); Type bv_type = nm.mk_bv_type(32); Type fp_type = nm.mk_fp_type(5, 11); Type rm_type = nm.mk_rm_type(); Type array_type = nm.mk_array_type(bv_type, fp_type); Type fun_type = nm.mk_fun_type({bool_type, rm_type, array_type}); Node bool_const = nm.mk_const(bool_type); Node bv_const = nm.mk_const(bv_type); Node fp_const = nm.mk_const(fp_type); Node rm_const = nm.mk_const(rm_type); Node array_const = nm.mk_const(array_type); Node fun_const = nm.mk_const(fun_type); ASSERT_NE(bool_const, nm.mk_const(bool_type)); ASSERT_NE(bv_const, nm.mk_const(bv_type)); ASSERT_NE(fp_const, nm.mk_const(fp_type)); ASSERT_NE(rm_const, nm.mk_const(rm_type)); ASSERT_NE(array_const, nm.mk_const(array_type)); ASSERT_NE(fun_const, nm.mk_const(fun_type)); ASSERT_EQ(bool_const.kind(), Kind::CONSTANT); ASSERT_EQ(bool_const.num_children(), 0); ASSERT_TRUE(bool_const.type().is_bool()); ASSERT_EQ(bv_const.kind(), Kind::CONSTANT); ASSERT_EQ(bv_const.num_children(), 0); ASSERT_TRUE(bv_const.type().is_bv()); ASSERT_EQ(fp_const.kind(), Kind::CONSTANT); ASSERT_EQ(fp_const.num_children(), 0); ASSERT_TRUE(fp_const.type().is_fp()); ASSERT_EQ(rm_const.kind(), Kind::CONSTANT); ASSERT_EQ(rm_const.num_children(), 0); ASSERT_TRUE(rm_const.type().is_rm()); ASSERT_EQ(array_const.kind(), Kind::CONSTANT); ASSERT_EQ(array_const.num_children(), 0); ASSERT_TRUE(array_const.type().is_array()); ASSERT_EQ(fun_const.kind(), Kind::CONSTANT); ASSERT_EQ(fun_const.num_children(), 0); ASSERT_TRUE(fun_const.type().is_fun()); } TEST_F(TestNodeManager, mk_const_array) { NodeManager nm; Type bv32 = nm.mk_bv_type(32); Node value = nm.mk_const(bv32); Node const_array = nm.mk_const_array(nm.mk_array_type(nm.mk_bool_type(), bv32), value); ASSERT_EQ(const_array.kind(), Kind::CONST_ARRAY); ASSERT_TRUE(const_array.type().is_array()); ASSERT_EQ( const_array, nm.mk_const_array(nm.mk_array_type(nm.mk_bool_type(), bv32), value)); ASSERT_NE(const_array, nm.mk_const_array(nm.mk_array_type(bv32, bv32), value)); } TEST_F(TestNodeManager, mk_value_bool) { NodeManager nm; Node val_true = nm.mk_value(true); Node val_false = nm.mk_value(false); ASSERT_EQ(val_true.kind(), Kind::VALUE); ASSERT_EQ(val_false.kind(), Kind::VALUE); ASSERT_EQ(val_true.type(), nm.mk_bool_type()); ASSERT_EQ(val_true.type(), val_false.type()); ASSERT_EQ(val_true, nm.mk_value(true)); ASSERT_EQ(val_false, nm.mk_value(false)); ASSERT_EQ(val_true.value(), true); ASSERT_EQ(val_false.value(), false); ASSERT_NE(val_true, val_false); } TEST_F(TestNodeManager, mk_value_bv) { NodeManager nm; BitVector bv = BitVector::from_ui(32, 1); Node val = nm.mk_value(bv); ASSERT_EQ(val.kind(), Kind::VALUE); ASSERT_EQ(val.type(), nm.mk_bv_type(32)); ASSERT_EQ(val, nm.mk_value(BitVector::from_ui(32, 1))); ASSERT_EQ(val.value(), bv); ASSERT_EQ(val.value(), BitVector::from_ui(32, 1)); ASSERT_NE(val, nm.mk_value(BitVector::from_ui(32, 2))); } TEST_F(TestNodeManager, mk_value_rm) { NodeManager nm; Node val_rna = nm.mk_value(RoundingMode::RNA); Node val_rne = nm.mk_value(RoundingMode::RNE); Node val_rtn = nm.mk_value(RoundingMode::RTN); Node val_rtp = nm.mk_value(RoundingMode::RTP); Node val_rtz = nm.mk_value(RoundingMode::RTZ); for (const auto& val : {val_rna, val_rne, val_rtn, val_rtp, val_rtz}) { ASSERT_EQ(val.kind(), Kind::VALUE); ASSERT_EQ(val.type(), nm.mk_rm_type()); ASSERT_EQ(val_rna.type(), val.type()); } ASSERT_EQ(val_rna, nm.mk_value(RoundingMode::RNA)); ASSERT_EQ(val_rne, nm.mk_value(RoundingMode::RNE)); ASSERT_EQ(val_rtn, nm.mk_value(RoundingMode::RTN)); ASSERT_EQ(val_rtp, nm.mk_value(RoundingMode::RTP)); ASSERT_EQ(val_rtz, nm.mk_value(RoundingMode::RTZ)); ASSERT_EQ(val_rna.value(), RoundingMode::RNA); ASSERT_EQ(val_rne.value(), RoundingMode::RNE); ASSERT_EQ(val_rtn.value(), RoundingMode::RTN); ASSERT_EQ(val_rtp.value(), RoundingMode::RTP); ASSERT_EQ(val_rtz.value(), RoundingMode::RTZ); for (const auto& val : {val_rne, val_rtn, val_rtp, val_rtz}) { ASSERT_NE(val_rna, val); } } TEST_F(TestNodeManager, mk_value_fp) { // TODO: after FloatingPoint refactor is done. } TEST_F(TestNodeManager, mk_node) { NodeManager nm; Type bool_type = nm.mk_bool_type(); Node x = nm.mk_const(bool_type); Node y = nm.mk_const(bool_type); Node z = nm.mk_const(bool_type); Node x_and_y = nm.mk_node(Kind::AND, {x, y}); ASSERT_EQ(x_and_y.num_children(), 2); ASSERT_NE(x_and_y.begin(), x_and_y.end()); ASSERT_EQ(x_and_y[0], x); ASSERT_EQ(x_and_y[1], y); for (auto it = x_and_y.begin(); it != x_and_y.end(); ++it) { ASSERT_FALSE(it->is_null()); ASSERT_TRUE(*it == x || *it == y); } for (const Node& c : x_and_y) { ASSERT_FALSE(c.is_null()); ASSERT_TRUE(c == x || c == y); } Node or_z = nm.mk_node(Kind::OR, {x_and_y, z}); ASSERT_EQ(x_and_y, nm.mk_node(Kind::AND, {x, y})); ASSERT_EQ(or_z, nm.mk_node(Kind::OR, {nm.mk_node(Kind::AND, {x, y}), z})); } TEST_F(TestNodeManager, mk_apply) { NodeManager nm; Type bool_type = nm.mk_bool_type(); Type bv_type = nm.mk_bv_type(32); Type fun_type = nm.mk_fun_type({bool_type, bool_type, bool_type, bool_type, bool_type, bool_type, bv_type}); Node fun = nm.mk_const(fun_type); Node bool_const = nm.mk_const(bool_type); Node apply = nm.mk_node(Kind::APPLY, {fun, bool_const, bool_const, bool_const, bool_const, bool_const, bool_const}); ASSERT_EQ(apply.num_children(), 7); ASSERT_EQ(apply[0], fun); for (size_t i = 1; i < apply.num_children(); ++i) { ASSERT_EQ(apply[i], bool_const); } ASSERT_EQ(apply.type(), bv_type); ASSERT_DEATH_DEBUG(nm.mk_node(Kind::APPLY, {fun}), ""); ASSERT_DEATH_DEBUG(nm.mk_node(Kind::APPLY, {fun, bool_const}), ""); } TEST_F(TestNodeManager, check_type) { NodeManager nm; // Test boolean operators Type bool_type = nm.mk_bool_type(); Node bool_const1 = nm.mk_const(bool_type); Node bool_const2 = nm.mk_const(bool_type); ASSERT_EQ(nm.mk_node(Kind::EQUAL, {bool_const1, bool_const2}).type(), bool_type); ASSERT_EQ(nm.mk_node(Kind::NOT, {bool_const1}).type(), bool_type); for (auto kind : {Kind::AND, Kind::OR}) { ASSERT_EQ(nm.mk_node(kind, {bool_const1, bool_const2}).type(), bool_type); } // Test bit-vector operators Type bv_type = nm.mk_bv_type(32); Node bv_const1 = nm.mk_const(bv_type); Node bv_const2 = nm.mk_const(bv_type); ASSERT_EQ(nm.mk_node(Kind::EQUAL, {bv_const1, bv_const2}).type(), bool_type); ASSERT_EQ(nm.mk_node(Kind::BV_NOT, {bv_const1}).type(), bv_type); for (auto kind : {Kind::BV_SLT, Kind::BV_ULT}) { ASSERT_EQ(nm.mk_node(kind, {bv_const1, bv_const2}).type(), bool_type); } for (auto kind : {Kind::BV_AND, Kind::BV_ADD, Kind::BV_MUL, Kind::BV_SHL, Kind::BV_SHR, Kind::BV_ASHR, Kind::BV_UDIV, Kind::BV_UREM}) { ASSERT_EQ(nm.mk_node(kind, {bv_const1, bv_const2}).type(), bv_type); } ASSERT_EQ(nm.mk_node(Kind::BV_CONCAT, {bv_const1, bv_const2}).type(), nm.mk_bv_type(64)); ASSERT_EQ(nm.mk_node(Kind::BV_EXTRACT, {bv_const1}, {5, 0}).type(), nm.mk_bv_type(6)); // Test floating-point operators Type fp_type = nm.mk_fp_type(5, 11); Type rm_type = nm.mk_rm_type(); Node fp_const1 = nm.mk_const(fp_type); Node fp_const2 = nm.mk_const(fp_type); Node fp_const3 = nm.mk_const(fp_type); Node rm_const = nm.mk_const(rm_type); ASSERT_EQ(nm.mk_node(Kind::EQUAL, {fp_const1, fp_const2}).type(), bool_type); ASSERT_EQ(nm.mk_node(Kind::EQUAL, {rm_const, nm.mk_const(rm_type)}).type(), bool_type); for (auto kind : {Kind::FP_ABS, Kind::FP_NEG}) { ASSERT_EQ(nm.mk_node(kind, {fp_const1}).type(), fp_type); } for (auto kind : { Kind::FP_IS_INF, Kind::FP_IS_NAN, Kind::FP_IS_NEG, Kind::FP_IS_NORMAL, Kind::FP_IS_POS, Kind::FP_IS_SUBNORMAL, Kind::FP_IS_ZERO, }) { ASSERT_EQ(nm.mk_node(kind, {fp_const1}).type(), bool_type); } ASSERT_EQ(nm.mk_node(Kind::FP_TO_FP_FROM_BV, {bv_const1}, {8, 24}).type(), nm.mk_fp_type(8, 24)); for (auto kind : {Kind::FP_EQUAL, Kind::FP_LEQ, Kind::FP_LT}) { ASSERT_EQ(nm.mk_node(kind, {fp_const1, fp_const2}).type(), bool_type); } for (auto kind : {Kind::FP_MIN, Kind::FP_MAX, Kind::FP_REM}) { ASSERT_EQ(nm.mk_node(kind, {fp_const1, fp_const2}).type(), fp_type); } for (auto kind : {Kind::FP_SQRT, Kind::FP_RTI}) { ASSERT_EQ(nm.mk_node(kind, {rm_const, fp_const1}).type(), fp_type); } for (auto kind : {Kind::FP_TO_SBV, Kind::FP_TO_UBV}) { ASSERT_EQ(nm.mk_node(kind, {rm_const, fp_const1}, {32}).type(), nm.mk_bv_type(32)); } ASSERT_EQ( nm.mk_node(Kind::FP_TO_FP_FROM_FP, {rm_const, fp_const1}, {8, 24}).type(), nm.mk_fp_type(8, 24)); for (auto kind : {Kind::FP_TO_FP_FROM_SBV, Kind::FP_TO_FP_FROM_UBV}) { ASSERT_EQ(nm.mk_node(kind, {rm_const, bv_const1}, {5, 11}).type(), nm.mk_fp_type(5, 11)); } for (auto kind : {Kind::FP_ADD, Kind::FP_MUL, Kind::FP_DIV}) { ASSERT_EQ(nm.mk_node(kind, {rm_const, fp_const1, fp_const2}).type(), fp_type); } ASSERT_EQ( nm.mk_node(Kind::FP_FMA, {rm_const, fp_const1, fp_const2, fp_const3}) .type(), fp_type); // Test array operators Type array_type = nm.mk_array_type(bv_type, fp_type); Node array_const = nm.mk_const(array_type); ASSERT_EQ( nm.mk_node(Kind::EQUAL, {array_const, nm.mk_const(array_type)}).type(), bool_type); ASSERT_EQ(nm.mk_node(Kind::SELECT, {array_const, bv_const1}).type(), fp_type); ASSERT_EQ(nm.mk_node(Kind::STORE, {array_const, bv_const1, fp_const1}).type(), array_type); // Test functions Type fun_type = nm.mk_fun_type({bool_type, rm_type, array_type}); Node fun_const = nm.mk_const(fun_type); ASSERT_EQ(nm.mk_node(Kind::APPLY, {fun_const, bool_const1, rm_const}).type(), array_type); Node x = nm.mk_var(bv_type); Node y = nm.mk_var(fp_type); Node l1 = nm.mk_node(Kind::LAMBDA, {y, nm.mk_node(Kind::STORE, {array_const, x, y})}); Node l2 = nm.mk_node(Kind::LAMBDA, {x, l1}); ASSERT_EQ(nm.mk_node(Kind::EQUAL, {l2, l2}).type(), bool_type); ASSERT_EQ(l2.type(), nm.mk_fun_type({bv_type, fp_type, array_type})); ASSERT_EQ(nm.mk_node(Kind::APPLY, {l2, bv_const1, fp_const1}).type(), array_type); // Test quantifiers Node var = nm.mk_var(bv_type); for (auto kind : {Kind::FORALL, Kind::EXISTS}) { ASSERT_EQ(nm.mk_node(kind, {var, nm.mk_node(Kind::EQUAL, {var, bv_const1})}) .type(), bool_type); } // Test ITE ASSERT_EQ( nm.mk_node(Kind::ITE, {bool_const1, bool_const1, bool_const2}).type(), bool_type); ASSERT_EQ(nm.mk_node(Kind::ITE, {bool_const1, bv_const1, bv_const2}).type(), bv_type); ASSERT_EQ(nm.mk_node(Kind::ITE, {bool_const1, fp_const1, fp_const2}).type(), fp_type); ASSERT_EQ(nm.mk_node(Kind::ITE, {bool_const1, rm_const, rm_const}).type(), rm_type); ASSERT_EQ( nm.mk_node(Kind::ITE, {bool_const1, array_const, array_const}).type(), array_type); ASSERT_EQ(nm.mk_node(Kind::ITE, {bool_const1, l2, l2}).type(), nm.mk_fun_type({bv_type, fp_type, array_type})); } } // namespace bzla::test