knowrob  2.1.0
A Knowledge Base System for Cognition-enabled Robots
knowrob::PrologEngine Class Reference

#include <PrologEngine.h>

Inheritance diagram for knowrob::PrologEngine:
Collaboration diagram for knowrob::PrologEngine:

Public Types

using ErrorHandler = ThreadPool::ExceptionHandler
 
using GoalFactory = std::function< PrologTerm()>
 
using Solution = std::map< Variable, TermPtr, std::less<> >
 
using ErrorHandler = ThreadPool::ExceptionHandler
 
using GoalFactory = std::function< PrologTerm()>
 
using Solution = std::map< Variable, TermPtr, std::less<> >
 
- Public Types inherited from knowrob::ThreadPool
using ExceptionHandler = std::function< void(const std::exception &)>
 
using ExceptionHandler = std::function< void(const std::exception &)>
 

Public Member Functions

 PrologEngine (uint32_t maxNumThreads=0)
 
 PrologEngine (uint32_t maxNumThreads=0)
 
- Public Member Functions inherited from knowrob::ThreadPool
 ThreadPool (uint32_t maxNumThreads)
 
virtual ~ThreadPool ()
 
 ThreadPool (const ThreadPool &)=delete
 
void shutdown ()
 
void pushWork (const std::shared_ptr< ThreadPool::Runner > &goal, ThreadPool::ExceptionHandler exceptionHandler)
 
 ThreadPool (uint32_t maxNumThreads)
 
virtual ~ThreadPool ()
 
 ThreadPool (const ThreadPool &)=delete
 
void shutdown ()
 
void pushWork (const std::shared_ptr< ThreadPool::Runner > &goal, ThreadPool::ExceptionHandler exceptionHandler)
 

Static Public Member Functions

static void initializeProlog ()
 
static void finalizeProlog ()
 
static bool isPrologInitialized ()
 
static bool eval (const GoalFactory &goalFactory)
 
static std::optional< SolutiononeSolution (const GoalFactory &goalFactory)
 
static std::vector< SolutionallSolutions (const GoalFactory &goalFactory)
 
static void query (const GoalFactory &goalFactory, const BindingsHandler &callback)
 
static bool consult (const std::filesystem::path &uri, const char *module={})
 
static void pushGoal (const std::shared_ptr< ThreadPool::Runner > &goal, const ErrorHandler &errHandler)
 
static void pushGoalAndJoin (const std::shared_ptr< ThreadPool::Runner > &goal)
 
static std::filesystem::path getPrologPath (const std::filesystem::path &filename)
 
static std::filesystem::path getResourcePath (const std::filesystem::path &filename)
 
static void initializeProlog ()
 
static void finalizeProlog ()
 
static bool isPrologInitialized ()
 
static bool eval (const GoalFactory &goalFactory)
 
static std::optional< SolutiononeSolution (const GoalFactory &goalFactory)
 
static std::vector< SolutionallSolutions (const GoalFactory &goalFactory)
 
static void query (const GoalFactory &goalFactory, const BindingsHandler &callback)
 
static bool consult (const std::filesystem::path &uri, const char *module={})
 
static void pushGoal (const std::shared_ptr< ThreadPool::Runner > &goal, const ErrorHandler &errHandler)
 
static void pushGoalAndJoin (const std::shared_ptr< ThreadPool::Runner > &goal)
 
static std::filesystem::path getPrologPath (const std::filesystem::path &filename)
 
static std::filesystem::path getResourcePath (const std::filesystem::path &filename)
 

Protected Member Functions

bool initializeWorker () override
 
bool initializeWorker () override
 

Static Protected Member Functions

static void expandSearchPaths ()
 
static void expandSearchPaths ()
 

Static Protected Attributes

static bool isPrologInitialized_ = false
 
static std::vector< std::string > arguments_ = std::vector<std::string>()
 
static std::optional< PrologEngineself_ = std::nullopt
 

Additional Inherited Members

- Protected Attributes inherited from knowrob::ThreadPool
std::function< void()> finalizeWorker_
 

Detailed Description

A pool of threads with attached Prolog engines. Prolog threads have their own stacks and only share the Prolog heap: predicates, records, flags and other global non-backtrackable data. NOTE: term_t cannot be created in the main thread and used it in a worker thread! The term reference will be most likely a variable in the worker thread no matter what value it has in the main thread.

