Prolog query question - prolog

I am new to prolog, and I have to write a program about the water
jugs. My problem is regarding the initial state of jugs and the query
formation. The query will be of the form:
?- myPredicate(args), filled(j1,1)
Meaning j1 filled with 1 gallon of water. j1 represents one of the jugs; the other is j2. Initally, I have
filled(j1,0)
filled(j2,5)
capacity(j1,2)
capacity(j2,5)
I would really be grateful if you provide me with information regarding the following:
Question A: Do I have to declare initial state of the j1 inside my program? filled(j1,0)
Question B: I need to make my program find a solution for
filled(j1,1). For that I have some ideas, but what I am not sure
about, is how to update filled(J,Volume) from query and
myPredicate.
I am very confused since I have the initial state filled(j1,0) and now
I have to create a filled(j1,1) in myPredicate. So I should have some form of filled(J,Volume) in myPredicate, so the query returns true instead of false.
How do I incorporate filled(J,Voume) inside myPredicate so when the above query is run, I can show correct answer?

Example program with a passed-in parameter, an initial fact and an iterative task to perform. Iteration is by means of recursion. Before each reentry the value related to certain a parameter can be effectively updated for the next pass.
my_loop(N) :- N > 10.
my_loop(N) :- N =< 10,
write(N), nl,
Nextin is N + 1,
my_loop(Nextin).
:- my_loop(1).
A:
The given information (facts) are needed by
the program. They can be made available from keyboard input, as initial
arguments to some predicate, or as facts in the database as you
suggested. Also, only suggested for special situations, the facts
can be hard-coded into some predicate or rule.
Below and above are example of passing the initial information in as parameters: :- my_predicate(args...).
If there are a lot of facts, the database is best. A few facts that
need to change every time is best gotten from the keyboard. Otherwise,
it probably doesn't matter.
:- my_predicate([fill(j1,0),fill(j2,5)], Answer),
write(Answer),
nl.
B:
See the my_ loop example:
In my_loop, the task of counting [1..10] is solved iteratively.
The givens: 1 is passed in as a parameter, mainly because the
program does the same thing over-and-over:
1. take a number (N); quit if it is too big. Otherwise...
2. print it.
3. calculate the next number (N+1)
4. repeat
10 is hard-coded. It could have been a fact: stop_after(10).
Now the data to be manipulated, the variable N in my_loop, and
{ j1,j2 } in myPredicate doesn't actually need to be re-assigned over-and-over again: See my_loop. Just re-enter
the computation when it's time to do the same
thing again, but with different parameters:
cap(j1,2).
cap(j2,5).
my_predicate(Status, Answer) :-
got_juice(Status,0),
Answer=Status.
%%% Instead of changing values, rerun comp. with new values
%%% based on a computation made from the old ones.
my_predicate([filled(j1,J1), filled(j2,J2)], Answer) :-
Used is J1 + J2,
got_juice(Used, J), J \= 0,
cap(j1,C1), cap(C2),
%% Use cap and filled to add more to filled..
NextJ1 is J1 + ...,
NextJ2 is J2 + ...,
my_predicate(filled(j1,NextJ1), filled(..., Answer).
NOTE:
The predicate above is just to demonstrate iteration in Prolog, using the parameters of "myProgaram". For an actual implementation see the program suggested in the comment from matcheek.

Related

Finding whether a number is a multiple of another

Looking at the code below:
multiple(X,0).
multiple(X,Y) :- lt(0,X), lt(0,Y), diff(Y,X,D), multiple(X,D).
There happens to be something wrong. For your reference:
lt/2 is whether the first argument is less than the second.
diff/3 is whether the third argument is equal to the first argument minus the second.
lt/2 and diff/3 are defined correctly.
Is there a logical mistake in the definition? Is assuming that 0 is the multiple of every number problematic or is the logical mistake somewhere else? I get correct answers but the query goes to infinite loop I think.
EDIT:
here are the other definitions.
natNum(0).
natNum(s(X)) :- natNum(X).
lt(0,s(X)) :- natNum(X).
lt(s(X),s(Y)) :- lt(X,Y).
sum(0,X,X).
sum(s(X),Y,s(Z)) :- sum(X,Y,Z).
diff(X,Y,Z) :- sum(Z,Y,X).
?- multiple(X, s(s(s(s(s(s(0))))))).
where s(0) is 1, s(s(0)) is 2 etc. It gives all the desired answers for X but after the last answer, it gets stuck. I assume in an infinite recursive loop?
What is happening in your program? Does it loop forever, or does it only take some time since you haven't updated your hardware in recent decades? We cannot tell. (Actually, we could tell by looking at your program, but that is much too complex for the moment).
What we can do with ease is narrow down the source of this costly effort. And this, without a deep understanding of your program. Let's start with the query:
?- multiple(X, s(s(s(s(s(s(0))))))).
X = s(0)
; X = s(s(0))
; X = s(s(s(0)))
; X = s(s(s(s(s(s(0))))))
; loops. % or takes too long
Isn't there an easier way to do this? All this semicolon typing. Instead, simply add false to your query. In this manner the solutions found are no longer shown and we can concentrate on this annoying looping. And, if we're at it, you can also add false goals into your program! By such goals the number of inferences might be reduced (or stays the same). And if the resulting fragment (called a failure-slice) is looping, then this is a reason why your original program loops:
multiple(_X,0) :- false.
multiple(X,Y) :- lt(0,X), false, lt(0,Y), diff(Y,X,D), multiple(X,D).
natNum(0) :- false.
natNum(s(X)) :- natNum(X), false.
lt(0,s(X)) :- natNum(X), false.
lt(s(X),s(Y)) :- false, lt(X,Y).
?- multiple(X, s(s(s(s(s(s(0))))))), false.
loops.
Do your recognize your program? Only those parts remained that are needed for a loop. And, actually in this case, we have an infinite loop.
To fix this, we need to modify something in the remaining, visible part. I'd go for lt/2 whose first clause can be generalized to lt(0, s(_)).
But wait! Why is it OK to generalize away the requirement that we have a natural number? Look at the fact multiple(X,0). which you have written. You have not demanded that X is a natural number either. This kind of over-generalizations often appears in Prolog programs. They improve termination properties at a relatively low price: Sometimes they are too general but all terms that additionally fit into the generalization are not natural numbers. They are terms like any or [a,b,c], so if they appear somewhere you know that they do not belong to the solutions.
So the idea was to put false goals into your program such that the resulting program (failure-slice) still loops. In the worst case you put false at a wrong place and the program terminates. By trial-and-error you get a minimal failure-slice. All those things that are now stroked through are irrelevant! In particular diff/3. So no need to understand it (for the moment). It suffices to look at the remaining program.

Prolog manual or custom labeling

I am currently writing a solver for a floor planning problem in Prolog and have some issues with the labeling part.
The current problem is my constraints are posted but when I launch the labeling, it takes forever to find a solution. I would like to bring in some heuristics.
My question is, how do I manually label my variables ? I am afraid that after defining a clpfd variable like this :
X in Xinf..Xsup
and constraining it, If I do something like :
fd_sup(X, Xmax),
X = Xmax,
...
in my custom label, I won't be using the backtrack ability of Prolog to test the other values of X's domain. Am I wrong ?
Also, is there a smarter way to label my variables than writing custom labeling procedures ? My idea of heuristics would consist in trying extrema of a variable domain alternatively (like max(X), min(X), max(X-1), min(X-1) etc...)
Hope you can help me :)
It is not difficult to write a custom labeling procedure, and with most real problems you will eventually need one anyway in order to incorporate problem-specific heuristics.
The two main components of a labeling procedure are
variable selection: from all the remaining (i.e. not yet instantiated) problem variables, pick one to consider next.
value selection or branching: explore, via backtracking, two or more alternative sub-problems by reducing the chosen variable's domain in (usually) complementary ways.
Using this scheme, the default labeling procedure can be written as
label(Xs) :-
( select_variable(X, Xs, Xs1) ->
branch(X),
label(Xs1)
;
true % done, no variables left
).
select_variable(X, [X|Xs], Xs). % 'leftmost' strategy
branch(X) :- indomain(X).
You can now redefine select_variable/3 to implement techniques such as "first-fail", and redefine branch/1 to try domain values in different orders. As long as you make sure that branch/1 enumerates all of X's domain values on backtracking, your search remains complete.
Sometimes you want to try just one domain value first (say, one suggested by a heuristics), but, if it is no good, not commit to another value immediately.
Let's say that, as in your example, you want to try the maximum domain value first. You could write this as
branch(X) :-
fd_sup(X, Xmax),
(
X = Xmax % try the maximum
;
X #\= Xmax % otherwise exclude the maximum
).
Because the two cases are complementary and cover all possible values for X, your search is still complete. However, because of the second alternative, branch/1 can now succeed with an uninstantiated X, which means you must make sure in the labeling procedure that you don't lose this variable from your list. One possibility would be:
label(Xs) :-
( select_variable(X, Xs, Xs1) ->
branch(X),
( var(X) -> append(Xs1, [X], Xs2) ; Xs2=Xs1 ),
label(Xs2)
;
true % done, no variables left
).
First, always try built-in heuristics. ff is often a good strategy.
For custom labeling strategies, it is often easiest to first convert the domain to a list, then reorder the list, and then simply use member/2 to assign the values of the domain using the new order.
A good building black is dom_integers/2, relating a finite CLP(FD) domain to a list of integers:
:- use_module(library(clpfd)).
dom_integers(D, Is) :- phrase(dom_integers_(D), Is).
dom_integers_(I) --> { integer(I) }, [I].
dom_integers_(L..U) --> { numlist(L, U, Is) }, Is.
dom_integers_(D1\/D2) --> dom_integers_(D1), dom_integers_(D2).
Your specific strategy is easily expressed on a list of such ordered integers, relating these integers to a second list where the values occur in the order you describe:
outside_in([]) --> [].
outside_in([I]) --> [I].
outside_in([First|Rest0]) --> [First,Last],
{ append(Rest, [Last], Rest0) },
outside_in(Rest).
Sample query and result:
?- phrase(outside_in([1,2,3,4]), Is).
Is = [1, 4, 2, 3] ;
false.
Combining this with fd_dom/2 and dom_integers/2, we get (bindings for variables other than X omitted):
?- X in 10..20,
fd_dom(X, Dom),
dom_integers(Dom, Is0),
phrase(outside_in(Is0), Is),
member(X, Is).
X = 10 ;
X = 20 ;
X = 11 ;
X = 19 ;
X = 12 ;
X = 18 ;
etc.
Nondeterminism is preserved by member/2.
Make sure to distinguish labeling strategies from additional propagation. These two aspects are currently a bit mixed in your question.
In SWI-Prolog, there is a predicate called clpfd:contracting/1. It does what you describe: It tries values from the domain boundaries, and removes values that can be seen as inconsistent, i.e., for which it is known that no solution exists.
Therefore, if you have a list of variables Vs, you can try: clpfd:contracting(Vs), and see if this helps.
Note that this can also significantly slow down the search, though on the other hand, also help significantly to reduce the search space before even trying any labeling!
To complement the other answers (one contrasting labeling and propagation, one showing a dedicated labeling method), I now tackle a further very important aspect of this question:
Very often, when beginners complain about the speed of their code, it turns out that their code in fact doesn't even terminate! More efficiency would not help in that case.
Hence, this answer points you towards first ensuring actual termination of your relation.
The best way to ensure termination of CLP(FD) programs is to separate them into 2 parts:
the first, called the core relation, simply posts all constraints.
the second uses labeling/2 to perform the actual search.
Have you done this in your program? If not, please do. When this is done, make sure that the core relation, say solution/2 (where the arguments are: a term denoting the task instance, and the list of variables to be labeled) terminates universally by querying:
?- solution(Instance, Vs), false.
If this terminates, then the following also terminates:
?- solution(Instance, Vs), label(Vs), false.
Of course, in larger tasks, you have no chance to actually witness the termination of the latter query, but a good chance to witness the termination of the first query, because setting up the constraints is often much faster than actually obtaining even a a single solution.
Therefore, test whether your core relation terminates!
This follows up on this previous answer by #mat.
If you have got some more CPU cycles to burn, try shave_zs/1 as defined in this previous answer.
shave_zs/1 kind of works like the auxiliary library predicate clpfd:contracting/1. Unlike contracting/1, however, all values are "up for grabs"—not just the ones at the boundary. YMMV!

