Split a list multiple time in Prolog - prolog

this my code :
div2(L,N,L1,L2) :-
length(L1,N),%n=4
append(L1,L2, L),
L=L2,L1=[],L2=[].
i want it to display each time in L1 a 4 element list but it return false.
example :
L=[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]
L1=[1,2,3,4]
L1=[5,6,7,8]
L1=[9,10,11,12]
L1=[13,14,15,16]
how can i make it work. and thanks for the help.

Assuming you want div(L,N,L1,L2) to be that L1 is the first N element of L, and L2 is what remains:
div2(L,N,L1,L2) :-
length(L1,N),
append(L1,L2,L).
There are no other conditions that need to be placed on L, L1 or L2.
If you want to be the first 4 elements after some multiple of 4 elements, and L2 to be the rest, you need to say so:
div2(L,N,L1,L2) :-
append(L01,L2,L), % break up L
length(L01,Nx), % make sure prefix's length is multiple of N
0 is mod(Nx,N),
append(L0,L1,L01),% set L1 to be last N elements of prefix
length(L1,N).

A slightly different solution...
div2([X|Xs], N, P) :-
( length(P1, N),
append(P1, R, [X|Xs])
-> ( P = P1
; div2(R, N, P)
)
; P = [X|Xs]
).
This solution defines a list P1 of length N, and attempts to unify it (with append as a prefix list of [X|Xs]. ([X|Xs] is used instead of L to ensure that the predicate succeeds only if the first argument is a list with at least one element.)
If the append is successful, then the solution is either P1 (P is unified with P1) or a recursive call to div2 with the remainder of the first argument list with the prefix P1 absent.
If the append fails (which will happen if the number of partition elements N is larger than the first argument list length), then P is unified with the first argument list.

Related

Comparing a list with lists in another list in Prolog

I have two lists:
L1 = [[a,b,c], [e,b,d], [f,g,a]]
L2 = [a,e]
I want to compare L2 with each list in L1 and find the number of common items. I am trying following code:
common([],L).
common([H|T], L, Out):-
intersection(H,L,Out), common(T, L, Out),
length(Out,Len).
However, it is not working:
?- common([[a,b,c], [e,b,d], [f,g,a]], [a,e], Outlist).
false.
The main list remains list in list (as seen after debugging with writeln statements):
L is:
[a,e]
H|T is:
[[f,g,a]]
Outlist = [] .
Where is the problem and how can I correct this?
I edited the code to debug and found that somehow it has started working:
common([],L,Out).
common([H|T], L, Out):-
writeln('------------in common--------------'),
writeln('L is:'), writeln(L),
writeln('H is:'), writeln(H),
intersection(L,H,Out2list),
writeln('Out2list is:'), writeln(Out2list),
common(T, L, Out2).
41 ?- common([[a,b,c], [e,b,d], [f,g,a]], [a,e], Outlist).
------------in common--------------
L is:
[a,e]
H is:
[a,b,c]
Out2list is:
[a]
------------in common--------------
L is:
[a,e]
H is:
[e,b,d]
Out2list is:
[e]
------------in common--------------
L is:
[a,e]
H is:
[f,g,a]
Out2list is:
[a]
true.
First let's observe that you have written a predicate common/2 and a predicate common/3. Reading your question, I assume you intend the former to be the base case for common/3. Thinking about the relation you want to describe, it would make sense to define that the intersection of the empty list and any other list is the empty list:
common([],_,[]).
However, it is not entirely clear what you expect the third argument to be. In your question you write that it should be the number of common items. The use of length/2 in your predicate common/3 supports this interpretation. In this case you want to have the lengths of the respective intersections in the third list:
common([],_,[]).
common([H|T], L, [Len|Out]):- % Len is in the 3rd list
intersection(H,L,I), % I is intersection of H and L
length(I,Len), % Len is length of I
common(T, L, Out). % the same for T, L and Out
With this version your example query yields:
?- common([[a,b,c], [e,b,d], [f,g,a]],[a,e],I).
I = [1,1,1]
In your first comment however, you write that you want Outlist to be [a]. That suggests that you want lists instead of numbers in the third argument. But looking at your example query [a] can not be the answer. On the one hand, if you mean that you want to see all the intersections of the elements of the first list with the second argument, you might like to write something like:
common2([],_,[]).
common2([H|T], L, [I|Out]):- % I is in the third list
intersection(H,L,I), % I is intersection of H and L
common2(T, L, Out). % the same for T, L and Out
This yields with your example:
?- common2([[a,b,c], [e,b,d], [f,g,a]],[a,e],I).
I = [[a],[e],[a]]
On the other hand, if you mean that you want to see the intersection of all the lists of the first argument with the second argument, you might like to go with something like this:
common3([],_,[]). % special case empty list
common3([H|T],L,I) :- % if 1st list not empty
common3_([H|T],L,I). % I is described in common3_/3
common3_([],I,I). % if the list is empty I = Outlist
common3_([H|T], L, O) :-
intersection(H,L,I), % I is intersection of H and L
common3_(T,I,O). % only the elements in I can be in O
With your example lists this yields
?- common3([[a,b,c], [e,b,d], [f,g,a]],[a,e],I).
I = []
since neither a nor e occur in all three lists. But if you add a to the second list:
?- common3([[a,b,c], [e,b,d,a], [f,g,a]],[a,e],I).
I = [a]

Prolog inserting multiple elements into list

I want to implement a predicate (vecLine2BitLine) which does the following:
get two lists and a number the first list is the length of blocks (the elements of the blocks are '$') and the second list contains the indexes that these blocks should be placed at meaning:
vecLine2BitLine([1,2,1],[2,5,9],12,BitLine).
BitLine=[' ','$',' ',' ','$','$',' ',' ','$',' ',' ',' '].
explanation:a block of length 1 is at index 2
and a block of length 2 is at index 5 and so on..
insert_at_mul : inserts an element N times (it works perfectly,dupli and my_flatten were implemented previously so i used them)
Ive been trying to activate insert_at_mul N times when N is the length of the list X and Y
in the predicate vecLine2BitLine.
dupli(L1,N,L2) :- dupli(L1,N,L2,N).
dupli([],_,[],_).
dupli([_|Xs],N,Ys,0) :- dupli(Xs,N,Ys,N).
dupli([X|Xs],N,[X|Ys],K) :- K > 0, K1 is K - 1, dupli([X|Xs],N,Ys,K1).
my_flatten(X,[X]) :- \+ is_list(X).
my_flatten([],[]).
my_flatten([X|Xs],Zs) :- my_flatten(X,Y), my_flatten(Xs,Ys), append(Y,Ys,Zs).
insert_at_mul(L,X,K,R,N):-dupli([X],N,XX) , insert_at(L,XX,K,L1) , my_flatten(L1,R).
get_num_spaces(L,N,X):-sum(L,S), X is N-S.
generate_spaces(N,L,X):- insert_at_mul(L,'',1,X,N).
vecLine2BitLineAux([],[],_,_,_).
vecLine2BitLineAux([X|Tail1],[Y|Tail2],N,L,Lnew):- insert_at_mul(L,'*',Y,Lnew,X) ,vecLine2BitLineAux(Tail1,Tail2,N,Lnew,R). // problem here!!!
vecLine2BitLine(X,Y,N,L):- get_num_spaces(X,N,Z) , generate_spaces(Z,[],ZZ) , vecLine2BitLineAux(X,Y,N,ZZ,L).
now the problem is that in the function vecLine2BitLine i cant activate insert_at_mul N times(thats what i tried to do in this code, but failed).
how can I fix vecLine2BitLine for it to work properly as in returning the correct output by actually activating the predicate insert_at_mul N times??
THANKS!
added :
vecLine2BitLine : input parameters : (L1,L2,N,Result)
N: after activating the predicate Result will be N in length.
L1: L1 is a list of numbers each number indicates the length of a block, a block is comprised of a Sequence of '$'.
L2: L2 is a list of numbers the numbers are indices for where the blocks in L1 should be placed.
example:
vecLine2BitLine([3,2],[1,5],9,BitLine).
we can look at the input better as tuples :
vecLine2BitLine[(3,1),(2,5)],9,BitLine).
(3,1) : there is a sequence of '' 3 times at index 1
(2,5) : there is a sequence of '' 2 times at index 5
in our example 9 is the length of BitLine at the end and we have to insert into the
list BitLine 3+2 of the "special chars" '*' but we have 9-(3+2) places left in the list
so we add '' in those places and then we get:
BitLine=['$','$','$','','$','$','','','',''].
This is kind of a nice problem because you can use the arguments as loop counters. The K argument gets you to the proper index. Let's just traverse the list and find a particular index as an example. Notice the base case is that you're at the right element, and the inductive case is prior to the right element.
traverse(1, [X|_], X).
traverse(N, [_|Xs], X) :- N > 0, N0 is N-1, traverse(N0, Xs, X).
We're going to apply that pattern to insert_at/4 to get to the right location in the list. Now let's write a repeat/3 predicate that repeats X N times in a new list L. This time the base case is when we've added all the repetitions we care to, and the inductive case is that we'll add another instance.
repeat(1, X, [X]).
repeat(N, X, [X|Xs]) :- N > 0, N0 is N-1, repeat(N0, X, Xs).
You can see the similarity of structure between these two. Try to combine them into a single predicate. Since this is homework, I'll stop here. You're inches from the goal.

