Threaded queries? Rulebase independence?

I’m interested in using SWI prolog as a knowledge base and reasoning system for an online medical webservice.

Suppose I’m interested in serving multiple queries in parallel:

  • can I use a single SWI prolog instance?
  • can the knowledge base be efficiently and independently forked – i.e. can I load a very initial large knowledge base, assert a few extra facts for query 1, assert facts for query 2, and have the knowledge bases for query 1 and query 2 be independent and also have the queries execute simultaneously?)

(am happy to get stuck into the C/C++ library)


  • Stuart
1 Like

Using a many worlds design pattern give you query independence by separating the facts for each query with the initial knowledge base being shared among all queries. I have a pattern example here. In this case, you have individual learning problems instead of queries with as many learning problems loaded simultaneously as needed (look into the SCRIPT.txt file for an example run). With the query facts separated, using SWI-Prolog support for multi-threading allows you to easily have concurrent queries. No need to resort to C/C++.

Roughly, you can separate knowledge by using different modules or use thread local predicates. A quick look suggests using modules is close to what Paulo suggests.

Next you can represent the combination of a large stable model and small variations using a shared stable KB and differential KBs with a some simple code that combines the two (e.g., something is true if it is in the shared or local KB and something is true if it is in the shared and its negation is not in the local KB.

Current work on tabling may come handy for certain reasoning tasks, providing better termination, less dependency on order for performance, well founded semantics for negation and incremental truth maintenance.

Perfect. Many thanks!

Inheritance naturally provides that functionality without requiring writing any additional code. The shared KB can provide default definitions for anything that may be overridden by query-specific facts (as described by the OP). A very simple example:

:- object(shared).

    :- public(a/1).

    :- public(b/1).

:- end

and then e.g.

:- object(query1, extends(shared)).


:- end_object.

or if a query needs to be created dynamically at runtime:

?- create_object(query2, [extends(shared)], [], [b(two)]).

we then get:

?- query1::(a(X), b(Y)).
X = 2, Y = one.

?- query2::(a(X), b(Y)).
X = 1, Y = two.

As Jan suggested, you can combine this sketched solution with tabling, threading, and other notable SWI-Prolog features.