This may seem like an odd question that could simply be answered by the findall/3 predicate. However my problem is a little deeper than that.
So I have a predicate called ran_num/1 that returns one of five random numbers (that is I do not know what the numbers could be but there are only 5 of them).
When I run the predicate it returns this output as an example:
?- ran_num(X).
X = 2
?-
Note that there are no alternative answers, pressing ; will do nothing. Prolog is awaiting another query command.
If I run findall on this the result is:
?- findall(X, ran_num(X), L).
L = [2]
?-
Is there an inbuilt predicate or method I can implement that will get me all the possible numbers that can be generated? So for example I can get a list which is [2,60,349,400,401].
Assume I cannot change the ran_num/1 predicate to give me alternatives.
The problem that you face is that ran_num/1 is deterministic as far as the interpreter is concerned. It doesn't know that calling it again may yield a different result.
Prolog's random_between/3 works like that, so I've defined your predicate ran_num/1 as follows.
ran_num(X) :-
random_between(1, 5, Y),
ran_num_mapping(Y, X).
ran_num_mapping(1, 2).
ran_num_mapping(2, 60).
ran_num_mapping(3, 349).
ran_num_mapping(4, 400).
ran_num_mapping(5, 401).
This is deterministic, like your example.
So ran_num/1 returns one of five different numbers at random and we want to know these five numbers. This means we need to keep calling ran_num/1 until we have a set of five numbers.
We can define a set S of length N.
is_set_of_length(S, N) :-
is_set(S),
length(S, N).
So we have all "ran_num"s if we have a set of length 5.
get_all_ran_nums(Y, Y) :-
is_set_of_length(Y, 5), !.
Otherwise, we get another ran_num, add it to the set, and check again.
get_all_ran_nums(L, T) :-
ran_num(X),
ord_add_element(T, X, Lout),
get_all_ran_nums(L, Lout).
We need to start this with an empty list.
get_all_ran_nums(X) :-
get_all_ran_nums(X, []).
And this yields our result.
?-
get_all_ran_nums(X).
X = [2, 60, 349, 400, 401]
?-
Please note that the cut in the first clause of get_all_ran_nums/2 is necessary, otherwise we can keep backtracking but getting the same result. Since we can keep generating ran_nums and adding them to the set; if they are already in the set, ord_add_element/3 will still succeed.
Also note that, since the numbers are generated at random, in theory this could keep running for any length of time and not getting the fifth number we need to stop.
Related
I'm currently studying Prolog, and in one of the notes I'm reading an example is given of how to use the cut operator correctly. Consider the following function to remove all elements of a particular value from a list.
rm(_,[],[]).
rm(A,[A|L],R) :- rm(A,L,R).
rm(A,[B|L],[B|R]) :- rm(A,L,R).
Due to backtracking, this is not a correct definition of the function, and the function will return all sublists of the list obtained from removing some elements of a particular value, but not necessarily all of them. The notes I'm reading say that a correct way to fix this is to replace the second line by the line
rm(A,[A|L],R) :- !, rm(A,L,R)
But that replacing the line by
rm(A,[A|L],R) :- rm(A,L,R), !
is not correct. I'm not sure why the second example is an incorrect way to fix the function. In swipl, replacing the second term by these fixes seems to always return the same answer on the test cases I consider. What am I missing here?
Your example is a perfect example to illustrate why using the cut here is never a good idea.
Using rm(A,[A|L],R) :- !, rm(A,L,R). makes only sense if both the first and second argument are sufficiently instantiated. But if they are insufficiently instantiated, you get an incomplete answer like:
?- rm(X, [a], R).
X = a, R = []. % incomplete
This clearly misses an answer, as it constrains X to be a only. But if X is anything else, we get a different result, namely:
?- X = b, rm(X,[a],R).
R = [a].
Using the cut at the end as in rm(A,[A|L],R) :- rm(A,L,R), !. is even worse: First, all our assumptions so far must hold, and then additionally the third argument must not be instantiated. Otherwise we get additional incorrect solutions.
?- rm(a,[a],R).
R = [].
?- rm(a,[a],[a]).
true, unexpected. % incorrect
Just recall what we are asking here:
User: When removing a from the list [a] what do we get?
Prolog: Nothing, nil, nada.
User: But can't I have instead of nothing just [a]? Please!
Prolog: OK, I give in.
That's not the way you want to implement an accounting system.
So both uses of cuts are bad. But the second one is clearly worse for it has many more preconditions to remember and is also inefficient.
On the other hand there are some cases where you can use these predicates. But typically it is quite difficult to remember when this is safe. Thus such cuts are a permanent source of errors.
Is there any hope to get rid of all this fine print? Fortunately, there is a way out using if_/3 from library(reif) for SICStus|SWI. Download it and say:
:- use_module(reif).
rm(_,[],[]).
rm(A,[X|Xs], Ys0) :-
if_(A = X, Ys0 = Ys, Ys0 = [X|Ys]),
rm(A, Xs, Ys).
This program is comparably efficient but does not have any of the aforementioned defects:
?- rm(X, [a], R).
X = a, R = []
; R = [a], dif(X, a).
Note the second new answer! It says that for all X that are different to a, the list remains unchanged.
This is probably the most trivial implementation of a function that returns the length of a list in Prolog
count([], 0).
count([_|B], T) :- count(B, U), T is U + 1.
one thing about Prolog that I still cannot wrap my head around is the flexibility of using variables as parameters.
So for example I can run count([a, b, c], 3). and get true. I can also run count([a, b], X). and get an answer X = 2.. Oddly (at least for me) is that I can also run count(X, 3). and get at least one result, which looks something like X = [_G4337877, _G4337880, _G4337883] ; before the interpreter disappears into an infinite loop. I can even run something truly "flexible" like count(X, A). and get X = [], A = 0 ; X = [_G4369400], A = 1., which is obviously incomplete but somehow really nice.
Therefore my multifaceted question. Can I somehow explain to Prolog not to look beyond first result when executing count(X, 3).? Can I somehow make Prolog generate any number of solutions for count(X, A).? Is there a limitation of what kind of solutions I can generate? What is it about this specific predicate, that prevents me from generating all solutions for all possible kinds of queries?
This is probably the most trivial implementation
Depends from viewpoint: consider
count(L,C) :- length(L,C).
Shorter and functional. And this one also works for your use case.
edit
library CLP(FD) allows for
:- use_module(library(clpfd)).
count([], 0).
count([_|B], T) :- U #>= 0, T #= U + 1, count(B, U).
?- count(X,3).
X = [_G2327, _G2498, _G2669] ;
false.
(further) answering to comments
It was clearly sarcasm
No, sorry for giving this impression. It was an attempt to give you a synthetic answer to your question. Every details of the implementation of length/2 - indeed much longer than your code - have been carefully weighted to give us a general and efficient building block.
There must be some general concept
I would call (full) Prolog such general concept. From the very start, Prolog requires us to solve computational tasks describing relations among predicate arguments. Once we have described our relations, we can query our 'knowledge database', and Prolog attempts to enumerate all answers, in a specific order.
High level concepts like unification and depth first search (backtracking) are keys in this model.
Now, I think you're looking for second order constructs like var/1, that allow us to reason about our predicates. Such constructs cannot be written in (pure) Prolog, and a growing school of thinking requires to avoid them, because are rather difficult to use. So I posted an alternative using CLP(FD), that effectively shields us in some situation. In this question specific context, it actually give us a simple and elegant solution.
I am not trying to re-implement length
Well, I'm aware of this, but since count/2 aliases length/2, why not study the reference model ? ( see source on SWI-Prolog site )
The answer you get for the query count(X,3) is actually not odd at all. You are asking which lists have a length of 3. And you get a list with 3 elements. The infinite loop appears because the variables B and U in the first goal of your recursive rule are unbound. You don't have anything before that goal that could fail. So it is always possible to follow the recursion. In the version of CapelliC you have 2 goals in the second rule before the recursion that fail if the second argument is smaller than 1. Maybe it becomes clearer if you consider this slightly altered version:
:- use_module(library(clpfd)).
count([], 0).
count([_|B], T) :-
T #> 0,
U #= T - 1,
count(B, U).
Your query
?- count(X,3).
will not match the first rule but the second one and continue recursively until the second argument is 0. At that point the first rule will match and yield the result:
X = [_A,_B,_C] ?
The head of the second rule will also match but its first goal will fail because T=0:
X = [_A,_B,_C] ? ;
no
In your above version however Prolog will try the recursive goal of the second rule because of the unbound variables B and U and hence loop infinitely.
I'm trying to write a simple procedure that checks if a list has any duplicates. This is what I have tried so far:
% returns true if the list has no duplicate items.
no_duplicates([X|XS]) :- member(X,XS) -> false ; no_duplicates(XS).
no_duplicates([]) :- true.
If I try no_duplicates([1,2,3,3]). It says true. Why is this? I'm probably misunderstanding Prolog here, but any help is appreciated.
To answer your questions: your solution actually fails as expected for no_duplicates([1,2,3,3]). So there is no problem.
Now take the queries:
?- A = 1, no_duplicates([A, 2]).
A = 1.
?- no_duplicates([A, 2]), A = 1.
They both mean the same, so we should expect that Prolog will produce the same answer. (To be more precise we expect the same ignoring errors and non-termination).
However, four proposed solutions differ! And the one that does not, differs for:
?- A = 2, no_duplicates([A, 2]).
false.
?- no_duplicates([A, 2]), A = 2.
Note that it is always the second query that makes troubles. To solve this problem we need a good answer for no_duplicates([A, 2]). It cannot be false, since there are some values for A to make it true. Like A = 1. Nor can it be true, since some values do not fit, like A = 2.
Another possibility would be to issue an instantiation_error in this case. Meaning: I have not enough information so I better stop than mess around with potentially incorrect information.
Ideally, we get one answer that covers all possible solutions. This answer is dif(A, 2) which means that all A that are different to 2 are solutions.
dif/2 is one of the oldest built-in predicates, already Prolog 0 did possess it. Unfortunately, later developments discarded it in Prolog I and thus Edinburgh Prolog and thus ISO Prolog.
However, current systems including SICStus, YAP, SWI all offer it. And there is a safe way to approximate dif/2 safely in ISO-Prolog
no_duplicates(Xs) :-
all_different(Xs). % the common name
all_different([]).
all_different([X|Xs]) :-
maplist(dif(X),Xs).
all_different(Xs).
See: prolog-dif
Here's yet another approach, which works because sort/2 removes duplicates:
no_duplicates(L) :-
length(L, N),
sort(L, LS),
length(LS, N).
I'd go at the problem more descriptively:
no_duplicates( [] ) . % the empty list is unique
no_duplicates( [X|Xs] ) :- % a list of length 1+ is unique
\+ member(X,Xs) , % - if its head is not found in the tail,
no_duplicates(Xs) % - and its tail is itself unique.
. %
Thinking on this, since this is a somewhat expensive operation — O(n2)? — it might be more efficient to use sort/2 and take advantage of the fact that it produces an ordered set, removing duplicates. You could say something like
no_duplicates( L ) :-
sort(L,R) , % sort the source list, removing duplicates
length(L,N) , % determine the length of the source list
length(R,N) . % check that against the result list
Or you could use msort/3 (which doesn't remove duplicates), might be a bit faster, too:
no_duplicates( L ) :-
msort(L,R), % order the list
\+ append(_,[X,X|_],R) % see if we can find two consecutive identical members
.
Duplicates in a list are same elements not at the same place in the list, so no_duplicates can be written :
no_duplicates(L) :-
\+((nth0(Id1, L, V), nth0(Id2, L, V), Id1 \= Id2)).
Jay already noted that your code is working. An alternative, slightly less verbose
no_duplicates(L) :- \+ (append(_, [X|XS], L), memberchk(X, XS)).
i just can't get my head around this problem i'm having with prolog. Only just started, but i can't seem to find a way to find out if an object is unique. Heres my code:
/* (Student Name, Student Number)*/
Student(stuart, 11234).
Student(ross, 11235).
Student(rose, 11236).
Student(stuart, 11237).
how can i find out if a student is unique. Take for example Stuart, there's two students named Stuart, so Stuart is not unique. How could i write a procedure to tell if its another Student called Stuart.
I've tried spending so many hours on this, but i can't seem to get my head around dealing with the original Stuart rather than the other Stuart because i can't exclude the one i'm trying to find out if its unique.
Thanks for the help.
With your database example this could do
unique(S) :-
student(S, N), \+ (student(S, M), M \= N).
as it yields
?- unique(S).
S = ross ;
S = rose ;
false.
Generally, Prolog is targeted toward existence of solutions. Then predication about cardinality need some support from the 'impure' part of the language: nb_setarg it's currently our best friend when we need to efficiently tracking cardinality.
Using a metapredicate like this:
%% count_solutions(+Goal, ?C)
%
% adapted from call_nth/2 for http://stackoverflow.com/a/14280226/874024
%
count_solutions(Goal, C) :-
State = count(0, _), % note the extra argument which remains a variable
( Goal,
arg(1, State, C1),
C2 is C1 + 1,
nb_setarg(1, State, C2),
fail
; arg(1, State, C)
).
:- meta_predicate count_solutions(0, ?).
you could solve the problem without considering the second argument
unique(S) :-
student(S, _), count_solutions(student(S, _), 1).
The same predicate could use aggregate_all(count, student(S,_), 1) from library(aggregate), but such library currently builds a list internally, then you could consider the answer from Peter as easier to implement.
There are probably quite a few ways to solve this problem but I would do it this way:
% a student has a name and a number
student(stuart, 11234).
student(ross, 11235).
student(rose, 11236).
student(stuart, 11237).
This code says "find a list the same length as the number of students with Name" and then "make Count the same as the length of the list":
% for every student name there is an associated count of how many times
% that name appears
number_students(Name, Count) :-
findall(_, student(Name, _), Students),
length(Students, Count).
This predicate will only be true if the number_students is 1:
% a student name is unique (appears once and only once) is the
% number_students count is 1
unique_student(Name) :-
number_students(Name, 1).
Testing:
12 ?- unique_student(ross).
true.
13 ?- unique_student(rose).
true.
14 ?- unique_student(bob).
false.
15 ?- unique_student(stuart).
false.
This is an easy way to solve the problem, but it isn't a great Prolog solution because you cannot say things like "give me a unique student name" and get a list of all the unique names.
Some comments on the code you have. This is not a fact:
Student(Ross).
These are two different facts (in SWI-Prolog, at least):
student(ross).
student('Ross').
In other words, predicate names must start with small letters, and identifiers starting with a capital letters denote variables, not atoms. You can put any character string in single quotes to make it a valid atom.
Now this out of the way, it is not clear what you are aiming at. What are you going to do with your unique student? How do you know the first one is the one you are looking for, and not the second? And why not use the student number for that (at least in your example the two Stuarts seem to have different numbers)?
I'm new to Prolog and I'm stuck on a predicate that I'm trying to do. The aim of it is to recurse through a list of quads [X,Y,S,P] with a given P, when the quad has the same P it stores it in a temporary list. When it comes across a new P, it looks to see if the temporary list is greater than length 2, if it is then stores the temporary list in the output list, if less than 2 deletes the quad, and then starts the recursion again the new P.
Heres my code:
deleteUP(_,[],[],[]).
deleteUP(P,[[X,Y,S,P]|Rest],Temp,Output):-
!,
appends([X,Y,S,P],Temp,Temp),
deleteUP(P,[Rest],Temp,Output).
deleteUP(NextP,[[X,Y,S,P]|Rest],Temp,Output):-
NextP =\= P,
listlen(Temp,Z),
Z > 1, !,
appends(Temp,Output,Output),
deleteUP(NextP,[_|Rest],Temp,Output).
listlen([], 0).
listlen([_|T],N) :-
listlen(T,N1),
N is N1 + 1.
appends([],L,L).
appends([H|T],L,[H|Result]):-
appends(T,L,Result).
Thanks for any help!
Your problem description talks about storing, recursing and starting. That is a very imperative, procedural description. Try to focus first on what the relation should describe. Actually, I still have not understood what minimal length of 2 is about.
Consider to use the predefined append/3 and length/2 in place of your own definitions. But actually, both are not needed in your example.
You might want to use a dedicated structure q(X,Y,S,P) in place of the list [X,Y,S,P].
The goal appends([X,Y,S,P],Temp,Temp) shows that you assume that the logical variable Temp can be used like a variable in an imperative language. But this is not the case. By default SWI creates here a very odd structure called an "infinite tree". Forget this for the moment.
?- append([X,Y,S,P],Temp,Temp).
Temp = [X, Y, S, P|Temp].
There is a safe way in SWI to avoid such cases and to detect (some of) such errors automatically. Switch on the occurs check!
?- set_prolog_flag(occurs_check,error).
true.
?- append([X,Y,S,P],Temp,Temp).
sto. % ERROR: lists:append/3: Cannot unify _G392 with [_G395,_G398,_G401,_G404|_G392]: would create an infinite tree
The goal =\=/2 means arithmetical inequality, you might prefer dif/2 instead.
Avoid the ! - it is not needed in this case.
length(L, N), N > 1 is often better expressed as L = [_,_|_].
The major problem, however, is what the third and fourth argument should be. You really need to clarify that first.
Prolog variables can't be 'modified', as you are attempting calling appends: you need a fresh variables to place results. Note this code is untested...
deleteUP(_,[],[],[]).
deleteUP(P,[[X,Y,S,P]|Rest],Temp,Output):-
!,
appends([X,Y,S,P],Temp,Temp1),
deleteUP(P, Rest, Temp1,Output). % was deleteUP(P,[Rest],Temp,Output).
deleteUP(NextP,[[X,Y,S,P]|Rest],Temp,Output1):-
% NextP =\= P, should be useless given the test in clause above
listlen(Temp,Z),
Z > 1, !, % else ?
deleteUP(NextP,[_|Rest],Temp,Output),
appends(Temp,Output,Output1).