Predicate to match list (all possibilities) with no duplicate integers, have length N, and be within a domain of 1 to N - prolog

This is for GNU-Prolog
I'm having trouble getting a certain predicate to work. Its functionality is that it matches a list of integers
that have a domain of 1 to N with no duplicates and length N. Basically what I want to do is have this as inputs and outputs:
| ?- row_valid(X, 3).
X = [1, 2, 3] ? ;
X = [1, 3, 2] ? ;
X = [2, 1, 3] ? ;
X = [2, 3, 1] ? ;
X = [3, 1, 2] ? ;
X = [3, 2, 1] ? ;
no
| ?- row_valid(X, 2).
X = [1, 2] ? ;
X = [2, 1] ? ;
no
| ?- row_valid(X, 1).
X = [1] ? ;
no
But right now, this is what is happening:
| ?- row_valid(X, 3).
X = [] ? ;
no
This is probably happening because of the row_valid([], _). predicate I have in the code. However, I can verify that the predicate matches correctly since:
| ?- row_valid([1,2,3], 3).
true ?
yes
Here are the predicates defined. Do you have any suggestions on how I could get this to work the way I want? Thanks for your time.
% row_valid/2: matches if list of integers has domain of 1 to N and is not duplicated
% 1 - list of integers
% 2 - N
row_valid([], _).
row_valid(Row, N) :-
length(Row, N), % length
no_duplicates_within_domain(Row, 1, N),
row_valid(RestRow, N).
% no_duplicates/1: matches if list doesn't have repeat elements
% 1 - list
no_duplicates([]). % for empty list always true
no_duplicates([Element | RestElements]) :-
\+ member(Element, RestElements), % this element cannot be repeated in the list
no_duplicates(RestElements).
% within_domain/3 : matches if list integers are within a domain
% 1 - list
% 2 - min
% 3 - max
within_domain(Integers, Min, Max) :-
max_list(Integers, Max),
min_list(Integers, Min).
% no_duplicates_within_domain/3: matches if list integers are within a domain and isn't repeated
% 1 - list
% 2 - min
% 3 - max
no_duplicates_within_domain(Integers, Min, Max) :-
no_duplicates(Integers),
within_domain(Integers, Min, Max).

How about the following?
row_valid(Xs,N) :-
length(Xs,N),
fd_domain(Xs,1,N),
fd_all_different(Xs),
fd_labeling(Xs).
Running it with GNU Prolog 1.4.4:
?- row_valid(Xs,N).
N = 0
Xs = [] ? ;
N = 1
Xs = [1] ? ;
N = 2
Xs = [1,2] ? ;
N = 2
Xs = [2,1] ? ;
N = 3
Xs = [1,2,3] ? ;
N = 3
Xs = [1,3,2] ? ;
N = 3
Xs = [2,1,3] ? ;
N = 3
Xs = [2,3,1] ? ;
N = 3
Xs = [3,1,2] ? ;
N = 3
Xs = [3,2,1] ? ;
N = 4
Xs = [1,2,3,4] ? % ...and so on...

Here is a simple piece of code that does this in SWI-Prolog. I don't know if GNU-Prolog provides between/3 and permutation/2, so maybe it doesn't directly answer your question, but maybe it can still help you further.
row_valid(List, N) :-
findall(X, between(1, N, X), Xs),
permutation(Xs, List).
Usage examples:
?- row_valid(List, 0).
List = [].
?- row_valid(List, 1).
List = [1] ;
false.
?- row_valid(List, 2).
List = [1, 2] ;
List = [2, 1] ;
false.
?- row_valid(List, 3).
List = [1, 2, 3] ;
List = [2, 1, 3] ;
List = [2, 3, 1] ;
List = [1, 3, 2] ;
List = [3, 1, 2] ;
List = [3, 2, 1] ;
false.

Related

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.

Find all natural divisors of a number (with Prolog)

