Fawkes API Fawkes Development Version
pddl_semantics.cpp
1/***************************************************************************
2 * pddl_semantics.cpp semantic checks during parsing
3 *
4 * Created: Thursday 15 October 2020
5 * Copyright 2020 Tarik Viehmann
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
21#include "pddl_semantics.h"
22
23#include "pddl_exception.h"
24
25#include <algorithm>
26
27namespace pddl_parser {
28
29namespace semantics_utils {
30bool
31typing_required(const Domain &d)
32{
33 auto typing_reqs = {"typing", "adl", "ucpop"};
34 for (const auto &type_req : typing_reqs) {
35 if (d.requirements.end() != std::find(d.requirements.begin(), d.requirements.end(), type_req)) {
36 return true;
37 }
38 }
39 return false;
40}
41
42void
43check_type_vs_requirement(const iterator_type &where, bool typing_required, const std::string &type)
44{
45 if ((type == "") && typing_required) {
46 throw PddlTypeException(std::string("Missing type."), where);
47 }
48 if ((type != "") && !typing_required) {
49 throw PddlTypeException(std::string("Requirement typing disabled, unexpected type found."),
50 where);
51 }
52}
53
54} // end namespace semantics_utils
55
56pair_type
57TypeSemantics::operator()(const iterator_type &where,
58 const pair_type & parsed,
59 const Domain & domain) const
60{
61 if (!semantics_utils::typing_required(domain)) {
62 throw PddlTypeException(std::string("Requirement typing disabled, unexpected type found."),
63 where);
64 }
65 return parsed;
66}
67
68pair_type
69ParamTransformer::operator()(const iterator_type & where,
70 const pair_strings_type &parsed,
71 string_pairs_type & target) const
72{
73 if (parsed.second.empty()) {
74 std::transform(parsed.first.begin(),
75 parsed.first.end(),
76 std::back_inserter(target),
77 [](const std::string &s) { return std::make_pair(s, ""); });
78 } else {
79 for (const auto &variant_type : parsed.second) {
80 std::transform(parsed.first.begin(),
81 parsed.first.end(),
82 std::back_inserter(target),
83 [variant_type](const std::string &s) {
84 return std::make_pair(s, variant_type);
85 });
86 }
87 }
88 pair_type res = target.back();
89 target.pop_back();
90 return res;
91}
92
93pair_multi_const
94ConstantSemantics::operator()(const iterator_type & where,
95 const pair_multi_const & parsed,
96 const Domain & domain,
97 std::vector<std::string> &warnings) const
98{
99 // typing test:
100 bool typing_enabled = semantics_utils::typing_required(domain);
101 if (typing_enabled) {
102 auto search =
103 std::find_if(domain.types.begin(), domain.types.end(), [parsed](const pair_type &p) {
104 return p.first == parsed.second || p.second == parsed.second;
105 });
106 if (search == domain.types.end()) {
107 throw PddlTypeException(std::string("Unknown type: ") + parsed.second, where);
108 }
109 }
110 semantics_utils::check_type_vs_requirement(where, typing_enabled, parsed.second);
111 for (const auto &constant : parsed.first) {
112 for (const auto &dom_constants : domain.constants) {
113 std::for_each(dom_constants.first.begin(),
114 dom_constants.first.end(),
115 [&parsed, &constant, &dom_constants, &warnings](const auto &c) mutable {
116 if (c == constant && parsed.second != dom_constants.second) {
117 warnings.push_back(std::string("Ambiguous type: ") + constant + " type "
118 + parsed.second + " and " + dom_constants.second);
119 }
120 });
121 }
122 }
123 return parsed;
124}
125
126Action
127ActionSemantics::operator()(const iterator_type &where,
128 const Action & parsed,
129 const Domain & domain) const
130{
131 bool typing_enabled = semantics_utils::typing_required(domain);
132 for (const auto &action_param : parsed.action_params) {
133 if (typing_enabled) {
134 auto search =
135 std::find_if(domain.types.begin(), domain.types.end(), [action_param](const pair_type &p) {
136 return p.first == action_param.second || p.second == action_param.second;
137 });
138 if (search == domain.types.end()) {
139 throw PddlTypeException(std::string("Unknown type: ") + action_param.first + " - "
140 + action_param.second,
141 where);
142 }
143 }
144 semantics_utils::check_type_vs_requirement(where, typing_enabled, action_param.second);
145 }
146 // predicate signature test:
147 string_pairs_type bound_vars;
148 check_action_condition(where, parsed.precondition, domain, parsed, bound_vars);
149 check_action_condition(where, parsed.effect, domain, parsed, bound_vars);
150
151 return parsed;
152}
153
154bool
155ActionSemantics::check_type(const iterator_type &where,
156 const std::string & got,
157 const std::string & expected,
158 const Domain & domain)
159{
160 if (got != expected) {
161 auto generalized_it = std::find_if(domain.types.begin(),
162 domain.types.end(),
163 [got](const pair_type &p) { return p.first == got; });
164 if (generalized_it == domain.types.end()) {
165 return false;
166 } else {
167 return check_type(where, generalized_it->second, expected, domain);
168 }
169 } else {
170 return true;
171 }
172}
173
174void
175ActionSemantics::check_action_condition(const iterator_type &where,
176 const Expression & expr,
177 const Domain & domain,
178 const Action & curr_action,
179 string_pairs_type & bound_vars)
180{
181 auto curr_obj_type = boost::apply_visitor(ExpressionTypeVisitor(), expr.expression);
182 // this function checks conditions, if the expression is an atom, then the action has an invalid structure
183 if (curr_obj_type == std::type_index(typeid(Atom))) {
184 throw PddlExpressionException(std::string("Unexpected Atom in expression: ")
185 + boost::get<Atom>(expr.expression),
186 where);
187 }
188 if (curr_obj_type == std::type_index(typeid(QuantifiedFormula))) {
189 QuantifiedFormula f = boost::get<QuantifiedFormula>(expr.expression);
190 bound_vars.insert(bound_vars.end(), f.args.begin(), f.args.end());
191 check_action_condition(where, f.sub_expr, domain, curr_action, bound_vars);
192 }
193
194 if (curr_obj_type == std::type_index(typeid(Predicate))) {
195 return check_action_predicate(
196 where, boost::get<Predicate>(expr.expression), expr.type, domain, curr_action, bound_vars);
197 }
198}
199
200void
201ActionSemantics::check_action_predicate(const iterator_type & where,
202 const Predicate & pred,
203 const ExpressionType &type,
204 const Domain & domain,
205 const Action & curr_action,
206 string_pairs_type & bound_vars)
207{
208 bool typing_enabled = semantics_utils::typing_required(domain);
209 switch (type) {
210 case ExpressionType::BOOL: {
211 for (const auto &sub_expr : pred.arguments) {
212 // recursively check sub expressions of booelean expressions, they all are predicate expressions
213 check_action_condition(where, sub_expr, domain, curr_action, bound_vars);
214 }
215 break;
216 }
217 case ExpressionType::PREDICATE: {
218 auto defined_pred =
219 // check if the predicate name is defined in the domain ...
220 std::find_if(domain.predicates.begin(),
221 domain.predicates.end(),
222 [pred](const predicate_type &p) { return pred.function == p.first; });
223 if (defined_pred == domain.predicates.end()) {
224 // ... if it is not, then this predicate is invalid
225 throw PddlPredicateException(std::string("Unknown predicate: ") + pred.function, where);
226 } else {
227 // If the predicate is defined, the signature has to match
228 if (defined_pred->second.size() != pred.arguments.size()) {
229 throw PddlPredicateException(std::string("Predicate argument length missmatch, expected ")
230 + std::to_string(defined_pred->second.size()) + " but got "
231 + std::to_string(pred.arguments.size()),
232 where);
233 } else {
234 // and all arguments must be atomic expressions
235 for (size_t i = 0; i < pred.arguments.size(); i++) {
236 if (boost::apply_visitor(ExpressionTypeVisitor(), pred.arguments[i].expression)
237 != std::type_index(typeid(Atom))) {
238 throw PddlPredicateException(std::string("Unexpected nested predicate."), where);
239 } else {
240 Atom curr_arg = boost::get<Atom>(pred.arguments[i].expression);
241 bool is_type_error = false;
242 std::string arg_type = "";
243 if (curr_arg.front() != '?') {
244 // constants need to be known
245 bool constant_found = false;
246 auto constant_match = std::find_if(
247 domain.constants.begin(),
248 domain.constants.end(),
249 [&curr_arg, &domain, &defined_pred, &i, &where, &constant_found, &arg_type](
250 const pair_multi_const &c) mutable {
251 if (c.first.end() != std::find(c.first.begin(), c.first.end(), curr_arg)) {
252 constant_found = true;
253 arg_type += " " + c.second;
254 return check_type(where, c.second, defined_pred->second[i].second, domain);
255 } else {
256 return false;
257 }
258 });
259 if (constant_match == domain.constants.end()) {
260 is_type_error = true;
261 if (!constant_found) {
262 throw PddlConstantException(std::string("Unknown constant ") + curr_arg, where);
263 }
264 }
265 } else {
266 auto bound_vars_match =
267 std::find_if(bound_vars.begin(), bound_vars.end(), [curr_arg](const pair_type &c) {
268 return c.first == curr_arg.substr(1, std::string::npos);
269 });
270 if (bound_vars_match == bound_vars.end()) {
271 auto parameter_match =
272 std::find_if(curr_action.action_params.begin(),
273 curr_action.action_params.end(),
274 [curr_arg](const pair_type &c) {
275 return c.first == curr_arg.substr(1, std::string::npos);
276 });
277 if (parameter_match == curr_action.action_params.end()) {
278 throw PddlParameterException(std::string("Unknown Parameter ") + curr_arg, where);
279 } else {
280 arg_type = parameter_match->second;
281 }
282 } else {
283 arg_type = bound_vars_match->second;
284 }
285 is_type_error = !check_type(where, arg_type, defined_pred->second[i].second, domain);
286 }
287 // and if typing is required, then the types should match the signature
288 if (typing_enabled && is_type_error) {
289 throw PddlTypeException(std::string("Type missmatch: Argument ") + std::to_string(i)
290 + " of " + defined_pred->first + " expects "
291 + defined_pred->second[i].second + " but got " + arg_type,
292 where);
293 }
294 }
295 }
296 }
297 }
298 break;
299 }
300 default: break;
301 }
302}
303} // namespace pddl_parser
Exception thrown by the parser if a declared constant does not match a defined one.
Exception thrown by the parser if an expression is invalid.
Exception thrown by the parser if a parameter mismatch is encountered.
Exception thrown by the parser if a declared relation does not match the defined predicate.
Exception thrown by the parser if declared type does not match the defined one.
This class tries to translate the found plan to interpreteable data for the rest of the program.
A structured representation of a PDDL action.
Definition: pddl_ast.h:133
string_pairs_type action_params
A typed list of action parameters.
Definition: pddl_ast.h:137
Expression effect
The effect of an action.
Definition: pddl_ast.h:143
Expression precondition
The precondition of an action.
Definition: pddl_ast.h:141
pair_multi_const operator()(const iterator_type &where, const pair_multi_const &parsed, const Domain &domain, std::vector< std::string > &warnings) const
Check whether the given type for a set of constants is defined and registers warnings if constants ar...
A structured representation of a PDDL domain.
Definition: pddl_ast.h:157
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
Retrieve the type index of an expression_t expression to determine the underlying type of the variant...
A PDDL Expression.
Definition: pddl_ast.h:78
expression_t expression
The expression formula.
Definition: pddl_ast.h:82
ExpressionType type
The type of the expression, determined at parsing time.
Definition: pddl_ast.h:80
pair_type operator()(const iterator_type &where, const pair_strings_type &parsed, string_pairs_type &target) const
Transform a pair of string vectors to pairs of strings.
A PDDL formula (either part of a precondition or an effect(.
Definition: pddl_ast.h:107
std::vector< Expression > arguments
The arguments of the predicate or the subformulae of the compound formula.
Definition: pddl_ast.h:115
Atom function
The name of the predicate for atomic formulae, 'and' for a conjunction, 'or' for a disjunction,...
Definition: pddl_ast.h:111
A PDDL quantified formula.
Definition: pddl_ast.h:89
Expression sub_expr
Sub-expression that is quantified over.
Definition: pddl_ast.h:97
string_pairs_type args
args that are bound by the quantifier
Definition: pddl_ast.h:94
pair_type operator()(const iterator_type &where, const pair_type &parsed, const Domain &domain) const
Throw an exception if the parsed type is a sub-type but the domain does not have the requirement :typ...