#include #include #include #include namespace fs = std::experimental::filesystem; const pddl::Context::WarningCallback ignoreWarnings = [](const auto &, const auto &){}; const auto pddlInstanceBasePath = fs::path("data") / "pddl-instances"; //////////////////////////////////////////////////////////////////////////////////////////////////// TEST_CASE("[parser correctness] The official PDDL instances are parsed correctly", "[parser correctness]") { pddl::Tokenizer tokenizer; pddl::Context context(std::move(tokenizer), ignoreWarnings); SECTION("types, predicates, and actions in blocksworld domain") { const auto domainFile = pddlInstanceBasePath / "ipc-2000" / "domains" / "blocks-strips-typed" / "domain.pddl"; context.tokenizer.read(domainFile); auto description = pddl::parseDescription(context); CHECK(description.domain->name == "blocks"); CHECK(description.domain->constants.empty()); const auto &types = description.domain->types; REQUIRE(types.size() == 1); const auto &typeBlock = types[0]; CHECK(typeBlock->name == "block"); const auto &predicates = description.domain->predicates; REQUIRE(predicates.size() == 5); CHECK(predicates[0]->name == "on"); REQUIRE(predicates[0]->parameters.size() == 2); CHECK(predicates[0]->parameters[0]->name == "x"); CHECK(predicates[0]->parameters[0]->type.value().get()->declaration == typeBlock.get()); CHECK(predicates[0]->parameters[1]->name == "y"); CHECK(predicates[0]->parameters[1]->type.value().get()->declaration == typeBlock.get()); CHECK(predicates[1]->name == "ontable"); REQUIRE(predicates[1]->parameters.size() == 1); CHECK(predicates[1]->parameters[0]->name == "x"); CHECK(predicates[1]->parameters[0]->type.value().get()->declaration == typeBlock.get()); CHECK(predicates[2]->name == "clear"); REQUIRE(predicates[2]->parameters.size() == 1); CHECK(predicates[2]->parameters[0]->name == "x"); CHECK(predicates[2]->parameters[0]->type.value().get()->declaration == typeBlock.get()); CHECK(predicates[3]->name == "handempty"); CHECK(predicates[3]->parameters.empty()); CHECK(predicates[4]->name == "holding"); REQUIRE(predicates[4]->parameters.size() == 1); CHECK(predicates[4]->parameters[0]->name == "x"); CHECK(predicates[4]->parameters[0]->type.value().get()->declaration == typeBlock.get()); const auto &actions = description.domain->actions; REQUIRE(actions.size() == 4); CHECK(actions[3]->name == "unstack"); REQUIRE(actions[3]->parameters.size() == 2); CHECK(actions[3]->parameters[0]->name == "x"); CHECK(actions[3]->parameters[0]->type.value().get()->declaration == typeBlock.get()); CHECK(actions[3]->parameters[1]->name == "y"); CHECK(actions[3]->parameters[1]->type.value().get()->declaration == typeBlock.get()); const auto &preconditionAnd = actions[3]->precondition.value().get>(); const auto &precondition0 = preconditionAnd->arguments[0].get().get(); // TODO: check declaration once implemented REQUIRE(precondition0->arguments.size() == 2); CHECK(precondition0->arguments[0].get()->declaration->name == "x"); CHECK(precondition0->arguments[0].get()->declaration->type.value().get()->declaration == typeBlock.get()); CHECK(precondition0->arguments[1].get()->declaration->name == "y"); CHECK(precondition0->arguments[1].get()->declaration->type.value().get()->declaration == typeBlock.get()); const auto &precondition1 = preconditionAnd->arguments[1].get().get(); // TODO: check declaration once implemented REQUIRE(precondition1->arguments.size() == 1); CHECK(precondition1->arguments[0].get()->declaration->name == "x"); CHECK(precondition1->arguments[0].get()->declaration->type.value().get()->declaration == typeBlock.get()); const auto &precondition2 = preconditionAnd->arguments[2].get().get(); // TODO: check declaration once implemented REQUIRE(precondition2->arguments.empty()); const auto &effectAnd = actions[3]->effect.value().get>(); const auto &effect0 = effectAnd->arguments[0].get().get().get(); // TODO: check declaration once implemented REQUIRE(effect0->arguments.size() == 1); CHECK(effect0->arguments[0].get()->declaration->name == "x"); CHECK(effect0->arguments[0].get()->declaration->type.value().get()->declaration == typeBlock.get()); const auto &effect1 = effectAnd->arguments[1].get().get().get(); // TODO: check declaration once implemented REQUIRE(effect1->arguments.size() == 1); CHECK(effect1->arguments[0].get()->declaration->name == "y"); CHECK(effect1->arguments[0].get()->declaration->type.value().get()->declaration == typeBlock.get()); const auto &effectNot2 = effectAnd->arguments[2].get().get>()->argument.get(); // TODO: check declaration once implemented REQUIRE(effectNot2->arguments.size() == 1); CHECK(effectNot2->arguments[0].get()->declaration->name == "x"); CHECK(effectNot2->arguments[0].get()->declaration->type.value().get()->declaration == typeBlock.get()); const auto &effectNot3 = effectAnd->arguments[3].get().get>()->argument.get(); // TODO: check declaration once implemented REQUIRE(effectNot3->arguments.empty()); const auto &effectNot4 = effectAnd->arguments[4].get().get>()->argument.get(); // TODO: check declaration once implemented REQUIRE(effectNot4->arguments.size() == 2); CHECK(effectNot4->arguments[0].get()->declaration->name == "x"); CHECK(effectNot4->arguments[0].get()->declaration->type.value().get()->declaration == typeBlock.get()); CHECK(effectNot4->arguments[1].get()->declaration->name == "y"); CHECK(effectNot4->arguments[1].get()->declaration->type.value().get()->declaration == typeBlock.get()); } SECTION("types, predicates, and actions in blocksworld instance") { const auto domainFile = pddlInstanceBasePath / "ipc-2000" / "domains" / "blocks-strips-typed" / "domain.pddl"; const auto instanceFile = pddlInstanceBasePath / "ipc-2000" / "domains" / "blocks-strips-typed" / "instances" / "instance-1.pddl"; context.tokenizer.read(domainFile); context.tokenizer.read(instanceFile); auto description = pddl::parseDescription(context); const auto &types = description.domain->types; const auto &typeBlock = types[0]; REQUIRE(description.problem); const auto &problem = description.problem.value(); CHECK(problem->name == "blocks-4-0"); CHECK(problem->domain->name == "blocks"); const auto &objects = problem->objects; REQUIRE(objects.size() == 4); CHECK(objects[0]->name == "d"); CHECK(objects[1]->name == "b"); CHECK(objects[2]->name == "a"); CHECK(objects[3]->name == "c"); const auto &facts = problem->initialState.facts; REQUIRE(facts.size() == 9); const auto &fact0 = facts[0].get().get().get(); // TODO: check declaration once implemented REQUIRE(fact0->arguments.size() == 1); CHECK(fact0->arguments[0].get()->declaration->name == "c"); CHECK(fact0->arguments[0].get()->declaration->type.value().get()->declaration == typeBlock.get()); const auto &fact5 = facts[5].get().get().get(); // TODO: check declaration once implemented REQUIRE(fact5->arguments.size() == 1); CHECK(fact5->arguments[0].get()->declaration->name == "a"); CHECK(fact5->arguments[0].get()->declaration->type.value().get()->declaration == typeBlock.get()); const auto &fact8 = facts[8].get().get().get(); // TODO: check declaration once implemented REQUIRE(fact8->arguments.empty()); REQUIRE(problem->goal); const auto &goal = problem->goal.value(); const auto &goalAnd = goal.get>(); REQUIRE(goalAnd->arguments.size() == 3); const auto &goal0 = goalAnd->arguments[0].get().get(); // TODO: check declaration once implemented REQUIRE(goal0->arguments.size() == 2); CHECK(goal0->arguments[0].get()->declaration->name == "d"); CHECK(goal0->arguments[0].get()->declaration->type.value().get()->declaration == typeBlock.get()); CHECK(goal0->arguments[1].get()->declaration->name == "c"); CHECK(goal0->arguments[1].get()->declaration->type.value().get()->declaration == typeBlock.get()); const auto &goal1 = goalAnd->arguments[1].get().get(); // TODO: check declaration once implemented REQUIRE(goal0->arguments.size() == 2); CHECK(goal1->arguments[0].get()->declaration->name == "c"); CHECK(goal1->arguments[0].get()->declaration->type.value().get()->declaration == typeBlock.get()); CHECK(goal1->arguments[1].get()->declaration->name == "b"); CHECK(goal1->arguments[1].get()->declaration->type.value().get()->declaration == typeBlock.get()); const auto &goal2 = goalAnd->arguments[2].get().get(); // TODO: check declaration once implemented REQUIRE(goal0->arguments.size() == 2); CHECK(goal2->arguments[0].get()->declaration->name == "b"); CHECK(goal2->arguments[0].get()->declaration->type.value().get()->declaration == typeBlock.get()); CHECK(goal2->arguments[1].get()->declaration->name == "a"); CHECK(goal2->arguments[1].get()->declaration->type.value().get()->declaration == typeBlock.get()); } SECTION("“either” type in zenotravel domain") { context.mode = pddl::Mode::Compatibility; const auto domainFile = pddlInstanceBasePath / "ipc-2002" / "domains" / "zenotravel-strips-hand-coded" / "domain.pddl"; context.tokenizer.read(domainFile); auto description = pddl::parseDescription(context); const auto &predicates = description.domain->predicates; REQUIRE(predicates.size() == 4); REQUIRE(predicates[0]->name == "at"); REQUIRE(predicates[0]->parameters.size() == 2); REQUIRE(predicates[0]->parameters[0]->name == "x"); REQUIRE(predicates[0]->parameters[0]->type); CHECK(predicates[0]->parameters[0]->type.value().get>()->arguments[0]->declaration->name == "person"); CHECK(predicates[0]->parameters[0]->type.value().get>()->arguments[1]->declaration->name == "aircraft"); REQUIRE(predicates[0]->parameters[1]->name == "c"); REQUIRE(predicates[0]->parameters[1]->type); CHECK(predicates[0]->parameters[1]->type.value().get()->declaration->name == "city"); } SECTION("typed constants in schedule domain") { context.mode = pddl::Mode::Compatibility; const auto domainFile = pddlInstanceBasePath / "ipc-2000" / "domains" / "schedule-adl-typed" / "domain.pddl"; context.tokenizer.read(domainFile); auto description = pddl::parseDescription(context); const auto &constants = description.domain->constants; REQUIRE(constants.size() == 14); CHECK(constants[0]->name == "cold"); CHECK(constants[0]->type.value().get()->declaration->name == "temperature"); CHECK(constants[1]->name == "hot"); CHECK(constants[1]->type.value().get()->declaration->name == "temperature"); CHECK(constants[2]->name == "cylindrical"); CHECK(constants[2]->type.value().get()->declaration->name == "ashape"); CHECK(constants[3]->name == "polisher"); CHECK(constants[3]->type.value().get()->declaration->name == "machine"); CHECK(constants[4]->name == "roller"); CHECK(constants[4]->type.value().get()->declaration->name == "machine"); CHECK(constants[10]->name == "immersion-painter"); CHECK(constants[10]->type.value().get()->declaration->name == "machine"); CHECK(constants[11]->name == "polished"); CHECK(constants[11]->type.value().get()->declaration->name == "surface"); CHECK(constants[13]->name == "smooth"); CHECK(constants[13]->type.value().get()->declaration->name == "surface"); } SECTION("type inheritance in logistics domain") { context.mode = pddl::Mode::Compatibility; const auto domainFile = pddlInstanceBasePath / "ipc-2000" / "domains" / "logistics-strips-typed" / "domain.pddl"; context.tokenizer.read(domainFile); auto description = pddl::parseDescription(context); const auto &types = description.domain->types; REQUIRE(types.size() == 10); CHECK(types[0]->name == "truck"); REQUIRE(types[0]->parentTypes.size() == 1); CHECK(types[0]->parentTypes[0]->declaration->name == "vehicle"); CHECK(types[1]->name == "airplane"); REQUIRE(types[1]->parentTypes.size() == 1); CHECK(types[1]->parentTypes[0]->declaration->name == "vehicle"); CHECK(types[2]->name == "vehicle"); REQUIRE(types[2]->parentTypes.size() == 1); CHECK(types[2]->parentTypes[0]->declaration->name == "physobj"); CHECK(types[3]->name == "package"); REQUIRE(types[3]->parentTypes.size() == 1); CHECK(types[3]->parentTypes[0]->declaration->name == "physobj"); CHECK(types[4]->name == "physobj"); REQUIRE(types[4]->parentTypes.size() == 1); CHECK(types[4]->parentTypes[0]->declaration->name == "object"); CHECK(types[5]->name == "airport"); REQUIRE(types[5]->parentTypes.size() == 1); CHECK(types[5]->parentTypes[0]->declaration->name == "place"); CHECK(types[6]->name == "location"); REQUIRE(types[6]->parentTypes.size() == 1); CHECK(types[6]->parentTypes[0]->declaration->name == "place"); CHECK(types[7]->name == "place"); REQUIRE(types[7]->parentTypes.size() == 1); CHECK(types[7]->parentTypes[0]->declaration->name == "object"); CHECK(types[8]->name == "city"); REQUIRE(types[8]->parentTypes.size() == 1); CHECK(types[8]->parentTypes[0]->declaration->name == "object"); CHECK(types[9]->name == "object"); REQUIRE(types[9]->parentTypes.empty()); } SECTION("typing in mystery domain") { context.mode = pddl::Mode::Compatibility; const auto domainFile = pddlInstanceBasePath / "ipc-1998" / "domains" / "mystery-round-1-adl" / "domain.pddl"; const auto instanceFile = pddlInstanceBasePath / "ipc-1998" / "domains" / "mystery-round-1-adl" / "instances" / "instance-1.pddl"; context.tokenizer.read(domainFile); context.tokenizer.read(instanceFile); auto description = pddl::parseDescription(context); const auto &actions = description.domain->actions; REQUIRE(actions.size() == 3); // TODO: adjust if there are changes to handling :vars section REQUIRE(actions[0]->parameters.size() == 5); CHECK(actions[0]->parameters[0]->name == "c"); CHECK(actions[0]->parameters[0]->type.value().get()->declaration->name == "pain"); CHECK(actions[0]->parameters[1]->name == "v"); CHECK(actions[0]->parameters[1]->type.value().get()->declaration->name == "pleasure"); CHECK(actions[0]->parameters[2]->name == "n"); CHECK(actions[0]->parameters[2]->type.value().get()->declaration->name == "food"); CHECK(actions[0]->parameters[3]->name == "s1"); CHECK(actions[0]->parameters[3]->type.value().get()->declaration->name == "planet"); CHECK(actions[0]->parameters[4]->name == "s2"); CHECK(actions[0]->parameters[4]->type.value().get()->declaration->name == "planet"); REQUIRE(description.problem); const auto &problem = description.problem.value(); const auto &objects = problem->objects; REQUIRE(objects.size() == 21); CHECK(objects[0]->name == "rice"); CHECK(objects[0]->type.value().get()->declaration->name == "food"); CHECK(objects[1]->name == "pear"); CHECK(objects[1]->type.value().get()->declaration->name == "food"); CHECK(objects[2]->name == "flounder"); CHECK(objects[2]->type.value().get()->declaration->name == "food"); CHECK(objects[5]->name == "lamb"); CHECK(objects[5]->type.value().get()->declaration->name == "food"); CHECK(objects[6]->name == "rest"); CHECK(objects[6]->type.value().get()->declaration->name == "pleasure"); CHECK(objects[7]->name == "hangover"); CHECK(objects[7]->type.value().get()->declaration->name == "pain"); CHECK(objects[8]->name == "depression"); CHECK(objects[8]->type.value().get()->declaration->name == "pain"); CHECK(objects[9]->name == "abrasion"); CHECK(objects[9]->type.value().get()->declaration->name == "pain"); CHECK(objects[10]->name == "kentucky"); CHECK(objects[10]->type.value().get()->declaration->name == "province"); CHECK(objects[16]->name == "guanabara"); CHECK(objects[16]->type.value().get()->declaration->name == "province"); CHECK(objects[17]->name == "mars"); CHECK(objects[17]->type.value().get()->declaration->name == "planet"); CHECK(objects[20]->name == "venus"); CHECK(objects[20]->type.value().get()->declaration->name == "planet"); } SECTION("complicated nested effect expressions in schedule domain") { context.mode = pddl::Mode::Compatibility; const auto domainFile = pddlInstanceBasePath / "ipc-2000" / "domains" / "schedule-adl-typed" / "domain.pddl"; context.tokenizer.read(domainFile); auto description = pddl::parseDescription(context); const auto &actions = description.domain->actions; REQUIRE(actions.size() == 9); CHECK(actions[1]->name == "do-roll"); const auto &effectAnd = actions[1]->effect.value().get>(); REQUIRE(effectAnd->arguments.size() == 10); CHECK(effectAnd->arguments[0].get().get().get()->arguments[0].get()->declaration->name == "roller"); CHECK(effectAnd->arguments[1].get().get().is()); CHECK(effectAnd->arguments[2].get().get().is()); CHECK(effectAnd->arguments[3].get().get().is()); const auto &effectWhen4 = effectAnd->arguments[4].get>(); // TODO: check name of declaration CHECK(effectWhen4->argumentLeft.get>()->argument.get().is()); CHECK(effectWhen4->argumentRight.get().get().is()); const auto &effectForAll5 = effectAnd->arguments[5].get>(); REQUIRE(effectForAll5->parameters.size() == 1); CHECK(effectForAll5->parameters[0]->name == "oldsurface"); CHECK(effectForAll5->parameters[0]->type.value().get()->declaration->name == "surface"); const auto &effectForAll5When = effectForAll5->argument.get>(); // TODO: check name of declaration CHECK(effectForAll5When->argumentLeft.get().is()); CHECK(effectForAll5When->argumentRight.get().get>()->argument.is()); const auto &effectForAll6 = effectAnd->arguments[6].get>(); REQUIRE(effectForAll6->parameters.size() == 1); CHECK(effectForAll6->parameters[0]->name == "oldpaint"); CHECK(effectForAll6->parameters[0]->type.value().get()->declaration->name == "colour"); const auto &effectForAll9 = effectAnd->arguments[9].get>(); REQUIRE(effectForAll9->parameters.size() == 1); CHECK(effectForAll9->parameters[0]->name == "oldtemp"); CHECK(effectForAll9->parameters[0]->type.value().get()->declaration->name == "temperature"); const auto &effectForAll9When = effectForAll9->argument.get>(); // TODO: check name of declaration CHECK(effectForAll9When->argumentLeft.get().is()); CHECK(effectForAll9When->argumentRight.get().get>()->argument.is()); } }