prolog compare SOS - prolog

let say i had this two facts.
animal(fifi,10).
animal(fofo,20).
If i call
animal(X,Y).
then Prolog will return me
X = fifi,
Y = 10 ;
X = fofo,
Y = 20.
What I need to do, to let to Prolog only return me the animal X with the highest value of Y according to the fact?
Is there any possible way that it will just display X only for the highest value of Y instead of displaying X and Y together?

Alternatively :
max_animal(MaxAnimal) :-
findall(Y, animal(X, Y), Ys),
max_list(Ys, Max),
animal(MaxAnimal, Max).

Sure, you can build a list of all the animals and their values, then sort the list and take the element you want from it:
max_animal(MaxAnimal):-
findall(Value-Animal, animal(Animal, Value), L),
keysort(L, Sorted),
reverse(Sorted, [_-MaxAnimal|_]).

Related

Prolog - partially ordered set

There is a partially ordered set relation le(X,Y), when Y mod X = 0
(so there are le(1,5), le(5,70), le(7,14) etc.)
I have to make predicates
max(X) is X maximum element
greatest(X) is X the greatest element
defining max(X) is simple, because
max(X) :- \+ le(X,A), le(B,X). (there isn't any greater element and X is in set)
But how about greatest(X)?
For the least upper bound (LUB), you need two sets. First the argument set S, that you are asking for the LUB, and then the partial order T where you are searching for the LUB. So input is as follows:
T the partial order
S the set, S subset T
The code is then very similar as for the max. Just use range restricted formulas, that search over the partial order. This works in ordinary Prolog for finite partial orders.
Here is your divisibility example:
?- [user].
ls(X,Y) :-
Y mod X =:= 0.
bound(M,Y) :-
\+ (member(X,M),
\+ls(X,Y)).
lub(S,T,Y) :-
member(Y,T), bound(S,Y),
\+ (member(Z,T), bound(S,Z),
\+ls(Y,Z)).
^D
And here are some example runs:
?- lub([3,2],[1,2,3,4,5,6,7,8,9,10],Y).
Y = 6 ;
false.
?- lub([5,3],[1,2,3,4,5,6,7,8,9,10],Y).
false.
?- lub([5,3],[1,2,3,4,5,6,7,8,9,10,11,12,14,15,16,17,18,19,20],Y).
Y = 15 ;
false.
The above very general algorithm is not the efficientest, it is of order m^2*n^2, where n is the size of S and m is the size of T. For infinite partial orders you would need to invent something with CLP(X).

How does the recursing work in prolog for adding number

My aim is to take the numbers between X and Y and produce Z.
num_between(3,6, All)
For example, if X is 3 and Y is 6 then Z is a list of the numbers between X and Y inclusive. Something like num_between(3,6,[3,4,5,6]) should evaluate as true. Here's what I have so far:
num_between(0,0, []).
num_between(X,Y, All) :-
increase(X, New) , % increase number X++
\+(X = Y) , % check if X is not equal to Y
num_between(New,Y,[All|X]) . % requestion ???
increase(F,N) :- N is F+1 .
increase/1 is working and returns number that is required, but
when recursion is gone through num_between/3 it goes unlit: X is 6 then it fails as I want,
but I can not manage to keep numbers or to return them. All = [3,4,5,6].
All = All + F. Could anyone help please.
Your base clause is incorrect: since you never decrease X or Y, they would never get to zero (unless Y starts at zero, and X starts at a non-positive value). The base clause should look like this:
num_between(X, Y, []) :- X > Y.
This ensures that you get an empty result when the user enters an invalid "backward" range (say, from 6 to 3).
Now to the main clause: all you need to do is to check that the range is valid, get the next value, and make a recursive call, like this:
num_between(X, Y, [X|Tail]) :-
X =< Y,
Next is X + 1,
num_between(Next, Y, Tail).
Demo.
Your original code made an error when constructing a list - it tried to use X as the "tail" of the list, which is incorrect:
num_between(New,Y,[All|X]).
you pass on All, the result after an "expansion", down through the recursive chain of invocation. It should be the other way around - you need to pass in a Tail to collect the result, and then pre-pend X to it when the recursive invocation is over.
You have to change both your base case and your recursive clause:
num_between(X, X, [X]).
num_between(X, Y, [X|L]):-
X < Y,
increase(X, New),
num_between(New, Y, L).
First clause is the base case, it states that the number ranging from X and X is just [X].
The recursive clause states that a number X which is less than a number Y should have it in the output list (thus the [X|L] in the third argument of the head), then it increases the value (i'm just using your helper procedure for that) and recursively calling itself now with the New value for the first argument.
I would write this along these lines:
numbers_between( X , X , [X] ) . % if X and Y have converged, we have the empty list
numbers_between( X , Y , [X|Zs] ) :- % otherwise, add X to the result list
X < Y , % - assuming X is less than Y
X1 is X+1 , % - increment X
numbers_between(X1,Y,Zs) % - recurse down
. %
numbers_between( X , Y , [X|Zs] ) :- % otherwise, add X to the result list
X > Y , % - assuming X > Y
X1 is X-1 , % - decrement X
numbers_between(X1,Y,Zs) % - recurse down
. %

How can I get this simple Prolog predicate to "return" the right way?

So I am learning Prolog. I need to write a predicate that finds the min/max value of an integer list. For example, the query minmaxArray([4,-1,5,4,1,2,3,-2],X,Y) would return X = -2 Y = 5. Here is what I have so far:
%min/max element of a 1 item list is that item.
minmaxArray([X], X, X).
%when there is only 2 items, put the smaller element in A and the
%larger element in B
minmaxArray([X,Y], A, B) :- mymin(X,Y,Min),
A is Min, mymax(X,Y,Max), B is Max.
%when there is more than two items make a recursive call to find the min/max
%of the rest of the list.
minmaxArray([X,Y|T], A, B) :- minmaxArray([Y|T], M, K),
mymin(X,M,Temp), A is Temp, mymax(X,K,Temp2), B is Temp2.
Assume mymin and mymax predicates work properly. They return the min and max of 2 numbers.
The issue here is that for example when I query minmaxArray([4,-1,5],X,Y) it returns X = -1 Y = 5 and then again X = -1 Y = 5. I know this must be because it hits the 2nd condition on the recursive call. I only want it to return X = -1 Y = 5 one time. I tried replacing condition 3 with this:
minmaxArray([X,Y,_|T], A, B) :- minmaxArray([Y,_|T], M, K),
mymin(X,M,Temp), A is Temp, mymax(X,K,Temp2), B is Temp2.
but that crashes the program. What can I do to fix this?
Note: I know that I may not be using the terminology correctly by saying returning and saying predicate when it should be rule, etc so I apologize in advance.
Seems that your code could be simpler. This predicate does all what's needed, and attempt to show how to use some standard construct (if/then/else)
minmaxArray([X], X, X).
minmaxArray([X|R], Min, Max) :-
minmaxArray(R, Tmin, Tmax),
( X < Tmin -> Min = X ; Min = Tmin ), % or mymin(X,Tmin,Min)
( X > Tmax -> Max = X ; Max = Tmax ).
You have provided 2 ways of solving the case where there are 2 items: one explicitly for 2 items, and your general case, which then employs the 1 element case.
Solution: remove the unneeded 2-element case.
Or, tail-recursive:
minmax([X|Xs],Min,Max) :- % we can only find the min/max of a non-empty list.
minmax(Xs,(X,X),Min,Max) % invoke the helper with the min/max accumulators seeded with the first item
.
minmax([],(Min,Max),Min,Max). % when the source list is exhausted, we're done: unify the accumulators with the result
minmax([X|Xs],(M,N),Min,Max) :- % when the source list is non-empty
min(X,M,M1) , % - get a new min value for the accumulator
max(X,N,N1) , % - get a new max value for the accumulator
minmax(Xs,(M1,N1),Min,Max) % - recurse down on the tail.
.
min(X,Y,X) :- X =< Y . % X is the min if it's less than or equal to Y.
min(X,Y,Y) :- X > Y . % Y is the min if it's greater than X.
max(X,Y,X) :- X >= Y . % X is the max if it's greater than or equal to Y.
max(X,Y,Y) :- X < Y . % Y is the max if it's greater than X.

Prolog Bubblesort

I'm trying to best understand everything about this code. This is how I currently perceive what's happening:
So I can see if X > Y we swap the elements, if not we recurse down the sublist until we find an X that X > Y, if we do not, then the list is sorted.
Problems I'm having is I don't really understand the base case, bubblesort(Sorted, Sorted). I thought you would need a base case for an empty list? I would really appreciate if someone could describe a sort of step by step description of this program.
bubblesort(List,Sorted) :-
swap(List,List1),
!,
bubblesort(List1,Sorted).
bubblesort(Sorted,Sorted).
swap([X,Y|Rest],[Y,X|Rest]) :- % swaps X with Y if gt(X,Y) is true.
gt(X,Y).
swap([Z|Rest],[Z|Rest1]) :- % calls swap on sublists excluding the heads.
swap(Rest,Rest1).
gt(X,Y) :- % true if X is greater than Y.
X > Y.

prolog function returning memory locations instead of values

just started programming with prolog and I'm having a few issues. The function I have is supposed to take a value X and copy it N number of times into M. My function returns a list of N number of memory locations. Here's the code, any ideas?
duple(N,_,M):- length(M,Q), N is Q.
duple(N,X,M):- append(X,M,Q), duple(N,X,Q).
Those are not memory adresses. Those are free variables. What you see is their internal names in your prolog system of choice. Then, as #chac pointed out (+1 btw), the third clause is not really making sense! Maybe you can try to tell us what you meant so that we can bring light about how to do it correctly.
I'm going to give you two implementations of your predicate to try to show you correct Prolog syntax:
duple1(N, X, L) :-
length(L, N),
maplist(=(X), L).
Here, in your duple1/3 predicate, we tell prolog that the length of the resulting list L is N, and then we tell it that each element of L should be unified with X for the predicate to hold.
Another to do that would be to build the resulting list "manually" through recursion:
duple2(0, _X, []).
duple2(N, X, [X|L]) :-
N > 0,
NewN is N - 1,
duple1(NewN, X, L).
Though, note that because we use >/2, is and -/2, ie arithmetic, we prevent prolog from using this predicate in several ways, such as:
?- duple1(X, Y, [xyz, xyz]).
X = 2,
Y = xyz.
This worked before, in our first predicate!
Hope this was of some help.
I suppose you call your predicate, for instance, in this way:
?- duple(3,xyz,L).
and you get
L = [_G289, _G292, _G295] ;
ERROR: Out of global stack
If you try
?- length(X,Y).
X = [],
Y = 0 ;
X = [_G299],
Y = 1 ;
X = [_G299, _G302],
Y = 2 ;
X = [_G299, _G302, _G305],
Y = 3 ;
X = [_G299, _G302, _G305, _G308],
Y = 4 .
...
you can see what's happening:
your query will match the specified *M*, displaying a list of M uninstantiated variables (memory locations), then continue backtracking and generating evee longer lists 'til there is stack space. Your second rule will never fire (and I don't really understand its purpose).
A generator is easier to write in this way:
duple(N,X,M) :- findall(X,between(1,N,_),M).
test:
?- duple(3,xyz,L).
L = [xyz, xyz, xyz].

Resources