I want to create a predicate divisors(X,[Y]) which is true if
X>1 and Y is the list of all divisors of X starting with X and going down to 1.
What my code right now looks like:
divisors(1,[1]).
divisors(X,[Y,Z|Ys]) :-
X>0,
Y is X,
Y>Z,
divides(X,[Z|Ys]).
divides(X,[Y,Z|Ys]) :-
Y>Z,
0 is X mod Y,
divides(X,[Z|Ys]).
divides(X,[1]).
But there are several problems with it:
prolog returns an error if asked for the list (e.g. ?-divisors(10,X).)
?- divisors(X,[Y]). Where [Y] is an incomplete list of divisors is true...
Edit by Guy Coder
This answer is by the OP and was posted in a comment below.
Moving here so others can see it.
divisors(X,R) :-
X > 1,
divisors(X,1,[],R).
divisors(X,D,R,R):-
D>X.
divisors(N,D0,R0,R) :-
divisors_0(N,D0,R0,R1),
D is D0 + 1,
divisors(N,D,R1,R).
divisors_0(N,D,R0,[D|R0]) :-
divides(N,D).
divisors_0(N,D,R0,R0).
divides(N,D) :-
0 is N mod D.
Op also noted some errors in this version:
It doesn't terminate if I ask a wrong statement like (10,[1,2,3]).
It throws an error if I ask a statement like (X, [10,5,2,1]). (-> Arguments are not sufficiently initialized.)
While the answer by William is nice and probably faster here is answer closer to what you were writing.
divides(N,D) :-
0 is N mod D.
divisors_0(N,D,R0,[D|R0]) :-
divides(N,D).
divisors_0(N,D,R0,R0) :-
\+ divides(N,D).
divisors(_,0,R,R).
divisors(N,D0,R0,R) :-
divisors_0(N,D0,R0,R1),
D is D0 - 1,
divisors(N,D,R1,R).
divisors(X,R) :-
X > 1,
divisors(X,X,[],R), !.
Example:
?- between(1,15,N), divisors(N,Rs).
N = 2,
Rs = [1, 2] ;
N = 3,
Rs = [1, 3] ;
N = 4,
Rs = [1, 2, 4] ;
N = 5,
Rs = [1, 5] ;
N = 6,
Rs = [1, 2, 3, 6] ;
N = 7,
Rs = [1, 7] ;
N = 8,
Rs = [1, 2, 4, 8] ;
N = 9,
Rs = [1, 3, 9] ;
N = 10,
Rs = [1, 2, 5, 10] ;
N = 11,
Rs = [1, 11] ;
N = 12,
Rs = [1, 2, 3, 4, 6, 12] ;
N = 13,
Rs = [1, 13] ;
N = 14,
Rs = [1, 2, 7, 14] ;
N = 15,
Rs = [1, 3, 5, 15].
Edit
OP modified their code, see update in question and had some errors.
This version resolves those errors.
divisors(X,R) :-
(
var(X)
->
false
;
(
var(R)
->
X > 1,
divisors(X,1,[],R)
;
divisors_2(X,R), !
)
).
divisors_2(_,[]).
divisors_2(X,[H|T]) :-
divides(X,H),
divisors_2(X,T).
divisors(X,D,R,R):-
D>X.
divisors(N,D0,R0,R) :-
divisors_0(N,D0,R0,R1),
D is D0 + 1,
divisors(N,D,R1,R).
divisors_0(N,D,R0,[D|R0]) :-
divides(N,D).
divisors_0(_,_,R0,R0).
divides(N,D) :-
0 is N mod D.
The first error: It doesn't terminate if I ask a wrong statement like divisors(10,[1,2,3]).
is fixed by adding to divisors/2
(
var(R)
->
X > 1,
divisors(X,1,[],R)
;
divisors_2(X,R), !
)
and
divisors_2(_,[]).
divisors_2(X,[H|T]) :-
divides(X,H),
divisors_2(X,T).
which just processes the list of denominators instead of generating a list.
The second error: It throws an error if I ask a statement like divisors(X, [10,5,2,1]). (-> Arguments are not sufficiently initialized.)
is resolved by further adding to divisor/2
divisors(X,R) :-
(
var(X)
->
false
;
(
var(R)
->
X > 1,
divisors(X,1,[],R)
;
divisors_2(X,R), !
)
).
which checks if the first parameter X is a variable and if so just returns false. The other option would be to generate an infinite list of answers. While possible it wasn't requested.
In Prolog, it is quite common to use backtracking and propose multiple solutions to the same query. Instead of constructing a list of dividers, we thus can construct a predicate that unifies the second parameter with all divisors. For example:
divisor(N, D) :-
between(1, N, D),
0 is N mod D.
This then yields:
?- divisor(12, N).
N = 1 ;
N = 2 ;
N = 3 ;
N = 4 ;
N = 6 ;
N = 12.
The above algorithm is an O(n) algorithm: we scan for divisors linear with the value of the item for which we want to obtain the divisors. We can easily improve this to O(√n) by scanning up to √n, and each time yield both the divisor (of course in case it is a divisor), and the co-divisor, like:
emitco(D, _, D).
emitco(D, C, C) :-
dif(D, C).
divisor(N, R) :-
UB is floor(sqrt(N)),
between(1, UB, D),
0 is N mod D,
C is N / D,
emitco(D, C, R).
This still yield the correct answers, but the order is like a convergent alternating sequence:
?- divisor(12, N).
N = 1 ;
N = 12 ;
N = 2 ;
N = 6 ;
N = 3 ;
N = 4.
?- divisor(16, N).
N = 1 ;
N = 16 ;
N = 2 ;
N = 8 ;
N = 4 ;
false.
We can obtain a list of the divisors by using a findall/3 [swi-doc] or setof/3 [swi-doc]. The setof/3 will even sort the divisors, so we can implement divisors/2 in terms of divisor/2:
divisors(N, Ds) :-
setof(D, divisor(N, D), Ds).
For example:
?- divisors(2, N).
N = [1, 2].
?- divisors(3, N).
N = [1, 3].
?- divisors(5, N).
N = [1, 5].
?- divisors(12, N).
N = [1, 2, 3, 4, 6, 12].
?- divisors(15, N).
N = [1, 3, 5, 15].
We can use reverse/2 to reverse that result.

