Fibonacci in Prolog - Breaks if False - prolog

I have a program fib(X,Y). If Y is the Xth Fibonacci number it returns True else it should return False. My program breaks anytime I input statement which is false.
fib(R,V) :- fib(0,1,R,V).
fib(X, Y, 0, V) :- Y == V.
fib(X, Y, R, V) :- Z is X + Y, C is R - 1, fib(Y, Z, C, V).
fib(0,1) -> True
fib(1,1) -> True
fib(2,2) -> True
fib(3,3) -> True
fib(4,5) -> True
fib(3,5) -> Won't finish.
What do I do wrong? I am using https://swish.swi-prolog.org/ to run my program queries.

The problem here is that you write two clauses fib(X, Y, 0, V) :- and fib(X, Y, R, V) :-. Prolog uses backtracking: in case one clause has been tried, it wil - regardless of sucess or failure - also later retry the next clause (there are some meta-predicates like once/1 that can alter this).
So even if R is 0, or lower, Prolog will also try the second clause.
A quick way to fix this is by using a guards for the second clause:
fib(_, Y, 0, V) :-
Y == V.
fib(X, Y, R, V) :-
R > 0,
Z is X + Y,
C is R - 1,
fib(Y, Z, C, V).
Furthermore your code is not very elegant in the sense that you can not use the relation in a reversed way, nor can we query for the X-th element.
For instance you use Y == V, but this blocks unification: if we want to know the X-th fibonacci number, we want a way to propagate the result back. So we can use unification instead:
fib(_, V, 0, V).
fib(X, Y, R, V) :-
R > 0,
Z is X + Y,
C is R - 1,
fib(Y, Z, C, V).
But now we still do not have a bidirectional relation: we can not obtain the X for a given value V. This is more complex. The easiest way is probably using clpfd for this:
:- use_module(library(clpfd)).
fib(_, V, 0, V).
fib(X, Y, R, V) :-
R #> 0,
V #>= Y,
Z is X + Y,
C #= R - 1,
fib(Y, Z, C, V).
Now we can:
enumerate all indices and the corresponding Fibonacci numbers:
?- fib(A,B).
A = 0,
B = 1 ;
A = B, B = 2 ;
A = B, B = 3 ;
A = 4,
B = 5 ;
A = 5,
B = 8 ;
A = 6,
B = 13 ;
A = 7,
B = 21
...
Obtain the i-th Fibonacci number:
?- fib(2,B).
B = 2 ;
false.
?- fib(10,B).
B = 89 ;
false.
obtain the i for which the corresponding Fibonacci number is a certain value:
?- fib(A,1).
A = 0 ;
A = 1 ;
false.
?- fib(A,2).
A = 2 ;
false.
?- fib(A,3).
A = 3 ;
false.
?- fib(A,4).
false.
?- fib(A,5).
A = 4 ;
false.
Check if the i-th Fibonacci number is a given value:
?- fib(4,5).
true ;
false.
?- fib(4,6).
false.
?- fib(4,10).
false.
?- fib(5,8).
true ;
false.

Related

Incrementing value on backtrack

