Arrangements of elements of a list in prolog - prolog

domains
el=integer
list = el*
lista = list*
predicates
aux(list,integer,list)
arrangements(list,integer,lista)
clauses
aux([H|_],1,[H]).
aux([_|L],N,L1):-
aux(L,N,L1).
aux([H|L],N,[H|L1]):-
N<>1,
N1=N-1,
aux(L,N1,L1).
arrangements(L,N,R):-
findall(X,aux(L,N,X),R).
This code shows all the combinations of elements of a list. How should I modify it to show the arrangements. I have no ideas
arrangements
[2,3,4] K=2 => [[2,3], [3,2], [2,4], [4,2], [3,4], [4,3]]
combinations
[2,3,4] K=2 => [[3,4], [2,3], [2,4]]

Use select in aux/3 to get any of the permutations from the list:
aux(L, N, [H|T]) :-
N > 1,
select(H, L, M), % Select an element "H" from "L", leaving "M"
N1 is N-1, % NOTE the "is" here, not "=" !!
aux(M, N1, T). % Recurse with remaining elements "M" and count-1
aux(L, 1, [X]) :- member(X, L).
arrangements(L, N, R):-
findall(X, aux(L, N, X), R).
Resulting in:
| ?- arrangements([2,3,4], 2, R).
R = [[2,3],[2,4],[3,2],[3,4],[4,2],[4,3]]
yes

Related

How to use an fd solver to determine which elements of a list can sum to a given number?

Given a list of possible summands I want to determine which, if any, can form a given sum. For example, with [1,2,3,4,5] I can make the sum of 9 with [4,5], [5,3,1], and [4,3,2].
I am using GNU Prolog and have something like the following which does not work
numbers([1,2,3,4,5]).
all_unique(_, []).
all_unique(L, [V|T]) :-
fd_exactly(1, L, V),
all_unique(L, T).
fd_sum([], Sum).
fd_sum([H|T], Sum):-
S = Sum + H,
fd_sum(T, S).
sum_clp(N, Summands):-
numbers(Numbers),
length(Numbers, F),
between(1, F, X),
length(S, X),
fd_domain(S, Numbers),
fd_domain(Y, [N]),
all_unique(S, Numbers),
fd_sum(S, Sum),
Sum #= Y,
fd_labeling(S).
I think the main problem is that I am not representing the constraint on the sum properly? Or maybe it is something else?
Just in case you're really interested in CLP(FD), here is your corrected program.
numbers([1,2,3,4,5]).
% note: use builtins where available, both for efficiency and correctness
%all_unique(_, []).
%all_unique(L, [V|T]) :-
% fd_exactly(1, L, V),
% all_unique(L, T).
fd_sum([], 0). % sum_fd_SO.pl:8: warning: singleton variables [Sum] for fd_sum/2
fd_sum([H|T], Sum):-
% note: use CLP(FD) operators and the correct operands
Sum #= S + H,
fd_sum(T, S).
sum_clp(N, S):- % sum_fd_SO.pl:13-23: warning: singleton variables [Summands] for sum_clp/2
numbers(Numbers),
length(Numbers, F),
between(1, F, X),
length(S, X),
fd_domain(S, Numbers),
%fd_domain(Y, [N]),
%all_unique(S, Numbers),
fd_all_different(S),
fd_sum(S, N),
%Sum #= Y,
fd_labeling(S).
test
?- sum_clp(3,L).
L = [3] ? ;
L = [1,2] ? ;
L = [2,1] ? ;
no
I think mixing the code for sublist into clp code is causing some confusion. GNU-Prolog has a sublist/2 predicate, you can use that.
You seem to be building the arithmetic expression with fd_sum but it is incorrectly implemented.
sum_exp([], 0).
sum_exp([X|Xs], X+Xse) :-
sum_exp(Xs, Xse).
sum_c(X, N, Xsub) :-
sublist(Xsub, X),
sum_exp(Xsub, Xe),
N #= Xe.
| ?- sum_exp([A, B, C, D], X).
X = A+(B+(C+(D+0)))
yes
| ?- sum_c([1, 2, 3, 4, 5], 9, X).
X = [4,5] ? ;
X = [2,3,4] ? ;
X = [1,3,5] ? ;
(1 ms) no
| ?- length(X, 4), sum_c(X, 4, [A, B]), member(A, [1, 2, 3]).
A = 1
B = 3
X = [_,_,1,3] ? ;
A = 2
B = 2
X = [_,_,2,2] ? ;
A = 3
B = 1
X = [_,_,3,1] ?
yes

Swap function in prolog, infinite loop

