Prolog insertion sort - prolog

There is a simple Prolog insertion sort alghoritm:
sorting([A|B], Sorted) :- sorting(B, SortedTail), insert(A, SortedTail, Sorted).
sorting([], []).
insert(A, [B|C], [B|D]) :- A #> B, !, insert(A, C, D).
insert(A, C, [A|C]).
It does well on normal lists:
?- sorting([5, 4, 9, 1, 3, 8], X).
X = [1, 3, 4, 5, 8, 9].
But I also need to sort sublist of list contains any of them:
?- sorting([2, 5, [5, 4, 3], [6, 3], 4, 8], X).
X = [2, 4, 5, 8, [5, 4, 3], [6, 3]].
Is what return now. And
?- sorting([2, 5, [5, 4, 3], [6, 3], 4, 8], X).
X = [2, 4, 5, 8, [3, 4, 5], [3, 6]].
what I need to return. So how can I sort sublist too? Thanks in advance!

I offer this simple solution:
Insert element in the sorted list
insert(X, [], [X]):- !.
insert(X, [X1|L1], [X, X1|L1]):- X=<X1, !.
insert(X, [X1|L1], [X1|L]):- insert(X, L1, L).
Use principe of insertion sort algorithm
insertionSort([], []):- !.
insertionSort([X|L], S):- insertionSort(L, S1), insert(X, S1, S).

Related

Prolog can't figure out how to append