Definition at line 22 of file PrologEngine.h.

Member Typedef Documentation

◆ ErrorHandler [1/2]

◆ ErrorHandler [2/2]

◆ GoalFactory [1/2]

Definition at line 25 of file PrologEngine.h.

◆ GoalFactory [2/2]

Definition at line 25 of file PrologEngine.h.

◆ Solution [1/2]

using knowrob::PrologEngine::Solution = std::map<Variable, TermPtr, std::less<> >

Definition at line 26 of file PrologEngine.h.

◆ Solution [2/2]

using knowrob::PrologEngine::Solution = std::map<Variable, TermPtr, std::less<> >

Definition at line 26 of file PrologEngine.h.

Constructor & Destructor Documentation

◆ PrologEngine() [1/2]

PrologEngine::PrologEngine ( uint32_t  maxNumThreads = 0)
explicit
Parameters
maxNumThreadsmaximum number of worker threads.

Definition at line 32 of file PrologEngine.cpp.

33  : ThreadPool(maxNumThreads) {
34  finalizeWorker_ = [] {
35  // destroy the engine previously bound to this thread
36  PL_thread_destroy_engine();
37  KB_DEBUG("destroyed Prolog engine");
38  };
40 }
#define KB_DEBUG
Definition: Logger.h:25
static void initializeProlog()
ThreadPool(uint32_t maxNumThreads)
Definition: ThreadPool.cpp:26
std::function< void()> finalizeWorker_
Definition: ThreadPool.h:168

◆ PrologEngine() [2/2]

knowrob::PrologEngine::PrologEngine ( uint32_t  maxNumThreads = 0)
explicit
Parameters
maxNumThreadsmaximum number of worker threads.

Member Function Documentation

◆ allSolutions() [1/2]

std::vector< PrologEngine::Solution > PrologEngine::allSolutions ( const GoalFactory goalFactory)
static

Evaluate a goal in a thread with a Prolog engine.

Parameters
goalFactorya goal factory
Returns
all solutions found

Definition at line 224 of file PrologEngine.cpp.

224  {
225  std::vector<Solution> solutions;
226 
227  pushGoalAndJoin(std::make_shared<LambdaRunner>(
228  [&goalFactory, &solutions](const LambdaRunner::StopChecker &hasStopRequest) {
229  auto goal = goalFactory();
230  auto qid = goal.openQuery(prologQueryFlags);
231  while (!hasStopRequest() && goal.nextSolution(qid)) {
232  Solution solution;
233  for (auto &var: goal.vars()) {
234  solution[var.first] = PrologTerm::toKnowRobTerm(var.second);
235  }
236  solutions.push_back(solution);
237  }
238  PL_close_query(qid);
239  }));
240 
241  return solutions;
242 }
std::map< Variable, TermPtr, std::less<> > Solution
Definition: PrologEngine.h:26
static void pushGoalAndJoin(const std::shared_ptr< ThreadPool::Runner > &goal)
TermPtr toKnowRobTerm() const
Definition: PrologTerm.cpp:691
std::function< bool()> StopChecker
Definition: ThreadPool.h:152
VariableRule & var()
Definition: terms.cpp:91

◆ allSolutions() [2/2]

static std::vector<Solution> knowrob::PrologEngine::allSolutions ( const GoalFactory goalFactory)
static

Evaluate a goal in a thread with a Prolog engine.

Parameters
goalFactorya goal factory
Returns
all solutions found

◆ consult() [1/2]

bool PrologEngine::consult ( const std::filesystem::path &  uri,
const char *  module = {} 
)
static

Consults a Prolog file, i.e. loads facts and rules and executed directives in the file. May throw an exception if there is no valid Prolog file at the given path.

Parameters
urithe local path to the file.
modulethe module to consult the file into
Returns
true on success

Definition at line 264 of file PrologEngine.cpp.

264  {
265  static auto consult_f = "consult";
266  auto path = PrologEngine::getPrologPath(uri);
267 
268  return PrologEngine::eval([&]() {
269  PrologTerm plTerm(consult_f, path.native());
270  if (module) plTerm.setModule(module);
271  return plTerm;
272  });
273 }
static std::filesystem::path getPrologPath(const std::filesystem::path &filename)
static bool eval(const GoalFactory &goalFactory)

