Prolog: Create sublist, given two indices - prolog

Basically, I need to create a predicate of the form sublist(S,M,N,L), where S is a new list formed from the elements of L between index M and index N, inclusive.
Here's where I've gotten:
sublist([],_,_,[]).
sublist([],M,N,_) :- (M > N).
sublist(S,M,N,L) :- sublist2(S,M,N,L,-1).
sublist2([H|T],St,En,[H2|T2],Idx) :-
(Idx2 is Idx + 1,
St =< Idx2,
En >= Idx2,
H = H2,
sublist2(T,St,En,T2,Idx2);
Idx2 is Idx + 1,
sublist2(T,St,En,T2,Idx2)).
As with all my prolog problems, I feel I'm making it way more complicated than it should be. I've got the base cases right, but anything else evaluates to false. Any advice for this problem, and just general approach to prolog? I understand the language for the most part, but I can't seem to see the simple solutions.

Simple solutions follow simple outlook. For lists it's recursion. Recursive programming is simple - just imagine you already have your function, following the given interface/requirements, and so you get to use it whenever you feel like it (but better, in the reduced cases).
sublist(S,M,N,[_A|B]):- M>0, M<N, sublist(S,M-1,N-1,B).
think of it as stating a law of sublists: sublist in a shorter list starts at decreased index.
sublist(S,M,N,[A|B]):- 0 is M, M<N, N2 is N-1, S=[A|D], sublist(D,0,N2,B).
and,
sublist([],0,0,_).
it is exclusive in the second index. tweak it. :)

There is the possibility to handle indexing in a way similar to more traditional languages:
sublist(L, M, N, S) :-
findall(E, (nth1(I, L, E), I >= M, I =< N), S).
or equivalently
sublist(L, M, N, S) :-
findall(E, (between(M, N, I), nth1(I, L, E)), S).
nth1/3 is for indexing from 1, otherwise nth0/3 allows C style - start from 0. I've placed the sublist as last argument. It's a common convention in Prolog to place output parameters after input.
Here a (cumbersome) recursive definition
sublist(L,M,N,S) :- sublist2(1,L,M,N,S).
sublist2(_,[],_,_,[]).
sublist2(I,[X|Xs],M,N,[X|Ys]) :-
between(M,N,I),
J is I + 1,
!, sublist2(J,Xs,M,N,Ys).
sublist2(I,[_|Xs],M,N,Ys) :-
J is I + 1,
sublist2(J,Xs,M,N,Ys).

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.

Separating a list into a list of fixed length sublists

Given a list L, for instance, [1,2,3,4,5,6,7] and a number N, for instance 3, I would like to make a predicate that would separate the elements of L into lists of size N.
So, the result will be: [[1,2,3], [4,5,6], [7]] in our case.
What I have tried:
% List containing the first N elements of given list.
takeN([X|Xs], 0, []) :- !.
takeN([X|Xs], N, [X|Ys]) :- N1 is N-1, takeN(Xs, N1, Ys).
% Given list without the first N elements.
dropN(R, 0, R) :- !.
dropN([X|Xs], N, R) :- N1 is N-1, dropN(Xs, N1, R).
% size of list.
sizeL([], 0) :- !.
sizeL([X|Xs], N) :- sizeL(Xs, N1), N is N1+1.
blockify(R, N, [R|[]]) :- sizeL(R, N1), N1 < N, !.
blockify([X|Xs], N, [Y|Ys]) :- sizeL(R, N1), N1 >= N, takeN([X|Xs], N, Y),
dropN([X|Xs], N, Res), blockify(Res, N, Ys).
It doesn't work (blockify([1,2,3], 2, R) for example returns false, instead of [[1,2], [3]]).
I can't find where I'm mistaken, though. What's wrong with this?
I think you are making thinks a bit overcomplicated. First of all let's exclude the case where we want to blockify/3 the empty list:
blockify([],_,[]).
Now in the case there are elements in the original list, we simply make use of two accumulators:
- some kind of difference list that stores the running sequence; and
- an accumulator that counts down and look whether we reached zero, in which case we append the running difference list and construct a new one.
So this would be something like:
blockify([H|T],N,R) :-
N1 is N-1,
blockify(T,N1,N1,[H|D],D,R).
Now the blockify/5 has some important cases:
we reach the end of the list: in that case we close the difference list and append it to the running R:
blockify([],_,_,D,[],[D]).
we reach the bottom of the current counter, we add the difference list to R and we intialize a new difference list with an updated counter:
blockify([H|T],N,0,D,[],[D|TR]) :-
blockify(T,N,N,[H|D2],D2,TR).
none of these cases, we simply append the element to the running difference decrement the accumulator and continue:
blockify([H|T],N,M,D,[H|D2],TR) :-
M > 0,
M1 is M-1,
blockify(T,N,M1,D,D2,TR).
Or putting it all together:
blockify([],_,[]).
blockify([H|T],N,R) :-
N1 is N-1,
blockify(T,N1,N1,[H|D],D,R).
blockify([],_,_,D,[],[D]).
blockify([H|T],N,0,D,[],[D|TR]) :-
blockify(T,N,N,[H|D2],D2,TR).
blockify([H|T],N,M,D,[H|D2],TR) :-
M > 0,
M1 is M-1,
blockify(T,N,M1,D,D2,TR).
Since in each recursive call all clauses run in O(1) and we do the recursion O(n) deep with n the number of elements in the original list, this program runs in O(n).
if your Prolog provides length/2, a compact solution could be:
blockify(R, N, [B|Bs]) :-
length(B, N),
append(B, T, R),
!, blockify(T, N, Bs).
blockify(R, _N, [R]).
Let me teach you how to debug a Prolog query:
1) blockify([1,2,3], 2, R)
2) does it match blockify(R, N, [R|[]]) ? oh yes,
it can be bound to blockify([1, 2, 3], 2, [[1, 2, 3]])
3) let's evaluate the body: sizeL(R, N1), N1 < N, !.
Replace R and N, we get: sizeL([1, 2, 3], N1), N1 < 2, !.
4) evaluate sizeL([1, 2, 3], N1): for brevity, since it's a common
list count predicate, the result should be obvious: N1 = 3
5) evaluate N1 < N: 3 < 2 => false
6) since the rest are all , (and operator) a single false
is enough to make the whole body to evaluate to false
7) there you go, the predicate is false
See where your mistake is?

CLP in Prolog involving consecutive sums in a list

Example of my CLP problem (this is a small part of a larger problem which uses the clpfd library):
For a list of length 5, a fact el_sum(Pos,N,Sum) specifies that the N consecutive elements starting from position Pos (index from 1) have sum equal to Sum. So if we have
el_sum(1,3,4).
el_sum(2,2,3).
el_sum(4,2,5).
Then [1,2,1,4,1] would work for this example since 1+2+1=4, 2+1=3, 4+1=5.
I'm struggling with how to even start using the el_sum's to find solutions with an input list [X1,X2,X3,X4,X5]. I'm thinking I should use findall but I'm not really getting anywhere.
(My actual problem is much bigger than this so I'm looking for a solution that doesn't just work for three facts and a small list).
Thanks!
You are mixing here the monotonic world of constraints with some non-monotonic quantification. Don't try to mix them too closely. Instead, first transform those facts into, say, a list of terms.
el_sums(Gs) :-
G = el_sum(_,_,_),
findall(G, G, Gs).
And then, only then, start with the constraint part that will now remain monotonic. So:
?- el_sums(Gs), length(L5,5), maplist(l5_(L5), Gs).
l5_(L5, el_sum(P, N, S)) :-
length([_|Pre], P),
length(Cs, N),
phrase((seq(Pre),seq(Cs),seq(_)), L5),
list_sum(Cs,S).
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).
Not sure this will help, I don't understand your workflow... from where the list do come ? Anyway
:- [library(clpfd)].
el_sum(Pos,N,Sum) :-
length(L, 5),
L ins 0..100,
el_sum(Pos,N,Sum,L),
label(L), writeln(L).
el_sum(P,N,Sum,L) :-
N #> 0,
M #= N-1,
Q #= P+1,
el_sum(Q,M,Sum1,L),
element(N,L,T),
Sum #= Sum1 + T.
el_sum(_P,0,0,_L).
yields
?- el_sum(1,2,3).
[0,3,0,0,0]
true ;
[0,3,0,0,1]
true ;
...