Prolog: Rotate list n times right

Working on a predicate, rotate(L,M,N), where L is a new list formed by rotating M to the right N times.
My approach was to just append the tail of M to its head N times.
rotate(L, M, N) :-
( N > 0,
rotate2(L, M, N)
; L = M
).
rotate2(L, [H|T], Ct) :-
append(T, [H], L),
Ct2 is Ct - 1,
rotate2(L, T, Ct2).
Currently, my code returns L equal to the original M, no matter what N is set to.
Seems like when I'm recursing, the tail isn't properly moved to the head.
You can use append to split lists, and length to create lists:
% rotate(+List, +N, -RotatedList)
% True when RotatedList is List rotated N positions to the right
rotate(List, N, RotatedList) :-
length(Back, N), % create a list of variables of length N
append(Front, Back, List), % split L
append(Back, Front, RotatedList).
Note: this only works for N <= length(L). You can use arithmetic to fix that.
Edit for clarity
This predicate is defined for List and N arguments that are not variables when the predicate is called. I inadvertently reordered the arguments from your original question, because in Prolog, the convention is that strictly input arguments should come before output arguments. So, List and N and input arguments, RotatedList is an output argument. So these are correct queries:
?- rotate([a,b,c], 2, R).
?- rotate([a,b,c], 1, [c,a,b]).
but this:
?- rotate(L, 2, [a,b,c]).
will go into infinite recursion after finding one answer.
When reading the SWI-Prolog documentation, look out for predicate arguments marked with a "?", as in length. They can be used as shown in this example.

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).

