Prolog: create a list of empty lists - prolog

I'm working on creating a board used for the Bert Bos puzzle, and I'm trying to represent the board as a list of lists.
I need to create a list of empty lists ex [ [], [] , [] , [] ] but the problem is I need the exact number of empty lists provided from the input. So for example if I give create_board(4,X), it should return X= [ [], [], [], [] ].
Here is what I have so far
generate_board(0, [[]]) :- !
generate_board(N, [[] | T]) :-
N =< 12, N >= 1,
N is N-1.
generate_board(N, T).

An easy way to create a list of a given length consisting of the same element, or just empty lists in this case, is to use maplist2:
generate_board(Length, Board) :-
length(Board, Length),
maplist(=([]), Board).
Here, maplist(=([]), Board) will call =([], Element) (the canonical form of [] = Element) for each Element in Board, thus unifying each element with []:
| ?- generate_board(4, L).
L = [[],[],[],[]]
yes
| ?-
You can extend this concept to do a two-dimensional empty board. Think of the board as a list of rows (with length Length) and each row as a list of elements (with length Width):
generate_board(Length, Width, Board) :-
length(Row, Width),
maplist(=([]), Row), % A row of empty lists, forming an empty row
length(Board, Length),
maplist(=(Row), Board). % A list of empty rows
| ?- generate_board(4,3, L).
L = [[[],[],[]],[[],[],[]],[[],[],[]],[[],[],[]]]
yes
| ?-

Here is just the reason why your program did not work (apart from the . in place of ,). Because this fragment fails, also your original program fails. You have to generalize the visible part somehow.
:- op(950,fy,*).
*_.
generate_board(0, [[]]) :- !
generate_board(N, _/*[[] | T]*/) :- % 2nd
* N =< 12, % 2nd
* N >= 1, % 2nd
N is N-1,
* generate_board(N, T). % 1st generalization
?- generate_board(4, B).
This method works for pure, monotonic Prolog programs. You have, however, used a cut which restricts generalization. In this case, one really has to pay attention not to generalize anything prior to the cut. The first generalization is thus the recursive goal. It is the very last goal in the clause. Only then, the other generalizations may take place
In your program without the cut, we could have generalized your program even further:
generate_board(0, _/*[[]]*/).
...

A simple solution:
generate_board(N, Board) :-
findall([], between(1, N, _), Board).

Apart from a couple of syntax errors, the main problem with your code is the line N is N-1. In Prolog, you cannot 're-assign' a variable. A variable has a single value throughout a predicate. 'N is N-1` can only succeed for a value which is equal to itself minus 1, which will obviously never be the case.
Fixing it is simple: just use a different variable for the reduced value:
generate_board(0, [[]]) :- !.
generate_board(N, [[] | T]) :-
N =< 12, N >= 1,
N2 is N-1,
generate_board(N2, T).
?- generate_board(4, X).
X = [[], [], [], [], []]
This gives a result, but it's one more element than intended. Can you figure out how to fix this yourself (hint: look at what the base case returns for input 0)

Related

Prolog - count occurrence of number

