Prolog: Rotate list n times right - prolog

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.

Related

How can I verify if a coordinate is in a list

I'm generating random coordinates and adding on my list, but first I need verify if that coordinate already exists. I'm trying to use member but when I was debugging I saw that isn't working:
My code is basically this:
% L is a list and Q is a count that define the number of coordinate
% X and Y are the coordinate members
% check if the coordniate already exists
% if exists, R is 0 and if not, R is 1
createCoordinates(L,Q) :-
random(1,10,X),
random(1,10,Y),
convertNumber(X,Z),
checkCoordinate([Z,Y],L,R),
(R is 0 -> print('member'), createCoordinates(L,Q); print('not member'),createCoordinates(L,Q-1).
checkCoordinate(C,L,R) :-
(member(C,L) -> R is 0; R is 1).
% transforms the number N in a letter L
convertNumber(N,L) :-
N is 1, L = 'A';
N is 2, L = 'B';
...
N is 10, L = 'J'.
%call createCoordinates
createCoordinates(L,20).
When I was debugging this was the output:
In this picture I'm in the firts interation and L is empty, so R should be 1 but always is 0, the coordinate always is part of the list.
I have the impression that the member clause is adding the coordinate at my list and does'nt make sense
First off, I would recommend breaking your problem down into smaller pieces. You should have a procedure for making a random coordinate:
random_coordinate([X,Y]) :-
random(1, 10, XN), convertNumber(XN, X),
random(1, 10, Y).
Second, your checkCoordinate/3 is converting Prolog's success/failure into an integer, which is just busy work for Prolog and not really improving life for you. memberchk/2 is completely sufficient to your task (member/2 would work too but is more powerful than necessary). The real problem here is not that member/2 didn't work, it's that you are trying to build up this list parameter on the way out, but you need it to exist on the way in to examine it.
We usually solve this kind of problem in Prolog by adding a third parameter and prepending values to the list on the way through. The base case then equates that list with the outbound list and we protect the whole thing with a lower-arity procedure. In other words, we do this:
random_coordinates(N, Coordinates) :- random_coordinates(N, [], Coordinates).
random_coordinates(0, Result, Result).
random_coordinates(N, CoordinatesSoFar, FinalResult) :- ...
Now that we have two things, memberchk/2 should work the way we need it to:
random_coordinates(N, CoordinatesSoFar, FinalResult) :-
N > 0, succ(N0, N), % count down, will need for recursive call
random_coordinate(Coord),
(memberchk(Coord, CoordinatesSoFar) ->
random_coordinates(N, CoordinatesSoFar, FinalResult)
;
random_coordinates(N0, [Coord|CoordinatesSoFar], FinalResult)
).
And this seems to do what we want:
?- random_coordinates(10, L), write(L), nl.
[[G,7],[G,3],[H,9],[H,8],[A,4],[G,1],[I,9],[H,6],[E,5],[G,8]]
?- random_coordinates(10, L), write(L), nl.
[[F,1],[I,8],[H,4],[I,1],[D,3],[I,6],[E,9],[D,1],[C,5],[F,8]]
Finally, I note you continue to use this syntax: N is 1, .... I caution you that this looks like an error to me because there is no distinction between this and N = 1, and your predicate could be stated somewhat tiresomely just with this:
convertNumber(1, 'A').
convertNumber(2, 'B').
...
My inclination would be to do it computationally with char_code/2 but this construction is actually probably better.
Another hint that you are doing something wrong is that the parameter L to createCoordinates/2 gets passed along in all cases and is not examined in any of them. In Prolog, we often have variables that appear to just be passed around meaninglessly, but they usually change positions or are used multiple times, as in random_coordinates(0, Result, Result); while nothing appears to be happening there, what's actually happening is plumbing: the built-up parameter becomes the result value. Nothing interesting is happening to the variable directly there, but it is being plumbed around. But nothing is happening at all to L in your code, except it is supposedly being checked for a new coordinate. But you're never actually appending anything to it, so there's no reason to expect that anything would wind up in L.
Edit Notice that #lambda.xy.x solves the problem in their answer by prepending the new coordinate in the head of the clause and examining the list only after the recursive call in the body, obviating the need for the second list parameter.
Edit 2 Also take a look at #lambda.xy.x's other solution as it has better time complexity as N approaches 100.
Since i had already written it, here is an alternative solution: The building block is gen_coord_notin/2 which guarantees a fresh solution C with regard to an exclusion list Excl.
gen_coord_notin(C, Excl) :-
random(1,10,X),
random(1,10,Y),
( memberchk(X-Y, Excl) ->
gen_coord_notin(C, Excl)
;
C = X-Y
).
The trick is that we only unify C with the new result, if it is fresh.
Then we only have to fold the generations into N iterations:
gen_coords([], 0).
gen_coords([X|Xs], N) :-
N > 0,
M is N - 1,
gen_coords(Xs, M),
gen_coord_notin(X, Xs).
Remark 1: since coordinates are always 2-tuples, a list representation invites unwanted errors (e.g. writing [X|Y] instead of [X,Y]). Traditionally, an infix operator like - is used to seperate tuples, but it's not any different than using coord(X,Y).
Remark 2: this predicate is inherently non-logical (i.e. calling gen_coords(X, 20) twice will result in different substitutions for X). You might use the meta-level predicates var/1, nonvar/1, ground/1, integer, etc. to guard against non-sensical calls like gen_coord(1-2, [1-1]).
Remark 3: it is also important that the conditional does not have multiple solutions (compare member(X,[A,B]) and memberchk(X,[A,B])). In general, this can be achieved by calling once/1 but there is a specialized predicate memberchk/2 which I used here.
I just realized that the performance of my other solutions is very bad for N close to 100. The reason is that with diminishing possible coordinates, the generate and test approach will take longer and longer. There's an alternative solution which generates all coordinates and picks N random ones:
all_pairs(Ls) :-
findall(X-Y, (between(1,10,X), between(1,10,Y)), Ls).
remove_index(X,[X|Xs],Xs,0).
remove_index(I,[X|Xs],[X|Rest],N) :-
N > 0,
M is N - 1,
remove_index(I,Xs,Rest,M).
n_from_pool(_Pool, [], 0).
n_from_pool(Pool, [C|Cs], N) :-
N > 0,
M is N - 1,
length(Pool, L),
random(0,L,R),
remove_index(C,Pool,NPool,R),
n_from_pool(NPool, Cs, M).
gen_coords2(Xs, N) :-
all_pairs(Pool),
n_from_pool(Pool, Xs, N).
Now the query
?- gen_coords2(Xs, 100).
Xs = [4-6, 5-6, 5-8, 9-6, 3-1, 1-3, 9-4, 6-1, ... - ...|...] ;
false.
succeeds as expected. The error message
?- gen_coords2(Xs, 101).
ERROR: random/1: Domain error: not_less_than_one' expected, found0'
when we try to generate more distinct elements than possible is not nice, but better than non-termination.

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

Prolog - writing a combination of k numbers in the given list

I am trying to define a function in prolog that takes arguments of the form combination(3,[a,b,c,d],L) , the result returns
L=a,b,c
L=a,b,d
L=a,c,d
L=b,c,d
My implementation is as follows:
combination(K,argList,L):-
unknown(X,argList,Y),
Z is select(X,argList),
length(Z,K),
L is Z,
combination(K,Z,L).
unknown(X,[X|L],L).
unknown(X,[_|L],R) :- unknown(X,L,R).
The unknown predicate behaves as follows:
![enter image description here][1]
Please help.
The simplest solution that comes to mind using your definition of unknown/3 is:
combination(0, _, []) :-
!.
combination(N, L, [V|R]) :-
N > 0,
NN is N - 1,
unknown(V, L, Rem),
combination(NN, Rem, R).
unknown(X,[X|L],L).
unknown(X,[_|L],R) :-
unknown(X,L,R).
Explanation: the second clause of combination/3 looks to select an element from the list L, which the predicate unknown/3 does in a linear manner, returning the remainder, Rem. Once the number of elements selected out of list L exceeds N, the base case is triggered (the first clause of combination/3) which terminates the branch. Note that the definition of combination/3 relies on the non-deterministic nature of unknown/3 which leaves choice-points for selecting alternate list elements.

Comparing two list?

I'm trying to compare two lists by length and set the output to true or false.
min(List1, List2, output) :-
length(List1, N),
length(List2, M),
output is N<M.
But I keep getting errors, what's the syntax for the lists?
A couple of problems here; #Enigmativity is right in that you need to make Output variable, but is/2 isn't defined over the operator < (it's used to evaluate arithmetic expressions such as +, or those that are user defined).
Instead, consider the following:
min(List1, List2, Output) :-
length(List1, N),
length(List2, M),
(N < M ->
Output = 'true'
; Output = 'false'
).
Here, N < M is a logical test which either succeeds or fails. If N < M is true, implication -> directs the interpreter to bind the Output variable to the atom 'true', else to 'false', indicating the length relationship between the lists that you've asked for. You can bind anything here as you like, not just atoms.
Executing this gives:
?- min([1,2,3,4],[1,2],Output).
Output = false.
If you want min/3 to simply return the smaller of the two input lists, you can try:
min(List1, List2, Output) :-
length(List1, N),
length(List2, M),
(N < M ->
Output = List1
; Output = List2
).
Executing this on the same example gives:
?- min([1,2,3,4],[1,2],X).
X = [1, 2].
This might run faster than solutions than compare the lengths if there is a small and a very large list (as it will stop as soon as the end of the smallest list is reached).
min_list([_|L1t], [_|L2t], Output) :- min(L1t, L2t, Output), !.
min_list(_, [], false).
min_list([], _, true).
About the list syntax all you need to know is that lists are expressed as [Head|Tail] where Head is the first element of the list and Tail a sublist containing the rest of elements.
The ! is the cut operator to avoid backtracking for exploring other solutions (if you don't use it there, the system will wait for you to press the semicolon if you want another answer, and then it will say false).
Predicate variables that are not used are expressed as an underscore (otherwise you will get a warning about singleton variables).
The simple change here is:
min(List1, List2, Output) :-
length(List1, N),
length(List2, M),
Output is N<M.
Output is a variable, not a term, so it should start with an upper-case character.
Does that solve your problem?

Resources