Prolog - How to count elements of a list? [closed] - list

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
Based that we have 1 list and we want to count how many times we found each element on that list, and make a new list that contains an element of the format N*X, for each element X that shows up N times in the given list.
I have to write a program in Prolog that utilizes that construction. More specifically a predicate freq(L,S), which is true if S is a list with elements with N*X format, in which the element N*X is included exactly one time if and only if the element X is included exactly N times inside the list L.
Here are some examples, the order of list S doesn't matter
| ?- freq([],S).
S = []
| ?- freq([a,b,c],S).
S = [1*a,1*b,1*c]
| ?- freq([0,0,0,0,0,a,a,a],S).
S = [5*0,3*a]
| ?- freq([5,5,5],S).
S = [3*5]
| ?- freq([a,a,0,a,0,0,0,b,a,0],S).
S = [5*0,4*a,1*b]
We use GNU-Prolog and we can't import any libraries other than the defaults.

library(aggregate) is on purpose:
freq(L,F) :- findall(N*E,aggregate(count,member(E,L),N),F).

Very simple solution using only mebmer/2, findall/3 and nth/3. Moreover, if you do not want to use findall/3 and nth/3 you can write your own predicate to count the occurrences of elements in the list (and it will be faster):
freq([],[]).
freq(L,LO):-
msort(L,LS),
freq_(LS,LS,[],LO).
freq_([],_,L,L).
freq_([H|T],LI,LT,L):-
member(_*H,LT), !,
freq_(T,LI,LT,L).
freq_([H|T],LI,LT,L):-
findall(I,nth0(I,LI,H),LO),
length(LO,N),
append(LT,[N*H],L1),
freq_(T,LI,L1,L).
?- freq([a,a,0,a,0,0,0,b,a,0],S).
S = [5*0, 4*a, 1*b]

How about this. With Unit Tests.
:- discontiguous rt/1. % unit test invocation predicate
rtall :- bagof(X,rt(X),_). % run all unit tests by calling all rt/1
% ===
% Something to replace (badly named & ugly) "var(X)" and "nonvar(X)"
% ===
% is X referencing a fresh/unbound/uninstantiated term?
% ("is X a freshvar"?)
ff(X) :- var(X).
% is X referencing an nonfresh/bound/instantiated term?
% ("is X a boundvar"?)
bb(X) :- nonvar(X).
% ===
% increment(+Key,+ListIn,-ListOut)
% Increments-by-1 or adds Key-with-1 to ListIn, giving ListOut
% ===
increment(Key,[],[*(1,Key)]) :- !.
increment(Key,[*(N,Key)|Rest],[*(NP,Key)|Rest]) :-
succ(N,NP),!.
increment(Key,[*(N,SomeKey)|Rest],[*(N,SomeKey)|ListOut]) :-
SomeKey \== Key,!, increment(Key,Rest,ListOut).
% ---
% Testing the above
% ---
:- begin_tests(inc).
test(one,true(ListOut == [(1*foo)])) :-
increment(foo,[],ListOut).
test(two,true(ListOut == [(2*foo)])) :-
increment(foo,[],ListA),
increment(foo,ListA,ListOut).
test(two,true(ListOut == [(2*foo),(1*bar)])) :-
increment(bar,[(2*foo)],ListOut).
:- end_tests(inc).
rt(inc) :- run_tests(inc).
% ===
% freq(+Expanded,?Collapsed)
% Either accepts the "Expanded" list and builds the "Collapsed" list
% or, id "Collapsed" is a boundvar, builds a new "Collapsed" list
% and compares with the passed "Collapsed" list so that key positions
% are irrelevant
% ===
freq(Expanded,Collapsed) :-
bb(Expanded),ff(Collapsed),!,
freq_with_hot_potatoe(Expanded,[],Collapsed).
freq(Expanded,Collapsed) :-
bb(Expanded),bb(Collapsed),!,
freq_with_hot_potatoe(Expanded,[],CollapsedNew),
compare_position_independently(Collapsed,CollapsedNew).
compare_position_independently(CollapsedA,CollapsedB) :-
% sort to the "standard order of terms", keep duplicates
msort(CollapsedA,CASorted),
msort(CollapsedB,CBSorted),
CASorted == CBSorted.
freq_with_hot_potatoe([X|Xs],CollapsedSoFar,CollapsedOut) :-
!,
increment(X,CollapsedSoFar,CollapsedPass),
freq_with_hot_potatoe(Xs,CollapsedPass,CollapsedOut).
freq_with_hot_potatoe([],Collapsed,Collapsed).
% ---
% Testing the above
% ---
:- begin_tests(freq).
test(f0) :- freq([],[]).
test(f1,fail) :- freq([],[1*a]).
test(f2) :- freq([a,b,c],[1*a,1*b,1*c]).
test(f3,fail) :- freq([a,b,c],[1*a,1*b,2*c]).
test(f4,fail) :- freq([a,b,c],[1*a,1*b,1*c,0*d]). % BORDERLINE, should succeed...
test(f5) :- freq([a,b,c],[1*a,1*c,1*b]). % Order unimportant
test(f6) :- freq([0,0,0,0,0,a,a,a],[5*0,3*a]).
test(f7) :- freq([5,5,5],[3*5]).
test(f8) :- freq([a,a,0,a,0,0,0,b,a,0],[5*0,4*a,1*b]).
:- end_tests(freq).
rt(freq) :- run_tests(freq).
Running all tests:
?- rtall.
% PL-Unit: inc ... done
% All 3 tests passed
% PL-Unit: freq ......... done
% All 9 tests passed
true.

