How to fix this permutation sort? - sorting

The following Prolog program defines a predicate sorted/2 for sorting by permutation (permutation sort) in ascending order a list passed in first argument, which results in the list passed in second argument:
sorted(X, Y) :-
permuted(X, Y),
ordered(Y).
permuted([], []).
permuted(U, [V|W]) :-
permuted(X, W),
deleted(V, U, X).
deleted(X, [X|Y], Y).
deleted(U, [V|W], [V|X]) :-
deleted(U, W, X).
ordered([]).
ordered([_]).
ordered([X, Y|Z]) :-
ordered([Y|Z]), X =< Y.
How to solve the following issues?
The program duplicates solutions for queries in which a list with duplicate elements is passed in second argument:
?- sorted(X, [1, 1, 2]).
X = [1, 1, 2]
; X = [1, 1, 2]
; X = [1, 2, 1]
; X = [1, 2, 1]
; X = [2, 1, 1]
; X = [2, 1, 1]
; false.
The program exhausts resources for queries in which a free variable is passed in second argument:
?- sorted([2, 1, 1], Y).
Y = [1, 1, 2]
; Y = [1, 1, 2]
;
Time limit exceeded
The Prolog program is based on the Horn clause program given at section 11 of Robert Kowalski’s famous paper Predicate Logic as Programming Language:

To solve non-termination, you can add same_length/2 to sorted/2 as #false suggested:
sorted(X, Y) :-
same_length(X, Y),
permuted(X, Y),
ordered(Y).
same_length([], []).
same_length([_|Xs], [_|Ys]) :-
same_length(Xs, Ys).
Or you may embed it into permuted/2 by adding a new argument:
sorted(X, Y) :-
permuted(X, X, Y),
ordered(Y).
permuted([], [], []).
permuted(U, [_|L1], [V|W]) :-
permuted(X, L1, W),
deleted(V, U, X).
The program will still return duplicates as it only sees one item at a time.
To solve duplication, you can either generate all permutations and discard the repeated ones (which is not efficient), or only generate distinct permutations. The following modification does the latter by taking the idea of the recursive procedure permuted/2 + deleted/2 which for each item puts it at the beginning of the list and does a recursive call on the remaining list, and changes it to another recursive procedure permuted_all/2 + deleted_all/2 which for each group of same items puts them at the beginning of the list and does a recursive call on the remaining list. This program uses difference lists for better efficiency:
sorted(X, Y) :-
same_length(X, Y),
permuted_all(X, Y),
ordered(Y).
permuted_all([], []).
permuted_all(U, [V|W]) :-
deleted_all(V, U, X, n-T, [V|W]),
permuted_all(X, T).
% deleted_all(Item, List, Remainder, n-T, Items|T)
deleted_all(_, [], [], y-[X|Xs], [X|Xs]).
deleted_all(X, [V|Y], [V|Y1], y-[X|Xs], Xs1) :-
dif(X, V),
deleted_all(X, Y, Y1, y-[X|Xs], Xs1).
deleted_all(X, [X|Y], Y1, _-Xs, Xs1) :-
deleted_all(X, Y, Y1, y-[X|Xs], Xs1).
deleted_all(U, [V|W], [V|X], n-T, Xs) :-
dif(U, V),
deleted_all(U, W, X, n-T, Xs).
Sample runs:
?- sorted(X, [1, 1, 2]).
X = [1, 2, 1]
; X = [1, 1, 2]
; X = [2, 1, 1]
; false.
?- sorted([2, 1, 1], Y).
Y = [1, 1, 2]
; false.
As per OPs comment asking for a version which does not use difference lists, here goes one which instead obtains the remainder using same_length/2 + append/3 and with added comments:
permuted_all([], []).
permuted_all(U, [V|W]) :-
deleted_all(V, U, X, n, [V|W]),
same_length(X, T), % the remaining list X has the same length as T
append(_, T, [V|W]), % T corresponds to the last items of [V|W]
permuted_all(X, T). % T is a permutation of X
% deleted_all(Item, List, Remainder, n, Items|_)
deleted_all(_, [], [], y, _). % base case
deleted_all(X, [V|Y], [V|Y1], y, Xs1) :-
% recursive step when the current item is not the one we are gathering
dif(X, V),
deleted_all(X, Y, Y1, y, Xs1).
deleted_all(X, [X|Y], Y1, _, [X|Xs1]) :-
% recursive step when the current item is the one we are gathering
deleted_all(X, Y, Y1, y, Xs1).
deleted_all(U, [V|W], [V|X], n, Xs) :-
% recursive step when we have not selected yet the item we will be gathering
dif(U, V),
deleted_all(U, W, X, n, Xs).

Your second problem can by solved by replacing first line with
sorted(X, Y) :-
permuted(X, Y),
ordered(Y),
!.
or
sorted(X, Y) :-
permuted(X, Y),
ordered(Y),
length(X, Z),
length(Y, Z).
The first one is not so easy to solve because of the implementation of this algorithm. Both 1st [1, 1, 2] and 2nd [1, 1, 2] are valid permutations since your code that generated permutations generates all permutations not unique permutations.

