Fawkes API  Fawkes Development Version
test_pddl_parser.cpp
1 /***************************************************************************
2  * test_skill_parser.cpp - Tests for ExecutionTimeEstimator::Skill
3  *
4  * Created: 23-10-2020
5  * Copyright 2021 Tarik Viehmann <viehmann@kbsg.rwth-aachen.de>
6  ****************************************************************************/
7 
8 /* This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU Library General Public License for more details.
17  *
18  * Read the full text in the LICENSE.GPL file in the doc directory.
19  */
20 #include "../pddl_exception.h"
21 #include "../pddl_parser.h"
22 
23 #include <gtest/gtest.h>
24 
25 #include <filesystem>
26 #include <fstream>
27 #include <sstream>
28 
29 using namespace pddl_parser;
30 
31 TEST(PddlParserTest, TypingTest)
32 {
33  auto benchmarks = {R"delim(
34 (define (domain action-arg-pred-missmatch)
35  (:requirements :strips :typing)
36  (:types
37  obj-a - object
38  obj-b - object
39  )
40  (:predicates
41  (pred ?r - obj-a)
42  )
43  (:action test-action
44  :parameters (?t - obj-b)
45  :precondition (pred ?t)
46  :effect (not (pred ?t))
47  )
48 ))delim",
49  R"delim(
50  (define (domain typing-disabled-but-type-defined)
51  (:requirements :strips)
52  (:types
53  obj-a - object
54  )
55  (:predicates
56  (pred ?r)
57  )
58  (:action test-action
59  :parameters (?t)
60  :precondition (pred ?t)
61  :effect (not (pred ?t))
62  )
63 ))delim",
64  R"delim(
65 (define (domain typing-disabled-but-type-constant)
66  (:requirements :strips)
67  (:constants
68  TEST_CONST - object
69  )
70  (:predicates
71  (pred ?r)
72  )
73  (:action test-action
74  :parameters (?t)
75  :precondition (pred ?t)
76  :effect (not (pred ?t))
77  )
78 ))delim",
79  R"delim(
80 (define (domain typing-disabled-but-type-param)
81  (:requirements :strips)
82  (:predicates
83  (pred ?r)
84  )
85  (:action test-action
86  :parameters (?t - object)
87  :precondition (pred ?t)
88  :effect (not (pred ?t))
89  )
90 ))delim",
91  R"delim(
92 (define (domain action-unknown-type-in-pred)
93  (:requirements :strips :typing)
94  (:types
95  obj-a - object
96  )
97  (:predicates
98  (pred ?r - obj-b)
99  )
100  (:action test-action
101  :parameters (?t - obj-a)
102  :precondition (pred ?t)
103  :effect (not (pred ?t))
104  )
105 ))delim",
106  R"delim(
107 (define (domain action-unknown-type-in-param)
108  (:requirements :strips :typing)
109  (:types
110  obj-a - object
111  )
112  (:predicates
113  (pred ?r - obj-a)
114  )
115  (:action test-action
116  :parameters (?t - obj-b)
117  :precondition (pred ?t)
118  :effect (not (pred ?t))
119  )
120 ))delim",
121  R"delim(
122 (define (domain action-unknown-type-in-constant)
123  (:requirements :strips :typing)
124  (:types
125  obj-a - object
126  )
127  (:constants
128  TEST_CONST - obj-b
129  )
130  (:predicates
131  (pred ?r - obj-a)
132  )
133  (:action test-action
134  :parameters (?t - obj-a)
135  :precondition (pred ?t)
136  :effect (not (pred ?t))
137  )
138 ))delim",
139  R"delim(
140 (define (domain action-constant-missmatch)
141  (:requirements :strips :typing)
142  (:types
143  obj-a - object
144  obj-b - object
145  )
146  (:constants
147  TEST_CONST - obj-b
148  )
149  (:predicates
150  (pred ?r - obj-a)
151  )
152  (:action test-action
153  :parameters (?t - obj-a)
154  :precondition (pred TEST_CONST)
155  :effect (not (pred ?t))
156  )
157 ))delim"};
158  for (const auto &s : benchmarks) {
159  EXPECT_THROW(
160  {
161  PddlParser p;
162  p.parseDomain(s);
163  },
165  }
166 }
167 
168 TEST(PddlParserTest, MinimalDomain)
169 {
170  PddlParser p;
171  Domain d;
172  EXPECT_NO_THROW(d = p.parseDomain(R"delim(
173 (define (domain test-domain)
174  (:requirements)
175  (:predicates
176  (pred)
177  )
178  (:action test-action
179  :parameters (?t)
180  :precondition (pred)
181  :effect (not (pred))
182  )
183 ))delim"););
184 
185  ASSERT_EQ(d.requirements.size(), 0);
186  ASSERT_EQ(d.types.size(), 0);
187  ASSERT_EQ(d.constants.size(), 0);
188  ASSERT_EQ(d.predicates.size(), 1);
189  ASSERT_EQ(d.functions.size(), 0);
190  ASSERT_EQ(d.actions.size(), 1);
191  ASSERT_EQ(d.actions[0].name, "test-action");
192  ASSERT_EQ(d.actions[0].action_params.size(), 1);
193  // action precondition correctly parsed?
194  ASSERT_EQ(d.actions[0].precondition.type, ExpressionType::PREDICATE);
195  ASSERT_EQ(boost::get<Predicate>(d.actions[0].precondition.expression).function, "pred");
196  ASSERT_EQ(boost::get<Predicate>(d.actions[0].precondition.expression).arguments.size(), 0);
197  // action effect correctly parsed?
198  ASSERT_EQ(d.actions[0].effect.type, ExpressionType::BOOL);
199  ASSERT_EQ(boost::get<Predicate>(d.actions[0].effect.expression).function, "not");
200  ASSERT_EQ(boost::get<Predicate>(d.actions[0].effect.expression).arguments.size(), 1);
201  ASSERT_EQ(boost::get<Predicate>(d.actions[0].effect.expression).arguments[0].type,
202  ExpressionType::PREDICATE);
203  ASSERT_EQ(boost::get<Predicate>(
204  boost::get<Predicate>(d.actions[0].effect.expression).arguments[0].expression)
205  .function,
206  "pred");
207  ASSERT_EQ(boost::get<Predicate>(
208  boost::get<Predicate>(d.actions[0].effect.expression).arguments[0].expression)
209  .arguments.size(),
210  0);
211 }
212 
213 TEST(PddlParserTest, DurativeAction)
214 {
215  PddlParser p;
216  Domain d;
217  EXPECT_NO_THROW(d = p.parseDomain(R"delim(
218 (define (domain test-durative-action)
219  (:requirements :strips :durative-actions)
220  (:predicates
221  (pred ?r)
222  )
223  (:durative-action test-action
224  :parameters (?t)
225  :duration (= ?duration 5.5)
226  :condition (and (at start (pred ?t))
227  (over all (pred ?t)))
228  :effect (and (at end (not (pred ?t)))
229  (at start (pred ?t)))
230  )
231 ))delim"););
232  ASSERT_EQ(d.requirements.size(), 2);
233  ASSERT_EQ(d.types.size(), 0);
234  ASSERT_EQ(d.constants.size(), 0);
235  ASSERT_EQ(d.predicates.size(), 1);
236  ASSERT_EQ(d.functions.size(), 0);
237  ASSERT_EQ(d.actions.size(), 1);
238  ASSERT_EQ(d.actions[0].name, "test-action");
239  ASSERT_EQ(d.actions[0].duration.type, ExpressionType::VALUE);
240  ASSERT_EQ(boost::get<Atom>(d.actions[0].duration.expression), "5.5");
241  ASSERT_EQ(d.actions[0].action_params.size(), 1);
242  // action precondition correctly parsed?
243  ASSERT_EQ(d.actions[0].precondition.type, ExpressionType::BOOL);
244  ASSERT_EQ(boost::get<Predicate>(d.actions[0].precondition.expression).function, "and");
245  ASSERT_EQ(boost::get<Predicate>(d.actions[0].precondition.expression).arguments.size(), 2);
246  ASSERT_EQ(boost::get<Predicate>(
247  boost::get<Predicate>(d.actions[0].precondition.expression).arguments[0].expression)
248  .function,
249  "at start");
250  ASSERT_EQ(boost::get<Predicate>(
251  boost::get<Predicate>(d.actions[0].precondition.expression).arguments[0].expression)
252  .arguments.size(),
253  1);
254  ASSERT_EQ(boost::get<Predicate>(
255  boost::get<Predicate>(d.actions[0].precondition.expression).arguments[0].expression)
256  .arguments[0]
257  .type,
258  ExpressionType::PREDICATE);
259  ASSERT_EQ(boost::get<Predicate>(
260  boost::get<Predicate>(
261  boost::get<Predicate>(d.actions[0].precondition.expression).arguments[0].expression)
262  .arguments[0]
263  .expression)
264  .function,
265  "pred");
266  ASSERT_EQ(boost::get<Predicate>(
267  boost::get<Predicate>(
268  boost::get<Predicate>(d.actions[0].precondition.expression).arguments[0].expression)
269  .arguments[0]
270  .expression)
271  .arguments.size(),
272  1);
273  ASSERT_EQ(boost::get<Predicate>(
274  boost::get<Predicate>(
275  boost::get<Predicate>(d.actions[0].precondition.expression).arguments[0].expression)
276  .arguments[0]
277  .expression)
278  .arguments[0]
279  .type,
280  ExpressionType::ATOM);
281  ASSERT_EQ(boost::get<Predicate>(
282  boost::get<Predicate>(d.actions[0].precondition.expression).arguments[1].expression)
283  .function,
284  "over all");
285  ASSERT_EQ(boost::get<Predicate>(
286  boost::get<Predicate>(d.actions[0].precondition.expression).arguments[1].expression)
287  .arguments.size(),
288  1);
289  ASSERT_EQ(boost::get<Predicate>(
290  boost::get<Predicate>(d.actions[0].precondition.expression).arguments[1].expression)
291  .arguments[0]
292  .type,
293  ExpressionType::PREDICATE);
294  ASSERT_EQ(boost::get<Predicate>(
295  boost::get<Predicate>(
296  boost::get<Predicate>(d.actions[0].precondition.expression).arguments[1].expression)
297  .arguments[0]
298  .expression)
299  .function,
300  "pred");
301  ASSERT_EQ(boost::get<Predicate>(
302  boost::get<Predicate>(
303  boost::get<Predicate>(d.actions[0].precondition.expression).arguments[1].expression)
304  .arguments[0]
305  .expression)
306  .arguments.size(),
307  1);
308  ASSERT_EQ(boost::get<Predicate>(
309  boost::get<Predicate>(
310  boost::get<Predicate>(d.actions[0].precondition.expression).arguments[1].expression)
311  .arguments[0]
312  .expression)
313  .arguments[0]
314  .type,
315  ExpressionType::ATOM);
316  // action effect correctly parsed?
317  ASSERT_EQ(boost::get<Predicate>(d.actions[0].effect.expression).function, "and");
318  ASSERT_EQ(boost::get<Predicate>(d.actions[0].effect.expression).arguments.size(), 2);
319  ASSERT_EQ(boost::get<Predicate>(
320  boost::get<Predicate>(d.actions[0].effect.expression).arguments[0].expression)
321  .function,
322  "at end");
323  ASSERT_EQ(boost::get<Predicate>(
324  boost::get<Predicate>(d.actions[0].effect.expression).arguments[0].expression)
325  .arguments.size(),
326  1);
327  ASSERT_EQ(boost::get<Predicate>(
328  boost::get<Predicate>(d.actions[0].effect.expression).arguments[0].expression)
329  .arguments[0]
330  .type,
331  ExpressionType::BOOL);
332  ASSERT_EQ(boost::get<Predicate>(
333  boost::get<Predicate>(
334  boost::get<Predicate>(d.actions[0].effect.expression).arguments[0].expression)
335  .arguments[0]
336  .expression)
337  .function,
338  "not");
339  ASSERT_EQ(boost::get<Predicate>(
340  boost::get<Predicate>(
341  boost::get<Predicate>(d.actions[0].effect.expression).arguments[0].expression)
342  .arguments[0]
343  .expression)
344  .arguments.size(),
345  1);
346  ASSERT_EQ(boost::get<Predicate>(
347  boost::get<Predicate>(
348  boost::get<Predicate>(d.actions[0].effect.expression).arguments[0].expression)
349  .arguments[0]
350  .expression)
351  .arguments[0]
352  .type,
353  ExpressionType::PREDICATE);
354  ASSERT_EQ(boost::get<Predicate>(
355  boost::get<Predicate>(
356  boost::get<Predicate>(
357  boost::get<Predicate>(d.actions[0].effect.expression).arguments[0].expression)
358  .arguments[0]
359  .expression)
360  .arguments[0]
361  .expression)
362  .function,
363  "pred");
364  ASSERT_EQ(boost::get<Predicate>(
365  boost::get<Predicate>(
366  boost::get<Predicate>(
367  boost::get<Predicate>(d.actions[0].effect.expression).arguments[0].expression)
368  .arguments[0]
369  .expression)
370  .arguments[0]
371  .expression)
372  .arguments.size(),
373  1);
374  ASSERT_EQ(boost::get<Predicate>(
375  boost::get<Predicate>(
376  boost::get<Predicate>(
377  boost::get<Predicate>(d.actions[0].effect.expression).arguments[0].expression)
378  .arguments[0]
379  .expression)
380  .arguments[0]
381  .expression)
382  .arguments[0]
383  .type,
384  ExpressionType::ATOM);
385  ASSERT_EQ(boost::get<Predicate>(
386  boost::get<Predicate>(d.actions[0].effect.expression).arguments[1].expression)
387  .function,
388  "at start");
389  ASSERT_EQ(boost::get<Predicate>(
390  boost::get<Predicate>(d.actions[0].effect.expression).arguments[1].expression)
391  .arguments.size(),
392  1);
393  ASSERT_EQ(boost::get<Predicate>(
394  boost::get<Predicate>(d.actions[0].effect.expression).arguments[1].expression)
395  .arguments[0]
396  .type,
397  ExpressionType::PREDICATE);
398  ASSERT_EQ(boost::get<Predicate>(
399  boost::get<Predicate>(
400  boost::get<Predicate>(d.actions[0].effect.expression).arguments[1].expression)
401  .arguments[0]
402  .expression)
403  .function,
404  "pred");
405  ASSERT_EQ(boost::get<Predicate>(
406  boost::get<Predicate>(
407  boost::get<Predicate>(d.actions[0].effect.expression).arguments[1].expression)
408  .arguments[0]
409  .expression)
410  .arguments.size(),
411  1);
412  ASSERT_EQ(boost::get<Predicate>(
413  boost::get<Predicate>(
414  boost::get<Predicate>(d.actions[0].effect.expression).arguments[1].expression)
415  .arguments[0]
416  .expression)
417  .arguments[0]
418  .type,
419  ExpressionType::ATOM);
420 }
421 
422 TEST(PddlParserTest, Functions)
423 {
424  EXPECT_NO_THROW(PddlParser p; p.parseDomain(R"delim(
425 (define (domain test-functions)
426  (:requirements :strips :numeric-fluents)
427  (:predicates
428  (pred ?r)
429  )
430  (:functions
431  (func ?r)
432  )
433  (:action test-action
434  :parameters (?t)
435  :precondition (and (pred ?t)
436  (= (func ?t) 1.1))
437  :effect (increase (pred ?t) (pred ?t))
438  )
439 ))delim"););
440 }
441 TEST(PddlParserTest, IPC2014)
442 {
443  using recursive_directory_iterator = std::filesystem::recursive_directory_iterator;
444  std::vector<std::string> domains;
445  std::string domain_suffix = "domain.pddl";
446  for (const auto &dir : recursive_directory_iterator(std::string(SRCDIR) + "/ipc2014")) {
447  std::string dirEntry = dir.path().stem().string();
448  std::string file_ending = dir.path().extension().string();
449  if (file_ending == ".pddl" && dirEntry.find("domain") != std::string::npos) {
450  domains.push_back(dir.path().string());
451  }
452  }
453  for (const auto &s : domains) {
454  EXPECT_NO_THROW(std::ifstream t(s); if (t.fail()) {
455  FAIL() << " Failed to read file: " << s;
456  } std::stringstream buffer;
457  buffer << t.rdbuf();
458  PddlParser p;
459  p.parseDomain(buffer.str()););
460  }
461 }
Parse a PDDL domain file or problem.
Definition: pddl_parser.h:34
static Domain parseDomain(const std::string &pddl_domain)
Parse the PDDL domain.
Definition: pddl_parser.cpp:72
Exception thrown by the parser if declared type does not match the defined one.
A structured representation of a PDDL domain.
Definition: pddl_ast.h:157
std::vector< Action > actions
A list of actions defined in the domain.
Definition: pddl_ast.h:173
pairs_multi_consts constants
A typed list of constants defined in the domain.
Definition: pddl_ast.h:165
pairs_type types
A list of types with their super types.
Definition: pddl_ast.h:163
std::vector< predicate_type > predicates
A list of predicate names in the domain, including the types of their arguments.
Definition: pddl_ast.h:169
std::vector< std::string > requirements
A list of PDDL features required by the domain.
Definition: pddl_ast.h:161
std::vector< Function > functions
A list of numeric functions in the domain.
Definition: pddl_ast.h:171