◆ consult() [2/2]

static bool knowrob::PrologEngine::consult ( const std::filesystem::path &  uri,
const char *  module = {} 
)
static

Consults a Prolog file, i.e. loads facts and rules and executed directives in the file. May throw an exception if there is no valid Prolog file at the given path.

Parameters
urithe local path to the file.
modulethe module to consult the file into
Returns
true on success

◆ eval() [1/2]

bool PrologEngine::eval ( const GoalFactory goalFactory)
static

Evaluate a goal in a thread with a Prolog engine.

Parameters
goalFactorya goal factory
Returns
true if the goal succeeded

Definition at line 191 of file PrologEngine.cpp.

191  {
192  bool hasSolution = false;
193 
194  pushGoalAndJoin(std::make_shared<LambdaRunner>(
195  [&goalFactory, &hasSolution](const LambdaRunner::StopChecker &) {
196  auto goal = goalFactory();
197  auto qid = goal.openQuery(prologQueryFlags);
198  hasSolution = goal.nextSolution(qid);
199  PL_close_query(qid);
200  }));
201 
202  return hasSolution;
203 }

◆ eval() [2/2]

static bool knowrob::PrologEngine::eval ( const GoalFactory goalFactory)
static

Evaluate a goal in a thread with a Prolog engine.

Parameters
goalFactorya goal factory
Returns
true if the goal succeeded

◆ expandSearchPaths() [1/2]

void PrologEngine::expandSearchPaths ( )
staticprotected

Definition at line 130 of file PrologEngine.cpp.

130  {
131  static std::filesystem::path projectPath(KNOWROB_SOURCE_DIR);
132  static std::filesystem::path installPath(KNOWROB_INSTALL_PREFIX);
133 
134  // expand library search path, e.g. used by use_module/2 to locate Prolog source files.
135  // prefer files from projectPath
136  auto libPaths = {
137  installPath / "share" / "knowrob" / "integration" / "prolog",
138  installPath / "share" / "knowrob" / "reasoner" / "prolog",
139  installPath / "share" / "knowrob" / "reasoner",
140  installPath / "share" / "knowrob",
141  projectPath / "src" / "integration" / "prolog",
142  projectPath / "src" / "reasoner" / "prolog",
143  projectPath / "src" / "reasoner",
144  projectPath / "src"
145  };
146  for (const auto &p: libPaths) {
147  if (!exists(p)) continue;
148  eval([&p] {
149  return PrologTerm("asserta", PrologTerm(":", "user", PrologTerm("library_directory", p.string())));
150  });
151  }
152 
153  // expand file search path, e.g. used by absolute_file_name/3 predicate
154  // "knowrob" files:
155  auto filePaths_knowrob = {
156  projectPath,
157  installPath / "share" / "knowrob"
158  };
159  for (const auto &p: filePaths_knowrob) {
160  if (!exists(p)) continue;
161  eval([&p] {
162  return PrologTerm("assertz", PrologTerm("file_search_path", "knowrob", p.string()));
163  });
164  }
165 
166  // "test" files:
167  auto filePaths_tests = {
168  projectPath / "tests"
169  };
170  for (const auto &p: filePaths_tests) {
171  if (!exists(p)) continue;
172  eval([&p] {
173  return PrologTerm("assertz", PrologTerm("file_search_path", "test", p.string()));
174  });
175  }
176 }

◆ expandSearchPaths() [2/2]

static void knowrob::PrologEngine::expandSearchPaths ( )
staticprotected

◆ finalizeProlog() [1/2]

void PrologEngine::finalizeProlog ( )
static

Must be called after all Prolog library interactions.

Definition at line 118 of file PrologEngine.cpp.

118  {
119  if (!isPrologInitialized_) return;
120  // finalize the Prolog engine
121  self_->shutdown();
122  PL_cleanup(0);
123  arguments_.clear();
124  self_ = std::nullopt;
125  // toggle off flag
126  isPrologInitialized_ = false;
127  KB_DEBUG("Prolog has been finalized.");
128 }
static std::vector< std::string > arguments_
Definition: PrologEngine.h:118
static std::optional< PrologEngine > self_
Definition: PrologEngine.h:119
static bool isPrologInitialized_
Definition: PrologEngine.h:117