Backwards Chaining With Variables

I have been reading up about inference in Prolog/Datalog and while forward chaining seems fairly simple to grasp, I have some issues with backward chaining with any sort of complex example which isn't simply propositional or used to determine a true or false value. I was reading an article the following example was given:
sg(X,X)
sg(X,Y) :- par(X, X1), par(Y,Y1), sg(X1,Y1)
Suppose we were to query sg(a,W) where a is a constant and W is a variable. This could be read as saying:
Give me all those who are in the same generation as a.
The article firstly states that these particular rules will result in an infinite loop in Prolog/Datalog, but can be fixed by changing the second rule to:
sg(X,Y) :- par(X, X1), sg(X1,Y1), par(Y,Y1).
Why would the original result in a loop? Secondly, what would the execution of this kind of query look like? When do values get bound to these variables?
The article seems not be very explicative. Assume the call is "sg(a,W)". Let analize first possibility:
sg(X,Y) :- par(X, X1), par(Y,Y1), sg(X1,Y1)
first "par" will be queried as "par(X=a,X1)", next as "par(Y=W,Y1)". This last query is a totally unbound query, and probably is what the article tries to skip.
Now, the second possibility:
sg(X,Y) :- par(X, X1), sg(X1,Y1), par(Y,Y1).
is executed as par(X=a,X1), sg(X1 /* bound in previous /, Y1), par(Y=W,Y1/ bound in previous */). As you can see, in all queries at least one of the arguments has been previously bound.

