yuce / pyswip

PySwip is a Python - SWI-Prolog bridge enabling to query SWI-Prolog in your Python programs. It features an (incomplete) SWI-Prolog foreign language interface, a utility class that makes it easy querying with Prolog and also a Pythonic interface.
MIT License
464 stars 97 forks source link

Broken variable handling? #124

Closed VorpalBlade closed 3 years ago

VorpalBlade commented 3 years ago

I'm not sure if I'm doing something wrong or if this is a bug:

In swipl:

?- assertz(a(X,X)).
true.

?- a(X,Y).
X = Y.

This is what I expect.

With pyswip:

In [1]: import pyswip

In [2]: p = pyswip.Prolog()

In [3]: p.assertz("a(X,X)")

In [4]: list(p.query("a(X,Y)."))
Out[4]: [{'X': Variable(70), 'Y': Variable(73)}]

As can be seen, the two variables are not identified to be the same. For my purposes (refinement operators for ILP tasks) I need to be able to tell if two variables are identical.

I have tried this on the both the version from PyPI (0.2.10) and the latest git as of writing this (9642fd9efa398c35a11d25efa702aef6e613baaf).

$ swipl --version
SWI-Prolog version 8.2.4 for x86_64-linux
$ python --version
Python 3.8.5
$ lsb_release -d
Description:    Ubuntu 20.04.2 LTS

I have also tested this on Python 3.9 with the same behaviour.

VorpalBlade commented 3 years ago

I tried debugging this, and it seems the call to PL_get_chars in Variable.__init__ returns 0 and thus Variable.chars is never set. I assume this should be set to the print name of the variable and allow me to identify unique variables.

I don't have a minimal test case for this (though maybe I could try to write one), but this also happens with a more complex query:

In swipl:

refine(grandparent(Tgt0,Tgt1) :- true, [Tgt0,Tgt1], 0, 0, Results).
Results = [((grandparent(Tgt0, Tgt1):-parent(Tgt0, Tgt0)), 0, 1, [Tgt0, Tgt1]), ...]

And the same query via pyswip:

list(prolog.query(query))
Out[3]: 
[{'Tgt0': Variable(70),
  'Tgt1': Variable(73),
  'Results': [Functor(196877,2,:-(grandparent(Variable(83), Variable(84)), parent(Variable(85), Variable(86))),,(0, ,(1, [Variable(92), Variable(93)]))),
              ...]}]

As can be seen, here every time the same variable appears it has a unique identifier, which means the result is unusable for my application.

VorpalBlade commented 3 years ago

I found an (the?) issue. The values in core.py for CVT_VARIABLE, BUF_RING etc no longer matches SWI-Prolog.h. I don't know the exact version where these changes were introduced but it seems new version logic is needed for this.