printing pairs of a list in SWI-prolog

basically, I want to print pairs from one list like this
?- [1 2 3 4 5,R]
the output is
R = [1, 2]
R = [1, 3]
R = [1, 4]
R = [1, 5]
R = [2, 3]
R = [2, 4]
R = [2, 5]
R = [3, 4]
R = [3, 5]
R = [4, 5]
I used the code that creates subsets and modified it
sub(0,_,[]).
sub(N,[X|T],[X|R]):-N>0,N1 is N-1,sub(N1,T,R).
sub(N,[_|T],R):-N>0,sub(N,T,R).
and I would call
sub(2,[1,2,3,4,5],R)
but is there a way to do it without using a counter?
Prolog is about defining relations (in the form of rules) and to try to avoid thinking procedurally (steps of execution to achieve a result). You can solve this by breaking it down into simple rules for the pairs:
For a list with head H and tail T, a valid pair is [H,E] where E is a member of T.
For a list with head H and tail T, a valid pair is a pair taken from T.
If you think about these rules, they are (1) mutually exclusive (there isn't a solution that matches both rules), and (2) they are complete (they cover all of the valid solutions).
Writing these in Prolog, you get:
pair([H|T], [H,E]) :- member(E, T).
pair([_|T], P) :- pair(T, P).
This provides a relational solution which yields:
| ?- sub([a,b,c,d], S).
S = [a,b] ? ;
S = [a,c] ? ;
S = [a,d] ? ;
S = [b,c] ? ;
S = [b,d] ? ;
S = [c,d] ? ;
(1 ms) no
| ?-
And works in a more general case:
| ?- pair(L, P).
L = [A,B]
P = [A,B] ? ;
L = [A,B|_]
P = [A,B] ? ;
L = [A,_,B|_]
P = [A,B] ? ;
L = [A,_,_,B|_]
P = [A,B] ? ;
...
an easy way:
?- L = [1,2,3,4,5], forall((nth1(I,L,X), nth1(J,L,Y), I<J), writeln(I/J)).
1/2
1/3
1/4
1/5
2/3
2/4
2/5
3/4
3/5
4/5
L = [1, 2, 3, 4, 5].
Yes, there is, since you don't have to account for subsets of arbitrary length.
There are two steps you need to account for, and both have two variants.
Select the first element of the pair:
Use the head of the list
Discard the head and pick it out of the tail of the list
Select the second element of the pair:
Use the head of the list
Discard the head and pick it out of the tail of the list
% Use the head as the first element
pairs((H, P2), [H | T]) :- pairs((H, P2), T).
% If we have the first element, use the head as the second element
pairs((P1, H), [H | _]) :- nonvar(P1).
% Ignore the head and pick what we need out of the tail
pairs(P, [_ | T]) :- pairs(P, T).

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