◆ finalizeProlog() [2/2]

static void knowrob::PrologEngine::finalizeProlog ( )
static

Must be called after all Prolog library interactions.

◆ getPrologPath() [1/2]

std::filesystem::path PrologEngine::getPrologPath ( const std::filesystem::path &  filename)
static

Resolve the path to a Prolog file. The function attempts to resolve project-relative paths.

Parameters
filenamea name or path.
Returns
a path where the file might be stored

Definition at line 275 of file PrologEngine.cpp.

275  {
276  static std::filesystem::path projectPath(KNOWROB_SOURCE_DIR);
277  static std::filesystem::path installPath(KNOWROB_INSTALL_PREFIX);
278 
279  if (!exists(filePath)) {
280  auto possiblePaths = {
281  projectPath / filePath,
282  projectPath / "src" / filePath,
283  projectPath / "src" / "reasoner" / "prolog" / filePath,
284  installPath / "share" / "knowrob" / filePath
285  };
286  for (const auto &p: possiblePaths) {
287  if (exists(p)) return p;
288  }
289  }
290  return filePath;
291 }

◆ getPrologPath() [2/2]

static std::filesystem::path knowrob::PrologEngine::getPrologPath ( const std::filesystem::path &  filename)
static

Resolve the path to a Prolog file. The function attempts to resolve project-relative paths.

Parameters
filenamea name or path.
Returns
a path where the file might be stored

◆ getResourcePath() [1/2]

std::filesystem::path PrologEngine::getResourcePath ( const std::filesystem::path &  filename)
static

Resolve the path to a resource file. The function attempts to resolve project-relative paths.

Parameters
filenamea name or path.
Returns
a path where the file might be stored

Definition at line 293 of file PrologEngine.cpp.

293  {
294  static std::filesystem::path projectPath(KNOWROB_SOURCE_DIR);
295  static std::filesystem::path installPath(KNOWROB_INSTALL_PREFIX);
296 
297  if (!exists(filePath)) {
298  auto possiblePaths = {
299  projectPath / filePath,
300  installPath / "share" / "knowrob" / filePath
301  };
302  for (const auto &p: possiblePaths) {
303  if (exists(p)) return p;
304  }
305  }
306  return filePath;
307 }

◆ getResourcePath() [2/2]

static std::filesystem::path knowrob::PrologEngine::getResourcePath ( const std::filesystem::path &  filename)
static

Resolve the path to a resource file. The function attempts to resolve project-relative paths.

Parameters
filenamea name or path.
Returns
a path where the file might be stored

◆ initializeProlog() [1/2]

void PrologEngine::initializeProlog ( )
static

Must be called before any Prolog library interactions.

Definition at line 72 of file PrologEngine.cpp.

