Prolog calls wrong rule. Does not backtrack correctly - debugging

Whats up?
I'm having some really weird problems with Prolog.
A recursive rule to replace an element in a list at a given index isn't always working.
My rule looks like this:
% Base rule - Stops when index is 1 and replaces the head with the element.
replaceAtIndex(1, _element, [_|_tail], [_element|_tail]).
% Recursive rule - Enter recursion for tail as long as index is larger than 1.
replaceAtIndex(_index, _element, [_head|_tail], [_head|_new_tail]):-
_index > 1,
_new_index is _index - 1,
replaceAtIndex(_new_index, _element, _tail, _new_tail).
When I use the debugger from within my program I see its always calling the second rule no matter what the index is, but when I execute the exact same command outside my program it works perfectly well. It reaches index 1 but calls the second rule, and does NOT backtrack and attempt the first rule and fails all the way back up...
The rule calling the replaceAtIndex looks like this:
level_replace_block_value(_x, _y, _value):-
current_level(_level_number, _width, _height, _blocks, _drawX, _drawY),
coordinates_to_index(_x, _y, _index),
_index_in_list is _index + 1, % the replaceAtIndex is not 0 terminated
replaceAtIndex(_index_in_list, _value, _blocks, _new_blocks),
retractall(current_level(_,_,_,_,_,_)),
assert(current_level(_level_number, _width, _height, _new_blocks, _drawX, _drawY),
graphics_update_block_value(_x, _y).
When I'm debugging its calling with index being 111.
When I'm replacing the _index_in_list with a constant 111 it works.
Anyone might have a clue why that happens?

Preserve logical-purity by using the builtin predicates same_length/2, length/2 and append/3!
replace_at(I,X,Xs0,Xs2) :-
same_length(Xs0,Xs2),
append(Prefix,[_|Xs1],Xs0),
length([_|Prefix],I),
append(Prefix,[X|Xs1],Xs2).
First, let's run the sample query that #magus used in a previous answer to this question:
?- replace_at(3,0,[1,2,3,4,5,6],Xs).
Xs = [1,2,0,4,5,6] ;
false.
Does it work when the list items are instantiated later?
?- replace_at(3,0,[A,B,C,D,E,F],Xs), A=1,B=2,C=3,D=4,E=5,F=6.
A = 1, B = 2, C = 3, D = 4, E = 5, F = 6, Xs = [1,2,0,4,5,6] ;
false.
Yes! What if the index isn't a concrete integer, but an unbound logical variable? Does that work?
?- replace_at(I,x,[_,_,_,_,_],Ys).
I = 1, Ys = [ x,_B,_C,_D,_E] ;
I = 2, Ys = [_A, x,_C,_D,_E] ;
I = 3, Ys = [_A,_B, x,_D,_E] ;
I = 4, Ys = [_A,_B,_C, x,_E] ;
I = 5, Ys = [_A,_B,_C,_D, x] ;
false.
It does! With monotone code, we get logically sound answers even with very general queries.

I suspect you misunderstand the direction in which backtracking will take place.
The first "base" rule will be tried first for any call to replaceAtIndex/4. If it fails, due to non-unifiability of the call with the "head" of the first rule, then the Prolog engine backtracks to the second rule. [Unification failure might result either from the first argument (index) differing from 1 or from the third argument not being a nonempty list.]
Backtracking never goes in the other direction. If the second rule is tried and fails, the call fails.
Of course things are complicated by the recursive definition. The success of applying the second rule entails a new call to replaceAtIndex/4, which as far as the Prolog engine is concerned must begin attempting to satisfy that goal by starting back at the first rule.
I'd suggest adding a cut to the first rule, since by construction the second rule will never succeed if the first rule does. But this is just an efficiency issue... why leave a choicepoint open that will never produce any further solutions?
replaceAtIndex(1, _element, [_|_tail], [_element|_tail]) :- !.
Added: I confirmed that your code works in Amzi! Prolog with a call like this:
?- replaceAtIndex(3, 0, [1,2,3,4,5,6], L).
L = [1, 2, 0, 4, 5, 6] ;
no
?-
But of course you also see success when the code is called in standalone/interpreted mode.
So I have to suspect the "index" argument being passed in is not an integer but rather a floating point number. Integer 1 will not unify with floating point 1.0, even if they are mathematically equal.
You can use the predicate is_integer/1 to test for this in Amzi! Prolog. The function integer(X) can be used to convert real 1.0 to an integer 1 by truncating the (nonexistent) fractional part.

Try _index_in_list set to 1. Wouldn't the first rule get called then?
Sure the reason why the second rule is getting called if your _index_in_list is 111 is because 111 is greater than 1 ? The first rule only deals with 1 - as the first parameter says.
When I'm replacing the _index_in_list with a constant 111 it
works.
What? You mean the first rule gets called? How can that be, the first param is 1.

replaceAtIndex(I, Value, List, Result) :-
RI is I-1,
findall(Before, (nth0(B, List, Before), B < RI), Before),
findall(After, (nth0(A, List, After), A > RI), After),
append([Before, [Value], After], Result).
?- replaceAtIndex(3,0,[1,2,3,4,5,6], L).
L = [1, 2, 0, 4, 5, 6].

Related

Predicate order change causes infinite loop

So I've got a predicate that works for uninstantiated variables nat_cset(N,Cs) that relates a natural number with the counting set Sn = {1,2,...,N}.
nat_cset_(0,Acc,Acc).
nat_cset_(N,Acc,Cs) :- N #> 0, N_1 #= N - 1, nat_cset_(N_1, [N|Acc], Cs).
nat_cset(N,Cs) :- nat_cset_(N,[],Cs).
One thing I've noticed is that is the following query nat_cset(N,Cs), N = 6. enters an infinite loop while N = 6, nat_cset(N,Cs). does not:
?- nat_cset(N,Cs), N = 6, false.
...
?- N = 6, nat_cset(N,Cs), false.
false
This happens because in the second query, prolog it should only look for solutions for N = 6 while in the first query, prolog will search for infinite solutions such that N = 6.
My question is, is this 'adequate' behaviour for nat_cset/2 or is this a unwanted behaviour? I've read somewhere that the order of predicates changing the solutions makes it not monotonic and removes its purity, but at the same time I can't think of a way to make nat_cset/2 any different.
Sorry for the noob question, a lot of the concepts are new to me and I'm still trying to process it all.
The query
?- nat_cset(N,Cs), N = 6, false.
has exactly the same termination property as
?- nat_cset(N,Cs), false, N = 6.
So the goal N = 6 has in this case no influence on termination whatsoever,1. Only if you add it in front can it influence termination.
As already said, rather start with programs using successor-arithmetics and not clpfd/clpz. They are much simpler and still expose the relevant properties needed to understand failure slicing.
1 This assumes that N = 6 is always terminating, as it does with clpz in Scryer and clpfd in SWI. With general coroutining this is not necessarily the case. Think of freeze(N, inf), N = 6.

SWI Prolog if statements, how do they work? Generating a simple grid

I realize I've edited out the if statements out of the original code which doesn't help readability and question clarity. Just skip to the answers for the explanation on how they work with a small example program.
To learn about more complex programs using if statements in Prolog, I'm creating a simple platformer that generates some objects and places them in a grid. First I'm trying to generate a simple 'world' with the idea of trying out generating things in prolog. The plan is to create a grid of 50 lists with 10000 items, which really shouldn't be that complicated but I can't get the if statements to work as I get the impression that I'm fundamentally misunderstanding how they work vs how I think they work. What happens is the condition isn't met, the if statement isn't called but the whole predicate is recalled with empty variables and evaluations are not instantiated.
Create a simple accumulator which has an X and Y axis, and limits to
how far they go before failing the predicate.
If the number of Y rows has been reached, terminate
Create a new [id, point(X,Y), Image] to be later filled with something
If X = end of the row, X is 0, else create the next point
Code:
generate(WorldList) :- generate_world(WorldList,0,_,10000,0,_,50).
generate_world([H|T],X,_,XEnd,Y,_,YEnd) :-
%Y has been filled with 50 rows, end recursion
not(Y > YEnd),
%iterate X by 1, store in XNew
XNew is X + 1,
%create a new [id,point(X,Y), Image]
H = [XNew,point(_,_)],
%if X has reached 10k, add 1 to Y and create a new row
X = XEnd -> YNew is Y + 1,
generate_world(T,0,_,XEnd,YNew,_,YEnd);
%continue adding items to current row Y
generate_world(T,XNew,_,XEnd,Y,_,YEnd).
generate_world([],_,_,_,_,_,_).
Am I doing something blatantly wrong or how are you supposed to use prolog conditional statements and can they even be used like this at all?
The way I expect it to work is a term is evaluated, then do what is to the left of the following OR if it's true, or the right if it's false. That happens, but I don't understand why the entire predicate is called again as it also empties the variables being evaluated. My brain hurts.
What the docs say: http://www.swi-prolog.org/pldoc/man?predicate=-%3E/2
#damianodamiano identified the problem, if statements in prolog need to be surrounded by () tags. I'd still like a more detailed explanation of how they actually work in regards to choice points, backtracking and other Prolog specific things I might not even know about.
Your predicate stops as soon as you run it because in not(By > YEnd), By is not instantiated (note that By is also a singleton variable and each singleton variable is useless and can drive to errors). Here i post two implementation, the first without if statement (which personally prefer), the second with if statement (i've put 2 and 2 as bound for brevity...).
First implementation:
generateList(L):-
generateWL(L,0,2,0,2).
generateWL([],0,_,Y,Y). %you can add a ! here
generateWL(L,MaxX,MaxX,R,MaxR):- %you can add a ! here
R1 is R+1,
generateWL(L,0,MaxX,R1,MaxR).
generateWL([H|T],X,MaxX,R,MaxR):-
X < MaxX,
R < MaxR,
X1 is X+1,
H = [X1,point(X1,R)],
generateWL(T,X1,MaxX,R,MaxR).
?- generateList(WL).
WL = [[1, point(1, 0)], [2, point(2, 0)], [1, point(1, 1)], [2, point(2, 1)]]
false
If you want to prevent backtracking, just add the two cuts i've annotated.
Second implementation
generateList2(L):-
generateWLIf(L,0,2,0,2).
generateWLIf([H|T],X,MaxX,R,MaxR):-
( X < MaxX, R < MaxR ->
X1 is X+1,
H = [X1,point(X1,R)],
generateWL(T,X1,MaxX,R,MaxR)
; X = MaxX, R < MaxR ->
R1 is R+1,
generateWL([H|T],0,MaxX,R1,MaxR)
; R = MaxR -> T = []).
?- generateList2(WL).
WL = [[1, point(1, 0)], [2, point(2, 0)], [1, point(1, 1)], [2, point(2, 1)]]
(Continuing from the comments)
The way I expect [conditional statements] to work is a term is
evaluated, then do what is to the left of the following OR if it's
true, or the right if it's false. That happens, but I don't understand
why the entire predicate is called again as it also empties the
variables being evaluated.
You probably mean that it back-tracks, and the reason is that the comparison not(Y > YEnd) eventually fails, and there is no else-clause (and no if either).
Also, your base case makes no sense, as the list is output not input. And you want to compare against XNew not X.
generate(WorldList) :-
generate_world(WorldList,1,10000,1,50).
generate_world(T,X,XEnd,Y,YEnd) :-
( Y = YEnd ->
T = []
; T = [point(X,Y)|Rest], XNew is X + 1,
( XNew = XEnd -> YNew is Y + 1,
generate_world(Rest,1,XEnd,YNew,YEnd)
; generate_world(Rest,XNew,XEnd,Y,YEnd) ) ).
This would seem to work in the sense that it does what you describe, but it is not good design. Now you have to pass this enormous list around all the time, and updating one location means deconstructing the list.
Your problem:
I'm creating a simple platformer that generates some objects and
places them in a grid. First I'm trying to generate a simple 'world'
with the idea of trying out generating things in prolog. The plan is
to create a grid of 50 lists with 10000 items
is much better solved in Prolog by having a predicate location/3 (for example) where the parameters are the coordinates and the content.
location(1,1,something).
location(1,2,something).
location(1,3,somethingelse).
...
And this predicate is created dynamically, using assert/3.
This is based on my understanding of ISO-prolog and the other answers given, boiled down to the essence of how if then else works in Prolog.
The if predicate -> forces evaluation its the surrounding complex terms grouped by ( and ). The outer brackets identify the if-statement as ( if -> then ; else ), where if,then and else are each goals in the form of terms to be evaluated, which return yes or no, also grouped by ( and ). Whether then or else is called, separated by the OR operator ;, depends on the yes or no result from the evaluated term represented by if. The outer groupings are strictly necessary while the inner ones are optional, BUT it's good practice in my opinion to add them anyway, given that you can nest another if statement as a term surrounded by () in the result of the first, which likely produces unwanted result and makes the code much harder to read, and any non-grouped nested ; will identify the right side as the else.
Choice points are created where there are variables that can have multiple possible answers as a possible solution to the posed goal. This means within an if, if a term can be satisfied in multiple ways, Prolog will try to satisfy that goal as a separate goal and then use the result to determine the outcome of the surrounding term. If a goal fails, it behaves like normal code and doesn't try to satisfy the goals further right.
If a choice point is before the whole if statement section, the whole section will be checked again.
Example program to clarify the idea.
fact(a).
fact(f).
start :-
(
%The entire complex term is evaluated as yes
(fact(a), write('first if'), nl) ->
%triggers the first line
(write('first then'),nl) ;
(write('first else'),nl)
),
(
%The entire complex term is evaluated as no
(fact(B), write('second if'), B = b, nl) ->
(write('second then'),nl) ;
%triggers the second line
(write('second else'),nl)
).
And the output for ?- start.
first if
first then
second ifsecond ifsecond else

Prolog can somebody explain this recursion

Can someone explain how the following Prolog recursion works ?
findRoute(A,A,_).
findRoute(A,C,Path) :-
nextCnvZone(A,B),
\+ member(B,Path),
findRoute(B,C,[B|Path]).
I can understand the second part but could not understand the first part i.e what is the first findRoute(A,A,_). doing ?
It is the part that stop the recursion, i.e. when the first parameter equals the second the recursion stops, and returns true through all of the recursion levels if it made it to that level.
In general, it has the rule that the first parameter equals the second. (check if true in case both variables are given, assign the value of the second to the first if the second is variable and the first is given, etc.)
?- findRoute(1, 1, 5).
true
?- findRoute(1, 2, 5).
false
?- findRoute(1, X, 5).
X = 1
?- findRoute(X, 2, 5).
X = 2

Reasoning through a program in Prolog

I am attempting a past paper question for a Prolog exam. I drew a 'tree' for how I believed Prolog ought to behave given the program and a certain goal. However, Prolog does not behave as I expected, and given a query for which I believed it would return 'true', it actually returned 'false'.
Here is my program:
sum(Term,N) :- Term = 0, N = 0.
sum(Term,N) :- Term = f(M,Subterm), number(M), sum(Subterm,N-M).
My query and search tree are as follows (goals are bracketed and in bold):
[ sum(f(1,0),1) ]
Using Rule 1, let Term = 0, N = 0, tries to unify [ 1 = 0, 1 = 0 ] fail.
Redo: using Rule 2, let Term = f(1,0), N=1 [ f(1,0) = f(M,Subterm), number(M), sum(Subterm,1-1) ]
Unifying, let M=1 and Subterm=0 [ number(1), sum(0,0) ]
Using Rule 1, this should succeed. However (SWI) Prolog says 'false'.
If someone can point out to me why my reasoning is flawed (and how I can learn from this in future), I would be very grateful.
Since your program is almost a pure1 one, you can locate the error in a systematic manner without using a debugger. The idea is to generalize your program by removing goals, one-by-one. I came up with the following pure generalization which I obtained by "commenting" out some goals like so:
:- op(950, fy, *).
*(_).
sum(Term,N) :-
Term = 0,
N = 0.
sum(Term,N) :-
* Term = f(M,Subterm),
* number(M),
sum(Subterm,N-M).
?- sum(Term, N).
Term = 0, N = 0
; false.
Also the query above is more general than yours. This is a very useful technique in Prolog: Instead of thinking about concrete solutions, we
first let Prolog do all the work for us.
The answer was quite clear: There is exactly one solution to this relation, even if the relation is now generalized.
So the problem must be somewhere in the remaining visible part. Actually, it's the -. Why not write instead:
:- use_module(library(clpfd)).
sum(0, 0).
sum(Term, N0) :-
Term = f(M, Subterm),
N0 #= M+N1,
sum(Subterm, N1).
I find that program much easier to understand. If I read a name sum, I immediately look for a corresponding +. Of course, if you insist, you could write N0-M #= N1 instead. It would be exactly the same, except that this requires a bit more thinking.
Fine print you don't need to read
1) Your original program used number/1 which is not pure. But since the problem persisted by removing it, it did not harm our reasoning.
To be more accurate, the first rule tries to unify f(1,0) = 0 and 1 = 0, which of course fails.
Analysis of rule 2 is also incorrect. Partly, it's because Prolog does not evaluate arithmetic expressions inline. The term N-M is just a term (short-hand for '-'(N, M). It does not result in M being subtracted from M unless the evaluation is done explicitly via is/2 or an arithmetic comparison (e.g., =:=/2, =</2, etc).
The analysis of rule 2 would go as follows. Step 5 is where your logic breaks down due to the above.
Call sum(f(1,0), 1) results in Term = f(1,0) and N = 1.
In rule 2, Term = f(M, Subterm) becomes f(1,0) = f(M, Subterm) which results in M = 1 and Subterm = 0.
number(N) becomes number(1) and succeeds (since 1 is a number)
The call sum(Subterm, N-M) becomes sum(0, 1-1).
Prolog matches sum(0, 1-1) with the head of rule 1 sum(Term, N) :- Term = 0, N = 0., but it fails because 1-1 = 0 (which is the same as '-'(1, 1) = 0 unification fails.
Prolog matches sum(0, 1-1) with the head of rule 2, and unifies Term = 0 and N = 1-1 (or N = '-'(1, 1)).
Term = f(M, Subterm) becomes 0 = f(M, Subterm) which fails because 0 cannot match the term f(M, Subterm).
No more rules to attempt, so the predicate call fails.
The easy fix here is a common, basic Prolog pattern to use a new variable to evaluate the expression explicitly:
sum(Term,N) :-
Term = f(M,Subterm),
number(M),
R is N - M,
sum(Subterm, R).
You can also tidy up the code quite a bit by unifying in the heads of the clauses. So the clauses could be rewritten:
sum(0, 0).
sum(f(M, Subterm), N) :-
number(N),
R is N - M,
sum(Subterm, R).
EDIT: My answer is intended to guide you through a walk through of your existing logic. Other than correcting the misunderstanding regarding expression evaluation, I did not analyze your solution for overall correctness.

index of element

I'm new to s.o and new to Prolog which is what i am working on, specifically SWI-Prolog.
I am trying to do as the title says, and have gotten it to work on a 1 based list (starting at 1 instead of zero) using some methods that were included in the SWI-library.
and this is my code:
indexof(I,E,L):-
nth1(I,L,E).
indexof(-1,_,_).
My assignment (yes it's hw -_-) is to do this but as a 0 based count
i tried on the last line to add I is I - 1 but i kept getting errors. Is there any other way to get it into a 0 based count?
so for this indexof(A,a,[w,x,y,z,a]). i should get 4 but am getting 5.
SWI-Prolog has nth0/3 which is just like nth1/3 but the index starts at 0.
To make your original approach work, you need something like:
indexof(I,E,L) :-
nth1(I1,L,E),
I is I1 - 1.
Prolog variables can only be assigned once. If you tried I is I - 1, you're claiming that I is itself minus 1. That's never true, so the predicate fails. You need to use an intermediate variable, like I1 in the example above.
The definition of nth1/3 is nth1(?Index, ?List, ?Elem). The ? means that the argument doesn't have to be instantiated, so Prolog will fill it for you, and that means you don't even have to make a new predicate for the purpose! Here's an example for using the built-in nth1/3 predicate this way:
?- nth1(I, [1,2,3,1,3,4,5], 1).
I = 1 ;
I = 4 ;
false.
?- nth1(I, [1,2,3,1,3,4,5], 2).
I = 2 ;
false.
?- nth1(I, [1,2,3,1,3,4,5], 3).
I = 3 ;
I = 5 ;
false.

Resources