How to create a list without using findall? Prolog - 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.

Related

Prolog: How to make a bagof fail in the middle of execution

My problem is that I have a functor with the next structure:
something(Perms, New_perms) :-
bagof(New_perm, aux_something(Perms, New_perm), <New_perms>).
aux_something(Perms, New_perm) :-
member(Perm, Perms),
take_impossible(Perm, New_perms).
take_impossible(Perm_poss, New_perm) :-
Perm_poss = [Var, Perm],
bagof(P, member(P, Perm), subsumes_term(Var, P)), New_perms),
New_perm = [Var, New_perms].
This takes a list of elements of the form:
[[A, 2, C], [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]]
It returns the list of possible permutations:
[[A, 2, C], [[1, 2, 3], [3, 2, 1]]]
But with the list containing an impossible element:
[[A, 4, C], [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]]
The functor should return false.
I need that, when it takes an element of the list which has no possible permutations, the list returns false. A forall instead of the bagof doesn't work because it doesn't change any variable bindings, and a forall before the bagof is too expensive, as I am doing the same operation to all elements of the list twice (it exceeds the limit time in the test). How can I break the execution of a bagof if the condition fails, or is there any other predicate that can do what I am looking for?
(Functor and aux_functor are not the real names of the variables, but this is college work, and so I am trying not to give too much info).
Stupid, question when I found the answer...
A bagof that fails when its objective fails is just a maplist.
Thanks for the help, anyway.
In this case, the correct answer would be:
something(Perms, New_perms) :-
maplist(take_impossible, Perms, New_perms).
take_impossible(Perm_poss, New_perm) :-
Perm_poss = [Var, Perm],
bagof(P, member(P, Perm), subsumes_term(Var, P)), New_perms),
New_perm = [Var, New_perms].

How to permute in Prolog the elements of a list composed of sub-list and atoms

Let us consider lists such as L=[[7,3,4],9,[4,5],[1,3,5],4] where components could be lists or atoms. How to produce this type of permutation results:
R = [[7, 3, 4], 9, [4, 5], [1, 3, 5], 4]
R = [[7, 4, 3], 9, [5, 4], [1, 3, 5], 4]
R = [[7, 4, 3], 9, [4, 5], [1, 5, 3], 4]
....
In fact, we would like to have all the possible permutations of the sub-lists of L while the atom should remain unchanged.
I wrote a classical predicate permutation(OriginalList,PermutedList), and an allperm predicate that apply the maplist function to this permutation predicate:
permutation([],[]).
permutation(L,[T|Q]) :-
select(T,L,L1),
permutation(L1,Q).
/*L is the list to permute, R the result*/
allperm(L,R) :-
maplist(permutation,L,R).
It functions only in the special case where L is composed of lists and doesn't function when L is heterogeneous (atoms and lists).
Could you provide hints or elements of solution to do the right permutation?
The following modification should do:
permutation(X,X).
permutation(L,[T|Q]) :-
dif(L,[T|Q]),
select(T,L,L1),
permutation(L1,Q).
allperm(L,R) :-
maplist(permutation,L,R).
We extend the “identity” permutation to any Prolog term (first clause of permutation) and disallow it in the second clause (which can only be applied to lists anyway).

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]] ;
...

Prolog merge sort a list that is inside a list

For an example I need to sort:
?- mergesort([8,1,[4,6,3],2],Sorted).
The outcome should be:
Sorted = [1, 2, 8, [3, 4, 6]]
Unfortunately I'm not sure what to do. I've tried to find an answer myself, but didn't find a solution. Currently the outcome is:
Sorted = [1, 2, 8, [4, 6, 3]]
My code:
mergesort([],[]).
mergesort([A],[A]).
mergesort([A,B|R],S) :-
split([A,B|R],L1,L2),
mergesort(L1,S1),
mergesort(L2,S2),
merge(S1,S2,S).
split([],[],[]).
split([A],[A],[]).
split([A,B|R],[A|Ra],[B|Rb]) :- split(R,Ra,Rb).
merge(A,[],A).
merge([],B,B).
merge([A|Ra],[B|Rb],[A|M]) :- A #=< B, merge(Ra,[B|Rb],M).
merge([A|Ra],[B|Rb],[B|M]) :- A #> B, merge([A|Ra],Rb,M).
Big thanks in advance!
I would write a simple preprocessing step:
sortl([H|T],[Hs|Ts]) :-
( is_list(H)
-> mergesort(H,Gs),
sortl(Gs,Hs)
; Hs = H
),
sortl(T,Ts).
sortl([],[]).
then you could use it this way
?- sortl([8,1,[4,6,[3,4],[1,8],3],2,[1,3,2]],T),mergesort(T,Sorted).
T = [8, 1, [3, 4, 6, [1, 8], [3|...]], 2, [1, 2, 3]],
Sorted = [1, 2, 8, [1, 2, 3], [3, 4, 6, [...|...]|...]]

Combinatios in List of LIsts Prolog

I need to find the combinations in a list of lists.
For example give the following list,
List = [[1, 2], [1, 2, 3]]
These should be the output,
Comb = [[1,1],[1,2],[1,3],[2,1],[2,2],[2,3]]
Another example:
List = [[1,2],[1,2],[1,2,3]]
Comb = [[1,1,1],[1,1,2],[1,1,3],[1,2,1],[1,2,2],[1,2,3]....etc]
I know how to do it for a list with two sublists but it needs to work for any number of sublists.
I'm new to prolog, please help.
try([],[]).
try([L|Ls],[M|Ms]):-
member(M,L),
try(Ls,Ms).
all(L,All) :- findall(M, try(L,M), All).
try returns one list composed of elements of the sublists of the first argument. all finds all such lists.
Here is your answer, cut and dry, as a fellow new prolog programmer myself.
%elementInList(input list, output answer)
answer(ListOfList, AnswerInList) :-
findall(Ans, combList(ListOfList, Ans), AnswerInList).
%combList(ListOfList, Comb) :-
combList([], []).
combList([Head|Tail], Comb) :-
combList(Tail, [Element|Tempcomb]),
elementInList(Head, Element).
%elementInList(List, Element)
elementInList([Head|_], Head).
elementInList([Head|Tail], Element) :-
elementInList(Tail, Element).
Using the definition answer(InputList, OutputResult), where e.g.
answer([[1,2],[7,8]],Comb).
Comb = [[1, 7], [2, 7], [1, 8], [2, 8]].
and e.g.
answer([[1,2],[2,8],[3,6,9]],Comb).
Comb = [[1, 2, 3], [2, 2, 3], [1, 8, 3], [2, 8, 3], [1, 2, 6], [2, 2, 6], [1, 8|...], [2|...], [...|...]|...].
and so on [X,Y,Z,..] for any number of sublists. You're welcome.

Resources