This functionality has been significantly expanded in 0.12.0, and is now the recommended way to use pyDatalog. See the sample files.
An in-line datalog statement is a Python statement:
pyDatalog.create_atoms()
(thus not in a method or class), pyDatalog.Mixin
.Similarly, an in-line query is a Python statement that follows the syntax of a body (see grammar below). An in-line query returns a Query object that behaves like a Python list of list : each element of the list is itself a list containing one value for each variable in the query, in order of the appearance of the variables in the query. Additionally, the Query object has a >= X
operator which return the first value of variable X in the result of the query.
After an in-line query, each variable in the query contains the list of possible values. It should be noted that the result of the query is determined when it is first needed (and thus not in the statement that defines the query).
p(X)
print(X) # the p(X) query is resolved here !
The terminal symbols in this grammar are defined in BNF as follows :
_pyD_
are reserved for pyDatalogPlease note:
0-
instead.X==expr
must be bound by a previous literal (otherwise, no result is returned)p[X]< expr
must be bound (otherwise, no result is returned).X<expr
comparisons must be bound (otherwise, an error is raised)_
prefix (e.g. _sum
) to differentiate with the python aggregate function=
" defines a logic formula, while "==
" appears in a fact, clause or query and must always be surrounded by parenthesisAggregate functions:
(P[X]==_len(Y)) <= body
: P[X] is the count of values of Y (associated to X by the body of the clause)(P[X]==_sum(Y, for_each=Z)) <= body
: P[X] is the sum of Y for each Z. (Z is used to distinguish possibly identical Y values)(P[X]==_min(Y, order_by=Z)) <= body
: P[X] is the minimum (or maximum) of Y sorted by Z.(P[X]==concat(Y, order_by=Z, sep=',')) <= body
: same as 'sum' but for string. The strings are sorted by Z, and separated by ','.(P[X]==rank(for_each=Y, order_by=Z)) <= body
: P[X] is the sequence number of X in the list of Y values when the list is sorted by Z.(P[X]==running_sum(N, for_each=Y, order_by=Z)) <= body
: P[X] is the sum of the values of N, for each Y that are before or equal to X when Y's are sorted by Z.order_by
arguments can be preceded by '-' for descending sort order. If the aggregation function does not depend on a variable, use a constant (e.g. P[None] == len(Y)
).The pyDatalog module has the following methods :
create_atoms
must be called at module level (not in a function or class definition) It can have any number of arguments : each arg is a string containing the name of the logic atoms to be created, separated by commas. The created logic atoms are either pyDatalog.Variable
(if it starts with an upper case) or pyParser.Symbol
(otherwise). create_atoms also creates symbols for the aggregate functions.predicate_name(terms[0], terms[1], ...)
predicate_name(terms[0], terms[1], ...)
&
operator. It returns an instance of pyDatalog.Answer, or None. An instance of the pyDatalog.Variable class has the following attributes and methods:
An instance of the pyParser.Query class is returned by an in-line query and has the following attributes and methods:
An instance of the pyDatalog.Answer class is returned by pyDatalog.ask(query
) and has the following attributes and methods:
pyEngine has the following attributes for debugging queries:
Note
Beware that, when loading a datalog program, a symbol could become a constant. For example,
@pyDatalog.program()
def _():
+ a(i)
for i in range(3):
+ b(i)
print(pyDatalog.ask("a('i')")) # prints a set with 1 element : the ('i',) tuple
print(pyDatalog.ask("b(X)")) # prints a set with 3 elements, each containing one element : 0, 1 or 2
The for
loop assigns an integer to i, which is inserted as a constant in + b(i)
.