How can i tell if an object is unique - prolog

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)?

Related

Merging two ordered lists ProLog

Hey so this is my code so far. I am only a begginer in prolog but i need it for school
firstElement([_|_], [Elem1|List1], [Elem2|List2]):-
Elem1 =< Elem2, merge([Elem1] , List1, [Elem2|List2]);
merge([], [Elem2], List2).
merge([Head|Tail], [Elem1|List1], [Elem2|List2]):-
Elem1 =< Elem2,!, add(Elem1,[Head|Tail],[Head|Tail1]),
merge([Head|Tail1], List1, [Elem2|List2]);
add(Elem2,[Head|Tail],[Head|Tail1]),
merge([Head|Tail1], [Elem1|List1], List2).
merge([Head|Tail], [], [Elem2|List2]):-
add(Elem2,[Head|Tail],[Head|Tail1]).
merge([Head|Tail], [Elem1|List1], []):-
add(Elem1,[Head|Tail],[Head|Tail1]).
merge([Head|Tail], [], []).
add(X,[],[X]).
add(X,[Y|Tail],[Y|Tail1]):-
add(X,Tail,Tail1).
I found out that everytime it gets out of a merge it keeps forgetting the last number so it gets back to nothing in the end.
I think you’ve gotten very mixed up here with your code. A complete solution can be had without helpers and with only a few clauses.
First let us discuss the two base cases involving empty lists:
merge(X, [], X).
merge([], X, X).
You don’t quite have these, but I see some sort of recognition that you need to handle empty lists specially in your second and third clauses, but I think you got confused and overcomplicated them. There’s really three scenarios covered by these two clauses. The case where both lists are empty is a freebie covered by both of them, but since that case would work out to merge([], [], []), it’s covered. The big idea here is that if you exhaust either list, because they were sorted, what you have left in the other list is your result. Think about it.
This leaves the interesting case, which is one where we have some items in both lists. Essentially what you want to do is select the smaller of the two, and then recur on the entire other list and the remainder of the one you selected the smaller value from. This is one clause for that:
merge([L|Ls], [R|Rs], [L|Merged]) :-
L #< R,
merge(Ls, [R|Rs], Merged).
Here’s what you should note:
The “result” has L prepended to the recursively constructed remainder.
The recursive call to merge rebuilds the entire second list, using [R|Rs].
It should be possible to build the other clause by looking at this.
As an intermediate Prolog user, I would be naturally a bit suspicious of using two clauses to do this work, because it’s going to create unnecessary choice points. As a beginner, you will be tempted to erase those choice points using cuts, which will go badly for you. A more intermediate approach would be to subsume both of the necessary clauses into one using a conditional operator:
merge([L|Ls], [R|Rs], [N|Ns]) :-
( L #< R ->
N = L, merge(Ls, [R|Rs], Ns)
; —- other case goes here
).
An expert would probably build it using if_/3 instead:
#<(X,Y,true) :- X #< Y.
#<(X,Y,false) :- X #>= Y.
merge([L|Ls], [R|Rs], [N|Ns]) :-
if_(#<(L,R),
(N = L, merge(Ls, [R|Rs], Ns)),
( -- other case here )).
Anyway, I hope this helps illustrate the situation.

find sister relation from family tree using prolog

