9 #include "knowrob/Logger.h"
10 #include "knowrob/reasoner/ReasonerManager.h"
11 #include "knowrob/reasoner/prolog/PrologReasoner.h"
12 #include "knowrob/reasoner/prolog/semweb.h"
13 #include "knowrob/terms/ListTerm.h"
14 #include "knowrob/formulas/Bottom.h"
15 #include "knowrob/queries/TokenQueue.h"
16 #include "knowrob/semweb/PrefixRegistry.h"
17 #include "knowrob/semweb/ImportHierarchy.h"
18 #include "knowrob/KnowledgeBase.h"
19 #include "knowrob/integration/prolog/PrologBackend.h"
20 #include "knowrob/reasoner/ReasonerError.h"
21 #include "knowrob/reasoner/prolog/semweb.h"
22 #include "knowrob/queries/AnswerNo.h"
23 #include "knowrob/terms/Numeric.h"
24 #include "knowrob/TimePoint.h"
28 static const int prologQueryFlags = PL_Q_CATCH_EXCEPTION | PL_Q_NODEBUG;
30 #define PROLOG_REASONER_EVAL(goal) PROLOG_ENGINE_EVAL(getReasonerQuery(goal))
37 static inline std::shared_ptr<PrologReasoner> getPrologReasoner(term_t t_reasonerManager, term_t t_reasonerModule) {
39 if (!definedReasoner) {
40 KB_ERROR(
"unable to find reasoner with id '{}' (manager id: {}).",
45 auto reasoner = definedReasoner->value();
46 auto typedReasoner = std::dynamic_pointer_cast<PrologReasoner>(reasoner);
48 KB_ERROR(
"reasoner with id '{}' (manager id: {}) is not a mongolog reasoner.",
57 reasoner_define_relation4(term_t t_reasonerManager, term_t t_reasonerModule, term_t t_relation, term_t t_arity) {
58 auto reasoner = getPrologReasoner(t_reasonerManager, t_reasonerModule);
62 PL_get_atom_chars(t_relation, &relationName) &&
63 PL_get_int64(t_arity, &arity)) {
72 reasoner_define_class3(term_t t_reasonerManager, term_t t_reasonerModule, term_t t_class) {
73 auto reasoner = getPrologReasoner(t_reasonerManager, t_reasonerModule);
75 if (reasoner && PL_get_atom_chars(t_class, &className)) {
96 static auto unload_f =
"reasoner_unload";
101 static const auto reasoner_call_f =
"reasoner_call";
102 return reasoner_call_f;
117 PL_register_foreign(
"reasoner_define_relation_cpp", 4, (pl_function_t) prolog::reasoner_define_relation4, 0);
118 PL_register_foreign(
"reasoner_define_class_cpp", 3, (pl_function_t) prolog::reasoner_define_class3, 0);
124 consult(std::filesystem::path(
"reasoner") /
"prolog" /
"__init__.pl",
"user",
false);
128 static const auto register_prefix_i =
"rdf_register_prefix";
130 const auto &uri = pair.first;
131 const auto &alias = pair.second;
138 for (
auto &pair: cfg) {
146 static auto reasoner_rdf_init_f =
"reasoner_rdf_init";
153 static auto set_setting_f =
"reasoner_set_setting";
158 static const auto b_setval_f =
"b_setval";
159 static const auto reasoner_module_a =
"reasoner_module";
160 static const auto reasoner_manager_a =
"reasoner_manager";
161 auto managerID = std::make_shared<Integer>(
reasonerManager().managerID());
163 PrologTerm(b_setval_f, reasoner_manager_a, managerID) &
168 const term_t &t_reasonerManager,
const term_t &t_reasonerModule) {
169 int i_reasonerManager;
170 if (!PL_get_integer(t_reasonerManager, &i_reasonerManager))
return {};
174 char *reasonerModule;
175 if (PL_get_atom_chars(t_reasonerModule, &reasonerModule)) {
178 if (strncmp(reasonerModule,
"Reasoner_", 9) == 0) {
188 static auto consult_f =
"consult";
199 static auto load_rdf_xml_f =
"load_rdf_xml";
206 static const auto query_scope_f =
"query_scope";
207 static const auto solution_scope_f =
"solution_scope";
212 auto runner = std::make_shared<ThreadPool::LambdaRunner>(
229 auto qid = queryGoal.openQuery(prologQueryFlags);
230 bool hasSolution =
false;
232 query->push(
yes(query, goal, answerFrame));
237 if (!hasSolution) query->push(
no(query));
242 KB_WARN(
"an exception occurred for prolog query ({}): {}.", *query->formula(), e.what());
255 KB_DEBUG(
"Prolog has a next solution.");
258 auto bindings = std::make_shared<Bindings>();
259 for (
const auto &kv: rdfGoal.
vars()) {
267 auto yes = std::make_shared<AnswerYes>(bindings);
273 if (answerFrame_rw) {
274 yes->setFrame(answerFrame_rw);
275 answerFrame_ro = answerFrame_rw;
281 auto &phi = query->formula();
282 for (
auto &literal: phi->literals()) {
283 auto &p = literal->predicate();
285 yes->addGrounding(std::static_pointer_cast<Predicate>(p_instance), literal->isNegated(), answerFrame_ro);
292 KB_DEBUG(
"Prolog has no solution.");
294 auto negativeAnswer = std::make_shared<AnswerNo>();
298 negativeAnswer->setIsUncertain(
true, std::nullopt);
304 auto &literals = query->formula()->literals();
305 if (literals.size() == 1) {
306 auto &firstLiteral = *literals.begin();
307 negativeAnswer->addUngrounded(
308 std::static_pointer_cast<Predicate>(firstLiteral->predicate()),
309 firstLiteral->isNegated());
312 return negativeAnswer;
325 int numFrameKeys = 2;
327 if (frame.
begin.has_value()) numFrameKeys += 1;
328 if (frame.
end.has_value()) numFrameKeys += 1;
331 atom_t scopeKeys[numFrameKeys];
332 auto scopeValues = PL_new_term_refs(numFrameKeys);
335 static const auto epistemicMode_a = PL_new_atom(
"epistemicMode");
336 static const auto knowledge_a = PL_new_atom(
"knowledge");
337 static const auto belief_a = PL_new_atom(
"belief");
341 scopeKeys[keyIndex] = epistemicMode_a;
342 if (!PL_put_atom(scopeValues, isAboutBelief ? belief_a : knowledge_a))
return false;
345 static const auto temporalMode_a = PL_new_atom(
"temporalMode");
346 static const auto sometimes_a = PL_new_atom(
"sometimes");
347 static const auto always_a = PL_new_atom(
"always");
350 scopeKeys[++keyIndex] = temporalMode_a;
351 if (!PL_put_atom(scopeValues + keyIndex, isAboutSomePast ? sometimes_a : always_a))
return false;
355 static const auto agent_a = PL_new_atom(
"agent");
356 scopeKeys[++keyIndex] = agent_a;
358 if (!PL_put_atom_chars(scopeValues + keyIndex, agent_iri.data()))
return false;
362 if (frame.
begin.has_value()) {
363 static const auto since_a = PL_new_atom(
"since");
364 scopeKeys[++keyIndex] = since_a;
365 if (!PL_put_float(scopeValues + keyIndex, frame.
begin.value()))
return false;
368 if (frame.
end.has_value()) {
369 static const auto until_a = PL_new_atom(
"until");
370 scopeKeys[++keyIndex] = until_a;
371 if (!PL_put_float(scopeValues + keyIndex, frame.
end.value()))
return false;
374 return PL_put_dict(frameTerm(), 0, numFrameKeys, scopeKeys, scopeValues);
378 std::shared_ptr<GraphSelector> frame;
380 if (PL_is_variable(plTerm())) {
383 }
else if (PL_is_dict(plTerm())) {
385 auto scope_val = PL_new_term_ref();
387 frame = std::make_shared<GraphSelector>();
390 static const auto time_key = PL_new_atom(
"time");
391 if (PL_get_dict_key(time_key, plTerm(), scope_val)) {
392 term_t arg = PL_new_term_ref();
393 std::optional<TimePoint> v_since, v_until;
396 if (PL_get_arg(1, scope_val, arg) &&
397 PL_term_type(arg) == PL_FLOAT &&
398 PL_get_float(arg, &val) &&
399 val > 0.001) { frame->begin = val; }
401 if (PL_get_arg(2, scope_val, arg) &&
402 PL_term_type(arg) == PL_FLOAT &&
403 PL_get_float(arg, &val)) { frame->end = val; }
406 static const auto uncertain_key = PL_new_atom(
"uncertain");
407 if (PL_get_dict_key(uncertain_key, plTerm(), scope_val)) {
409 if (PL_term_type(scope_val) == PL_ATOM && PL_get_atom(scope_val, &flagAtom)) {
411 frame->uncertain =
true;
416 static const auto confidence_key = PL_new_atom(
"confidence");
417 if (PL_get_dict_key(confidence_key, plTerm(), scope_val)) {
418 double confidenceValue = 1.0;
419 if (PL_term_type(scope_val) == PL_FLOAT && PL_get_float(scope_val, &confidenceValue)) {
420 frame->confidence = confidenceValue;
421 if (confidenceValue > 0.999) {
422 frame->uncertain =
false;
424 frame->uncertain =
true;
429 static const auto occasional_key = PL_new_atom(
"occasional");
430 if (PL_get_dict_key(occasional_key, plTerm(), scope_val)) {
432 if (PL_term_type(scope_val) == PL_ATOM && PL_get_atom(scope_val, &flagAtom)) {
437 static const auto agent_key = PL_new_atom(
"agent");
438 if (PL_get_dict_key(agent_key, plTerm(), scope_val)) {
440 if (PL_term_type(scope_val) == PL_ATOM && PL_get_atom(scope_val, &agentAtom)) {
445 PL_reset_term_refs(scope_val);
447 KB_WARN(
"solution scope has an unexpected type (should be dict).");
458 static const auto xunit_var = std::make_shared<Variable>(
"Term");
460 static const auto xunit_opt = std::make_shared<Function>(
Function(
"xunit_term", {xunit_var}));
467 std::make_shared<ListTerm>(
ListTerm({xunit_opt, silent_flag}))
471 std::list<TermPtr> output;
472 for (
auto &solution: solutions) {
473 if (solution.count(*xunit_var) > 0) {
474 output.push_back(solution[*xunit_var]);
476 KB_WARN(
"Solution has no key '{}'.", xunit_var->name());
#define PROLOG_REASONER_EVAL(goal)
#define PROLOG_ENGINE_EVAL(term)
#define PROLOG_ENGINE_ALL_SOL(term)
#define KNOWROB_BUILTIN_REASONER(Name, Type)
static std::shared_ptr< knowrob::Atom > Tabled(std::string_view stringForm)
void addDataHandler(const std::string &format, const DataSourceLoader &fn)
void enableFeature(GoalDrivenReasonerFeature feature)
static std::shared_ptr< IRIAtom > Tabled(std::string_view stringForm)
static std::shared_ptr< Perspective > get(std::string_view iri)
static PluginManager< Reasoner > * getManager(uint32_t managerID)
std::shared_ptr< NamedPlugin< T > > getPluginWithID(std::string_view pluginID)
static PrefixRegistry & get()
static void initializeProlog()
static std::filesystem::path getPrologPath(const std::filesystem::path &filename)
static void pushGoal(const std::shared_ptr< ThreadPool::Runner > &goal, const ErrorHandler &errHandler)
static bool eval(const GoalFactory &goalFactory)
static std::filesystem::path getResourcePath(const std::filesystem::path &filename)
virtual void initializeReasonerStorage()
std::list< TermPtr > runTests(const std::string &target)
bool load_rdf_xml(const std::filesystem::path &rdfFile)
bool setReasonerSetting(const TermPtr &key, const TermPtr &valueString)
AnswerNoPtr no(const GoalPtr &query)
virtual std::string_view callFunctor()
virtual bool initializeGlobalPackages()
static bool isKnowRobInitialized_
PrologTerm transformGoal(const PrologTerm &goal)
bool consult(const std::filesystem::path &uri, const char *module={}, bool doTransformQuery=true)
~PrologReasoner() override
AnswerYesPtr yes(const GoalPtr &query, const PrologTerm &rdfGoal, const PrologTerm &frameTerm)
virtual bool initializeDefaultPackages()
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
static bool putQueryFrame(PrologTerm &frameTerm, const GraphSelector &frame)
static std::shared_ptr< GraphSelector > createAnswerFrame(const PrologTerm &plTerm)
bool evaluate(GoalPtr query) override
void setModule(std::string_view module)
static bool nextSolution(qid_t qid)
static const atom_t & ATOM_true()
TermPtr toKnowRobTerm() const
TermPtr createKeyTerm(std::string_view key) const
ReasonerManager & reasonerManager() const
auto & reasonerName() const
std::function< bool()> StopChecker
GraphSelectorPtr DefaultGraphSelector()
@ QUERY_FLAG_ONE_SOLUTION
std::shared_ptr< Term > TermPtr
std::shared_ptr< const GraphSelector > GraphSelectorPtr
@ SupportsSimpleConjunctions
@ SupportsExtensionalGrounding
FirstOrderLiteralPtr applyBindings(const FirstOrderLiteralPtr &lit, const Bindings &bindings)
std::shared_ptr< const AnswerYes > AnswerYesPtr
std::shared_ptr< DataSource > DataSourcePtr
std::shared_ptr< Goal > GoalPtr
std::shared_ptr< const AnswerNo > AnswerNoPtr
std::optional< double > end
PerspectivePtr perspective
std::optional< double > begin