Related

Finding a pattern in a list, prolog

I´m trying to build a predicate pattern(List,Pattern) that takes a List formed only by a repeated pattern and the output has to be that pattern.
Some examples of the List:
List1=[a,b,a,b]
List2=[1,2,3,1,2,3]
List3=[a,a,a,a,a,a,a,a]
As you can see, in each case either the list and the pattern can have different lenghts.
And the output in each case would be:
Pattern1=[a,b]
Pattern2=[1,2,3]
Pattern3=[a]
The only way I can think about a solution is taking the first element of the List (for example, in List2 would be "1") and going through List2 until I find again a "1" and then put in Pattern everything before the second 1 ("123"), but I don´t think it is the best solution. Does anybody know an easier way to solve it? Maybe with Append/3 or Member/2? Thank you!
You are looking for the shortest sequence Q ("pattern") such that list L is n > 0 concatenations of Q (whereby if n = 1 iff Q = L), then
If you have a verifying predicate which verifies that L is indeed a concatenation of a (non necessarily) shortest Q:
multiple_concatenations(X,X). % L = 1 * Q
multiple_concatenations(Q,L) :- % L = N * Q (for some N >= 1, Q <> []) if
concatenation(Q,Rest,L), % L = Q + Rest and
multiple_concatenations(Q,Rest). % Rest = M * Q (for some M)
Where concatenation/3 is just the sanely named append/3 from Prolog:
concatenation(List1,List2,List12) :-
append(List1,List2,List12).
... then you can try to find a shortest Q by just generating longer and longer potential _Q_s (of length going from 1 to length(L)) and break off at the first Q which passes multiple_concatenations(Q,L,N):
shortest_q(Q,L) :-
length(L,Length), % The length of L
must_be(positive_integer,Length), % Enforce length(L) > 0; throws if not
length(Q,N), % Generate a longer and longer
% "list template" Q (i.e. a list with only
% uninstantiated variables) on backtracking,
% with N = 0,1,2,3,...
N>0, % Don't want an empty template though
(concatenation(Q,_,L) % Q's uninstantiated members are
% now instantiated; if this fails,
->
(multiple_concatenations(Q,L), % Check whether Q is acceptable
!) % If yes, cut (i.e. break off at first answer)
;
fail). % If concatenation(Q,_,L) fails, fail the
% predicate: we have
% gone too far (Q is longer than L)
Add a few plunit test cases, which are doubleplus important in the "what am I computing right now?" Prolog wonderland:
:- begin_tests(mq).
test(1) :-
shortest_q(Q,[a,b,a,b]),
assertion(Q == [a,b]).
test(2) :-
shortest_q(Q,[1,2,3,1,2,3]),
assertion(Q == [1,2,3]).
test(3) :-
shortest_q(Q,[a,a,a,a,a,a,a,a]),
assertion(Q == [a]).
test(4) :-
shortest_q(Q,[a,b,c,d,e,f,g]),
assertion(Q == [a,b,c,d,e,f,g]).
:- end_tests(mq).
And so:
?- run_tests.
% PL-Unit: mq .... done
% All 4 tests passed
true.
Note however that "verification mode" accepts a sequence longer than the minimum:
?- shortest_q([1,2,3],[1,2,3,1,2,3]).
true.
?- shortest_q([1,2,3,1,2,3],[1,2,3,1,2,3]).
true.
A simple solution using only append/3 is:
% pattern(+List, -Pattern)
pattern([], _). % Any pattern repeated 0 times gives []
pattern(L, [P|Ps]) :- % [P|Ps] guarantees a non-empty pattern
append([P|Ps], R, L), % Gets a prefix of L as a possible pattern
pattern(R, [P|Ps]), % Checks whether prefix is indeed a pattern
!. % stops when the shortest pattern is found
Examples:
?- pattern([a,b,a,b], P).
P = [a, b].
?- pattern([1,2,3,1,2,3], P).
P = [1, 2, 3].
?- pattern([a,a,a,a,a,a,a], P).
P = [a].

