diff --git a/include/plasp/pddl/Constant.h b/include/plasp/pddl/Constant.h new file mode 100644 index 0000000..97a1999 --- /dev/null +++ b/include/plasp/pddl/Constant.h @@ -0,0 +1,60 @@ +#ifndef __PLASP__PDDL__CONSTANT_H +#define __PLASP__PDDL__CONSTANT_H + +#include +#include + +#include +#include + +namespace plasp +{ +namespace pddl +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Constant +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +class Context; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +class Constant +{ + public: + static Constant &parse(utils::Parser &parser, Context &context); + static Constant &parseDeclaration(utils::Parser &parser, Context &context); + + public: + const std::string &name() const; + const PrimitiveType *type() const; + + bool isDeclared() const; + + private: + Constant(std::string name); + + void setDirty(bool isDirty = true); + bool isDirty() const; + + void setDeclared(); + + void setType(const PrimitiveType *parentType); + + bool m_isDirty; + bool m_isDeclared; + + std::string m_name; + + const PrimitiveType *m_type; +}; + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} + +#endif diff --git a/include/plasp/pddl/Context.h b/include/plasp/pddl/Context.h index 95c3529..d6e0188 100644 --- a/include/plasp/pddl/Context.h +++ b/include/plasp/pddl/Context.h @@ -5,6 +5,7 @@ #include #include +#include #include #include @@ -27,6 +28,9 @@ class Context std::vector> eitherTypes; + std::vector> constants; + std::unordered_map constantsHashMap; + std::vector> predicates; std::unordered_map predicatesHashMap; }; diff --git a/include/plasp/pddl/Domain.h b/include/plasp/pddl/Domain.h index 914284b..86102bf 100644 --- a/include/plasp/pddl/Domain.h +++ b/include/plasp/pddl/Domain.h @@ -29,6 +29,7 @@ class Domain const std::string &name() const; const Requirements &requirements() const; const std::vector> &types() const; + const std::vector> &constants() const; const std::vector> &predicates() const; private: @@ -42,6 +43,8 @@ class Domain void parseTypeSection(utils::Parser &parser); + void parseConstantSection(utils::Parser &parser); + void parsePredicateSection(utils::Parser &parser); void checkConsistency(); diff --git a/include/plasp/pddl/PrimitiveType.h b/include/plasp/pddl/PrimitiveType.h index 0f33657..13a4040 100644 --- a/include/plasp/pddl/PrimitiveType.h +++ b/include/plasp/pddl/PrimitiveType.h @@ -41,7 +41,7 @@ class PrimitiveType void setDeclared(); - void addParentType(const PrimitiveType &parentType); + void addParentType(const PrimitiveType *parentType); bool m_isDirty; bool m_isDeclared; diff --git a/src/plasp/pddl/Constant.cpp b/src/plasp/pddl/Constant.cpp new file mode 100644 index 0000000..b8e2a28 --- /dev/null +++ b/src/plasp/pddl/Constant.cpp @@ -0,0 +1,146 @@ +#include + +#include + +#include +#include + +namespace plasp +{ +namespace pddl +{ + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Constant +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +Constant::Constant(std::string name) +: m_isDirty{false}, + m_isDeclared{false}, + m_name(name), + m_type{nullptr} +{ +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +Constant &Constant::parse(utils::Parser &parser, Context &context) +{ + parser.skipWhiteSpace(); + + const auto constantName = parser.parseIdentifier(isIdentifier); + const auto match = context.constantsHashMap.find(constantName); + const auto constantExists = (match != context.constantsHashMap.cend()); + + // Return existing primitive types + if (constantExists) + { + auto &constant = *match->second; + + constant.setDirty(); + + return constant; + } + + // Store new primitive type + context.constants.emplace_back(std::make_unique(Constant(constantName))); + + auto &constant = *context.constants.back(); + + // Add a pointer to the primitive type to the hash map + context.constantsHashMap.emplace(std::make_pair(constantName, &constant)); + + // Flag type for potentially upcoming parent type declaration + constant.setDirty(); + + return constant; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +Constant &Constant::parseDeclaration(utils::Parser &parser, Context &context) +{ + // Parse and store constant + auto &constant = parse(parser, context); + + // Flag constant as correctly declared in the types section + constant.setDeclared(); + + parser.skipWhiteSpace(); + + // Check for typing information + if (!parser.advanceIf('-')) + return constant; + + // If existing, parse and store parent type + auto &type = PrimitiveType::parse(parser, context); + + // Assign parent type to all types that were previously flagged + std::for_each(context.constants.begin(), context.constants.end(), + [&](auto &constant) + { + if (!constant->isDirty()) + return; + + constant->setType(&type); + constant->setDirty(false); + }); + + return constant; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void Constant::setDirty(bool isDirty) +{ + m_isDirty = isDirty; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +bool Constant::isDirty() const +{ + return m_isDirty; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void Constant::setDeclared() +{ + m_isDeclared = true; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +bool Constant::isDeclared() const +{ + return m_isDeclared; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +const std::string &Constant::name() const +{ + return m_name; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +void Constant::setType(const PrimitiveType *type) +{ + m_type = type; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +const PrimitiveType *Constant::type() const +{ + return m_type; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +} +} diff --git a/src/plasp/pddl/Domain.cpp b/src/plasp/pddl/Domain.cpp index c2ea837..9957369 100644 --- a/src/plasp/pddl/Domain.cpp +++ b/src/plasp/pddl/Domain.cpp @@ -74,6 +74,13 @@ const std::vector> &Domain::types() const //////////////////////////////////////////////////////////////////////////////////////////////////// +const std::vector> &Domain::constants() const +{ + return m_context.constants; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + const std::vector> &Domain::predicates() const { return m_context.predicates; @@ -116,7 +123,7 @@ void Domain::parseSection(utils::Parser &parser) else if (sectionIdentifier == "types") parseTypeSection(parser); else if (sectionIdentifier == "constants") - skipSection(); + parseConstantSection(parser); else if (sectionIdentifier == "predicates") parsePredicateSection(parser); else if (sectionIdentifier == "functions") @@ -125,6 +132,10 @@ void Domain::parseSection(utils::Parser &parser) skipSection(); else if (sectionIdentifier == "action") skipSection(); + else if (sectionIdentifier == "durative-action") + skipSection(); + else if (sectionIdentifier == "derived") + skipSection(); } //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -228,6 +239,23 @@ void Domain::parseTypeSection(utils::Parser &parser) //////////////////////////////////////////////////////////////////////////////////////////////////// +void Domain::parseConstantSection(utils::Parser &parser) +{ + parser.skipWhiteSpace(); + + // Store constants + while (parser.currentCharacter() != ')') + { + Constant::parseDeclaration(parser, m_context); + + parser.skipWhiteSpace(); + } + + parser.expect(")"); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// + void Domain::parsePredicateSection(utils::Parser &parser) { parser.skipWhiteSpace(); @@ -263,6 +291,17 @@ void Domain::checkConsistency() throw ConsistencyException("Type \"" + type->name() + "\" used but never declared"); }); + // Verify that all used constants have been declared + std::for_each(m_context.constants.cbegin(), m_context.constants.cend(), + [&](const auto &constant) + { + if (!constant->isDeclared()) + throw ConsistencyException("Constant \"" + constant->name() + "\" used but never declared"); + + if (constant->type() == nullptr) + throw ConsistencyException("Constant \"" + constant->name() + "\" has an undeclared type"); + }); + // Verify that all used predicates have been declared std::for_each(m_context.predicates.cbegin(), m_context.predicates.cend(), [&](const auto &predicate) diff --git a/src/plasp/pddl/PrimitiveType.cpp b/src/plasp/pddl/PrimitiveType.cpp index f922d3a..e311f6d 100644 --- a/src/plasp/pddl/PrimitiveType.cpp +++ b/src/plasp/pddl/PrimitiveType.cpp @@ -89,7 +89,7 @@ PrimitiveType &PrimitiveType::parseDeclaration(utils::Parser &parser, Context &c if (!childType->isDirty()) return; - childType->addParentType(parentType); + childType->addParentType(&parentType); childType->setDirty(false); }); @@ -133,9 +133,9 @@ const std::string &PrimitiveType::name() const //////////////////////////////////////////////////////////////////////////////////////////////////// -void PrimitiveType::addParentType(const PrimitiveType &parentType) +void PrimitiveType::addParentType(const PrimitiveType *parentType) { - m_parentTypes.emplace_back(&parentType); + m_parentTypes.push_back(parentType); } //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/tests/TestPDDLParser.cpp b/tests/TestPDDLParser.cpp index 8d6ced2..f41033c 100644 --- a/tests/TestPDDLParser.cpp +++ b/tests/TestPDDLParser.cpp @@ -14,7 +14,8 @@ class PDDLParserTests : public ::testing::Test protected: PDDLParserTests() : m_blocksworldDomainFile(readFile("data/blocksworld-domain.pddl")), - m_storageDomainFile(readFile("data/storage-domain.pddl")) + m_storageDomainFile(readFile("data/storage-domain.pddl")), + m_woodworkingDomainFile(readFile("data/woodworking-domain.pddl")) { } @@ -34,6 +35,7 @@ class PDDLParserTests : public ::testing::Test std::stringstream m_blocksworldDomainFile; std::stringstream m_storageDomainFile; + std::stringstream m_woodworkingDomainFile; }; //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -155,3 +157,37 @@ TEST_F(PDDLParserTests, ParseStorageDomain) FAIL() << e.what(); } } + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +TEST_F(PDDLParserTests, ParseConstants) +{ + try + { + const auto description = plasp::pddl::Description::fromStream(m_woodworkingDomainFile); + + ASSERT_NO_THROW(description.domain()); + + const auto &domain = description.domain(); + + // Name + ASSERT_EQ(domain.name(), "woodworking"); + + // Types + const auto &acolour = *domain.types()[0]; + const auto &surface = *domain.types()[4]; + const auto &treatmentstatus = *domain.types()[5]; + + // Constants + ASSERT_EQ(domain.constants().size(), 8u); + ASSERT_EQ(domain.constants()[0]->type(), &surface); + ASSERT_EQ(domain.constants()[2]->type(), &surface); + ASSERT_EQ(domain.constants()[3]->type(), &treatmentstatus); + ASSERT_EQ(domain.constants()[6]->type(), &treatmentstatus); + ASSERT_EQ(domain.constants()[7]->type(), &acolour); + } + catch (const std::exception &e) + { + FAIL() << e.what(); + } +} diff --git a/tests/data/woodworking-domain.pddl b/tests/data/woodworking-domain.pddl new file mode 100644 index 0000000..cbc0e41 --- /dev/null +++ b/tests/data/woodworking-domain.pddl @@ -0,0 +1,215 @@ +(define (domain woodworking) + (:requirements :typing :durative-actions :numeric-fluents) + (:types + acolour awood woodobj machine + surface treatmentstatus - object + highspeed-saw glazer grinder immersion-varnisher + planer saw spray-varnisher - machine + board part - woodobj) + + (:constants + verysmooth smooth rough - surface + varnished glazed untreated colourfragments - treatmentstatus + natural - acolour) + + (:predicates + (idle ?machine - machine) + (unused ?obj - part) + (available ?obj - woodobj) + + (surface-condition ?obj - woodobj ?surface - surface) + (treatment ?obj - part ?treatment - treatmentstatus) + (colour ?obj - part ?colour - acolour) + (wood ?obj - woodobj ?wood - awood) + + (in-highspeed-saw ?b - board ?m - highspeed-saw) + (empty ?m - highspeed-saw) + (has-colour ?machine - machine ?colour - acolour) + (grind-treatment-change ?old ?new - treatmentstatus) + (is-smooth ?surface - surface)) + + (:functions + (board-size ?board - board) + (goal-size ?obj - part)) + + (:durative-action do-immersion-varnish + :parameters (?x - part ?m - immersion-varnisher + ?newcolour - acolour ?surface - surface) + :duration (= ?duration 10) + :condition (and + (at start (idle ?m)) + (at start (available ?x)) + (at start (surface-condition ?x ?surface)) + (at start (is-smooth ?surface)) + (at start (has-colour ?m ?newcolour)) + (at start (treatment ?x untreated))) + :effect (and + (at start (not (idle ?m))) + (at start (not (available ?x))) + (at start (not (treatment ?x untreated))) + (at start (not (colour ?x natural))) + (at end (idle ?m)) + (at end (available ?x)) + (at end (treatment ?x varnished)) + (at end (colour ?x ?newcolour)))) + + (:durative-action do-spray-varnish + :parameters (?x - part ?m - spray-varnisher + ?newcolour - acolour ?surface - surface) + :duration (= ?duration (goal-size ?x)) + :condition (and + (at start (idle ?m)) + (at start (available ?x)) + (at start (surface-condition ?x ?surface)) + (at start (is-smooth ?surface)) + (at start (has-colour ?m ?newcolour)) + (at start (treatment ?x untreated))) + :effect (and + (at start (not (idle ?m))) + (at start (not (available ?x))) + (at start (not (treatment ?x untreated))) + (at start (not (colour ?x natural))) + (at end (idle ?m)) + (at end (available ?x)) + (at end (treatment ?x varnished)) + (at end (colour ?x ?newcolour)))) + + (:durative-action do-glaze + :parameters (?x - part ?m - glazer + ?newcolour - acolour) + :duration (= ?duration (+ (goal-size ?x) 5)) + :condition (and + (at start (idle ?m)) + (at start (available ?x)) + (at start (has-colour ?m ?newcolour)) + (at start (treatment ?x untreated))) + :effect (and + (at start (not (idle ?m))) + (at start (not (available ?x))) + (at start (not (treatment ?x untreated))) + (at start (not (colour ?x natural))) + (at end (idle ?m)) + (at end (available ?x)) + (at end (treatment ?x glazed)) + (at end (colour ?x ?newcolour)))) + + (:durative-action do-grind + :parameters (?x - part ?m - grinder ?oldsurface - surface + ?oldcolour - acolour + ?oldtreatment ?newtreatment - treatmentstatus) + :duration (= ?duration (* 3 (goal-size ?x))) + :condition (and + (at start (idle ?m)) + (at start (available ?x)) + (at start (surface-condition ?x ?oldsurface)) + (at start (is-smooth ?oldsurface)) + (at start (colour ?x ?oldcolour)) + (at start (treatment ?x ?oldtreatment)) + (at start (grind-treatment-change ?oldtreatment ?newtreatment))) + :effect (and + (at start (not (idle ?m))) + (at start (not (available ?x))) + (at start (not (surface-condition ?x ?oldsurface))) + (at start (not (treatment ?x ?oldtreatment))) + (at start (not (colour ?x ?oldcolour))) + (at end (idle ?m)) + (at end (available ?x)) + (at end (surface-condition ?x verysmooth)) + (at end (treatment ?x ?newtreatment)) + (at end (colour ?x natural)))) + + (:durative-action do-plane + :parameters (?x - part ?m - planer ?oldsurface - surface + ?oldcolour - acolour ?oldtreatment - treatmentstatus) + :duration (= ?duration (* 2 (goal-size ?x))) + :condition (and + (at start (idle ?m)) + (at start (available ?x)) + (at start (surface-condition ?x ?oldsurface)) + (at start (treatment ?x ?oldtreatment)) + (at start (colour ?x ?oldcolour))) + :effect (and + (at start (not (idle ?m))) + (at start (not (available ?x))) + (at start (not (surface-condition ?x ?oldsurface))) + (at start (not (treatment ?x ?oldtreatment))) + (at start (not (colour ?x ?oldcolour))) + (at end (idle ?m)) + (at end (available ?x)) + (at end (surface-condition ?x smooth)) + (at end (treatment ?x untreated)) + (at end (colour ?x natural)))) + + (:durative-action load-highspeed-saw + :parameters (?b - board ?m - highspeed-saw) + :duration (= ?duration 30) + :condition (and + (at start (idle ?m)) + (at start (empty ?m)) + (at start (available ?b))) + :effect (and + (at start (not (idle ?m))) + (at start (not (available ?b))) + (at start (not (empty ?m))) + (at end (idle ?m)) + (at end (in-highspeed-saw ?b ?m)))) + + (:durative-action unload-highspeed-saw + :parameters (?b - board ?m - highspeed-saw) + :duration (= ?duration 10) + :condition (and + (at start (idle ?m)) + (at start (in-highspeed-saw ?b ?m))) + :effect (and + (at start (not (idle ?m))) + (at end (available ?b)) + (at end (not (in-highspeed-saw ?b ?m))) + (at end (empty ?m)) + (at end (idle ?m)))) + + (:durative-action cut-board + :parameters (?b - board ?p - part ?m - highspeed-saw ?w - awood + ?surface - surface) + :duration (= ?duration 10) + :condition (and + (at start (idle ?m)) + (at start (unused ?p)) + (at start (in-highspeed-saw ?b ?m)) + (at start (wood ?b ?w)) + (at start (surface-condition ?b ?surface)) + (at start (>= (board-size ?b) (goal-size ?p)))) + :effect (and + (at start (not (idle ?m))) + (at start (not (unused ?p))) + (at start (decrease (board-size ?b) (goal-size ?p))) + (at end (idle ?m)) + (at end (available ?p)) + (at end (wood ?p ?w)) + (at end (surface-condition ?p ?surface)) + (at end (colour ?p natural)) + (at end (treatment ?p untreated)))) + + (:durative-action do-saw + :parameters (?b - board ?p - part ?m - saw ?w - awood + ?surface - surface) + :duration (= ?duration 30) + :condition (and + (at start (idle ?m)) + (at start (unused ?p)) + (at start (available ?b)) + (at start (wood ?b ?w)) + (at start (surface-condition ?b ?surface)) + (at start (>= (board-size ?b) (goal-size ?p)))) + :effect (and + (at start (not (idle ?m))) + (at start (not (unused ?p))) + (at start (not (available ?b))) + (at end (decrease (board-size ?b) (goal-size ?p))) + (at end (idle ?m)) + (at end (available ?p)) + (at end (available ?b)) + (at end (wood ?p ?w)) + (at end (surface-condition ?p ?surface)) + (at end (colour ?p natural)) + (at end (treatment ?p untreated)))) +)