Related
I should preface this by saying this is a homework problem that I am having issues with, and Im not sure if that sort of thing is allowed around here, but I dont know where else to turn to. This is the question I've been asked:
In the sample code for this question, you can see a Fibonacci predicate fibSimple/2 which calculates the Fibonacci of X, a natural number. The problem with the naive recursive solution, is that you end up recalculating the same recursive case several times. See here for an explanation.
For example, working out the fib(5) involves working out the solution for fib(2) three separate times. A Dynamic Programming approach can solve this problem. Essentially, it boils down to starting with fib(2), then calculating fib(3), then fib(4) etc.... until you reach fib(X). You can store these answers in a list, with fib(X) ending up as the first item in the list.
Your base cases would look like the following:
fib(0,[0]).
fib(1,[1,0]).
Note the way that fib(1) is defined as [1,0]. fib(1) is really 1 but we are keeping a list of previous answers.
Why do we do this? Because to calculate fib(X), we just have to calculate fib(X-1) and add the first two elements together and insert them at the front of the list. For example, from the above, it is easy to calculate fib(2,Ans). fib(2) in this case would be [1,1,0]. Then fib(3) would be [2,1,1,0], fib(4) would be [3,2,1,1,0] etc....
Complete the fib/2 predicate as outlined above - the base cases are shown above. You need to figure out the one line that goes after the base cases to handle the recursion.
This is the sample code they provided
fibSimple(0,0). % fib of 0 is 0
fibSimple(1,1). % fib of 1 is 1
fibSimple(N,X) :- N>1,fibSimple(N-1,A), fibSimple(N-2,B), X is A+B.
fib(0,[0]).
fib(1,[1,0]).
I've had a few attempts at this, and while I'm fairly certain my attempt will end up being hopelessly wrong, this is what I have most recently tried
fib(X,[fib(X-2)+fib(X-1) | _]).
My reasoning to this is that if you can get the answer to the last 2, and add them together making them the first or "head" of the list, and then the underscore representing the rest.
My 2 issues are:
1) I don't know/think this underscore will do what I want it to do, and am lost in where to go from here
and
2) I don't know how to even run this program as the fib\2 predicate requires 2 parameters. And lets say for example I wanted to run fib\2 to find the fibonacci of 5, I would not know what to put as the 2nd parameter.
Because this is homework I will only sketch the solution - but it should answer the questions you asked.
A predicate differs from a function in that it has no return value. Prolog just tells you if it can derive it (*). So if you just ask if fib(5) is true the best you can get is "yes". But what are the Fibonacci numbers from 1 to 5 then? That's where the second argument comes in. Either you already know and check:
?- fib(5, [5, 3, 2, 1, 1, 0]).
true ; <--- Prolog can derive this fact. With ; I see more solutions.
false <--- no, there are no other solutions
Or you leave the second argument as a variable and Prolog will tell you what values that variable must have such that it can derive your query:
?- fib(5, X).
X = [5, 3, 2, 1, 1, 0] ;
false.
So the second argument contains the result you are looking for.
You can also ask the other queries like fib(X,Y) "which numbers and their fibonacci hostories can we derive?" or fib(X, [3 | _]) "which number computes the the fibonacci number 3?". In the second case, we used the underscore to say that the rest of the list does not matter. (2)
So what do we do with fib(X,[fib(X-2)+fib(X-1) | _]).? If we add it to the clauses for 0 and 1 you were given we can just query all results:
?- fib(X,Y).
X = 0,
Y = [1] ; <-- first solution X = 0, Y = [1]
X = 1,
Y = [1, 0] ; <-- second solution X = 1, Y = [1, 0]
Y = [fib(X-2)+fib(X-1)|_2088]. <-- third solution
The third solution just says: a list that begins with the term fib(X-2)+fib(X-1) is a valid solution (the _2088 as just a variable that was not named by you). But as mentioned in the beginning, this term is not evaluated. You would get similar results by defining fib(X, [quetzovercaotl(X-1) | _]).
So similar to fibSimple you need a rule that tells Prolog how to derive new facts from facts it already knows. I have reformatted fibSimple for you:
fibSimple(N,X) :-
N>1,
fibSimple(N-1,A),
fibSimple(N-2,B),
X is A+B.
This says if N > 1 and we can derive fibSimple(N-1,A) and we can derive fibSimple(N-2,B) and we can set X to the result of A + B, then we derive fibSimple(N, X). The difference to what you wrote is that fibSimple(N-1,A) occurs in the body of the rule. Again the argument N-1 does not get evaluated. What actually happens is that the recursion constructs the terms 3-1 and (3-1)-1) when called with the query fib(3,X). The actual evaluation happens in the arithmetic predicates is and <. For example, the recursive predicate stops when it tries to evaluate (3-1)-1 > 1 because 1>1 is not true. But we also do not hit the base case fibSimple(1, 1) because the term (3-1)-1 is not the same as 1 even though they evaluate to the same number.
This is the reason why Prolog does not find the Fibonacci number of 3 in the simple implementation:
?- fibSimple(3, X).
false.
The arithmetic evaluation is done by the is predicate: the query X is (3-1) -1 has exactly the solution X = 1. (3)
So fibSimple must actually look like this: (4)
fibSimple(0,1).
fibSimple(1,1).
fibSimple(N,X) :-
N>1,
M1 is N -1, % evaluate N - 1
M2 is N -2, % evaluate N - 2
fibSimple(M1,A),
fibSimple(M2,B),
X is A+B.
For fib you can use this as a template where you only need one recursive call because both A and B are in the history list. Be careful with the head of your clause: if X is the new value it can not also be the new history list. For example, the head could have the form fib(N, [X | Oldhistory]).
Good luck with the homework!
(1) This is a little simplified - Prolog will usually give you an answer substitution that tells you what values the variables in your query have. There are also some limited ways to deal with non-derivability but you don't need that here.
(2) If you use the arithmetic predicates is and > these two queries will not work with the straightforward implementation. The more declarative way of dealing with this is arithmetic constraints.
(3) For this evaluation to work, the right hand side of is may not contain variables. This is where you would need the arithmetic constraints from (2).
(4) Alternatively, the base cases could evaluate the arithmetic terms that were passed down:
fibSimple(X, 0) :-
0 is X.
fibSimple(X, 1) :-
1 is X.
fibSimple(N,X) :-
N>1,
fibSimple(N-1,A),
fibSimple(N-2,B),
X is A+B.
But this is less efficient because a single number takes much less space than the term 100000 - 1 - 1 -1 .... -1.
I've written some predicates which take the length of a list and attaches some constraints to it (is this the right vocabulary to be using?):
clp_length([], 0).
clp_length([_Head|Rest], Length) :-
Length #>= 0, Length #= Length1 + 1,
clp_length(Rest, Length1).
clp_length2([], 0).
clp_length2([_Head|Rest], Length) :-
Length #= Length1 + 1,
clp_length2(Rest, Length1).
The first terminates on this simple query, but the second doesn't:
?- Small in 1..2, clp_length(Little, Small).
Small = 1,
Little = [_1348] ;
Small = 2,
Little = [_1348, _2174] ;
false.
?- Small in 1..2, clp_length2(Little, Small).
Small = 1,
Little = [_1346] ;
Small = 2,
Little = [_1346, _2046] ;
% OOPS %
This is strange to me, because Length is pretty clearly greater than 0. To figure that out you could either search, find the zero, and deduce that adding from zero can only increase the number, or you could propagate the in 1..2 constraint down. It feels like the extra clause is redundant! That it isn't means my mental model of clpfd is pretty wrong.
So I think I have two questions (would appreciate answers to the second as comments)
Specifically, why does this additional constraint cause the query to work correctly?
Generally, is there a resource I can use to learn about how clpfd is implemented, instead of just seeing some examples of how it can be used? I'd prefer not to have to read Markus Triska's thesis but that's the only source I can find. Is that my only option if I want to be able to answer questions like this one?
1mo, there is the issue with naming. Please refer to previous answers by
mat
and me recommending relational names. You won't go far using inappropriate names. So list_length/2 or list_fdlength/2 would be an appropriate name. Thus we have list_fdlength/2 and list_fdlength2/2.
2do, consider the rule of list_fdlength2/2. Nothing suggests that 0 is of relevance to you. So that rule will be exactly the same if you are using 0 or 1 or -1 or whatever as base case. So how should this poor rule ever realize that 0 is the end to you? Better, consider a generalization:
list_fdlength2(fake(N), N) :- % Extension to permit fake lists
N #< 0.
list_fdlength2([], 0).
list_fdlength2([_Head|Rest], Length) :-
Length #= Length1 + 1,
list_fdlength2(Rest, Length1).
This generalization shows all real answers plus fake answers. Note that I have not changed the rule, I added this alternative fact only. Thus the fake solutions are actually caused by the rule:
?- list_fdlength2(L, 1).
L = [_A]
; L = [_A, _B|fake(-1)]
; L = [_A, _B, _C|fake(-2)]
; ... .
?- list_fdlength2(L, 0).
L = []
; L = [_A|fake(-1)]
; L = [_A, _B|fake(-2)]
; ... .
Each clause tries to contribute to the solutions just in the scope of the clause. But there is no way to derive (by the built-in Prolog execution mechanism) that some rules are no longer of relevance. You have to state that explicitly with redundant constraints as you did.
Now, back to your original solution containing the redundant constraint Length #>= 0. There should not be any such fake solution at all.
list_fdlength(fake(N), N) :-
N #< 0.
list_fdlength([], 0).
list_fdlength([_Head|Rest], Length) :-
Length #>= 0,
Length #= Length1 + 1,
list_fdlength(Rest, Length1).
?- list_fdlength(L, 1).
L = [_A]
; L = [_A, _B|fake(-1)] % totally unexpected
; false.
?- list_fdlength(L, 0).
L = []
; L = [_A|fake(-1)] % eek
; false.
There are fake answers, too! How ugly! At least, they are finite in number. But, you could have done it better by using
Length #>= 1 in place of Length #>=0. With this little change, there are no longer any fake solutions when N is non-negative and thus also your original program will be better.
I'm playing around with recursion in Prolog, and I'm confused. I am trying to write rules that can determine if a number is even or odd. I know that there are other stackoverflow questions about this, but I don't care about having a working solution, I am more interested in knowing why mine doesn't work.
Here are my rules:
even(0).
even(N) :- N>0, N1 is N-1, odd(N1).
odd(N) :- N>0, N1 is N-1, even(N1).
When I query even(0), I get returned 2 results. The first result is true, the 2nd is false. This also happens with odd(1), even(2), odd(3), etc. Why am I getting 2 return results? Shouldn't I just get 1?
When you query even(0), it succeeds as you have seen. But you've also seen it prompts you for more results because it left a choicepoint, which is a place in the logic where Prolog decides it can come back and explore other alternatives for a potentially successful query. Upon going back to the choicepoint and attempting to find more solutions, it does not find more, so it comes back "false" since it found no more solutions. So it did just find one solution, but the choice point caused backtracking after which it found no additional solutions. This is the case with your other successful queries as well.
You'll note that if you make a more general query, it gives an error (example taken from GNU Prolog):
| ?- even(N).
N = 0 ? ;
uncaught exception: error(instantiation_error,(>)/2)
| ?-
This is because you are using specific arithmetic expression operators that require that the variables be instantiated. These are relational operators like (>)/2 and the is/2 operator. You can make the solution more relational by using the CLP(FD) operators which are designed for reasoning with integers:
even(0).
even(N) :-
N #> 0,
N1 #= N-1,
odd(N1).
odd(N) :-
N #> 0,
N1 #= N-1,
even(N1).
Then you get a more general solution, which is more complete and more useful:
| ?- even(N).
N = 0 ? ;
N = 2 ? ;
N = 4 ? ;
N = 6 ? ;
...
| ?- odd(N).
N = 1 ? ;
N = 3 ? ;
N = 5 ? ;
N = 7 ?
...
If you know there is at most one answer, or if you only care about the first possible answer, you can use once/1 (examples taken from SWI Prolog here):
2 ?- even(2).
true ;
false.
3 ?- once(even(2)).
true.
4 ?- even(N).
N = 0 ;
N = 2 ;
N = 4 ;
...
5 ?- once(even(N)).
N = 0.
6 ?-
As expected, once(even(N)) terminates after finding the first solution.
The return values you have are correct. The point is how Prolog is evaluating predicates. When you query i.e.
even(2)
Prolog firstly evaluate that this predicate is Yes / true. When going through next possibility it return No / false, because it cannot find any more.
To check what exactly is performed under the hood go to:
https://swish.swi-prolog.org
on the left side type rules (i.e. odd/even) and on the query window type like 'odd(2)', but just before running click 'solutions'->'debug(trace)'. It will let you go step by step of what Prolog is doing.
Also please take a look at the successor example in tutorial below.
http://www.learnprolognow.org/lpnpage.php?pagetype=html&pageid=lpn-htmlse9
from a link above, try such code for a reversed example:
numeral(0).
numeral(succ(X)) :- numeral(X).
Now evaluating numeral(0) for the first time return succ(0), another time succ(succ(0)) etc.
Each time next evaluation brings another possible solution for a query.
What Prolog does is a "depth-first search", which means Prolog walks through a decision tree until it either finds a solution and succeeds OR it fails. In either case a process called "backtracking" kicks in. Along the way, going through the tree of choices, Prolog keeps track of where it has MULTIPLE possible routes that could potentially satisfy the goal. Such a point in the decision tree is called a "choice point".
This means Prolog will
search ->
succeed or fail ->
go back to the last choice point ->
repeat until all possible paths have been tried
Given your program:
even(0).
even(N) :- N>0, N1 is N-1, odd(N1).
odd(N) :- N>0, N1 is N-1, even(N1).
We can clearly see TWO ways to satisfy even(0).. The first is the fact even(0) and the second is the recursive rule even(N). Prolog reads top to bottom, left to right so the first encounter is even(0). which is true, and the second is even(N). which goes through N-1 making the result N1 = -1, then goes through odd(N) making the result N1 = -2, which in unequal to even(0). so it fails and then calls even(N) again. Your specific version of Prolog likely sees that it is an infinitely recursive predicate and doesn't even try to satisfy it even though it's a valid declarative path , but not a valid procedural path.
If you know that the mode is (+), you can place a cut,
to suppress the unnecessary choice point:
even(0) :- !.
even(N) :- N > 0, N1 is N-1, odd(N1).
odd(N) :- N > 0, N1 is N-1, even(N1).
The above is better than wrapping a query with
once/1 since it allows the Prolog interpreter to
use last call optimization. There is now no more
problem with an extra choice point:
?- even(3).
false.
?- even(4).
true.
But if the mode is not fixed, you have to be more careful
with cuts. Probably write a separate carefully crafted
predicate for each mode.
CLP(FD) itself seems not to help, it cannot avoid the need
to place cuts, but can sometimes avoid the need to code
different variants for different modes.
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.
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].