I know a little Prolog, and frequently use CLP(FD) etc. This paper (written in 2006, apparently) indicates that Mercury now has constraint solving, too. I've found a few mentions of it in the Library Reference Manual. However, I can't find how to use it. For instance:
main(!IO) :-
A >= 2,
A =< 2,
io.write(A, !IO).
gives compiler error
test1.m:011: In clause for `main(di, uo)':
test1.m:011: in argument 1 of call to predicate `int.>='/2:
test1.m:011: mode error: variable `A' has instantiatedness `free',
test1.m:011: expected instantiatedness was `ground'.
but in Prolog, with clpfd,
A #>= 2, A #=< 2.
works fine, giving A = 2 .
(Adding #s to the Mercury code doesn't help.)
How do you do constraint solving in Mercury?
That paper does NOT say the you can now do constraint solving in Mercury
the same way as you can do in Prolog. It describes features added to Mercury
at the time to support writing constraint solvers in Mercury, and then
using the resulting solvers, which is quite different.
Mercury does not have, and will not have, any builtin constraint solvers.
Related
?- X in 1..100.
X in 1..100.
?- X #> 0, X #< 101.
X in 1..100.
So far so good!
Now let's imagine that the sup bound of X depends on Y in 100..200.
?- Y in 100..200, X #> 0, X #=< Y.
Y in 100..200,
Y#>=X,
X in 1..200.
The domain of X propagates correctly to 1..200, with the constraint between X and Y.
But…
?- Y in 100..200, X in 1..Y.
ERROR: Arguments are not sufficiently instantiated
I thought that in was equivalent to the inequalities declaration, but it apparently is not.
Is there any hidden reason as to why in requires that both bounds are ground?
That's a very good question. It has a straight-forward answer that may at first appear deep, yet is really easy to understand once you are familiar with declarative debugging approaches that are beginning to become more widely available.
Declarative debugging relies on properties of logic programs that we know always hold. A key property of pure logic programs (see logical-purity) is monotonicity:
Generalizing a goal can at meast increase the set of solutions.
Here is an example:
?- append([a], [b], [c]).
false.
Why does this fail? We want to find an actual cause of failure, an explanation why this does not succeed. It is tempting to think in procedural terms and trace the execution, but this quickly gets extremely complex and does not really show us the essence of the reason.
Instead, we can get to the essence by generalizing the goals systematically. For example, the following succeeds:
?- append([a], [b], Cs).
I have generalized the query by replacing the term [c] with Cs, which subsumes it.
You can do this automatically, see Ulrich Neumerkel's library(diadem) and especially the GUPU system where these ideas are fully developed and help tremendously to locate the precise location of mistakes in Prolog programs.
To apply such techniques to their utmost extent, you must aim to preserve as many interesting properties as possible in your programs, essentially by staying in the pure monotonic core of Prolog. I say "essentially" because these techniques also work somewhat beyond this subset on a class of programs that is very hard to classify formally. Note also that much of the ongoing work on logic programming is aimed towards increasing the pure monotonic subset of Prolog as far as possible, so the restriction becomes less and less severe over time.
Consider now the specifics of (in)/2: The domain argument of (in)/2 carries within it a declarative flaw in that it uses a defaulty representation of domains. There are several ways to see this, and notably from the following situation: Suppose I tell you that a domain has the form inf..High, then what is High? It can be either of:
sup
an integer.
The fact that we cannot clearly distinguish these cases tells you that this representation is defaulty.
A clean representation of boundaries would look like this:
inf, sup to denote the infinities
n(N) to denote the integer N.
With such a representation, I could tell you that the domain looks like this: inf..n(N), and you know that N must be an integer.
Now another example:
?- X in 1..0.
false.
Why does this fail? Let us again generalize the arguments to find a reason:
?- X in Low..0.
Suppose now that (in)/2 accepted this as an admissible query. Then what is Low? Again, it can be either an integer, or the atom inf. Unfortunately, there is no sensible way to constrain Low in this way: Constraining it to integers would make CLP(FD) constraints most appropriate, making it tempting to answer with:
X in Low..0,
Low in inf..0
but that is of course too much, because it precludes Low = inf:
?- Low in inf..0, Low = inf.
Type error: `integer' expected, found `inf' (an atom)
Knowing that we cannot decide the type of the term Low in such situations, and lacking a sensible way to state this, an instantiation error is raised to indicate that such a generalization is inadmissible.
From these considerations, the overall answer is really simple:
(in)/2 cannot be easily generalized due to the defaulty representation of domains.
Invariably, there are only two reasons for using such representations:
they are easier to type
they are easier to read.
The hefty drawback of course is that they stand massively in the way of declarative reasoning over your programs.
Note that internally, the CLP(FD) system of SWI-Prolog does use a clean representation of domains. This can also be carried over to the user side, so that we could write:
?- X in n(Low)..0.
with the declaratively perfectly valid answer:
X in n(Low)..0,
Low in inf..0.
Over time, such cleaner notations will definitely find their way to users. For now, it would be a bit too much to ask, at least in my experience.
In the specific examples you cite, the domain boundary is already constrained to integers, so of course we can distinguish the cases and translate this automatically to inequalitites. However, this would not remove the core problem of defaultyness, and exchanging the goals would still raise an instantiation error.
I'm using swi-prolog. I'm simply trying to follow the examples in the book "the art of prolog", but I'm not getting the correct results. I'm afraid this might be due to the s/1 predicate. I can't even find s/1 in the documentation for swipl, the only predicate that is similar is succ/2: http://www.swi-prolog.org/pldoc/man?predicate=succ/2 This can't be used the same way as s/1. I'd much prefer to have the s predicate.
This is the program for determining whether a number is a natural number:
natural_number(0).
natural_number(s(X)) :- natural_number(X).
However, natural_number(1) for example yields false. What's the problem here?
I am required to write my own version of all_different in SWI-Prolog. I've written a predicate that returns the same true/false on the inputs I'm giving as all_different does, but I'm having trouble finding online a way to actually apply this predicate as a constraint.. Here is my version of all_different.
distinct([]).
distinct([X|Xs]) :-
different(X,Xs),
distinct(Xs).
different(_,[]).
different(X,[Y|Ys]) :-
(nonvar(X), nonvar(Y) -> X \= Y
;
true
),
different(X,Ys).
I need it to apply to a list of integers and _. Yes, this is the sudoku program project. Sorry if this is a dumb question, but I am still very new to Prolog, and I find it difficult to find sufficient documentation online.
Please help!
You have written a predicate and not a constraint. In a nutshell, predicates either succeed or fail, while constraints only express restrictions on the possible values. Constraints are being recorded by the constraints' solver that does some black magic to simplify them and to indicate ranges of possible values for the variables involved. Hence, you cannot apply your predicate as a constraint.
You can either reconsider the original problem and check whether you need a constraint, or modify your implementation above as follows (I'm using SWI-Prolog):
different(X,[Y|Ys]) :-
X#\= Y,
different(X,Ys).
#\= indicates that the disequality expression is a constraint.
You might like to check http://www.swi-prolog.org/man/clpfd.html and specifically differences between all_different/1 and all_distinct/1.
I'm trying to solve a logic puzzle with Prolog, as a learning exercise, and I think I've correctly mapped the problem using the GNU Prolog finite domain solver.
When I run the solve function, Prolog spits back: yes and a list of variables all bounded in the range 0..1 (booleans, as I've so constrained them). The problem is, when I try to add a fd_labeling(Solution) clause, Prolog about faces and spits out: no.
I'm new to this language and I can't seem to find any course of attack to figure out why everything seems to work until I actually ask it to label the answers...
Apparently, you didn't "correctly" map the problem to FD, since you get a "no" when you try to label the variables.
What you do in Constraint Logic Programming is set up a constraint model, where you have variables with a domain (in your case booleans with the domain [0,1]), and a number of constraints between these variables. Each constraint has a propagation rule that tries to achieve consistency for the domains of the variables on which the constraint is posted. Values that are not consistent are removed from the domains. There are several types of consistency, but they have one thing in common: the constraints usually won't by themselves give you a full solution, or even tell you whether there is a solution for the constraint model.
As an example, say you have two variables X and Y, both with domains [1..10], and the constraint X < Y. Then the propagation rule will remove the value 1 from the domain of Y and remove 10 from the domain of X. It will then stop, since the domains are now consistent: for each value in one domain there exists a value in the other domain so that the constraint is fulfilled.
In order to get a solution (where all variables are bound to values), you need to label variables. Each labeling will wake up the constraints attached to the labeled variable, triggering another round of propagation. This will lead to a solution (all variables bound to values, answer: yes) or failure (in each branch of the search tree, some variable ends up with an empty domain, answer: no)
Since each constraint is only aiming for consistency of the domains of the variables on which it is posted, it is possible that an infeasibility that arises from a combination of constraints is not detected during the propagation stage. For example, three variables X,Y,Z with domains [1..2], and pairwise inequality constraints. This seems to have happened with your constraint model.
If you are sure that there must be a solution to the puzzle, then your constraint model contains some infeasibility. Maybe a sharp look at the constraints is already sufficient to spot it.
If you don't see any obvious infeasibility (e.g., some contradicting constraints like the inequality example above), you need to debug your program. If it's possible, don't use a built-in labeling predicate, but write your own. Then you can add some output predicate that allows you to trace what variable was instantiated and what changes in the boolean decision variables this caused or whether it led to a failure.
(#twinterer already gave an explanation, my answer tries to take it from a different angle)
When you enter a query to Prolog what you get back is an answer. Often an answer contains a solution, sometimes it contains several solutions and sometimes it does not contain any solution at all. Quite often these two notions are confused. Let's look at examples with GNU Prolog:
| ?- length(Vs,3), fd_domain_bool(Vs).
Vs = [_#0(0..1),_#19(0..1),_#38(0..1)]
yes
Here, we have an answer that contains 8 solutions. That is:
| ?- length(Vs,3), fd_domain_bool(Vs), fd_labeling(Vs).
Vs = [0,0,0] ? ;
Vs = [0,0,1] ? ;
...
Vs = [1,1,1]
yes
And now another query. That is the example #twinterer referred to.
| ?- length(Vs,3), fd_domain_bool(Vs), fd_all_different(Vs).
Vs = [_#0(0..1),_#19(0..1),_#38(0..1)]
yes
The answer looks the same as before. However, it does no longer contain a solution.
| ?- length(Vs,3), fd_domain_bool(Vs), fd_all_different(Vs), fd_labeling(Vs).
no
Ideally in such a case, the toplevel would not say "yes" but "maybe". In fact, CLP(R), one of the very first constraint systems, did this.
Another way to make this a little bit less mysterious is to show the actual constraints involved. SWI does this:
?- length(Vs,3), Vs ins 0..1, all_different(Vs).
Vs = [_G565,_G568,_G571],
_G565 in 0..1,
all_different([_G565,_G568,_G571]),
_G568 in 0..1,
_G571 in 0..1.
?- length(Vs,3), Vs ins 0..1, all_different(Vs), labeling([], Vs).
false.
So SWI shows you all constraints that have to be satisfied to get a concrete solution. Read SWI's answer as: Yes, there is a solution, provided all this fine print is true!
Alas, the fine print is false.
And yet another way to solve this problem is to get an implementation of all_different/1 with stronger consistency. But this only works in specific cases.
?- length(Vs,3), Vs ins 0..1, all_distinct(Vs).
false.
In the general case you cannot expect a system to maintain global consistency. Reasons:
Maintaining consistency can be very expensive. It is often better to delegate such decisions to labeling. In fact, the simple all_different/1 is often faster than all_distinct/1.
Better consistency algorithms are often very complex.
In the general case, maintaining global consistency is an undecidable problem.
I'm working on a prolog assignment and I'm currently very very close to the solution. So, the problem is a constraint satisfaction problem where I have to find values for a set of variables such that certain conditions are true. Specifically, given 3 words (W1,W2,W3), assign their variables such that W1+W2=W3. An example of this would be SEND+MORE=MONEY, or IT+IS=ME.
The constraints are: (1) they have to add up correctly, (2) the starting letter cannot be 0 (3) and all variables must be distinct. And it has to work for a general word problem. My issue is happening when I try to ensure that they add up correctly (I've met the other conditions and I understand the problem). In terms of the second word problem we should have:
10*I + 1*T
+10*I + 1*S
___________
10*M + 1*E
So, I have made a function that makes lists of powers of 10 in a certain length, like so:
powlist(1,L) :-
append([1.0],[],L).
powlist(N,L) :-
N1 is N-1,
X is 10**N1,
powlist(N1,L1),
append([X],L1,L),
!.
I also have the actual list of letters, say, [I,T,I,S,M,E]. I then constructed a list of coefficients (I'll explain that part later) out of powlist so we have something like the following: [10,1,10,1,-10,-1]. I did this so if we took the dot product between this list of coefficients and the list of letters, and it was zero, the constraint would be satisfied. But, I can't get this dot product theory to work. I currently have a line that says:
scalar_product(Coefficients, Letters, #=, 0)
But this is giving me the following error:
! Instantiation error in argument 2 of is/2
! goal: _102 is 0+10.0*_109
I'm not sure how to define dot product so it can work on variables (instead of just atoms). All of the rest of the code works perfectly (and I don't want to put it on here because this is a very common question for introductory prolog courses, and I don't want to give lazy people answers). What do you guys suggest?
Your strategy is indeed sound and does work, at least with SWI-Prolog CLP(FD) using the built-in scalar_product/4. I am unfamiliar with the definition of this predicate in SICStus, but it's interface appears to be the same as in SWI-Prolog.
I can make a couple of suggestions. Firstly, perhaps some aspect of the code you've written is generating choicepoints which, when executed in backtracking (e.g., to seek alternate solutions, such as via label/1), the interpreter executes the subgoal _102 is 0+10.0*_109 where _109 is unintentionally unbound. Have you written a predicate which contains such a line? Even if not, I recommend double checking your code to ensure that they do not generate unnecessary choicepoints, such as your definition of powlist/2. I recommend that you try the following instead:
powlist(1, [1]) :- !.
powlist(N, [F|Fs]) :-
N > 1,
N1 is N - 1,
F is 10 ** N1,
powlist(N1, Fs).
This version leaves no choicepoints for the Prolog interpreter to backtrack to, which might resolve the problem (though, without seeing more code, I simply can't tell).
Otherwise, if you are correct and the error is indeed emanating from within the definition of scalar_product/4 (though I'd be surprised), then perhaps you could generate the scalar product constraint term and add it to the store yourself, manually. For example, consider:
my_scalar_product([V|Vs], [C|Cs], Op, Value) :-
construct_constraint(Vs, Cs, (V * C), Constr),
Constraint =.. [Op, Constr, Value],
Constraint.
construct_constraint([], [], Acc, Acc).
construct_constraint([V|Vs], [F|Fs], Acc, Res) :-
construct_constraint(Vs, Fs, '+'(Acc, (V * F)), Res).
This version (my_scalar_product/4) assumes the same interface as the built-in scalar_product/4, but it adds the constraint to the store instead of attempting to execute it using is/2.