72  {
73  if (isPrologInitialized_) return;
74  // toggle on flag
75  isPrologInitialized_ = true;
76 
77  // PL_initialise changes the locale. This can have bad consequences.
78  // I experienced unit tests for Redland failing because of this!
79  // Seems like it is related to parsing of numbers. Setting
80  // LC_NUMERIC to "C" before PL_initialise seems to fix the problem.
81  setenv("LC_NUMERIC", "C", 1);
82 
83  int pl_ac = 0;
84  char *pl_av[5];
85  arguments_.resize(4);
86  arguments_[pl_ac++] = getNameOfExecutable();
87  // '-g true' is used to suppress the welcome message
88  arguments_[pl_ac++] = "-g";
89  arguments_[pl_ac++] = "true";
90  // Inhibit any signal handling by Prolog
91  arguments_[pl_ac++] = "--signals=false";
92  for (int i = 0; i < pl_ac; i++) {
93  pl_av[i] = (char *) arguments_[i].c_str();
94  }
95  PL_initialise(pl_ac, pl_av);
96  KB_DEBUG("Prolog has been initialized.");
97  self_.emplace(std::thread::hardware_concurrency());
98 
99  // expand the Prolog library_directory path used to locate Prolog files
101 
102  // register some foreign predicates, i.e. cpp functions that are used to evaluate predicates.
103  // note: the predicates are loaded into module "user"
104  PL_register_foreign("knowrob_register_namespace",
105  2, (pl_function_t) pl_rdf_register_namespace2, 0);
106  PL_register_foreign("url_resolve",
107  2, (pl_function_t) url_resolve2, 0);
108  PL_register_foreign("log_message", 2, (pl_function_t) prolog::log_message2, 0);
109  PL_register_foreign("log_message", 4, (pl_function_t) prolog::log_message4, 0);
110  PL_register_extensions_in_module("algebra", prolog::PL_extension_algebra);
111  PL_register_extensions_in_module("semweb", prolog::PL_extension_semweb);
112  KB_DEBUG("common foreign Prolog modules have been registered.");
113 
114  consult(std::filesystem::path("integration") / "prolog" / "__init__.pl", "user");
115  KB_DEBUG("KnowRob __init__.pl has been consulted.");
116 }
foreign_t pl_rdf_register_namespace2(term_t prefix_term, term_t uri_term)
foreign_t url_resolve2(term_t t_url, term_t t_resolved)
static bool consult(const std::filesystem::path &uri, const char *module={})
static void expandSearchPaths()
foreign_t log_message4(term_t level_term, term_t msg_term, term_t file_term, term_t line_term)
Definition: logging.cpp:61
PL_extension PL_extension_algebra[]
Definition: algebra.h:12
PL_extension PL_extension_semweb[]
Definition: semweb.h:12
foreign_t log_message2(term_t level_term, term_t msg_term)
Definition: logging.cpp:57
char * getNameOfExecutable()
Definition: knowrob.cpp:30

◆ initializeProlog() [2/2]

static void knowrob::PrologEngine::initializeProlog ( )
static

Must be called before any Prolog library interactions.

◆ initializeWorker() [1/2]

bool PrologEngine::initializeWorker ( )
overrideprotectedvirtual

Reimplemented from knowrob::ThreadPool.

Definition at line 42 of file PrologEngine.cpp.

42  {
43  // call PL_thread_attach_engine once initially for each worker thread
44  if (PL_thread_attach_engine(nullptr) < 0) {
45  // `-1` indicates an error, and `-2` that Prolog is compiled without multithreading support
46  KB_ERROR("Failed to attach Prolog engine to current thread!");
47  return false;
48  } else {
49  // if PL_thread_attach_engine()>0, then the Prolog ID for the thread was returned
50  KB_DEBUG("Attached Prolog engine to current thread.");
51  return true;
52  }
53 }
#define KB_ERROR
Definition: Logger.h:28

◆ initializeWorker() [2/2]

bool knowrob::PrologEngine::initializeWorker ( )
overrideprotectedvirtual

Reimplemented from knowrob::ThreadPool.

◆ isPrologInitialized() [1/2]

static bool knowrob::PrologEngine::isPrologInitialized ( )
inlinestatic
Returns
true if the Prolog engine is initialized

Definition at line 46 of file PrologEngine.h.

46 { return isPrologInitialized_; }

◆ isPrologInitialized() [2/2]

static bool knowrob::PrologEngine::isPrologInitialized ( )
inlinestatic
Returns
true if the Prolog engine is initialized

Definition at line 46 of file PrologEngine.h.

46 { return isPrologInitialized_; }

◆ oneSolution() [1/2]

std::optional< PrologEngine::Solution > PrologEngine::oneSolution ( const GoalFactory goalFactory)
static

Evaluate a goal in a thread with a Prolog engine.

Parameters
goalFactorya goal factory
Returns
the first solution found or an empty optional

Definition at line 205 of file PrologEngine.cpp.

205  {
206  std::optional<Solution> solution;
207 
208  pushGoalAndJoin(std::make_shared<LambdaRunner>(
209  [&goalFactory, &solution](const LambdaRunner::StopChecker &) {
210  auto goal = goalFactory();
211  auto qid = goal.openQuery(prologQueryFlags);
212  if (goal.nextSolution(qid)) {
213  solution = Solution();
214  for (auto &var: goal.vars()) {
215  solution.value()[var.first] = PrologTerm::toKnowRobTerm(var.second);
216  }
217  }
218  PL_close_query(qid);
219  }));
220 
221  return solution;
222 }

