1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
|
/******************************************************************************
* Top contributors (to current version):
* Aina Niemetz, Morgan Deters, Andrew Reynolds
*
* This file is part of the cvc5 project.
*
* Copyright (c) 2009-2025 by the authors listed in the file AUTHORS
* in the top-level source directory and their institutional affiliations.
* All rights reserved. See the file COPYING in the top-level source
* directory for licensing information.
* ****************************************************************************
*
* White box testing of cvc5::theory::Theory.
*
* This test creates "fake" theory interfaces and injects them into
* TheoryEngine, so we can test TheoryEngine's behavior without relying on
* independent theory behavior. This is done in TheoryEngineWhite::setUp() by
* means of the TheoryEngineWhite::registerTheory() interface.
*/
#include <memory>
#include <string>
#include "base/check.h"
#include "context/context.h"
#include "expr/kind.h"
#include "expr/node.h"
#include "options/options.h"
#include "smt/smt_solver.h"
#include "test_smt.h"
#include "theory/bv/theory_bv_rewrite_rules_normalization.h"
#include "theory/bv/theory_bv_rewrite_rules_simplification.h"
#include "theory/theory_engine.h"
#include "util/integer.h"
#include "util/rational.h"
namespace cvc5::internal {
using namespace theory;
using namespace expr;
using namespace cvc5::context;
using namespace theory::bv;
namespace test {
class TestTheoryWhiteEngine : public TestSmt
{
protected:
void SetUp() override
{
TestSmt::SetUp();
d_theoryEngine = d_slvEngine->d_smtSolver->getTheoryEngine();
for (TheoryId id = THEORY_FIRST; id != THEORY_LAST; ++id)
{
delete d_theoryEngine->d_theoryOut[id];
delete d_theoryEngine->d_theoryTable[id];
d_theoryEngine->d_theoryOut[id] = nullptr;
d_theoryEngine->d_theoryTable[id] = nullptr;
}
d_theoryEngine->addTheory<DummyTheory<THEORY_BUILTIN> >(THEORY_BUILTIN);
d_theoryEngine->addTheory<DummyTheory<THEORY_BOOL> >(THEORY_BOOL);
d_theoryEngine->addTheory<DummyTheory<THEORY_UF> >(THEORY_UF);
d_theoryEngine->addTheory<DummyTheory<THEORY_ARITH> >(THEORY_ARITH);
d_theoryEngine->addTheory<DummyTheory<THEORY_ARRAYS> >(THEORY_ARRAYS);
d_theoryEngine->addTheory<DummyTheory<THEORY_BV> >(THEORY_BV);
}
TheoryEngine* d_theoryEngine;
};
TEST_F(TestTheoryWhiteEngine, rewriter_simple)
{
Rewriter* rr = d_slvEngine->getEnv().getRewriter();
Node x = d_nodeManager->mkVar("x", d_nodeManager->integerType());
Node y = d_nodeManager->mkVar("y", d_nodeManager->integerType());
Node z = d_nodeManager->mkVar("z", d_nodeManager->integerType());
// make the expression (ADD x y (MULT z 0))
Node zero = d_nodeManager->mkConstInt(Rational("0"));
Node zTimesZero = d_nodeManager->mkNode(Kind::MULT, z, zero);
Node n = d_nodeManager->mkNode(Kind::ADD, x, y, zTimesZero);
Node nExpected = n;
Node nOut;
// do a full rewrite; DummyTheory::preRewrite() and DummyTheory::postRewrite()
// assert that the rewrite calls that are made match the expected sequence
// set up above
nOut = rr->rewrite(n);
// assert that the rewritten node is what we expect
ASSERT_EQ(nOut, nExpected);
}
TEST_F(TestTheoryWhiteEngine, rewriter_complex)
{
Rewriter* rr = d_slvEngine->getEnv().getRewriter();
Node x = d_nodeManager->mkVar("x", d_nodeManager->integerType());
Node y = d_nodeManager->mkVar("y", d_nodeManager->realType());
TypeNode u = d_nodeManager->mkSort("U");
Node z1 = d_nodeManager->mkVar("z1", u);
Node z2 = d_nodeManager->mkVar("z2", u);
Node f = d_nodeManager->mkVar(
"f",
d_nodeManager->mkFunctionType(d_nodeManager->integerType(),
d_nodeManager->integerType()));
Node g = d_nodeManager->mkVar(
"g",
d_nodeManager->mkFunctionType(d_nodeManager->realType(),
d_nodeManager->integerType()));
Node one = d_nodeManager->mkConstInt(Rational("1"));
Node two = d_nodeManager->mkConstInt(Rational("2"));
Node f1 = d_nodeManager->mkNode(Kind::APPLY_UF, f, one);
Node f2 = d_nodeManager->mkNode(Kind::APPLY_UF, f, two);
Node fx = d_nodeManager->mkNode(Kind::APPLY_UF, f, x);
Node ffx = d_nodeManager->mkNode(Kind::APPLY_UF, f, fx);
Node gy = d_nodeManager->mkNode(Kind::APPLY_UF, g, y);
Node z1eqz2 = d_nodeManager->mkNode(Kind::EQUAL, z1, z2);
Node f1eqf2 = d_nodeManager->mkNode(Kind::EQUAL, f1, f2);
Node ffxeqgy = d_nodeManager->mkNode(Kind::EQUAL, ffx, gy);
Node and1 = d_nodeManager->mkNode(Kind::AND, ffxeqgy, z1eqz2);
Node ffxeqf1 = d_nodeManager->mkNode(Kind::EQUAL, ffx, f1);
Node or1 = d_nodeManager->mkNode(Kind::OR, and1, ffxeqf1);
// make the expression:
// (IMPLIES (EQUAL (f 1) (f 2))
// (OR (AND (EQUAL (f (f x)) (g y))
// (EQUAL z1 z2))
// (EQUAL (f (f x)) (f 1))))
Node n = d_nodeManager->mkNode(Kind::IMPLIES, f1eqf2, or1);
Node nExpected = n;
Node nOut;
// do a full rewrite; DummyTheory::preRewrite() and DummyTheory::postRewrite()
// assert that the rewrite calls that are made match the expected sequence
// set up above
nOut = rr->rewrite(n);
// assert that the rewritten node is what we expect
ASSERT_EQ(nOut, nExpected);
}
TEST_F(TestTheoryWhiteEngine, rewrite_rules)
{
TypeNode t = d_nodeManager->mkBitVectorType(8);
Node x = d_nodeManager->mkVar("x", t);
Node y = d_nodeManager->mkVar("y", t);
Node z = d_nodeManager->mkVar("z", t);
// (x - y) * z --> (x * z) - (y * z)
Node expr =
d_nodeManager->mkNode(Kind::BITVECTOR_MULT,
d_nodeManager->mkNode(Kind::BITVECTOR_SUB, x, y),
z);
Node result = expr;
if (RewriteRule<MultDistrib>::applies(expr))
{
result = RewriteRule<MultDistrib>::apply(expr);
}
Node expected =
d_nodeManager->mkNode(Kind::BITVECTOR_SUB,
d_nodeManager->mkNode(Kind::BITVECTOR_MULT, x, z),
d_nodeManager->mkNode(Kind::BITVECTOR_MULT, y, z));
ASSERT_EQ(result, expected);
// Try to apply MultSlice to a multiplication of two and three different
// variables, expect different results (x * y and x * y * z should not get
// rewritten to the same term).
expr = d_nodeManager->mkNode(Kind::BITVECTOR_MULT, x, y, z);
result = expr;
Node expr2 = d_nodeManager->mkNode(Kind::BITVECTOR_MULT, x, y);
Node result2 = expr;
if (RewriteRule<MultSlice>::applies(expr))
{
result = RewriteRule<MultSlice>::apply(expr);
}
if (RewriteRule<MultSlice>::applies(expr2))
{
result2 = RewriteRule<MultSlice>::apply(expr2);
}
ASSERT_NE(result, result2);
}
} // namespace test
} // namespace cvc5::internal
|