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

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

Related

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 maze problem : code gives infinite paths from start to end and doesn't backtrack

I am trying to solve a maze in Prolog using backtracking.
My problem is that when I run the program, it runs correctly for the first time, but after that it takes the end position as the starting position and keeps finding paths from there, hence goes into endless loop. It works correctly when path doesn't exist between 2 positions. I have tried lots of things but nothing seems to be working. Here's my code:
path(Dest, Dest, _, [], _) :- !.
path([Row0,Col0],[Row1,Col1],M,Path,1) :-
next_move([Row0,Col0],[Rnew,Cnew]),
is_available(Rnew, Cnew,Ret),
write(Rnew),
write(Cnew),
not(member([Rnew, Cnew], M)),
path([Rnew, Cnew], [Row1, Col1], [[Rnew,Cnew]|M], Path, Ret).
path([X0,Y0], [X1,Y1], [[X0,Y0]|M], [[X,Y]|Path], 0) :-
path([X,Y],[X1,Y1],M,Path,1).
Sample output:
?- solves([1,1],[1,7],P).
P = [[1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [1, 7]] ;
P = [[1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [2, 6], [2, 7], [2|...],
[...|...]|...] ;
P = [[1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [2, 6], [2, 7], [2|...],
[...|...]|...] ;
P = [[1, 2], [1, 3], [1, 4], [1, 5], [1, 6], [2, 6], [2, 7], [2|...],
[...|...]|...] .
When executing the program, it should display all the paths if a path exists between 2 positions. It should return false otherwise. As you can see above, my code goes into infinite loop and keep generating paths.
Please help as I am not very experienced in Prolog.
Thanks.
The first clause of the path/5 predicate and the recursive call in its second clause are wrong. It should be:
path(Dest, Dest, _, [], _) :- !.
path([Row0,Col0],[Row1,Col1],M,[[Rnew,Cnew]|Path],1) :-
next_move([Row0,Col0],[Rnew,Cnew]),
is_available(Rnew, Cnew,Ret),
write(Rnew),
write(Cnew),
\+ member([Rnew, Cnew], M),
path([Rnew, Cnew], [Row1, Col1], [[Rnew,Cnew]|M], Path, Ret).
Also, use the ISO Prolog standard \+/1 predicate instead of the not/1 legacy predicate.
Ha there's a fair amount of irony here that I even saw this post - you are on the PPL course? :)
Generally returning a value of 0 or 1 to say whether a statement is true or false is not necessary in prolog - it is implicit in whether the predicate has passed.
For example
is_available(Rnew, Cnew,Ret) would be better written as is_available(Rnew, Cnew) - if is_available resolves as false then it would already STOP and begin to backtrack to look for other solutions along its alternate lines if there was no alternative.
Furthermore this will mean that if there is no solution, a value of 'false' would be printed when you try to evaluate the maze.
On your output issues - actually that is not 'broken'; it is just suppressed output!
Try running this in your swi terminal before you run the maze solving expression:
set_prolog_flag(answer_write_options,[max_depth(0)]).
as per SWI-Prolog how to show entire answer (list)?

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).

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