Please explain the cut in the Bubblesort Prolog program? - prolog

I'm currently working trough the Bratko Prolog book and I am looking at the bubble-sort Program. I can't seem to figure out why the cut(!) is necessary. Say the cut isn't there, and Prolog would backtrack, how could it possibly find bad answers? Because if I leave the cut out of it, Prolog begins by giving me the correct answer but then also gives alternative bad answers.
As I see it, how can swap ever return a non sorted list? And how is it possible that a non sorted list ever hits the goal bubblesort(Sorted, Sorted).
Unless of course the first List is also being changed... Can't get my head around it.
Prolog BubbleSort program:
gt(X,Y) :- X > Y.
bubblesort(List, Sorted) :-
swap(List, List1), !, % A useful swap in List?
bubblesort(List1, Sorted).
bubblesort(Sorted, Sorted). % Otherwise list is already sorted
swap([X,Y|Rest], [Y,X|Rest]) :- % Swap first two elements
gt(X,Y).
swap([Z|Rest], [Z|Rest1]) :- % Swap elements in tail
swap(Rest, Rest1).
Leaving the cut of out it gives me:
?- bubblesort([5,7,3,6,8,9,2,6], Sorted).
Sorted = [2, 3, 5, 6, 6, 7, 8, 9] ;
Sorted = [2, 3, 5, 6, 7, 6, 8, 9] ;
Sorted = [2, 3, 5, 6, 7, 8, 6, 9] ;
Sorted = [2, 3, 5, 6, 7, 8, 9, 6] ;
I think that somehow I get it, but I am not sure. Could it be that at a certain moment, it backtracks over swap(List, List1) going to the second bubble-sort predicate and hitting the goal, meaning the two lists Sorted are equal?
In English, does this mean that bubble-sort needs to continue doing swaps until no more swaps are possible, but then needs to terminate? Or does it mean that every-time a successful swap has been done, there's no use backtracking over that success?

