5

Consider the following function for calculating the number of steps for a given input to the 3 n + 1 problem:

def num_steps(b, steps):
    e = b
    d = 0
    while True:
        if e == 1:
            d += steps[e]
            return d
        if e % 2 == 0:
            e //= 2
        else:
            e = 3*e + 1
        d += 1

Here, steps exists to allow for memoization of the result, but for the sake of this question, we just note that as long as steps[1] == 0, it should have no effect, since in that case, the effect of d += steps[e] is to add 0 to d. Indeed, the following example gives the expected result:

import numpy as np

steps = np.array([0, 0, 0, 0])
print(num_steps(3, steps))  # Prints 7

If, however, we JIT compile the method using numba.jit (or njit), we no longer get the right result:

import numpy as np
from numba import jit

steps = np.array([0, 0, 0, 0])
print(jit(num_steps)(3, steps))  # Prints 0

If we remove the seemingly-redundant d += steps[e] before compiling the method, we do get the right result, though. We could even put in a print(steps[e]) prior to d += steps[e] and see that the value is 0. I can also move the d += 1 to the top of the loop (and initialize d = -1 instead) to get something that also works in the Numba case.

This happens with Numba 0.48.0 (llvmlite 0.31.0) on Python 3.8 (the most recent versions available through the standard conda channel).

fuglede
  • 17,388
  • 2
  • 54
  • 99
  • @MrFuppes: Thanks, if I pin Python version to 3.7 with conda (which downgrades Numba to 0.47.0), I still run into the same issue. – fuglede Feb 17 '20 at 11:13
  • 3
    sorry, didn't check my numba version before I wrote the initial comment - can reproduce the invalid result also with Python 3.7 (numba 0.48, llvmlite 0.31)! *However*, if I switch to numba 0.46 / llvmlite 0.30 on Python 3.7, the njitted code works fine. – FObersteiner Feb 17 '20 at 11:13
  • 1
    @MrFuppes: Thanks, I can confirm that downgrading to numba 0.46 / llvmlite 0.30 resolves the issue. – fuglede Feb 17 '20 at 11:16
  • 1
    [GitHub issue for reference](https://github.com/numba/numba/issues/5273). – fuglede Feb 18 '20 at 14:45

1 Answers1

2

It looks like a bug to me, something with the in-place increment with steps[e]. If you set parallel=True that's where Numba crashes. You could create an issue at the Numba github repo, perhaps the developers can explain it.

If I rewrite the function to avoid that final in-place increment it works for me:

@numba.njit
def numb_steps(b, steps):

    e = b    
    d = 0

    while True:

        if e == 1:
            return d + steps[e]

        if e % 2 == 0:
            e //= 2
        else:
            e = 3*e + 1

        d += 1

With:

python                    3.7.6
numba                     0.47.0
Rutger Kassies
  • 61,630
  • 17
  • 112
  • 97