I am trying to create a swap function in prolog but I ended up with an infinite loop, I tried to debug it using trace()
An example of this function is swap(4, 3, ["You", "Are", "Awesome", "thank", "You"], SwappedList)
With the output being
["You", "Are", "thank", "Awesome", "You"]
In the trace output, it is showing that the problem is in the delete as it is failing and redoes the split
/* Getting the nth element of the list*/
n_thelement(1, [Head|_], Head).
n_thelement(N, [_|Tail], Item):-
NewN is N-1,
n_thelement(NewN, Tail, Item).
/* Deleting the element of the desired Nth element*/
delete(X, [X|Tail], Tail).
delete(X, [Head|Tail], [Head|Item]):-
delete(X, Tail, Item).
/* Adding the deleted element to the beginning of the list*/
append([], Element, Element).
append([Head], Element, [Head|Element]).
swap(X, X, List, List).
swap(X, Y, List, NList):-
n_thelement(X, List, Num1),
n_thelement(Y, List, Num2),
split(X, List, B1, A1),
delete(Num1, A1, L1),
append([Num2], L1, NList1),
append(B1, NList1, NList2),
split(Y, NList2, B2, A2),
delete(Num2, A2, L2),
append([Num1], L2, NList3),
append(B2, NList3, NList).
split(1, [Head|Tail], Head, Tail).
split(N, [Old_List|New_List], Old_List, New_List):-
NewN is N -1,
split(NewN, _, Old_List, New_List).
If I understand your problem statement correctly, given to indices into a list, M and N such that M < N and M and N are both valid indices into the list, you want to swap the elements at those indices.
I would first make the indices zero-relative instead of 1-relative as that makes the math a little easier.
So, you want to break up the list into 5 pieces, 3 of which are themselves lists of any length and two of which are the list entries to be swapped:
As: The lead-in prefix of the list. It is of length M.
B: The 1st item to be swapped.
Cs: The middle segment of the list. It is of length N - (M+1).
D: The 2nd item to be swapped.
Es: The suffix/remainder of the list. It is of any length.
append/3 is useful for deconstruction and reconstruction of lists, making the actual swap easy. You have 3 cases.
First, the special case of both indices being the same, in which case, there is no work to do:
swap( M, M, Ls, Ls ).
Second, the case of the indices being out of order, in which case we just recursively swap them to put them in order:
swap( M, N, Ls, Rs ) :- M > N, swap(N,M,Ls,Rs).
Third, the general case:
swap( M, N, Ls, Rs ) :- % if the 2 indices differ
M < N, % - and are in order
M >= 0, % - and M is greater than or equal to zero
N >= 0, % - and N is greater than or equal to zero
X is N - (M+1), % - compute the length of the middle segment
length( As, M ), % - construct an empty, unbound list of length M, the length of the prefix
length( Cs, X ), % - and construct an empty, unbound list of that length
append( As, [B|T1], Ls), % - get the prefix (As) and the first item (B) to be swapped
append( Cs, [D|Es], T1), % - get the middle segment (Cs), the second item (D) to be swapped, and the suffix (Es)
append( As, [D|Cs], T2), % - concatenate As, D, and Cs, then...
append( T2, [B|Es], Rs ) % - concatenate that with B and the suffix
. % Easy!
You can define a predicate to replace the i-th item of the list for another:
replace(Index, [Old|Rest], [New|Rest], Old, New) :- Index == 0, !.
replace(Index, [First|Rest], [First|NewRest], Old, New) :-
Index > 0,
Previous is Index - 1,
replace(Previous, Rest, NewRest, Old, New).
Examples:
?- replace(1, [a,b,c,d,e], List1, Old1, x).
List1 = [a, x, c, d, e],
Old1 = b.
?- replace(1, [a,b,c,d,e], List1, Old1, New1).
List1 = [a, New1, c, d, e],
Old1 = b.
?- replace(4, [a,b,c,d,e], List2, Old2, New2).
List2 = [a, b, c, d, New2],
Old2 = e.
Then, using this predicate, you can define:
swap(I, J, OldList, NewList) :-
replace(I, OldList, List, X, Y),
replace(J, List, NewList, Y, X).
Examples:
?- swap(3, 2, ["You", "Are", "Awesome", "thank", "You"], L).
L = ["You", "Are", "thank", "Awesome", "You"].
?- swap(1, 4, [a,b,c,d,e], L).
L = [a, e, c, d, b].
?- swap(0, 3, [a,b,c,d,e], L).
L = [d, b, c, a, e].
?- swap(1, 0, [a,b,c,d,e], L).
L = [b, a, c, d, e].
?- swap(2, 2, [a,b,c,d,e], L).
L = [a, b, c, d, e].
?- swap(3, 9, [a,b,c,d,e], L).
false.

Prolog: decompose number into its digits

