knowrob  2.1.0
A Knowledge Base System for Cognition-enabled Robots
Unifier.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/Logger.h"
7 #include "knowrob/terms/Unifier.h"
8 #include "knowrob/formulas/Bottom.h"
9 #include "knowrob/terms/Function.h"
10 
11 // macro toggles on *occurs* check in unification
12 #define USE_OCCURS_CHECK
13 
14 using namespace knowrob;
15 
16 Unifier::Unifier(const TermPtr &t0, const TermPtr &t1)
17  : Bindings(),
18  t0_(t0),
19  t1_(t1),
20  exists_(unify(t0, t1)) {
21 }
22 
23 bool Unifier::unify(const TermPtr &t0, const TermPtr &t1) //NOLINT
24 {
25  if (t1->termType() == TermType::VARIABLE) {
26  return unify(std::static_pointer_cast<Variable>(t1), t0);
27  } else {
28  switch (t0->termType()) {
29  case TermType::VARIABLE:
30  return unify(std::static_pointer_cast<Variable>(t0), t1);
31  case TermType::ATOMIC:
32  // if one of the terms is an atomic, the other must be an equal atomic
33  return *t0 == *t1;
34  case TermType::FUNCTION: {
35  // n-ary functions with n>0 only unify with other n-ary functions
36  if (t1->termType() != TermType::FUNCTION) {
37  return false;
38  }
39  auto *p0 = (Function *) t0.get();
40  auto *p1 = (Function *) t1.get();
41  // tests for functor equality, and matching arity
42  if (*p0->functor() != *p1->functor() ||
43  p0->arity() != p1->arity()) {
44  return false;
45  }
46  // unify all arguments
47  for (std::size_t i = 0; i < p0->arity(); ++i) {
48  if (!unify(p0->arguments()[i], p1->arguments()[i])) {
49  return false;
50  }
51  }
52  break;
53  }
54  }
55  }
56 
57  return true;
58 }
59 
60 bool Unifier::unify(const std::shared_ptr<Variable> &var, const TermPtr &t) {
61 #ifdef USE_OCCURS_CHECK
62  if (t->variables().find(var->name()) != t->variables().end()) {
63  // fail if var *occurs* in t (occurs check)
64  return false;
65  } else {
66 #endif
67  set(var, t);
68  return true;
69 #ifdef USE_OCCURS_CHECK
70  }
71 #endif
72 }
73 
75  if (!exists_) {
76  // no unifier exists
77  return Bottom::get()->functor();
78  } else if (t0_->isGround() || t1_->termType() == TermType::VARIABLE) {
79  // empty unifier, or only substitutions in t1
80  return t0_;
81  } else if (t1_->isGround() || t0_->termType() == TermType::VARIABLE) {
82  // only substitutions in t0
83  return t1_;
84  } else if (t0_->termType() == TermType::FUNCTION) {
85  // both t0_ and t1_ contain variables.
86  auto &p = (
87  t0_->variables().size() < t1_->variables().size() ?
88  t0_ : t1_);
89  return applyBindings(p, *this);
90  } else {
91  KB_WARN("something went wrong during unification.");
92  return Bottom::get()->functor();
93  }
94 }
#define KB_WARN
Definition: Logger.h:27
void set(const std::shared_ptr< Variable > &var, const TermPtr &term)
Definition: Bindings.cpp:52
static const std::shared_ptr< Bottom > & get()
Definition: Bottom.cpp:12
Unifier(const TermPtr &t0, const TermPtr &t1)
Definition: Unifier.cpp:16
TermPtr t1_
Definition: Unifier.h:40
bool unify(const TermPtr &t0, const TermPtr &t1)
Definition: Unifier.cpp:23
TermPtr apply()
Definition: Unifier.cpp:74
TermPtr t0_
Definition: Unifier.h:39
VariableRule & var()
Definition: terms.cpp:91
std::shared_ptr< Term > TermPtr
Definition: Term.h:117
FirstOrderLiteralPtr applyBindings(const FirstOrderLiteralPtr &lit, const Bindings &bindings)