Origin of clpfd_equal_, or the portability of internal libraries

I’m using as reference SWI-Prolog version 8.1.13, commit 3e2939d8767c221421b578a4a5e7904964907be6

I admit to being a pretty early-stage beginner in Prolog - maybe 10 hours practice. So, I may have missed something obvious to a more advanced user. However, please consider the following.

I’d like to load SWI Prolog’s CLP libraries in a different implementation of Prolog, if possible. (This is my ultimate goal, but not strictly the question I’m asking here. If you can definitively answer yea/nay/how on my goal, though, that’d obviate by question, anyway.) Looking at clpfd.pl, there’s a lot of code, leading me to hope that it was all defined in pure Prolog, and not just stubs calling C code or something. However, after fiddling with the code for a while, I noticed the following oddity in clpfd.pl:

X #= Y :- clpfd_equal(X, Y).

clpfd_equal(X, Y) :- clpfd_equal_(X, Y), reinforce(X).

Note that clpfd_equal is defined in terms of clpfd_equal_. I can find nowhere that clpfd_equal_ is defined, either in the Prolog libraries, or in the C source of SWI Prolog. My next best guess is that the trailing _ has a syntactic meaning, or that somehow it’s programmatically generated in the C source without clpfd_equal_ being explicitly written out anywhere. Would anybody happen to know? Thanks!

The clpfd implementation depends on non portable predicates for attributed variables, so it is probably quite a bit of work to port them to another prolog, but totally doable.

EDIT: Look at https://www.swi-prolog.org/pldoc/man?section=attvar for more info on attributed variables.

2 Likes

clpfd_equal_/2 is generated using term expansion when make_matches is expanded on line 7361. You can check that it’s there by doing the following:

?- use_module(library(clpfd)).
true.

?- clpfd:term_expansion(make_matches, C).
C = [(clpfd_equal_(_2272, _2274):-cyclic_term(_2272)->domain_error(clpfd_expression, _2272);cyclic_term(_2274)->domain_error(clpfd_expression, _2274);false),  (clpfd_equal_(_3492, _3494):-(((((... -> ...;..., ...), (... -> ...;..., ...)), true), !), constrain_to_integer(_22)), _22=_26),  (clpfd_equal_(_3718, _3720):-(((((..., ...), make_propagator(..., ...)), init_propagator(_26, _4044)), init_propagator(_716, _4044)), init_propagator(_22, _4044)), trigger_once(_4044)),  (clpfd_equal_(_3720, _3718):-((((..., ...), init_propagator(..., ...)), init_propagator(_716, _4044)), init_propagator(_22, _4044)), trigger_once(_4044)),  (clpfd_equal_(_4128, _4130):-(((..., ...), init_propagator(..., ...)), init_propagator(_26, _4454)), trigger_once(_4454)),  (clpfd_equal_(_4130, _4128):-((..., ...), init_propagator(..., ...)), trigger_once(_4454)),  (clpfd_equal_(_4538, _4540):-(..., ...), trigger_once(...)),  (clpfd_equal_(..., ...):- ..., ...),  (... :- ...)|...] ;
false.

?- 

Look at the definition of make_matches/1 to see how it is generated.

2 Likes

Yes. It isn’t all too bad though. There are a limited set of related interfaces to attributed variables. clpfd depends on dynamic attributed variables as invented by Bart Demoen. This simple interface is quite easily supported by the other interfaces. clpfd has been ported to several Prolog systems and is quite portable to any Prolog implementation with attributed variables. Some other Prolog systems have a clpfd with a different origin, often for a large part written in C. Most show pretty similar to the user though.

For short, you can use clpfd in most modern Prolog systems that do not aim to be some sort of minimal implementation of the ISO Prolog standard.

1 Like