There are several possibilities to make the goal swap(List, List1) fail. Either List is a list of length 0 or 1 ; or it does not contain two immediately succeeding elements where the second is smaller than the first.
The cut is placed in such a manner that it both cuts swap/2 and the alternative of bubblesort/2.
This is a good example, where a "deep cut" (cutting deep into swap/2) still works somewhat nicely. However, such situations are very rare. Most of the time, the cut cuts too much. The largest majority of such programs is very brittle to use, even more so, if the second argument is given already. They are often not steadfast.
Ah, I almost missed it: Even in this program, we have bubblesort(nonlist,L) succeeding, or bubblesort([1|nonlist],L) which probably is not intended and leads to subtle programming errors.
There is also another reason why this program does not present the ideal logic programming style: The second rule of bubblesort/2 when read alone says: Everything is a sorted list`. To understand this, we have to read both rules at the same time and narrow it down to Everything but ....
In English, does this mean that bubble-sort needs to continue doing swaps until no more swaps are possible, but then needs to terminate? Or does it mean that every-time a successful swap has been done, there's no use backtracking over that success?
It is the first procedural meaning that applies here. And certainly, backtracking over the success to the second clause of bubblesort/2 would be an error.
A further quite unintuitive detail which is not specific to the cut, is that in addition to numbers, the program also succeeds for expressions like bubblesort([1,1+1],L) which again might lead to subtle differences.

I just want to add that if-then-else is a far more appropriate language construct than !/0 to express the intention (and I know you did not choose !/0 on your own here):
bubblesort(List0, List) :-
( swap(List0, List1) ->
bubblesort(List1, List)
; List0 = List
).
You can change the -> to *-> to see alternative solutions of swap/2 as well, i.e., if you change this to:
bubblesort(List0, List) :-
( swap(List0, List1) *->
bubblesort(List1, List)
; List0 = List
).
Then you get for example:
?- bubblesort([5,7,3,6,8,9,2,6], Ascending).
Ascending = [2, 3, 5, 6, 6, 7, 8, 9] ;
Ascending = [2, 3, 5, 6, 6, 7, 8, 9] ;
Ascending = [2, 3, 5, 6, 6, 7, 8, 9] .
As you see, all of these lists are non-decreasing, as you already expected.

Related

Prolog stucks after giving the result

So I have this knowledge base and I am trying to achieve the goals in the code given as comments.
%format of foo: foo(Tag,NumList)
foo(a, [2, 4]).
foo(b,[2, 8, 8, 6,2]).
foo(c,[4, 8, 8, 8, 7]).
foo(d,[7, 8, 8, 2]).
foo(e,[5, 8, 9, 6]).
foo(f,[2, 5]).
foo(g,[2, 6]).
foo(h, [2, 8, 2]).
foo(i, [2, 8, 8, 2]).
foo(j, [2, 3]).
However there is a problem with the goo part. When I only give Total_num to goo and get the unified results for Foo_list, it gives the results but after that it just gets stuck. Nothing works and I have to close the interpreter all the time.
I tried putting cuts to goo helpers but nothing works. Also when I change the order of predicates in goo(putting goo_ordered in front), it doesn't give the list and just gets stuck. How can I fix this problem? What causes it?
Thank you
%returns the sum of the numbers the NumList
foo_sum(Tag,SUM):- foo(Tag,List),foo_sum_helper(List,SUM).
foo_sum_helper([],0).
foo_sum_helper([H|T],Result):- foo_sum_helper(T,Prev_result), Result is H + Prev_result.
%foo diff find the last number in the list.
%It should remain the if it is less than or equal to four, otherwise substract 8 from it
foo_diff(Tag,Diff):- foo(Tag,List),foo_diff_helper(List,Diff).
foo_diff_helper([Last],Result):- Last =< 4, Result is Last,!.
foo_diff_helper([Last],Result):- Last > 4, Result is Last - 4,!.
foo_diff_helper([_,X|T],Result):- foo_diff_helper([X|T], Result).
%goo takes a list of foo's and a number that represents the total number of each foo_sum of foo's.
%Total of foo_diff must be 0
%Also the list of foo's must be in the ascending order.(foo_sum of the first foo in the list is the least one.)
goo(Foo_list,Total_num):- goo_sum(Foo_List,Total_num),goo_diff(Foo_list,0),goo_ordered(Foo_list).
goo_ordered([]).
goo_ordered([_]).
goo_ordered([X,Y|Z]):- foo_sum(X,NUMX),foo_sum(Y,NUMY),NUMX =< NUMY, goo_ordered([Y|Z]).
goo_sum([X],RESULT):- foo_sum(X,RESULT).
goo_sum([H|T],RESULT):- goo_sum(T,PREV_RESULT),foo_sum(H,NUMH), RESULT is NUMH + PREV_RESULT.
goo_diff([X],RESULT):- foo_diff(X,RESULT).
goo_diff([H|T],RESULT):- goo_diff(T,PREV_RESULT),foo_diff(H,HDIFF), RESULT is HDIFF + PREV_RESULT.
What causes it?
Assuming you mean the looping of goo_sum(X, 20):
For the query I get quite a lot of answers. Actually, too much for me. So I will instead consider
?- goo_sum(X, 20), false.
which loops. The A reason is the following very compact failure-slice
goo_sum([X],RESULT):- false, foo_sum(X,RESULT).
goo_sum([H|T],RESULT):-
goo_sum(T,PREV_RESULT), false,
foo_sum(H,NUMH), RESULT is NUMH + PREV_RESULT.
You need to fix the remaining part somehow or the loop will remain.
BTW, using names as foo and goo is not a very good idea. I still do not understand your program and so do you, I presume.
I'd rather stick to smaller programs first. Also consider to use clpfd in place of the moded arithmetic via (is)/2. Here is such a suggested improvement—for a question of your colleague presumably.
And: You got some warnings by the system about a singleton variable, you need to fix that anyway. That is s/Foo_List/Foo_list/

Prolog Skip some backtracking branches

I'm trying to generate some Kakuros, generate not solve.
I have all rules to generate it, but the firsts results are senseless, those are like squares.
Now I want to skip some branches, 15000 for example, to see the kakuro generated at that point.
I have tried with an Auxiliary Variable, but when it fails, the Kakuro Generator start again.
You can keep a dynamic counter-like predicate in the knowledge base that gets increased every time the main predicate is executed. The value of the counter is changed with assert and retract, i.e., it is not a variable within your main predicate but a globally stored value.
Within your main predicate, if you add the condition that the counter should be higher than some skip value, then you force backtracking over the actual rules for a specified number of iterations.
As an example, consider the built-in predicate permutation/2 which computes permutations of a list (note: tested using SWI-Prolog, other interpreters have different built-in predicates). Example output:
?- permutation([1,2,3,4,5],L).
L = [1, 2, 3, 4, 5] ;
L = [1, 2, 3, 5, 4] ;
L = [1, 2, 4, 3, 5] ;
L = [1, 2, 4, 5, 3] ;
L = [1, 2, 5, 3, 4] ;
L = [1, 2, 5, 4, 3] ;
If you want to skip the first 5 iterations in your query, you can use the following code:
:- dynamic iteration_nr/1.
iteration_nr(0).
get_permutations(L1,L2,Skip) :-
permutation(L1,L2),
iteration_nr(N),
N2 is N+1,
retract(iteration_nr(N)),
asserta(iteration_nr(N2)),
Skip < N2. % force backtracking here if counter < Skip
Example output:
?- get_permutations([1,2,3,4,5],L2,5).
L2 = [1, 2, 5, 4, 3] ;
L2 = [1, 3, 2, 4, 5] ;
L2 = [1, 3, 2, 5, 4]
Note that asserta is used here (i.e., assert at the start) instead of plain assert, which is deprecated. Note also that the counter will keep the value, so when you run this a second time in the same session the results will be different. To reset the counter you can use a separate initialization predicate, for example:
init_and_get_permutations(L1,L2,Skip) :-
retractall(iteration_nr(_)),
asserta(iteration_nr(0)),
get_permutations(L1,L2,Skip).
Further note: the use of assert and retract is not really considered 'clean' Prolog programming, because it is procedural and changes the knowledge base. However, for some applications it can be useful.

List manipulation with prolog

I am trying to create a query that gives back the following:
sky([1,2,3,4,5,6],X).
X = [1,3,5,2,6,4]
That is, it takes out every other element of a list, and does the same on the remaining list and puts everything together.
This is my code so far.
sky([X|Y], Skied):-
split([X|Y],Z1),
split(X,Z2),
sky(Z2,Z3),
append(Z1,Z3,Skied).
sky([],[]).
split([X,_|T], [X|R]):-
split(T,R).
split([X|[]], [X]).
split([],[]).
Can someone explaint o me why it wont work and the process behind it, like a visual guide. Thanks!
Your code is almost right, instead of split(X,Z2) you need to write split(Y,Z2). That's because X is a single element and split(X,Z2) will return [X], which if I understood correctly isn't what you want. You need to write split(Y,Z2) to take the even elements (or in your description every other element) and call sky(Y,Z3) to do the same recursively. So the new version is:
sky([X|Y], Skied):-
split([X|Y],Z1),
split(Y,Z2),
sky(Z2,Z3),
append(Z1,Z3,Skied).
sky([],[]).
split([X,_|T], [X|R]):-
split(T,R).
split([X|[]], [X]).
split([],[]).
Some examples and output:
?- sky([1,2,3,4,5,6],X).
X = [1, 3, 5, 2, 6, 4] ;
false.
?- sky([1,2,3,4,5,6,7,8,9],X).
X = [1, 3, 5, 7, 9, 2, 6, 4, 8] ;
false.

Issue with output in Prolog

I recently wanted to experiment with Prolog to understand how the process of unification works so I wrote the following code to return the nth element from a list.
getfromarray([X|_],1,X).
getfromarray(A,N,E):-
N > 1,
A = [_|Y],
N1 is N-1,
getfromarray(Y,N1,E).
However, upon entering the input to the program as
getfromarray(A,3,E), it returns :-
A = [_G5129, _G5132, E|_G5136]
I understand that since i wrote the rule A = [_|Y] , A is being unified to satisfy the conditions of the rules in the program hence A is being displayed in this format. However, I don't understand why E is not being unified with the value in the array. I did read through the basics of unification in Prolog and I understand that while the answer is not wrong, it does not do what it is intended to do. Can someone suggest a topic in unification I might have missed upon which might help me solve this minor issue?
EDIT:
When I passed a list as a parameter to the program, it gave the associated value of E in the list.However, when I unified a variable A with a list and passed A as a parameter to the program, It is displaying the same output as i mentioned above.
5 ?- getfromarray([1,2,5,4,5],3,E).
E = 5 .
6 ?- A = [1,2,3,4,5].
A = [1, 2, 3, 4, 5].
7 ?- getfromarray(A,3,E).
A = [_G576, _G579, E|_G583] .
8 ?-
Prolog doesn't store your list A, therefore A is uninstantiate.
A = [1, 2, 3, 4, 5].
getfromarray(A,3,E).
This is like just calling :
getfromarray(A,3,E).
Try this in stead :
A = [1, 2, 3, 4, 5], getfromarray(A,3,E).

Prolog decomposition returning a period

I have a predicate that decomposes an expression and I am having results that I dont understand when I trace through it.
My predicate is as below
calc(R,Expr) :- Expr =..[Op,H,T].
So when I have an expression like [1,1], the Op is actually a period. Any idea why?
It's because the form [Head|Tail] is just syntactic sugar for '.'(Head, Tail) (everything is a term and lists are no exception). Normally, for the list made of 1, 2, 3 and 4, you'd have to write
'.'(1, '.'(2, '.'(3, '.'(4, [])))).
As you can see, that's not very practical and instead we use the shortcut:
[1|[2|[3|[4|[]]]]]
And this shortcut has a shortcut:
[1, 2, 3, 4]
And you can mix those as you wish:
[1, 2|[3, 4]]
That is handy when you want to specify some elements and then let the tail free:
[1, 2|A]
BTW, you can see that for yourself by using write_canonical/1:
?- write_canonical([1, 2, 3, 4]).
'.'(1,'.'(2,'.'(3,'.'(4,[]))))
true.
Hope it helped

Resources