how can I do increment on backtracking ... so that goal(S) receives incremented number .. every time it fails on the next run I want to get the next number
S1 is S + 1,goal(S1)
does not work, because :
?- S=0, S1 is S+1.
S = 0,
S1 = 1.
?- S=0,between(1,3,_), S1 is S+1.
S = 0,
S1 = 1 ;
S = 0,
S1 = 1 ;
S = 0,
S1 = 1.
this work
%%counting
baz(..,C) :- .... arg(...), Y is X + 1, nb_setarg(...), goal(Y), ...
foo(..C) :- ....baz(....,C)..., foo(...C).
%%counter
blah :- ....foo(....,counter(0))...
this is not working, i think cause the recursive foo() would force baz() to initialize counter(0)... but i'm good with #sligo solution above
baz(..) :- C = counter(0), .... arg(...), Y is X + 1, nb_setarg(...), goal(Y), ...
foo(..) :- ....baz(....)..., foo(...).
so that goal(S) receives incremented number .. every time it fails on the next run I want to get the next number
That's what between/3 does? Every time on backtracking it makes the next number:
goal(X) :-
write('inside goal, X is '),
write(X),
nl.
test :-
between(0, 3, S),
goal(S).
e.g.
?- test.
inside goal, X is 0
true ;
inside goal, X is 1
true ;
inside goal, X is 2
true ;
inside goal, X is 3
true ;
Edit: From the help for between/3:
between(+Low, +High, ?Value)
Low and High are integers, High >=Low. If Value is an integer,
Low =<Value =<High. When Value is a variable it is successively
bound to all integers between Low and High. If High is inf or
infinite between/3 is true iff Value >=Low, a feature that is
particularly interesting for generating integers from a certain value.
(And see the comments on the help page by LogicalCaptain)
Use non-backtrackable destructive assignment predicate nb_setarg/3:
?- C = counter(0), between(1, 3, _), arg(1, C, X), Y is X + 1, nb_setarg(1, C, Y).
C = counter(1),
X = 0,
Y = 1 ;
C = counter(2),
X = 1,
Y = 2 ;
C = counter(3),
X = 2,
Y = 3.
Alternatives:
foo(C) :-
between(1, inf, C),
goal(C),
!.
baz(C) :-
C = counter(0),
repeat,
arg(1, C, X),
Y is X + 1,
nb_setarg(1, C, Y),
goal(Y),
!.
goal(X) :-
X > 9.
Examples:
?- foo(C).
C = 10.
?- baz(C).
C = counter(10).

How to use an fd solver to determine which elements of a list can sum to a given number?

Given a list of possible summands I want to determine which, if any, can form a given sum. For example, with [1,2,3,4,5] I can make the sum of 9 with [4,5], [5,3,1], and [4,3,2].
I am using GNU Prolog and have something like the following which does not work
numbers([1,2,3,4,5]).
all_unique(_, []).
all_unique(L, [V|T]) :-
fd_exactly(1, L, V),
all_unique(L, T).
fd_sum([], Sum).
fd_sum([H|T], Sum):-
S = Sum + H,
fd_sum(T, S).
sum_clp(N, Summands):-
numbers(Numbers),
length(Numbers, F),
between(1, F, X),
length(S, X),
fd_domain(S, Numbers),
fd_domain(Y, [N]),
all_unique(S, Numbers),
fd_sum(S, Sum),
Sum #= Y,
fd_labeling(S).
I think the main problem is that I am not representing the constraint on the sum properly? Or maybe it is something else?
Just in case you're really interested in CLP(FD), here is your corrected program.
numbers([1,2,3,4,5]).
% note: use builtins where available, both for efficiency and correctness
%all_unique(_, []).
%all_unique(L, [V|T]) :-
% fd_exactly(1, L, V),
% all_unique(L, T).
fd_sum([], 0). % sum_fd_SO.pl:8: warning: singleton variables [Sum] for fd_sum/2
fd_sum([H|T], Sum):-
% note: use CLP(FD) operators and the correct operands
Sum #= S + H,
fd_sum(T, S).
sum_clp(N, S):- % sum_fd_SO.pl:13-23: warning: singleton variables [Summands] for sum_clp/2
numbers(Numbers),
length(Numbers, F),
between(1, F, X),
length(S, X),
fd_domain(S, Numbers),
%fd_domain(Y, [N]),
%all_unique(S, Numbers),
fd_all_different(S),
fd_sum(S, N),
%Sum #= Y,
fd_labeling(S).
test
?- sum_clp(3,L).
L = [3] ? ;
L = [1,2] ? ;
L = [2,1] ? ;
no
I think mixing the code for sublist into clp code is causing some confusion. GNU-Prolog has a sublist/2 predicate, you can use that.
You seem to be building the arithmetic expression with fd_sum but it is incorrectly implemented.
sum_exp([], 0).
sum_exp([X|Xs], X+Xse) :-
sum_exp(Xs, Xse).
sum_c(X, N, Xsub) :-
sublist(Xsub, X),
sum_exp(Xsub, Xe),
N #= Xe.
| ?- sum_exp([A, B, C, D], X).
X = A+(B+(C+(D+0)))
yes
| ?- sum_c([1, 2, 3, 4, 5], 9, X).
X = [4,5] ? ;
X = [2,3,4] ? ;
X = [1,3,5] ? ;
(1 ms) no
| ?- length(X, 4), sum_c(X, 4, [A, B]), member(A, [1, 2, 3]).
A = 1
B = 3
X = [_,_,1,3] ? ;
A = 2
B = 2
X = [_,_,2,2] ? ;
A = 3
B = 1
X = [_,_,3,1] ?
yes

