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

Preserve / Output CLP Ranges for Query #123

Closed rindPHI closed 3 years ago

rindPHI commented 3 years ago

Hi all,

I'm currently working with queries that output "abstract" terms containing CLP variables with bounded domain. For instance, a direct swipl query returns:

S = [stmt, [[assgn, [[var, [[_15304, []]]], [" := ", []], [rhs, [[digit, [[_15382, []]]]]]]]]],
_15304 in 120..122,
_15382 in 49..51

I did not find any way to retrieve the bounds 120..122 etc. for the contained variables; I only get the instantiation of S. Unfortunately, I need this information for further processing. Do you have any idea for solutions to that problem?

Thanks in advance and Best Regards, Dominic

rindPHI commented 3 years ago

OK, I thought I found a solution by applying a trick suggested by the clpfd documentation: Making the constraints involved in a term explicit by calling copy_term:

stmt(S), term_variables(S, Vs), copy_term(Vs, Vs, Gs).

However, the variables Gs have different handles than those in S, which they don't when I run this directly in the swipl interface. The names of these variables are something like _123, so they don't have the chars property set. Is there any way to fix this issue (i.e., same handles for same variables, or some workaround to check whether two variables w/ different handle actually represent the same variables)?

Thanks again!

/edit:

From swipl, I get the output

?- stmt(X), term_variables(X, Vs), copy_term(Vs, Vs, Gs).
X = [stmt, [[assgn, [[var, [[_34850, []]]], [" := ", []], [rhs, [[digit, [[_34928, []]]]]]]]]],
Vs = [_34850, _34928],
Gs = [clpfd:(_34850 in 120..122), clpfd:(_34928 in 49..51)],
_34850 in 0..10,
_34928 in 0..9 

whereas pyswip gives my

(["'stmt'", [["'assgn'", [["'var'", [['_155', []]]], ['" := "', []], ["'rhs'", [["'digit'", [['_181', []]]]]]]]]], 
['_208 in 0..10', '_215 in 0..9'])

Please ignore the different quotation marks; that's since these are Python strings. I translated the expressions from the pyswip objects to strings with a method I wrote myself, the _208 etc. are obtained by calling variable.handle. Note the different handles, which refer to different variables after translation to string.

If it necessary to know, the original string representation of the pyswip query result is

{'S': [Atom('919813'), [[Atom('919941'), [[Atom('110981'), [[Variable(174), []]]], [b' := ', []], [Atom('920325'), [[Atom('110981'), [[Variable(200), []]]]]]]]]], 
'Vs': [Variable(217), Variable(218)],
'Gs': [Functor(192781,2,clpfd,in(Variable(227), ..(0, 10))), Functor(192781,2,clpfd,in(Variable(234), ..(0, 10)))]}

All variable handles are different...

rindPHI commented 3 years ago

OK, kind of got it... Variables w/ different handles can represent the same prolog variable, which you find out by comparing them with standard Python equality ==. So when I translate those to a Prolog string, I have to "unify" (not in the Prolog sense!) the variable names for equal variables. Another trap was that I wanted to do this inside a list comprehension, and there equality checks did not work. Obviously the corresponding information about the handles got lost in between. Now I'm using a loop, and it works.

Is there any better procedure to convert a query result s.t. equal variables have the same handle? This would be quite useful and less confusing for beginners, I guess...