I want to write predicate which can count all encountered number:
count(1, [1,0,0,1,0], X).
X = 2.
I tried to write it like:
count(_, [], 0).
count(Num, [H|T], X) :- count(Num, T, X1), Num = H, X is X1 + 1.
Why doesn't work it?
Why doesn't work it?
Prolog is a programming language that often can answer such question directly. Look how I tried out your definition starting with your failing query:
?- count(1, [1,0,0,1,0], X).
false.
?- count(1, Xs, X).
Xs = [], X = 0
; Xs = [1], X = 1
; Xs = [1,1], X = 2
; Xs = [1,1,1], X = 3
; ... .
?- Xs = [_,_,_], count(1, Xs, X).
Xs = [1,1,1], X = 3.
So first I realized that the query does not work at all, then I generalized the query. I replaced the big list by a variable Xs and said: Prolog, fill in the blanks for me! And Prolog did this and reveals us precisely the cases when it will succeed.
In fact, it only succeeds with lists of 1s only. That is odd. Your definition is too restricted - it correctly counts the 1s in lists where there are only ones, but all other lists are rejected. #coder showed you how to extend your definition.
Here is another one using library(reif) for
SICStus|SWI. Alternatively, see tfilter/3.
count(X, Xs, N) :-
tfilter(=(X), Xs, Ys),
length(Ys, N).
A definition more in the style of the other definitions:
count(_, [], 0).
count(E, [X|Xs], N0) :-
if_(E = X, C = 1, C = 0),
count(E, Xs, N1),
N0 is N1+C.
And now for some more general uses:
How does a four element list look like that has 3 times a 1 in it?
?- length(L, 4), count(1, L, 3).
L = [1,1,1,_A], dif(1,_A)
; L = [1,1,_A,1], dif(1,_A)
; L = [1,_A,1,1], dif(1,_A)
; L = [_A,1,1,1], dif(1,_A)
; false.
So the remaining element must be something different from 1.
That's the fine generality Prolog offers us.
The problem is that as stated by #lurker if condition (or better unification) fails then the predicate will fail. You could make another clause for this purpose, using dif/2 which is pure and defined in the iso:
count(_, [], 0).
count(Num, [H|T], X) :- dif(Num,H), count(Num, T, X).
count(Num, [H|T], X) :- Num = H, count(Num, T, X1), X is X1 + 1.
The above is not the most efficient solution since it leaves many choice points but it is a quick and correct solution.
You simply let the predicate fail at the unification Num = X. Basically, it's like you don't accept terms which are different from the only one you are counting.
I propose to you this simple solution which uses tail recursion and scans the list in linear time. Despite the length, it's very efficient and elegant, it exploits declarative programming techniques and the backtracking of the Prolog engine.
count(C, L, R) :-
count(C, L, 0, R).
count(_, [], Acc, Acc).
count(C, [C|Xr], Acc, R) :-
IncAcc is Acc + 1,
count(C, Xr, IncAcc, R).
count(C, [X|Xr], Acc, R) :-
dif(X, C),
count(C, Xr, Acc, R).
count/3 is the launcher predicate. It takes the term to count, the list and gives to you the result value.
The first count/4 is the basic case of the recursion.
The second count/4 is executed when the head of the list is unified with the term you are looking for.
The third count/4 is reached upon backtracking: If the term doesn’t match, the unification fails, you won't need to increment the accumulator.
Acc allows you to scan the entire list propagating the partial result of the recursive processing. At the end you simply have to return it.
I solved it myself:
count(_, [], 0).
count(Num, [H|T], X) :- Num \= H, count(Num, T, X).
count(Num, [H|T], X) :- Num = H, count(Num, T, X1), X is X1 + 1.
I have decided to add my solution to the list here.
Other solutions here use either explicit unification/failure to unify, or libraries/other functions, but mine uses cuts and implicit unification instead. Note my solution is similar to Ilario's solution but simplifies this using cuts.
count(_, [], 0) :- !.
count(Value, [Value|Tail],Occurrences) :- !,
count(Value,Tail,TailOcc),
Occurrences is TailOcc+1.
count(Value, [_|Tail], Occurrences) :- count(Value,Tail,Occurrences).
How does this work? And how did you code it?
It is often useful to equate solving a problem like this to solving a proof by induction, with a base case, and then a inductive step which shows how to reduce the problem down.
Line 1 - base case
Line 1 (count(_, [], 0) :- !.) handles the "base case".
As we are working on a list, and have to look at each element, the simplest case is zero elements ([]). Therefore, we want a list with zero elements to have no instances of the Value we are looking for.
Note I have replaced Value in the final code with _ - this is because we do not care what value we are looking for if there are no values in the list anyway! Therefore, to avoid a singleton variable we negate it here.
I also added a ! (a cut) after this - as there is only one correct value for the number of occurrences we do not want Prolog to backtrack and fail - therefore we tell Prolog we found the correct value by adding this cut.
Lines 2/3 - inductive step
Lines 2 and 3 handle the "inductive step". This should handle if we have one or more elements in the list we are given. In Prolog we can only directly look at the head of the list, therefore let us look at one element at a time. Therefore, we have two cases - either the value at the head of the list is the Value we are looking for, or it is not.
Line 2
Line 2 (count(Value, [Value|Tail],Occurrences) :- !, count(Value,Tail,TailOcc), Occurrences is TailOcc+1.) handles if the head of our list and the value we are looking for match. Therefore, we simply use the same variable name so Prolog will unify them.
A cut is used as the first step in our solution (which makes each case mutually exclusive, and makes our solution last-call-optimised, by telling Prolog not to try any other rules).
Then, we find out how many instances of our term there are in the rest of the list (call it TailOcc). We don't know how many terms there are in the list we have at the moment, but we know it is one more than there are in the rest of the list (as we have a match).
Once we know how many instances there are in the rest of the list (call this Tail), we can take this value and add 1 to it, then return this as the last value in our count function (call this Occurences).
Line 3
Line 3 (count(Value, [_|Tail], Occurrences) :- count(Value,Tail,Occurrences).) handles if the head of our list and the value we are looking for do not match.
As we used a cut in line 2, this line will only be tried if line 2 fails (i.e. there is no match).
We simply take the number of instances in the rest of the list (the tail) and return this same value without editing it.