find biggest interval in a list of sublists (these sublists have 2 elements)

i have this exercise where i get a list of sublists like [[X1,Y1],[X2,Y2]...] which represent an interval (Xi-Yi), and i want to return a list with the biggest interval (it can be more than one interval).
this is what i've got so far.
i can't see what im doing wrong but when try to run biggest_interval([[1,2],[5,7],[6,10],[12,15]],L). i get true, followed by a false instead of [6,10]
biggest_interval([H|T],Answer):-
biggest_interval(H,T,-1,Answer).
biggest_interval([],_,_,_).
biggest_interval(_,[],_,_).
biggest_interval([X,Y],[H|T],Biggest,Answer):-
Z is Y-X,
Z =:= Biggest,
append(Answer,[X,Y],L),
!,
biggest_interval(H,T,Biggest,L).
biggest_interval([X,Y],[H|T],Biggest,Answer):-
Z is Y-X,
(
Z > Biggest -> append([],[X,Y],L),
biggest_interval(H,T,Z,L);
true
),
biggest_interval(H,T,Biggest,Answer).
One of the problems with your code is that your predicate biggest_interval/4 does not collect the Answer in the "base case" (it only stops the recursive process).
One possible solution is:
biggest_interval(ListOfLists, Answer) :-
biggest_interval(ListOfLists, -inf, [], Biggest),
reverse(Biggest, Answer). % if order of the pairs is important!
biggest_interval([], _, Answer, Answer) :- !. % collect Answer!
biggest_interval([[X,Y]|Lists], Max, Acc, Answer) :-
Z is Y-X,
( Z = Max -> biggest_interval(Lists, Max, [[X,Y]|Acc], Answer)
; Z > Max -> biggest_interval(Lists, Z, [[X,Y]], Answer)
; biggest_interval(Lists, Max, Acc, Answer) ).
Here are some examples:
?- biggest_interval([[1,2],[5,7],[6,10],[12,15]],L).
L = [[6, 10]].
?- biggest_interval([[1,20],[5,7],[6,10],[12,15]],L).
L = [[1, 20]].
?- biggest_interval([[1,2],[5,7],[6,10],[12,15],[3,10]],L).
L = [[3, 10]].
?- biggest_interval([[1,2],[5,7],[6,10],[12,15],[8,12]],L).
L = [[6, 10], [8, 12]].
Here is another way to do it, with functionnal design :
:- use_module(library(lambda)).
biggest_interval([[H1, H2]|T], Out) :-
D1 is H2 - H1,
foldl(\X^Y^Z^(X = [A,B],
D is B - A,
Y = [Delta, L],
( Delta > D
-> Z = Y
; ( Delta = D
-> append(L, [X], NL),
Z = [Delta, NL]
; Z = [D, [X]]))), T, [D1, [[H1,H2]]], [_, Out]).
example :
?- biggest_interval([[1,2],[5,7],[6,10],[12,15]],L).
L = [[6, 10]].
?- biggest_interval([[1,2],[5,7],[6,10],[12,15],[8,12]],L).
L = [[6, 10], [8, 12]].

Prolog: calculate index for a list of list