I have facts: male, female and child.
eg.
/* tg and yem are mother and father. rika,kiku and susu are children*/
female(rika).
female(tg).
male(kiku).
male(susu).
male(yem).
child(rika,tg).
child(kiku,tg).
child(susu,tg).
child(rika,yem).
child(kiku,yem).
child(susu,yem).
Now I need a query to extract sister relation like
sister(Sister1,Sister2):-
female(Sister1),
child(Sister1,X),child(Sister2,X),
Sister1 \= Sister2.
But it results duplicate responses. How can I improved to get single answers?
Since your predicate always terminates, you can use the predicate setof/3 to remove duplicate solutions:
?- setof(X-Y, sister(X,Y), Xs).
Xs = [rika-kiku, rika-susu].
The first argument defines a term template representing one solution, the second defines the goal of which you want to collect the answer substitutions and the third argument is the list of instantiated template terms.
You will still have redundancy if a parent has two daughters, which become sisters. E.g. if you add the facts
female(ala).
child(ala,tg).
child(ala,yem).
to your knowledgebase, then the query contains all sisters twice.
?- setof(X-Y, sister(X,Y), Xs).
Xs = [ala-kiku, ala-rika, ala-susu, rika-ala, rika-kiku, rika-susu].
One reason is that you defined your predicate sister with two arguments : sister is a relation between Sister1 and her sibling. (The way you wrote it, the variable name Sister2 gives the wrong intuition that the sibling is also female, but that's just a side note). If we only want to know who is a sister, this is a set (or one-place predicate) - let's call it is_sister/1:
is_sister(Xs) :-
setof(X, Y^sister(X,Y), Xs).
If you look at the answer substitutions, the queries setof(X, sister(X,Y), Xs). and setof(X, Y^sister(X,Y), Xs). differ a lot. The reason is that Y is free in the first template and you will receive a set depending on the possible substitutions of Y. In the second example, the Y^ binds the variable - we obtain all instantiations of X in one set, independent of the binding of Y.

Prolog no_duplicate function

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)).

Compare results return from a query

When I run a query, it can return zero, one or more than one results. How can I "save" these results so that I can compare them later, or how can I compare them on the fly?
For example, I have these facts:
father(john, mark).
father(john, michael).
age(michael, 10).
age(mark, 12).
Now if I run a query like this
?- father(john, X).
it will return mark and michael, but how can I compare the age of mark and michael? In fact, how can I even know that the query will return more than one results?
The idea is that I want to get the eldest son of a father
What you're running into here is the fact that on backtracking, Prolog releases the variable bindings it found when it produced the previous result. This feature causes a lot of consternation in the early days, so know that you're not alone, we were all there once.
The first thing you should do is try to let go of the need to tell Prolog how to get the result, and instead focus on telling Prolog how to distinguish the result you want logically. This is logic programming, after all. :) When you say "how can I compare the age of mark and michael?" you're hiding the real question behind the assumption that once you know how to hold onto things you can find the answer yourself. But you don't want to find the answer yourself, you want Prolog to find it!
Let's take an example. Say you want to find out who is the youngest child of whom. You can do this logically:
?- father(Father, Child),
age(Child, YoungestAge),
\+ (father(Father, Child2),
age(Child2, Younger),
Younger < YoungestAge).
Father = john,
Child = michael,
YoungestAge = 10.
This would be inefficient with a large database, unfortunately, since Prolog will have to search every age/2 fact to find all the children of a particular parent. Presumably Prolog will index these predicates and that may be enough to save us depending on how you use it, but it doesn't look like a strategy you can apply universally. But you can't beat the logical reading of this query: supposing I have a father Father of child Child, and supposing that Child's age is YoungestAge, there is no Child2 of this same Father whose age is Younger than YoungestAge.
Frequently, you do need all the solutions, and for that there are three predicates: setof/3, bagof/3 and findall/3. They all have basically the same API with slightly different semantics. For instance, if you want all the children for a parent, you can use setof to get them:
?- setof(Child, father(john, Child), Children).
Children = [mark, michael].
You'll need a bigger fact database to see the effect of the differences between the two, but that's a different question. In short, setof/3 will get you a sorted list of unique answers whereas bagof/3 will get you an unsorted list with all the answers. findall/3 does the same thing, with a difference in the way it treats variables. In my experience, setof/3 and findall/3 tend to be used a lot more than bagof/3.
If the work you're doing necessitates it, or if efficiency demands it, you can use these meta-predicates to find all the possible solutions and walk through the list doing whatever processing you need to do.
As for the question "how can I even know that the query will return more than one result?" the answer is basically you can generate them all and see how many you had (findall(..., Answers), length(Answers, Count)) or you can use once/1 to ensure that you get a single solution. once is great for making non-deterministic predicates deterministic; the effect is basically the same as putting a cut right after the clause. For instance:
?- father(john, X).
X = mark ;
X = michael.
?- once(father(john, X)).
X = mark.
?- father(john, X), !.
X = mark.
In general it is recommended that you use once/1 over explicit cuts, if possible.
Let me know if this helps.
just a footnote on Daniel answer:
eldest(Father, Child) :-
findall(A/C, (father(Father, C), age(C, T), A is -T), L),
sort(L, [_/Child|_]).
I used the trick of negating the age to get the list in reverse order.
Here a 'one liner', does just the same as above:
eldest(Father, Child) :-
setof(A/C, T^(father(Father, C), age(C, T), A is -T), [_/Child|_]).
edit if your Prolog has library(aggregate), there is a cleaner way to get the result:
eldest(Father, Child) :-
aggregate(max(A, C), (father(Father, C), age(C, A)), max(_, Child)).

