Find the minimum in a mixed list in Prolog - prolog

I am new to prolog, I am just learning about lists and I came across this question. The answer works perfect for a list of integers.
minimo([X], X) :- !.
minimo([X,Y|Tail], N):-
( X > Y ->
minimo([Y|Tail], N)
;
minimo([X|Tail], N)
).
How can I change this code to get the smallest int from a mixed list?
This
sint([a,b,3,2,1],S)
should give an answer:
S=1

you could just ignore the problem, changing the comparison operator (>)/2 (a binary builtin predicate, actually) to the more general (#>)/2:
minimo([X], X) :- !.
minimo([X,Y|Tail], N):-
( X #> Y ->
minimo([Y|Tail], N)
;
minimo([X|Tail], N)
).
?- minimo([a,b,3,2,1],S).
S = 1.

First of all, I don't think the proposed implementation is very elegant: here they pass the minimum found element thus far by constructing a new list each time. Using an additional parameter (we call an accumulator) is usually the way to go (and is probably more efficient as well).
In order to solve the problem, we first have to find an integer. We can do this like:
sint([H|T],R) :-
integer(H),
!,
sint(T,H,R).
sint([_|T],R) :-
sint(T,R).
So here we check if the head H is an integer/1. If that is the case, we call a predicate sint/3 (not to be confused with sint/2). Otherwise we call recursively sint/2 with the tail T of the list.
Now we still need to define sint/3. In case we have reached the end of the list [], we simply return the minum found thus far:
sint([],R,R).
Otherwise there are two cases:
the head H is an integer and smaller than the element found thus far, in that case we perform recursion with the head as new current minimum:
sint([H|T],M,R):
integer(H),
H < M,
!,
sint(T,H,R).
otherwise, we simply ignore the head, and perform recursion with the tail T.
sint([_|T],M,R) :-
sint(T,M,R).
We can put the recursive clauses in an if-then-else structure. Together with the earlier defined predicate, the full program then is:
sint([H|T],R) :-
integer(H),
!,
sint(T,H,R).
sint([_|T],R) :-
sint(T,R).
sint([],R,R).
sint([H|T],M,R):
(
(integer(H),H < M)
-> sint(T,H,R)
; sint(T,M,R)
).
The advantage of this approach is that filtering and comparing (to obtain the minimum) is done at the same time, so we only iterate once over the list. This will usually result in a performance boost since the "control structures" are only executed once: more is done in an iteration, but we only iterate once.
We can generalize the approach by making the filter generic:
filter_minimum(Filter,[H|T],R) :-
Goal =.. [Filter,H],
call(Goal),
!,
filter_minimum(Filter,T,H,R).
filter_minimum(Filter,[_|T],R) :-
filter_minimum(Filter,T,R).
filter_minimum(_,[],R,R).
filter_minimum(Filter,[H|T],M,R) :-
Goal =.. [Filter,H],
(
(call(Goal),H < M)
-> filter_minimum(Filter,T,H,R)
; filter_minimum(Filter,T,M,R)
).
You can then call it with:
filter_minimum(integer,[a,b,3,2,1],R).
to filter with integer/1 and calculate the minimum.

You could just write a predicate that returns a list with the numbers and the use the above minimo/2 predicate:
only_numbers([],[]).
only_numbers([H|T],[H|T1]):-integer(H),only_numbers(T,T1).
only_numbers([H|T],L):- \+integer(H),only_numbers(T,L).
sint(L,S):-only_numbers(L,L1),minimo(L1,S).

Related

Prolog program to return atoms in a proposition formula

I am a newbie to prolog and am trying to write a program which returns the atoms in a well formed propositional formula. For instance the query ats(and(q, imp(or(p, q), neg(p))), As). should return [p,q] for As. Below is my code which returns the formula as As. I dont know what to do to split the single F in ats in the F1 and F2 in wff so wff/2 never gets called. Please I need help to proceed from here. Thanks.
CODE
logical_atom( A ) :-
atom( A ),
atom_codes( A, [AH|_] ),
AH >= 97,
AH =< 122.
wff(A):- ground(A),
logical_atom(A).
wff(neg(A)) :- ground(A),wff(A).
wff(or(F1,F2)) :-
wff(F1),
wff(F2).
wff(and(F1,F2)) :-
wff(F1),
wff(F2).
wff(imp(F1,F2)) :-
wff(F1),
wff(F2).
ats(F, As):- wff(F), setof(F, logical_atom(F), As).
First, consider using a cleaner representation: Currently, you cannot distinguish atoms by a common functor. So, wrap them for example in a(Atom).
Second, use a DCG to describe the relation between a well-formed formula and the list of its atoms, like in:
wff_atoms(a(A)) --> [A].
wff_atoms(neg(F)) --> wff_atoms(F).
wff_atoms(or(F1,F2)) --> wff_atoms(F1), wff_atoms(F2).
wff_atoms(and(F1,F2)) --> wff_atoms(F1), wff_atoms(F2).
wff_atoms(imp(F1,F2)) --> wff_atoms(F1), wff_atoms(F2).
Example query and its result:
?- phrase(wff_atoms(and(a(q), imp(or(a(p), a(q)), neg(a(p))))), As).
As = [q, p, q, p].
This should do what you want. It extracts the unique set of atoms found in any arbitrary prolog term.
I'll leave it up to you, though, to determine what constitutes a "well formed propositional formula", as you put it in your problem statement (You might want to take a look at DCG's for parsing and validation).
The bulk of the work is done by this "worker predicate". It simply extracts, one at a time via backtracking, any atoms found in the parse tree and discards anything else:
expression_atom( [T|_] , T ) :- % Case #1: head of list is an ordinary atom
atom(T) , % - verify that the head of the list is an atom.
T \= [] % - and not an empty list
. %
expression_atom( [T|_] , A ) :- % Case #2: head of listl is a compound term
compound(T) , % - verify that the head of the list is a compound term
T =.. [_|Ts] , % - decompose it, discarding the functor and keeping the arguments
expression_atom(Ts,A) % - recurse down on the term's arguments
. %
expression_atom( [_|Ts] , A ) :- % Finally, on backtracking,
expression_atom(Ts,A) % - we simply discard the head and recurse down on the tail
. %
Then, at the top level, we have this simple predicate that accepts any [compound] prolog term and extracts the unique set of atoms found within by the worker predicate via setof/3:
expression_atoms( T , As ) :- % To get the set of unique atoms in an arbitrary term,
compound(T) , % - ensure that's its a compound term,
T =.. [_|Ts] , % - decompose it, discarding the functor and keeping the arguments
setof(A,expression_atom(Ts,A),As) % - invoke the worker predicate via setof/3
. % Easy!
I'd approach this problem using the "univ" operator =../2 and explicit recursion. Note that this solution will not generate and is not "logically correct" in that it will not process a structure with holes generously, so it will produce different results if conditions are reordered. Please see #mat's comments below.
I'm using cuts instead of if statements for personal aesthetics; you would certainly find better performance with a large explicit conditional tree. I'm not sure you'd want a predicate such as this to generate in the first place.
Univ is handy because it lets you treat Prolog terms similarly to how you would treat a complex s-expression in Lisp: it converts terms to lists of atoms. This lets you traverse Prolog terms as lists, which is handy if you aren't sure exactly what you'll be processing. It saves me from having to look for your boolean operators explicitly.
atoms_of_prop(Prop, Atoms) :-
% discard the head of the term ('and', 'imp', etc.)
Prop =.. [_|PropItems],
collect_atoms(PropItems, AtomsUnsorted),
% sorting makes the list unique in Prolog
sort(AtomsUnsorted, Atoms).
The helper predicate collect_atoms/2 processes lists of terms (univ only dismantles the outermost layer) and is mutually recursive with atoms_of_prop/2 when it finds terms. If it finds atoms, it just adds them to the result.
% base case
collect_atoms([], []).
% handle atoms
collect_atoms([A|Ps], [A|Rest]) :-
% you could replace the next test with logical_atom/1
atom(A), !,
collect_atoms(Ps, Rest).
% handle terms
collect_atoms([P|Ps], Rest) :-
compound(P), !, % compound/1 tests for terms
atoms_of_prop(P, PAtoms),
collect_atoms(Ps, PsAtoms),
append(PAtoms, PsAtoms, Rest).
% ignore everything else
collect_atoms([_|Ps], Rest) :- atoms_of_prop(Ps, Rest).
This works for your example as-is:
?- atoms_of_prop(ats(and(q, imp(or(p, q), neg(p))), As), Atoms).
Atoms = [p, q].