Prolog: is there any way to generate the following items from a list?

I want to develop a predicate in prolog called next, which given a list returns another list with the N elements following the last value of the list where N is the size of the main list. For example: next([1,2,3,4], R).
will return R = [5,6,7,8]. or: next([11,12,13], R). It will return R = [14,15,16].
The problem I have is that if I iterate over the main list until I am left with its last element and start adding the next one to it to the result list, I don't know how many times I should iterate since I don't know what the length of the main list was.This is why my algorithm goes into a loop.
next([], []).
next([X], [X1|Res]) :- X1 is X + 1, next3([X1],Res),!.
next([H|T], [X]) :- next3(T, X).
How about this.
Here we use Constraint Logic Programming to constraint the elements of the result list to be increasing-monotonically-by-1 but just set them to actual values (in one instruction) once we know the last element of the input list.
We also use an open list (a list with an unbound fin) instead of append/3 to grow the output list at its end efficiently. This idiom called "using a difference list".
Finally we add test cases.
:- use_module(library(clpfd)).
% ---
% Called by the customer
% ---
nextor([],[]) :- !. % Empty input list means no work to do!
nextor([X|Xs],Out) :- % The input list contains at least 1 element
assertion(integer(X)), % This is for stating what we assume
OpenList = [K|Fin], % We will create a list of fresh variables; in order
% _to append easily, the list is kept "open", i.e. its tail end
% _is not [] as in a proper list but an unbound variable
% _(namely, Fin). The first element is as yet undefined,
% it is the fresh variable K.
assertion(\+is_list(OpenList)), % Not a list at present time.
nextor_w(X,Xs,[K|Fin],LastFin,LastX), % Processing the list with the first element X already
% _separated out (for assertions). To grow the OpenList at
% _its end, we just need Fin (we don't care about that list's
% Tip when we grow it at the end). Finally, to communicate
% the last Fin set up in the depth of the recursion to this
% call place, use LastFin. The last X found will be in LastX.
LastFin=[], % The open list is close (made proper list) by setting its
% _final Fin to [].
assertion(is_list(OpenList)), % Yes, it is a list now!
K #= LastX+1, % Now that LastX is known, we know K too.
% _The constraint propagates down the list, fixing the still
% unbound variables in OpenList (which is now a closed list).
Out = OpenList. % Unify for result.
% ---
% Does the recursion down the input list
% ---
nextor_w(Xp,[],[_|Fin],Fin,Xp) :- !. % At the end of recursion, communicate the "last X" and the
% and the "latest Fin" back to the caller.
nextor_w(Xp,[X|Xs],[K|Fin],FinOut,XpOut) :-
assertion(Xp+1 =:= X), % The input list is assumed to increase monotonously.
Kn #= K+1, % Next K is constrained to be previous K + 1,
Fin = [Kn|NewFin], % The Fin of the open list is set to a new list cell, with a new Fin
nextor_w(X,Xs,[Kn|NewFin],FinOut,XpOut).
% ---
% Testing
% ---
:- begin_tests(nextor).
test("empty list" ,true(R == [])) :-
nextor([],R).
test("1-elem list",true(R == [2])) :-
nextor([1],R).
test("2-elem list",true(R == [3,4])) :-
nextor([1,2],R).
test("3-elem list",true(R == [4,5,6])) :-
nextor([1,2,3],R).
:- end_tests(nextor).
And so:
?- run_tests.
% PL-Unit: nextor .... done
% All 4 tests passed
true.
How about doing:
next(In,Out) :-
length(In,N),
maplist(plus(N),In,Out).
Uses length/2 and maplist/3. This works for the examples in your question - next([1,2,3,4],R). and next([11,12,13],R). - but only because the lists contain consecutive numbers. next([23,2,18],R). will unify R with [26,5,21].
Or:
next(In,Out) :-
length(In,N),
last(In,LastValue),
MinValue is LastValue+1,
MaxValue is LastValue+N,
numlist(MinValue,MaxValue,Out).
Uses last/2 and numlist/3. With this approach next([23,2,18],R). will unify R with [19,20,21].
This works fine for me:
next(Xs,Ys) :-
next(Xs,[_],Ys).
next([_],[],[]).
next([X],[_|Q],[X1|R]) :-
X1 is X + 1,
next([X1],Q,R).
next([_|T],Q,R) :-
next(T,[_|Q],R).
As it runs down the list it is building up a second list. When it finds the end of the first list it then runs down the second list building the output.
I got this kind of output:
?- next([1,2,3,7,8],W).
W = [9, 10, 11, 12, 13] .