I have a simple problem, and I know why what I'm doing is wrong, I just dont know how to do what I want.
I want to be able to find the max of list X and then append it to the result Xs. It would recurse slowly sorting the list until it was finished. I know there are better sorting algorithms but I want to try and make my problem work.
These are the 2 version of the code that I have tried but I seem to be getting no where
mysort([],_).
mysort([X,Y], Xs) :- max(X,M), mysort(Y,[M|Xs]).
mysort([],_).
mysort([X,Y], Xs) :- max(X,M),append(Xs, [M], Xs) mysort(Y,[M|Xs]).
I would hope to have some kind of hint to completing this code, or someone fixing this silly problem.
I am not sure if I understood your question correctly, but maybe you can use some of this:
Example one:
mysort(List, Result) :-
aggregate(max(X), member(X, List), Result).
Result:
mysort([1,2,3,4], Result).
Result = 4
Example two:
mysort(List, MaxList, Result) :-
aggregate(max(X), member(X, List), Max),
append(MaxList, [Max], Result).
Result:
mysort([1,2,300,3], [100, 200], Result)
Result = [100, 200, 300]
Example three:
mysort(List, Result) :- mysort(List, [], Result).
mysort([], Result, Result).
mysort([H | T], Tmp, Result) :-
aggregate(max(X), member(X, H), Max),
TmpResult = [Max | Tmp],
mysort(T, TmpResult, Result).
Result:
mysort([[122,2,3,4, 6, 10], [127,2,3,4, 6, 10], [127,2,3,4, 6, 10]], Result).
Result = [127, 127, 122]
[X,Y] is a list of 2 elements, then is not what you want.
Instead, you should concentrate on building a predicate select_max/3, that 'extracts' the maximal value and returns it and the list without it.
We could code it adapting the select/3 library predicate:
select_max(Max,List,Rest) :-
select(Max,List,Rest),
\+ (member(Other,List),Other#>Max).
Now you can try to build the main recursive mysort/2, I will left to you as an exercise (remember that the base case should instantiate the output list to empty).
First, you need a predicate to select a maximum element, separating it from the rest of the list. To do so:
Start by taking the first element of the list [X|Xs] as the current maximum element.
Then, recursively traverse the rest of the list (Xs) by comparing the current maximum element (X0) to the current first element (X1), separating the biggest of the two and putting the other in the rest.
Finally, when the list is empty, the current maximum element (Max) is indeed the maximum element of the original list.
% select_max(-Max, +List, -Rest)
select_max(Max, [X|Xs], Rest) :-
select_max(Xs, X, Max, Rest).
select_max([], Max, Max, []).
select_max([X1|Xs], X0, Max, [Lesser|Rest]) :-
compare(Relation, X0, X1),
sorted(Relation, X0, X1, Lesser, Bigger),
select_max(Xs, Bigger, Max, Rest).
sorted(=, A, B, A, B).
sorted(<, A, B, A, B).
sorted(>, A, B, B, A).
Example:
?- trace(select_max, +all), select_max(M, [5,3,7,1], R), trace(select_max, -all).
% select_max/3: [all]
% select_max/4: [all]
T [11] Call: select_max(_30924434, [5, 3, 7, 1], _30924438)
T [20] Call: select_max([3, 7, 1], 5, _30924434, _30924438)
T [29] Call: select_max([7, 1], 5, _30924434, _30929268)
T [38] Call: select_max([1], 7, _30924434, _30930168)
T [47] Call: select_max([], 7, _30924434, _30931068)
T [47] Exit: select_max([], 7, 7, [])
T [38] Exit: select_max([1], 7, 7, [1])
T [29] Exit: select_max([7, 1], 5, 7, [5, 1])
T [20] Exit: select_max([3, 7, 1], 5, 7, [3, 5, 1])
T [11] Exit: select_max(7, [5, 3, 7, 1], [3, 5, 1])
% select_max/3: Not tracing
% select_max/4: Not tracing
M = 7,
R = [3, 5, 1].
Afterwards, you should use predicate select_max/3 to define your sorting algorithm (aka. Bubble Sort) as follows:
% mysort(+List, -SortedList)
mysort(List, SortedList) :-
mysort(List, [], SortedList).
mysort([], SortedList, SortedList).
mysort([X|Xs], SortedSuffix, SortedList) :-
select_max(Max, [X|Xs], Rest),
mysort(Rest, [Max|SortedSuffix], SortedList).
Example:
?- trace(mysort, +all), mysort([5,3,7,1], S), trace(mysort, -all).
% mysort/2: [all]
% mysort/3: [all]
T [11] Call: mysort([5, 3, 7, 1], _36832)
T [20] Call: mysort([5, 3, 7, 1], [], _36832)
T [29] Call: mysort([3, 5, 1], [7], _36832)
T [38] Call: mysort([3, 1], [5, 7], _36832)
T [47] Call: mysort([1], [3, 5, 7], _36832)
T [56] Call: mysort([], [1, 3, 5, 7], _36832)
T [56] Exit: mysort([], [1, 3, 5, 7], [1, 3, 5, 7])
T [47] Exit: mysort([1], [3, 5, 7], [1, 3, 5, 7])
T [38] Exit: mysort([3, 1], [5, 7], [1, 3, 5, 7])
T [29] Exit: mysort([3, 5, 1], [7], [1, 3, 5, 7])
T [20] Exit: mysort([5, 3, 7, 1], [], [1, 3, 5, 7])
T [11] Exit: mysort([5, 3, 7, 1], [1, 3, 5, 7])
% mysort/2: Not tracing
% mysort/3: Not tracing
S = [1, 3, 5, 7].
More examples:
?- mysort([], S).
S = [].
?- mysort([5], S).
S = [5].
?- randseq(5, 100, L), mysort(L, S).
L = [77, 68, 11, 38, 65],
S = [11, 38, 65, 68, 77].
?- randseq(7, 100, L), mysort(L, S).
L = [57, 5, 16, 8, 11, 53, 55],
S = [5, 8, 11, 16, 53, 55, 57].

How to create a list without using findall? Prolog

I am generating permutations:
takeout(X,[X|T],T).
takeout(X,[F|R],[F|S]):-
takeout(X,R,S).
perm([],[]).
perm([X|Y],Z):-
perm(Y,W),
takeout(X,Z,W).
I want to know how to create a list of all the permutations without using findall.
Example:
?-perm([1,2,3],List).
List = [[1, 2, 3], [2, 1, 3], [2, 3, 1], [1, 3, 2], [3, 1, 2], [3, 2, 1]]
Group permutations by the element it starts with.
Take an element X and create permutations Ys1 without it in the original list.
Adding this element X as the first element of all these permutations we have the list XP of permutations starting with X.
Appending all the groups will give you all permutations.
cons(X, Xs, [X|Xs]).
perm([], [[]]).
perm(Xs, Ys) :-
dif(Xs, []),
maplist({Xs}/[X, XP]>>(select(X, Xs, Xs1),
perm(Xs1, Ys1),
maplist(cons(X), Ys1, XP)),
Xs, Yss),
append(Yss, Ys).
?- perm([1, 2, 3], X).
X = [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] ;
false.
?- length(Y, 8), perm(Y, X), length(X, N). %8 factorial
N = 40320
The idea is to generate permutations and test if you already created this permutation. I'm using the inbuild predicate permutation/2.
perm(Ori,Out):-
perm(Ori,[],Out).
perm(Ori,Acc,Ret):-
permutation(Ori,Perm),
\+ member(Perm,Acc),
!,
perm(Ori,[Perm|Acc],Ret).
perm(_,L,L).
?- perm([1,2,3],E).
E = [[3, 2, 1], [3, 1, 2], [2, 3, 1], [2, 1, 3], [1, 3, 2], [1, 2, 3]].
The code is not the fastest one since it checks multiple times for membership.

Prolog intersection of 2 lists of lists

I am trying to find the intersection of 2 different lists of lists. In other words, find out if all the lists in list1 intersect with any of the lists in list 2.
List1:
[[1,4],[1,6],[6,8],[8,10]]
List2:
[[], [10], [8], [8, 10], [6], [6, 10], [6, 8], [6, 8, 10]]
I want to find an item in list2 where all the items of list1 intersect.
A solution would be [4,6,8]
How would I do this?
A very simple implementation could be the following
intersect(L, M, E) :-
member(E, M),
maplist(intersect_(E), L).
intersect_(L, M) :-
member(E, L),
member(E, M).
Example queries:
?- intersect([[1,4],[1,6],[6,8],[8,10]], [[], [10], [8], [8, 10], [6], [6, 10], [6, 8], [6, 8, 10]], E).
false.
?- intersect([[1,4],[1,6],[6,8],[8,10]], [[], [10], [8], [8, 10], [6], [6, 10], [6, 8], [6, 8, 10], [4,6,8]], E).
E = [4, 6, 8] ;
E = [4, 6, 8] ; % This succeeds twice because the list [6,8] has two ways of satisfying the predicate
false.

Removing list within lists based on nth element

I've got a list of lists, for example:
[[1, 2, 3, 2], [1, 3, 4, 3], [1, 4, 5, 4], [2, 3, 5, 6], [1, 5, 6, 5],
[2, 4, 6, 8], [1, 6, 7, 6], [2, 5, 7, 10], [3, 4, 7, 12], [2, 6, 8, 12]]
I'd like to get the last element of and check to see if is the same as the 4th element of any of the other lists. If it is the same then leave the list alone, but if it is unique then remove the list. So in the example above I would be left with:
[[3, 4, 7, 12], [2, 6, 8, 12]]
Essentially I want to be remove all the lists where the last element is unique.
I've written a predicate to get the nth element:
my_membership(X, [X|_]).
my_membership(X, [_|Tail]) :-
my_membership(X, Tail).
where:
my_membership([_,_,_,Fourth],[[3, 4, 7, 12], [2, 6, 8, 12]]).
gives:
Fourth = 12
Fourth = 12
Start by building two basic predicates:
last([X], X).
last([_|T], X) :- last(T, X).
forth([_,_,_,F|_], F).
The first predicate extracts the last element of a list; the second predicate extracts the forth element of a list.
Now you can make a predicate that counts how many tomes an element X appears in forth place in any of the lists of a list of lists. Below, H in [H|T] is a list:
matching_forth([], _, 0).
matching_forth([H|T], X, R) :- forth(H, X), matching_forth(T, X, RR), R is RR + 1.
matching_forth([_|T], X, R) :- matching_forth(T, X, R).
With these predicates in place you can build a predicate for checking your condition. It will have three clauses - for a situation when the list is empty, for when the head list has a matching forth element in another list, and for situations when it doesn't:
my_membership([], [], _).
my_membership([H|T], [H|R], A) :-
last(H, X), matching_forth(A, X, C), C > 1, my_membership(T, R, A).
my_membership([_|T], R, A) :- my_membership(T, R, A).
The first and last clauses are self-explanatory. The middle clause extracts the last element from the head list, counts how many times it matches the forth element in the original list of lists (A stands for "all"), and adds H to the result when there is a match. Adding happens through unification with the head of the result list.
Finally, you need a my_membership/2 predicate to start off the recursive chain that passes along the original list of lists:
my_membership(L, R) :- my_membership(L, R, L).
Demo.
Here's a different twist on a potential solution. It uses an accumulator to collect members that we've seen already and checks along the way. The result saves those that have either been seen or are currently in the tail. It requires the use of the built-in, memberchk/2.
my_membership(L, R) :-
my_membership(L, [], R).
my_membership([], _, []).
my_membership([X|T], Acc, R) :-
X = [_,_,_,D],
( memberchk([_,_,_,D], Acc)
-> R = [X|T1],
Acc1 = Acc
; memberchk([_,_,_,D], T)
-> R = [X|T1],
Acc1 = [X|Acc]
; R = T1,
Acc1 = Acc
),
my_membership(T, Acc1, T1).
| ?- my_membership([[1, 2, 3, 2], [1, 3, 4, 3], [1, 4, 5, 4], [2, 3, 5, 6], [1, 5, 6, 5],
[2, 4, 6, 8], [1, 6, 7, 6], [2, 5, 7, 10], [3, 4, 7, 12], [2, 6, 8, 12]], L).
L = [[2,3,5,6],[1,6,7,6],[3,4,7,12],[2,6,8,12]]
yes

create a matrix and permutate each line

i can create a list from 0 to N and permutation it. But how can i make it into matrix and permutation each line just from matrix(2,L).
add(X,L,[X|L]).
add(X,[L|H],[L|R]):- add(X,H,R).
permut([],[]).
permut([L|H],R):- permut(H,R1),add(L,R1,R).
permutations(L,R):- findall(P,permut(L,P),R).
do_list(N, L) :- do_list1(N, [], L).
do_list1(0, L, L) :- !.
do_list1(N, R, L) :- N > 0,
N1 is N-1,
do_list1(N1, [N|R], L).
matrix(N,L):-
do_list(N,R),
permut(R,L).
not sure about your request. Here is a possible answer based on builtins...
3 ?- [user].
|: matrix(N, Mat) :- length(Rows, N), maplist(numlist(1,N), Rows), maplist(permutation, Rows, Mat).
% user://1 compiled 0.01 sec, 2 clauses
true.
4 ?- matrix(3, M).
M = [[1, 2, 3], [1, 2, 3], [1, 2, 3]] ;
M = [[1, 2, 3], [1, 2, 3], [1, 3, 2]] ;
M = [[1, 2, 3], [1, 2, 3], [2, 1, 3]] ;
M = [[1, 2, 3], [1, 2, 3], [2, 3, 1]] ;
...

Resources