printing business cards - a kind of knapsack task

I am new to Prolog and I have some probably simple issue with a piece of code. This is a real world problem that arose last Friday and believe me this is not a CS Homework.
We want to print business cards and these can only be printed in blocks of 900 cards (100 sheets with 9 cards per sheet). The cards for anybody should not be distributed over several blocks. People ordered different amount of cards, E.G:
% "braucht" is german and means "needs"
braucht(anton,400).
braucht(berta,200).
braucht(claudia,400).
braucht(dorothee,100).
braucht(edgar,200).
braucht(frank,400).
braucht(georg,100).
I put together the following definition to find an appropriate block of 900 business cards:
block(0,[]).
block(N,[H|T]) :-
braucht(H,Nh),
% \+(member(H,T)),
D is N - Nh,
D >= 0,
block(D,T).
This produces a nice list of blocks of people whose cards fit together on a 900 cards block. But it stops working if I activate the commented line "\+member...." and just gives me a "false". But I need to assure that nobody is getting more than once on that block. What am I doing wrong here?
It seems that what you want to achieve is to set a constraint that H does not appear in the tail T of the list. However, T is still unbound when you call member/2, so that member(H, T) will succeed and hence \+ member(H,T) will fail.
If you don't want to use Constraint Programming, but use pure Prolog instead, you should use the check in the other direction and check whether H is already present in the list of people that has been aggregated up to that point. Something like:
block(0, List, List).
block(N, Rest, List) :-
braucht(H, Nh),
\+(memberchk(H, Rest)), % will fail when H is already in Rest
D is N-Nh,
D >= 0,
block(D, [H|Rest], List).
The predicate block/3 can be called from a predicate block/2:
block(N, List) :-
block(N, [], List).
If the second argument in your block predicate is the "output", then your problem is that T is a free variable, so member(_,T) will always succeed. For instance:
?- member(anton,T).
T = [anton|_]
T = [_,anton|_]
T = [_,_,anton|_]
and so on...

Prolog dot product with variables (constraint satisfaction)

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.

Resources