Maple Sequence Length

455 views Asked by At

I'm trying to create a basic program in Maple that runs the Collatz sequence when given a number (n) from the user. For those that don't know, the Collatz sequence is basically "If the number given is odd, do 3n + 1, if it is even, divide by 2 and continue to do so for every answer. Eventually, the answer will reach 1" I'm trying to grab the number of iterations that the sequence is performed, say if the sequence is run through 10 times, it prints that out. Here is my current code:

Collatz := proc (n::posint) 
if type(n, even) then (1/2)*n 
else 3*n+1 
end if 
end proc

CollSeq := proc (n::posint) 
local i; 
i := n; 
while 1 < i do 
lprint(i); 
i := Collatz(i) 
end do 
end proc

This so far works, and if the proc CollSeq(50) is entered, it will perform the Collatz sequence on 50 until it reaches 1. The bit I am stuck on is the length of the sequence. I have read around and learned that I might be able to use the nops([]) function of Maple to get the length of the sequence. Here is what I have tried:

CollLen := proc (n::posint) 
local c; 
c := CollSeq(n); 
print(nops([c])) 
end proc

I have a feeling this is horribly wrong. Any help would be much appreciated.

Many Thanks

2

There are 2 answers

0
DrC On BEST ANSWER

Your function fails to return the actual sequence of values. You need to accumulate it as you go through the loop.

CollSeq := proc (n::posint) 
    local i, s; 
    i := n; 
    s := i; 
    while 1 < i do
        lprint(i);
        i := Collatz(i);
        s := s, i;
    end do;
    s;
end proc
0
AmirHosein Sadeghimanesh On

The lprint() command just prints its argument to the terminal (showing it on screen), it DOES not save it in a list. And nops() or a better command numelems() counts the number of elements in a list! So putting nops around something that has lprint will not count the number of things. Instead of using lprint in your second function (procedure), define a list, or better than list, an array and in the lprint-line, use a command to append the new number to your growing collection. If you want to see these numbers, just print this collection. Now this time, your third function can have a meaning and it will work as you expected.

Here is the closest fix to your codes.

Collatz := proc( n :: posint ) 
    if type(n, even) then 
        return( n/2 ): 
    else
        return( 3*n+1 ): 
    end if: 
end proc:
CollSeq := proc ( n :: posint ) 
    local 
        i :: posint,
        c :: 'Array'( posint ): 
    i := n:
    c := Array([]): 
    while 1 < i do 
        ArrayTools:-Append( c, i ): 
        i := Collatz( i ): 
    end do:
    return( c ):
end proc:
CollLen := proc ( n :: posint ) 
    local c :: posint: 
    c := CollSeq( n ): 
    return( numelems( c ) ):
end proc:

Here is a screenshot of using them in a Maple worksheet. enter image description here

Why do I use an array and not a list? Because if you use a list which is immutable, each time you want to add an element to it, in fact it is defining a new list. It is not a memory efficient way, while array is mutable and your edits modifies the array itself. See the help pages on these in Maple.

And looking at your codes, it seems you have the same problem that some of my students in their first programming course usually have, return and print are not the same thing. If you really want a "print" action, that is fine, but you should not expect that the printed value be the output of the function unless you are using a return line inside the function that returns the same value of the print as well. For example you can have print(c): before return(c): in the second function above. So it both prints the sequence on the terminal and returns it to be used by another function or line of code.