#
# Computations on the 3n+1 conjecture
#
#	(or Collatz problem, or Ulam's conjecture or Hasse's algorithm
#	 or the Syracuse problem or .... )
#
# Define for integer n, f(1) = 1, f(n) = n/2 for even n, f(n) = (3*n+1)/2 for odd n.
# The 3n+1 conjecture is whether f(n) goes to 1 for all integer n > 0
# The routine DistTo1 computes in an efficient way, the number of itations it takes
# for n to go to 1 with DistTo(1) defined to be 0.
#
#			Gaston H. Gonnet.
#
# DistTo1: compute how many iterations it will take to
#	reduce the argument to 1
#

alias( CollatzMod = `Collatz/mod`, pow2 = `Collatz/pow2` ):
DistTo1 := proc(n:posint) local its, t, qt, u, rt, bits;
    its := 0;
    t := n;
    do
        if t < 10 then RETURN( op(t,[0,1,7,2,5,8,16,3,19,6]) + its ) fi;
        bits := 3;
        while 2*length(pow2(bits)) < length(t) do bits := 2*bits od;
        qt := iquo(t,pow2(bits),'rt');
        u := CollatzMod(rt,bits);
        its := its+u[2]+bits;
        t := qt*3^u[2]+u[1];
    od;
end:
#
# Compute the iteration mod 2^b
#
CollatzMod := proc(r,b)
local b2, q1, q2, u1, u2, res;
    b2 := iquo(b,2);
    u1 := CollatzMod(irem(r,pow2(b2),'q1'),b2);
    u2 := CollatzMod(irem(q1*3^u1[2]+u1[1],pow2(b2),'q2'),b2);
    res := [q2*3^u2[2]+u2[1], u1[2]+u2[2]];
    if b <= 12 then CollatzMod(args) := res fi;
    res
end:
CollatzMod(0,1) := [0,0]:  CollatzMod(1,1) := [2,1]:
CollatzMod(0,2) := [0,0]:  CollatzMod(1,2) := [1,1]:
CollatzMod(2,2) := [2,1]:  CollatzMod(3,2) := [8,2]:
CollatzMod(0,3) := [0,0]:  CollatzMod(1,3) := [2,2]:
CollatzMod(2,3) := [1,1]:  CollatzMod(3,3) := [4,2]:
CollatzMod(4,3) := [2,1]:  CollatzMod(5,3) := [2,1]:
CollatzMod(6,3) := [8,2]:  CollatzMod(7,3) := [26,3]:
#
pow2 := proc(b) option remember;
if b <= 24 then 2^b else pow2(b/2)^2 fi end:
#
# Iterate(x,n) perform n iterations on the initial value
#	x and return the resulting value
#
Iterate := proc( x:posint, n:posint )
local bits, qt, rn, rt, rx, u;
    rn := n;  rx := x;
    while rn > 0 do
        if rx=1 then RETURN( op( modp(rn,3)+1, [1,4,2] ) )
        elif rx=2 then RETURN( op( modp(rn,3)+1, [2,1,4] ) )
        elif rx=4 then RETURN( op( modp(rn,3)+1, [4,2,1] ) )
        elif rn < 6 then
             if irem(rx,2,'qt')=1 then rx := 3*rx+1 else rx := qt fi;
             rn := rn-1
        else bits := 3;
             while 2*length(pow2(bits)) < length(t) and 4*bits < rn
                 do bits := 2*bits od; 
             qt := iquo(rx,pow2(bits),'rt');
             u := CollatzMod(rt,bits);
             rn := rn-u[2]-bits;
             rx := qt*3^u[2]+u[1];
             fi
        od;
    rx
end:
alias( CollatzMod = CollatzMod, pow2 = pow2 ):

#save `Collatz.m`;
#quit