Deleting first N prime numbers from a list (Prolog)

Basically I want to remove the first N numbers from a list, the function that checks whether a number is prime or not seems to work well but the program itself doesn't
For example for input [2,4,5,7,6,9,11] and N = 3 I should get [4, 6, 9, 11] but I get only [4, 6, 9].
divisible(X,Y) :-
0 is X mod Y, !.
divisible(X,Y) :-
X > Y+1,
divisible(X, Y+1).
%isPrime function check whether or not the argument is a prime number
isPrime(2) :- true,!.
isPrime(X) :- X < 2,!,false.
isPrime(X) :- not(divisible(X, 2)).
%delFunction (input_list, N, output_list)
delFunction([],_,_).
delFunction(_,0,_).
delFunction([H|T], N, [H|Res]):-
not(isPrime(H)), !,
delFunction(T, N, Res).
delFunction([_|T], N, Res):-
N1 is N-1,
delFunction(T,N1,Res).
delFunction([2,4,5,7,6,9,11],3,X) -> [4,6,9] (which is not the correct answer)
Honestly, I don't know where I went wrong, the implementation idea seems pretty easy and straight forward, so is the code.
Also, when I run it it stops at [4] and I have to keep on clicking next to get me to the end of the execution (thus the result). Any idea how to fix it? I'm thinking maybe I need some cuts but not sure where.
P.S: I'd rather not use built-in functions (if there are any that would help in this scenario)
Fists of all, instead of
delFunction([],_,_).
you should write
delFunction([],_,[]).
because when the input list (the left one) is empty, you have to construct the base for the output list: an empty list; with delFunction([], _, _) you don't unify the output list with the empty list so the result end with an not unified variable.
Second. Instead of
delFunction(_,0,_).
you should write
delFunction(L,0,L).
The problem is the same: when number is zero you can "copy" the input in the output; that is, you can unify they; that is delFunction(L,0,L). With delFunction(_,0,_) you don't unify and the result ends with a not unified variable.
Third. In the is-prime clause
delFunction([_|T], N, Res):-
N1 is N-1,
delFunction(T,N1,Res).
you should check that N is greater than zero
delFunction([_|T], N, Res):-
N > 0,
N1 is N-1,
delFunction(T,N1,Res).
or, if you prefer, you should add a cut (!) in the zero clause
delFunction(L,0,L) :- !.
Just to avoid that Prolog, via backtracking, can give multiple undesired answers.
--- EDIT ---
As Guy Coder, I avoid cuts like a plague; so I propose the following solution to avoid unwanted repetitions.
delFunction([], _, []).
delFunction([H | T], 0, [H | T]).
delFunction([H | T], N, [H | Res]) :-
N > 0,
not(isPrime(H)),
delFunction(T, N, Res).
delFunction([H | T], N, Res):-
N > 0,
isPrime(H),
N1 is N-1,
delFunction(T, N1, Res).

