How can I modify the following Prolog program - prolog

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.

Related

Split a list on an index in Prolog

I am writing a split predicate with 4 parameters. The first parameter (Index) is the index at which the complete list should be split. The second parameter (CompleteList) is the list that the predicate should split on a given index. Parameter 3 and 4 are output parameters (here FirstHalf and SecondHalf).
split(_,[],[],[]).
split(0,CompleteList,FirstHalfList,CompleteList).
split(Index,[CompleteListHead|CompleteListTail],FirstHalfList,SecondHalfList) :-
append(FirstHalfList,[CompleteListHead],NewFirstHalfList),
NewIndex is Index-1,
split(NewIndex,CompleteListTail,NewFirstHalfList,SecondHalfList).
An example of the desired output of a query would be
split(2,[5,4,3,2,1],X,Y).
X=[5,4],
Y=[3,2,1]
I understand how the second half of the list can be returned, yet I have trouble returning the first half. The current output of the program for the example query is
split(2,[5,4,3,2,1],X,Y).
X=[],
Y=[3,2,1]
Is it possible to return the FirstHalfList (instead of the NewFirstHalfList, which backtracks to an empty list) or is the current code a wrong approach towards writing Prolog predicates ?
Edit: thank you all for the responses, they have given me a better insight.
There are many ways to do this.
Here is a compressed way:
split(Index,List,Left,Right) :-
length(Left,Index), % Actually CREATES a list of fresh variables if "Left" is unbound
append(Left,Right,List). % Demand that Left + Right = List.
Then:
?- split(2,[5,4,3,2,1],X,Y).
X = [5, 4],
Y = [3, 2, 1].
?- split(2,[],X,Y).
false.
?- split(0,[],X,Y).
X = Y, Y = [].
It can even automagically work "in reverse":
?- split(L,[5,4,3,2,1],[5,4],Y).
L = 2,
Y = [3, 2, 1].
Think about why this works!
Debug printout helps here:
split(Index,List,Left,Right) :-
debugme(Index,List,Left,Right),
length(Left,Index),
debugme(Index,List,Left,Right),
append(Left,Right,List),
debugme(Index,List,Left,Right).
debugme(Index,List,Left,Right) :-
format("Index: ~q, List: ~q, Left: ~q, Right: ~q\n",[Index,List,Left,Right]).
Then:
?- split(L,[5,4,3,2,1],[5,4],Y).
Index: _6640, List: [5,4,3,2,1], Left: [5,4], Right: _6646
Index: 2, List: [5,4,3,2,1], Left: [5,4], Right: _6646
Index: 2, List: [5,4,3,2,1], Left: [5,4], Right: [3,2,1]
L = 2,
Y = [3, 2, 1].
Notice the way in which the set of variables appearing in the clause get progressively filled with information.
The split predicate recursively reduces its second argument.
The first clause handles the terminal case (when Index > length of given list)
The second clause handles the other terminal case when Index is reduced to 0.
split(_,[],[],[]).
split(0,L,[],L).
split(Index,[CompleteListHead|CompleteListTail],[CompleteListHead|FirstHalfTail],SecondHalfList) :-
Index >= 0,
NewIndex is Index-1,
split(NewIndex,CompleteListTail,FirstHalfTail,SecondHalfList).
?- split(2,[5,4,3,2,1],X,Y).
X = [5, 4],
Y = [3, 2, 1] ;
?- split(8,[5,4,3,2,1],X,Y).
X = [5, 4, 3, 2, 1],
Y = [] ;
?- split(4,[5,4,3,2,1],X,Y).
X = [5, 4, 3, 2],
Y = [1] ;
%! split(?INDEX0,?Xs0,?Ys,?Zs)
%
% `Xs0` is split at `INDEX0` into `Ys` and `Zs` .
split(_,[],[],[]) .
split(INDEX,Xs0,Ys,Zs)
:-
lists:length(Ys,INDEX) ,
lists:append(Ys,Zs,Xs0)
.
/*
?- split(2,[5,4,3,2,1],Ys,Zs) .
Ys = [5,4] ,
Zs = [3,2,1] .
*/
/*
?- split(INDEX,Xs0,[5,4],[3,2,1]) .
INDEX = 2 ,
Xs0 = [5,4,3,2,1] .
*/
/*
?- split(INDEX,Xs0,Ys,Zs) .
Xs0 = Ys = Zs = [] ? ;
INDEX = 0 ,
Xs0 = Zs ,
Ys = [] ? ;
INDEX = 1 ,
Xs0 = [A|Zs] ,
Ys = [A] ? ;
INDEX = 2 ,
Xs0 = [A,B|Zs] ,
Ys = [A,B] ? ;
INDEX = 3 ,
Xs0 = [A,B,C|Zs] ,
Ys = [A,B,C] ? ;
INDEX = 4 ,
Xs0 = [A,B,C,D|Zs] ,
Ys = [A,B,C,D] ? %etcetera.
*/

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

Finding consecutive sublists of a list

I want to write a predicate split/2 that generates all consecutive lists found inside another list.
Example: split([1,2,3,4],X) should return
X = [4], X = [2,3],X = [1,2], X = [1,2,3] etc.
So far I only have a predicate that returns all possible sublists of a list:
sublist([],[]).
sublist([H|T], [H|R]) :-
sublist(T,R).
sublist([_|T], R) :-
sublist(T,R).
However, with the query from the example this predicate includes unwanted answers like X = [2,4] and X = [1,3] that aren't found consecutively in [1,2,3,4].
Usually a problem is easier if you split it in subproblems. We can first construct a predicate that will construct all suffixes for a given list.
We can construct such predicate as follows:
suffix(_, []).
suffix([H|T], [H|T2]) :-
suffix(T, T2).
So for each point in the list, we can decide to stop (with the empty list), or emit the next item. For the given sample list, we thus get:
?- suffix([1,2,3,4],X).
X = [] ;
X = [1] ;
X = [1, 2] ;
X = [1, 2, 3] ;
X = [1, 2, 3, 4].
Now we only need to decide when we start the suffix. For each item in the list, we can decide to start at that point, and enumerate over all suffixes that we then append to that item:
split([H|T], [H|S]) :-
suffix(T, S).
split([_|T], S) :-
split(T, S).
For example:
?- split([1,2,3,4],X).
X = [1] ;
X = [1, 2] ;
X = [1, 2, 3] ;
X = [1, 2, 3, 4] ;
X = [2] ;
X = [2, 3] ;
X = [2, 3, 4] ;
X = [3] ;
X = [3, 4] ;
X = [4] ;
false.
The nice thing is that we got a second predicate "for free": we can also obtain all suffixes for a list.
We might want to include the empty list as well. I leave this as an exercise.

Prolog list combinations

I'm trying to write a prolog code which will take a list and return all pairs of each element of that list. So for example:
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 far I am able to get uptil the third line and not able to get the rest of the output. My code is:
select_pair(X,Y,[X|Xs],Zs):- select(Y,Xs,Zs).
select_pair(X,Y,[H|Z1],[H|Z2]):- select_pair(X,Y,Z1,Z2).
In words, what you want to achieve is:
Take any X from the input list
Take any Y different from X from the input list
Elements other than X and Y are in Zs
This translates quite easily into a prolog predicate:
select_pair(X, Y, L, Zs) :-
select(X, L, Xs),
select(Y, Xs, Zs).
First we select X from the input L. From the remaining elements Xs we select Y. After this, the remaining elements is Zs.

Compute a list of distinct odd numbers (if one exists), such that their sum is equal to a given number

:- use_module(library(clpfd)). % load constraint library
% [constraint] Compute a list of distinct odd numbers (if one exists), such that their sum is equal to a given number.
odd(Num) :- Num mod 2 #= 1.
sumOfList([],N,N) :- !.
sumOfList([H|T],Counter,N) :-
NewN #= H + Counter,
sumOfList(T,NewN,N).
buildOddList(N,InputList,L) :-
%return list when sum of list is N
V in 1..N,
odd(V),
append(InputList,[V],TempL),
sumOfList(TempL,0,N)->
L = TempL;
buildOddList(N,TempL,L).
computeOddList(N) :-
buildOddList(N,[],L),
label(L).
This is my code, I can't seem to get the right output, any code critics? :)
Here my take on this question, realized by a predicate nonNegInt_oddPosSummands/2 and an auxiliary predicate list_n_sum/3:
:- use_module(library(clpfd)).
list_n_sum([],_,0).
list_n_sum([Z|Zs],N,Sum) :-
Z #>= 1,
Z #=< N,
Z mod 2 #= 1,
Sum #= Z + Sum0,
Sum0 #>= 0,
list_n_sum(Zs,N,Sum0).
nonNegInt_oddPosSummands(N,List) :-
length(_,N),
list_n_sum(List,N,N),
chain(List,#<),
labeling([],List).
Now on to some queries!
First, "which lists can 19 be decomposed into?":
?- nonNegInt_oddPosSummands(19,Zs).
Zs = [19] ;
Zs = [1, 3, 15] ;
Zs = [1, 5, 13] ;
Zs = [1, 7, 11] ;
Zs = [3, 5, 11] ;
Zs = [3, 7, 9] ;
false.
Next, a more general query that does not terminate as the solution set is infinite. "Which positive integers N can be decomposed into Zs if Zs has a length of 2?"
?- Zs=[_,_], nonNegInt_oddPosSummands(N,Zs).
N = 4, Zs = [1,3] ;
N = 6, Zs = [1,5] ;
N = 8, Zs = [1,7] ;
N = 8, Zs = [3,5] ;
N = 10, Zs = [1,9] ...
Finally, the most general query. Like the one above it does not terminate, as the solution set is infinite. However, it fairly enumerates all decompositions and corresponding positive integers.
?- nonNegInt_oddPosSummands(N,Zs).
N = 0, Zs = [] ;
N = 1, Zs = [1] ;
N = 3, Zs = [3] ;
N = 4, Zs = [1,3] ;
N = 5, Zs = [5] ;
N = 6, Zs = [1,5] ;
N = 7, Zs = [7] ;
N = 8, Zs = [1,7] ;
N = 8, Zs = [3,5] ;
N = 9, Zs = [9] ;
N = 9, Zs = [1,3,5] ;
N = 10, Zs = [1,9] ...
Can suggest you this solution:
:- use_module(library(clpfd)).
all_odd([]) :-!.
all_odd([H | T]) :-
H mod 2 #= 1,
all_odd(T).
solve(N,L) :-
N2 is floor(sqrt(N)),
Len in 1..N2,
label([Len]),
length(L, Len),
L ins 1..N,
all_different(L),
all_odd(L),
sum(L,#=,N),
label(L),
% only show sorted sets
sort(L,L).
Example:
?- solve(17,L).
L = [17] ;
L = [1, 3, 13] ;
L = [1, 5, 11] ;
L = [1, 7, 9] ;
L = [3, 5, 9] ;
false.
I see others have posted complete solutions already. Still, your code can be made to wok with only two slight modifications:
computeOddList only tests whether such a list exists. To know which list matches the constraints, just return it. Thus:
computeOddList(N, L) :-
...
The list TempL may currently contain duplicates. Just place all_different(TempL) after append to fix that.
Now computeOddList will return at least one list of distinct odd numbers if it exists. Still, for e.g. computeOddList(17, L) it will not return all lists. I don't know clpFD myself, so other than suggesting you compare your code to Xonix' code I cannot really help you.
:- use_module(library(clpfd)). % load constraint library
% [constraint] Compute a list of distinct odd numbers (if one exists), such that their sum is equal to a given number.
odd(Num) :- Num mod 2 #= 1.
sumOfList([],N,N) :- !.
sumOfList([H|T],Counter,N) :-
NewN #= H + Counter,
sumOfList(T,NewN,N).
oddList([]) :- !.
oddList([H|T]) :-
odd(H),
oddList(T).
computeOddList(N,L) :-
(L = [];L=[_|_]),
length(L,V),
V in 1..N,
L ins 1..N,
all_different(L),
oddList(L),
sumOfList(L,0,N).
I managed to kinda solved it, however it doesn't end properly after it runs out of cases. Hmm.

Resources