Search code examples
javacollatz

How to Generate the Collatz tree in Java?


I'm hopelessly trying to generate trhough an infinite loop all the numbers in the collatz sequence. The program should start by one and print all the possible collatz,until the user stops, or we get an memory overflow.So we has to be an inverse collatz function. The logic would be something like this:(If n is even duplicate it,if n/3 is an integer, we do the inverse operation,the odd number operation.)

import java.math.BigInteger;

public class InverseColatz {
    public static void main(String args[]) throws InterruptedException{
        BigInteger n = BigInteger.valueOf(2);
        System.out.println(1);
        while(true){
            if(n.mod(BigInteger.valueOf(3)).equals(BigInteger.ZERO)){
                n = n.divide(BigInteger.valueOf(3));
                n = n.subtract(BigInteger.ONE);
                System.out.println(n);
               Thread.sleep(500);
            }
            if(n.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
                n = n.multiply(BigInteger.valueOf(2));
                System.out.println(n);
                Thread.sleep(500);
            }
        } 
    }
}

The problem is I'm just generating the even numbers sequences(n*2),but I'm not being able to generate the odd numbers((n/3)-1) because this code never reach the odd number condition,because all the numbers that are being generated does not match the first condition.Can someone please give me some enlightenment? Thanks in advance.


Solution

  • First off, excuse my formatting, I cannot use images to show equations because this is my first post.

    Let's start by taking a look at the Collatz Conjecture. We know that the series involved is referred to as the Halestone Series in reference to the behavior of all numbers 2n where n is a positive whole number. The series is defined by recursively modifying the value based on whether the value is odd or even.

    • If the number is even, divide it by two.
    • If the number is odd, triple it and add one.

    To reverse this process there are potentially two outcomes for one number. For example, both 5 and 32 evaluate to 16.

    • 5 is odd, (3 * 5) + 1 = 16
    • 32 is even, 32 / 2 = 16

    To find the inverse function, we need to take into account that there can be two answers for every number. We also need to define what a valid answer is. A valid answer from the inverse function must be a positive, whole number.

    Now we do some algebra to arrive at the inverses. Define a as the resultant of one iteration of the Halestone series.

    Solve for n :
                        
        3n + 1 = a        2 = a

            a̲ ̲-̲ ̲1̲
        n =  3           n = 2a

    So now we have our new rules. We know for a fact that n = 2a will always evaluate to a positive integer, so this expression is always true. However, the other equation only evaluates to a positive integer if a - 1 is divisible by 3. Every other instance is not going to return a whole integer, but rather be trailed by an infinite number of threes or sixes. These decimal numbers are unacceptable and will be thrown out. Notice how the input value of 4 returns 1 as one of the answers

    To start thinking about the code, we should break down the proposed tree into layers. Similar to the horizontal layering of this image. For every iteration, every branch has the potential to break off into two separate branches. This means that we need to store an unknown amount of numbers as we iterate up the tree.

    This is what I came up with. Essentially it's still just a stream of data that needs to be formatted into something readable. It should fail when either the stack size is used up or if the number of concurrent branches exceeds 231 - 1. This is due to the nature of arrays.

    public static void main(String args[]) throws InterruptedException {
        ArrayList<BigInteger> tree = new ArrayList<BigInteger>();
        tree.add(BigInteger.valueOf(2));
        System.out.println(1);
        while (true) {
            // Store a snapshot of the current tree so new branches created don't mess with
            // the iteration process.
            BigInteger[] originalTree = tree.toArray(new BigInteger[tree.size()]);
    
            // Keep track of new branches added during each step for index alignment in
            // the stepping method.
            int newBranchCount = 0;
    
            // Iterate over the values of the original tree.
            for(int i = 0; i < originalTree.length; i++) {
                // Evaluate branch
                stepBranch(tree, originalTree[i], i + newBranchCount);
    
                // Update branch count after step.
                newBranchCount = tree.size() - originalTree.length;
            }
        }
    }
    
    /*
     * Given the tree to mutate, a value from a mutation free version of the tree,
     * and the current working index of the tree:
     * Evaluate whether or not to add a new odd valued branch and report new value(s).
    */
    public static void stepBranch(ArrayList<BigInteger> tree, BigInteger branch, int index) throws InterruptedException {
    
        // If (n + 1) is divisible by three, do so and create a new branch to store the new value
        if (branch.subtract(BigInteger.ONE).mod(BigInteger.valueOf(3)).equals(BigInteger.ZERO)) {
    
            // If the input is 4, the output is 1 which appears earlier, therefore requires no attention.
            if(!branch.equals(BigInteger.valueOf(4))) {
                // Create new value. 
                BigInteger odd = branch.subtract(BigInteger.ONE).divide(BigInteger.valueOf(3));
    
                // If the output is even, it doesn't fit the requirements for an odd cell.
                if(!odd.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) {
                    tree.add(index + 1, odd);
                    System.out.println(tree.get(index + 1));
                }
            } else {
                System.out.println(1);
            }
            Thread.sleep(500);
        }
    
        // The original branch, not considering a new branch if one was created, is
        // multiplied by 2 so as to check for a new odd node in the next iteration.
        tree.set(index, branch.multiply(BigInteger.valueOf(2)));
        System.out.println(tree.get(index));
        Thread.sleep(500);
    }
    

    Hope this helped!