◆ oneSolution() [2/2]

static std::optional<Solution> knowrob::PrologEngine::oneSolution ( const GoalFactory goalFactory)
static

Evaluate a goal in a thread with a Prolog engine.

Parameters
goalFactorya goal factory
Returns
the first solution found or an empty optional

◆ pushGoal() [1/2]

void PrologEngine::pushGoal ( const std::shared_ptr< ThreadPool::Runner > &  goal,
const ErrorHandler errHandler 
)
static

Run a goal in a worker thread with a Prolog engine.

Parameters
goalthe work goal
errHandlera function that handles exceptions thrown by the goal

Definition at line 178 of file PrologEngine.cpp.

178  {
179  self_->pushWork(goal, errHandler);
180 }

◆ pushGoal() [2/2]

static void knowrob::PrologEngine::pushGoal ( const std::shared_ptr< ThreadPool::Runner > &  goal,
const ErrorHandler errHandler 
)
static

Run a goal in a worker thread with a Prolog engine.

Parameters
goalthe work goal
errHandlera function that handles exceptions thrown by the goal

◆ pushGoalAndJoin() [1/2]

void PrologEngine::pushGoalAndJoin ( const std::shared_ptr< ThreadPool::Runner > &  goal)
static

Run a goal in a worker thread with a Prolog engine and wait for termination. Also rethrow any exceptions in the thread of the caller.

Parameters
goalthe work goal

Definition at line 182 of file PrologEngine.cpp.

182  {
183  // push goal and wait for termination
184  std::exception_ptr excPtr = nullptr;
185  pushGoal(goal, [&excPtr](...) { excPtr = std::current_exception(); });
186  goal->join();
187  // rethrow any exceptions in this thread
188  if (excPtr) std::rethrow_exception(excPtr);
189 }
static void pushGoal(const std::shared_ptr< ThreadPool::Runner > &goal, const ErrorHandler &errHandler)

◆ pushGoalAndJoin() [2/2]

static void knowrob::PrologEngine::pushGoalAndJoin ( const std::shared_ptr< ThreadPool::Runner > &  goal)
static

Run a goal in a worker thread with a Prolog engine and wait for termination. Also rethrow any exceptions in the thread of the caller.

Parameters
goalthe work goal

◆ query() [1/2]

void PrologEngine::query ( const GoalFactory goalFactory,
const BindingsHandler callback 
)
static

Evaluate a goal in a thread with a Prolog engine.

Parameters
goalFactorya goal factory
callbacka function that handles the solutions

Definition at line 244 of file PrologEngine.cpp.

244  {
245  pushGoalAndJoin(std::make_shared<LambdaRunner>(
246  [&goalFactory, &callback](const LambdaRunner::StopChecker &hasStopRequest) {
247  auto goal = goalFactory();
248  auto qid = goal.openQuery(prologQueryFlags);
249  while (!hasStopRequest() && goal.nextSolution(qid)) {
250  auto bindings = std::make_shared<Bindings>();
251  for (auto &var: goal.vars()) {
252  if (PL_term_type(var.second) == PL_VARIABLE) {
253  continue;
254  }
255  bindings->set(std::make_shared<Variable>(var.first),
257  }
258  callback(bindings);
259  }
260  PL_close_query(qid);
261  }));
262 }

◆ query() [2/2]

static void knowrob::PrologEngine::query ( const GoalFactory goalFactory,
const BindingsHandler callback 
)
static

Evaluate a goal in a thread with a Prolog engine.

Parameters
goalFactorya goal factory
callbacka function that handles the solutions

Member Data Documentation

◆ arguments_

std::vector< std::string > PrologEngine::arguments_ = std::vector<std::string>()
staticprotected

Definition at line 118 of file PrologEngine.h.

◆ isPrologInitialized_

bool PrologEngine::isPrologInitialized_ = false
staticprotected

Definition at line 117 of file PrologEngine.h.

◆ self_

std::optional< PrologEngine > PrologEngine::self_ = std::nullopt
staticprotected

Definition at line 119 of file PrologEngine.h.


The documentation for this class was generated from the following files: