Find repeating sublists in list using Prolog - 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]].

Related

output a binary tree in preorder as a list in prolog

I am trying to create a list as output for a binary tree in prolog here is my code so far.
preorder(node(R, empty, empty),[R]).
preorder(node(R,Lb,Rb),[R|Ys]) :- preorder(Lb, Ys).
preorder(node(R,Lb,Rb),[R|Ys]) :-preorder(Rb, Ys).
My thought being that you traverse the tree and add the R to the rest list Ys.
it doesnt work as intendet though
?- preorder(node(1,node(2,empty,empty),node(3,empty,empty)),Z).
Z = [1, 2] ;
Z = [1, 3] ;
false.
This is the query I try to run and what I get. Prolog gives me all possible ways to the leafs, but I want just one list with all values in preorder, so basically the 2 lists combined([1,2,3]).
You can use the following code:
preorder(T, L) :-
preorder(T, [], L).
preorder(empty, L, L).
preorder(node(R, Lb, Rb), L0, [R|L2]) :-
preorder(Rb, L0, L1),
preorder(Lb, L1, L2).
Examples:
?- preorder(node(1,node(2,empty,empty),node(3,empty,empty)), L).
L = [1, 2, 3].
?- preorder(empty, L).
L = [].
?- preorder(node(1, empty, empty), L).
L = [1].
?- preorder(node(1,node(2,node(3,empty,empty),node(4,empty,empty)),node(5,empty,empty)), L).
L = [1, 2, 3, 4, 5].

Prolog - Why does my definition for append_list not return the combined list?

% appends an element to the beginning of a list.
append_element(X, T, [X|T]).
% append a list to another list to create a combined list,
% by breaking the first list apart, and using append_element.
append_list([], L, L).
append_list([H|T], L, NewList) :-
append_element(H, L, NL),
append_list(T, NL, NL).
When I try to run append_list,
?- append_list([1,2], [3, 4, 5], NL).
I get back false. Instead of
NL = [2, 1, 3, 4, 5].
Why?

Storing results in a list in Prolog