Related

Build a new list of elements which appears more than 3 times in old list in Prolog

My main task - build a new list of elements (numbers) that appear in the old list more than three times.
Asking query: res([1,2,2,3,3,3,4,4,4,4,5,5,5,5,5],X).
Expected result: X = [4, 5]
I have a code that counts the number of occurrences of each number:
count(_, [], 0).
count(Num, [H|T], X) :- dif(Num,H), count(Num, T, X).
count(Num, [H|T], X) :- Num = H, count(Num, T, X1), X is X1 + 1.
res(A, X) :- findall(X,count(_,A,X),X).
But it works little bit wrong - it gives X = [0, 5, 4, 3, 2, 1] instead X = [1, 2, 3, 4, 5].
I ignored this problem for while and tried this to finish main task:
count(_, [], 0).
count(Num, [H|T], X) :- dif(Num,H), count(Num, T, X).
count(Num, [H|T], X) :- Num = H, count(Num, T, X1), X is X1 + 1, X<3, X is Num.
res(A, X) :- findall(X,count(_,A,X),X).
But gives strange result: X = [0, 1]
Where i'm wrong? Thank you.
Reusing your first count predicate,
%countElement(Element, List, Nb_Element_in_List)
countElement(_, [], 0).
countElement(Num, [H|T], X) :- dif(Num,H), countElement(Num, T, X).
countElement(Num, [H|T], X) :- Num = H, countElement(Num, T, X1), X is X1 + 1.
Here is the predicate query/1
query(X) :-
L = [1,2,2,3,3,3,4,4,4,4,5,5,5,5,5],
countOneByOne(L, L, [], X).
%countOneByOne(A1,A2,In,Out)
%For each Element of A1, if it satisfies countElement(Element,A2,N) & N>4, is accumulated with In, to give Out
%Out is the list of Elements of A1 that satisfies countElement(Element,A2,N) & N>4, added to In
countOneByOne([], _, X, X).
countOneByOne([H|Xs], L, X1, X2) :-
countElement(H, L, N), N<4, !,
countOneByOne(Xs, L, X1, X2).
countOneByOne([H|Xs], L, X1, X2) :-
removeElement(Xs, H, Ss),
countOneByOne(Ss, L, [H|X1], X2).
%remove(List, Element, List_Without_Element)
removeElement( [], _, []).
removeElement([X|Xs], H, [X|R1]) :-
dif(X,H), removeElement(Xs, H, R1).
removeElement([X|Xs], X, R1) :-
removeElement(Xs, X, R1).
Not an answer but another approach using foldl/4 and the dict of SWI-Prolog.
Whenever I hear "scan through a list to perform a computation with a final result at the end", the appropriate approach is probably the "accumulator idiom". One hands a data structure (the "accumulator") between the calls where something happens with a list element, "accumulating" the result. foldl/N is meant to provide boilerplate code around this.
In this case the accumulator is the SWI_prolog dict accumulating "occurrence counts", which happens at each call to inc_for_key/3. At the end, we just need to select the entries with a high enough occurence count:
filter_occurrences(List,Limit,Reacheds,Finals) :-
foldl(inc_for_key,List,_{},Finals),
findall(Key,(Finals.Key >= Limit),Reacheds).
inc_for_key(Key,DictIn,DictOut) :-
(get_dict(Key,DictIn,X) -> succ(X,XP) ; XP=1),
put_dict(Key,DictIn,XP,DictOut).
Testing using plunit
:- begin_tests(filter_occurrences_less_than_n).
test("filter empty list",true(R == [])) :-
filter_occurrences([],3,R,_).
test("filter nonempty list #1 (limit 3)",true([R,Finals] == [[a,c],foo{a:4,b:2,c:3,d:1,e:1,f:1}])) :-
filter_occurrences([a,b,c,d,c,e,b,a,a,f,a,c],3,R,Finals),
dict_pairs(Finals,foo,_). % Sets the tag of the Finals dict to "foo"
test("filter nonempty list #2 (limit 4)",true([R,Finals] == [[a],foo{a:4,b:2,c:3,d:1,e:1,f:1}])) :-
filter_occurrences([a,b,c,d,c,e,b,a,a,f,a,c],4,R,Finals),
dict_pairs(Finals,foo,_). % Sets the tag of the Finals dict to "foo"
test("filter nonempty list #3 (limit 5)",true([R,Finals] == [[],foo{a:4,b:2,c:3,d:1,e:1,f:1}])) :-
filter_occurrences([a,b,c,d,c,e,b,a,a,f,a,c],5,R,Finals),
dict_pairs(Finals,foo,_). % Sets the tag of the Finals dict to "foo"
:- end_tests(filter_occurrences_less_than_n).
And so:
?- run_tests.
% PL-Unit: filter_occurrences_less_than_n .... done
% All 4 tests passed
true.

