8 #include "knowrob/integration/prolog/PrologTerm.h"
9 #include "knowrob/formulas/Predicate.h"
10 #include "knowrob/formulas/Negation.h"
11 #include "knowrob/formulas/Implication.h"
12 #include "knowrob/Logger.h"
13 #include "knowrob/terms/ListTerm.h"
14 #include "knowrob/formulas/Bottom.h"
15 #include "knowrob/formulas/Top.h"
16 #include "knowrob/formulas/Conjunction.h"
17 #include "knowrob/formulas/Disjunction.h"
18 #include "knowrob/queries/QueryError.h"
19 #include "knowrob/semweb/ImportHierarchy.h"
20 #include "knowrob/terms/Numeric.h"
21 #include "knowrob/terms/String.h"
22 #include "knowrob/terms/IRIAtom.h"
23 #include "knowrob/terms/Blank.h"
24 #include "knowrob/semweb/GraphQuery.h"
25 #include "knowrob/semweb/GraphSequence.h"
41 for (
auto &elem: elements) {
43 throw QueryError(
"Failed to put element into PrologList.");
50 : plTerm_(PL_new_term_ref()) {
56 : plTerm_(PL_new_term_ref()) {
61 : plTerm_(PL_new_term_ref()) {
66 : plTerm_(PL_new_term_ref()) {
71 : plTerm_(PL_new_term_ref()) {
76 : plTerm_(PL_new_term_ref()) {
81 : plTerm_(PL_new_term_ref()) {
86 : plTerm_(PL_new_term_ref()) {
92 PL_put_nil(empty_list());
97 static const auto comma_f =
",";
98 if (PL_term_type(
plTerm_) == PL_VARIABLE) {
100 }
else if (PL_term_type(other.
plTerm_) == PL_VARIABLE) {
108 static const auto semicolon_f =
";";
109 if (PL_term_type(
plTerm_) == PL_VARIABLE) {
111 }
else if (PL_term_type(other.
plTerm_) == PL_VARIABLE) {
119 static const auto semicolon_f =
"\\+";
124 for (
auto &pair : other.
vars_) {
126 vars_[pair.first] = pair.second;
128 if(!PL_unify(
vars_[pair.first], pair.second)) {
129 KB_WARN(
"failed to unify two variables.");
136 if (PL_term_type(
plTerm_) != PL_TERM && PL_term_type(
plTerm_) != PL_ATOM) {
137 throw QueryError(
"PrologTerm is not a compound nor atom (actual type: {}).", PL_term_type(
plTerm_));
140 module_t ctxModule =
module_.has_value() ?
141 PL_new_module(PL_new_atom(
module_.value().data())) :
nullptr;
145 if (!PL_get_name_arity(
plTerm_, &name_atom, &arity)) {
146 throw QueryError(
"Failed to get name and arity of Prolog term.");
149 term_t args = PL_new_term_refs(arity);
150 for (std::size_t i = 0; i < arity; i++) {
151 if (!PL_get_arg(i + 1,
plTerm_, args + i)) {
152 throw QueryError(
"Failed to get argument {} of Prolog term.", i);
156 predicate_t pred = PL_predicate(
157 PL_atom_nchars(name_atom,
nullptr),
158 static_cast<int>(arity),
160 return PL_open_query(ctxModule, flags, pred, args);
164 if (PL_next_solution(qid)) {
167 auto pl_exception = PL_exception(qid);
168 if (pl_exception != (term_t) 0) {
171 PL_clear_exception();
173 throw QueryError(
"Prolog error: {}.", *errorTerm);
180 #ifdef KNOWROB_USE_PROLOG_RDF11
181 static inline bool putTypedLiteral(term_t pl_arg,
const char *value,
const std::string &xsdType) {
183 static functor_t literalFunctor = PL_new_functor(PL_new_atom(
"^^"), 2);
184 term_t typedLiteral = PL_new_term_refs(2);
185 return PL_put_atom_chars(typedLiteral, value) &&
186 PL_put_atom_chars(typedLiteral + 1, xsdType.c_str()) &&
187 PL_cons_functor_v(pl_arg, literalFunctor, typedLiteral);
191 #ifdef KNOWROB_USE_PROLOG_RDF_DB
193 static inline bool putTypedLiteral(term_t pl_arg, std::string_view value, std::string_view xsdType) {
195 static functor_t literalFunctor = PL_new_functor(PL_new_atom(
"literal"), 1);
196 static functor_t literalTypeFunctor = PL_new_functor(PL_new_atom(
"type"), 2);
197 term_t typedLiteral = PL_new_term_refs(3);
198 return PL_put_atom_chars(typedLiteral, xsdType.data()) &&
199 PL_put_atom_chars(typedLiteral + 1, value.data()) &&
200 PL_cons_functor_v(typedLiteral + 2, literalTypeFunctor, typedLiteral) &&
201 PL_cons_functor_v(pl_arg, literalFunctor, typedLiteral + 2);
204 static inline bool putTyped(term_t pl_arg, std::string_view value, std::string_view xsdType) {
206 static functor_t literalTypeFunctor = PL_new_functor(PL_new_atom(
"type"), 2);
207 term_t typedLiteral = PL_new_term_refs(2);
208 return PL_put_atom_chars(typedLiteral, xsdType.data()) &&
209 PL_put_atom_chars(typedLiteral + 1, value.data()) &&
210 PL_cons_functor_v(pl_arg, literalTypeFunctor, typedLiteral);
216 term_t plArgs = PL_new_term_refs(args.size());
217 for (uint32_t i = 0; i < args.size(); i++) {
218 auto &arg_i = args[i];
219 if (!PL_put_term(plArgs + i, arg_i())) {
220 PL_reset_term_refs(plArgs);
221 KB_WARN(
"Failed to put argument {} into PrologTerm.", i);
227 if (!PL_cons_functor_v(plTerm,
228 PL_new_functor(PL_new_atom(functor.data()), args.size()),
230 PL_reset_term_refs(plArgs);
231 KB_WARN(
"Failed to put functor into PrologTerm.");
238 term_t pl_arg = PL_new_term_refs(4);
239 if (!PL_put_atom_chars(pl_arg, triple.
subject().data()) ||
240 !PL_put_atom_chars(pl_arg + 1, triple.
predicate().data())) {
241 PL_reset_term_refs(pl_arg);
246 o_put = PL_put_atom_chars(pl_arg + 2, triple.
valueAsString().data());
249 switch (triple.
xsdType().value()) {
251 o_put = putTypedLiteral(pl_arg + 2, triple.
valueAsString().data(), xsdType);
259 PL_reset_term_refs(pl_arg);
263 if (triple.
graph()) {
264 if (!PL_put_atom_chars(pl_arg + 3, (*triple.
graph()).data())) {
265 PL_reset_term_refs(pl_arg);
271 PL_reset_term_refs(pl_arg);
276 auto pl_functor = PL_new_functor(PL_new_atom(functor.data()), 4);
277 if (!PL_cons_functor_v(
plTerm_, pl_functor, pl_arg)) {
278 PL_reset_term_refs(pl_arg);
279 throw QueryError(
"Failed to put triple into PrologTerm.");
293 static auto negationFun = PL_new_functor(PL_new_atom(
"\\+"), 1);
294 static auto implicationFun = PL_new_functor(PL_new_atom(
":-"), 2);
296 switch (phi->type()) {
301 auto negated = std::static_pointer_cast<Negation>(phi)->negatedFormula();
302 auto negated_t = PL_new_term_ref();
304 PL_cons_functor_v(plTerm, negationFun, negated_t);
308 auto implication = std::static_pointer_cast<Implication>(phi);
309 auto args = PL_new_term_refs(2);
310 return putFormula(implication->consequent(), args) &&
311 putFormula(implication->antecedent(), args + 1) &&
312 PL_cons_functor_v(plTerm, implicationFun, args);
322 KB_WARN(
"Modal formula cannot be mapped to Prolog terms.");
341 if (fn->
arity() > 0) {
343 term_t pl_arg = PL_new_term_refs(fn->
arity());
344 term_t pl_arg0 = pl_arg;
346 for (
const auto &qa_arg: fn->
arguments()) {
347 if (!
putTerm(qa_arg, pl_arg)) {
353 return PL_cons_functor_v(pl_term,
355 PL_new_atom(fn->
functor()->stringForm().data()),
360 return PL_put_atom_chars(pl_term,
361 fn->
functor()->stringForm().data());
366 if (!PL_put_nil(pl_term))
return false;
367 term_t pl_elem = PL_new_term_ref();
368 for (
auto &elem: list->
elements()) {
370 !PL_cons_list(pl_term, pl_elem, pl_term)) {
379 static const auto rdf_has_f =
"rdf_has";
381 switch (kb_term->termType()) {
383 return putTriplePattern(*std::static_pointer_cast<GraphPattern>(kb_term)->value(), rdf_has_f, pl_term);
386 return putBuiltin(std::static_pointer_cast<GraphBuiltin>(kb_term), pl_term);
390 for (
const auto &subTerm: std::static_pointer_cast<GraphConnective>(kb_term)->terms()) {
394 return PL_put_term(pl_term, goal());
398 for (
const auto &subTerm: std::static_pointer_cast<GraphConnective>(kb_term)->terms()) {
402 return PL_put_term(pl_term, goal());
409 static const auto less_f =
"lt";
410 static const auto less_or_equal_f =
"le";
411 static const auto greater_f =
"gt";
412 static const auto greater_or_equal_f =
"ge";
413 static const auto equal_f =
"eq";
422 patternTerm = ~patternTerm;
425 patternTerm =
PrologTerm(
"ignore", patternTerm);
445 filter =
PrologTerm(less_or_equal_f, objectTerm);
451 filter =
PrologTerm(greater_or_equal_f, objectTerm);
464 patternTerm = ~patternTerm;
468 patternTerm =
PrologTerm(
"\\+", negatedTerm) | patternTerm;
473 return PL_put_term(plTerm, patternTerm());
480 static const auto greater_or_equal_a =
Atom::Tabled(
">=");
483 static const auto bind_f =
"=";
484 static const auto min_f =
"sw_literal_min";
485 static const auto max_f =
"sw_literal_max";
486 static const auto compare_f =
"sw_literal_compare";
488 switch (builtin->builtinType()) {
490 if (builtin->arguments().size() == 2) {
493 return PL_put_term(plTerm, t());
497 if (builtin->arguments().size() == 2) {
498 PrologTerm t =
PrologTerm(compare_f, less_or_equal_a, builtin->arguments()[0], builtin->arguments()[1]);
500 return PL_put_term(plTerm, t());
504 if (builtin->arguments().size() == 2) {
505 PrologTerm t =
PrologTerm(compare_f, greater_a, builtin->arguments()[0], builtin->arguments()[1]);
507 return PL_put_term(plTerm, t());
511 if (builtin->arguments().size() == 2) {
512 PrologTerm t =
PrologTerm(compare_f, greater_or_equal_a, builtin->arguments()[0], builtin->arguments()[1]);
514 return PL_put_term(plTerm, t());
518 if (builtin->arguments().size() == 2) {
519 PrologTerm t =
PrologTerm(compare_f, equal_a, builtin->arguments()[0], builtin->arguments()[1]);
521 return PL_put_term(plTerm, t());
525 if (builtin->arguments().size() == 1 && builtin->bindVar() !=
nullptr) {
526 PrologTerm t(bind_f, builtin->bindVar(), builtin->arguments()[0]);
528 return PL_put_term(plTerm, t());
532 if (builtin->arguments().size() == 2 && builtin->bindVar() !=
nullptr) {
533 PrologTerm t(min_f, builtin->arguments()[0], builtin->arguments()[1], builtin->bindVar());
535 return PL_put_term(plTerm, t());
539 if (builtin->arguments().size() == 2 && builtin->bindVar() !=
nullptr) {
540 PrologTerm t(max_f, builtin->arguments()[0], builtin->arguments()[1], builtin->bindVar());
542 return PL_put_term(plTerm, t());
546 if (builtin->arguments().size() == 2) {
547 PrologTerm t =
PrologTerm(compare_f, not_equal_a, builtin->arguments()[0], builtin->arguments()[1]);
549 return PL_put_term(plTerm, t());
557 switch (kbTerm->termType()) {
559 auto *fn = (
Function *) kbTerm.get();
567 auto *qa_var = (
Variable *) kbTerm.get();
568 auto it =
vars_.find(*qa_var);
569 if (it !=
vars_.end()) {
571 return PL_put_term(pl_term, it->second);
572 }
else if (PL_put_variable(pl_term)) {
579 vars_[*qa_var] = pl_term;
587 return putRDFAtomic(std::static_pointer_cast<Atomic>(kbTerm), pl_term);
589 return putNativeAtomic(std::static_pointer_cast<Atomic>(kbTerm), pl_term);
598 return PL_put_atom_chars(pl_term,
atomic->stringForm().data());
600 auto xsdAtomic = std::static_pointer_cast<XSDAtomic>(
atomic);
603 return putTyped(pl_term,
atomic->stringForm(), xsdType);
605 return putTypedLiteral(pl_term,
atomic->stringForm(), xsdType);
612 switch (
atomic->atomicType()) {
614 return PL_put_atom_chars(pl_term,
atomic->stringForm().data());
617 return PL_put_string_chars(pl_term,
atomic->stringForm().data());
621 switch (numeric->xsdType()) {
623 return PL_put_float(pl_term, numeric->asDouble());
625 return PL_put_float(pl_term, numeric->asFloat());
628 return PL_put_integer(pl_term, numeric->asInteger());
630 return PL_put_int64(pl_term, numeric->asLong());
632 return PL_put_integer(pl_term, numeric->asShort());
634 return PL_put_uint64(pl_term, numeric->asUnsignedLong());
636 return PL_put_integer(pl_term, numeric->asUnsignedInteger());
638 return PL_put_integer(pl_term, numeric->asUnsignedShort());
640 return PL_put_bool(pl_term, numeric->asBoolean());
656 term_t last_head = PL_new_term_ref();
658 for (
auto i = phi->
formulae().size(); i > 0; --i) {
665 term_t pl_arg = PL_new_term_refs(2);
667 !PL_put_term(pl_arg + 1, last_head) ||
668 !PL_cons_functor_v((j == 0 ? pl_term : last_head), pl_functor, pl_arg)) {
682 if (PL_get_chars(plTerm, &s, CVT_VARIABLE|BUF_MALLOC)) {
687 throw QueryError(
"Failed to get variable name.");
695 static TermPtr toKnowRobLiteral1(
const term_t &type_term) {
696 term_t xsd_type = PL_new_term_ref();
698 if (!PL_get_arg(1, type_term, xsd_type) || !PL_get_arg(2, type_term,
xsd_value)) {
699 KB_WARN(
"failed to get argument of type term.");
703 atom_t xsd_type_atom;
704 if (!PL_get_atom(xsd_type, &xsd_type_atom)) {
705 KB_WARN(
"Failed to get XSD type atom.");
709 atom_t xsd_value_atom;
710 if (!PL_get_atom(
xsd_value, &xsd_value_atom)) {
711 KB_WARN(
"Failed to get XSD value atom.");
715 return XSDAtomic::create(PL_atom_chars(xsd_value_atom), PL_atom_chars(xsd_type_atom));
718 static TermPtr toKnowRobLiteral(
const term_t &literal_term) {
719 term_t type_term = PL_new_term_ref();
720 if (!PL_get_arg(1, literal_term, type_term)) {
721 KB_WARN(
"failed to get argument of literal term.");
724 if (PL_term_type(type_term) != PL_TERM) {
725 KB_WARN(
"argument of literal term must be a term.");
729 size_t literal_arity;
731 if (!PL_get_name_arity(type_term, &literal_name, &literal_arity) ||
732 literal_arity != 2 || std::string_view(PL_atom_chars(literal_name)) !=
"type") {
733 KB_WARN(
"argument of literal term must be a 2-ary type term.");
737 return toKnowRobLiteral1(type_term);
741 switch (PL_term_type(t)) {
745 if (!PL_get_name_arity(t, &name, &arity))
break;
750 if (functorName ==
"literal" && arity == 1) {
751 auto xsdLiteral = toKnowRobLiteral(t);
752 if (xsdLiteral)
return xsdLiteral;
754 if (functorName ==
"type" && arity == 2) {
755 auto xsdLiteral = toKnowRobLiteral1(t);
756 if (xsdLiteral)
return xsdLiteral;
760 std::vector<TermPtr> arguments(arity);
761 term_t arg = PL_new_term_ref();
762 for (std::size_t n = 1; n <= arity; n++) {
763 if (PL_get_arg(n, t, arg)) {
766 KB_WARN(
"Failed to construct argument {} of predicate {}.", n, functorName);
770 return std::make_shared<Function>(functorName, arguments);
774 return std::make_shared<Variable>(
getVarName(t));
778 if (!PL_get_atom(t, &
atom))
break;
787 std::string_view charForm = PL_atom_chars(
atom);
801 if (!PL_get_long(t, &val))
break;
802 return std::make_shared<Long>(val);
806 if (!PL_get_float(t, &val))
break;
807 return std::make_shared<Double>(val);
811 if (!PL_get_chars(t, &s, CVT_ALL|BUF_MALLOC))
break;
812 auto str = std::make_shared<String>(s);
819 term_t head = PL_new_term_ref();
820 std::list<TermPtr> elements;
821 while (PL_get_list(t, head, t)) {
824 return std::make_shared<ListTerm>(
825 std::vector<TermPtr>(elements.begin(), elements.end()));
828 KB_WARN(
"Unknown Prolog term type {}.", PL_term_type(t));
832 KB_WARN(
"Failed to read Prolog term of type {}.", PL_term_type(t));
845 std::shared_ptr<Predicate> p = (
850 if (p->functor()->stringForm() == comma_functor) {
851 std::vector<FormulaPtr> formulas(p->arity());
852 for (std::size_t i = 0; i < formulas.size(); i++) {
855 return std::make_shared<Conjunction>(formulas);
856 }
else if (p->functor()->stringForm() == semicolon_functor) {
857 std::vector<FormulaPtr> formulas(p->arity());
858 for (std::size_t i = 0; i < formulas.size(); i++) {
861 return std::make_shared<Disjunction>(formulas);
872 static atom_t a = PL_new_atom(
"fail");
877 static atom_t a = PL_new_atom(
"false");
882 static atom_t a = PL_new_atom(
"true");
887 static atom_t a = PL_new_atom(
",");
892 static atom_t a = PL_new_atom(
";");
921 switch (PL_term_type(t)) {
925 if (PL_get_chars(t, &s, CVT_ALL|BUF_MALLOC)) {
932 if (PL_get_chars(t, &s, CVT_VARIABLE|BUF_MALLOC)) {
939 if (PL_get_string_chars(t, &s, &len)) {
945 term_t a = PL_new_term_ref();
948 if (!PL_get_name_arity(t, &name, &arity))
break;
949 std::string_view functor(PL_atom_chars(name));
951 if (functor ==
"," || functor ==
";") {
953 for (n = 1; n <= arity; n++) {
954 if (!PL_get_arg(n, t, a))
break;
956 os <<
'\n' << indent << functor <<
' ';
958 if (!
display(os, a, indent+
'\t')) os <<
"_";
962 os << functor <<
'(';
963 for (n = 1; n <= arity; n++) {
964 if (!PL_get_arg(n, t, a))
break;
965 if (n > 1) os <<
", ";
966 if (!
display(os, a)) os <<
"_";
static std::shared_ptr< knowrob::Atom > Tabled(std::string_view stringForm)
static std::shared_ptr< Blank > Tabled(std::string_view stringForm)
static const std::shared_ptr< Bottom > & get()
static std::shared_ptr< IRIAtom > Tabled(std::string_view stringForm)
static constexpr std::string_view ORIGIN_USER
static std::shared_ptr< ListTerm > nil()
static const AtomPtr & listFunctor()
static FunctionPtr toFunction(const std::shared_ptr< Predicate > &predicate)
static std::shared_ptr< Predicate > fromFunction(const FunctionPtr &fn)
static const atom_t & ATOM_false()
bool putFunction(Function *fn, term_t pl_term)
void unifyVars(const PrologTerm &other)
bool putTriple(std::string_view functor, const Triple &triple)
FormulaPtr toKnowRobFormula() const
qid_t openQuery(int flags) const
static bool nextSolution(qid_t qid)
bool putRDFAtomic(const std::shared_ptr< Atomic > &atomic, term_t pl_term) const
static const atom_t & ATOM_true()
static const predicate_t & PREDICATE_semicolon()
static bool putNativeAtomic(const std::shared_ptr< Atomic > &atomic, term_t pl_term)
static const functor_t & FUNCTOR_comma()
void write(std::ostream &os) const override
TermPtr toKnowRobTerm() const
bool putFormula(const FormulaPtr &phi)
std::map< Variable, term_t, std::less<> > vars_
static const atom_t & ATOM_fail()
PrologTerm operator~() const
static const atom_t & ATOM_semicolon()
bool putCompound(CompoundFormula *phi, term_t pl_term, const functor_t &pl_functor)
PrologTerm operator&(const PrologTerm &other) const
static std::string getVarName(term_t plTerm)
bool putCompoundTerm(term_t plTerm, std::string_view functor, const std::vector< PrologTerm > &args)
static bool display(std::ostream &os, term_t t, const std::string &indent="")
std::optional< std::string_view > module_
bool putBuiltin(const std::shared_ptr< GraphBuiltin > &builtin, term_t plTerm)
static const atom_t & ATOM_comma()
bool putTerm(const TermPtr &kbTerm)
bool putTriplePattern(const TriplePattern &pattern, const char *functor, term_t plTerm)
PrologTerm operator|(const PrologTerm &other) const
static const predicate_t & PREDICATE_comma()
static const functor_t & FUNCTOR_semicolon()
bool putList(ListTerm *list, term_t pl_term)
static const std::shared_ptr< Top > & get()
virtual std::string_view valueAsString() const =0
virtual std::optional< std::string_view > graph() const =0
virtual std::string_view subject() const =0
virtual std::string_view predicate() const =0
std::string createStringValue() const
bool isObjectBlank() const
auto objectOperator() const
auto & propertyTerm() const
auto & subjectTerm() const
auto & objectVariable() const
auto & objectTerm() const
static std::shared_ptr< XSDAtomic > create(std::string_view lexicalForm, std::string_view xsdTypeIRI)
GraphTermRule & graphTerm()
GraphTermRule & pattern()
std::string_view xsdTypeToIRI(XSDType type)
RDFNodeType rdfNodeTypeGuess(std::string_view str)
std::shared_ptr< Term > TermPtr
std::shared_ptr< Formula > FormulaPtr
std::shared_ptr< GraphQuery > GraphQueryPtr