#include #include #include #include #include #include #include namespace pddl { namespace detail { //////////////////////////////////////////////////////////////////////////////////////////////////// // // Precondition // //////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////// // Forward Declarations //////////////////////////////////////////////////////////////////////////////////////////////////// normalizedAST::Literal normalizeNested(ast::AndPointer &and_, detail::NormalizationContext &normalizationContext); normalizedAST::Literal normalizeNested(ast::AtomicFormula &, detail::NormalizationContext &); normalizedAST::Literal normalizeNested(ast::ExistsPointer &exists, detail::NormalizationContext &normalizationContext); normalizedAST::Literal normalizeNested(ast::ForAllPointer &forAll, detail::NormalizationContext &); normalizedAST::Literal normalizeNested(ast::ImplyPointer &, detail::NormalizationContext &); normalizedAST::Literal normalizeNested(ast::NotPointer ¬_, detail::NormalizationContext &normalizationContext); normalizedAST::Literal normalizeNested(ast::OrPointer &or_, detail::NormalizationContext &normalizationContext); normalizedAST::AndPointer normalizeTopLevel(ast::AndPointer &and_, detail::NormalizationContext &normalizationContext); normalizedAST::AtomicFormula normalizeTopLevel(ast::AtomicFormula &, detail::NormalizationContext &); normalizedAST::Literal normalizeTopLevel(ast::ExistsPointer &exists, detail::NormalizationContext &normalizationContext); normalizedAST::Literal normalizeTopLevel(ast::ForAllPointer &forAll, detail::NormalizationContext &); normalizedAST::Literal normalizeTopLevel(ast::ImplyPointer &, detail::NormalizationContext &); normalizedAST::NotPointer normalizeTopLevel(ast::NotPointer ¬_, detail::NormalizationContext &normalizationContext); normalizedAST::OrPointer normalizeTopLevel(ast::OrPointer &or_, detail::NormalizationContext &normalizationContext); //////////////////////////////////////////////////////////////////////////////////////////////////// normalizedAST::DerivedPredicatePointer addDerivedPredicate(const std::vector ¶meters, detail::NormalizationContext &normalizationContext) { auto &derivedPredicates = normalizationContext.derivedPredicates; const auto derivedPredicateID = normalizationContext.derivedPredicateIDStart + derivedPredicates.size() + 1; auto name = "derived-predicate-" + std::to_string(derivedPredicateID); normalizedAST::DerivedPredicate::Arguments arguments; arguments.reserve(parameters.size()); for (const auto ¶meter : parameters) arguments.emplace_back(std::make_unique(parameter)); derivedPredicates.emplace_back(std::make_unique()); auto *derivedPredicate = derivedPredicates.back().get(); derivedPredicate->name = std::move(name); derivedPredicate->parameters = std::move(parameters); return std::make_unique(std::move(arguments), derivedPredicate); } //////////////////////////////////////////////////////////////////////////////////////////////////// normalizedAST::Literal normalizeNested(ast::AndPointer &and_, detail::NormalizationContext &normalizationContext) { std::vector parameters; VariableStack variableStack; collectFreeVariables(and_, parameters, variableStack); auto derivedPredicate = addDerivedPredicate(parameters, normalizationContext); normalizedAST::And::Arguments normalizedArguments; normalizedArguments.reserve(and_->arguments.size()); for (auto &argument : and_->arguments) normalizedArguments.emplace_back(argument.match( [&](auto &x) -> normalizedAST::Literal { return normalizeNested(x, normalizationContext); })); derivedPredicate->declaration->precondition = std::make_unique>(std::move(normalizedArguments)); // TODO: investigate, could be a compiler bug return std::move(derivedPredicate); } //////////////////////////////////////////////////////////////////////////////////////////////////// normalizedAST::Literal normalizeNested(ast::AtomicFormula &atomicFormula, detail::NormalizationContext &) { return normalize(std::move(atomicFormula)); } //////////////////////////////////////////////////////////////////////////////////////////////////// normalizedAST::Literal normalizeNested(ast::ExistsPointer &exists, detail::NormalizationContext &normalizationContext) { std::vector parameters; VariableStack variableStack; collectFreeVariables(exists, parameters, variableStack); auto derivedPredicate = addDerivedPredicate(parameters, normalizationContext); derivedPredicate->declaration->existentialParameters = std::move(exists->parameters); derivedPredicate->declaration->precondition = exists->argument.match( [&](auto &x) -> normalizedAST::DerivedPredicatePrecondition { return normalizeTopLevel(x, normalizationContext); }); // TODO: investigate, could be a compiler bug return std::move(derivedPredicate); } //////////////////////////////////////////////////////////////////////////////////////////////////// normalizedAST::Literal normalizeNested(ast::ForAllPointer &, detail::NormalizationContext &) { // “forall” expressions should be reduced to negated “exists” statements at this point throw std::logic_error("precondition not in normal form (forall), please report to the bug tracker"); } //////////////////////////////////////////////////////////////////////////////////////////////////// normalizedAST::Literal normalizeNested(ast::ImplyPointer &, detail::NormalizationContext &) { // “imply” expressions should be reduced to disjunctions at this point throw std::logic_error("precondition not in normal form (imply), please report to the bug tracker"); } //////////////////////////////////////////////////////////////////////////////////////////////////// normalizedAST::Literal normalizeNested(ast::NotPointer ¬_, detail::NormalizationContext &normalizationContext) { auto normalizedArgumentLiteral = not_->argument.match( [&](auto &x) -> normalizedAST::Literal { return normalizeNested(x, normalizationContext); }); // Multiple negations should be eliminated at this point if (normalizedArgumentLiteral.is>()) throw std::logic_error("precondition not in normal form (multiple negation), please report to the bug tracker"); auto &normalizedArgument = normalizedArgumentLiteral.get(); return std::make_unique>(std::move(normalizedArgument)); } //////////////////////////////////////////////////////////////////////////////////////////////////// normalizedAST::Literal normalizeNested(ast::OrPointer &or_, detail::NormalizationContext &normalizationContext) { std::vector parameters; VariableStack variableStack; collectFreeVariables(or_, parameters, variableStack); auto derivedPredicate = addDerivedPredicate(parameters, normalizationContext); normalizedAST::Or::Arguments normalizedArguments; normalizedArguments.reserve(or_->arguments.size()); for (auto &argument : or_->arguments) normalizedArguments.emplace_back(argument.match( [&](auto &x) -> normalizedAST::Literal { return normalizeNested(x, normalizationContext); })); derivedPredicate->declaration->precondition = std::make_unique>(std::move(normalizedArguments)); // TODO: investigate, could be a compiler bug return std::move(derivedPredicate); } //////////////////////////////////////////////////////////////////////////////////////////////////// normalizedAST::AtomicFormula normalizeTopLevel(ast::AtomicFormula &atomicFormula, detail::NormalizationContext &) { return normalize(std::move(atomicFormula)); } //////////////////////////////////////////////////////////////////////////////////////////////////// // Normalize top-level conjunctions normalizedAST::AndPointer normalizeTopLevel(ast::AndPointer &and_, detail::NormalizationContext &normalizationContext) { normalizedAST::And::Arguments arguments; arguments.reserve(and_->arguments.size()); const auto handleAtomicFormula = [&](ast::AtomicFormula &atomicFormula) -> normalizedAST::Literal { return normalize(std::move(atomicFormula)); }; const auto handleNot = [&](ast::NotPointer ¬_) -> normalizedAST::Literal { return normalizeTopLevel(not_, normalizationContext); }; const auto handleNested = [&](auto &nested) -> normalizedAST::Literal { return normalizeNested(nested, normalizationContext); }; for (auto &argument : and_->arguments) { auto normalizedArgument = argument.match(handleAtomicFormula, handleNot, handleNested); arguments.emplace_back(std::move(normalizedArgument)); } return std::make_unique>(std::move(arguments)); } //////////////////////////////////////////////////////////////////////////////////////////////////// normalizedAST::Literal normalizeTopLevel(ast::ExistsPointer &exists, detail::NormalizationContext &normalizationContext) { return normalizeNested(exists, normalizationContext); } //////////////////////////////////////////////////////////////////////////////////////////////////// normalizedAST::Literal normalizeTopLevel(ast::ForAllPointer &, detail::NormalizationContext &) { throw std::logic_error("precondition not in normal form (forall), please report to the bug tracker"); } //////////////////////////////////////////////////////////////////////////////////////////////////// normalizedAST::Literal normalizeTopLevel(ast::ImplyPointer &, detail::NormalizationContext &) { throw std::logic_error("precondition not in normal form (imply), please report to the bug tracker"); } //////////////////////////////////////////////////////////////////////////////////////////////////// // Normalize top-level negations normalizedAST::NotPointer normalizeTopLevel(ast::NotPointer ¬_, detail::NormalizationContext &normalizationContext) { // “not” expressions may be nested one time to form simple literals if (not_->argument.is()) return std::make_unique>(normalize(std::move(not_->argument.get()))); auto normalizedArgument = not_->argument.match( [&](auto &nested) -> normalizedAST::AtomicFormula { auto normalizedLiteral = normalizeNested(nested, normalizationContext); // Multiple negations should be eliminated at this point if (normalizedLiteral.template is>()) throw std::logic_error("precondition not in normal form (multiple negation), please report to the bug tracker"); return std::move(normalizedLiteral.template get()); }); return std::make_unique>(std::move(normalizedArgument)); } //////////////////////////////////////////////////////////////////////////////////////////////////// // TODO: refactor to avoid code duplication normalizedAST::OrPointer normalizeTopLevel(ast::OrPointer &or_, detail::NormalizationContext &normalizationContext) { normalizedAST::Or::Arguments arguments; arguments.reserve(or_->arguments.size()); const auto handleAtomicFormula = [&](ast::AtomicFormula &atomicFormula) -> normalizedAST::Literal { return normalize(std::move(atomicFormula)); }; const auto handleNot = [&](ast::NotPointer ¬_) -> normalizedAST::Literal { return normalizeTopLevel(not_, normalizationContext); }; const auto handleNested = [&](auto &nested) -> normalizedAST::Literal { return normalizeNested(nested, normalizationContext); }; for (auto &argument : or_->arguments) { auto normalizedArgument = argument.match(handleAtomicFormula, handleNot, handleNested); arguments.emplace_back(std::move(normalizedArgument)); } return std::make_unique>(std::move(arguments)); } //////////////////////////////////////////////////////////////////////////////////////////////////// normalizedAST::Precondition normalize(ast::Precondition &&precondition, detail::NormalizationContext &normalizationContext) { // Bring precondition to normal form reduce(precondition); const auto handleAtomicFormula = [&](ast::AtomicFormula &atomicFormula) -> normalizedAST::Precondition { return normalizeTopLevel(atomicFormula, normalizationContext); }; const auto handleAnd = [&](ast::AndPointer &and_) -> normalizedAST::Precondition { return normalizeTopLevel(and_, normalizationContext); }; const auto handleExists = [&](ast::ExistsPointer &exists) -> normalizedAST::Precondition { return normalizeTopLevel(exists, normalizationContext); }; const auto handleForAll = [&](ast::ForAllPointer &forAll) -> normalizedAST::Precondition { return normalizeTopLevel(forAll, normalizationContext); }; const auto handleImply = [&](ast::ImplyPointer &imply) -> normalizedAST::Precondition { return normalizeTopLevel(imply, normalizationContext); }; const auto handleNot = [&](ast::NotPointer ¬_) -> normalizedAST::Precondition { return normalizeTopLevel(not_, normalizationContext); }; const auto handleOr = [&](ast::OrPointer &or_) -> normalizedAST::Precondition { return normalizeNested(or_, normalizationContext); }; return precondition.match(handleAtomicFormula, handleAnd, handleExists, handleForAll, handleImply, handleNot, handleOr); } //////////////////////////////////////////////////////////////////////////////////////////////////// } }