I don't know how to stop this from going into a loop

The question was to create a replace/4 predicate that would replace a certain element (X) from the first list with another element (Y) like x and finally store it into the last argument, a new list. I know there is obviously something wrong with my base case (?), but I can't seem to figure it out. When I trace this code, it starts of normal, but after the first list is empty, it starts adding anonymous variables. Please have mercy, I'm new to Prolog.
replace([], _, _, []).
replace([H|T], X, Y, N):-
H = X,
append(N, [Y], NL),
replace(T, X, Y, NL).
replace([H|T], X, Y, N):-
H \= X,
append(N, [H], NL),
replace(T, X, Y, NL).
A simple more efficient solution without append/3 would be:
replace([], _, _, []).
replace([X|T], X, Y, [Y|T1]):-replace(T, X, Y, T1).
replace([H|T], X, Y, [H|T1]):-dif(X,H), replace(T, X, Y, T1).
Note that it is much better to use predicate dif/2 instead of \= operator (it has more relational behavior: Just test dif(X,Y). and X\=Y. with X,Y unbound variables to see the difference).
Example:
?- replace([2,4,5,7,8,2,3,4],2,12,L).
L = [12, 4, 5, 7, 8, 12, 3, 4] ;
false.
Another solution would be using DCG:
replace([],_,_) -->[].
replace([X|T],X,Y) --> [Y],replace(T,X,Y).
replace([H|T],X,Y) --> [H],{dif(H,X)},replace(T,X,Y).
final_replace(In_L,X,Y,Out_L):- phrase(replace(In_L,X,Y),Out_L).
Example:
?- final_replace([2,4,5,7,8,2,3,4],2,12,L).
L = [12, 4, 5, 7, 8, 12, 3, 4] ;
false.

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.

Replace elements of a list in Prolog

I have a predicate variablize/3 that takes a list and replaces each item, in turn, with a variable, example:
% ?- variablize([a,b,c], X, L).
% L = [[X, b, c], [a, X, c], [a, b, X]]
Now I am trying to extend this predicate to accept a list of variables, example:
% ?- variablize([a,b,c], [X,Y], L).
% L = [[X, Y, c], [X, b, Y], [a, X, Y]]
My code so far is:
replace_at([_|Tail], X, 1, [X|Tail]).
replace_at([Head|Tail], X, N, [Head|R]) :- M is N - 1, replace_at(Tail, X, M, R).
replace_each([], _, _, [], _).
replace_each([_|Next], Orig, X, [Res|L], N) :-
replace_at(Orig, X, N, Res),
M is N + 1,
replace_each(Next, Orig, X, L, M).
variablize(I, X, L) :- replace_each(I, I, X, L, 1).
Any pointers? Do I extend replace_at/4 to have a list of indexes that should be skipped?
A simplified, builtin based way of implementing variablize/3
variablize(I, X, L) :-
bagof(R, U^select(U, I, X, R), L).
put in evidence that instead of select/4 we could have a distribute/3 that applies replacements of elements of X, when X becomes a list. select/4 can be implemented in this way
myselect(B, I, X, R) :-
append(A, [B|C], I), append(A, [X|C], R).
and this form is convenient because we have the part to the right of input list I, where I suppose you need to distribute remaining variables. Then a recursion on X elements should do:
distribute(I, [X|Xs], L) :-
append(A, [_|C], I),
distribute(C, Xs, R),
append(A, [X|R], L).
distribute(I, [], I).
distribute/3 behaves this way:
?- distribute([a,b,c,d],[1,2],X).
X = [1, 2, c, d] ;
X = [1, b, 2, d] ;
X = [1, b, c, 2] ;
X = [a, 1, 2, d] ;
X = [a, 1, c, 2] ;
X = [a, b, 1, 2] ;
false.
thus
variablize_l(I, X, L) :-
bagof(R, distribute(I, X, R), L).
give us:
?- variablize_l([a,b,c],[X,Y],L).
L = [[X, Y, c], [X, b, Y], [a, X, Y]].
edit
I initially wrote this way, for here the evidence of separating the distribution phase from list construction:
replace_v([_|T], X, [X|T]).
replace_v([L|T], X, [L|R]) :-
replace_v(T, X, R).
variablize(I, X, L) :-
bagof(E, replace_v(I, X, E), L).
variablize(L1,L2,L) :-
append(L1,L2,L3),
length(L1,Len1),
length(L2,Len2),
findall(L4,(combination(L3,Len1,L4),var_count(L4,Len2)),L).
combination(X,1,[A]) :-
member(A,X).
combination([A|Y],N,[A|X]) :-
N > 1,
M is N - 1,
combination(Y,M,X).
combination([_|Y],N,A) :-
N > 1,
combination(Y,N,A).
var_count([],0).
var_count([V|R],N) :-
var(V),
var_count(R,N1),
N is N1 + 1,
!.
var_count([A|R],N) :-
var_count(R,N).

Resources