Related
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].
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] .
I want to count the number of elements in a list which have a relation with the element following.
The predicate I have works by using an accumulator variable which it increments if the predicate related returns true.
The following example code is to check the number of times an element is greater than it's previous element.
So for example
count_list([1,2,3,2,1,3,2],Count).
should return 3.
The code almost works. It increments the accumulator variable correctly. However, the function returns false, when it tries to compare the final 2 at the end with the non-existent next term.
listofitems([],N,N).
%count number of items which are related to the previous
listofitems([A,B|T],Acc,N) :-
write(A),write(' '), write(B),
( related(A,B) -> Acc1 is Acc+1 ; Acc1 = Acc ),
write(Acc1),write('\n'),
listofitems([B|T],Acc1,N).
count_list(L,N):-
listofitems(L,0,N).
%define the relationship to be counted
related(A,B):-
B>A.
Does anyone have any suggestions as to how to create an elegant terminating condition so I can return the accumulated value?
Does anyone have any suggestions as to how to create an elegant terminating condition so I can return the accumulated value?
The problem you have is that your query fails. Try first to minimize the query as much as possible. Certainly, you expect it to work for:
?- listofitems([], Count).
Count = 0.
Yet, it already fails for:
?- listofitems([1], Count).
false.
So let's try to dig into the reason for that.
And since your program is pure (apart from those writes), it is possible to diagnose this a little better by considering a generalization of your program. I prefer to look at such generalizations as I do not want to read too much (eye strain and such):
:- op(950, fy, *).
*_.
listofitems([], N,N).
listofitems([A,B|T], Acc,N) :-
* ( related(A,B) -> Acc1 is Acc+1 ; Acc1 = Acc ),
* listofitems([B|T], Acc1,N).
count_list(L,N):-
listofitems(L,0,N).
?- count_list([1], Count).
false.
Even this generalization fails! So now in desperation I try to ask the most general query. It's like when I ask one thing after the other and get a noe after a no. Good this is Prolog, for we can ask: "Say me just everything you know".
?- count_list(Es,Count).
Es = [], Count = 0
; Es = [_,_|_].
So it is only the case for the empty list and lists with at least two elements. But there is no answer for one-elemented lists! You will thus have to generalize the program somehow.
A natural way would be to add a fact
listofitems([_], N, N).
As a minor remark, this isn't called a "terminating condition" but rather a "base case".
And if you really want to trace your code, I recommend these techniques instead of adding manual writes. They are much too prone to error.
If the all list items are integers and your Prolog system supports clpfd, you can proceed like this:
:- use_module(library(clpfd)).
:- use_module(library(lists), [last/3]).
:- use_module(library(maplist), [maplist/4]).
To relate adjacent items, look at two sublists of [E|Es], Es and Fs. If, say,
[E|Es] = [1,2,3,2,1,3,2] holds ...
... then Fs lacks the last item (Fs = [1,2,3,2,1,3,2]) ...
... and Es lacks the first item (Es = [1,2,3,2,1,3,2]).
maplist/4 and i0_i1_gt01/3 map corresponding list items in Fs and Es to 0 / 1:
i_j_gt01(I, J, B) :- % if I #< J then B #= 1
I #< J #<=> B. % if I #>= J then B #= 0
?- maplist(i_j_gt01, [1,2,3,2,1,3], [2,3,2,1,3,2], Bs).
Bs = [1,1,0,0,1,0].
Last, sum up [1,1,0,0,1,0] using sum/3:
?- sum([1,1,0,0,1,0], #=, N).
N = 3.
Let's put it all together!
count_adj_gt([E|Es], N) :-
last(Fs, _, [E|Es]), % or: `append(Fs, [_], [E|Es])`
% or: `list_butlast([E|Es], Fs)`
maplist(i_j_gt01, Es, Fs, Bs),
sum(Bs, #=, N).
Sample query using SICStus Prolog 4.3.2:
?- count_adj_gt([1,2,3,2,1,3,2], N).
N = 3. % succeeds deterministically
not sure about
an elegant terminating condition
my whole code would be
?- Vs=[1,2,3,2,1,3,2], aggregate_all(count, (append(_,[X,Y|_], Vs), X<Y), Count).
That's all...
If you need something more complex, remember that library(clpfd) has more to offer.
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.
I got this grid:
tab([[s,f,f,f,s,f,f,f,s],
[f,s,f,f,f,f,f,s,f],
[f,f,s,f,f,f,s,f,f],
[f,f,f,f,f,f,f,f,f],
[s,f,f,f,m,f,f,f,s],
[f,f,f,f,f,f,f,f,f],
[f,f,s,f,f,f,s,f,f],
[f,s,f,f,f,f,f,s,f],
[s,f,f,f,s,f,f,f,s]]).
I want to print in the screen without brackets and commas.
By the way I can't print it right with or without them.
These are the print rules:
viewTab([]).
viewTab([H|T]) :-
printList(H),
viewTab(T).
printList([]) :-
nl.
printList([H|T]) :-
write(H),
write(' | '),
printList(T).
I call it in the Prolog's terminal like:
?- viewTab(X), tab(X).
I can't print a thing, and I get an infinite loop at:
printList([]) :-
nl.
Can you help me find my mistake?
Or some tips to make the code easier to work with.
Your viewTab/1 is not a purely logical predicate: it has a side effect, and it does not terminate for if its argument is a variable.
For example:
?- listing(foo).
foo([]).
foo([_|A]) :-
foo(A).
true.
?- foo(X).
X = [] ;
X = [_G256] ;
X = [_G256, _G259] ;
X = [_G256, _G259, _G262] ;
X = [_G256, _G259, _G262, _G265] ;
X = [_G256, _G259, _G262, _G265, _G268] . % and so on
So this:
?- viewTab(X), tab(X).
Puts a list in X, then tab(X) fails, and you are back at viewTab(X), ad infinitum.
You should try:
?- tab(X), viewTab(X).
Use dcg!
Definite clause grammars are a versatile, logical way of processing input/output.
For a start, read this well-written DCG primer by Markus Triska, also known as #mat on SO!
Right now, as a quick fix, use the built-in predicate format/2 like this:
?- X = [a,b,c], format('~s~n',[X]).
abc % output via side-effect
X = [a, b, c]. % query succeeds