I am trying to compute arithmetic calculations and store the results in a new list in Prolog.
The function prototype goes as follows:
calculation(List1, ListofLists, ResultList)
for the first argument I provide a list, for the second argument a list of lists and third the result list. I compute the first argument list with each list of list of lists and store the result in the resulting list.
So can somebody tell me how can I store results in the resulting (empty) list?
With library lambda you can write:
:- use_module(library(lambda)).
:- use_module(library(clpfd)).
calculation(L1, L2, Compute, L) :-
maplist([L2,Compute] +\X^Y^call(Compute,L2, X, Y), L1, L).
% my_compute succeeds when R is the list of all the products
% of the numbers component of L with the number V
my_compute(L, V, R) :-
maplist(V +\X^Y^maplist(V +\Z^T^(T #= Z * V), X, Y), L, R).
Here is an example:
?- calculation([1,2,3], [[4,5],[6,7]], my_compute, Zss).
Zss = [[[4, 5], [6, 7]], [[8, 10], [12, 14]], [[12, 15], [18, 21]]].
?- Zss = [[[4,5],[6,7]],[[8,10],[12,14]],[[12,15],[18,21]]],
calculation(Xs, [[4,5],[6,7]], my_compute, Zss).
Xs = [1, 2, 3].
?- Zss = [[[4,5],[6,7]],[[8,10],[12,14]],[[12,15],[18,21]]],
calculation([1,2,3], Xss, my_compute, Zss).
Xss = [[4, 5], [6, 7]].
calculation([], [], []).
calculation([X|Xs], [Y|Ys], [Z|Zs]) :-
calculate(X, Y, Z),
calculation(Xs, Ys, Zs).
which is identical to:
calculation(X, Y, Z) :-
maplist(calculate, X, Y, Z).
either way, you need a predicate calculate/3 that takes a first argument, a list of lists as the second argument, and calculates a result. For example, summing the list in the second argument and multiplying it to the first argument:
calculate(X, Ys, Z) :-
list_sum(Ys, S),
Z is X * S.
If I understood correctly, you want to do some computation on List1 and every member of ListofLists, and get a list of results.
You can do this using findall:
calculation(List1, ListofLists, ResultList) :-
findall(Result, (
member(List2, ListofLists),
your_computation(List1, List2, Result)
), ResultList).
For example, if you replace your_compuation with append, you get:
?- calculation([a,b],[[c,d],[e,f,g],[h]],X).
X = [[a, b, c, d], [a, b, e, f, g], [a, b, h]].

Getting the product of a list from left to right

How do you get the product of a list from left to right?
For example:
?- product([1,2,3,4], P).
P = [1, 2, 6, 24] .
I think one way is to overload the functor and use 3 arguments:
product([H|T], Lst) :- product(T, H, Lst).
I'm not sure where to go from here.
You can use library(lambda) found here : http://www.complang.tuwien.ac.at/ulrich/Prolog-inedit/lambda.pl
Quite unreadable :
:- use_module(library(lambda)).
:- use_module(library(clpfd)).
product(L, R) :-
foldl(\X^Y^Z^(Y = []
-> Z = [X, [X]]
; Y = [M, Lst],
T #= X * M,
append(Lst, [T], Lst1),
Z = [T, Lst1]),
L, [], [_, R]).
Thanks to #Mike_Hartl for his advice, the code is much simple :
product([], []).
product([H | T], R) :-
scanl(\X^Y^Z^( Z #= X * Y), T, H, R).
seems like a list copy, just multiplying by last element handled. Let's start from 1 for the leftmost element:
product(L, P) :-
product(L, 1, P).
product([X|Xs], A, [Y|Ys]) :-
Y is X * A,
product(Xs, Y, Ys).
product([], _, []).
if we use library(clpfd):
:- [library(clpfd)].
product([X|Xs], A, [Y|Ys]) :-
Y #= X * A,
product(Xs, Y, Ys).
product([], _, []).
it works (only for integers) 'backward'
?- product(L, [1,2,6,24]).
L = [1, 2, 3, 4].
Probably very dirty solution (I am new to Prolog):
product([ListHead|ListTail], Answer) :-
product_acc(ListTail, [ListHead], Answer).
product_acc([ListHead|ListTail], [AccHead|AccTail], Answer) :-
Product is ListHead * AccHead,
append([Product, AccHead], AccTail, TempList),
product_acc(ListTail, TempList, Answer).
product_acc([], ReversedList, Answer) :-
reverse(ReversedList, Answer).
So basically at the beginning we call another predicate which has
extra "variable" Acc which is accumulator list.
So we take out head (first number) from original list and put it in
to Accumulator list.
Then we always take head (first number) from original list and
multiply it with head (first number) from accumulator list.
Then we have to append our new number which we got by multiplying
with the head from accumulator and later with the tail
Then we call same predicate again until original list becomes empty
and at the end obviously we need to reverse it.
And it seems to work
?- product([1,2,3,4], L).
L = [1, 2, 6, 24].
?- product([5], L).
L = [5].
?- product([5,4,3], L).
L = [5, 20, 60].
Sorry if my explanation is not very clear. Feel free to comment.

How to create a list of numbers that add up to a specific number

I need some help writing a predicate in Prolog that, given a number as input, returns a list of lists with numbers that add up to it.
Let's call the predicate addUpList/2, it should work like this:
?- addUpList(3,P).
P = [[1,2], [2,1], [1,1,1]]. % expected result
I'm having so much trouble figuring this out I'm beginning to think it's impossible. Any ideas? Thanks in advance.
Try this:
condense([], Rs, Rs).
condense([X|Xs], Ys, Zs) :-
condense(Xs, [X|Ys], Zs).
condense([X, Y|Xs], Ys, Zs) :-
Z is X + Y,
condense([Z|Xs], Ys, Zs).
condense(Xs, Rs) :-
condense(Xs, [], Rs).
expand(0, []).
expand(N, [1|Ns]) :-
N > 0,
N1 is N - 1,
expand(N1, Ns).
addUpList(N, Zs) :-
expand(N, Xs),
findall(Ys, condense(Xs, Ys), Zs).
Let me know what marks I get. :-)
The rule num_split/2 generates ways of splitting a number into a list, where the first element X is any number between 1 and N and the rest of the list is a split of N-X.
num_split(0, []).
num_split(N, [X | List]) :-
between(1, N, X),
plus(X, Y, N),
num_split(Y, List).
In order to get all such splits, just call findall/3 on num_split/2.
add_up_list(N, Splits) :-
findall(Split, num_split(N, Split), Splits).
Usage example:
?- add_up_list(4, Splits).
Splits =
[[1, 1, 1, 1], [1, 1, 2], [1, 2, 1], [1, 3], [2, 1, 1], [2, 2], [3, 1], [4]].
See also the post by #hardmath which gives the same answer with a bit more explanation.
The example given in the Question suggests that compositions (ordered partitions) of any positive integer N ≤ 10 are wanted. Note however that the solution [3] for N=3 seems to have been omitted/overlooked. The number of compositions of N is 2^(N-1), so N=10 gives a long list but not an unmanageable one.
It is also desired to collect all such solutions into a list, something that findall/3 can do generically after we write a predicate composition/2 that generates them.
The idea is to pick the first summand, anything between 1 and N, subtract it from the total and recurse (stopping with an empty list when the total reaches zero). SWI-Prolog provides a predicate between/3 that can generate those possible first summands, and Amzi! Prolog provides a similar predicate for/4. For the sake of portability we write our own version here.
summand(Low,High,_) :-
Low > High,
!,
fail.
summand(Low,High,Low).
summand(Low,High,Val) :-
Now is Low + 1,
summand(Now,High,Val).
composition(0,[ ]).
composition(N,[H|T]) :-
summand(1,N,H),
M is N - H,
composition(M,T).
Given the above Prolog source code, compiled or interpreted, a list of all solutions can be had in this way:
?- findall(C,composition(3,C),L).
C = H126
L = [[1, 1, 1], [1, 2], [2, 1], [3]]
Of course some arrangement of such a list of solutions or the omission of the singleton list might be required for your specific application, but this isn't clear as the Question is currently worded.
There are plenty of great answers to this question already, but here is another solution to this problem for you to consider. This program differs from the others in that it is very efficient, and generates non-redundant solutions of lists which are assumed to represent sets of integers which add up to the specified number.
gen(N, L) :-
gen(N-1, N, N, FL),
dup_n(FL, L).
gen(C-F, M, M, [C-F]).
gen(C-F, S, M, [C-F|R]) :-
S < M, C > 1,
C0 is C - 1,
F0 is floor(M / C0),
S0 is S + (C0 * F0),
gen(C0-F0, S0, M, R).
gen(C-F, S, M, R) :-
F > 0,
F0 is F - 1,
S0 is S - C,
gen(C-F0, S0, M, R).
dup_n([], []).
dup_n([_-0|R], L) :-
!, dup_n(R, L).
dup_n([V-F|R], [V|L]) :-
F0 is F - 1,
dup_n([V-F0|R], L).
Your implementation of addUpList/2 can be achieved by:
addUpList(N, P) :-
findall(L, gen(N, L), P).
Which should give you the following behaviour:
?- addUpList(4,L).
L = [[4], [3, 1], [2, 2], [2, 1, 1], [1, 1, 1, 1]].
Note that the list containing one 2 and two 1s only appears once in this result set; this is because gen/4 computes unique sets of integers which add up to the specified number.
This answer is somewhere between
#Kaarel's answer and
#sharky's "efficient" answer.
Like #sharky's code, we impose an ordering relation between adjacent list items to restrict the size of the solution space---knowing how to inflate it if we ever need to. So the solution sets of break_down/2 and gen/2 by #sharky are equal (disregarding list reversal).
And as for performance, consider:
?- time((break_down(40,_),false)).
% 861,232 inferences, 0.066 CPU in 0.066 seconds (100% CPU, 13127147 Lips)
false.
?- time((gen(40,_),false)).
% 8,580,839 inferences, 0.842 CPU in 0.842 seconds (100% CPU, 10185807 Lips)
false.

Resources