Prolog Finding middle element in List

I am trying to make use of prolog predicates and find middle element of a given list. My idea was to cut first and last element of list using recursion.Unfortunately I dont know how to handle recursion call properly.
delete_last(L, L1) :-
append(L1, [_], L).
delete_first(L,L1) :-
append([_],L1,L).
check_len(L) :-
length(L,LEN), \+ 1 is LEN.
delete_both([],_):-
false.
delete_both([_,_],_) :-
false.
delete_both([X],X):-
true, write('MidElement').
delete_both(L,L2) :-
delete_first(LT,L2), delete_last(L,LT),check_len(LT)
->write('here should be recursive call only when length is more than one').
I would be grateful for any help.
It would save a lot of typing if you checked the length of the list, calculated the position of the middle element, and only then traversed the list to get the element at that position. With SWI-Prolog, this would be:
?- length(List, Len),
divmod(Len, 2, N, 1),
nth0(N, List, a).
List = [a], Len = 1, N = 0 ;
List = [_G2371, a, _G2377], Len = 3, N = 1 ;
List = [_G2371, _G2374, a, _G2380, _G2383], Len = 5, N = 2 . % and so on
This solution makes sure the list has an odd length. You can see the documentation of divmod/4 if you need to define it yourself. Or, if the list does not have to have and odd, length, just use N is Len div 2. If for some reason you are not allowed to use nth0/3, it is still an easier predicate to implement than what you are trying to do.
You can tighten up what you have quite a bit as follows:
delete_last(L, L1) :-
append(L1, [_], L).
delete_first([_|L], L).
% No need to check length of 1, since we only need to check
% if L = [X] in the caller, so we'll eliminate this predicate
%check_len(L) :-
% length(L, 1). % No need for an extra variable to check length is 1
% Clauses that yield false are not needed since clauses already fail if not true
% So you can just remove those
%
delete_both([X], X) :-
write('MidElement').
% Here you need to fix the logic in your main clause
% You are deleting the first element of the list, then the last element
% from that result and checking if the length is 1.
delete_both(L, X) :-
delete_first(L, L1), % Remove first and last elements from L
delete_last(L1, LT),
( LT = [X] % Check for length of 1
-> true
; delete_both(LT, X) % otherwise, X is result of delete_both(LT, X)
).
With results:
| ?- delete_both([a,b,c,d,e], X).
X = c
yes
| ?- delete_both([a,b,c,d,e,f], X).
no
A DCG solution also works well here:
% X is the middle if it is flanked by two sequences of the same length
%
middle(X) --> seq(N), [X], seq(N).
seq(0) --> [].
seq(N) --> [_], { N #= N1 + 1 }, seq(N1).
middle(List, X) :- phrase(middle(X), List).
With results:
| ?- middle([a,b,c,d,e], X).
X = c ? ;
(1 ms) no
| ?- middle(L, a).
L = [a] ? ;
L = [_,a,_] ? ;
L = [_,_,a,_,_] ?
...
Another possible solution is to use SWI Prolog's append/2 predicate, which appends a list of lists (assuming you're using SWI):
middle(L, X) :-
same_length(Left, Right),
append([Left, [X], Right], L).
same_length([], []).
same_length([_|T1], [_|T2]) :- same_length(T1, T2).
In all of the above solutions, the predicate fails if the list has an even number of elements. Since that's what your original solution does, I assumed that's what is required. If there is a specific requirement for even lists, that needs to be stated clearly.

