diff --git a/include/plasp/pddl/Description.h b/include/plasp/pddl/Description.h index 8ec66f5..3bf6344 100644 --- a/include/plasp/pddl/Description.h +++ b/include/plasp/pddl/Description.h @@ -4,6 +4,7 @@ #include #include +#include #include namespace plasp @@ -36,7 +37,7 @@ class Description Context m_context; std::unique_ptr m_domain; - //std::unique_ptr m_problem; + std::unique_ptr m_problem; }; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/include/plasp/pddl/Problem.h b/include/plasp/pddl/Problem.h new file mode 100644 index 0000000..836554e --- /dev/null +++ b/include/plasp/pddl/Problem.h @@ -0,0 +1,50 @@ +#ifndef __PLASP__PDDL__PROBLEM_H +#define __PLASP__PDDL__PROBLEM_H + +#include +#include +#include + +namespace plasp +{ +namespace pddl +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Problem +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +class Problem +{ + public: + static Problem fromPDDL(Context &context); + + public: + const std::string &name() const; + const Requirements &requirements() const; + + private: + Problem(Context &context); + + void parseSection(); + + void parseRequirementSection(); + bool hasRequirement(Requirement::Type requirementType) const; + void computeDerivedRequirements(); + + void checkConsistency(); + + Context &m_context; + + std::string m_name; + Requirements m_requirements; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/src/plasp/pddl/Description.cpp b/src/plasp/pddl/Description.cpp index 6dc5c93..3eb8598 100644 --- a/src/plasp/pddl/Description.cpp +++ b/src/plasp/pddl/Description.cpp @@ -89,8 +89,8 @@ void Description::parseSection() if (sectionIdentifier == "domain") m_domain = std::make_unique(Domain::fromPDDL(m_context)); - //else if (sectionIdentifier == "problem") - // m_problem = std::make_unique(Problem::fromPDDL(parser)); + else if (sectionIdentifier == "problem") + m_problem = std::make_unique(Problem::fromPDDL(m_context)); else throw utils::ParserException(m_context.parser, "Unknown PDDL section \"" + sectionIdentifier + "\""); } diff --git a/src/plasp/pddl/Problem.cpp b/src/plasp/pddl/Problem.cpp new file mode 100644 index 0000000..36438fd --- /dev/null +++ b/src/plasp/pddl/Problem.cpp @@ -0,0 +1,205 @@ +#include + +#include + +#include +#include + +namespace plasp +{ +namespace pddl +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Problem +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +Problem::Problem(Context &context) +: m_context(context) +{ +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +Problem Problem::fromPDDL(Context &context) +{ + Problem problem(context); + + problem.m_name = context.parser.parseIdentifier(isIdentifier); + + std::cout << "Parsing problem " << problem.m_name << std::endl; + + context.parser.expect(")"); + + while (true) + { + context.parser.skipWhiteSpace(); + + if (context.parser.currentCharacter() == ')') + break; + + problem.parseSection(); + } + + problem.computeDerivedRequirements(); + + problem.checkConsistency(); + + return problem; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +const std::string &Problem::name() const +{ + return m_name; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +const Requirements &Problem::requirements() const +{ + return m_requirements; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void Problem::parseSection() +{ + m_context.parser.expect("("); + m_context.parser.expect(":"); + + const auto sectionIdentifier = utils::toLowerCase(m_context.parser.parseIdentifier(isIdentifier)); + + const auto skipSection = + [&]() + { + std::cout << "Skipping section " << sectionIdentifier << std::endl; + + size_t openParentheses = 1; + + while (true) + { + const auto character = m_context.parser.currentCharacter(); + m_context.parser.advance(); + + if (character == '(') + openParentheses++; + else if (character == ')') + { + openParentheses--; + + if (openParentheses == 0) + return; + } + } + }; + + // TODO: check order of the sections + if (sectionIdentifier == "domain") + skipSection(); + else if (sectionIdentifier == "requirements") + parseRequirementSection(); + else if (sectionIdentifier == "objects") + skipSection(); + else if (sectionIdentifier == "init") + skipSection(); + else if (sectionIdentifier == "goal") + skipSection(); + else if (sectionIdentifier == "constraints") + skipSection(); + else if (sectionIdentifier == "metric") + skipSection(); + else if (sectionIdentifier == "length") + skipSection(); + else + throw utils::ParserException(m_context.parser, "Unknown problem section \"" + sectionIdentifier + "\""); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void Problem::parseRequirementSection() +{ + m_context.parser.skipWhiteSpace(); + + while (m_context.parser.currentCharacter() != ')') + { + m_context.parser.expect(":"); + + m_requirements.emplace_back(Requirement::parse(m_context)); + + m_context.parser.skipWhiteSpace(); + } + + // If no requirements are specified, assume STRIPS + if (m_requirements.empty()) + m_requirements.emplace_back(Requirement::Type::STRIPS); + + m_context.parser.expect(")"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +bool Problem::hasRequirement(Requirement::Type requirementType) const +{ + const auto match = std::find_if(m_requirements.cbegin(), m_requirements.cend(), + [&](const auto &requirement) + { + return requirement.type() == requirementType; + }); + + return match != m_requirements.cend(); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void Problem::computeDerivedRequirements() +{ + const auto addRequirementUnique = + [&](const auto requirement) + { + if (hasRequirement(requirement)) + return; + + m_requirements.push_back(Requirement(requirement)); + }; + + if (hasRequirement(Requirement::Type::ADL)) + { + addRequirementUnique(Requirement::Type::STRIPS); + addRequirementUnique(Requirement::Type::Typing); + addRequirementUnique(Requirement::Type::NegativePreconditions); + addRequirementUnique(Requirement::Type::DisjunctivePreconditions); + addRequirementUnique(Requirement::Type::Equality); + addRequirementUnique(Requirement::Type::QuantifiedPreconditions); + addRequirementUnique(Requirement::Type::ConditionalEffects); + } + + if (hasRequirement(Requirement::Type::QuantifiedPreconditions)) + { + addRequirementUnique(Requirement::Type::ExistentialPreconditions); + addRequirementUnique(Requirement::Type::UniversalPreconditions); + } + + if (hasRequirement(Requirement::Type::Fluents)) + { + addRequirementUnique(Requirement::Type::NumericFluents); + addRequirementUnique(Requirement::Type::ObjectFluents); + } + + if (hasRequirement(Requirement::Type::TimedInitialLiterals)) + addRequirementUnique(Requirement::Type::DurativeActions); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void Problem::checkConsistency() +{ +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +}