Comparing a list of integers with a number prolog - prolog

I have to define a predicate which takes as input a list of integers, and instantiates X with the elements of L smaller than 10, and Y with the elements of the list greater than or equal to 10.
This is the predicate: separate(L, X, Y)
Here are some examples of the output I'm looking for:
?− separate([2, 13, 4, 0, 55], X, Y).
X = [2, 4, 0]
Y = [13, 55]
?− separate([2, 3], X, Y).
X = [2, 3]
Y = [ ]

Quite simple. Here a solution without built-in predicates:
separate([],[],[]).
separate([H|T],LG,LL):-
( H > 10 ->
LG = [H|TG],
separate(T,TG,LL) ;
LL = [H|TL],
separate(T,LG,TL)
).
?- separate([2, 13, 4, 0, 55], X, Y).
X = [13, 55],
Y = [2, 4, 0]
?- separate([2, 3], X, Y).
X = [],
Y = [2, 3]

I would break it up into multiple clauses:
separate( [] , [] , [] ) .
separate( [X|Xs] , [X|Ys] , Zs ) :- X < 10, separate(Xs,Ys,Zs).
separate( [X|Xs] , Ys , [X|Zs] ) :- X >= 10, separate(Xs,Ys,Zs).
Easier to read. Better expresses intent, too, as well as not making assumptions about the content of the list — e.g., what happens with [1,12,3,x,9,28]?

Related

What is the simple way to find the max length of a list in prolog?

I'm new to learn the Prolog, I have a list, which looks like -> [[6, 7, 8,9], [6, 7, 8, 9], [6, 7, 8, 9], [7, 8, 9], [7, 8, 9],[5,6,7]], I want to find the all max length lists in the list, In this case, it should return [[6,7,8,9],[6,7,8,9],[6,7,8,9]]
my code
maxlist([A],A).
maxlist([A,B|Rest],Max):-
maxlist([B|Rest],Maxrest),
max(A,Maxrest,Max).
max(A,B,A):-
length(A,N1),
length(B,N2),
N1>N2.
max(A,B,B):-
length(A,N1),
length(B,N2),
N2>N1.
I could only find the one, I don't know how I find all, please don’t solve this predicate in complicate way or use complicates functor, it’s hard to understand for me.
Another possible solution is:
maxlist(ListOfLists, Answer) :-
maxlist(ListOfLists, -inf, [], Answer).
maxlist([], _, Answer, Answer).
maxlist([List|Lists], Max, Acc, Answer) :-
length(List, N),
( N = Max -> maxlist(Lists, Max, [List|Acc], Answer)
; N > Max -> maxlist(Lists, N, [List], Answer)
; maxlist(Lists, Max, Acc, Answer) ).
Examples:
?- maxlist([[6,7,8,9], [6,7,8,9], [6,7,8,9], [7,8,9], [7,8,9], [5,6,7]], M).
M = [[6, 7, 8, 9], [6, 7, 8, 9], [6, 7, 8, 9]].
?- maxlist([[1,2,3],[4,5,6,7,8,9],[0]], M).
M = [[4, 5, 6, 7, 8, 9]].
?- maxlist([[1,2,3], [4,5,6,7], [8], [9,0,1], [2,3,4,5]], M).
M = [[2, 3, 4, 5], [4, 5, 6, 7]].
The big issue with this problem is the repeated iteration of the list and its sublists, is it not?
I would start with a predicate that iterates over your list-of-lists once, prefixing each sublist with its length, and computing the length of the sublist as it goes:
map_lengths( Xs, L, X1 ) :- map_lengths(Xs,0,L,X1) .
map_lengths( [] , M , M , [] ) .
map_lengths( [X|Xs] , T , M , [L:X|Ys] ) :-
length(X,L),
T1 is max(L,T),
map_lengths(Xs,T1,M,Ys)
.
That's one pass over the list and its sublists.
Now that we have that, all we need is a way to extract sublists of a specified length. That's as easy as this:
lists_of_length( _ , [] , [] ) .
lists_of_length( L , [L:X|Xs] , [X|Ys] ) :- !, lists_of_length(L,Xs,Ys) .
lists_of_length( L , [_:_|Xs] , Ys ) :- lists_of_length(L,Xs,Ys) .
That is another single pass of the outer list. We no longer need to iterate over the sublists themselves.
And then, we just wire up the two predicates:
longest( Xs , Ys ) :-
map_lengths( Xs, L, X1 ) ,
lists_of_length(L,X1,Ys)
.
Putting it all together, you get:
https://swish.swi-prolog.org/p/VyUrjJjD.pl
longest( Xs , Ys ) :-
map_lengths( Xs, L, X1 ) ,
lists_of_length(L,X1,Ys)
.
map_lengths( Xs, L, X1 ) :- map_lengths(Xs,0,L,X1) .
map_lengths( [] , M , M , [] ) .
map_lengths( [X|Xs] , T , M , [L:X|Ys] ) :-
length(X,L),
T1 is max(L,T),
map_lengths(Xs,T1,M,Ys)
.
lists_of_length( _ , [] , [] ) .
lists_of_length( L , [L:X|Xs] , [X|Ys] ) :- !, lists_of_length(L,Xs,Ys) .
lists_of_length( L , [_:_|Xs] , Ys ) :- lists_of_length(L,Xs,Ys) .
Overall time and space complexity is O(N).
You can do it traversing the list once and keeping the current maximum length found along with the lists that have that maximum length:
maxlist(L, ML):-
maxlist(L, 0-[], ML).
maxlist([], _-ML, ML).
maxlist([A|L], MaxLen-ML, ML2):-
length(A, Len),
compare(C, Len, MaxLen),
memberchk(C-MaxLen1/ML1, [(<)-MaxLen/ML, (=)-MaxLen/[A|ML], _-Len/[A]]),
maxlist(L, MaxLen1-ML1, ML2).
Sample run:
?- maxlist([[6, 7, 8,9], [6, 7, 8, 9], [6, 7, 8, 9], [7, 8, 9], [7, 8, 9],[5,6,7], [1,2,3,4,5]], ML).
ML = [[1, 2, 3, 4, 5]].
Another alternative:
max_len_lists(LstLists, LstMaxLenFilter) :-
max_len_lists_(LstLists, _LenMax, LstMaxLenFilter),
% No need to check for alternatives
!.
max_len_lists_([], 0, []).
max_len_lists_([H|T], Len, LstMax) :-
length(H, LenH),
% Use recursion to check the rest of the list
max_len_lists_(T, LenT, F),
( LenH = LenT -> Len = LenH, LstMax = [H|F]
; LenH > LenT -> Len = LenH, LstMax = [H]
; Len = LenT, LstMax = F ).

Prolog write n as sum of consecutive numbers

I'm studying prolog and I want to determine all decomposition of n (n given, positive), as sum of consecutive natural numbers but I don't know how to approach this.
Any ideas ?
The key here is between/3, which relates numbers and ranges. Prolog is not going to conjure up numbers from thin air, you have to give it some clues. In this case, you can assume a range of numbers between 1 and the n which you are given:
decomp2(N, X, Y) :-
between(1, N, X),
between(1, N, Y),
N =:= X + Y.
This will give you the sum of two numbers that yields N:
?- decomp2(5, X, Y).
X = 1,
Y = 4 ;
X = 2,
Y = 3 ;
X = 3,
Y = 2 ;
X = 4,
Y = 1 ;
Once you can get two, you can get a longer list by tearing one value off with decomp2/2 and getting the rest through induction. You just need to come up with a base case, such as, the singleton list of N:
decomp(N, [N]).
decomp(N, [X|L]) :- decomp2(N, X, Y), decomp(Y, L).
Be warned that this is going to produce a lot of repetition!
?- decomp(5, L).
L = [5] ;
L = [1, 4] ;
L = [1, 1, 3] ;
L = [1, 1, 1, 2] ;
L = [1, 1, 1, 1, 1] ;
L = [1, 1, 2, 1] ;
L = [1, 2, 2] ;
L = [1, 2, 1, 1] ;
L = [1, 3, 1] ;
L = [2, 3] ;
L = [2, 1, 2] ;
L = [2, 1, 1, 1] ;
L = [2, 2, 1] ;
L = [3, 2] ;
L = [3, 1, 1] ;
L = [4, 1] ;
You could probably clamp down on the repetition by introducing an ordering requirement, such as that X be greater than Y.
I have reached the solution and it looks something like this:
Remark: in isConsecutive i get rid of the "solution" when the list is the number itself
% equal with the given parameter N.
% generatePair(N - integer, X - integer, Y - integer)
% generatePair(i,o,o)
% generatePair(N) = { (X,Y), X<Y && X+Y=N
generatePair(N, X, Y) :-
my_between(1, N, Y),
my_between(1, N, X),
X < Y,
N =:= X + Y.
% This predicate decomposes the given number N into a list of integers
% such that their sum is equal to N.
% decomposeNumber(N - integer, L - list)
% decomposeNumber(i,o)
% decomposeNumber(N) = { [X|L]
decomposeNumber(N, [N]).
decomposeNumber(N, [X|L]) :- generatePair(N, X, Y), decomposeNumber(Y, L).
% This predicate checks it the that elements in the given list have
% consecutive value.
% isConsecutive(L - list)
% isConsecutive(i)
% isConsecutive([l1,l2,..,ln]) = { true, L=[l1,l2] && l1+1=l2
% { isConsecutive(l2..ln), l1+1=l2 && n>2
% { false, otherwise
isConsecutive([X,Y]):-X+1=:=Y.
isConsecutive([H1,H2|T]):-H2=:=H1+1, isConsecutive([H2|T]).
nAsSumOfConsecutives(N,L):-decomposeNumber(N,X), isConsecutive(X), L=X.
main(N,L):-findall(R,nAsSumOfConsecutives(N,R),L).

n-queens solution not working in Prolog

I am trying to run following code from N-Queens Problem‍​..How far can we go? to find solutions to n-queens problem:
generate([],_).
generate([H|T],N) :- H in 1..N , generate(T,N).
lenlist(L,N) :- lenlist(L,0,N).
lenlist([],N,N).
lenlist([_|T],P,N) :- P1 is P+1 , lenlist(T,P1,N).
queens(N,L) :-
generate(L,N),lenlist(L,N),
safe(L),!,
labeling([ffc],L).
notattack(X,Xs) :- notattack(X,Xs,1).
notattack(X,[],N).
notattack(X,[Y|Ys],N) :- X #\= Y,
X #\= Y - N,
X #\= Y + N,
N1 is N + 1,
notattack(X,Ys,N1).
safe([]).
safe([F|T]) :- notattack(F,T), safe(T).
I have swi-prolog installed on Debian-9 (stable) Linux and I am running above using command "swipl -f nqueens.pl". On loading, I get an error:
Syntax error: operator expected (probably on 2nd code line)
Where is the problem and how can this be solved? Thanks for your help.
The question actually mentions that it is writting in CLPFD (A Constraint Logic Programming tool over Finite Domains). You have to import this library:
:- use_module(library(clpfd)).
generate([],_).
generate([H|T],N) :- H in 1..N , generate(T,N).
lenlist(L,N) :- lenlist(L,0,N).
lenlist([],N,N).
lenlist([_|T],P,N) :- P1 is P+1 , lenlist(T,P1,N).
queens(N,L) :-
generate(L,N),lenlist(L,N),
safe(L),!,
labeling([ffc],L).
notattack(X,Xs) :- notattack(X,Xs,1).
notattack(X,[],N).
notattack(X,[Y|Ys],N) :- X #\= Y,
X #\= Y - N,
X #\= Y + N,
N1 is N + 1,
notattack(X,Ys,N1).
safe([]).
safe([F|T]) :- notattack(F,T), safe(T).
Then it works, and produces for instance:
?- queens(5,L).
L = [1, 3, 5, 2, 4] ;
L = [1, 4, 2, 5, 3] ;
L = [2, 4, 1, 3, 5] ;
L = [2, 5, 3, 1, 4] ;
L = [3, 1, 4, 2, 5] ;
L = [3, 5, 2, 4, 1] ;
L = [4, 1, 3, 5, 2] ;
L = [4, 2, 5, 3, 1] ;
L = [5, 2, 4, 1, 3] ;
L = [5, 3, 1, 4, 2].
When I look at line 2, as the error message suggests, the most probable cause is the H in 1..N. I would have written that as between(1, H, N). I haven't done anything in Prolog lately, though.
There are several different implementations of Prolog, and they differ in these little details. Try searching for guidelines for writing portable Prolog code.

Form a single list from multiple answers in Prolog

I currently have this piece of code in Prolog
s1(Q,100) :- generate(Q).
generate([X,Y,S,P]) :-
nat(X, 49),
nat(Y, 98),
S is X+Y,
P is X*Y,
S =< 100,
X < Y.
nat(2,_).
nat(X,N) :-
N > 2,
M is N - 1,
nat(Y,M),
X is Y + 1.
It currently generates a list of quadruples, X, Y, S, P such that
1 < X < 49
1 < Y < 98
1 < X < Y
X + Y <= 100
P = X * Y
S = X + Y
This works and creates all possible solutions but with multiple answers (i.e, having to press ; every time to get the next result.)
How can a single list be formed of all these results, for instance,
[[2, 3, 5, 6], [2, 4, 6, 8], ...]
without using any built in predicates such as findall/3?
First, the upper interval bounds you gave for X and Y are both off by one:
1 < X < 49 does not match nat(X,49), 1 < X =< 49 does.
1 < Y < 98 does not match nat(Y,98), 1 < Y =< 98 does.
Let's get it started!
If you want to collect all solutions without using findall/3 (etc), one way is to calculate the Cartesian product (a.k.a. cross-product) of two lists Xs and Ys.
To get Xs and Ys, we can use the builtin predicate numlist/3:
?- numlist(2,49,Xs).
Xs = [2,3,4,/* consecutive integers from 5 to 47 omitted */,48,49].
?- numlist(2,98,Ys).
Ys = [2,3,4,/* consecutive integers from 5 to 96 omitted */,97,98].
To combine every X in Xs with every Y in Ys we use dcg xproduct//3.
For selecting which quadruples to collect, use the grammar rule x_y_maybe_quadruple//2:
x_y_maybe_quadruple(X,Y) -->
( { 1 < X, X < Y, X+Y =< 100 } % if all these conditions are met
-> { P is X * Y },
{ S is X + Y },
[[X,Y,S,P]] % then add single "quadruple"
; [] % else add nothing.
).
Let's put it all together!
?- numlist(2,49,Xs),
numlist(2,98,Ys),
phrase(xproduct(x_y_maybe_quadruple,Xs,Ys),Qss).
Qss = [[2,3,5,6],[2,4,6,8],
/* lots of other quadruples omitted */,
[48,51,99,2448],[48,52,100,2496]].
So... do we actually get all quadruples we would have gotten if we had used findall/3?
?- findall(Qs,generate(Qs),Qss1),
numlist(2,49,Xs),
numlist(2,98,Ys),
phrase(xproduct(x_y_maybe_quadruple,Xs,Ys),Qss2),
Qss1 = Qss2.
Qss1 = Qss2,
Qss2 = [[2, 3, 5, 6], [2, 4, 6, 8], [2|...], [...|...]|...],
Xs = [2, 3, 4, 5, 6, 7, 8, 9, 10|...],
Ys = [2, 3, 4, 5, 6, 7, 8, 9, 10|...].
It works! And not just that: we get exactly the same quadruples in the exact same order!
You need to add a solution to a list if it is not already in the list..if its in the list fail.
so
myfindall(List) :-
my_find(List,[]),
!.
my_find(List,Ac) :-
s1(Q,100),
my_set(Q,Ac,NewAc),
my_find(List,NewAc).
my_find(Ac,Ac).
my_set(X,[],[X]) :-
!.
my_set(H,[H|_],_) :-
!,
fail.
my_set(X,[H|T],L) :-
my_set(X,T,Rtn),
L = [H|Rtn].

How can I modify the following Prolog program

I have written the following program to compute all pairs of members in a list. Here is my code:
select_pair(X, Y, [X|[Y|T]], T).
select_pair(X, Y, [Head|[X|[Y|T]]], [Head|Rest]) :- select_pair(X, Y, T, Rest).
I am supposed to call my code with this 3-member list only:
select pair(X, Y, [1,2,3], Zs).
But this doesn't generate all possible combinations. It only generates
X = 1, Y = 2, Zs = [3]
and it is supposed to generate this, but it does not:
X = 1, Y = 2, Zs = [3] ;
X = 1, Y = 3, Zs = [2] ;
X = 2, Y = 1, Zs = [3] ;
X = 2, Y = 3, Zs = [1] ;
X = 3, Y = 1, Zs = [2] ;
X = 3, Y = 2, Zs = [3]
So, how can I modify this code to generate all possible pairs of members of the list [1, 2, 3]?
I'd use procedure select/3:
select_pair(X, Y, List, Rest):-
select(X, List, MList),
select(Y, MList, Rest).
The first select would remove the first element from List into X and put the rest of the list in MList.
Then the second select would get you the second element and the Rest.

Resources