Fawkes API Fawkes Development Version
clips-executive-rest-api.cpp
1
2/***************************************************************************
3 * clips-executive-rest-api.cpp - CLIPS Executive REST API
4 *
5 * Created: Fri Mar 16 17:17:17 2018
6 * Copyright 2006-2018 Tim Niemueller [www.niemueller.de]
7 ****************************************************************************/
8
9/* This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU Library General Public License for more details.
18 *
19 * Read the full text in the LICENSE.GPL file in the doc directory.
20 */
21
22#include "clips-executive-rest-api.h"
23
24#include <core/threading/mutex_locker.h>
25#include <webview/rest_api_manager.h>
26
27#include <iostream>
28
29using namespace fawkes;
30
31/** @class ClipsExecutiveRestApi "clips-executive-rest-api.h"
32 * REST API backend for the CLIPS executive.
33 * @author Tim Niemueller
34 */
35
36/** Constructor. */
38: Thread("ClipsWebviewThread", Thread::OPMODE_WAITFORWAKEUP)
39{
40}
41
42/** Destructor. */
44{
45}
46
47void
49{
50 {
51 std::map<std::string, LockPtr<CLIPS::Environment>> envs = clips_env_mgr->environments();
52 if (envs.find("executive") == envs.end()) {
53 throw Exception("No CLIPS environment named 'executive' found");
54 }
55 clips_ = envs["executive"];
56 }
57
58 rest_api_ = new WebviewRestApi("clips-executive", logger);
60 WebRequest::METHOD_GET, "/goals", std::bind(&ClipsExecutiveRestApi::cb_list_goals, this));
61 rest_api_->add_handler<Goal>(WebRequest::METHOD_GET,
62 "/goals/{id}",
63 std::bind(&ClipsExecutiveRestApi::cb_get_goal,
64 this,
65 std::placeholders::_1));
67 WebRequest::METHOD_GET,
68 "/domain-operators",
69 std::bind(&ClipsExecutiveRestApi::cb_list_domain_operators, this));
71 WebRequest::METHOD_GET,
72 "/domain-objects",
73 std::bind(&ClipsExecutiveRestApi::cb_list_domain_objects, this));
75 WebRequest::METHOD_GET,
76 "/domain-predicates",
77 std::bind(&ClipsExecutiveRestApi::cb_list_domain_predicates, this));
79 WebRequest::METHOD_GET,
80 "/domain-facts",
81 std::bind(&ClipsExecutiveRestApi::cb_list_domain_facts, this));
83 WebRequest::METHOD_GET, "/plans", std::bind(&ClipsExecutiveRestApi::cb_list_plans, this));
84 rest_api_->add_handler<Plan>(WebRequest::METHOD_GET,
85 "/plans/{goal-id}/{id}",
86 std::bind(&ClipsExecutiveRestApi::cb_get_plan,
87 this,
88 std::placeholders::_1));
90 WebRequest::METHOD_GET,
91 "/pddl-groundings",
92 std::bind(&ClipsExecutiveRestApi::cb_list_pddl_groundings, this));
94 WebRequest::METHOD_GET,
95 "/pddl-predicates",
96 std::bind(&ClipsExecutiveRestApi::cb_list_pddl_predicates, this));
98 WebRequest::METHOD_GET,
99 "/pddl-formulas",
100 std::bind(&ClipsExecutiveRestApi::cb_list_pddl_formulas, this));
102 WebRequest::METHOD_GET,
103 "/grounded-pddl-predicates",
104 std::bind(&ClipsExecutiveRestApi::cb_list_grounded_pddl_predicates, this));
106 WebRequest::METHOD_GET,
107 "/grounded-pddl-formulas",
108 std::bind(&ClipsExecutiveRestApi::cb_list_grounded_pddl_formulas, this));
109
110 rest_api_->add_handler<PDDLGrounding>(WebRequest::METHOD_GET,
111 "/pddl-groundings/{id}",
112 std::bind(&ClipsExecutiveRestApi::cb_get_pddl_groundings,
113 this,
114 std::placeholders::_1));
115 rest_api_->add_handler<PDDLPredicate>(WebRequest::METHOD_GET,
116 "/pddl-predicates/{id}",
117 std::bind(&ClipsExecutiveRestApi::cb_get_pddl_predicates,
118 this,
119 std::placeholders::_1));
120 rest_api_->add_handler<PDDLFormula>(WebRequest::METHOD_GET,
121 "/pddl-formulas/{id}",
122 std::bind(&ClipsExecutiveRestApi::cb_get_pddl_formulas,
123 this,
124 std::placeholders::_1));
126 WebRequest::METHOD_GET,
127 "/grounded-pddl-predicates/{id}",
128 std::bind(&ClipsExecutiveRestApi::cb_get_grounded_pddl_predicates,
129 this,
130 std::placeholders::_1));
132 WebRequest::METHOD_GET,
133 "/grounded-pddl-groundings/{id}",
134 std::bind(&ClipsExecutiveRestApi::cb_get_grounded_pddl_formulas, this, std::placeholders::_1));
135
137}
138
139void
141{
143 delete rest_api_;
144}
145
146void
148{
149}
150
151/** Get a value from a fact.
152 * @param fact pointer to CLIPS fact
153 * @param slot_name name of field to retrieve
154 * @return template-specific return value
155 */
156template <typename T>
157T
158get_value(const CLIPS::Fact::pointer &fact, const std::string &slot_name)
159{
160 CLIPS::Values v = fact->slot_value(slot_name);
161 if (v.empty()) {
162 throw Exception("No value for slot '%s'", slot_name.c_str());
163 }
164 if (v[0].type() == CLIPS::TYPE_SYMBOL && v[0].as_string() == "nil") {
165 return T();
166 }
167 return v[0];
168}
169
170/** Specialization for bool.
171 * @param fact pointer to CLIPS fact
172 * @param slot_name name of field to retrieve
173 * @return boolean value
174 */
175template <>
176bool
177get_value(const CLIPS::Fact::pointer &fact, const std::string &slot_name)
178{
179 CLIPS::Values v = fact->slot_value(slot_name);
180 if (v.empty()) {
181 throw Exception("No value for slot '%s'", slot_name.c_str());
182 }
183 if (v[0].type() != CLIPS::TYPE_SYMBOL) {
184 throw Exception("Value for slot '%s' is not a boolean", slot_name.c_str());
185 }
186 return (v[0].as_string() == "TRUE");
187}
188
189/** Get value array.
190 * This is not a template because the overly verbose operator API
191 * of CLIPS::Value can lead to ambiguous overloads, e.g., resolving
192 * std::string to std::string or const char * operators.
193 * @param fact pointer to CLIPS fact
194 * @param slot_name name of field to retrieve
195 * @return vector of strings from multislot
196 */
197static std::vector<std::string>
198get_values(const CLIPS::Fact::pointer &fact, const std::string &slot_name)
199{
200 CLIPS::Values v = fact->slot_value(slot_name);
201 std::vector<std::string> rv(v.size());
202 for (size_t i = 0; i < v.size(); ++i) {
203 switch (v[i].type()) {
204 case CLIPS::TYPE_FLOAT: rv[i] = std::to_string(static_cast<double>(v[i])); break;
205 case CLIPS::TYPE_INTEGER: rv[i] = std::to_string(static_cast<long long int>(v[i])); break;
206 case CLIPS::TYPE_SYMBOL:
207 case CLIPS::TYPE_STRING:
208 case CLIPS::TYPE_INSTANCE_NAME: rv[i] = static_cast<std::string &>(v[i]); break;
209 default: rv[i] = "CANNOT-REPRESENT"; break;
210 }
211 }
212 return rv;
213}
214
215Goal
216ClipsExecutiveRestApi::generate_goal(CLIPS::Fact::pointer fact)
217{
218 Goal g;
219 g.set_kind("Goal");
221 g.set_id(get_value<std::string>(fact, "id"));
222 g.set__class(get_value<std::string>(fact, "class"));
223 g.set_type(get_value<std::string>(fact, "type"));
224 g.set_sub_type(get_value<std::string>(fact, "sub-type"));
225 g.set_mode(get_value<std::string>(fact, "mode"));
226 g.set_parent(get_value<std::string>(fact, "parent"));
227 g.set_outcome(get_value<std::string>(fact, "outcome"));
228 g.set_error(get_values(fact, "error"));
229 g.set_message(get_value<std::string>(fact, "message"));
230 g.set_priority(get_value<long int>(fact, "priority"));
231 g.set_parameters(get_values(fact, "params"));
232 g.set_meta(get_values(fact, "meta"));
233 g.set_required_resources(get_values(fact, "required-resources"));
234 g.set_acquired_resources(get_values(fact, "acquired-resources"));
235
236 CLIPS::Fact::pointer pfact = clips_->get_facts();
237 while (pfact) {
238 CLIPS::Template::pointer tmpl = pfact->get_template();
239 if (tmpl->name() == "plan") {
240 try {
241 if (get_value<std::string>(pfact, "goal-id") == *g.id()) {
242 g.addto_plans(std::move(get_value<std::string>(pfact, "id")));
243 }
244 } catch (Exception &e) {
245 }
246 }
247 pfact = pfact->next();
248 }
249
250 return g;
251}
252
254ClipsExecutiveRestApi::cb_list_goals()
255{
256 MutexLocker lock(clips_.objmutex_ptr());
258
259 CLIPS::Fact::pointer fact = clips_->get_facts();
260 while (fact) {
261 CLIPS::Template::pointer tmpl = fact->get_template();
262 if (tmpl->name() == "goal") {
263 try {
264 rv.push_back(std::move(generate_goal(fact)));
265 } catch (Exception &e) {
266 logger->log_warn(name(), "Failed to add goal: %s", e.what_no_backtrace());
267 }
268 }
269
270 fact = fact->next();
271 }
272
273 return rv;
274}
275
276Goal
277ClipsExecutiveRestApi::cb_get_goal(WebviewRestParams &params)
278{
279 const std::string id = params.path_arg("id");
280
281 MutexLocker lock(clips_.objmutex_ptr());
282 CLIPS::Fact::pointer fact = clips_->get_facts();
283 while (fact) {
284 CLIPS::Template::pointer tmpl = fact->get_template();
285 if (tmpl->name() == "goal") {
286 try {
287 if (get_value<std::string>(fact, "id") == id) {
288 return generate_goal(fact);
289 }
290 } catch (Exception &e) {
291 logger->log_warn(name(), "Failed to add goal: %s", e.what_no_backtrace());
292 }
293 }
294
295 fact = fact->next();
296 }
297
298 throw WebviewRestException(WebReply::HTTP_BAD_REQUEST, "Goal '%s' is unknown", id.c_str());
299}
300
302ClipsExecutiveRestApi::cb_list_domain_operators()
303{
304 MutexLocker lock(clips_.objmutex_ptr());
306
307 std::map<std::string, std::list<std::pair<std::string, std::string>>> op_params;
308
309 CLIPS::Fact::pointer fact = clips_->get_facts();
310 while (fact) {
311 CLIPS::Template::pointer tmpl = fact->get_template();
312 if (tmpl->name() == "domain-operator-parameter") {
313 std::string operator_name = get_value<std::string>(fact, "operator");
314 if (op_params.find(operator_name) == op_params.end()) {
315 op_params[operator_name] = {};
316 }
317 op_params[operator_name].push_back(
318 std::make_pair(get_value<std::string>(fact, "name"), get_value<std::string>(fact, "type")));
319 }
320 fact = fact->next();
321 }
322
323 fact = clips_->get_facts();
324 while (fact) {
325 CLIPS::Template::pointer tmpl = fact->get_template();
326 if (tmpl->name() == "domain-operator") {
327 try {
329 o.set_kind("DomainOperator");
331 o.set_name(get_value<std::string>(fact, "name"));
332 o.set_wait_sensed(get_value<bool>(fact, "wait-sensed"));
333 if (op_params.find(*o.name()) != op_params.end()) {
334 for (const auto &p : op_params[*o.name()]) {
336 param.set_name(p.first);
337 param.set_type(p.second);
338 o.addto_parameters(std::move(param));
339 }
340 }
341
342 rv.push_back(std::move(o));
343 } catch (Exception &e) {
344 logger->log_warn(name(), "Failed to add goal: %s", e.what_no_backtrace());
345 }
346 }
347
348 fact = fact->next();
349 }
350
351 return rv;
352}
353
355ClipsExecutiveRestApi::cb_list_domain_objects()
356{
357 MutexLocker lock(clips_.objmutex_ptr());
359
360 CLIPS::Fact::pointer fact = clips_->get_facts();
361 while (fact) {
362 CLIPS::Template::pointer tmpl = fact->get_template();
363 if (tmpl->name() == "domain-object") {
364 DomainObject o;
365 o.set_kind("DomainObject");
367 o.set_name(get_value<std::string>(fact, "name"));
368 o.set_type(get_value<std::string>(fact, "type"));
369 rv.push_back(std::move(o));
370 }
371 fact = fact->next();
372 }
373
374 return rv;
375}
376
378ClipsExecutiveRestApi::cb_list_domain_predicates()
379{
380 MutexLocker lock(clips_.objmutex_ptr());
382
383 CLIPS::Fact::pointer fact = clips_->get_facts();
384 while (fact) {
385 CLIPS::Template::pointer tmpl = fact->get_template();
386 if (tmpl->name() == "domain-predicate") {
388 p.set_kind("DomainPredicate");
390 p.set_name(get_value<std::string>(fact, "name"));
391 p.set_sensed(get_value<bool>(fact, "sensed"));
392 p.set_param_names(get_values(fact, "param-names"));
393 p.set_param_types(get_values(fact, "param-types"));
394 rv.push_back(std::move(p));
395 }
396 fact = fact->next();
397 }
398
399 return rv;
400}
401
403ClipsExecutiveRestApi::cb_list_domain_facts()
404{
405 MutexLocker lock(clips_.objmutex_ptr());
407
408 CLIPS::Fact::pointer fact = clips_->get_facts();
409 while (fact) {
410 CLIPS::Template::pointer tmpl = fact->get_template();
411 if (tmpl->name() == "domain-fact") {
412 DomainFact f;
413 f.set_kind("DomainFact");
415 f.set_name(get_value<std::string>(fact, "name"));
416 f.set_param_values(get_values(fact, "param-values"));
417 rv.push_back(std::move(f));
418 }
419 fact = fact->next();
420 }
421
422 return rv;
423}
424
425std::shared_ptr<PDDLGrounding>
426ClipsExecutiveRestApi::gen_pddl_grounding(const CLIPS::Fact::pointer fact)
427{
428 auto grounding = std::make_shared<PDDLGrounding>();
429 grounding->set_kind("PDDLGrounding");
430 grounding->set_apiVersion(PDDLGrounding::api_version());
431 grounding->set_id(get_value<std::string>(fact, "id"));
432
433 for (const auto &pn : get_values(fact, "param-names")) {
434 grounding->addto_param_names(std::move(pn));
435 }
436
437 for (const auto &pv : get_values(fact, "param-values")) {
438 grounding->addto_param_values(std::move(pv));
439 }
440
441 return grounding;
442}
443
445ClipsExecutiveRestApi::cb_list_pddl_groundings()
446{
447 MutexLocker lock(clips_.objmutex_ptr());
449
450 CLIPS::Fact::pointer fact = clips_->get_facts();
451 while (fact) {
452 CLIPS::Template::pointer tmpl = fact->get_template();
453 if (tmpl->name() == "pddl-grounding") {
454 rv.push_back(*gen_pddl_grounding(fact));
455 }
456 fact = fact->next();
457 }
458
459 return rv;
460}
461
463ClipsExecutiveRestApi::cb_get_pddl_groundings(WebviewRestParams &params)
464{
465 std::string id = params.path_arg("id");
466
467 MutexLocker lock(clips_.objmutex_ptr());
468 PDDLGrounding ret;
469
470 CLIPS::Fact::pointer fact = clips_->get_facts();
471 while (fact) {
472 CLIPS::Template::pointer tmpl = fact->get_template();
473 if (tmpl->name() == "pddl-grounding" && get_value<std::string>(fact, "id") == id) {
474 ret = *gen_pddl_grounding(fact);
475 }
476 fact = fact->next();
477 }
478
479 throw WebviewRestException(WebReply::HTTP_BAD_REQUEST,
480 "No grounding with ID '%s' found",
481 id.c_str());
482
483 return ret;
484}
485
486std::shared_ptr<PDDLFormula>
487ClipsExecutiveRestApi::gen_pddl_formula(const CLIPS::Fact::pointer fact)
488{
489 auto formula = std::make_shared<PDDLFormula>();
490 formula->set_kind("PDDLFormula");
491 formula->set_apiVersion(PDDLFormula::api_version());
492 formula->set_id(get_value<std::string>(fact, "id"));
493 formula->set_type(get_value<std::string>(fact, "type"));
494 formula->set_part_of(get_value<std::string>(fact, "part-of"));
495
496 return formula;
497}
498
500ClipsExecutiveRestApi::cb_list_pddl_formulas()
501{
502 MutexLocker lock(clips_.objmutex_ptr());
504
505 CLIPS::Fact::pointer fact = clips_->get_facts();
506 while (fact) {
507 CLIPS::Template::pointer tmpl = fact->get_template();
508 if (tmpl->name() == "pddl-formula") {
509 rv.push_back(*gen_pddl_formula(fact));
510 }
511 fact = fact->next();
512 }
513
514 return rv;
515}
516
518ClipsExecutiveRestApi::cb_get_pddl_formulas(WebviewRestParams &params)
519{
520 std::string id = params.path_arg("id");
521
522 MutexLocker lock(clips_.objmutex_ptr());
523 PDDLFormula ret;
524
525 CLIPS::Fact::pointer fact = clips_->get_facts();
526 while (fact) {
527 CLIPS::Template::pointer tmpl = fact->get_template();
528 if (tmpl->name() == "pddl-formula" && get_value<std::string>(fact, "id") == id) {
529 ret = *gen_pddl_formula(fact);
530 }
531 fact = fact->next();
532 }
533
534 throw WebviewRestException(WebReply::HTTP_BAD_REQUEST,
535 "No formula with ID '%s' found",
536 id.c_str());
537
538 return ret;
539}
540
541std::shared_ptr<PDDLPredicate>
542ClipsExecutiveRestApi::gen_pddl_predicate(const CLIPS::Fact::pointer fact)
543{
544 auto predicate = std::make_shared<PDDLPredicate>();
545 predicate->set_kind("PDDLPredicate");
546 predicate->set_apiVersion(PDDLPredicate::api_version());
547 predicate->set_id(get_value<std::string>(fact, "id"));
548 predicate->set_part_of(get_value<std::string>(fact, "part-of"));
549 predicate->set_predicate(get_value<std::string>(fact, "predicate"));
550
551 for (const auto &pn : get_values(fact, "param-names")) {
552 predicate->addto_param_names(std::move(pn));
553 }
554
555 for (const auto &pc : get_values(fact, "param-constants")) {
556 predicate->addto_param_constants(std::move(pc));
557 }
558
559 return predicate;
560}
561
563ClipsExecutiveRestApi::cb_list_pddl_predicates()
564{
565 MutexLocker lock(clips_.objmutex_ptr());
567
568 CLIPS::Fact::pointer fact = clips_->get_facts();
569 while (fact) {
570 CLIPS::Template::pointer tmpl = fact->get_template();
571 if (tmpl->name() == "pddl-predicate") {
572 rv.push_back(*gen_pddl_predicate(fact));
573 }
574 fact = fact->next();
575 }
576
577 return rv;
578}
579
581ClipsExecutiveRestApi::cb_get_pddl_predicates(WebviewRestParams &params)
582{
583 std::string id = params.path_arg("id");
584
585 MutexLocker lock(clips_.objmutex_ptr());
586 PDDLPredicate ret;
587
588 CLIPS::Fact::pointer fact = clips_->get_facts();
589 while (fact) {
590 CLIPS::Template::pointer tmpl = fact->get_template();
591 if (tmpl->name() == "pddl-predicate" && get_value<std::string>(fact, "id") == id) {
592 ret = *gen_pddl_predicate(fact);
593 }
594 fact = fact->next();
595 }
596
597 throw WebviewRestException(WebReply::HTTP_BAD_REQUEST,
598 "No predicate with ID '%s' found",
599 id.c_str());
600
601 return ret;
602}
603
604std::shared_ptr<GroundedPDDLFormula>
605ClipsExecutiveRestApi::gen_grounded_pddl_formula(const CLIPS::Fact::pointer fact)
606{
607 auto formula = std::make_shared<GroundedPDDLFormula>();
608 formula->set_kind("GroundedPDDLFormula");
609 formula->set_apiVersion(GroundedPDDLFormula::api_version());
610 formula->set_id(get_value<std::string>(fact, "id"));
611 formula->set_formula_id(get_value<std::string>(fact, "formula-id"));
612 formula->set_grounding(get_value<std::string>(fact, "grounding"));
613 formula->set_is_satisfied(get_value<bool>(fact, "is-satisfied"));
614
615 return formula;
616}
617
619ClipsExecutiveRestApi::cb_list_grounded_pddl_formulas()
620{
621 MutexLocker lock(clips_.objmutex_ptr());
623
624 CLIPS::Fact::pointer fact = clips_->get_facts();
625 while (fact) {
626 CLIPS::Template::pointer tmpl = fact->get_template();
627 if (tmpl->name() == "grounded-pddl-formula") {
628 rv.push_back(*gen_grounded_pddl_formula(fact));
629 }
630 fact = fact->next();
631 }
632
633 return rv;
634}
635
637ClipsExecutiveRestApi::cb_get_grounded_pddl_formulas(WebviewRestParams &params)
638{
639 std::string id = params.path_arg("id");
640
641 MutexLocker lock(clips_.objmutex_ptr());
643
644 CLIPS::Fact::pointer fact = clips_->get_facts();
645 while (fact) {
646 CLIPS::Template::pointer tmpl = fact->get_template();
647 if (tmpl->name() == "grounded-pddl-formula" && get_value<std::string>(fact, "id") == id) {
648 ret = *gen_grounded_pddl_formula(fact);
649 }
650 fact = fact->next();
651 }
652
653 throw WebviewRestException(WebReply::HTTP_BAD_REQUEST,
654 "No grounded formula with ID '%s' found",
655 id.c_str());
656
657 return ret;
658}
659
660std::shared_ptr<GroundedPDDLPredicate>
661ClipsExecutiveRestApi::gen_grounded_pddl_predicate(const CLIPS::Fact::pointer fact)
662{
663 auto predicate = std::make_shared<GroundedPDDLPredicate>();
664 predicate->set_kind("GroundedPDDLPredicate");
665 predicate->set_apiVersion(GroundedPDDLPredicate::api_version());
666 predicate->set_id(get_value<std::string>(fact, "id"));
667 predicate->set_predicate_id(get_value<std::string>(fact, "predicate-id"));
668 predicate->set_grounding(get_value<std::string>(fact, "grounding"));
669 predicate->set_is_satisfied(get_value<bool>(fact, "is-satisfied"));
670
671 return predicate;
672}
673
675ClipsExecutiveRestApi::cb_list_grounded_pddl_predicates()
676{
677 MutexLocker lock(clips_.objmutex_ptr());
679
680 CLIPS::Fact::pointer fact = clips_->get_facts();
681 while (fact) {
682 CLIPS::Template::pointer tmpl = fact->get_template();
683 if (tmpl->name() == "grounded-pddl-predicate") {
684 rv.push_back(*gen_grounded_pddl_predicate(fact));
685 }
686 fact = fact->next();
687 }
688
689 return rv;
690}
691
693ClipsExecutiveRestApi::cb_get_grounded_pddl_predicates(WebviewRestParams &params)
694{
695 std::string id = params.path_arg("id");
696
697 MutexLocker lock(clips_.objmutex_ptr());
699
700 CLIPS::Fact::pointer fact = clips_->get_facts();
701 while (fact) {
702 CLIPS::Template::pointer tmpl = fact->get_template();
703 if (tmpl->name() == "grounded-pddl-predicate" && get_value<std::string>(fact, "id") == id) {
704 ret = *gen_grounded_pddl_predicate(fact);
705 }
706 fact = fact->next();
707 }
708
709 throw WebviewRestException(WebReply::HTTP_BAD_REQUEST,
710 "No grounded predicate with ID '%s' found",
711 id.c_str());
712
713 return ret;
714}
715
716void
717ClipsExecutiveRestApi::gen_plan_precompute(PlanMap & plans,
718 PlanActionMap & plan_actions,
719 PreCompoundMap & prec,
720 PreAtomMap & prea,
721 PDDLGroundingMap & pgm,
722 PDDLFormulaMap & pfm,
723 PDDLPredicateMap & ppm,
724 GroundedPDDLFormulaMap & gpfm,
725 GroundedPDDLPredicateMap &gppm)
726{
727 CLIPS::Fact::pointer fact = clips_->get_facts();
728 while (fact) {
729 CLIPS::Template::pointer tmpl = fact->get_template();
730 if (tmpl->name() == "plan") {
731 plans[std::make_pair(get_value<std::string>(fact, "goal-id"),
732 get_value<std::string>(fact, "id"))] = fact;
733 } else if (tmpl->name() == "plan-action") {
734 plan_actions[std::make_pair(get_value<std::string>(fact, "goal-id"),
735 get_value<std::string>(fact, "plan-id"))]
736 .push_back(fact);
737 } else if (tmpl->name() == "pddl-grounding") {
738 pgm[get_value<std::string>(fact, "id")] = fact;
739 } else if (tmpl->name() == "pddl-formula") {
740 pfm[get_value<std::string>(fact, "id")] = (fact);
741 } else if (tmpl->name() == "pddl-predicate") {
742 ppm[get_value<std::string>(fact, "id")] = (fact);
743 } else if (tmpl->name() == "grounded-pddl-formula") {
744 gpfm[get_value<std::string>(fact, "grounding")].push_back(fact);
745 } else if (tmpl->name() == "grounded-pddl-predicate") {
746 gppm[get_value<std::string>(fact, "grounding")].push_back(fact);
747 }
748 fact = fact->next();
749 }
750}
751
753ClipsExecutiveRestApi::gen_plan_compute_precons(PDDLFormulaTreeNode node,
754 PDDLFormulaTreeMap tree,
755 PDDLGroundingMap groundings)
756{
757 CLIPS::Fact::pointer node_fp = std::get<0>(node);
758 CLIPS::Fact::pointer node_g_fp = std::get<1>(node);
759 CLIPS::Template::pointer tmpl = node_fp->get_template();
760 GroundedFormula formula;
761
763 if (tmpl->name() == "pddl-predicate") {
764 formula.set_kind("GroundedPredicate");
765 formula.set_name(get_value<std::string>(node_fp, "predicate"));
766 formula.set_type("atom");
767 std::vector<std::string> param_names =
768 get_values(groundings[get_value<std::string>(node_g_fp, "grounding")], "param-names");
769 std::vector<std::string> param_values =
770 get_values(groundings[get_value<std::string>(node_g_fp, "grounding")], "param-values");
771 std::vector<std::string> predicate_param_values;
772 for (const auto &param : get_values(node_fp, "param-names")) {
773 auto it = std::find(param_names.begin(), param_names.end(), param);
774 if (it != param_names.end()) {
775 auto index = std::distance(param_names.begin(), it);
776 predicate_param_values.push_back(param_values[index]);
777 }
778 }
779 formula.set_param_names(get_values(node_g_fp, "param-names"));
780 formula.set_param_values(predicate_param_values);
781 formula.set_param_constants(get_values(node_g_fp, "param-constants"));
782 } else if (tmpl->name() == "pddl-formula") {
783 formula.set_kind("GroundedFormula");
784 formula.set_name(get_value<std::string>(node_fp, "id"));
785 formula.set_type(get_value<std::string>(node_fp, "type"));
786 }
787 get_value<std::string>(node_g_fp, "is-satisfied") == "TRUE" ? formula.set_is_satisfied(true)
788 : formula.set_is_satisfied(false);
789
790 for (const auto &child_node : tree[get_value<std::string>(node_fp, "id")]) {
791 auto child = get_value<std::string>(std::get<0>(child_node), "id");
792 formula.addto_child(gen_plan_compute_precons(child_node, tree, groundings));
793 }
794
795 return formula;
796}
797
798Plan
799ClipsExecutiveRestApi::gen_plan(const PlanKey & plan_key,
800 const CLIPS::Fact::pointer fact,
801 PlanActionMap & plan_actions,
802 PreCompoundMap & prec,
803 PreAtomMap & prea,
804 PDDLGroundingMap & pgm,
805 PDDLFormulaMap & pfm,
806 PDDLPredicateMap & ppm,
807 GroundedPDDLFormulaMap & gpfm,
808 GroundedPDDLPredicateMap & gppm)
809{
810 const std::string &goal_id = get_value<std::string>(fact, "goal-id");
811 const std::string &plan_id = get_value<std::string>(fact, "id");
812
813 Plan p;
814 p.set_kind("Plan");
816 p.set_goal_id(goal_id);
817 p.set_id(plan_id);
818 p.set_cost(get_value<double>(fact, "cost"));
819 if (plan_actions.find(plan_key) != plan_actions.end()) {
820 std::vector<std::shared_ptr<PlanAction>> actions;
821
822 for (auto &pai : plan_actions[plan_key]) {
823 auto pa = std::make_shared<PlanAction>();
824
825 int64_t action_id = get_value<int64_t>(pai, "id");
826 std::string operator_name = get_value<std::string>(pai, "action-name");
827
828 // general info
829 pa->set_kind("PlanAction");
830 pa->set_apiVersion(PlanAction::api_version());
831 pa->set_id(action_id);
832 pa->set_operator_name(operator_name);
833 for (const auto &pv : get_values(pai, "param-values")) {
834 pa->addto_param_values(std::move(pv));
835 }
836 pa->set_state(get_value<std::string>(pai, "state"));
837 pa->set_executable(get_value<bool>(pai, "executable"));
838 pa->set_duration(get_value<double>(pai, "duration"));
839 pa->set_dispatch_time(get_value<double>(pai, "dispatch-time"));
840 pa->set_precondition(gen_pddl_grounding(pgm[get_value<std::string>(pai, "precondition")]));
841
842 // preconditions
843 std::string grnd_name = *(pa->precondition()->id());
844 std::string op_name = *(pa->operator_name());
845 PDDLFormulaTreeMap grounded_parent_map;
846
847 for (const auto &p : gpfm[grnd_name]) {
848 PDDLFormulaTreeNode node = std::make_tuple(pfm[get_value<std::string>(p, "formula-id")], p);
849 grounded_parent_map[get_value<std::string>(pfm[get_value<std::string>(p, "formula-id")],
850 "part-of")]
851 .push_back(node);
852 }
853 for (const auto &p : gppm[grnd_name]) {
854 PDDLFormulaTreeNode node =
855 std::make_tuple(ppm[get_value<std::string>(p, "predicate-id")], p);
856 grounded_parent_map[get_value<std::string>(ppm[get_value<std::string>(p, "predicate-id")],
857 "part-of")]
858 .push_back(node);
859 }
860
861 //get root node
862 for (const auto &rnode : grounded_parent_map[op_name]) {
863 CLIPS::Fact::pointer root_fp = std::get<0>(rnode);
864 std::string root = get_value<std::string>(root_fp, "id");
865
866 //recursively compute the tree and set the preconditions
867 pa->set_preconditions(std::make_shared<GroundedFormula>(
868 gen_plan_compute_precons(rnode, grounded_parent_map, pgm)));
869 }
870
871 actions.push_back(std::move(pa));
872 }
873
874 std::sort(actions.begin(),
875 actions.end(),
876 [](std::shared_ptr<PlanAction> &a, std::shared_ptr<PlanAction> &b) {
877 return *a->id() < *b->id();
878 });
879 p.set_actions(actions);
880 }
881
882 return p;
883}
884
886ClipsExecutiveRestApi::cb_list_plans()
887{
888 MutexLocker lock(clips_.objmutex_ptr());
890
891 std::map<PlanKey, CLIPS::Fact::pointer> plans;
892 std::map<PlanKey, ClipsFactList> plan_actions;
893 PreCompoundMap prec;
894 PreAtomMap prea;
895 PDDLGroundingMap pgm;
896 PDDLFormulaMap pfm;
897 PDDLPredicateMap ppm;
898 GroundedPDDLFormulaMap gpfm;
899 GroundedPDDLPredicateMap gppm;
900
901 gen_plan_precompute(plans, plan_actions, prec, prea, pgm, pfm, ppm, gpfm, gppm);
902
903 for (auto &pi : plans) {
904 rv.push_back(std::move(
905 gen_plan(pi.first, pi.second, plan_actions, prec, prea, pgm, pfm, ppm, gpfm, gppm)));
906 }
907
908 return rv;
909}
910
911Plan
912ClipsExecutiveRestApi::cb_get_plan(WebviewRestParams &params)
913{
914 std::string goal_id = params.path_arg("goal-id");
915 std::string id = params.path_arg("id");
916
917 MutexLocker lock(clips_.objmutex_ptr());
919
920 std::map<PlanKey, CLIPS::Fact::pointer> plans;
921 std::map<PlanKey, ClipsFactList> plan_actions;
922 PreCompoundMap prec;
923 PreAtomMap prea;
924 PDDLGroundingMap pgm;
925 PDDLFormulaMap pfm;
926 PDDLPredicateMap ppm;
927 GroundedPDDLFormulaMap gpfm;
928 GroundedPDDLPredicateMap gppm;
929
930 gen_plan_precompute(plans, plan_actions, prec, prea, pgm, pfm, ppm, gpfm, gppm);
931
932 const PlanKey plan_key{goal_id, id};
933 if (plans.find(plan_key) == plans.end()) {
934 throw WebviewRestException(WebReply::HTTP_BAD_REQUEST,
935 "No plan for goal '%s' with ID '%s' found",
936 goal_id.c_str(),
937 id.c_str());
938 }
939
940 return gen_plan(plan_key, plans[plan_key], plan_actions, prec, prea, pgm, pfm, ppm, gpfm, gppm);
941}
virtual void finalize()
Finalize the thread.
virtual void init()
Initialize the thread.
virtual void loop()
Code to execute in the thread.
DomainFact representation for JSON transfer.
Definition: DomainFact.h:28
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
Definition: DomainFact.h:118
void set_kind(const std::string &kind)
Set kind value.
Definition: DomainFact.h:101
static std::string api_version()
Get version of implemented API.
Definition: DomainFact.h:48
void set_name(const std::string &name)
Set name value.
Definition: DomainFact.h:135
void set_param_values(const std::vector< std::string > &param_values)
Set param-values value.
Definition: DomainFact.h:152
DomainObject representation for JSON transfer.
Definition: DomainObject.h:28
void set_name(const std::string &name)
Set name value.
Definition: DomainObject.h:135
void set_type(const std::string &type)
Set type value.
Definition: DomainObject.h:152
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
Definition: DomainObject.h:118
void set_kind(const std::string &kind)
Set kind value.
Definition: DomainObject.h:101
static std::string api_version()
Get version of implemented API.
Definition: DomainObject.h:48
DomainOperatorParameter representation for JSON transfer.
void set_type(const std::string &type)
Set type value.
void set_name(const std::string &name)
Set name value.
DomainOperator representation for JSON transfer.
void addto_parameters(const std::shared_ptr< DomainOperatorParameter > &&parameters)
Add element to parameters array.
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
void set_kind(const std::string &kind)
Set kind value.
std::optional< std::string > name() const
Get name value.
static std::string api_version()
Get version of implemented API.
void set_name(const std::string &name)
Set name value.
void set_wait_sensed(const bool &wait_sensed)
Set wait-sensed value.
DomainPredicate representation for JSON transfer.
static std::string api_version()
Get version of implemented API.
void set_sensed(const bool &sensed)
Set sensed value.
void set_param_types(const std::vector< std::string > &param_types)
Set param-types value.
void set_name(const std::string &name)
Set name value.
void set_param_names(const std::vector< std::string > &param_names)
Set param-names value.
void set_kind(const std::string &kind)
Set kind value.
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
Goal representation for JSON transfer.
Definition: Goal.h:28
void set_message(const std::string &message)
Set message value.
Definition: Goal.h:272
void set_acquired_resources(const std::vector< std::string > &acquired_resources)
Set acquired-resources value.
Definition: Goal.h:463
void set_parameters(const std::vector< std::string > &parameters)
Set parameters value.
Definition: Goal.h:323
void set_id(const std::string &id)
Set id value.
Definition: Goal.h:135
void set_mode(const std::string &mode)
Set mode value.
Definition: Goal.h:203
void set_sub_type(const std::string &sub_type)
Set sub-type value.
Definition: Goal.h:169
void set_meta(const std::vector< std::string > &meta)
Set meta value.
Definition: Goal.h:358
void set_parent(const std::string &parent)
Set parent value.
Definition: Goal.h:289
void set_required_resources(const std::vector< std::string > &required_resources)
Set required-resources value.
Definition: Goal.h:428
std::optional< std::string > id() const
Get id value.
Definition: Goal.h:126
void set_outcome(const std::string &outcome)
Set outcome value.
Definition: Goal.h:220
void set__class(const std::string &_class)
Set class value.
Definition: Goal.h:186
void set_kind(const std::string &kind)
Set kind value.
Definition: Goal.h:101
static std::string api_version()
Get version of implemented API.
Definition: Goal.h:48
void addto_plans(const std::string &&plans)
Add element to plans array.
Definition: Goal.h:401
void set_priority(const int64_t &priority)
Set priority value.
Definition: Goal.h:306
void set_error(const std::vector< std::string > &error)
Set error value.
Definition: Goal.h:237
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
Definition: Goal.h:118
void set_type(const std::string &type)
Set type value.
Definition: Goal.h:152
GroundedFormula representation for JSON transfer.
static std::string api_version()
Get version of implemented API.
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
void set_param_names(const std::vector< std::string > &param_names)
Set param-names value.
void addto_child(const std::shared_ptr< GroundedFormula > &&child)
Add element to child array.
void set_type(const std::string &type)
Set type value.
void set_kind(const std::string &kind)
Set kind value.
void set_param_values(const std::vector< std::string > &param_values)
Set param-values value.
void set_param_constants(const std::vector< std::string > &param_constants)
Set param-constants value.
void set_is_satisfied(const bool &is_satisfied)
Set is-satisfied value.
void set_name(const std::string &name)
Set name value.
GroundedPDDLFormula representation for JSON transfer.
static std::string api_version()
Get version of implemented API.
GroundedPDDLPredicate representation for JSON transfer.
static std::string api_version()
Get version of implemented API.
PDDLFormula representation for JSON transfer.
Definition: PDDLFormula.h:28
static std::string api_version()
Get version of implemented API.
Definition: PDDLFormula.h:48
PDDLGrounding representation for JSON transfer.
Definition: PDDLGrounding.h:28
static std::string api_version()
Get version of implemented API.
Definition: PDDLGrounding.h:48
PDDLPredicate representation for JSON transfer.
Definition: PDDLPredicate.h:28
static std::string api_version()
Get version of implemented API.
Definition: PDDLPredicate.h:48
static std::string api_version()
Get version of implemented API.
Definition: PlanAction.h:52
Plan representation for JSON transfer.
Definition: Plan.h:29
void set_id(const std::string &id)
Set id value.
Definition: Plan.h:136
void set_goal_id(const std::string &goal_id)
Set goal-id value.
Definition: Plan.h:153
static std::string api_version()
Get version of implemented API.
Definition: Plan.h:49
void set_kind(const std::string &kind)
Set kind value.
Definition: Plan.h:102
void set_cost(const float &cost)
Set cost value.
Definition: Plan.h:170
void set_apiVersion(const std::string &apiVersion)
Set apiVersion value.
Definition: Plan.h:119
void set_actions(const std::vector< std::shared_ptr< PlanAction > > &actions)
Set actions value.
Definition: Plan.h:187
Container to return array via REST.
Definition: rest_array.h:36
void push_back(M &m)
Add item at the back of the container.
Definition: rest_array.h:123
LockPtr< CLIPSEnvManager > clips_env_mgr
CLIPS environment manager.
Definition: clips_manager.h:44
Base class for exceptions in Fawkes.
Definition: exception.h:36
virtual const char * what_no_backtrace() const noexcept
Get primary string (does not implicitly print the back trace).
Definition: exception.cpp:663
Mutex * objmutex_ptr() const
Get object mutex.
Definition: lockptr.h:284
virtual void log_warn(const char *component, const char *format,...)=0
Log warning message.
Logger * logger
This is the Logger member used to access the logger.
Definition: logging.h:41
Mutex locking helper.
Definition: mutex_locker.h:34
Thread class encapsulation of pthreads.
Definition: thread.h:46
const char * name() const
Get name of thread.
Definition: thread.h:100
WebviewRestApiManager * webview_rest_api_manager
Webview REST API manager.
Definition: webview.h:55
void unregister_api(WebviewRestApi *api)
Remove a request processor.
void register_api(WebviewRestApi *api)
Add a REST API.
Webview REST API component.
Definition: rest_api.h:221
void add_handler(WebRequest::Method method, std::string path, Handler handler)
Add handler function.
Definition: rest_api.cpp:85
REST processing exception.
Definition: rest_api.h:71
REST parameters to pass to handlers.
Definition: rest_api.h:125
std::string path_arg(const std::string &what)
Get a path argument.
Definition: rest_api.h:142
Fawkes library namespace.