Related
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've been searching through the many existing Prolog questions on SO relevant to splitting but couldn't find one as generic as the one that I want. I'd like to point out that I've been able to split lists into lists of 2/3/4 elements by using 2/3/4 variables piped before a list variable. This question is different from that only because of its genericness.
So, my list will always contain N*N items, N being unknown beforehand(usually will vary from 4 to 36, yes N is also a perfect square). I want to split it into a list of N lists containing N items each because that'll allow me to treat it as a matrix, hence allowing to transpose and certain operations of that sort. I haven't really been able to get too far with the logic because I'm relatively new to declarative programming; please see below my incomplete(faulty) attempt:
listmodel(1,L):- L = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16].
size(L,N) :- length(L,N1), N is round(sqrt(N1)).
% add_tail(+Liste, +Element, -ResultantList)
add_tail([],L,[L]).
add_tail([X|L1],L2,[X|LI]):-add_tail(L1,L2,LI).
% partition the list containing N*N items into a list of N lists containing N elements each.
% part(+Liste, +Size, -ResultantList)
part([],_,DL).
part(L,N,DL) :-
length(P,N), % P(refix) initialized
append(P,S,L), % S(uffix) contains rest of L, using append in (-,-,+) mode
add_tail(DL,P,DL1), %add P(first N elements) as first element of DL.
part(S,N,DL1).
Now running ?- listmodel(1,L),size(L,N),part(L,N,DL). will produce DL=[] because that is what it gets initialized to in the first add_tail call in the part predicate. I can't seem to figure out how to store all elements in a list that's preserved through the recursion.
Any help/direction of any kind will be appreciated. I'm stuck here since over 23 hours 10 minutes now.
Thanks.
This should do it:
part([], _, []).
part(L, N, [DL|DLTail]) :-
length(DL, N),
append(DL, LTail, L),
part(LTail, N, DLTail).
Base case is first/last arguments are empty lists.
Recursive step takes a fresh list of N elements, takes the first N elements from L (which will be one of the items of the third argument) and calls recursively.
Want to combine versatility and favorable termination properties?
Use clpfd!
:- use_module(library(clpfd)).
First, we define
list_prefix_n_suffix/4.
list_prefix_n_suffix(Zs,Xs,N,Ys) is logically equivalent to both append(Xs,Ys,Zs), length(Xs,N) and length(Xs,N), append(Xs,Ys,Zs), but has better universal termination behavior than either1 one!
list_prefix_n_suffix(Zs, Xs, N, Ys) :-
list_prefix_n0_n_suffix(Zs, Xs, 0,N, Ys).
list_prefix_n0_n_suffix(Zs, Xs, N0,N, Ys) :-
zcompare(Order, N0, N),
rel_list_prefix_n0_n_suffix(Order, Zs, Xs, N0,N, Ys).
rel_list_prefix_n0_n_suffix(=, Ys, [], _,_, Ys).
rel_list_prefix_n0_n_suffix(<, [Z|Zs], [Z|Xs], N0,N, Ys) :-
N1 #= N0 + 1,
list_prefix_n0_n_suffix(Zs, Xs, N1,N, Ys).
Some sample queries for list_prefix_n_suffix/4:
?- list_prefix_n_suffix([a,b,c], Xs,-1, Ys).
false. % OK: too small
?- list_prefix_n_suffix([a,b,c], Xs, 0, Ys).
Xs = [], Ys = [a,b,c]. % succeeds deterministically
?- list_prefix_n_suffix([a,b,c], Xs, 4, Ys).
false. % OK: too big
?- list_prefix_n_suffix([a,b,c], Xs, N, Ys).
Xs = [] , N = 0, Ys = [a,b,c]
; Xs = [a] , N = 1, Ys = [b,c]
; Xs = [a,b] , N = 2, Ys = [c]
; Xs = [a,b,c], N = 3, Ys = []
; false. % terminates universally
Based upon above list_prefix_n_suffix/4 we define list_rows_width/3:
list_rows_width([], [], _N).
list_rows_width([E|Es0], [[R|Rs]|Rss], N) :-
list_prefix_n_suffix([E|Es0], [R|Rs], N, Es),
list_rows_width(Es, Rss, N).
Sample queries using list_rows_width/3:
?- list_rows_width([a,b,c,d,e,f], Rows, 4).
false. % OK: 6 is not divisible by 4
?- list_rows_width([a,b,c,d,e,f], Rows, 3).
Rows = [[a,b,c],[d,e,f]]. % succeeds deterministically
?- list_rows_width([a,b,c,d,e,f,g,h,i,j,k,l], Rows, N).
N = 1, Rows = [[a],[b],[c],[d],[e],[f],[g],[h],[i],[j],[k],[l]]
; N = 2, Rows = [[a, b],[c, d],[e, f],[g, h],[i, j],[k, l]]
; N = 3, Rows = [[a, b, c],[d, e, f],[g, h, i],[j, k, l]]
; N = 4, Rows = [[a, b, c, d],[e, f, g, h],[i, j, k, l]]
; N = 6, Rows = [[a, b, c, d, e, f],[g, h, i, j, k, l]]
; N = 12, Rows = [[a, b, c, d, e, f, g, h, i, j, k, l]]
; false. % terminates universally
Works just like it should!
Footnote 1: Without resorting to using alternative control-flow mechanisms like prolog-coroutining.
I need to define a predicate toAdd/3 such that if Xss and Yss are lists of lists then toAdd(X,Xss,Yss) holds if Yss can be obtained by adding the element X to the end of every element in Xss, e.g.
?- toAdd(g, [[e],[b,c,f],[k,h]], Yss).
Yss = [[e,g],[b,c,f,g],[k,h,g]]. % expected result
I know how to add an element to a list but lists of lists confuse me.
I wrote this code that adds to the end of one list, but not sublists.
add(X,[],[X]).
add(X,[A|L],[A|L1]) :-
add(X,L,L1).
Let's put the predicate add/3 to use with meta-predicate maplist/3!
toAdd(X,Xss,Yss) :-
maplist(add(X),Xss,Yss).
Sample query:
?- toAdd(g, [[e],[b,c,f],[k,h]], Yss).
Yss = [[e,g],[b,c,f,g],[k,h,g]]
; false.
split the problem in two parts:
- transform each element
- append to tail
then
add(_,[],[]). % done
add(X,[E|Es],[T|Ts]) :-
append(E,[X],T),
add(X,Es,Ts).
we can do inline using findall/3 and member/2
1 ?- [user].
|: tooAdd(X, Es, Ts) :- findall(T, (member(E,Es),append(E,[X],T)), Ts).
% user://1 compiled 71.19 sec, 2 clauses
true.
2 ?- tooAdd(g, [[e], [b, c, f], [k, h]], Yss).
Yss = [[e, g], [b, c, f, g], [k, h, g]].
I want a have a matrix of size N x N in SWI-Prolog. A possible solution could be to create a list of N lists of size N, but now sure how to code this in Prolog.
length_list(N, L) :-
length(L, N).
n_matrix(N, Xss) :-
length(Xss, N),
maplist(length_list(N),Xss).
maplist(_, []).
maplist(C, [X|Xs]) :-
call(C,X),
maplist(C, Xs).
To avoid the awkward auxiliary definition, we might use library(lambda):
n_matrix(N, Xss) :-
length(Xss, N),
maplist(N+\Xs^length(Xs,N),Xss).
I need to finish a prolog exercise, I have half of it but I need something more to finish it, that is the reason I am asking for help.
What I need is an small prolog program, given two lists (L1, L2) and one position as P, insert the first list into the second one and store that list in a third list (L3).
insert_at(L1,L2,P,L3)
Here an example:
?- insert_at ([h1,h2], [a1,a2,a3,a4], 2,L3).
L3 = [a1,h1,h2,a2,a3,a4]
The code I have for this is this one:
remove_at(X,[X|Xs],1,Xs).
remove_at(X,[Y|Xs],K,[Y|Ys]) :-
K > 1,
K1 is K - 1,
remove_at(X,Xs,K1,Ys).
insert_at(X,L,K,R) :- remove_at(X,R,K,L).
What I get is this:
?- insert_at([h1,h2],[a1,a2,a3,a4],2,L3).
L3 = [a1, [h1, h2], a2, a3, a4] % What I get
L3 = [a1, h1, h2, a2, a3, a4] % What I really want
I dont know why I get the brackets inside the list...I dont want them as I explained up.
To finish it I also need to take care about more cases:
If P is higher than the second list lenght, L1 will be inserted at the end of L2.
If we insert a non-empty list in an empty list (no matters P), we will get the inserted list.
If we insert an empty list in a non-empty list (no matters P), we will get the non-empty list.
Thanks in advance
The quick-fix solution:
insert_at(X, L, K, R) :-
remove_at(X, R1, K, L),
flatten(R1, R).
The solution involving rewriting remove_at to manage a list:
remove_at([], Y, _, Y) :- !. % added as a list base case
remove_at(_, [], _, []) :- !. % added as a list base case
remove_at([X|T], [X|Xs], 1, L) :- % handle a list [X|T] instead of just X
remove_at(T, Xs, 1, L).
remove_at(X, [Y|Xs], K, [Y|Ys]) :- % same as before :)
K > 1,
K1 is K - 1,
remove_at(X, Xs, K1, Ys).
insert_at(X, L, K, R) :- remove_at(X, R, K, L).
The second remove_at/4 base case says that if the list I want to remove from is empty, then the result is empty and it succeeds. That means insert_at/4 will succeed if K is greater than the length of L and it will return the original list, L, as the solution.
If you want the insert_at/4 to succeed when K is greater than the length of the list and instantiate R with X appended to L (rather than just L itself), you can replace remove_at(_, [], _, []) :- !. with remove_at(X, X, _, []) :- !.