Searching a list for (same) two elements in Prolog

How can I search a list in Prolog for a specific element that appears more than once?
For example, if we are searching the list [1,2,3,4,1] for the element 1, Prolog should return true, but otherwise false for all other numbers.
This is what I have so far:
duplicate([], _) :-
false,
!.
duplicate([X|_], X) :-
true,
!.
duplicate([H|T], X) :-
T = [_|T1],
duplicate(T, X),
duplicate(T1, X).
My basic idea is to search the list until I find the element I am looking for, then search the tail of the list for the item again. I do not want to use the member() function provided by Prolog.
Prolog should also return the elements that appear more than once if asked by the query: duplicate([1,2,3,4,1], X), should print X = 1.
And here the obvious version using grammars. In a sense, we are describing the structure of a list containing a duplicate. That structure is as follows:
First, there is anything (...),
then there is the element ([V]),
again anything (...)
and again the element ([V])
followed by anything.
duplicate(L, V) :-
phrase(( ..., [V], ..., [V], ... ), L).
... --> [] | [_], ... .
As a downside, this version will produce redundant answers for a query like
?- duplicate([a,a,a],a).
This can be overcome by using dif/2:
duplicate(L, V) :-
phrase(( all(dif(V)), [V], all(dif(V)), [V], ... ), L).
The definition for non-terminal all//1.
What I was saying in my comment was : I want two items from the list L wich are not in the same place so
duplicate(L, V) :-
% nth0 gives the index (from 0) of an element in a list
% element V is at the place Id1 in L
nth0(Id1, L, V),
% element V is at the place Id2 in L
nth0(Id2, L, V),
% Id1 is different from Id2
% It is more usefull to say that Id1 < Id2
% Thanks **false** for the improvement
Id1 < Id2.
Another way to do this is to say : I remove the element of the list (this is done in SWI-Prolog by select/3) and I check if it's in the rest of the list :
duplicate(L, V) :-
select(V, L, L1),
member(V, L1).
Pure and simple! Use meta-predicate tcount/3 with reified term equality (=)/3 like so:
?- tcount(=(X), [1,2,3,4,1], 2).
X = 1 ; % succeeds, but leaves choicepoint
false.
?- tcount(=(1), [1,2,3,4,1], 2).
true. % succeeds deterministically
?- tcount(=(X), [b,c,d,a,b,a,c], 2).
X = b ;
X = c ;
X = a ;
false.
?- tcount(=(a), [b,c,d,a,b,a,c], 2).
true. % succeeds deterministically
Last, let's run the following quite general query:
?- tcount(=(a), Ls, 2).
Ls = [a,a] ;
Ls = [a,a,_X], dif(_X,a) ;
Ls = [a,a,_X,_Y], dif(_X,a), dif(_Y,a) ;
Ls = [a,a,_X,_Y,_Z], dif(_X,a), dif(_Y,a), dif(_Z,a) ...
The solution by #false is as clean as it will get. Here is a more verbose solution that states the problem in simpler terms. One thing to remember is that a "duplicated" element might mean that an element occurs exactly twice -- this is how this predicate interprets it -- or it might mean that an element occurs more than once -- this is what you probably mean (so the name duplicate is in fact misleading)
%% duplicate(List, Element) is true for every matching pair of _Element_ in _List_
duplicate([First|Rest], Element) :-
duplicate_1(Rest, First, Element).
% First occurrence
duplicate_1([This|Rest], X, X) :- % first occurrence
duplicate_2(Rest, This, X).
duplicate_1([This|Rest], _, X) :- % look further for first occurrence
duplicate_1(Rest, This, X).
% Second occurrence
duplicate_2(_, X, X). % second occurrence
duplicate_2([This|Rest], _, X) :- % look further for second occurrence
duplicate_2(Rest, This, X).
This can now be used in all directions:
?- duplicate([b,c,d,a,b,a,c], X).
X = b ;
X = c ;
X = a ;
false.
?- duplicate([b,c,d,a,b,a,c], a).
true ;
false.
?- duplicate(L, a).
L = [a, a|_G274] ;
L = [a, _G273, a|_G277] ;
L = [a, _G273, _G276, a|_G280] .
You will have to use cuts, or dif/2, or once/1 to get rid of the multiple answers, if they are a problem. How exactly depends on how you want to use the predicate.
for the first part of your problem I have found a simple solution:
duplicated([H|T], Item) :- H == Item, second_stage(T, Item). %first occurence found
duplicated([H|T], Item) :- duplicated(T, Item).
second_stage([H|T], Item) :- H == Item. %second occurence found -> match!
second_stage([H|T], Item) :- second_stage(T, Item).
This will give true f.e. with duplicated([1,2,3,1,5], 1).
For the second part (query with Variable) I will try to find a way...but I dont
know if this is possible in Prolog.
:)

