find maximum in a list in Prolog [duplicate] - list

Is it possible to create a predicate max/2 without an accumulator so that max(List, Max) is true if and only if Max is the maximum value of List (a list of integers)?

Yes, you can calculate the maximum after the recursive step. Like:
max([M],M). % the maximum of a list with one element is that element.
max([H|T],M) :-
max(T,M1), % first calculate the maximum of the tail.
M is max(H,M1). % then calculate the real maximum as the max of
% head an the maximum of the tail.
This predicate will work on floating points for instance. Nevertheless it is better to use an accumulator since most Prolog interpreters use tail call optimization (TCO) and predicates with accumulators tend to work with tail calls. As a result predicates with TCO will usually not get a stack overflow exception if you want to process huge lists.
As #Lurker says, is only works in case that the list is fully grounded: it is a finite list and all elements grounded. You can however use Prolog's constraint logic programming package clp(fd):
:- use_module(library(clpfd)).
max([M],M). % the maximum of a list with one element is that element.
max([H|T],M) :-
max(T,M1), % first calculate the maximum of the tail.
M #= max(H,M1). % then calculate the real maximum as the max of
% head an the maximum of the tail.
You can then for instance call:
?- max([A,B,C],M),A=2,B=3,C=1.
A = 2,
B = M, M = 3,
C = 1 ;
false.
So after the max/2 call, by grounding A, B and C, we obtain M=3.