Depth limited search in prolog (vanilla meta-interpreter)

I need to modify the vanilla meta-interpreter in order to make a search with limited depth. I'm using the following code for testing my sollution:
value(wire1,1).
connected(wire2, wire1).
connected(wire3, wire2).
connected(wire4, wire3).
connected(wire5, wire4).
connected(wire6, wire5).
connected(wire7, wire6).
connected(wire8, wire7).
connected(wire9, wire8).
value(W,X):-connected(W,V), value(V,X).
And the target is that something like:
solve(value(w9,X), 3). /*depth =3, it should return false*/
solve(value(w9,X), 20). /*depth=20 is enought for returning X=1*/
By the way my code is
solve(true,_):-!.
solve((A,B),D) :-!, solve(A,D), solve(B,D).
solve(A,D) :- clause(A, B),solve(B,D2),D=D2+1,D>0).
But it don't work property. Can you help me? Thanks a lot in advance
An interesting page on metaprogramming came from a good developer: Markus Triska.
Here (A Couple of Meta-interpreters in Prolog) you find both theory and practice. For instance:
... Another group of extensions aims to improve the incomplete default computation strategy. We start from an MI that limits the depth of the search tree:
mi_limit(Goal, Max) :-
mi_limit(Goal, Max, _).
mi_limit(true, N, N).
mi_limit((A,B), N0, N) :-
mi_limit(A, N0, N1),
mi_limit(B, N1, N).
mi_limit(g(G), N0, N) :-
N0 > 0,
mi_clause(G, Body),
N1 is N0 - 1,
mi_limit(Body, N1, N).
You were almost there. Only the last clause needs a slight rearranging:
solve(A, D) :- clause(A, B), D1 is D - 1, D1 > 0, solve(B, D1).
?- solve(value(wire9, X), 9). ===> false.
?- solve(value(wire9, X), 10). ===> X = 1.
dls(X,X,[X],L):-
L >0 goal(X).
dls(X,Y,[A|p],L):-
L > 0 ,goal(Y) ,
move(X,Y),
L1 is L - 1 ,
dls(Z,Y ,P,L1).

Simple nth1 predicate in Prolog

With SWI Prolog, there's a predicate that finds the nth item in a list called nth1. I want to implement my own version of the predicate but SWI's is so complicated if you look at the listing(nth1) code. Is there a simpler way of doing it?
Thank you :).
Consider using finite domain constraints for general (reversible) integer arithmetic:
:- use_module(library(clpfd)).
nth1(1, [E|_], E).
nth1(N, [_|Xs], E) :-
N #> 1,
N #= N1 + 1,
nth1(N1, Xs, E).
I didn't mean to be contradictory or get someone else to do my work actually; I just wanted some advice, sorry for not being clearer.
I've implemented it myself now but could you guys possibly suggest improvements or better ways of doing it? What I often find myself doing in Prolog is writing a predicate with say a counter or set of counters and getting a predicate with fewer arguments to call the clauses with extra arguments. This often ends up producing quite a bit of code. Anyway, here's my implementation I just did:
item_at( N, L, Item ) :-
item_at( N, 0, L, Item ).
item_at( N, Count, [H|_], Item ) :-
CountNew is Count + 1,
CountNew = N,
Item = H.
item_at( N, Count, [_|T], Item ) :-
CountNew is Count + 1,
item_at( N, CountNew, T, Item ).
Any comments? Thanks :). Usage:
?- item_at(3,[a,b,c,d,e],Item).
Item = c ;
The SWI code is a bit complex because the predicate can be used to generate from a variable index:
?- nth1(Idx,[a,b,c],X).
Idx = 1,
X = a ;
Idx = 2,
X = b ;
Idx = 3,
X = c ;
false.
If you don't want that behavior, nth1/3 can be implemented easily in terms of nth0:
nth1(Idx,List,X) :-
Idx0 is Idx-1,
nth0(Idx0,List,X).
Edit: it's also possible to do without nth0 in just a few lines of code:
nth1(1,[X|_],X) :- !.
nth1(Idx,[_|List],X) :-
Idx > 1,
Idx1 is Idx-1,
nth1(Idx1,List,X).

Resources