loading...

The Collatz Sequence in J

petecorey profile image Pete Corey Originally published at petecorey.com on ・3 min read

I’ve been playing around quite a bit with the Collatz Conjecture after watching the latest Coding Train video on the subject. In an effort to keep my J muscles from atrophying, I decided to use the language to implement a Collatz sequence generator.

At its heart, the Collatz sequence is a conditional expression. If the current number is even, the next number in the sequence is the current number divided by two. If the current number is odd, the next number in the sequence is one plus the current number multiplied by three:

We can write each of these branches with some straight-forward J code. Our even case is simply the divide (%) verb bonded (&) to 2:


   even =: %&2

And our odd case is a “monadic noun fork” of 1 plus (+) 3 bonded (&) to multiply (*):


   odd =: 1 + 3&*

We can tie together those two verbs and use agenda (@.) to pick which one to call based on whether the argument is even:


   next =: even`odd@.pick

Our pick verb is testing for even numbers by checking if 1: equals (=) 2 bonded to the residue verb (|).


   pick =: 1:=2&|

We can test our next verb by running it against numbers with known next values. After 3, we’d expect 10, and after 10, we’d expect 5:


   next 3
10
   next 10
5

Fantastic!

J has an amazing verb, power (^:), that can be used to find the “limit” of a provided verb by continuously reapplying that verb to its result until a repeated result is encountered. If we pass power boxed infinity (<_) as an argument, it’ll build up a list of all the intermediate results.

This is exactly what we want. To construct our Collatz sequence, we’ll find the limit of next for a given input, like 12:


   next^:(<_) 12

But wait, there’s a problem! A loop exists in the Collatz sequences between 4, 2, and 1. When we call next on 1, we’ll receive 4. Calling next on 4 returns 2, and calling next on 2 returns 1. Our next verb never converges to a single value.

To get over this hurdle, we’ll write one last verb, collatz, that checks if the argument is 1 before applying next:


   collatz =: next`]@.(1&=)

Armed with this new, converging collatz verb, we can try finding our limit again:


   collatz^:(<_) 12
12 6 3 10 5 16 8 4 2 1

Success! We’ve successfully implemented a Collatz sequence generator using the J programming langauge. Just for fun, let’s plot the sequence starting with 1000:


   require 'plot'
   plot collatz^:(<_) 1000

Posted on by:

Discussion

markdown guide