Prolog - find an item in a list without built-in predicates [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 8 years ago.
Improve this question
I want to create a predicate that is TRUE if the element I search for is NOT in the list.
And that's without any built-in predicates or arithmetic constructions.
I am such a beginner in prolog and i'm thinking way too much in oop languages at the moment.
Thanks for a nice tipp in advance.
list_without([], _).
list_without([E|Es], F) :-
dif(E,F),
list_without(Es, F).
Is the closest one can get. It does use dif/2 which is a built-in predicate. But there is no other way to express inequality in a sound manner. See prolog-dif for more.
This definition can be used in various ways:
Regular testing:
?- list_without([a,b,c],d).
true.
But also more general cases:
?- list_without([a,b,c],X).
dif(X, c), dif(X, b), dif(X, a).
?- list_without([a,b,c],X), X = a.
false.
?- list_without([a,b,c],X), X = d.
X = d.
?- list_without([a,b,E],d).
dif(E, d).
Assuming that both the list and the element to test are ground, plus that standard control constructs are not classified as built-in predicates, a solution would be:
list_without(List, Element) :-
list_without(List, Element, Copy),
equal(List, Copy).
list_without([], _, []).
list_without([Head| Tail], Element, Copy) :-
( equal(Head, Element) ->
list_without(Tail, Element, Copy)
; Copy = [Head| TailCopy],
list_without(Tail, Element, TailCopy)
).
equal(Term, Term).
Some sample queries:
?- [list_without].
true.
?- list_without([1,2,3], 4).
true.
?- list_without([1,2,3], 2).
false.
?- list_without([1,2,3], 3).
false.
?- list_without([1,2,3], 1).
false.
But this is a rather odd exercise...
This will work:
not_in( _ , [] ) . % By definition, the empty list contains nothing.
not_in( X , [X|_] ) :- % If the head of the non-empty list matches,
!, fail . % we fail with prejudice.
not_in( X , [_|L] ) :- % otherwise,
not_in( X , L ) % simply recurse down on the tail.
.
alternatively, you can do something like this: a negated, positive test:
is_member_of( X , [X|_]) . % Success! The head of the list matches the desired item.
is_member_of( X , [_|L]) :- % otherwise...
is_member_of( X , L ) % recurse down on the tail.
.
is_not_a_member_of( X , L ) :-
\+ is_member_of( X , L ) .