Neither the standard predicate is/2 nor a CLP(FD) predicate (#=)/2 can do mathematics here. So that in the end, for certain applications such as exact geometry, they might not be suitable.
To make a point lets consider an example and the alternative of a computer algebra system (CAS). I am doing the demonstration with the new Jekejeke Minlog 0.9.2 prototype which provides CAS from within Prolog.
As a preliminary we have two predicates eval_keys/2 and min_key/2, their code is found at the appendix in this post. Lets illustrate what this predicates do, first with integer. The first predicate just makes the keys of a pair list evaluated:
Welcome to SWI-Prolog (Multi-threaded, 64 bits, Version 7.3.25-3-gc3a87c2)
Copyright (c) 1990-2016 University of Amsterdam, VU Amsterdam
?- eval_keys([(1+3)-foo,2-bar],L).
L = [4-foo,2-bar]
The second predicate picks this first value where the key is minimum:
?- min_key([4-foo,2-bar],X).
X = bar
Now lets look at other key values, we will use square roots, which belong to the domain of algebraic numbers. Algebraic numbers are irrational and thus never fit into a float. We therefore get for the new example the outcome foo:
?- eval_keys([(sqrt(98428513)+sqrt(101596577))-foo,sqrt(400025090)-bar],L).
L = [20000.62724016424-foo, 20000.627240164245-bar].
?- min_key([20000.62724016424-foo, 20000.627240164245-bar], X).
X = foo.
CLP(FD) has only integers and there is no direct way to represent algebraic numbers. On the other hand many CAS systems support radicals. Our Prototype even supports comparison of them so that we can obtain the exact result bar:
Jekejeke Prolog 2, Runtime Library 1.2.2
(c) 1985-2017, XLOG Technologies GmbH, Switzerland
?- eval_keys([(sqrt(98428513)+sqrt(101596577))-foo,sqrt(400025090)-bar],L).
L = [radical(0,[98428513-1,101596577-1])-foo,
radical(0,[400025090-1])-bar]
?- min_key([radical(0,[98428513-1,101596577-1])-foo,
radical(0,[400025090-1])-bar],X).
X = bar
That bar is the exact result can be seen for example by using a multi-precision calculator. If we double the precision we indeed see that the last square root is the smaler one and not the sum of the square roots:
?- use_module(library(decimal/multi)).
% 7 consults and 0 unloads in 319 ms.
Yes
?- X is mp(sqrt(98428513)+sqrt(101596577), 32).
X = 0d20000.627240164244658958331341095
?- X is mp(sqrt(400025090), 32).
X = 0d20000.627240164244408966171597261
But a CAS need not to proceed this way. For example our Prolog implementation uses a Swinnerton-Dyer polynomial inspired method to compare radical expressions, which works purely symbolic.
Appendix Test Code:
% :- use_module(library(groebner/generic)). /* to enable CAS */
eval_keys([X-A|L], [Y-A|R]) :- Y is X, eval_keys(L, R).
eval_keys([], []).
min_key([X-A|L], B) :- min_key(L, X, A, B).
min_key([X-A|L], Y, _, B) :- X < Y, !, min_key(L, X, A, B).
min_key([_|L], X, A, B) :- min_key(L, X, A, B).
min_key([], _, A, A).

Related

Prolog finding a integer complement in a list

Given a sorted, no duplicates list L I would like to find out if it has at least one pair of complementary integers (i.e. <-1,1>, <-2,2>, etc.)
I am puzzled how to structure this one functionally in prolog. Essentially what I want to do is iterate through each negative number one by one and check if its complement (positive number digit) exists in the list. Normally this would be a double loop in other languages but how could I do this in Prolog?
Here's what I have so far but I am curious if there is a more elegant solution without using a control statement...
findint(X,[X|_]).
findint(X,[_|Tail]) :- findint(X,Tail).
findpair([X|Tail]) :- X < 0, Y is -1*X, (findint(Y,Tail) -> true ; findpair(Tail)).
a 'trick of the trade': use member/2 instead of iteration
complement_integers(L, I1,I2) :-
member(I1,L),
member(I2,L),
I1 =:= -I2.

Prolog: Finding the maximum absolute difference of two adjacent list elements

listelements([i|o],listelements) :-
u is abs((listmax)-(listmin)),
listelements(u,listelements).
listmin([min],min).
listmin([x|y],z) :-
listmin(y,h),
min(x,h,z).
min(Q,W,Q) :-
Q =< W.
min(Q,W,W) :-
W < Q.
listmax([max],max).
listmax([a|b],c) :-
listmax(b,f),
max(a,f,c).
max(M,N,M) :-
M =< N.
max(M,N,N) :-
N < M.
Arithmetic: `listmax' is not a function
This is the error. Help please!
When I ask ?- listmin([1,2,3,4,5,6],z).
it answers false instead of 1. Why?
Considering your concrete choice of arithmetic predicates,
I guess you want to support all kinds of Prolog numbers (floating point numbers, integers, and rational numbers).
If you only work with integer numbers here then make sure you are using clpfd!
In this answer we proceed step-by-step, like this:
We define an auxiliary predicate num_num_absdiff/3 which computes the absolute difference of its first two arguments.
num_num_absdiff(X,Y,D) :-
D is abs(X-Y).
To apply num_num_absdiff/3 to all adjacent items and gather the results, we use mapadj/3:
?- mapadj(num_num_absdiff,[1,2,4,8,16,100],Ds).
Ds = [1, 2, 4, 8, 84].
The maximum absolute difference is the maximum number in above list.
We employ list_maxnum/2 to get said number.
?- list_maxnum([1,2,4,8,84], Max).
Max = 84.
Let's put it all together and define maxabsdiff_of/2:
maxabsdiff_of(D,Nums) :-
mapadj(num_num_absdiff,Nums,Ds),
list_maxnum(Ds,D).
Here are some sample queries:
?- maxabsdiff_of(D,[1,2,3,4,5,6]). % as given by the OP
D = 1.
?- maxabsdiff_of(D,[1,2,3,4,5,6,8]).
D = 2.
?- maxabsdiff_of(D,[1,2,3,100,4,5,6,8]).
D = 97.
Of course, you could also use lambda together with meta-predicate foldl/4, like so:
:- use_module(library(lambda)).
maxabsdiff_of(X,[V0,V1|Vs]) :-
foldl(\E^(E0+D0)^(E+D)^(D is max(D0,abs(E-E0))), Vs, V1+abs(V1-V0),_+X).
Sample queries:
?- maxabsdiff_of(D,[1,2,3,4,5,6]).
D = 1.
?- maxabsdiff_of(D,[1,2,3,4,5,6,8]).
D = 2.
?- maxabsdiff_of(D,[1,2,3,100,4,5,6,8]).
D = 97.
Same results as before!

Prolog Recursion removing elements at index that is multiples of n from a list where n is any number

This is my first time asking a question here but I have a problem that I really can't wrap my head around which is Prolog recursion especially when it deals with list. So the task that I am supposed to solve is to write a drop predicate that works like this. For example, drop([1,2,3,4,5,6,7,8,9], 2, L) where L = [1,3,5,7,9] and N=n where elements at position n, 2n, 3n.... will be removed. The list starts from 1 is another thing to be noted.
Here is my attempt so far and thought process:
drop([], _, []).
indexOf([X|_], X, 1). %Using 1 because the question says the first element starts from 1.
indexOf([_|Ys], Y , I):-
indexOf(Ys, Y, N),
I is N + 1.
drop([X|Xs], Y, [X|_]) :-
indexOf([X|Xs] , X , A),
Z is A mod Y,
Z \== 0.
drop([X|Xs], Y, Zs) :-
%indexOf([X|Xs], X, A),
drop(Xs, Y, Zs).
I created an indexOf predicate to find the index of the elements starting from 1 . Next, my idea was to use the my first drop recursive case (in the code above it is the 5th case) to check and see whether the position of the element returns a remainder of zero when divided by the Y (second input). if it does not return a remainder of zero, then the X remains inside the list and is not dropped. Then, prolog moves on to the 2nd drop recursive case which can only be arrived when Z=0 and it will drop X from the list to return Zs. In essence, an element with index n, 2n, 3n... that is returned by indexOf will be dropped if it does not return a remainder of zero when divided by Y (second input).
I have not learnt Cut at this point of the course at the moment. I would appreciate if someone can point me to the right direction. I have been working on this for almost a day.
I am still trying to adapt the logic and declarative thinking in this programming paradigm. I would appreciate it if you could share with me, how did you personally go about mastering Logic programming?
First, looking at your approach, there's a flaw with using the indexOf/3. That is, at a given point in time when you need to know the index of what you're removing, you don't know what the item is yet until you get to it. At that point, the index is 1.
That's one issue with the following rule:
drop([X|Xs], Y, [X|_]) :-
indexOf([X|Xs], X, A),
Z is A mod Y,
Z \== 0.
The first subquery: indexOf([X|Xs], X, A) will succeed with A = 1 on its first attempt, just by definition (of course, X has index 1 in list [X|Xs]. As it succeeds, then the next line Z is A mod Y yields 1 since 1 mod Y is always 1 if Y > 0. And therefore, Z \== 0 will always succeed in this case.
Thus, you get the result: [X|_] where X is the first element of the list. So the first solution you get for, say, drop([1,2,3,4], 2, L). is L = [1|_]. Your third drop/3 predicate clause just recurses to the next element in the list, so then it will succeed the second clause the same way, yielding, L = [2|_], and so on...
Starting from the top, here's a way to think about a problem like this.
Auxiliary predicate
I know I want to remove every N-th element, so it helps to have a counter so that every time it gets to N I will ignore that element. This is done with an auxiliary predicate, drop/4 which will also have a recurring counter in addition to the original N:
drop(L, N, R) :-
drop(L, N, 1, R). % Start counter at 1
Base rule
If I drop any element from the empty list, I get the empty list. It doesn't matter what elements I drop. That's expressed as:
drop([], _, _, []).
You have this rule expressed correctly already. The above is the 4-argument version.
Recursive rule 1 - The N-th element
I have list [X|Xs] and X is the N-th element index, then the result is R if I skip X, reset my index counter to 1, and drop the N-th element from Xs:
drop([_|Xs], N, N, R) :- % I don't care what the element is; I drop it
drop(Xs, N, 1, R).
Recursive rule 2 - Other than the N-th element
I have list [X|Xs] and X is the A-th element (< N), then the result is [X|R] if I increment my index counter (A), and drop N-th elements from Xs with my updated index counter:
drop([X|Xs], N, A, [X|R]) :-
A < N,
NextA is A + 1,
drop(Xs, N, NextA, R).
Those are all the needed rules (4 of them).

Easily replicate an element in Prolog :)

I am working on a longer problem that has me duplicate an element N times in list form, and I believe that using append is the right way to go for this. The tiny predicate should theoretically act like this:
?- repl(x,5,L).
L = [x, x, x, x, x] ;
false.
I cannot seem to find any tips for this online, the replication of a single element, but I believe we need to use append, but no recursive solution. I come from more of a Haskell background, where this problem would be much easier to perform. Can someone help get me started on this? :)
Mine so far:
repl(E, N, R) :-
N > 0, append([E], [], R), writeln(R), repl(E, N-1, R), fail.
Which gives me:
?- repl(x,5,L).
[x]
[x]
[x]
[x]
[x]
false.
Close but not quite!
A recursive approach would be straight-forward and would work. I recommend figuring that one out. But here's a fun alternative:
repl(X, N, L) :-
length(L, N),
maplist(=(X), L).
If N is instantiated, then length(L, N) will generate a list of length N of just "blanks" (don't care terms). Then maplist(=(X), L) will unify each element of L with the variable X.
This gives a nice, relational approach and yields sensible results in the general case:
| ?- repl(X, N, L).
L = []
N = 0 ? ;
L = [X]
N = 1 ? ;
L = [X,X]
N = 2 ? ;
| ?- repl(X, N, [x,x,x]).
N = 3
X = x
yes
...
To figure out a recursive case, think about what your base case looks like (it would be repl with a count of 0 - what does the list look like then?). In the recursive case, think in terms of:
repl(X, N, [X|T]) :- ...
Meaning: The list [X|T] is the element X repeated N times if.... Figure out if what? If your base case is length 0, then your recursion is probably going to describe the repl of a list of length N in terms of the repl of a list of length N-1. Don't forget in this recursive rule to ensure N > 0 to avoid infinite recursion on backtracking. If you don't need the predicate to be purely relational and assume N is instantiated, then it can be fairly simple.
If you make a simple recursive version, you can "wrap" it in this predicate to make it work with variable N:
repl(X, N, L) :-
length(L, N),
simple_recursive_repl(X, N, L).
...
Because length/2 is relational, it is much more useful than just providing the length o a given list. When N and L are not instantiated, it becomes a generator of variable lists, starting at length 0. Type, length(L, N). at the Prolog prompt and see what happens.
Determinism
You give the following example of the predicate you envision:
?- repl(x,5,L).
L = [x, x, x, x, x] ;
false.
Notice that the ; is not very productive here. If you want to repeat x 5 times, then this can be done in exactly one way. I would therefore specify this predicate as deterministic not nondeterministic as you are doing.
Repeating list
Your code is actually quite far off a working solution, despite the output looking quite close in spirit to the envisioned result. You try to define the base case and the recursive case at the same time, which will not work.
Here is a simple (but less fun than #lurker gave :-)) implementation of the base and recursive case:
repeating_list(_, 0, []):- !.
repeating_list(H, Reps1, [H|T]):-
Reps2 is Reps1 - 1,
repeating_list(H, Reps2, T).
In a sense #lurker's implementation is simpler, and it is surely shorter.
Some extensions
In real-world/production code you would like to catch type errors and treat different instantiations with the same predicate. The second clause checks whether a given list consists of repeating elements (and if so, which one and how many occurrences there are).
%! repeating_list(+Term:term, +Repeats:integer, -List:list(term)) is det.
%! repeating_list(?Term:term, ?Repeats:integer, +List:list(term)) is det.
repeating_list(_, 0, []):- !.
% The term and number of repetitions are known given the list.
repeating_list(H, Reps, L):-
nonvar(L), !,
L = [H|T],
forall(
member(X, T),
% ==/2, since `[a,X]` does not contain 2 repetitions of `a`.
X == H
),
length([H|T], Reps).
% Repetitions is given, then we generate the list.
repeating_list(H, Reps1, [H|T]):-
must_be(nonneg, Reps1), !,
Reps2 is Reps1 - 1,
repeating_list(H, Reps2, T).
% Repetitions is not `nonneg`.
repeating_list(_, Reps, _):-
domain_error(nonneg, Reps).
Notice that I throw a domain error in case the number of repetitions is negative. This uses library error in SWI-Prolog. If your Prolog does not support this feature, then you may leave the last clause out.
PS: Comparison to Haskell
The combination of your statement that you do not know how to solve this problem in Prolog and your statement that this problem can be solved much easier in Haskell seems a little strange to me. I think you can only compare the difficulty of two implementations once you know how both of them look like.
I do prefer findall/3 to build lists, and between/3 to work with ranges:
repl(E, N, L) :- findall(E, between(1, N, _), L).

Prolog Finding Kth element in a list

I am trying write a predicate in prolog to find Kth element in a list.
Example:
?- element_at(X,[a,b,c,d,e],3).
X = c
my code as follows
k_ele(X,[X|_],1).
k_ele(X,[_|T],Y) :- Y > 1,Y is Y - 1, k_ele(X,T,Y).
But no use, I found solution on Internet as
element_at(X,[X|_],1).
element_at(X,[_|L],K) :- K > 1, K1 is K - 1, element_at(X,L,K1).
Which is same as my logic except they used one extra variable K1.
What is wrong with my code, why I need another variable ?
The reason your code does not work is that unification is not an assignment. When you say
Y is Y - 1
you are trying to unify a value of Y with the value of Y-1, which is mathematically impossible. This is roughly the same as saying 4 is 3 or 1001 is 1000. The entire condition fails, leading to the failure to find the element in the list.
The fixed solution that you have found on the internet introduces a separate variable K1, which is unified with K - 1. This is very much doable: K1 gets the value to which K-1 evaluates, the condition succeeds, and the clause moves on to the recursive invocation part.
Because variables in prolog are write-once critters. Having been [assigned|unified with|bound to] a non-variable value, it ceases to be variable. It is henceforth that value. Unlike more...conventional...programming languages, once bound, the only way to reassign a prolog variable is to backtrack through the assignment and undo it.
It should be noted, though, that a variable can be unified with another variable: Given a predicate something like
foo(X,Y) :- X = Y .
and something like
shazam(X,Y) :- bar(X,Y) , X = 3.
will result in both X and Y being 3. Having been unified, X and Y are both the same variable, albeit with different names.
I imagine you're working with the exercises from this link:
http://www.ic.unicamp.br/~meidanis/courses/problemas-prolog/
Note, in my opinion the original solution is not the best either.
For example, a query:
element_at(X,[a,b,c],Y).
would crash, even if there are 3 solutions:
X = a, Y = 1;
X = b, Y = 2;
X = c, Y = 3;
I believe writing in an alternative way:
element_at(H, [H | _], 1).
element_at(H, [_ | T], N) :- element_at(H, T, NMinus1), N is NMinus1 + 1.
would give better results. It's less efficient as one can not apply the last call optimization, but the logic becomes more general.