I'm new to prolog. I want to implement a predict called high/3. This predict supports two scenarios: One is to return the index of one character in a list of list, for example:
high([[a,b,c],[d,e,f], [g,h]], b, X) returns X = 1
high([[a,b,c],[d,e,f], [g,h]], f, X) returns X = 2
The second scenario is if you provide an index, it should also return all characters at that index position.
e.g.
high([[a,b,c],[d,e,f], [g,h]], X, 1) returns X = b; X= e; X= h
high([[a,b,c],[d,e,f], [g,h]], X, 2) returns X = c; X= f.
I wrote the following predirect:
high([[X|_]|L], X, 0).
high([[Head|Tail]|L], X, H):- member(X, Tail), high([Tail|L], X, H1),H is H1 + 1.
high([[Head|Tail]|L], X, H):- not(member(X, Tail)), high(L, X, H).
This predict only works for the first scenario, but it doesn't work properly for the second scenario.
If I run high([[a,b,c],[d,e,f], [g,h]], X, 1), it only returns X = b, but I expect it returns b, e, h there one by one.
Why does it return only b and fail?
It's a bit unclear what it should do in cases where there are identical elements in different lists. Nevertheless, here's my solution using library(clpfd):
:- use_module(library(clpfd)).
high([H|_], X, I) :-
high_(H, X, I, 0).
high([_|T], X, I) :-
high(T, X, I).
high_([X|_], X, I, I).
high_([_|T], X, I, J) :-
J #>= 0,
J #=< I,
J1 #= J + 1,
high_(T, X, I, J1).
This has the following behaviour:
?- high([[a,b,c],[d,e,f],[g,h]], b, I).
I = 1 ;
false.
?- high([[a,b,c],[d,e,f],[g,h]], f, I).
I = 2 ;
false.
?- high([[a,b,c],[d,e,f],[g,h]], X, 1).
X = b ;
X = e ;
X = h ;
false.
?- high([[a,b,c],[d,e,f],[g,h]], X, 2).
X = c ;
X = f ;
false.
But also works when there are duplicates:
?- high([[a,a],[b,a]], a, X).
X = 0 ;
X = 1 ;
X = 1 ;
false.
With unknown sublists:
?- high([A,B], X, 2).
A = [_4552, _4558, X|_4566] ;
B = [_4552, _4558, X|_4566] ;
false.
With an unknown list of lists:
?- high(L, X, 2).
L = [[_4518, _4524, X|_4532]|_4514] ;
L = [_4512, [_4524, _4530, X|_4538]|_4520] ;
L = [_4512, _4518, [_4530, _4536, X|_4544]|_4526] ;
…
It only returns one result because not(member(X, Tail)) will never be true as long as X hasn't been unified with anything (and Tail is not empty). In other words, since the second clause succeeds, the third one cannot and the recursion does not continue to handle the following lists.
However, I'd say you're going about this the wrong way. Your current code will also give wrong output if an element is present in multiple sublists.
You can break down your problem into smaller parts: you need to be able to relate and element to its index inside a single, simple list; and you need to be able to evaluate this for all sublists in your total list.
First things first: relate and element to its index:
index([X|_], X, 0).
index([_|T], X, I) :- index(T, X, I2), I is I2 + 1.
Very simple and easy to understand, right?
Now to recurse through all lists and match all elements/indices in them:
high([H|_], X, I) :- index(H, X, I).
high([_|T], X, I) :- high(T, X, I).
This will give all the expected outputs:
?- high([[a,b,c],[d,e,f], [g,h]], b, X)
X = 1;
false.
?- high([[a,b,c],[d,e,f], [g,h]], f, X)
X = 2;
false.
high([[a,b,c],[d,e,f], [g,h]], X, 1).
X = b;
X = e;
X = h;
false.
high([[a,b,c],[d,e,f], [g,h]], X, 2).
X = c;
X = f;
false.

Inverse factorial in Prolog

