knowrob  2.1.0
A Knowledge Base System for Cognition-enabled Robots
MongologReasoner.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 <gtest/gtest.h>
7 
8 #include "knowrob/Logger.h"
9 #include "knowrob/reasoner/prolog/PrologTests.h"
10 #include "knowrob/reasoner/ReasonerManager.h"
11 #include "knowrob/reasoner/mongolog/MongologReasoner.h"
12 #include "knowrob/queries/QueryError.h"
13 #include "knowrob/reasoner/ReasonerError.h"
14 #include "knowrob/terms/Numeric.h"
15 #include "knowrob/knowrob.h"
16 
17 using namespace knowrob;
18 
19 // make reasoner type accessible
21 
22 // foreign predicates
23 foreign_t pl_is_readonly2(term_t, term_t);
24 
25 foreign_t pl_db_name3(term_t, term_t, term_t);
26 
27 foreign_t pl_uri3(term_t, term_t, term_t);
28 
29 foreign_t pl_assert_triple_cpp9(term_t, term_t, term_t, term_t, term_t, term_t, term_t, term_t, term_t);
30 
32  : PrologReasoner() {}
33 
35 = default;
36 
38  static auto unload_f = "mongolog_reasoner_unload";
40  // also unload the PrologReasoner
42 }
43 
45  static bool initialized = false;
46 
47  if (!initialized) {
48  initialized = true;
49  // load mongolog code once globally into the Prolog engine
50  consult(std::filesystem::path("reasoner") / "mongolog" / "__init__.pl",
51  "user", false);
52 
53  PL_register_foreign("mng_is_readonly_cpp",
54  2, (pl_function_t) pl_is_readonly2, 0);
55  PL_register_foreign("mng_db_name_cpp",
56  3, (pl_function_t) pl_db_name3, 0);
57  PL_register_foreign("mng_uri_cpp",
58  3, (pl_function_t) pl_uri3, 0);
59 
60  PL_register_foreign("mng_assert_triple_cpp",
61  9, (pl_function_t) pl_assert_triple_cpp9, 0);
62  }
63 
64  return true;
65 }
66 
67 bool MongologReasoner::initializeReasoner(const PropertyTree &reasonerConfiguration) {
68  if (!PrologReasoner::initializeReasoner(reasonerConfiguration)) return false;
69 
70  if (!knowledgeGraph_) {
71  knowledgeGraph_ = std::make_shared<MongoKnowledgeGraph>();
72  knowledgeGraph_->setVocabulary(std::make_shared<Vocabulary>());
73  knowledgeGraph_->initializeBackend(
77  );
79  KB_WARN("Falling back to default configuration for MongoDB!");
80  }
81 
82  return true;
83 }
84 
85 std::string_view MongologReasoner::callFunctor() {
86  static const auto call_f = "mongolog_call";
87  return call_f;
88 }
89 
90 static inline std::shared_ptr<MongologReasoner> getMongologReasoner(term_t t_reasonerManager,
91  term_t t_reasonerModule) {
92  auto definedReasoner = PrologReasoner::getDefinedReasoner(t_reasonerManager, t_reasonerModule);
93  if (!definedReasoner) {
94  KB_ERROR("unable to find reasoner with id '{}' (manager id: {}).",
95  *PrologTerm::toKnowRobTerm(t_reasonerModule),
96  *PrologTerm::toKnowRobTerm(t_reasonerManager));
97  return {};
98  }
99  auto reasoner = definedReasoner->value();
100  auto mongolog = std::dynamic_pointer_cast<MongologReasoner>(reasoner);
101  if (!mongolog) {
102  KB_ERROR("reasoner with id '{}' (manager id: {}) is not a mongolog reasoner.",
103  *PrologTerm::toKnowRobTerm(t_reasonerModule),
104  *PrologTerm::toKnowRobTerm(t_reasonerManager));
105  }
106  return mongolog;
107 }
108 
109 
110 foreign_t pl_is_readonly2(term_t t_reasonerManager, term_t t_reasonerModule) {
111  auto mongolog = getMongologReasoner(t_reasonerManager, t_reasonerModule);
112  if (mongolog) {
113  return mongolog->knowledgeGraph()->isReadOnly();
114  }
115  return false;
116 }
117 
118 foreign_t pl_db_name3(term_t t_reasonerManager, term_t t_reasonerModule, term_t t_dbName) {
119  auto mongolog = getMongologReasoner(t_reasonerManager, t_reasonerModule);
120  if (mongolog) {
121  auto &dbName = mongolog->knowledgeGraph()->dbName();
122  return PL_unify_atom_chars(t_dbName, dbName.c_str());
123  }
124  return false;
125 }
126 
127 foreign_t pl_uri3(term_t t_reasonerManager, term_t t_reasonerModule, term_t t_uri) {
128  auto mongolog = getMongologReasoner(t_reasonerManager, t_reasonerModule);
129  if (mongolog) {
130  auto &uri = mongolog->knowledgeGraph()->dbURI();
131  return PL_unify_atom_chars(t_uri, uri.c_str());
132  }
133  return false;
134 }
135 
136 foreign_t pl_assert_triple_cpp9(term_t t_reasonerManager,
137  term_t t_reasonerModule,
138  term_t t_subjectTerm,
139  term_t t_propertyTerm,
140  term_t t_objectTerm,
141  term_t t_graphTerm,
142  term_t t_beginTerm,
143  term_t t_endTerm,
144  term_t t_confidenceTerm) {
145  auto mongolog = getMongologReasoner(t_reasonerManager, t_reasonerModule);
146  if (mongolog) {
147  TripleView tripleData;
148 
149  // "s" field
150  auto subjectTerm = PrologTerm::toKnowRobTerm(t_subjectTerm);
151  if (subjectTerm->termType() != TermType::ATOMIC) throw QueryError("invalid subject term {}", *subjectTerm);
152  tripleData.setSubject(((Atomic *) subjectTerm.get())->stringForm());
153 
154  // "p" field
155  auto propertyTerm = PrologTerm::toKnowRobTerm(t_propertyTerm);
156  if (propertyTerm->termType() != TermType::ATOMIC) throw QueryError("invalid property term {}", *propertyTerm);
157  tripleData.setPredicate(((Atomic *) propertyTerm.get())->stringForm());
158 
159  // "o" field
160  auto objectTerm = PrologTerm::toKnowRobTerm(t_objectTerm);
161  if(objectTerm->termType() == TermType::ATOMIC) {
162  auto atomic = std::static_pointer_cast<Atomic>(objectTerm);
163  if (atomic->isNumeric()) {
164  tripleData.setXSDValue(atomic->stringForm(),
165  std::static_pointer_cast<Numeric>(atomic)->xsdType());
166  } else if (atomic->isIRI()) {
167  tripleData.setObjectIRI(atomic->stringForm());
168  } else if (atomic->isBlank()) {
169  tripleData.setObjectBlank(atomic->stringForm());
170  } else {
171  tripleData.setStringValue(atomic->stringForm());
172  }
173  } else {
174  throw QueryError("object term {} of triple has an invalid type", *objectTerm);
175  }
176 
177  // "g" field
179  if (!PL_is_variable(t_graphTerm)) {
180  graphTerm = PrologTerm::toKnowRobTerm(t_graphTerm);
181  if (graphTerm->termType() != TermType::ATOMIC) throw QueryError("invalid property term {}", *graphTerm);
182  tripleData.setGraph(((Atomic *) graphTerm.get())->stringForm());
183  } else {
184  tripleData.setGraph(mongolog->reasonerManager().backendManager()->vocabulary()->importHierarchy()->defaultGraph());
185  }
186 
187  // "c" field
188  TermPtr confidenceTerm;
189  if (!PL_is_variable(t_confidenceTerm)) {
190  confidenceTerm = PrologTerm::toKnowRobTerm(t_confidenceTerm);
191  if (confidenceTerm->isNumeric()) {
192  tripleData.setConfidence(std::static_pointer_cast<Numeric>(confidenceTerm)->asDouble());
193  } else {
194  throw QueryError("invalid confidence term {}", *confidenceTerm);
195  }
196  }
197 
198  // "b" field
199  TermPtr beginTerm;
200  if (!PL_is_variable(t_beginTerm)) {
201  beginTerm = PrologTerm::toKnowRobTerm(t_beginTerm);
202  if (beginTerm->isNumeric()) {
203  tripleData.setBegin(std::static_pointer_cast<Numeric>(beginTerm)->asDouble());
204  } else {
205  throw QueryError("invalid begin term {}", *beginTerm);
206  }
207  }
208 
209  // "e" field
210  TermPtr endTerm;
211  if (!PL_is_variable(t_endTerm)) {
212  endTerm = PrologTerm::toKnowRobTerm(t_endTerm);
213  if (endTerm->isNumeric()) {
214  tripleData.setEnd(std::static_pointer_cast<Numeric>(endTerm)->asDouble());
215  } else {
216  throw QueryError("invalid end term {}", *endTerm);
217  }
218  }
219 
220  mongolog->reasonerManager().kb()->edb()->mergeInsert(mongolog->knowledgeGraph(), tripleData);
221  //mongolog->kb()->insertOne(tripleData);
222  return true;
223  } else {
224  KB_WARN("[mongolog] unable to assert triple: reasoner not found");
225  return false;
226  }
227 }
228 
229 namespace knowrob::testing {
230  class MongologTests : public PrologTestsBase {
231  protected:
232  static std::shared_ptr<MongologReasoner> reasoner_;
233  static std::shared_ptr<KnowledgeBase> kb_;
234  static std::shared_ptr<MongoKnowledgeGraph> db_;
235 
236  static std::shared_ptr<knowrob::MongoKnowledgeGraph>
237  createBackend2(const std::string &name, const std::shared_ptr<KnowledgeBase> &kb) {
238  auto kg = std::make_shared<MongoKnowledgeGraph>();
239  kb->backendManager()->addPlugin(name, PluginLanguage::CPP, kg);
240  kg->initializeBackend(
244  kg->drop();
245  kg->tripleCollection()->createTripleIndex();
246  return kg;
247  }
248 
249  static std::shared_ptr<MongologReasoner>
250  createReasoner2(const std::string &name, const std::shared_ptr<KnowledgeBase> &kb,
251  const std::shared_ptr<MongoKnowledgeGraph> &db) {
252  auto r = std::make_shared<MongologReasoner>();
253  r->setStorage(db);
254  kb->reasonerManager()->addPlugin(name, PluginLanguage::CPP, r);
255  r->initializeReasoner(knowrob::PropertyTree());
256  r->load_rdf_xml("http://www.ease-crc.org/ont/SOMA.owl");
257  return r;
258  }
259 
260  // Per-test-suite set-up.
261  static void SetUpTestSuite() {
262  // Initialize the reasoner
263  try {
264  reasoner();
265  } catch (std::exception &e) {
266  FAIL() << "SetUpTestSuite failed: " << e.what();
267  }
268  }
269 
270  // Per-test-suite tear-down.
271  static void TearDownTestSuite() {
272  reasoner_ = nullptr;
273  db_ = nullptr;
274  kb_ = nullptr;
275  }
276 
277  static void runTests(const std::string &t) {
278  try {
279  runPrologTests(reasoner(), t);
280  } catch (std::exception &e) {
281  FAIL() << "runTests failed: " << e.what();
282  }
283  }
284 
285  static std::shared_ptr<MongologReasoner> reasoner() {
286  if (!reasoner_) {
287  std::stringstream ss;
288  ss << "mongolog_";
289  insertUnique(ss);
290 
291  kb_ = KnowledgeBase::create();
292  db_ = createBackend2(ss.str(), kb_);
293  reasoner_ = createReasoner2(ss.str(), kb_, db_);
294 
295  kb_->loadCommon();
296  kb_->init();
297  }
298  return reasoner_;
299  }
300 
301  static std::string getPath(const std::string &filename) {
302  return std::filesystem::path("reasoner") / "mongolog" / filename;
303  }
304  };
305 
306  std::shared_ptr<MongologReasoner> MongologTests::reasoner_;
307  std::shared_ptr<KnowledgeBase> MongologTests::kb_;
308  std::shared_ptr<MongoKnowledgeGraph> MongologTests::db_;
309 }
310 using namespace knowrob::testing;
311 
312 TEST_F(MongologTests, arithmetic) { runTests(getPath("iso/arithmetic.pl")); }
313 
314 TEST_F(MongologTests, atoms) { runTests(getPath("iso/atoms.pl")); }
315 
316 TEST_F(MongologTests, comparison) { runTests(getPath("iso/comparison.pl")); }
317 
318 TEST_F(MongologTests, control) { runTests(getPath("iso/control.pl")); }
319 
320 TEST_F(MongologTests, findall) { runTests(getPath("iso/findall.pl")); }
321 
322 TEST_F(MongologTests, lists) { runTests(getPath("iso/lists.pl")); }
323 
324 TEST_F(MongologTests, meta) { runTests(getPath("iso/meta.pl")); }
325 
326 TEST_F(MongologTests, terms) { runTests(getPath("iso/terms.pl")); }
327 
328 TEST_F(MongologTests, typecheck) { runTests(getPath("iso/typecheck.pl")); }
329 
330 TEST_F(MongologTests, unification) { runTests(getPath("iso/unification.pl")); }
331 
332 TEST_F(MongologTests, database) { runTests(getPath("database.pl")); }
333 
334 TEST_F(MongologTests, fluents) { runTests(getPath("fluents.pl")); }
335 
336 TEST_F(MongologTests, sgml) { runTests(getPath("sgml.pl")); }
337 
338 TEST_F(MongologTests, annotation) { runTests(getPath("annotation.pl")); }
339 
340 TEST_F(MongologTests, triple) { runTests(getPath("triple.plt")); }
TEST_F(MongologTests, arithmetic)
foreign_t pl_is_readonly2(term_t, term_t)
foreign_t pl_assert_triple_cpp9(term_t, term_t, term_t, term_t, term_t, term_t, term_t, term_t, term_t)
foreign_t pl_uri3(term_t, term_t, term_t)
foreign_t pl_db_name3(term_t, term_t, term_t)
#define KB_ERROR
Definition: Logger.h:28
#define KB_WARN
Definition: Logger.h:27
#define PROLOG_ENGINE_EVAL(term)
Definition: PrologEngine.h:128
#define KNOWROB_BUILTIN_REASONER(Name, Type)
static std::shared_ptr< KnowledgeBase > create()
static const std::string COLL_NAME_TRIPLES
static const std::string DB_NAME_KNOWROB
static const std::string DB_NAME_TESTS
static const std::string DB_URI_DEFAULT
bool initializeReasoner(const PropertyTree &cfg) override
bool initializeDefaultPackages() override
std::shared_ptr< MongoKnowledgeGraph > knowledgeGraph_
std::string_view callFunctor() override
bool consult(const std::filesystem::path &uri, const char *module={}, bool doTransformQuery=true)
PrologTerm getReasonerQuery(const PrologTerm &goal)
static std::shared_ptr< NamedReasoner > getDefinedReasoner(const term_t &t_reasonerManager, const term_t &t_reasonerModule)
bool initializeReasoner(const PropertyTree &cfg) override
TermPtr toKnowRobTerm() const
Definition: PrologTerm.cpp:691
static void runPrologTests(const std::shared_ptr< knowrob::PrologReasoner > &reasoner, const std::string &target)
Definition: PrologTests.cpp:23
ReasonerManager & reasonerManager() const
Definition: Reasoner.cpp:24
void setConfidence(double confidence)
Definition: Triple.h:307
void setBegin(double begin)
Definition: Triple.h:297
void setEnd(double end)
Definition: Triple.h:302
void setXSDValue(std::string_view v, XSDType type)
Definition: Triple.cpp:32
void setStringValue(std::string_view v) override
Definition: Triple.h:464
void setObjectIRI(std::string_view object) override
Definition: Triple.h:452
void setPredicate(std::string_view predicate) override
Definition: Triple.h:449
void setObjectBlank(std::string_view identifier) override
Definition: Triple.h:461
void setGraph(std::string_view graph) override
Definition: Triple.h:497
void setSubject(std::string_view subject) override
Definition: Triple.h:446
GraphTermRule & graphTerm()
Definition: graph.cpp:77
TermRule & string()
Definition: terms.cpp:63
TermRule & atomic()
Definition: terms.cpp:79
std::shared_ptr< Term > TermPtr
Definition: Term.h:117
void insertUnique(std::ostream &os)
Definition: knowrob.cpp:44