prolog - confusing behaviour of prolog code (beginner)

Here is my code.
equals2(X,Y,N,I):- X is Y,I is N+1; I is N.
elemNum(X,[],0).
elemNum(X,[Y|Ys],N) :- elemNum(X,Ys,N1),equals2(X,Y,N1,I),N is I.
lemNum first argument is element from array, second is array. It counts the number of elements in array.
Then in console
| ?- elemNum(1,[1,2,3,1,1],N),N<2.
N = 1 ?
yes
I am sure than my function elemNum works just fine. How its possible that in console this assertion returns 1?
Thanks for help
Non sure to understand what do you want ... but I suppose that you want count the number of element in the list (second argument of elemNum/3) that are equals to the first argument.
If so, you should modify equals2/4 as follows
equals2(X,Y,N,I):- X is Y,I is N+1; X \== Y, I is N.
or better (IMHO) split it in 2 different clauses
equals2(X,X,N,I):- I is N+1.
equals2(X,Y,N,N):- X \== Y.
With your equal2/4, the second or case (I is N) is executed (in backtracking) even when X is equal to Y so elemNum(1,[1,2,3,1,1],N) unifiy N with 3, 2, 2 again, 1, 2, 1, 1 again and 0.
Regarding elemNum/3, works but you can semplify it (avoiding a warning) as
elemNum(_,[],0).
elemNum(X,[Y|Ys],I) :- elemNum(X,Ys,N1), equals2(X,Y,N1,I).
or you can rewrite it, avoiding the use of equals2/4 as
elemNum(_, [], 0).
elemNum(X, [X | Ys], I) :- elemNum(X, Ys, I0), I is I0+1.
elemNum(X, [Y | Ys], I) :- X \== Y, elemNum(X, Ys, I).

Fact for each element of a list Prolog