How to bypass assigning an empty list to procedure's argument of the form [X|L]?

I have the following program:
% finds all members in sorted list L1 that are not in the sorted L2
% and puts them in NL
make_list(L1,L2,NL):-
make_list(L1,L2,NL,x).
make_list([],_,[],_):-!.
% X represents the last value parsed from L1
make_list(L1,[],L2,X):-!,
make_list(L1,[99999999],L2,X).
make_list([X1|L1],[X2|L2],[X3|NewL],Last):-
(
(X1<X2,
X1 \= Last,
X3=X1,!,
make_list(L1,[X2|L2],NewL,X1);
X1<X2,!,
make_list(L1,[X2|L2],[X3|NewL],X1)
)
);
(
X1=X2,!,
make_list(L1,[X2|L2],[X3|NewL],*)
);
make_list([X1|L1],L2,[X3|NewL],*).
My problem is that when the last values are the same (i.e: ?- make_list([1,2],[2],L). ), the code doesn't work because of
make_list([X1|L1],L2,[X3|NewL],*).
and
make_list(L1,[X2|L2],[X3|NewL],*)
which passes a list with at least one variable (the 3rd list) to make_list([],_,[],_). There is a comment that says what the program does. How to make the code do what it supposed to do?
I also asked a question about the same but completely not working code here: How do parenthesis work? .
You should consider six mutually exclusive cases when solving this problem:
You run out of elements in both lists
You run out of elements in the first list, but not in the second
You run out of elements in the second list, but not in the first
Both lists have at least one element, and the head elements match
Both lists have at least one element, and the head element of the first list is smaller
Both lists have at least one element, and the head element of the first list is greater
These six combinations cover the rules that you need to write.
The first two cases can be covered by a single rule:
make_list([], _, []).
This means that if the first list is empty, there will be nothing to add to the output list.
The third case is simple too: if the second list is empty, the output is the same as the first list:
make_list(L1, [], L1).
Case number four is slightly less trivial: if the heads unify, drop them both at the same time, and solve a smaller sub-problem:
make_list([H|T1], [H|T2], NL) :-
make_list(T1, T2, NL).
Case number five inserts the head of the first list into the output, and case number six skips the head of the second list:
make_list([H1|T1], [H2|T2], NL) :-
H1 < H2,
make_list(T1, [H2|T2], N2),
NL = [H1|N2].
make_list([H1|T1], [H2|T2], NL) :-
H1 > H2,
make_list([H1|T1], T2, NL).
Note that this solution does not work as expected when the first list contains duplicates, and the second list does not contain duplicates of the corresponding elements.
% finds all members in sorted list L1 that are not in the sorted L2
% and puts them in NL
make_list(L1,L2,NL):-
make_list(L1,L2,NL,x).
make_list([],_,[],_):-!.
% X represents the last value parsed from L1
make_list(L1,[],L2,X):-!,
make_list(L1,[99999999],L2,X).
the problem here was that NewL was [X3|NewL] and when L1 was empty, the make_list([],_,[],_):-!. was failed because [X3|NewL] cannot assign with []
make_list([X1|L1],[X2|L2],NewL,Last):-
X1<X2,
X1 \= Last,
NewL = [X3|NewL2],X3=X1,
make_list(L1,[X2|L2],NewL2,X1),!
;
X1<X2,
make_list(L1,[X2|L2],NewL,X1),!.
make_list([X1|L1],[X1|L2],NewL,Last):-!,
make_list(L1,[X1|L2],NewL,Last).
this next two cases is when X1>X2, X2 is ignored anyway, X1 ignored only if X1=Last
make_list([X1|L1],[_|L2],NewL,X1):-!, % X1>X2
make_list(L1,L2,NewL,X1).
make_list([X1|L1],[_|L2],NewL,Last):- % X1>X2
make_list([X1|L1],L2,NewL,Last).

Resources