Can someone helping me to find a way to get the inverse factorial in Prolog...
For example inverse_factorial(6,X) ===> X = 3.
I have been working on it a lot of time.
I currently have the factorial, but i have to make it reversible. Please help me.
Prolog's predicates are relations, so once you have defined factorial, you have implicitly defined the inverse too. However, regular arithmetics is moded in Prolog, that is, the entire expression in (is)/2 or (>)/2 has to be known at runtime, and if it is not, an error occurs. Constraints overcome this shortcoming:
:- use_module(library(clpfd)).
n_factorial(0, 1).
n_factorial(N, F) :-
N #> 0, N1 #= N - 1, F #= N * F1,
n_factorial(N1, F1).
This definition now works in both directions.
?- n_factorial(N,6).
N = 3
; false.
?- n_factorial(3,F).
F = 6
; false.
Since SICStus 4.3.4 and SWI 7.1.25 also the following terminates:
?- n_factorial(N,N).
N = 1
; N = 2
; false.
See the manual for more.
For reference, here is the best implementation of a declarative factorial predicate I could come up with.
Two main points are different from #false's answer:
It uses an accumulator argument, and recursive calls increment the factor we multiply the factorial with, instead of a standard recursive implementation where the base case is 0. This makes the predicate much faster when the factorial is known and the initial number is not.
It uses if_/3 and (=)/3 extensively, from module reif, to get rid of unnecessary choice points when possible. It also uses (#>)/3 and the reified (===)/6 which is a variation of (=)/3 for cases where we have two couples that can be used for the if -> then part of if_.
factorial/2
factorial(N, F) :-
factorial(N, 0, 1, F).
factorial(N, I, N0, F) :-
F #> 0,
N #>= 0,
I #>= 0,
I #=< N,
N0 #> 0,
N0 #=< F,
if_(I #> 2,
( F #> N,
if_(===(N, I, N0, F, T1),
if_(T1 = true,
N0 = F,
N = I
),
( J #= I + 1,
N1 #= N0*J,
factorial(N, J, N1, F)
)
)
),
if_(N = I,
N0 = F,
( J #= I + 1,
N1 #= N0*J,
factorial(N, J, N1, F)
)
)
).
(#>)/3
#>(X, Y, T) :-
zcompare(C, X, Y),
greater_true(C, T).
greater_true(>, true).
greater_true(<, false).
greater_true(=, false).
(===)/6
===(X1, Y1, X2, Y2, T1, T) :-
( T1 == true -> =(X1, Y1, T)
; T1 == false -> =(X2, Y2, T)
; X1 == Y1 -> T1 = true, T = true
; X1 \= Y1 -> T1 = true, T = false
; X2 == Y2 -> T1 = false, T = true
; X2 \= Y2 -> T1 = false, T = false
; T1 = true, T = true, X1 = Y1
; T1 = true, T = false, dif(X1, Y1)
).
Some queries
?- factorial(N, N).
N = 1 ;
N = 2 ;
false. % One could probably get rid of the choice point at the cost of readability
?- factorial(N, 1).
N = 0 ;
N = 1 ;
false. % Same
?- factorial(10, N).
N = 3628800. % No choice point
?- time(factorial(N, 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000)).
% 79,283 inferences, 0.031 CPU in 0.027 seconds (116% CPU, 2541106 Lips)
N = 100. % No choice point
?- time(factorial(N, 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518284253697920827223758251185210916864000000000000000000000000)).
% 78,907 inferences, 0.031 CPU in 0.025 seconds (125% CPU, 2529054 Lips)
false.
?- F #> 10^100, factorial(N, F).
F = 11978571669969891796072783721689098736458938142546425857555362864628009582789845319680000000000000000,
N = 70 ;
F = 850478588567862317521167644239926010288584608120796235886430763388588680378079017697280000000000000000,
N = 71 ;
F = 61234458376886086861524070385274672740778091784697328983823014963978384987221689274204160000000000000000,
N = 72 ;
...
a simple 'low tech' way: enumerate integers until
you find the sought factorial, then 'get back' the number
the factorial being built is greater than the target. Then you can fail...
Practically, you can just add 2 arguments to your existing factorial implementation, the target and the found inverse.
Just implement factorial(X, XFact) and then swap arguments
factorial(X, XFact) :- f(X, 1, 1, XFact).
f(N, N, F, F) :- !.
f(N, N0, F0, F) :- succ(N0, N1), F1 is F0 * N1, f(N, N1, F1, F).

Resources