#ifndef __TEST__FWD_BWD_SIMPLIFICATION_TESTER_HPP__
#define __TEST__FWD_BWD_SIMPLIFICATION_TESTER_HPP__
#include "Test/TestUtils.hpp"
#include "Kernel/Clause.hpp"
#include "Test/ClausePattern.hpp"
#include "Test/MockedSaturationAlgorithm.hpp"
#include "Test/BuilderPattern.hpp"
namespace Test {
template<class A, class Equal>
void dedup(Stack<A>& self, Equal eq)
{
if (self.size() == 0) return;
unsigned offs = 0;
for (unsigned i = 1; i < self.size(); i++) {
if (eq(self[offs], self[i])) {
} else {
self[offs++ + 1] = std::move(self[i]);
}
}
self.pop(self.size() - (offs + 1));
}
template<class A>
void dedup(Stack<A>& self)
{ dedup(self, [](auto const& l, auto const& r) { return l == r; }); }
namespace FwdBwdSimplification {
class TestCase;
template<class Rule>
class FwdBwdSimplificationTester
{
Rule _rule;
public:
FwdBwdSimplificationTester(Rule rule)
: _rule(std::move(rule))
{ }
virtual bool eq(Kernel::Clause* lhs, Kernel::Clause* rhs) const
{ return TestUtils::eqModAC(lhs, rhs); }
friend class TestCase;
};
class TestCase
{
using Clause = Kernel::Clause;
void testFail(std::string const& test, Lib::Exception& e)
{
std::cout << std::endl;
std::cout << "[ test ]: " << test << std::endl;
std::cout << "[ toSimplify ]: " << pretty( toSimplify()) << std::endl;
std::cout << "[ simplifyWith ]: " << pretty(simplifyWith()) << std::endl;
std::cout << "[ exception ]: " << std::endl;
e.cry(std::cout);
exit(-1);
}
template<class Is, class Expected>
void testFail(std::string const& test, Is const& is, Expected const& expected)
{
std::cout << std::endl;
std::cout << "[ test ]: " << test << std::endl;
std::cout << "[ toSimplify ]: " << pretty( toSimplify()) << std::endl;
std::cout << "[ simplifyWith ]: " << pretty(simplifyWith()) << std::endl;
std::cout << "[ is ]: " << pretty( is) << std::endl;
std::cout << "[ expected ]: " << pretty( expected) << std::endl;
exit(-1);
}
public:
BUILDER_METHOD(TestCase, Stack<Clause*>, simplifyWith)
BUILDER_METHOD(TestCase, Stack<Clause*>, toSimplify )
BUILDER_METHOD(TestCase, Stack<ClausePattern>, expected)
BUILDER_METHOD(TestCase, Stack<ClausePattern>, justifications)
BUILDER_METHOD(TestCase, ForwardSimplificationEngine* , fwd)
BUILDER_METHOD(TestCase, BackwardSimplificationEngine*, bwd)
void runFwd()
{
Problem p;
Options o;
o.resolveAwayAutoValues(p);
MockedSaturationAlgorithm alg(p, o);
auto container = alg.getSimplifyingClauseContainer();
ForwardSimplificationEngine& fwd = *this->fwd().unwrap();
fwd.attach(&alg);
auto simplifyWith = this->simplifyWith().unwrap();
for (auto c : simplifyWith) {
container->add(c);
}
ClauseStack results;
ClauseStack justifications;
auto toSimpl = toSimplify().unwrap();
for (auto toSimpl : toSimpl) {
Clause* replacement = nullptr;
ClauseIterator premises;
bool succ;
try {
succ = fwd.perform(toSimpl, replacement, premises);
} catch (Lib::Exception& e) {
testFail("fwd", e);
}
if (succ ) {
if (replacement) {
results.push(replacement);
}
justifications.loadFromIterator(std::move(premises));
}
}
justifications.sort();
justifications.dedup();
fwd.detach();
Ordering::unsetGlobalOrdering();
auto expected = this->expected().unwrap();
auto expJust = this->justifications().unwrapOrElse([&]()
{ return iterTraits(this->simplifyWith().unwrap().iterFifo())
.map([](Clause* cl) -> ClausePattern { return cl; } )
.template collect<Stack>(); });
if (!TestUtils::permEq(expected, results, [&](auto exp, auto res) { return exp.matches(*this, res); })) {
testFail("fwd", results, expected);
}
if (!TestUtils::permEq(expJust, justifications, [&](auto exp, auto res) { return exp.matches(*this, res); })) {
testFail("fwd (justifications)", justifications, expJust);
}
}
void runBwd()
{
Problem p;
Options o;
o.resolveAwayAutoValues(p);
MockedSaturationAlgorithm alg(p, o);
auto container = alg.getSimplifyingClauseContainer();
BackwardSimplificationEngine& bwd = *this->bwd().unwrap();
bwd.attach(&alg);
auto toSimpl = toSimplify().unwrap();
for (auto c : toSimpl) {
container->add(c);
}
Stack<Clause*> results; auto simplifyWith = this->simplifyWith().unwrap();
for (auto cl : simplifyWith) {
Inferences::BwSimplificationRecordIterator simpls;
try {
bwd.perform(cl, simpls);
} catch (Lib::Exception& e) {
testFail("bwd", e);
}
for (auto simpl : iterTraits(std::move(simpls))) {
results.push(simpl.replacement);
}
}
bwd.detach();
Ordering::unsetGlobalOrdering();
auto expected = this->expected().unwrap();
if (!TestUtils::permEq(expected, results, [&](auto exp, auto res) { return exp.matches(*this, res); })) {
testFail("bwd", results, expected);
}
}
void run()
{
runFwd();
runBwd();
}
template<class A>
bool eq(A* lhs, A* rhs) const
{ return TestUtils::eqModAC(lhs, rhs); }
};
#define TEST_SIMPLIFICATION(name, ...) \
TEST_SIMPLIFICATION_WITH_SUGAR(name, MY_SYNTAX_SUGAR, __VA_ARGS__)
#define TEST_SIMPLIFICATION_WITH_SUGAR(name, syntax_sugar, ...) \
TEST_FUN(name) { \
__ALLOW_UNUSED(syntax_sugar) \
auto test = __VA_ARGS__; \
test.run(); \
} \
}
}
#endif