Prolog Assigning integer to a variable

I'm new to Prolog, and using GNU Prolog, so no clp(fd) allowed. What I'm trying to do is for a given integer N, generate a list with elements of 1 ~ N. So set(3,T). will output T = [1,2,3].
Here is what I have so far:
set(0,[]).
set(N,T):-set(N-1,T1),append(T1,[N],T).
When I try set(2,T), it crashes. I debugged with trace, and find out that it's not evaluating N-1, but rather doing N-1-1-1...
Anyone can tell me how to solve this?
Thank you.
n_ups(N, Xs) :-
length(Xs, N),
numbered_from(Xs, 1).
numbered_from([], _).
numbered_from([I0|Is], I0) :-
I1 is I0+1,
numbered_from(Is, I1).
In fact, the complexity is hidden within length/2.
It should be:
set(N,T):- N2 is N-1, set(N2,T1), append(T1,[N],T).
Arithmetic operations are performed by using is/2. N-1 is a shorthand for -(N,1) (just like N2 is N-1 is shorthand for is(N2, N-1)), so you were just creating infinite tree -(-(-(-(...),1),1,1,1).
Little educational note:
If you want set/2 to be proper relation so it can answer queries like set(3,X), set(X, [1,2,3]) and set(X,Y) without error then you should write this predicate that way:
set(0, []).
set(Value, List) :-
length(List, Value),
append(ShorterList, [Value], List),
ValueMinusOne is Value - 1,
set(ValueMinusOne, ShorterList).
That way result of arithmetic operation is always possible to obtain because input value (lenght of the list) is either explicitly given or generated from length/1.

Prolog issue with max list function: nondeterm vs procedure

I am trying to do a small project in prolog where a user can input a list and then it calculates the average, max in the list etc. etc.
So far so good, but I ran into a problem when writing the max function (finds max number in the list). The code is:
maxN([X],X):-!.
maxN([X|L],X) :- maxN(L,M), X > M.
maxN([X|L],M) :- maxN(L,M), M >= X.
The function itself works separately, but I get this error message:
The predicate 'forma::maxN/2 (i,o)', which is declared as 'procedure', is actually 'nondeterm' forma.pro
This is my predicate in the *.cl definition:
maxN: (integer* Z, integer U) procedure (i,o).
I cannot declare it as nondeterm because it causes issues with my whole form. Can you help me/give a hint how to make it a procedure? I am thinking I have to make a cut somewhere but my attempts have failed so far.
P.S. I am using Visual Prolog 7.4.
Edit: After trying the alternatives proposed to make the two rules into one or with an accumulator, I now get that the predicate is 'determ' instead of a procedure. According to my Prolog guide that means that the predicate doesn't have multiple solutions now, but instead has a chance to fail. Basically all code variations I've done up to now lead me to a 'determ'.
The problem is that Prolog sees a choice point between your second and third rules. In other words, you, the human, know that both X > M and M >= X cannot both be true, but Prolog is not able to infer that.
IMO the best thing to do would be to rephrase those two rules with one rule:
maxN([X], X) :- !.
maxN([X|L], Max) :-
maxN(L, M),
X > M -> Max = X
; Max = M.
This way there isn't ever an extra choice point that would need to be pruned with a cut.
Following #CapelliC's advice, you could also reformulate this with an accumulator:
maxN([X|Xs], Max) :- maxN_loop(Xs, X, Max).
maxN_loop([], Max, Max).
maxN_loop([X|Xs], Y, Max) :-
X > Y -> maxN_loop(Xs, X, Max)
; maxN_loop(Xs, Y, Max).
sorry, I don't know the Prolog dialect you're using, my advice is to try to add a cut after the second clause:
maxN([X|L],X) :- maxN(L,M), X > M, !.
Generally, I think a recursive procedure can be made deterministic transforming it to tail recursive. Unfortunately, this requires to add an accumulator:
maxN([],A,A).
maxN([X|L],A,M) :- X > A, !, maxN(L,X,M).
maxN([X|L],A,M) :- maxN(L,A,M).
Of course, top level call should become
maxN([F|L],M) :- maxN(L,F,M).

Prolog - sequence in list

We want to build a predicate that gets a list L and a number N and is true if N is the length of the longest sequence of list L.
For example:
?- ls([1,2,2,4,4,4,2,3,2],3).
true.
?- ls([1,2,3,2,3,2,1,7,8],3).
false.
For this I built -
head([X|S],X). % head of the list
ls([H|T],N) :- head(T,X),H=X, NN is N-1 , ls(T,NN) . % if the head equal to his following
ls(_,0) :- !. % get seq in length N
ls([H|T],N) :- head(T,X) , not(H=X) ,ls(T,N). % if the head doesn't equal to his following
The concept is simply - check if the head equal to his following , if so , continue with the tail and decrement the N .
I checked my code and it works well (ignore cases which N = 1) -
ls([1,2,2,4,4,4,2,3,2],3).
true ;
false .
But the true answer isn't finite and there is more answer after that , how could I make it to return finite answer ?
Prolog-wise, you have a few problems. One is that your predicate only works when both arguments are instantiated, which is disappointing to Prolog. Another is your style—head/2 doesn't really add anything over [H|T]. I also think this algorithm is fundamentally flawed. I don't think you can be sure that no sequence of longer length exists in the tail of the list without retaining an unchanged copy of the guessed length. In other words, the second thing #Zakum points out, I don't think there will be a simple solution for it.
This is how I would have approached the problem. First a helper predicate for getting the maximum of two values:
max(X, Y, X) :- X >= Y.
max(X, Y, Y) :- Y > X.
Now most of the work sequence_length/2 does is delegated to a loop, except for the base case of the empty list:
sequence_length([], 0).
sequence_length([X|Xs], Length) :-
once(sequence_length_loop(X, Xs, 1, Length)).
The call to once/1 ensures we only get one answer. This will prevent the predicate from usefully generating lists with sequences while also making the predicate deterministic, which is something you desired. (It has the same effect as a nicely placed cut).
Loop's base case: copy the accumulator to the output parameter:
sequence_length_loop(_, [], Length, Length).
Inductive case #1: we have another copy of the same value. Increment the accumulator and recur.
sequence_length_loop(X, [X|Xs], Acc, Length) :-
succ(Acc, Acc1),
sequence_length_loop(X, Xs, Acc1, Length).
Inductive case #2: we have a different value. Calculate the sequence length of the remainder of the list; if it is larger than our accumulator, use that; otherwise, use the accumulator.
sequence_length_loop(X, [Y|Xs], Acc, Length) :-
X \= Y,
sequence_length([Y|Xs], LengthRemaining),
max(Acc, LengthRemaining, Length).
This is how I would approach this problem. I don't know if it will be useful for you or not, but I hope you can glean something from it.
How about adding a break to the last rule?
head([X|S],X). % head of the list
ls([H|T],N) :- head(T,X),H=X, NN is N-1 , ls(T,NN) . % if the head equal to his following
ls(_,0) :- !. % get seq in length N
ls([H|T],N) :- head(T,X) , not(H=X) ,ls(T,N),!. % if the head doesn't equal to his following
Works for me, though I'm no Prolog expert.
//EDIT: btw. try
14 ?- ls([1,2,2,4,4,4,2,3,2],2).
true ;
false.
Looks false to me, there is no check whether N is the longest sequence. Or did I get the requirements wrong?
Your code is checking if there is in list at least a sequence of elements of specified length. You need more arguments to keep the state of the search while visiting the list:
ls([E|Es], L) :- ls(E, 1, Es, L).
ls(X, N, [Y|Ys], L) :-
( X = Y
-> M is N+1,
ls(X, M, Ys, L)
; ls(Y, 1, Ys, M),
( M > N -> L = M ; L = N )
).
ls(_, N, [], N).

studying for prolog/haskell programming exam

I starting to study for my upcoming exam and I'm stuck on a trivial prolog practice question which is not a good sign lol.
It should be really easy, but for some reason I cant figure it out right now.
The task is to simply count the number of odd numbers in a list of Int in prolog.
I did it easily in haskell, but my prolog is terrible. Could someone show me an easy way to do this, and briefly explain what you did?
So far I have:
odd(X):- 1 is X mod 2.
countOdds([],0).
countOdds(X|Xs],Y):-
?????
Your definition of odd/1 is fine.
The fact for the empty list is also fine.
IN the recursive clause you need to distinguish between odd numbers and even numbers. If the number is odd, the counter should be increased:
countOdds([X|Xs],Y1) :- odd(X), countOdds(Xs,Y), Y1 is Y+1.
If the number is not odd (=even) the counter should not be increased.
countOdds([X|Xs],Y) :- \+ odd(X), countOdds(Xs,Y).
where \+ denotes negation as failure.
Alternatively, you can use ! in the first recursive clause and drop the condition in the second one:
countOdds([X|Xs],Y1) :- odd(X), !, countOdds(Xs,Y), Y1 is Y+1.
countOdds([X|Xs],Y) :- countOdds(Xs,Y).
In Prolog you use recursion to inspect elements of recursive data structs, as lists are.
Pattern matching allows selecting the right rule to apply.
The trivial way to do your task:
You have a list = [X|Xs], for each each element X, if is odd(X) return countOdds(Xs)+1 else return countOdds(Xs).
countOdds([], 0).
countOdds([X|Xs], C) :-
odd(X),
!, % this cut is required, as rightly evidenced by Alexander Serebrenik
countOdds(Xs, Cs),
C is Cs + 1.
countOdds([_|Xs], Cs) :-
countOdds(Xs, Cs).
Note the if, is handled with a different rule with same pattern: when Prolog find a non odd element, it backtracks to the last rule.
ISO Prolog has syntax sugar for If Then Else, with that you can write
countOdds([], 0).
countOdds([X|Xs], C) :-
countOdds(Xs, Cs),
( odd(X)
-> C is Cs + 1
; C is Cs
).
In the first version, the recursive call follows the test odd(X), to avoid an useless visit of list'tail that should be repeated on backtracking.
edit Without the cut, we get multiple execution path, and so possibly incorrect results under 'all solution' predicates (findall, setof, etc...)
This last version put in evidence that the procedure isn't tail recursive. To get a tail recursive procedure add an accumulator:
countOdds(L, C) :- countOdds(L, 0, C).
countOdds([], A, A).
countOdds([X|Xs], A, Cs) :-
( odd(X)
-> A1 is A + 1
; A1 is A
),
countOdds(Xs, A1, Cs).

Resources