Which operators and predicates can be used with clp(fd)? - prolog

Firstly, the clp(fd) documentation mentions:
In modern Prolog systems, arithmetic constraints subsume and supersede low-level predicates over integers. The main advantage of arithmetic constraints is that they are true relations and can be used in all directions. For most programs, arithmetic constraints are the only predicates you will ever need from this library.
Secondly, on a previously asked question, it was mentioned that include/3 is incompatible with clp(fd).
Does that mean that only clp(fd) operators and clp(fd) predicates can be used when writing prolog with the clp(fd) library?
Furthermore, for example, why is include/3 incompatible with clp(fd)? Is it because it does not use clp(fd) operators? To use include/3 in clp(fd) code, would one need to rewrite a version that uses clp(fd) operators and constraints?

why is include/3 incompatible with clp(fd)?
?- X = 1, include(#\=(1),[0,X,2],Xs), X = 1.
X = 1,
Xs = [0,2]. % looks good
?- include(#\=(1),[0,X,2],Xs), X = 1.
false, unexpected.
?- include(#\=(1),[0,X,2],Xs). % generalization
Xs = [0,X,2],
X in inf..0\/2..sup
; unexpected. % missing second answer
So, (#\=)/2 works in this case only if it is sufficiently instantiated. How can you be sure it is? Well, there is no direct safe test. And thus you will get incorrect results in certain cases. As long as these examples fit on a single line, it is rather easy to spot the error. But with a larger program, this is practically impossible. Because of this, constraints and include/3 are incompatible.
A way out would be to produce instantiation errors in cases with insufficient instantiation, but this is pretty hairy in the context of clpfd. Other built-in predicates like (=\=)/2 do this, and are limited in their applicability.
?- X = 1, include(=\=(1),[0,X,2],Xs), X = 1.
X = 1,
Xs = [0,2].
?- include(=\=(1),[0,X,2],Xs), X = 1.
instantiation_error. % much better than an incorrect answer
A safe variant of include/3 is tfilter/3 of library(reif). But before using it, I recommend you read this.

include/3 doesn't have to be incompatible with clpfd (or any other use of attributed variables) - depends on the safe (for the purposes of the program, rather than necessarily "logically pure") usage of the attributed variables. E.g.:
:- use_module(library(clpfd)).
test_include(F) :-
L = [N1, N2, N3, N4],
N1 #< 2,
N2 #> 5,
N3 #< 3,
N4 #> 8,
include(gt_3_fd, L, F).
gt_3_fd(I) :-
I #> 3.
Result in swi-prolog:
?- test_include(F).
F = [_A, _B],
_A in 6..sup,
_B in 9..sup.
The above code is safe, because the variables being used with clpfd are being used consistently with clpfd, and the specified constraints result in reification of gt_3_fd being unnecessary.
Once the variables are nonvar/ground depending on the use-case (clpfd deals with integers, rather than e.g. compound terms, so nonvar is good enough), then the variables can also be used outside of clpfd. Example:
?- I = 5, I > 4, I #> 4, I #> 4.
I = 5.
An operator such as > uses the actual value of the variable, and ignores any attributes which might have been added to the variable by e.g. clpfd.
Logical purity, e.g. adding constraints to the elements in list L after the include/3 rather than before, is a separate issue, and applies to non-attributed variables also.
In summary: A program may be using some integers with clpfd, and some integers outside of clpfd, i.e. a mixture. That is OK, as long as the inside-or-outside distinction is consistently applied, while it is relevant (because e.g. labeling will produce actual values).

Related

How can I write a rule that finds a number using integer/1?

I am writing a rule that is looking for a particular integer. I assumed I can write something like this
find_number(X):-
integer(X),
X > 1, X < 5.
Then expect the result of a query to integer(X) to result in X=2, X=3, X=4, false. Instead, I just get a false result. The only way I found to write this rule is to use numlist/3 like so
find_number(X):-
numlist(2, 4, NumList),
member(X, NumList).
Can anyone explain why this is?
Your reasoning would be perfectly valid iff integer/1 were an actual relation that satisfies basic logical properties.
For example, in classical logic, a unary predicate P satisfies the following property:
If P(σ(T)) is satisfiable for any substitution σ and term T, then P(T) is also satisfiable.
This seems completely obvious and of course holds also for all pure predicates in Prolog.
The problem is that integer/1 is not a pure relation.
In particular, we have for example:
?- integer(3).
true.
Yet the following more general query fails:
?- integer(X).
false.
Is there any integer? No.
Believe it or not, that's how integer/1 actually works.
Clearly, something seems not quite right for such predicates, and so there are better alternatives in all widely used modern Prolog systems. I strongly recommend you use such alternatives instead, to get the most out of Prolog.
For the case of integers, I recommend you check out CLP(FD) constraints (clpfd).
For example, in GNU Prolog, your code could look like this:
good_number(X) :-
X #> 1,
X #< 5.
With the following queries and answers:
| ?- good_number(X).
X = _#2(2..4)
| ?- good_number(X), fd_labeling([X]).
X = 2 ? ;
X = 3 ? ;
X = 4
This works exactly as we expect a relation to work! I have taken the liberty to change the name such that it makes sense also in more specific cases, where there is nothing left to "find":
| ?- good_number(3).
yes
Depending on your Prolog system, you may have to import a library to use such more declarative features. See also logical-purity for more information.
You get only false because integer/1 tests if the input is an integer and if it is it succeeds else if it is not an integer or if it is a variable that is not instantiated as in your case, then it fails.
You could use between/2 built in predicate:
find_number(X):-between(2,4,X).
This will return:
?- find_number(X).
X = 2 ;
X = 3 ;
X = 4.

Duplicate constraints in CLP(FD) and with dif/2

In SWI-Prolog, the following query gives this result:
?- X mod 2 #= 0, X mod 2 #= 0.
X mod 2#=0,
X mod 2#=0.
While correct, there is obviously no need for the second constraint
Similarly:
?- dif(X,0), dif(X,0).
dif(X, 0),
dif(X, 0).
Is there no way to avoid such duplicate constraints? (Obviously the most correct way would be to not write code that leads to that situation, but it is not always that easy).
You can either avoid posting redundant constraints, or remove them with a setof/3-like construct. Both are very implementation specific. The best interface for such purpose is offered by SICStus. Other implementations like YAP or SWI more or less copied that interface, by leaving out some essential parts. A recent attempt to overcome SWI's deficiencies was rejected.
Avoid posting constraints
In SICStus, you can use frozen/2 for this purpose:
| ?- dif(X,0), frozen(X,Goal).
Goal = prolog:dif(X,0),
prolog:dif(X,0) ? ;
no
| ?- X mod 2#=0, frozen(X, Goal).
Goal = clpfd:(X in inf..sup,X mod 2#=0),
X mod 2#=0,
X in inf..sup ? ;
no
Otherwise, copy_term/3 might be good enough, provided the constraints are not too much interconnected with each other.
Eliminate redundant constraints
Here, a setof-like construct together with call_residue_vars/1 and copy_term/3 is probably the best approach. Again, the original implementation is in SICStus....
For dif/2 alone, entailment can be tested without resorting to any internals:
difp(X,Y) :-
( X \= Y -> true
; dif(X, Y)
).
Few constraint programming systems implement contraction also related to factoring in resolution theorem proving, since CLP labeling is not SMT. Contraction is a structural rule, and it reads as follows, assuming constraints are stored before the (|-)/2 in negated form.
G, A, A |- B
------------ (Left-Contraction)
G, A |- B
We might also extend it to the case where the two A's are derivably equivalent. Mostlikely this is not implemented, since it is costly. For example Jekejeke Minlog already implements contraction for CLP(FD), i.e. finite domains. We find for queries similar to the first query from the OP:
?- use_module(library(finite/clpfd)).
% 19 consults and 0 unloads in 829 ms.
Yes
?- Y+X*3 #= 2, 2-Y #= 3*X.
3*X #= -Y+2
?- X #< Y, Y-X #> 0.
X #=< Y-1
Basically we normalize to A1*X1+..+An*Xn #= B respectively A1*X1+..+An*Xn #=< B where gcd(A1,..,An)=1 and X1,..,Xn are lexically ordered, and then we check whether there is already the same constraint in the constraint store. But for CLP(H), i.e. Herbrand domain terms, we have not yet implemented contraction. We are still deliberating an efficient algorithm:
?- use_module(library(term/herbrand)).
% 2 consults and 0 unloads in 35 ms.
Yes
?- neq(X,0), neq(X,0).
neq(X, 0),
neq(X, 0)
Contraction for dif/2 would mean to implement a kind of (==)/2 via the instantiation defined in the dif/2 constraint. i.e. we would need to apply a recursive test following the pairing of variables and terms defined in the dif/2 constraint against all other dif/2 constraints already in the constraint store. Testing subsumption instead of contraction would also make more sense.
It probably is only feasible to implement contraction or subsumption for dif/2 with the help of some appropriate indexing technique. In Jekejeke Minlog for example for CLP(FD) we index on X1, but we did not yet realize some indexing for CLP(H). What we first might need to figure out is a normal form for the dif/2 constraints, see also this problem here.

How to write number classifiers in prolog?

Playing with Prolog for the first time and while I thought I knew what it basically is good for, I find it hard to get anything done in it. So, I tried to find the easiest possible task and even fail to accomplish that.
I think it is due to me not knowing how prolog data types (numbers) are supposed to work or they have special syntax.
So, my first attempt to classify even numbers was:
even(0).
even(X) :- even(X-2).
Result: stack overflow for the query: even(2).
So I thought well if this is not it, then maybe it is:
even(0).
even(X+2) :- even(X).
Result of even(2): false.
So my simple question is: How to write such simple things in prolog? Is it all not working because i use numbers?
Why not do it the normal way:
is_even(X) :-
X /\ 0x1 =:= 0.
If you want to enumerate non-negative even numbers upon backtracking when the argument is not bound, this is a different thing altogether. It is probably easy to just say:
even(X) :-
between(0, infinite, X),
is_even(X).
You can use the second definition like this:
?- even(X).
X = 0 ;
X = 2 ;
X = 4 ;
X = 6 . % and so on
There are some differences between is_even/1 and even/1:
is_even/1 will work for any integer, positive or negative
is_even/1 will, surprisingly enough, work for expressions that evaluate to integers, too, for example, X = 3, ..., is_even(X + 1). This is because =:= accepts an arithmetic expression on either side.
even/1 uses between/3, so the domain of X and error conditions are the same as for the third argument of between/3.
As a consequence, even/1 does not work with negative integers or arithmetic expressions.
But wait, there's more!
Apparently, between(0, infinite, X) is not something you can do in almost any Prolog apart from SWI. So, instead, you can use another predicate that will enumerate positive integers (list lengths):
even_f(X) :-
length(_, X),
is_even(X).
(Thank you to #false for this)
Use is/2 to force the arithmetic evaluation. On their own, Prolog terms are just structural symbolic entities, X-2 is a compound term of arity 2, -(X,2):
3 ?- write_canonical( X-2 ).
-(_,2)
true.
But is is for arithmetic expressions:
4 ?- Z is 5-2.
Z = 3.
Your definition should thus be
even(X):- X=:=0 -> true
; X > 0 -> Y is X-2, even(Y).
The drawback of such definition is that it can't be called in a generative fashion, like even(X) to get all the evens generated one after the other.
It is only good for checking a given number. For simplicity, it ignores the negative numbers and always fails for them.

Getting a sorted, distinct list of integers in Prolog

I'm trying to do something very simple while learning Prolog. However I'm confused why this works:
?- length( L, 3 ),
maplist( member, L, [[1,2,3], [1,2,3], [1,2,3]] ),
sort( L, L ).
L = [1, 2, 3] ;
But this seemingly equivalent variation using clpfd doesn't:
?- use_module(library(clpfd)).
?- length( L, 3 ), L ins 1..3, sort( L, L ).
L = [_G5891, _G5894, _G5897],
_G5891 in 1..3,
_G5894 in 1..3,
_G5897 in 1..3.
This works:
?- length( L, 3 ), L ins 1..3, chain( L, #< ).
L = [1, 2, 3].
But this doesn't:
?- length( L, 3 ), L ins 1..3, chain( L, #=< ), all_different( L ).
L = [_G6519, _G6522, _G6525],
_G6519 in 1..3,
all_different([_G6519, _G6522, _G6525]),
_G6522#>=_G6519,
_G6522 in 1..3,
_G6525#>=_G6522,
_G6525 in 1..3.
Can anyone explain why the non-working examples don't give me the outcome I'm expecting?
As a side question, is there a more concise way to rewrite my maplist expression in the first example above?
CLP in Prolog
The system you are using (SWI-Prolog + library(clpfd)) is one example of the embedding of an integer finite-domain constraint solver into a Prolog system (some others are CHIP, ECLiPSe+fd/ic, B-Prolog, SICStus+clpfd). Such an embedding is very natural in the sense that many Prolog concepts map directly to concepts in Constraint Programming, giving us Constraint Logic Programming (CLP).
However, there are number of features of plain Prolog that should be avoided when using it for CLP. Among those are cuts (including the hidden ones in the if-then-else construct and the \+/2 negation), but also meta-logical operations as in your case. For our purposes, meta-logical means any primitive that treats variables as objects (rather than just as placeholders for values). Examples of these are var/1, ==/2, #</2, and indeed also sort/2.
Meta-logical primitives can already cause ugly effects in plain Prolog, e.g.
?- X\==Y, X=3, Y=3, X==Y.
Yes
but Prolog programmers have learned to use them correctly and avoid such problems. With CLP however, it is easier to fall into these traps because the execution control flow is much less obvious.
As to your examples, the first one works because sort/2 sorts lists of integers, no problem there. In the second case, sort/2 sorts a list of domain variables, resulting in a list of domain variables in an arbitrary, system-defined order. Once this is done, sort/2 considers its job done. If you later assign integer values to those ostensibly "sorted" variables, the sortedness of the list will not be checked again, and your program can now return unsorted integer lists as results.
The correct alternative is to use a sortedness check that involves only pure logical Prolog primitives and/or the constraint predicates defined by the CLP solver. You have already done that by using the chain/2 constraint in your third example.
Local Propagation and Search
In your last example you can observe the typical behaviour of a constraint solver based on local propagation: The answer you get is correct, but not very satisfactory. By analyzing the constraints more deeply, it is actually possible to infer that the only correct solution is [1,2,3], but the solver doesn't do that because it could be computationally expensive. But look what happens if you add just a little bit of information:
?- L=[_,Y,_], L ins 1..3, chain(L, #=<), all_different(L), Y=2.
L = [1, 2, 3],
Y = 2
Ass soon as the solver knows that Y is 2, the problem becomes easy enough for the solver to solve completely.
A solution for the general case is to systematically break down the problem into simpler sub-problems, making sure you cover everything. In other words, you add search, and the Prolog way to do search is with a disjunction. In the example, this could be a simple member(Y,[1,2,3]). Typically, you want to do the same for all the domain variables in your problem, just to be on the safe side. A CLP solver will give you a convenient primitive for this, e.g. in the case of clpfd
?- L=[_,_,_], L ins 1..3, chain(L, #=<), all_different(L), label(L).
L = [1, 2, 3] ;
false.
This is a general structure for CLP programs: first constraint setup, then search.
The built-in predicate sort/2 effectively sorts a list based on the term order defined over all terms including variables. For this reason this predicate cannot be considered to implement a concrete relation. Only in special cases like when the first argument is variable free (that is, ground(L) succeeds) and the term is acyclic (acyclic_term(L) succeeds), the built-in corresponds to the obvious relation.
Here is another such strange case sort([X,1],[1,1]) which succeeds, unifying X = 1.

PROLOG predicate order

I've got a very large number of equations which I am trying to use PROLOG to solve. However, I've come a minor cropper in that they are not specified in any sort of useful order- that is, some, if not many variables, are used before they are defined. These are all specified within the same predicate. Can PROLOG cope with the predicates being specified in a random order?
Absolutely... ni (in Italian, Yes and Not)
That is, ideally Prolog requires that you specify what must be computed, not how, writing down the equations controlling the solution in a fairly general logical form, Horn clauses.
But this ideal is far from reach, and this is the point where we, as programmers, play a role. You should try to topologically sort formulae, if you want Prolog just apply arithmetic/algorithms.
But at this point, Prolog is not more useful than any other procedural language. It just make easier to do such topological sort, in sense that formulas can be read (this builtin it's a full Prolog parser!), variables identified and quantified easily, terms transformed, evaluated, and the like (metalanguages features, a strong point of Prolog).
Situation changes if you can use CLP(FD). Just an example, a bidirectional factorial (cool, isn't it?), from the documentation of the shining implementation that Markus Triska developed for SWI-Prolog:
You can also use CLP(FD) constraints as a more declarative alternative for ordinary integer arithmetic with is/2, >/2 etc. For example:
:- use_module(library(clpfd)).
n_factorial(0, 1).
n_factorial(N, F) :- N #> 0, N1 #= N - 1, F #= N * F1, n_factorial(N1, F1).
This predicate can be used in all directions. For example:
?- n_factorial(47, F).
F = 258623241511168180642964355153611979969197632389120000000000 ;
false.
?- n_factorial(N, 1).
N = 0 ;
N = 1 ;
false.
?- n_factorial(N, 3).
false.
To make the predicate terminate if any argument is instantiated, add the (implied) constraint F #\= 0 before the recursive call. Otherwise, the query n_factorial(N, 0) is the only non-terminating case of this kind.
Thus if you write your equations in CLP(FD) you get much more chances to have your 'equation system' solved as is. SWI-Prolog has dedicated debugging for the low level details used to solve CLP(FD).
HTH

Resources