Title: Dynamic programming of recursive functions in Prolog
Date: 2017-10-03T00:00:00
Tags: Prolog, Memoization
Authors: Henry Brooks

Last week I was able to successfully implementing Fibonacci with memoization in Prolog. This time I thought I would try the Hailstone and Ackermann formulas to see if all recursive functions can benefit from memoization.

Hailstone

By itself the Hailstone function is not recursive however, trying to calculate the longest Hailstone Sequence is a highly recursive task.

I coded up this first memoized version of the Hailstone formula rather quickly by modifying the Fibonacci code from last week.

:- use_module(library(clpfd)).

hailstone_(1,1).

hailstone(N,S):-
    hailstone_(N,S),
    !.
hailstone(N,S):-
    0 #= mod(N,2),
    N1 #= div(N,2),
    hailstone(N1,S1),
    S #= S1 + 1,
    assert(hailstone_(N,S)).
hailstone(N,S):-
    1 #= mod(N,2),
    N1 #= 3 * N + 1,
    hailstone(N1,S1),
    S #= S1 + 1,
    assert(hailstone_(N,S)).

Some quick testing showed that I was getting correct results.

?- hailstone(12,X).
X = 10.

?- hailstone(19,X).
X = 21.

?- hailstone(27,X).
X = 112.

I then went looking around the web to see if I could improve my implementation and found an example on Rosetta Code that generated the list of hailstone values while working through the equation instead of just the length.

I modified my code and then tested the memoization version vs the non-memoization version

:- use_module(library(clpfd)).

hailstone1(1,[1]) :- !.
hailstone1(N,[N|S]) :- 
    0 is N mod 2,
    N1 is N / 2,
    hailstone1(N1,S).
hailstone1(N,[N|S]) :-
    1 is N mod 2,
    N1 is (3 * N) + 1,
    hailstone1(N1, S).

% memoization version
hailstone2_(1,[1]).

hailstone2(N,S) :-
    hailstone2_(N,S),
    !.
hailstone2(N,[N|S]) :- 
    0 is N mod 2,
    N1 is N / 2,
    hailstone2(N1,S),
    assert(hailstone2_(N,[N|S])).
hailstone2(N,[N|S]) :-
    1 is N mod 2,
    N1 is (3 * N) + 1,
    hailstone2(N1, S),
    assert(hailstone2_(N,[N|S])).

longestHailstoneSequence1(M, Seq, Len) :-
    longesthailstone1(M, 1, 1, Seq, Len).

longesthailstone1(1, Cn, Cl, Mn, Ml):-
    Mn = Cn,
	  Ml = Cl.
longesthailstone1(N, _, Cl, Mn, Ml) :-
    hailstone1(N, X),
    length(X, L),
    Cl < L,
    N1 is N-1,
    longesthailstone1(N1, N, L, Mn, Ml).
longesthailstone1(N, Cn, Cl, Mn, Ml) :-
    N1 is N-1,
    longesthailstone1(N1, Cn, Cl, Mn, Ml).

longestHailstoneSequence2(M, Seq, Len) :-
    longesthailstone2(M, 1, 1, Seq, Len).

longesthailstone2(1, Cn, Cl, Mn, Ml):-
    Mn = Cn,
    Ml = Cl.
longesthailstone2(N, _, Cl, Mn, Ml) :-
    hailstone2(N, X),
    length(X, L),
    Cl < L,
    N1 is N-1,
    longesthailstone2(N1, N, L, Mn, Ml).
longesthailstone2(N, Cn, Cl, Mn, Ml) :-
    N1 is N-1,
    longesthailstone2(N1, Cn, Cl, Mn, Ml).


main(Max,LongestHailstone1,Hailstone1,LongestHailstone2,Hailstone2):-
    get_time(T1),
    longestHailstoneSequence1(Max,_,LongestHailstone1),
    get_time(T2),
    longestHailstoneSequence2(Max,_,LongestHailstone2),
    get_time(T3),
    Hailstone1 is T2 - T1,
    Hailstone2 is T3 - T2.

I tested both versions to find the longest length less than 1,000,000.

?- main(1000000,RegularLength,RegularTime,MemoizedLength,MemoizedTime).
RegularLength = MemoizedLength, MemoizedLength = 525,
RegularTime = 45.83147144317627,
MemoizedTime = 13.176789045333862 .

And loo.king at the results it seems that memoization sped up the calculation by around a factor of 3. Running the calculation again gives further evidence to the time saved through memoization techniques.