I want to solve this problem in Prolog. i want give a list of natural numbers to find all the elements in the list that satisfy this condition:
All elements on the left of it are smaller than it and all the elements on the right of it are larger than it.
For example give a list [3,2,4,1,5,7,8,9,10,8] the answer would be 5,7
So far I've manage to make this function that given an element of the list it returns true or false if the element satisfises the condition described above.
check(Elem, List) :-
seperate(Elem, List, List1, List2),
lesser(Elem, List1, X1),
bigger(Elem, List2, X2),
size(X1, L1),
size(X2, L2),
size(List, L3),
match(L1, L2, L3),
Now I want to make another predicate that given a list, it does the above computations for each element of the list. Due to the fact that more than one element may satisfy it I want to create another list with all the elements that satisfy the problem.
The question would be something like ?-predicate_name([[3,2,4,1,5,7,8,9,10,8],N). and the result would be a list of elements.
Sry If I am not using the right terms of Prolog. I will describe what I want to do in sequential logic language to be more specific although it's not a good idea to think like that. If we consider a the predicate check as a function that given a list and element of the list it would return true or false whether or not the element satisfied the conditions of the problem. Now I want to parse each element of the list and for each one of it call the function check. If that would return true then I would add the element in another list a.k.a result. I want to do this in Prolog but I don't know how to iterate a list.
Here is a version using DCGs and assuming we want to compare arithmetically.
list_mid(L, M) :-
phrase(mid(M), L).
mid(M) -->
seq(Sm),
[M],
{maplist(>(M),Sm)},
seq(Gr),
{maplist(<(M),Gr)}.
seq([]) -->
[].
seq([E|Es]) -->
[E],
seq(Es).
Often it is not worth optimizing this any further. The first seq(Sm) together with the subsequent maplist/2 might be merged together. This is a bit tricky, since one has to handle separately the cases where Sm = [] and Sm = [_|_].
mid(M) -->
( [M]
| max(Mx),
[M],
{Mx < M}
),
min(M).
max(M) -->
[E],
maxi(E, M).
maxi(E, E) -->
[].
maxi(E, M) -->
[F],
{G is max(F,E)},
maxi(G, M).
min(_) -->
[].
min(M) -->
[E],
{M < E},
min(M).
I'm going to take a different approach on the problem.
We want to find all of the values that meet the criteria of being a "mid" value, which is one defined as being greater than all those before it in the list, and less than all those after.
Define a predicate mid(L, M) as meaning M is a "mid" value of L:
mid([X|T], X) :- % The first element of a list is a "mid" if...
less(X, T). % it is less than the rest of the list
mid([X|T], M) :- % M is a "mid" of [X|T] if...
mid(T, X, M). % M is a "mid" > X
% (NOTE: first element is not a "mid" by definition)
mid([X|T], LastM, X) :- % X is a "mid" > Y if...
X > LastM, % X > the last "mid"
less(X, T). % X < the rest of the list, T
mid([X|T], LastM, M) :- % Also, M is a "mid" if...
Z is max(X, LastM), % Z is the larger of X and the last "mid"
mid(T, Z, M). % M is the "mid" of T which is > Z
less(X, [Y|T]) :- % X is less than the list [Y|T] if...
X < Y, % X < Y, and
less(X, T). % X < the tail, T
less(_, []). % An element is always less than the empty list
Each query will find the next "mid":
| ?- mid([3,2,4,1,5,7,8,9,10,8], M).
M = 5 ? ;
M = 7 ? ;
no
Then they can be captured with a findall:
mids(L, Ms) :-
findall(M, mid(L, M), Ns).
| ?- mids([3,2,4,1,5,7,8,9,10,8], Ms).
Ms = [5,7]
yes
| ?- mids([2], L).
L = [2]
(1 ms) yes
This is probably not the most computationally efficient solution since it doesn't take advantage of a couple of properties of "mids". For example, "mids" will all be clustered together contiguously, so once a "mid" is found, it doesn't make sense to continue searching if an element is subsequently encountered which is not itself a "mid". If efficiency is a goal, these sorts of ideas can be worked into the logical process.
ADDENDUM
With credit to #false for reminding me about maplist, the above predicate call less(X, T) could be replaced by maplist(<(X), T) eliminating the definition of less in the above implementation.

Prolog: Create list containing elements at even indices

Basically, I need to write a predicate, even_elts(L,M), such that L is a new list generated that contains only the even indexed elements from M (0th, 2nd, 4th, etc)
add_tail([X],[],X).
add_tail([H|NewT],[H|T],X) :-
add_tail(NewT,T,X).
even_elts(L,[]) :- L = [].
even_elts(L,M) :- even_elts2(L,M,1).
even_elts2(L,[H2|T2],Ct) :-
Ct2 is Ct + 1,
((Ct2 mod 2) =:= 0, add_tail(L,L2,H2), even_elts2(L2,T2,Ct2); even_elts2(L,T2,Ct2)).
even_elts2(_,[],_) :- !.
This works if M is empty or contains 1 or 2 elements. But, it only gets the first even indexed element from M, not the rest. Any pointers
EDIT: Solved the problem a different way, by removing the odd indexed elements rather than trying to create a new list and copying the data over. But, if someone can figure out a solution for my original code, I would be interested to see.
You're making this much more complicated than it is. You can use pattern matching to get each even element out, then collect those in the second (output) argument.
% an empty list does not have even elements
even_elts([], []).
% for all other lists, skip the second element (_),
% add the first to the output, recurse
even_elts([X, _ | L], [X | R]) :-
even_elts(L, R).
Just another approach with accumulator:
even_elts(L,M) :-
even_elts(M,0,[],L).
even_elts([H|T],I,Acc,Ans) :-
( I mod 2 =:= 0, append(Acc,[H], AccNew)
; I mod 2 =:= 1, AccNew = Acc
),
Inew is I + 1,
even_elts(T,Inew,AccNew,Ans).
even_elts([],_,Acc,Acc).
And
?- even_elts(X,[1,2,3,4,5]).
X = [1, 3, 5] ;
evens([A,B|C], [A|D]):- !, .....
evens(X, X).
is all you need. Fill in the blanks. :)

Resources