Related
I need to create a prolog relation that receives a tree, sums the values in each nodes and finds the path with the maximal sum.
I've tried this method of a max sub tree:
max_sub_tree(Tree,T,N):-
sol_tree_noroot(Tree,T1,N1),
sol_tree_withroot(Tree,T2,N2),!,
max_set(T1,N1,T2,N2,T,N).
max_set(T1, N1, T2, N2, T, N) :-
(N1>N2,T=T1,N=N1;
N2>N1,T=T2,N=N2;
N2=:=N1,N=N1,(T=T1;T=T2)).
sol_tree_noroot(nil,nil,0).
sol_tree_noroot(t(L,_,R),T,N):-
max_sub_tree(L,T1,N1),max_sub_tree(R,T2,N2),!,
max_set(T1, N1, T2, N2, T, N).
sol_tree_withroot(nil,nil,0).
sol_tree_withroot(t(L,X,R),t(L1,X,R1),N3):-
sol_tree_withroot(L,T1,N1),sol_tree_withroot(R,T2,N2),
max_set2(T1,N1,T2,N2,L1,R1,N),
N3 is N+X.
max_set2(T1,N1,T2,N2,L,R,N):-
(N1>0,N2>0,N is N1+N2,L=T1,R=T2;
N1>=0,N2<0,N is N1 ,R=nil,L=T1;
N1<0,N2>=0,N is N2 ,L=nil,R=T2;
N1<0,N2<0,N1<N2,N is N2 ,L=nil,R=T2;
N1<0,N2<0,N1>N2,N is N1 ,L=T1,R=nil;
N1>0,N2=0,N is N1,(L=T1,R=nil;L=T1,R=T2);
N1=0,N2>0,N is N2,(R=T2,L=nil;L=T1,R=T2);
N1=0,N2=0,N is N1,(L=T1,R=nil;R=T2,L=T1;L=T1,R=T2)).
When I use the query
max_sub_tree(t(t(t(nil,2,nil),1,t(t(nil,40,nil),-30,nil)),-100,t(nil,50,t(nil,60,nil))) ,T,N).
I get
N = 110,
T = t(nil, 50, t(nil, 60, nil))
But I want the output to look like this:
N = 10,
T =.. [t, -100, 50, 60]
What Am I missing? how do I include the root? do i need to start over?
Subtree Sums
This looks complicated, might I suggest we start from how to generate the sums of the subtrees that terminate in leaf nodes:
tree_sum(t(nil, N, nil), N). % leaf
tree_sum(t(T, N, nil), X) :- % only left branch
tree_sum(T, M), X is N + M.
tree_sum(t(nil, N, T), X) :- % only right branch
tree_sum(T, M), X is N + M.
tree_sum(t(T1, N, T2), X) :- % branches
( tree_sum(T1, M), X is N + M
; tree_sum(T2, M), X is N + M
).
That disjunction is where we need to focus to find the maximum tree sum, let's add that into our code next. There's no change to the first three rules
max_tree_sum(t(nil, N, nil), N). % leaf
max_tree_sum(t(T, N, nil), X) :- % only left branch
max_tree_sum(T, M), X is N + M.
max_tree_sum(t(nil, N, T), X) :- % only right branch
max_tree_sum(T, M), X is N + M.
max_tree_sum(t(T1, N, T2), X) :-
max_tree_sum(T1, M1), X1 is N + M1,
max_tree_sum(T2, M2), X2 is N + M12,
X is max(X1, X2).
A solution
Ok, so our code is finding the maximum solution, now we need it to track the path, building the list. We add in the final argument for this and an extra sub-predicate to do the comparison of branches for us:
max_tree_sum(t(nil, N, nil), N, [N]). % leaf
max_tree_sum(t(T, N, nil), X, [N|MT]) :- % left branch only
max_tree_sum(T, M, MT), X is N + M.
max_tree_sum(t(nil, N, T), X, [N|MT]) :- % right branch only
max_tree_sum(T, M, MT), X is N + M.
max_tree_sum(t(T1, N, T2), X, [N|T]) :- % branches
max_tree_sum(T1, M1, MT1),
max_tree_sum(T2, M2, MT2),
max_subtree(M1, M2, MT1, MT2, M, T), X is M + N.
max_subtree(N1, N2, T1, _, N1, T1) :-
N1 >= N2.
max_subtree(N1, N2, _, T2, N2, T2) :-
N1 =< N2.
As Requested with T =.. [t|Nodes]
Now if you want the list converted to a predicate, put an extra predicate call to this:
max_subtree_sum(Tree, Sum, Pred) :-
max_tree_sum(Tree, Sum, Path),
Pred =.. [t|L].
?- max_subtree_sum(ExampleTree, 10, t(-100, 50, 60)).
But now t(-100, 50, 60) is not a tree.
I created a program in Prolog which returns following powers of two starting from one:
twos(N, L) :- twosH(N, 1, L).
twosH(0, _, L) :- L = [], !.
twosH(N, I, [R|L]) :- R is 2*I, N1 is N-1, twosH(N1, R, L).
I would like it to use difference list instead of regular one. I know how to append an element to difference list:
appendD(A-B, B-C, A-C).
but I don't know how to incorporate it into my program.
If you use a DCG, then you are using a difference list:
powers_of_2(0, 1) --> [1].
powers_of_2(N, PT) --> [PT], { PT #= 2 * PT1, N #> 0, N #= N1 + 1 }, powers_of_2(N1, PT1).
powers_of_2(N, PT) :-
phrase(powers_of_2(N, _), PT).
| ?- powers_of_2(4, P).
P = [16,8,4,2,1] ? ;
no
| ?-
A listing of what the DCG looks like as standard predicates (obtained by entering listing. then I changed the variable names a little):
powers_of_2(0, 1, [1|T], T).
powers_of_2(N, PT, [PT|PTs], T) :-
PT #= 2 * PT1,
N #> 0,
N #= N1 + 1,
powers_of_2(N1, PT1, PTs, T).
If you called it directly, you would give it the empty list as the final tail:
| ?- powers_of_2(4, P, PT, []).
P = 16
PT = [16,8,4,2,1] ? ;
no
If you want the numbers in the reverse order, I'll leave that as an exercise. :)
i need to covert list to binary search tree ,then search about range of ages in this tree and return the a list contain these values, and also return number of checks in order to build the output list .
i spend two days trying do this but it always return false
here my last code that i reach it with help of mbratch:
my_list( [[30,'john'], [58,'alex'], [14,'randy'], [65,'shawn'], [67,'jack']] ).
construct(L,T) :- construct(L,T,nil).
construct([],T,T).
construct([N|Ns],T,T0) :- add(N,T0,T1), construct(Ns,T,T1).
add(X, nil, node(X, nil, nil)).
add(X, node(Root, L, R),node(Root, L1, R)) :- X #< Root, add(X, L, L1).
add(X, node(Root, L, R),node(Root, L, R1)) :- X #> Root, add(X, R, R1).
findInRange(R1, R2, T, S, N) :- find(R1, R2, T, S, N),!.
find(_R1,_R2, nil, [], 0).
find(R1, R2, node([Age,Name],L,R), S, N) :-
R1 =< Age,R2 >= Age, % is the age OK (in range), if it is check left and
find(R1, R2, L, LL, NL),
find(R1,R2,R,LR,NR),
append([[Age,Name]],LL,X),
append(X,LR,S),
N is NL+NR+1.
find(R1, R2, node([Age,Name],L,R), [], 0) :-
Age > R2;Age<R1. % if the age is greater than R2, return []
find(R1, R2, node([Age,Name],L,R), LL, N) :-
R1 < Age, % if the age is bigger than R1 search the left tree return LL
find(R1,R2,L,LL,NL),
N is NL+1.
find(R1, R2, node([Age,Name],L,R), LR, N) :-
R2 > Age, % if the age smaller than R1 search the right tree return LR
find(R1,R2,R,LR,NR),
N is NR+1.
and here is my query :
my_list(Z), construct(Z, T), findInRange(11, 15, T, S, N).
it should retufn [[14,'randy']] and number of checks.
Why does it return empty list and N=0 ?
I think this will do the trick. I ran the query you posted and got S = [[30, john], [14, randy]].
my_list( [[30,'john'], [58,'alex'], [14,'randy'], [65,'shawn'], [67,'jack']] ).
construct(L,T) :- construct(L,T,nil).
construct([],T,T).
construct([N|Ns],T,T0) :- add(N,T0,T1),construct(Ns,T,T1).
add(X, nil, node(X, nil, nil)).
add(X, node(Root, L, R),node(Root, L1, R)) :- X #< Root, add(X, L, L1).
add(X, node(Root, L, R),node(Root, L, R1)) :- X #> Root, add(X, R, R1).
findInRange(R1, R2, T, S, N) :- find(R1, R2, T, S, N),!.
find(_R1,_R2, nil, [], 0).
find(R1, R2, node([Age,Name],L,R), S, N) :-
R1 =< Age,R2 >= Age, % is the age OK (in range), if it is check left and right side
find(R1, R2, L, LL, NL),
find(R1,R2,R,LR,NR),
append([[Age,Name]| LL],LR,S),
N is NL+NR+1.
find(R1, R2, node([Age,Name],L,R), LL, N) :-
Age > R2, % if the age is bigger than R2 search the left tree return LL
find(R1,R2,L,LL,NL),
N is NL+1.
find(R1, R2, node([Age,Name],L,R), LR, N) :-
R1 > Age, % if the age smaller than R1 search the right tree return LR
find(R1,R2,R,LR,NR),
N is NR+1.
This is the pretty known code for an inorder traversal in a generic binary tree in PROLOG:
inorder(t(K,L,R), List) :-
inorder(L,LL), inorder(R, LR),
append(LL, [K|LR], List).
inorder(nil, []).
if the input binary tree is a binary search tree (BST), what about If I want to modify such code in such way I will not visit just all the nodes, but only the minimum needed to find those ones whose key falls in a given range, having them as output result?
I am trying something like:
inorder(R1, R2, t(K,L,R), List) :-
(K >= R1 -> inorder(R1, R2, L, LL); true),
(K =< R2 -> inorder(R1, R2, R, LR); true),
append(LL, [K|LR], List).
inorder(_, _, _, _).
I figured out the correct version:
inorder(R1,R2, t(K,L,R), List) :-
( R2 < K
-> inorder(R1,R2, L, LL),
append(LL,[],List);
K < R1
-> inorder(R1,R2, R, LR),
append(LR,[],List);
inorder(R1,R2, L, LL),
inorder(R1,R2, R, LR),
append(LL, [K|LR], List)
).
you are 'near to target', and you will benefit of studying what your code does. Here is my solution (only minimally tested)
inorder(R1,R2, t(K,L,R), List) :-
( R2 < K
-> inorder(R1,R2, L, List)
; K < R1
-> inorder(R1,R2, R, List)
; inorder(R1,R2, L, LL),
inorder(R1,R2, R, LR),
append(LL, [K|LR], List)
).
inorder(_R1,_R2, -, []).
of course, I like best a DCG solution
inorder(R1,R2, Tree, Yield) :-
phrase(inorder(R1, R2, Tree), Yield, []).
inorder(R1,R2, t(K,L,R)) -->
{R2 < K}
-> inorder(R1,R2,L)
; {K < R1}
-> inorder(R1,R2,R)
; inorder(R1,R2,L),
[K],
inorder(R1,R2,R).
inorder(_R1,_R2, -) --> [].
note: no more append/3 needed. It's cleaner and more efficient.
edit better naming:
inorder(R1,R2, Tree, Yield) :-
phrase(rangequery(R1, R2, Tree), Yield, []).
rangequery(R1,R2, t(K,L,R)) -->
{R2 < K}
-> rangequery(R1,R2,L)
; {K < R1}
-> rangequery(R1,R2,R)
; rangequery(R1,R2,L),
[K],
rangequery(R1,R2,R).
rangequery(_R1,_R2, -) --> [].
and sample run
?- inorder(1,2,t(3,t(1,-,-),-),L).
L = [1] ;
false.
?- inorder(1,4,t(3,t(1,-,t(2,-,-)),-),L).
L = [1, 2, 3] ;
false.
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).