Find min of list using fail, backtracking Prolog - prolog

I want to calculate the minimum of list, using fail which causes to backtrack. How do i change min(Min, X, Min), to make it work.
%min(X, A, B) X is the min of A, B
min(X, X, Y) :- X =< Y.
min(Y, X, Y) :- Y < X.
member(X, [X|_]).
member(X, [_|Ys]) :-
member(X,Ys).
program :-
Min is 1000,
(member(X, [1, 2, 3, 4]),
writeln(X),
min(Min, X, Min), %This is wrong !
fail;
writeln(Min),
true).
My previous working code for calculating min
solve([Head|Rest], Ans) :-
solve(Rest, Till),
min(Ans, Head, Till).
But i do not want to do this, as for calling solve, i am doing something like this
program :-
findall(X, solve(List, X), Z).
which is causing to find all solutions of X and storing in memory. This method is not working for large inputs, getting killed.
Hence, i want to calculate the min of each solve call on fly and not store as did using findall.

If you're worried about memory usage, you shouldn't be using a guess-and-check metaphor (which using failure implies you're using). There's an O(n) algorithm that doesn't require failure at all.
minlist(Min, [X|Xs]) :- minlist(X, Xs, Min).
minlist(Min, [], Min).
minlist(MinSoFar, [X|Xs], Min) :-
min(NextMin, MinSoFar, X),
minlist(NextMin, Xs, Min).

Related

Find minimum of various predicates

I want to find the minimum value of all permutations called from main predicate. For simplicity, I have removed my entire code, assume that I just want to find the minimum of head elements of all permutations.
appendlist([], X, X).
appendlist([T|H], X, [T|L]) :- appendlist(H, X, L).
permutation([], []).
permutation([X], [X]) :-!.
permutation([T|H], X) :- permutation(H, H1), appendlist(L1, L2, H1), appendlist(L1, [T], X1), appendlist(X1, L2, X).
%min(X, A, B) X is the minimum of A, B
min(X, X, Y) :- X =< Y.
min(Y, X, Y) :- Y < X.
solve([Head|Rest], Head):-
writeln([Head|Rest]).
main :-
Sort = [1, 2, 3],
PrvAns is 1000,
permutation(Sort, X),
solve(X, Here),
min(Ans, Here, PrvAns),
writeln(Ans),
PrvAns = Ans,
!, fail;
true,
writeln(PrvAns).
I want to calculate the minimum on fly for each permutation. Now, permute is working fine, and you can see that solve prints all permutations and even returns the first value Head properly, but PrvAns = Ans is wrong.
Expected output PrvAns : 1
I'm sorry if I didn't understand properly (and tell me, so I can help you), but, you mean something like this?
findMinHead(X,Z):-
findall( Y, ( permutation(X,[Y|_]) ), Z1 ),
min_list(Z1,Z).
in this predicate we find all the Y values where Y is the head of a permutation of X, put all that values in a bag, and then find the min.

Swapping sublists in prolog

I'm searching for a compact predicate to swap sublists of fixed length within a larger list. For example, if sublists have size 3 then
[a,t,t,g,c,c]
becomes
[g,c,c,a,t,t]
I ended up with the following program:
dna_sub(A,B,X,Xe) :-
append(A1,_,A),
length(A1,Xe),
append(B1,B,A1),
length(B1,X).
dna_swap(A,B,X,Xe,Y,Ye) :-
length(A, Size),
dna_sub(A,Part1, 0, X),
dna_sub(A,Part2, X, Xe),
dna_sub(A,Part3, Xe, Y),
dna_sub(A,Part4, Y, Ye),
dna_sub(A,Part5, Ye, Size),
append(Part1, Part4, Tmp),
append(Tmp, Part3, Tmp2),
append(Tmp2, Part2, Tmp3),
append(Tmp3, Part5, B).
dna_swap(A,B) :-
length(A, Size),
Limit is Size - 3,
between(0,Limit, X),
Xe is X + 3,
Xs is Xe,
between(Xs, Size, Y),
Ye is Y + 3,
dna_swap(A,B,X,Xe,Y,Ye).
It seems to be working. For example, the following query:
dna_swap([t,a,g,t,g,c], L).
Obtains the correct answer in L.
Anyway, as you can see, it's very verbose. Is there a better way?
Edit
This seems to work a lot better:
dna_swap(A,B) :-
append(Left1, [X1,X2,X3|Right1], A),
append(Left2, [Y1,Y2,Y3|Right2], Right1),
append(Left1, [Y1,Y2,Y3|Left2], Tmp),
append(Tmp, [X1,X2,X3|Right2], B).
sublists(List,Count,A,B) :-
length(A,Count),
append(A,B,List).
swap(List,Count,SwappedList) :-
sublists(List,Count,A,B),
append(B,A,SwappedList).
Hope this is what you are looking for:
4 ?- swap([a,b,c,d],2,S).
S = [c, d, a, b].

Sorting large lists in Prolog: Not enough memory

I'm trying to sort a 10k element list in prolog with bubblesort and I get the out of local stack error. Mergesort seems to be the best option since I don't get any errors for the same input. However I'd really like to get some running times for bubblesort with large input data but I can't. Any ideas?
Here's the code:
%% NOTE: SWI-PROLOG USED
%% generate_list(Limit, N, L): - insert upper limit and length of list N
%% to get a random list with N numbers from 0 to limit
generate_list(_, 0, []).
generate_list(Limit, N, [Y|L]):-
N =\= 0,
random(0, Limit, Y),
N1 is N-1,
generate_list(Limit, N1, L).
%% bubble(L, Ls, max):- insert list L and get max member of list by
%% swapping members from the start of L.
bubble([Z], [], Z).
bubble([X,Y|L], [X|Ls], Z):- X =< Y, bubble([Y|L], Ls, Z).
bubble([X,Y|L], [Y|Ls], Z):- X > Y, bubble([X|L], Ls, Z).
%% bubble_sort(List, Accumulator, Sorted_List)
bubblesort([X], Ls, [X|Ls]).
bubblesort(L, Accumulate, Result):- bubble(L, Ls, Max),
bubblesort(Ls, [Max|Accumulate], Result).
bubble_sort(L, Sorted):- bubblesort(L, [], Sorted).
As you can I see I'm using tail recursion. I've also tried enlarging the stacks by using:
set_prolog_stack(global, limit(100 000 000 000)).
set_prolog_stack(trail, limit(20 000 000 000)).
set_prolog_stack(local, limit(2 000 000 000)).
but it just runs for a bit longer. Eventually I get out of local stack again.
Should I use another language like C and malloc the list or not use recursion?
Since there are two answers, and no one pointed out explicitly enough the reason why you get into "out of local stack" trouble (Mat says in the comment to your question that your predicates are not deterministic, but does not explain exactly why).
Two of the predicates you have defined, namely, bubblesort/3 and bubble/3, have mutually exclusive clauses. But Prolog (at least SWI-Prolog) does not recognize that these are mutually exclusive. So, choice points are created, you don't get tail recursion optimization, and probably no garbage collection (you need to measure using your implementation of choice if you want to know how much goes where and when).
You have two different problems.
Problem 1: lists with exactly one element
This problem pops up in both predicates. In the most simple predicate possible:
foo([_]).
foo([_|T]) :-
foo(T).
And then:
?- foo([a]).
true ;
false.
This is not surprising; consider:
?- [a] = [a|[]].
true.
You can solve this by using a technique called lagging:
bar([H|T]) :-
bar_1(T, H).
bar_1([], _).
bar_1([H|T], _) :-
bar_1(T, H).
Then:
?- bar([a]).
true.
In the definition of bar_1/2, the first argument to the first clause is the empty list; the first argument to the second clause is a non-empty list (a list with at least one element, and a tail). Prolog does not create choice points when all clauses are obviously exclusive. What obvious means will depend on the implementation, but usually, when the first arguments to all clauses are all terms with different functors, then no choice points are created.
Try the following (you might get different results, but the message is the same):
?- functor([], Name, Arity).
Name = [],
Arity = 0.
?- functor([_|_], Name, Arity).
Name = '[|]',
Arity = 2.
See this question and the answer by Mat to see how you can use this to make your program deterministic.
Mat, in his answer, uses this approach, if I see correctly.
Problem 2: constraints (conditions) in the body of the clauses
This is the problem with the second and third clause of bubble/3. In the textbook "correct" example of choosing the minimum of two elements:
min(A, B, B) :- B #< A.
min(A, B, A) :- A #=< B.
Then:
?- min(1,2,1).
true.
but:
?- min(2,1,1).
true ;
false.
You can solve this in two ways: either by doing what Mat is doing, which is, using compare/3, which succeeds deterministically; or, by doing what CapelliC is doing, which is, using an if-then-else.
Mat:
min_m(A, B, Min) :-
compare(Order, A, B),
min_order(Order, A, B, Min).
min_order(<, A, _, A).
min_order(=, A, _, A).
min_order(>, _, B, B).
And Carlo:
min_c(A, B, Min) :-
( B #< A
-> Min = B
; Min = A
).
I know there will always be at least as many opinions as heads, but both are fine, depending on what you are doing.
PS
You could use the built in length/2 to generate a list, and re-write your generate_list/3 like this:
generate_list(Limit, Len, List) :-
length(List, Len),
random_pos_ints(List, Limit).
random_pos_ints([], _).
random_pos_ints([H|T], Limit) :-
random(0, Limit, H),
random_pos_ints(T, Limit).
The helper random_pos_ints/2 is a trivial predicate that can be expressed in terms of maplist:
generate_list(Limit, Len, List) :-
length(List, Len),
maplist(random(0, Limit), List).
Here is a version of bubble/3 that is deterministic if the first argument is instantiated, so that tail call optimisation (and, more specifically, tail recursion optimisation) applies:
bubble([L|Ls0], Ls, Max) :- phrase(bubble_(Ls0, L, Max), Ls).
bubble_([], Max, Max) --> [].
bubble_([L0|Ls0], Max0, Max) -->
elements_max(L0, Max0, Max1),
bubble_(Ls0, Max1, Max).
elements_max(X, Y, Max) -->
{ compare(C, X, Y) },
c_max(C, X, Y, Max).
c_max(<, X, Y, Y) --> [X].
c_max(=, X, Y, Y) --> [X].
c_max(>, X, Y, X) --> [Y].
Example usage, with the rest of the program unchanged (running times depend on the random list, which is bad if you want to reproduce these results - hint: introduce the random seed as argument to fix this):
?- generate_list(100, 10_000, Ls), time(bubble_sort(Ls, Ls1)).
% 200,099,991 inferences, 29.769 CPU in 34.471 seconds
...
For testing different versions, please use a version of the query that you can use to reliably reproduce the same initial list, such as:
?- numlist(1, 10_000, Ls0), time(bubble_sort(Ls0, Ls)).
The nice thing is: If you just use zcompare/3 from library(clpfd) instead of compare/3, you obtain a version that can be used in all directions:
?- bubble(Ls0, Ls, Max).
Ls0 = [Max],
Ls = [] ;
Ls0 = [Max, _G677],
Ls = [_G677],
_G677#=<Max+ -1,
zcompare(<, _G677, Max) ;
Ls0 = [Max, _G949, _G952],
Ls = [_G949, _G952],
_G952#=<Max+ -1,
_G949#=<Max+ -1,
zcompare(<, _G952, Max),
zcompare(<, _G949, Max) ;
etc.
This describes the relation in general terms between integers.
Disclaimer: following the hint by #mat could be more rewarding...
I've played a bit with your code, in my experiment the local stack overflow was thrown with a list length near 2500. Then I've placed some cut:
%% bubble(L, Ls, max):- insert list L and get max member of list by
%% swapping members from the start of L.
bubble([Z], [], Z).
bubble([X,Y|L], [R|Ls], Z):-
( X =< Y -> (R,T)=(X,Y) ; (R,T)=(Y,X) ),
bubble([T|L], Ls, Z).
%% bubble_sort(List, Accumulator, Sorted_List)
bubblesort([X], Ls, [X|Ls]) :- !.
bubblesort(L, Accumulate, Result):-
bubble(L, Ls, Max),
!, bubblesort(Ls, [Max|Accumulate], Result).
and I get
?- time(generate_list(100,10000,L)),time(bubble_sort(L,S)).
% 60,000 inferences, 0.037 CPU in 0.037 seconds (99% CPU, 1618231 Lips)
% 174,710,407 inferences, 85.707 CPU in 86.016 seconds (100% CPU, 2038460 Lips)
L = [98, 19, 80, 24, 16, 59, 70, 39, 22|...],
S = [0, 0, 0, 0, 0, 0, 0, 0, 0|...]
.
so, it's working, but very slowly, showing the quadratic complexity...

Regarding two implementations of min_of_list in prolog

Can someone explain clearly why this implementation (from SO 3965054) of min_of_list works in prolog:
% via: http://stackoverflow.com/questions/3965054/prolog-find-minimum-in-a-list
min_of_list_1( [H], H).
min_of_list_1([H,K|T],M) :- H =< K, min_of_list_1([H|T],M).
min_of_list_1([H,K|T],M) :- H > K, min_of_list_1([K|T],M).
while this implementation generates an incorrect output:
min_of_list_2( [H], H).
min_of_list_2( [H| T], X) :- compare(<, X, H), min_of_list_2(T, X).
min_of_list_2( [H| T], H) :- compare(>, X, H), min_of_list_2(T, X).
min_of_list_2( [H| T], H) :- compare(=, X, H), min_of_list_2(T, H).
Epilogue. This works.
min_of_list_3( [H], H).
min_of_list_3( [H| T], X) :- min_of_list_3(T, X), compare(<, X, H).
min_of_list_3( [H| T], H) :- min_of_list_3(T, X), compare(>, X, H).
min_of_list_3( [H| T], H) :- min_of_list_3(T, X), compare(=, X, H).
?
The behavior I get is that min_of_list_2 returns the last element in the list.
Thanks.
The first clause of min_of_list_2/2 is OK, it says the minimum of a list with a single element is that element. The second clause is not quite so OK: The intention seems to state that if X is the minimum of the list T, and X is smaller than H, then X is also the minimum of the list [H|T], and this would work as intended if compare/3 behaved like a true relation, but unfortunately it doesn't:
?- compare(<, a, b).
true.
Yet the more general query fails as if there were no solution (although we know there is at least one!):
?- compare(<, a, X).
false.
Since one typical usage of min_of_list_2/2 (including for example its use in the third clause) leaves the second argument uninstantiated, you will run into this problem. Your code will work as expected if you place all calls of compare/3 after the respective recursive calls of min_of_list_2/2. As a consequence, your predicate is then no longer tail recursive, in contrast to the other program you posted. The compare/3 call in the last clause should be removed (what is the X in that case?), as it will always fail!
the first one compares the first two elements of the list and then puts the min again in the list till there is only one element.
the second one... takes the head of the list and compares with X. X is non-instantiated in the first call so compare(<,X,_any_number) will be true. X wont be instantiated so the same will repeat till there is only one element in the list which will be returned* (the last one).
'* where returned = unified with the second argument.

Prolog Programming

I have made two programs in Prolog for the nqueens puzzle using hill climbing and beam search algorithms.
Unfortunately I do not have the experience to check whether the programs are correct and I am in dead end.
I would appreciate if someone could help me out on that.
Unfortunately the program in hill climbing is incorrect. :(
The program in beam search is:
queens(N, Qs) :-
range(1, N, Ns),
queens(Ns, [], Qs).
range(N, N, [N]) :- !.
range(M, N, [M|Ns]) :-
M < N,
M1 is M+1,
range(M1, N, Ns).
queens([], Qs, Qs).
queens(UnplacedQs, SafeQs, Qs) :-
select(UnplacedQs, UnplacedQs1,Q),
not_attack(SafeQs, Q),
queens(UnplacedQs1, [Q|SafeQs], Qs).
not_attack(Xs, X) :-
not_attack(Xs, X, 1).
not_attack([], _, _) :- !.
not_attack([Y|Ys], X, N) :-
X =\= Y+N,
X =\= Y-N,
N1 is N+1,
not_attack(Ys, X, N1).
select([X|Xs], Xs, X).
select([Y|Ys], [Y|Zs], X) :- select(Ys, Zs, X).
I would like to mention this problem is a typical constraint satisfaction problem and can be efficiency solved using the CSP module of SWI-Prolog. Here is the full algorithm:
:- use_module(library(clpfd)).
queens(N, L) :-
N #> 0,
length(L, N),
L ins 1..N,
all_different(L),
applyConstraintOnDescDiag(L),
applyConstraintOnAscDiag(L),
label(L).
applyConstraintOnDescDiag([]) :- !.
applyConstraintOnDescDiag([H|T]) :-
insertConstraintOnDescDiag(H, T, 1),
applyConstraintOnDescDiag(T).
insertConstraintOnDescDiag(_, [], _) :- !.
insertConstraintOnDescDiag(X, [H|T], N) :-
H #\= X + N,
M is N + 1,
insertConstraintOnDescDiag(X, T, M).
applyConstraintOnAscDiag([]) :- !.
applyConstraintOnAscDiag([H|T]) :-
insertConstraintOnAscDiag(H, T, 1),
applyConstraintOnAscDiag(T).
insertConstraintOnAscDiag(_, [], _) :- !.
insertConstraintOnAscDiag(X, [H|T], N) :-
H #\= X - N,
M is N + 1,
insertConstraintOnAscDiag(X, T, M).
N is the number of queens or the size of the board (), and , where , being the position of the queen on the line .
Let's details each part of the algorithm above to understand what happens.
:- use_module(library(clpfd)).
It indicates to SWI-Prolog to load the module containing the predicates for constraint satisfaction problems.
queens(N, L) :-
N #> 0,
length(L, N),
L ins 1..N,
all_different(L),
applyConstraintOnDescDiag(L),
applyConstraintOnAscDiag(L),
label(L).
The queens predicate is the entry point of the algorithm and checks if the terms are properly formatted (number range, length of the list). It checks if the queens are on different lines as well.
applyConstraintOnDescDiag([]) :- !.
applyConstraintOnDescDiag([H|T]) :-
insertConstraintOnDescDiag(H, T, 1),
applyConstraintOnDescDiag(T).
insertConstraintOnDescDiag(_, [], _) :- !.
insertConstraintOnDescDiag(X, [H|T], N) :-
H #\= X + N,
M is N + 1,
insertConstraintOnDescDiag(X, T, M).
It checks if there is a queen on the descendant diagonal of the current queen that is iterated.
applyConstraintOnAscDiag([]) :- !.
applyConstraintOnAscDiag([H|T]) :-
insertConstraintOnAscDiag(H, T, 1),
applyConstraintOnAscDiag(T).
insertConstraintOnAscDiag(_, [], _) :- !.
insertConstraintOnAscDiag(X, [H|T], N) :-
H #\= X - N,
M is N + 1,
insertConstraintOnAscDiag(X, T, M).
Same as previous, but it checks if there is a queen on the ascendant diagonal.
Finally, the results can be found by calling the predicate queens/2, such as:
?- findall(X, queens(4, X), L).
L = [[2, 4, 1, 3], [3, 1, 4, 2]]
If I read your code correctly, the algorithm you're trying to implement is a simple depth-first search rather than beam search. That's ok, because it should be (I don't see how beam search will be effective for this problem and it can be hard to program).
I'm not going to debug this code for you, but I will give you a suggestion: build the chess board bottom-up with
queens(0, []).
queens(N, [Q|Qs]) :-
M is N-1,
queens(M, Qs),
between(1, N, Q),
safe(Q, Qs).
where safe(Q,Qs) is true iff none of Qs attack Q. safe/2 is then the conjunction of a simple memberchk/2 check (see SWI-Prolog manual) and your not_attack/2 predicate, which on first sight seems to be correct.
A quick check on Google has found a few candidates for you to compare with your code and find what to change.
My favoured solution for sheer clarity would be the second of the ones linked to above:
% This program finds a solution to the 8 queens problem. That is, the problem of placing 8
% queens on an 8x8 chessboard so that no two queens attack each other. The prototype
% board is passed in as a list with the rows instantiated from 1 to 8, and a corresponding
% variable for each column. The Prolog program instantiates those column variables as it
% finds the solution.
% Programmed by Ron Danielson, from an idea by Ivan Bratko.
% 2/17/00
queens([]). % when place queen in empty list, solution found
queens([ Row/Col | Rest]) :- % otherwise, for each row
queens(Rest), % place a queen in each higher numbered row
member(Col, [1,2,3,4,5,6,7,8]), % pick one of the possible column positions
safe( Row/Col, Rest). % and see if that is a safe position
% if not, fail back and try another column, until
% the columns are all tried, when fail back to
% previous row
safe(Anything, []). % the empty board is always safe
safe(Row/Col, [Row1/Col1 | Rest]) :- % see if attack the queen in next row down
Col =\= Col1, % same column?
Col1 - Col =\= Row1 - Row, % check diagonal
Col1 - Col =\= Row - Row1,
safe(Row/Col, Rest). % no attack on next row, try the rest of board
member(X, [X | Tail]). % member will pick successive column values
member(X, [Head | Tail]) :-
member(X, Tail).
board([1/C1, 2/C2, 3/C3, 4/C4, 5/C5, 6/C6, 7/C7, 8/C8]). % prototype board
The final link, however, solves it in three different ways so you can compare against three known solutions.

Resources