?- main(1000000,RegularLength,RegularTime,MemoizedLength,MemoizedTime).
RegularLength = MemoizedLength, MemoizedLength = 525,
RegularTime = 45.660714626312256,
MemoizedTime = 1.4994690418243408 .

Running main again with a smaller value also gives us a chance to look at how Prolog is storing the values.

?- main(25,RegularLength,RegularTime,MemoizedLength,MemoizedTime).
RegularLength = MemoizedLength, MemoizedLength = 24,
RegularTime = 0.0004966259002685547,
MemoizedTime = 0.00028586387634277344 .

?- listing.

hailstone2_(1, [1]).
hailstone2_(2, [2, 1]).
hailstone2_(4, [4, 2, 1]).
hailstone2_(8, [8, 4, 2, 1]).
hailstone2_(16, [16, 8, 4, 2, 1]).
hailstone2_(5, [5, 16, 8, 4, 2, 1]).
hailstone2_(10, [10, 5, 16, 8, 4, 2, 1]).
hailstone2_(20, [20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(40, [40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(13, [13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(26, [26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(52, [52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(17, [17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(34, [34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(11, [11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(22, [22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(44, [44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(88, [88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(29, [29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(58, [58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(19, [19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(38, [38, 19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(76, [76, 38, 19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(25, [25, 76, 38, 19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(3, [3, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(6, [6, 3, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(12, [12, 6, 3, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(24, [24, 12, 6, 3, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(80, [80, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(160, [160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(53, [53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(106, [106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(35, [35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(70, [70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(23, [23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(32, [32, 16, 8, 4, 2, 1]).
hailstone2_(64, [64, 32, 16, 8, 4, 2, 1]).
hailstone2_(21, [21, 64, 32, 16, 8, 4, 2, 1]).
hailstone2_(7, [7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(14, [14, 7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(28, [28, 14, 7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(9, [9, 28, 14, 7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(18, [18, 9, 28, 14, 7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(46, [46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1]).
hailstone2_(15, [15, 46, 23, 70, 35, 106, 53, 160, 80, 40, 20, 10, 5, 16, 8, 4, 2, 1]).

Ackermann

I started with the code from Rosetta Code and modified it to have a memoization version as I did for the Hailstone program.

:- use_module(library(clpfd)).

ack1(0, N, Ans) :-
    Ans is N+1.
ack1(M, 0, Ans) :-
    M>0, X is M-1,
    ack1(X, 1, Ans).
ack1(M, N, Ans) :-
    M>0,
    N>0,
    X is M-1,
    Y is N-1,
    ack1(M, Y, Ans2),
    ack1(X, Ans2, Ans).

% memoization version
ack2_(0,0,1).
ack2_(0,1,2).
ack2_(1,0,2).
ack2_(1,1,3).

ack2(0, N, Ans) :-
    Ans #= N+1,
    assert(ack2_(0,N,Ans)).
ack2(M, 0, Ans) :-
    M>0,
    X is M-1,
    ack2(X, 1, Ans),
    assert(ack2_(M, 0, Ans)).
ack2(M, N, Ans) :-
    M>0,
    N>0,
    X is M-1,
    Y is N-1,
    ack2(M, Y, Ans2),
    ack2(X, Ans2, Ans),
    assert(ack2_(M, N, Ans)).

main(M, N, Ack1, Ack2):-
    get_time(T1),
    ack1(M, N, _Ans1),
    get_time(T2),
    ack2(M, N, _Ans2),
    get_time(T3),
    Ack1 is T2 - T1,
    Ack2 is T3 - T2.

Since I know that Ackermann will blow up in size quickly I tried calculating some small values of Ackermann to start with to compare the times.

?- main(1,1,Ack1,Ack2).
Ack1 = 1.0013580322265625e-5,
Ack2 = 2.2411346435546875e-5 .

?- main(1,1,Ack1,Ack2).
Ack1 = 1.0013580322265625e-5,
Ack2 = 2.2411346435546875e-5 .

?- main(3,2,Ack1,Ack2).
Ack1 = 0.0004432201385498047,
Ack2 = 0.0014376640319824219 .

?- main(3,3,Ack1,Ack2).
Ack1 = 0.0027358531951904297,
Ack2 = 0.004640340805053711 .

?- main(3,4,Ack1,Ack2).
Ack1 = 0.02543926239013672,
Ack2 = 0.1792759895324707 .

?- main(3,5,Ack1,Ack2).
Ack1 = 0.23902654647827148,
Ack2 = 3.0773415565490723 .

Initially I figured that the memoization was taking up to much overhead for these small values however, after reading responses to a stackoverflow thread I found that this function is so ill behaved that memoization doesn’t really help with the calculations.

Example

To give show how quickly this problem gets out of hand. If I call listing before I have actually run ack2 I get the following result.

?- listing.

ack2_(0, 0, 1).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(1, 1, 3).

Running Ackermann with 2,1 blows the result up to this.

?- main(2,1,Ack1,Ack2).
Ack1 = 1.6450881958007812e-5,
Ack2 = 6.270408630371094e-5 .

?- listing.

ack2_(0, 0, 1).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(1, 1, 3).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(2, 0, 3).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(2, 1, 5).

Ackermann 2,2 results in the following blow up again.

?- main(2,2,Ack1,Ack2).
Ack1 = 4.363059997558594e-5,
Ack2 = 5.53131103515625e-5 .

?- listing.
ack2_(0, 0, 1).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(1, 1, 3).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(2, 0, 3).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(2, 1, 5).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(2, 0, 3).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(2, 1, 5).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(2, 2, 7).

So we went from 18 memoized results to 45 by increasing N by 1.

Going to 3,2 increases the results to 585. Unlike the Fibonacci and Hailstone formulas, Ackermann doesn’t seem to spend a lot of time recalculating old values. Instead it is expanding to calculate new values with each increase of M and N.

I have included ack2(3,2) saved results below, the jump to ack2(3,3) would be similar.

?- main(3,2,Ack1,Ack2).
Ack1 = 0.0006780624389648438,
Ack2 = 0.00354766845703125 .

?- listing.
ack2_(0, 0, 1).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(1, 1, 3).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(2, 0, 3).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(2, 1, 5).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(2, 0, 3).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(2, 1, 5).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(2, 2, 7).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(2, 0, 3).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(2, 1, 5).
ack2_(3, 0, 5).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(2, 0, 3).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(2, 1, 5).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(2, 2, 7).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(0, 7, 8).
ack2_(1, 6, 8).
ack2_(0, 8, 9).
ack2_(1, 7, 9).
ack2_(2, 3, 9).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(0, 7, 8).
ack2_(1, 6, 8).
ack2_(0, 8, 9).
ack2_(1, 7, 9).
ack2_(0, 9, 10).
ack2_(1, 8, 10).
ack2_(0, 10, 11).
ack2_(1, 9, 11).
ack2_(2, 4, 11).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(0, 7, 8).
ack2_(1, 6, 8).
ack2_(0, 8, 9).
ack2_(1, 7, 9).
ack2_(0, 9, 10).
ack2_(1, 8, 10).
ack2_(0, 10, 11).
ack2_(1, 9, 11).
ack2_(0, 11, 12).
ack2_(1, 10, 12).
ack2_(0, 12, 13).
ack2_(1, 11, 13).
ack2_(2, 5, 13).
ack2_(3, 1, 13).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(2, 0, 3).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(2, 1, 5).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(2, 2, 7).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(0, 7, 8).
ack2_(1, 6, 8).
ack2_(0, 8, 9).
ack2_(1, 7, 9).
ack2_(2, 3, 9).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(0, 7, 8).
ack2_(1, 6, 8).
ack2_(0, 8, 9).
ack2_(1, 7, 9).
ack2_(0, 9, 10).
ack2_(1, 8, 10).
ack2_(0, 10, 11).
ack2_(1, 9, 11).
ack2_(2, 4, 11).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(0, 7, 8).
ack2_(1, 6, 8).
ack2_(0, 8, 9).
ack2_(1, 7, 9).
ack2_(0, 9, 10).
ack2_(1, 8, 10).
ack2_(0, 10, 11).
ack2_(1, 9, 11).
ack2_(0, 11, 12).
ack2_(1, 10, 12).
ack2_(0, 12, 13).
ack2_(1, 11, 13).
ack2_(2, 5, 13).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(0, 7, 8).
ack2_(1, 6, 8).
ack2_(0, 8, 9).
ack2_(1, 7, 9).
ack2_(0, 9, 10).
ack2_(1, 8, 10).
ack2_(0, 10, 11).
ack2_(1, 9, 11).
ack2_(0, 11, 12).
ack2_(1, 10, 12).
ack2_(0, 12, 13).
ack2_(1, 11, 13).
ack2_(0, 13, 14).
ack2_(1, 12, 14).
ack2_(0, 14, 15).
ack2_(1, 13, 15).
ack2_(2, 6, 15).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(0, 7, 8).
ack2_(1, 6, 8).
ack2_(0, 8, 9).
ack2_(1, 7, 9).
ack2_(0, 9, 10).
ack2_(1, 8, 10).
ack2_(0, 10, 11).
ack2_(1, 9, 11).
ack2_(0, 11, 12).
ack2_(1, 10, 12).
ack2_(0, 12, 13).
ack2_(1, 11, 13).
ack2_(0, 13, 14).
ack2_(1, 12, 14).
ack2_(0, 14, 15).
ack2_(1, 13, 15).
ack2_(0, 15, 16).
ack2_(1, 14, 16).
ack2_(0, 16, 17).
ack2_(1, 15, 17).
ack2_(2, 7, 17).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(0, 7, 8).
ack2_(1, 6, 8).
ack2_(0, 8, 9).
ack2_(1, 7, 9).
ack2_(0, 9, 10).
ack2_(1, 8, 10).
ack2_(0, 10, 11).
ack2_(1, 9, 11).
ack2_(0, 11, 12).
ack2_(1, 10, 12).
ack2_(0, 12, 13).
ack2_(1, 11, 13).
ack2_(0, 13, 14).
ack2_(1, 12, 14).
ack2_(0, 14, 15).
ack2_(1, 13, 15).
ack2_(0, 15, 16).
ack2_(1, 14, 16).
ack2_(0, 16, 17).
ack2_(1, 15, 17).
ack2_(0, 17, 18).
ack2_(1, 16, 18).
ack2_(0, 18, 19).
ack2_(1, 17, 19).
ack2_(2, 8, 19).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(0, 7, 8).
ack2_(1, 6, 8).
ack2_(0, 8, 9).
ack2_(1, 7, 9).
ack2_(0, 9, 10).
ack2_(1, 8, 10).
ack2_(0, 10, 11).
ack2_(1, 9, 11).
ack2_(0, 11, 12).
ack2_(1, 10, 12).
ack2_(0, 12, 13).
ack2_(1, 11, 13).
ack2_(0, 13, 14).
ack2_(1, 12, 14).
ack2_(0, 14, 15).
ack2_(1, 13, 15).
ack2_(0, 15, 16).
ack2_(1, 14, 16).
ack2_(0, 16, 17).
ack2_(1, 15, 17).
ack2_(0, 17, 18).
ack2_(1, 16, 18).
ack2_(0, 18, 19).
ack2_(1, 17, 19).
ack2_(0, 19, 20).
ack2_(1, 18, 20).
ack2_(0, 20, 21).
ack2_(1, 19, 21).
ack2_(2, 9, 21).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(0, 7, 8).
ack2_(1, 6, 8).
ack2_(0, 8, 9).
ack2_(1, 7, 9).
ack2_(0, 9, 10).
ack2_(1, 8, 10).
ack2_(0, 10, 11).
ack2_(1, 9, 11).
ack2_(0, 11, 12).
ack2_(1, 10, 12).
ack2_(0, 12, 13).
ack2_(1, 11, 13).
ack2_(0, 13, 14).
ack2_(1, 12, 14).
ack2_(0, 14, 15).
ack2_(1, 13, 15).
ack2_(0, 15, 16).
ack2_(1, 14, 16).
ack2_(0, 16, 17).
ack2_(1, 15, 17).
ack2_(0, 17, 18).
ack2_(1, 16, 18).
ack2_(0, 18, 19).
ack2_(1, 17, 19).
ack2_(0, 19, 20).
ack2_(1, 18, 20).
ack2_(0, 20, 21).
ack2_(1, 19, 21).
ack2_(0, 21, 22).
ack2_(1, 20, 22).
ack2_(0, 22, 23).
ack2_(1, 21, 23).
ack2_(2, 10, 23).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(0, 7, 8).
ack2_(1, 6, 8).
ack2_(0, 8, 9).
ack2_(1, 7, 9).
ack2_(0, 9, 10).
ack2_(1, 8, 10).
ack2_(0, 10, 11).
ack2_(1, 9, 11).
ack2_(0, 11, 12).
ack2_(1, 10, 12).
ack2_(0, 12, 13).
ack2_(1, 11, 13).
ack2_(0, 13, 14).
ack2_(1, 12, 14).
ack2_(0, 14, 15).
ack2_(1, 13, 15).
ack2_(0, 15, 16).
ack2_(1, 14, 16).
ack2_(0, 16, 17).
ack2_(1, 15, 17).
ack2_(0, 17, 18).
ack2_(1, 16, 18).
ack2_(0, 18, 19).
ack2_(1, 17, 19).
ack2_(0, 19, 20).
ack2_(1, 18, 20).
ack2_(0, 20, 21).
ack2_(1, 19, 21).
ack2_(0, 21, 22).
ack2_(1, 20, 22).
ack2_(0, 22, 23).
ack2_(1, 21, 23).
ack2_(0, 23, 24).
ack2_(1, 22, 24).
ack2_(0, 24, 25).
ack2_(1, 23, 25).
ack2_(2, 11, 25).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(0, 7, 8).
ack2_(1, 6, 8).
ack2_(0, 8, 9).
ack2_(1, 7, 9).
ack2_(0, 9, 10).
ack2_(1, 8, 10).
ack2_(0, 10, 11).
ack2_(1, 9, 11).
ack2_(0, 11, 12).
ack2_(1, 10, 12).
ack2_(0, 12, 13).
ack2_(1, 11, 13).
ack2_(0, 13, 14).
ack2_(1, 12, 14).
ack2_(0, 14, 15).
ack2_(1, 13, 15).
ack2_(0, 15, 16).
ack2_(1, 14, 16).
ack2_(0, 16, 17).
ack2_(1, 15, 17).
ack2_(0, 17, 18).
ack2_(1, 16, 18).
ack2_(0, 18, 19).
ack2_(1, 17, 19).
ack2_(0, 19, 20).
ack2_(1, 18, 20).
ack2_(0, 20, 21).
ack2_(1, 19, 21).
ack2_(0, 21, 22).
ack2_(1, 20, 22).
ack2_(0, 22, 23).
ack2_(1, 21, 23).
ack2_(0, 23, 24).
ack2_(1, 22, 24).
ack2_(0, 24, 25).
ack2_(1, 23, 25).
ack2_(0, 25, 26).
ack2_(1, 24, 26).
ack2_(0, 26, 27).
ack2_(1, 25, 27).
ack2_(2, 12, 27).
ack2_(0, 1, 2).
ack2_(1, 0, 2).
ack2_(0, 2, 3).
ack2_(1, 1, 3).
ack2_(0, 3, 4).
ack2_(1, 2, 4).
ack2_(0, 4, 5).
ack2_(1, 3, 5).
ack2_(0, 5, 6).
ack2_(1, 4, 6).
ack2_(0, 6, 7).
ack2_(1, 5, 7).
ack2_(0, 7, 8).
ack2_(1, 6, 8).
ack2_(0, 8, 9).
ack2_(1, 7, 9).
ack2_(0, 9, 10).
ack2_(1, 8, 10).
ack2_(0, 10, 11).
ack2_(1, 9, 11).
ack2_(0, 11, 12).
ack2_(1, 10, 12).
ack2_(0, 12, 13).
ack2_(1, 11, 13).
ack2_(0, 13, 14).
ack2_(1, 12, 14).
ack2_(0, 14, 15).
ack2_(1, 13, 15).
ack2_(0, 15, 16).
ack2_(1, 14, 16).
ack2_(0, 16, 17).
ack2_(1, 15, 17).
ack2_(0, 17, 18).
ack2_(1, 16, 18).
ack2_(0, 18, 19).
ack2_(1, 17, 19).
ack2_(0, 19, 20).
ack2_(1, 18, 20).
ack2_(0, 20, 21).
ack2_(1, 19, 21).
ack2_(0, 21, 22).
ack2_(1, 20, 22).
ack2_(0, 22, 23).
ack2_(1, 21, 23).
ack2_(0, 23, 24).
ack2_(1, 22, 24).
ack2_(0, 24, 25).
ack2_(1, 23, 25).
ack2_(0, 25, 26).
ack2_(1, 24, 26).
ack2_(0, 26, 27).
ack2_(1, 25, 27).
ack2_(0, 27, 28).
ack2_(1, 26, 28).
ack2_(0, 28, 29).
ack2_(1, 27, 29).
ack2_(2, 13, 29).
ack2_(3, 2, 29).