I am studying prolog and I am faced with a problem that I cannot deal with.
Given a number, I have to check if the sum of the factorial of each digit that composes it is equal to the number itself.
Example:
145
1! + 4! + 5! = 1 + 24 + 120
Now my problem is just how to decompose the number so that I can factorial and sum each digit.
EDIT1.
thank to #slago I understand how decompose the number, but now I have a problem to sum the factorial terms:
fact(N):-
fact(N, N, _ListNumber).
fact(N, 0, ListNumber):-
factorial(ListNumber, 1, Sum),
Sum == N.
fact(N, Number, [D|R]):-
D is Number mod 10,
Number1 is Number div 10,
fact(N, Number1, R).
factorial([], Counter, Counter).
factorial([D|R], Counter, Sum):-
print([D|R]),
checksum(D, Counter),
factorial(R, Counter, Sum).
checksum(D, Counter):-
Counter1 is Counter * D,
M is D - 1,
M >= 2, !,
checksum(M, Counter1).
I have tried like this, but I noticed [D|R] results empty, and I don't understand why.
Your code is organized in a very confusing way. It is best to code independent predicates (for more specific purposes) and, after that, use them together to get the answer you want.
Start by creating a predicate to decompose a natural number into digits.
decompose(N, [N]) :- N<10, !.
decompose(N, [D|R]) :- N>=10, D is N mod 10, M is N//10, decompose(M, R).
Example of decomposition:
?- decompose(145, D).
D = [5, 4, 1].
Then, create a predicate to compute the factorial of a natural number.
fact(N, F) :- fact(N, 1, F).
fact(0, A, A) :- !.
fact(N, A, F) :- N>0, M is N-1, B is N*A, fact(M, B, F).
Example of factorial:
?- fact(5, F).
F = 120.
After that, create a predicate to map each number of a list into its corresponding factorial (alternatively, you could use the predefined predicate maplist/3).
map_fact([], []).
map_fact([X|Xs], [Y|Ys]) :- fact(X,Y), map_fact(Xs, Ys).
Example of mapping:
?- decompose(145, D), map_fact(D, F).
D = [5, 4, 1],
F = [120, 24, 1].
You must also create a predicate to compute the sum of the items of a list (alternatively, you could use the predefined predicate sum_list/2).
sum(L, S) :- sum(L, 0, S).
sum([], A, A).
sum([X|Xs], A, S) :- B is A+X, sum(Xs, B, S).
Example of summation:
?- decompose(145, D), map_fact(D, F), sum(F, S).
D = [5, 4, 1],
F = [120, 24, 1],
S = 145.
Finally, create the predicate to check the desired number property.
check(N) :- decompose(N, D), map_fact(D, F), sum(F, N).
Example:
?- check(145).
true.
?- check(146).
false.

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?

Find repeating sublists in list using Prolog

I want to write a prolog predicate with the following output:
?- all_match([1,2,3,2,3,1,2],L).
L = [[], [1], [1, 2], [2], [2, 3], [3]].
?- all_match([1,1,1,2],L).
L = [[], [1], [1, 1]].
The purpose is to find the sublists that repeat more than once.
So far I found the solution to find all sublists in a list-
subSet(_, []).
subSet(L, [S|T]) :- append(_, L2,L), append([S|T], _, L2).
But I can't figure out how to repeat the search for every element.
Thanks in advance.
This code is a little different from your requirements, in that all_match/2 will omit the empty sequence and fail if there where no repeated subsequences in the input.
repeated(List, Sublist) :-
% For all prefixes, suffixes:
append(Sublist, Tail, List), Sublist \= [],
% For all suffixes of the former suffixes:
append(_, TailTail, Tail),
% Is the head of the latter suffix equal to the head of the input?
append(Sublist, _, TailTail).
repeated([_|List], Sublist) :-
% Strip leading character and continue
repeated(List, Sublist).
all_match(List, Lists) :-
% Aggregate all repeated sequences or fail if there weren't any.
setof(L, repeated(List, L), Lists).
A sketch of the idea of the first clause of repeated/2:
|----------------List------------------| repeated(List, Sublist)
|--Sublist--|------------Tail----------| append(Sublist, Tail, List)
|--Sublist--| |-----TailTail-----| append(_, TailTail, Tail)
|--Sublist--| |--Sublist--| | append(Sublist, _, TailTail)
Result:
?- all_match([1,2,3,2,3,1,2],L).
L = [[1], [1, 2], [2], [2, 3], [3]].
Update to allow overlapping sequences:
repeated([H|List], Sublist) :-
append(Sublist, _, [H|List]), Sublist \= [],
append(_, Tail, List),
append(Sublist, _, Tail).
repeated([_|List], Sublist) :-
repeated(List, Sublist).
I like Kay's answer (+1). Here a variation on thema
all_match(L, M) :-
take(L, M, R),
take(R, M, _).
take(L, [A|B], R) :- % use [A|B] to remove empties
append(_, T, L),
append([A|B], R, T).
yields
?- setof(L,all_match([1,2,3,2,3,1,2],L),R).
R = [[1], [1, 2], [2], [2, 3], [3]].

Resources