#include #include #include #include #include #include namespace pddl { namespace detail { //////////////////////////////////////////////////////////////////////////////////////////////////// // // Reduction // //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// // Forward declarations //////////////////////////////////////////////////////////////////////////////////////////////////// void eliminateImply(ast::Precondition &precondition); void negationNormalize(ast::Precondition &precondition); //////////////////////////////////////////////////////////////////////////////////////////////////// const auto handleUnsupported = [](ast::UnsupportedPointer &unsupported) { throw NormalizationException("“" + unsupported->type + "” expressions in preconditions can’t be normalized currently"); }; //////////////////////////////////////////////////////////////////////////////////////////////////// void eliminateImply(ast::Precondition &precondition) { const auto handleAtomicFormula = [](ast::AtomicFormula &) { }; const auto handleAnd = [](ast::AndPointer &and_) { for (auto &argument : and_->arguments) eliminateImply(argument); }; const auto handleExists = [](ast::ExistsPointer &exists) { eliminateImply(exists->argument); }; const auto handleForAll = [](ast::ForAllPointer &forAll) { eliminateImply(forAll->argument); }; const auto handleImply = [&](ast::ImplyPointer &imply) { eliminateImply(imply->argumentLeft); eliminateImply(imply->argumentRight); ast::Or::Arguments arguments; arguments.reserve(2); arguments.emplace_back(std::make_unique>(std::move(imply->argumentLeft))); arguments.emplace_back(std::move(imply->argumentRight)); precondition = std::make_unique>(std::move(arguments)); }; const auto handleNot = [](ast::NotPointer ¬_) { eliminateImply(not_->argument); }; const auto handleOr = [](ast::OrPointer &or_) { for (auto &argument : or_->arguments) eliminateImply(argument); }; precondition.match(handleAtomicFormula, handleAnd, handleExists, handleForAll, handleImply, handleNot, handleOr, handleUnsupported); } //////////////////////////////////////////////////////////////////////////////////////////////////// // Negation-normalize an expression whose parent is a “not” expression void negationNormalizeNegated(ast::Precondition &precondition, ast::Precondition &parent) { const auto handleAtomicFormula = [](ast::AtomicFormula &) { }; const auto handleAnd = [&](ast::AndPointer &and_) { ast::Or::Arguments arguments; arguments.reserve(and_->arguments.size()); // Apply De Morgan for (auto &argument : and_->arguments) arguments.emplace_back(std::make_unique>(std::move(argument))); // Finally, negation-normalize each argument for (auto &argument : arguments) negationNormalize(argument); // Replace the parent “not” containing this “and” with an “or” over the negated arguments parent = std::make_unique>(std::move(arguments)); }; const auto handleExists = [](ast::ExistsPointer &exists) { negationNormalize(exists->argument); }; const auto handleForAll = [](ast::ForAllPointer &forAll) { negationNormalize(forAll->argument); }; const auto handleImply = [](ast::ImplyPointer &) { throw std::logic_error("precondition not ready for negation normalization (imply), please report to the bug tracker"); }; const auto handleNot = [&](ast::NotPointer ¬_) { negationNormalize(not_->argument); // As the parent contains the argument, the argument needs to be saved before overwriting the parent // TODO: check whether this workaround can be avoided auto argument = std::move(not_->argument); parent = std::move(argument); }; const auto handleOr = [&](ast::OrPointer &or_) { ast::And::Arguments arguments; arguments.reserve(or_->arguments.size()); // Apply De Morgan for (auto &argument : or_->arguments) arguments.emplace_back(std::make_unique>(std::move(argument))); // Finally, negation-normalize each argument for (auto &argument : arguments) negationNormalize(argument); // Replace the parent “not” containing this “or” with an “and” over the negated arguments parent = std::make_unique>(std::move(arguments)); }; precondition.match(handleAtomicFormula, handleAnd, handleExists, handleForAll, handleImply, handleNot, handleOr, handleUnsupported); } //////////////////////////////////////////////////////////////////////////////////////////////////// void negationNormalize(ast::Precondition &precondition) { const auto handleAtomicFormula = [](ast::AtomicFormula &) { }; const auto handleAnd = [](ast::AndPointer &and_) { for (auto &argument : and_->arguments) negationNormalize(argument); }; const auto handleExists = [](ast::ExistsPointer &exists) { negationNormalize(exists->argument); }; const auto handleForAll = [](ast::ForAllPointer &forAll) { negationNormalize(forAll->argument); }; const auto handleImply = [](ast::ImplyPointer &) { throw std::logic_error("precondition not ready for negation normalization (imply), please report to the bug tracker"); }; const auto handleNot = [&](ast::NotPointer ¬_) { negationNormalizeNegated(not_->argument, precondition); }; const auto handleOr = [](ast::OrPointer &or_) { for (auto &argument : or_->arguments) negationNormalize(argument); }; precondition.match(handleAtomicFormula, handleAnd, handleExists, handleForAll, handleImply, handleNot, handleOr, handleUnsupported); } //////////////////////////////////////////////////////////////////////////////////////////////////// void eliminateForAll(ast::Precondition &precondition) { const auto handleAtomicFormula = [](ast::AtomicFormula &) { }; const auto handleAnd = [](ast::AndPointer &and_) { for (auto &argument : and_->arguments) eliminateForAll(argument); }; const auto handleExists = [](ast::ExistsPointer &exists) { eliminateForAll(exists->argument); }; const auto handleForAll = [&](ast::ForAllPointer &forAll) { auto negatedArgument = std::make_unique>(std::move(forAll->argument)); auto exists = std::make_unique>(std::move(forAll->parameters), std::move(negatedArgument)); precondition = std::make_unique>(std::move(exists)); }; const auto handleImply = [&](ast::ImplyPointer &imply) { eliminateForAll(imply->argumentLeft); eliminateForAll(imply->argumentRight); }; const auto handleNot = [](ast::NotPointer ¬_) { eliminateForAll(not_->argument); }; const auto handleOr = [](ast::OrPointer &or_) { for (auto &argument : or_->arguments) eliminateForAll(argument); }; precondition.match(handleAtomicFormula, handleAnd, handleExists, handleForAll, handleImply, handleNot, handleOr, handleUnsupported); } //////////////////////////////////////////////////////////////////////////////////////////////////// void reduce(ast::Precondition &precondition) { // Replace “imply” statements with disjunctions eliminateImply(precondition); // Negation-normalize the precondition negationNormalize(precondition); // Eliminate “forall” statements eliminateForAll(precondition); } //////////////////////////////////////////////////////////////////////////////////////////////////// } }