knowrob  2.1.0
A Knowledge Base System for Cognition-enabled Robots
formula.cpp
Go to the documentation of this file.
1 /*
2  * This file is part of KnowRob, please consult
3  * https://github.com/knowrob/knowrob for license details.
4  */
5 
6 #include <boost/spirit/include/phoenix.hpp>
7 #include "knowrob/queries/parsers/common.h"
8 #include "knowrob/queries/parsers/formula.h"
9 #include "knowrob/queries/parsers/terms.h"
10 #include "knowrob/queries/parsers/strings.h"
11 #include "knowrob/queries/QueryError.h"
12 #include "knowrob/formulas/Predicate.h"
13 #include "knowrob/formulas/Implication.h"
14 #include "knowrob/formulas/Conjunction.h"
15 #include "knowrob/formulas/Disjunction.h"
16 #include "knowrob/formulas/Negation.h"
17 #include "knowrob/formulas/ModalFormula.h"
18 #include "knowrob/terms/ListTerm.h"
19 #include "knowrob/terms/Term.h"
20 #include "knowrob/terms/Numeric.h"
21 #include "knowrob/TimeInterval.h"
22 #include "knowrob/Logger.h"
23 
24 #define RETURN_FORMULA_RULE(expr) static FormulaRule r(expr); return r
25 #define RETURN_PREDICATE_RULE(expr) static PredicateRule r(expr); return r
26 
27 #define REPORT_UNRECOGNIZED(opt) throw QueryError("Unrecognized option ({}) in modal operator.", *(opt))
28 
29 using namespace knowrob;
30 
31 static ModalOperatorPtr createK(const TermPtr &optionsTerm) {
32  static const auto a_agent1 = Atom::Tabled("agent");
33  static const auto a_agent2 = Atom::Tabled("a");
34 
35  if (optionsTerm && optionsTerm.get() != ListTerm::nil().get()) {
36  auto listTerm = (ListTerm *) optionsTerm.get();
37  std::optional<std::string> agentName;
38 
39  for (auto &option: *listTerm) {
40  // handle options without key
41  if (!agentName.has_value() && option->isAtom()) {
42  // assume first string that appears to be the agent name
43  agentName = std::static_pointer_cast<Atomic>(option)->stringForm();
44  continue;
45  }
46  // handle options with a key
47  else if (option->termType() == TermType::FUNCTION) {
48  // a key was specified for this option, ensure it is the "agent" ("a") key and use the value.
49  auto fn = std::static_pointer_cast<Function>(option);
50  if (fn->arity() == 2) {
51  auto &key = fn->arguments()[0];
52  auto &value = fn->arguments()[1];
53  if (!agentName.has_value() && value->isAtom() &&
54  (*key == *a_agent1 || *key == *a_agent2)) {
55  agentName = std::static_pointer_cast<Atomic>(value)->stringForm();
56  continue;
57  }
58  }
59  }
61  }
62 
63  // create a parametrized modal operator
64  if (agentName.has_value() && agentName.value() != "self") {
65  return modals::K(agentName.value());
66  }
67  }
68  return modals::K();
69 }
70 
71 static ModalOperatorPtr createB(const TermPtr &optionsTerm) {
72  static const auto a_agent1 = Atom::Tabled("agent");
73  static const auto a_agent2 = Atom::Tabled("a");
74  static const auto a_confidence1 = Atom::Tabled("confidence");
75  static const auto a_confidence2 = Atom::Tabled("c");
76 
77  if (optionsTerm && optionsTerm.get() != ListTerm::nil().get()) {
78  auto listTerm = (ListTerm *) optionsTerm.get();
79  std::optional<std::string> agentName;
80  std::optional<double> confidenceValue;
81 
82  for (auto &option: *listTerm) {
83  // handle options without key
84  if (!agentName.has_value() && option->isAtom()) {
85  // assume first string that appears to be the agent name
86  agentName = std::static_pointer_cast<Atomic>(option)->stringForm();
87  continue;
88  } else if (!confidenceValue.has_value() && option->isNumeric()) {
89  // assume first string that appears to be the agent name
90  confidenceValue = std::static_pointer_cast<Numeric>(option)->asDouble();
91  continue;
92  }
93  // handle options with a key
94  else if (option->isFunction()) {
95  // a key was specified for this option, ensure it is the "agent" ("a") key and use the value.
96  auto fn = std::static_pointer_cast<Function>(option);
97  if (fn->arity() == 2) {
98  auto &key = fn->arguments()[0];
99  auto &value = fn->arguments()[1];
100  if (!agentName.has_value() && value->isAtom() &&
101  (*key == *a_agent1 || *key == *a_agent2)) {
102  agentName = std::static_pointer_cast<Atomic>(value)->stringForm();
103  continue;
104  } else if (!confidenceValue.has_value() && value->isNumeric() &&
105  (*key == *a_confidence1 || *key == *a_confidence2)) {
106  confidenceValue = std::static_pointer_cast<Numeric>(value)->asDouble();
107  continue;
108  }
109  }
110  }
112  }
113 
114  if (agentName.has_value() && agentName.value() == "self") agentName = std::nullopt;
115  // create a parametrized modal operator
116  if (agentName.has_value()) {
117  if (confidenceValue.has_value()) {
118  return modals::B(agentName.value(), confidenceValue.value());
119  } else {
120  return modals::B(agentName.value());
121  }
122  } else if (confidenceValue.has_value()) {
123  return modals::B(confidenceValue.value());
124  }
125  }
126  return modals::B();
127 }
128 
129 static inline std::optional<TimeInterval> readTimeInterval(ListTerm *options) {
130  static const auto a_begin = Atom::Tabled("begin");
131  static const auto a_since = Atom::Tabled("since");
132  static const auto a_end = Atom::Tabled("end");
133  static const auto a_until = Atom::Tabled("until");
134 
135  std::optional<TimePoint> beginTime, endTime;
136  bool nextIsBegin = true;
137 
138  for (auto &option: *options) {
139  if (!option) {
140  nextIsBegin = false;
141  continue;
142  } else if (option->termType() == TermType::FUNCTION) {
143  // handle options with a key
144  auto function = (Function *) option.get();
145  if (function->arity() == 2) {
146  auto &key = function->arguments()[0];
147  auto &value = function->arguments()[1];
148  if (value) {
149  if (value->isNumeric()) {
150  auto numeric = std::static_pointer_cast<Numeric>(value);
151  if ((*key == *a_begin || *key == *a_since)) {
152  beginTime = time::fromSeconds(numeric->asDouble());
153  continue;
154  } else if ((*key == *a_end || *key == *a_until)) {
155  endTime = time::fromSeconds(numeric->asDouble());
156  continue;
157  }
158  }
159  }
160  }
161  } else if (option->isNumeric()) {
162  // handle options without key
163  auto numeric = std::static_pointer_cast<Numeric>(option);
164  if (nextIsBegin) {
165  beginTime = time::fromSeconds(numeric->asDouble());
166  nextIsBegin = false;
167  continue;
168  } else {
169  endTime = time::fromSeconds(numeric->asDouble());
170  continue;
171  }
172  } else if (option->isAtomic() && std::static_pointer_cast<Atomic>(option)->stringForm() == "_") {
173  nextIsBegin = false;
174  continue;
175  }
177  }
178 
179  if (beginTime.has_value() || endTime.has_value()) {
180  return TimeInterval(beginTime, endTime);
181  } else {
182  return std::nullopt;
183  }
184 }
185 
186 static ModalOperatorPtr createP(const TermPtr &optionsTerm) {
187  if (optionsTerm && optionsTerm.get() != ListTerm::nil().get()) {
188  auto listTerm = (ListTerm *) optionsTerm.get();
189  auto timeInterval = readTimeInterval(listTerm);
190  if (timeInterval.has_value()) {
191  return modals::P(timeInterval.value());
192  }
193  }
194  return modals::P();
195 }
196 
197 static ModalOperatorPtr createH(const TermPtr &optionsTerm) {
198  if (optionsTerm && optionsTerm.get() != ListTerm::nil().get()) {
199  auto listTerm = (ListTerm *) optionsTerm.get();
200  auto timeInterval = readTimeInterval(listTerm);
201  if (timeInterval.has_value()) {
202  return modals::H(timeInterval.value());
203  }
204  }
205  return modals::H();
206 }
207 
208 namespace knowrob::parsers::formula {
209  using namespace knowrob::parsers::terms;
210  namespace qi = boost::spirit::qi;
211 
213  RETURN_PREDICATE_RULE((str::atom_or_iri() >> '(' >> (term() % ',') >> ')')
214  [qi::_val = ptr_<Predicate>()(qi::_1, qi::_2)]);
215  }
216 
218  RETURN_PREDICATE_RULE(str::atom_or_iri() [qi::_val = ptr_<Predicate>()(qi::_1, std::vector<TermPtr>())]);
219  }
220 
223  }
224 
225  struct parsers_struct {
226  parsers_struct() {
227  formula %= implication | brackets;
228  brackets %= ('(' >>formula >> ')');
229 
230  implication = (((disjunction | brackets)
231  >> "->"
232  >> (implication | brackets))
233  [qi::_val = ptr_<Implication>()(qi::_1, qi::_2)]
234  | disjunction[qi::_val = qi::_1]
235  );
236  disjunction = (((conjunction | brackets)
237  >> (qi::char_(';') | qi::char_('|'))
238  >> (disjunction | brackets))
239  [qi::_val = (qi::_1 | qi::_3)]
240  | conjunction[qi::_val = qi::_1]);
241  conjunction = (((unary | brackets)
242  >> (qi::char_(',') | qi::char_('&'))
243  >> (conjunction | brackets))
244  [qi::_val = (qi::_1 & qi::_3)]
245  | unary[qi::_val = qi::_1]);
246 
247  unary %= modal | negation | predicate();
248  negation = (('~' >> (unary | brackets)) [qi::_val = ~qi::_1]);
249  modal %= belief | knowledge | occasional | always;
250 
251  belief = (
252  ('B' >> options_or_nil() >> (unary | brackets))
253  [qi::_val = ptr_<ModalFormula>()(boost::phoenix::bind(&createB, qi::_1), qi::_2)]
254  );
255  knowledge = (
256  ('K' >> options_or_nil() >> (unary | brackets))
257  [qi::_val = ptr_<ModalFormula>()(boost::phoenix::bind(&createK, qi::_1), qi::_2)]
258  );
259  occasional = (
260  ('P' >> options_or_nil() >> (unary | brackets))
261  [qi::_val = ptr_<ModalFormula>()(boost::phoenix::bind(&createP, qi::_1), qi::_2)]
262  );
263  always = (
264  ('H' >> options_or_nil() >> (unary | brackets))
265  [qi::_val = ptr_<ModalFormula>()(boost::phoenix::bind(&createH, qi::_1), qi::_2)]
266  );
267  }
268 
270  FormulaRule brackets;
271  FormulaRule implication;
272  FormulaRule disjunction, conjunction;
273  FormulaRule unary;
274  FormulaRule negation;
275  FormulaRule modal, belief, knowledge, occasional, always;
276  };
277 
278  auto &parsers() {
279  static parsers_struct p;
280  return p;
281  }
282 
284  return parsers().formula;
285  }
286 }
static std::shared_ptr< knowrob::Atom > Tabled(std::string_view stringForm)
Definition: Atom.cpp:40
static std::shared_ptr< ListTerm > nil()
Definition: ListTerm.cpp:22
std::shared_ptr< ModalFormula > K(const FormulaPtr &phi)
std::shared_ptr< ModalFormula > P(const FormulaPtr &phi)
std::shared_ptr< ModalFormula > B(const FormulaPtr &phi)
std::shared_ptr< ModalFormula > H(const FormulaPtr &phi)
PredicateRule & predicate_n()
Definition: formula.cpp:212
boost::spirit::qi::rule< std::string::const_iterator, std::shared_ptr< Predicate >(), boost::spirit::ascii::space_type > PredicateRule
Definition: formula.h:15
PredicateRule & predicate()
Definition: formula.cpp:221
boost::spirit::qi::rule< std::string::const_iterator, std::shared_ptr< Formula >(), boost::spirit::ascii::space_type > FormulaRule
Definition: formula.h:14
FormulaRule & formula()
Definition: formula.cpp:283
PredicateRule & predicate_0()
Definition: formula.cpp:217
StringRule & atom_or_iri()
Definition: strings.cpp:58
FunctionRule & function()
Definition: terms.cpp:140
TermRule & option()
Definition: terms.cpp:110
TermRule & options_or_nil()
Definition: terms.cpp:118
TermRule & term()
Definition: terms.cpp:136
TermRule & options()
Definition: terms.cpp:114
boost::phoenix::function< make_shared_f< T > > ptr_
Definition: common.h:29
TimePoint fromSeconds(double seconds)
Definition: TimePoint.cpp:17
std::shared_ptr< Term > TermPtr
Definition: Term.h:117
std::shared_ptr< const ModalOperator > ModalOperatorPtr
#define REPORT_UNRECOGNIZED(opt)
Definition: formula.cpp:27
#define RETURN_PREDICATE_RULE(expr)
Definition: formula.cpp:25