Max out of values defined by prolog clauses

I know how to iterate over lists in Prolog to find the maximum, but what if each thing is a separate clause? For example if I had a bunch of felines and their ages, how would I find the oldest kitty?
cat(sassy, 5).
cat(misty, 3).
cat(princess, 2).
My first thought was "hmm, the oldest cat is the one for which no older exists". But I couldn't really translate that well to prolog.
oldest(X) :- cat(X, AgeX), cat(Y, AgeY), X \= Y, \+ AgeX < AgeY, print(Y).
This still errorenously matches "misty". What's the proper way to do this? Is there some way to more directly just iterate over the ages to choose max?
One way is
oldest(X) :- cat(X, AgeX), \+ Y^(cat(Y, AgeY), Y \= X, AgeX < AgeY).
You can also use setof/3 to get a list of all cats and get the maximum from that.
A cat is the oldest if it's a cat and there is not a cat older than it. Let's write that in Prolog:
oldest(X):- cat(X, _), not( thereAreOlders(X)), !.
thereAreOlders(X):- cat(X, N), cat(C, M), C\=X, M > N.
If you consult:
?- oldest(X).
X = sassy.
Here is a solution that loops through all the solutions, always recording the solution that is better than the previous best. In the end, the best solution is returned.
The recording is done using assert/1, you could also use a non-backtrackable global variable if your Prolog provides that (SWI-Prolog does).
The benefit of this approach is that is considers each solution only once, i.e. complexity O(n). So, even though it looks uglier than starblue's solution, it should run better.
% Data
cat(sassy, 5).
cat(misty, 3).
cat(miisu, 10).
cat(princess, 2).
% Interface
oldest_cat(Name) :-
loop_through_cats,
fetch_oldest_cat(Name).
loop_through_cats :-
cat(Name, Age),
record_cat_age(Name, Age),
fail ; true.
:- dynamic current_oldest_cat/2.
record_cat_age(Name, Age) :-
current_oldest_cat(_, CAge),
!,
Age > CAge,
retract(current_oldest_cat(_, _)),
assert(current_oldest_cat(Name, Age)).
record_cat_age(Name, Age) :-
assert(current_oldest_cat(Name, Age)).
fetch_oldest_cat(Name) :-
retract(current_oldest_cat(Name, _Age)).
Usage example:
?- oldest_cat(Name).
Name = miisu
Miisu is a typical Estonian cat name. ;)
On a stylistic point- there are a few different approaches here (some are very elegant, others more 'readable'). If you're a beginner- chose your own, preferred, way of doing things- however inefficient.
You can learn techniques for efficiency later. Enjoy Prolog- its a beautiful language.
I don't remember much Prolog, but I do know that you shouldn't think about solving problems as you would with an imperative programming language.

Resources