knowrob  2.1.0
A Knowledge Base System for Cognition-enabled Robots
Bindings.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 "knowrob/terms/Bindings.h"
7 #include "knowrob/terms/Unifier.h"
8 #include "knowrob/knowrob.h"
9 #include "knowrob/formulas/CompoundFormula.h"
10 #include "knowrob/formulas/ModalFormula.h"
11 #include "knowrob/formulas/Implication.h"
12 #include "knowrob/formulas/Negation.h"
13 #include "knowrob/formulas/Conjunction.h"
14 #include "knowrob/formulas/Disjunction.h"
15 #include "knowrob/terms/Function.h"
16 #include "knowrob/integration/python/utils.h"
17 #include "knowrob/integration/python/converter/dict.h"
18 #include "knowrob/Logger.h"
19 
20 using namespace knowrob;
21 
22 Bindings::Bindings(const std::map<std::shared_ptr<Variable>, TermPtr> &mapping) {
23  for (const auto &pair: mapping) {
24  set(pair.first, pair.second);
25  }
26 }
27 
28 bool Bindings::operator==(const Bindings &other) const {
29  if (mapping_.size() != other.mapping_.size()) {
30  return false;
31  }
32 
33  for (auto &x: mapping_) {
34  auto &val1 = x.second.second;
35  auto &val2 = other.get(x.first);
36  if (val1 && val2) {
37  if (!(*val1 == *val2)) return false;
38  } else if (val1 || val2) {
39  return false;
40  }
41  }
42 
43  return true;
44 }
45 
46 void Bindings::operator+=(const Bindings &other) {
47  for (auto &x: other.mapping_) {
48  set(x.second.first, x.second.second);
49  }
50 }
51 
52 void Bindings::set(const std::shared_ptr<Variable> &var, const TermPtr &term) {
53  mapping_.insert({var->name(), {var, term}});
54 }
55 
56 bool Bindings::contains(std::string_view varName) const {
57  return mapping_.find(varName) != mapping_.end();
58 }
59 
60 const TermPtr &Bindings::get(std::string_view varName) const {
61  static const TermPtr null_term;
62 
63  auto it = mapping_.find(varName);
64  if (it != mapping_.end()) {
65  return it->second.second;
66  } else {
67  return null_term;
68  }
69 }
70 
71 std::shared_ptr<Atomic> Bindings::getAtomic(std::string_view varName) const {
72  static const std::shared_ptr<Atomic> null_term;
73 
74  auto term = get(varName);
75  if (term && term->termType() == TermType::ATOMIC) {
76  return std::static_pointer_cast<Atomic>(term);
77  } else {
78  return null_term;
79  }
80 }
81 
82 size_t Bindings::hash() const {
83  auto seed = static_cast<size_t>(0);
84 
85  for (const auto &item: mapping_) {
86  // Compute the hash of the key using the in-built hash function for string.
87  hashCombine(seed, std::hash<std::string_view>{}(item.first));
88 
89  auto value_hash = static_cast<size_t>(0);
90  if (item.second.second) {
91  value_hash = item.second.second->hash();
92  }
93  hashCombine(seed, value_hash);
94  }
95 
96  return seed;
97 }
98 
99 std::shared_ptr<const Bindings> Bindings::emptyBindings() {
100  static const auto empty = std::make_shared<Bindings>();
101  return empty;
102 }
103 
104 bool Bindings::isConsistentWith(const Bindings &other) const {
105  const Map *map_small;
106  const Map *map_large;
107  if (mapping_.size() < other.mapping_.size()) {
108  map_small = &mapping_;
109  map_large = &other.mapping_;
110  } else {
111  map_small = &other.mapping_;
112  map_large = &mapping_;
113  }
114 
115  for (const auto &pair: *map_small) {
116  auto it = map_large->find(pair.first);
117  if (it != map_large->end()) {
118  auto t0 = pair.second.second;
119  auto t1 = it->second.second;
120  Unifier sigma(t0, t1);
121  if (!sigma.exists()) {
122  return false;
123  }
124  }
125  }
126 
127  return true;
128 }
129 
130 bool Bindings::unifyWith(const Bindings &other) {
131  for (const auto &pair: other.mapping_) {
132  auto it = mapping_.find(pair.first);
133  if (it == mapping_.end()) {
134  // new variable instantiation
135  mapping_.insert(pair);
136  } else {
137  // variable has already an instantiation, need to unify
138  TermPtr t0 = it->second.second;
139  TermPtr t1 = pair.second.second;
140 
141  // t0 and t1 are not syntactically equal -> compute a unifier
142  Unifier sigma(t0, t1);
143  if (sigma.exists()) {
144  // a unifier exists
145  it->second.second = sigma.apply();
146  } else {
147  // no unifier exists
148  return false;
149  }
150  }
151  }
152 
153  return true;
154 }
155 
156 void Bindings::write(std::ostream &os) const {
157  uint32_t i = 0;
158  os << '{';
159  for (const auto &pair: mapping_) {
160  if (i++ > 0) os << ',';
161  os << pair.first << ':' << ' ' << (*pair.second.second);
162  }
163  os << '}';
164 }
165 
166 template<class T>
167 std::shared_ptr<T> applyCompoundBindings( //NOLINT(misc-no-recursion)
168  const std::shared_ptr<T> &phi,
169  const Bindings &bindings) {
170  std::vector<FormulaPtr> formulae;
171  bool hasNewFormula = false;
172  for (const auto &f: phi->formulae()) {
173  auto f1 = applyBindings(f, bindings);
174  if (f1 != f) {
175  hasNewFormula = true;
176  }
177  formulae.push_back(applyBindings(f, bindings));
178  }
179  if (!hasNewFormula) {
180  return phi;
181  } else {
182  return std::make_shared<T>(formulae);
183  }
184 }
185 
186 namespace knowrob {
187  FormulaPtr applyBindings(const FormulaPtr &phi, const Bindings &bindings) { //NOLINT(misc-no-recursion)
188  if (phi->isGround()) {
189  return phi;
190  }
191  switch (phi->type()) {
192  case FormulaType::MODAL: {
193  auto modal = std::static_pointer_cast<ModalFormula>(phi);
194  auto inner = applyBindings(modal->modalFormula(), bindings);
195  if (inner == modal->modalFormula()) {
196  return modal;
197  } else {
198  return std::make_shared<ModalFormula>(modal->modalOperator(), inner);
199  }
200  }
202  auto implication = std::static_pointer_cast<Implication>(phi);
203  auto antecedent = applyBindings(implication->antecedent(), bindings);
204  auto consequent = applyBindings(implication->consequent(), bindings);
205  if (antecedent == implication->antecedent() && consequent == implication->consequent()) {
206  return implication;
207  } else {
208  return std::make_shared<Implication>(antecedent, consequent);
209  }
210  }
211  case FormulaType::NEGATION: {
212  auto negation = std::static_pointer_cast<Negation>(phi);
213  auto negated = applyBindings(negation->negatedFormula(), bindings);
214  if (negated == negation->negatedFormula()) {
215  return negation;
216  } else {
217  return std::make_shared<Negation>(negated);
218  }
219  }
221  return applyCompoundBindings<Conjunction>(std::static_pointer_cast<Conjunction>(phi), bindings);
223  return applyCompoundBindings<Disjunction>(std::static_pointer_cast<Disjunction>(phi), bindings);
224  case FormulaType::PREDICATE: {
225  auto predicate = std::static_pointer_cast<Predicate>(phi);
226  auto args = predicate->arguments();
227  auto newArgs = std::vector<TermPtr>(args.size());
228  auto hasNewArg = false;
229  for (uint32_t i = 0; i < args.size(); i++) {
230  auto arg = applyBindings(args[i], bindings);
231  if (arg != args[i]) {
232  hasNewArg = true;
233  }
234  newArgs[i] = arg;
235  }
236  if (!hasNewArg) {
237  return predicate;
238  } else {
239  return std::make_shared<Predicate>(predicate->functor(), newArgs);
240  }
241  }
242  }
243  return phi;
244  }
245 
246  TermPtr applyBindings(const TermPtr &t, const Bindings &bindings) { //NOLINT
247  if (t->isGround()) {
248  return t;
249  }
250  switch (t->termType()) {
251  case TermType::ATOMIC:
252  return t;
253  case TermType::VARIABLE: {
254  auto var = std::static_pointer_cast<Variable>(t);
255  auto term = bindings.get(var->name());
256  if (term) {
257  return term;
258  } else {
259  return var;
260  }
261  }
262  case TermType::FUNCTION: {
263  auto function = std::static_pointer_cast<Function>(t);
264  auto args = function->arguments();
265  auto newArgs = std::vector<TermPtr>(args.size());
266  auto hasNewArg = false;
267  for (uint32_t i = 0; i < args.size(); i++) {
268  auto arg = applyBindings(args[i], bindings);
269  if (arg != args[i]) {
270  hasNewArg = true;
271  }
272  newArgs[i] = arg;
273  }
274  if (!hasNewArg) {
275  return function;
276  } else {
277  return std::make_shared<Function>(function->functor(), newArgs);
278  }
279  }
280  }
281  return t;
282  }
283 }
284 
285 namespace knowrob::py {
286  TermPtr applyBindings_t(const TermPtr &t, const Bindings &bindings) {
287  return applyBindings(t, bindings);
288  }
289 
290  FormulaPtr applyBindings_phi(const FormulaPtr &phi, const Bindings &bindings) {
291  return applyBindings(phi, bindings);
292  }
293 
294  template<>
296  using namespace boost::python;
297 
298  class_<Bindings, std::shared_ptr<Bindings>>("Bindings", init<>())
299  .def(init<std::map<VariablePtr, TermPtr>>())
300  .def("__eq__", &Bindings::operator==)
301  .def("__iter__", range(&Bindings::begin, &Bindings::end))
302  .def("__len__", &Bindings::size)
303  .def("__hash__", &Bindings::hash)
304  .def("empty", &Bindings::empty)
305  .def("set", &Bindings::set)
306  .def("get", &Bindings::get, return_value_policy<copy_const_reference>())
307  .def("contains", &Bindings::contains)
308  .def("unifyWith", &Bindings::unifyWith)
309  .def("isConsistentWith", &Bindings::isConsistentWith);
310 
311  // define global functions
312  def("applyBindings", applyBindings_t);
313  def("applyBindings", applyBindings_phi);
314  // Allow implicit conversion from shared_ptr<Bindings> to shared_ptr<const Bindings>
315  register_ptr_to_python<std::shared_ptr<const Bindings> >();
316  implicitly_convertible<std::shared_ptr<Bindings>, std::shared_ptr<const Bindings> >();
317  // Allow conversion from python dict to std::map
318  dict_map_converter<std::shared_ptr<Variable>,std::shared_ptr<Term>>::register_from_python_converter();
319  }
320 }
std::shared_ptr< T > applyCompoundBindings(const std::shared_ptr< T > &phi, const Bindings &bindings)
Definition: Bindings.cpp:167
bool contains(std::string_view varName) const
Definition: Bindings.cpp:56
auto begin() const
Definition: Bindings.h:70
std::shared_ptr< Atomic > getAtomic(std::string_view varName) const
Definition: Bindings.cpp:71
const TermPtr & get(std::string_view varName) const
Definition: Bindings.cpp:60
auto end() const
Definition: Bindings.h:75
bool isConsistentWith(const Bindings &other) const
Definition: Bindings.cpp:104
void set(const std::shared_ptr< Variable > &var, const TermPtr &term)
Definition: Bindings.cpp:52
static std::shared_ptr< const Bindings > emptyBindings()
Definition: Bindings.cpp:99
void write(std::ostream &os) const override
Definition: Bindings.cpp:156
bool unifyWith(const Bindings &other)
Definition: Bindings.cpp:130
void operator+=(const Bindings &other)
Definition: Bindings.cpp:46
auto size() const
Definition: Bindings.h:65
Bindings()=default
bool empty() const
Definition: Bindings.h:60
bool operator==(const Bindings &other) const
Definition: Bindings.cpp:28
size_t hash() const
Definition: Bindings.cpp:82
std::map< std::string_view, std::pair< std::shared_ptr< Variable >, TermPtr > > Map
Definition: Bindings.h:33
bool exists() const
Definition: Unifier.h:30
TermPtr apply()
Definition: Unifier.cpp:74
PredicateRule & predicate()
Definition: formula.cpp:221
VariableRule & var()
Definition: terms.cpp:91
FunctionRule & function()
Definition: terms.cpp:140
TermRule & term()
Definition: terms.cpp:136
FormulaPtr applyBindings_phi(const FormulaPtr &phi, const Bindings &bindings)
Definition: Bindings.cpp:290
TermPtr applyBindings_t(const TermPtr &t, const Bindings &bindings)
Definition: Bindings.cpp:286
void createType< Bindings >()
Definition: Bindings.cpp:295
const IRIAtomPtr range
Definition: rdfs.h:20
std::shared_ptr< Term > TermPtr
Definition: Term.h:117
std::shared_ptr< Formula > FormulaPtr
Definition: Formula.h:99
void hashCombine(std::size_t &seed, const std::size_t &v)
Definition: knowrob.cpp:39
FirstOrderLiteralPtr applyBindings(const FirstOrderLiteralPtr &lit, const Bindings &bindings)