1

Want to generate 2D array of (pseudo-)random numbers (at a large scale) using a chaotic map (here logistic map is used) in a optimized way.

My implementation:

def logisticmap(x_init, r, length):
    x = [r*x_init*(1-x_init)]
    for t in range(length):
       x.append(r*x[-1]*(1-x[-1]))
    return np.array(x)
x = logisticmap(0.2, 3.92, 250000)

I use this logic to create a 2D array by,

def gen_logistic(dim, initial, r):
    x = initial
    elements_size = dim * dim - 1
    for i in range(elements_size ):
        x.append(r*x[-1]*(1-x[-1]))
    return np.array(x).reshape(dim,dim)
import cProfile
cProfile.run('gen_logistic(1000,0.2,3.92)')
   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.382    0.382    0.611    0.611 559217765.py:6(gen_logistic)
        1    0.014    0.014    0.625    0.625 <string>:1(<module>)
        1    0.000    0.000    0.625    0.625 {built-in method builtins.exec}
        1    0.098    0.098    0.098    0.098 {built-in method numpy.array}
   999999    0.129    0.000    0.129    0.000 {method 'append' of 'list' objects}
        1    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}
        1    0.001    0.001    0.001    0.001 {method 'reshape' of 'numpy.ndarray' objects}

But it takes a decent time to generate them all. Is there any better implementation like using a vectorized version of something?

falamiw
  • 426
  • 4
  • 16
  • If for some reasons you specifically want these numbers to come from a logistic map, then you could use numba to speed things up roughly by a factor of 6. However, this gives you values that are uniformly distributed, so np.random.uniform would also do the trick and is 50 times faster. – lmielke Apr 23 '22 at 09:49

1 Answers1

1

I'm not aware of a vectorized way to do that, but you can try numba module and it's JIT (just its JIT compiler):

from numba import jit


@jit(nopython=True)
def gen_logistic2(dim, initial, r):
    x = [r * initial * (1 - initial)]
    elements_size = dim * dim - 1
    for i in range(elements_size):
        x.append(r * x[-1] * (1 - x[-1]))
    return np.array(x).reshape(dim, dim)

Benchmark:

from numba import jit
from timeit import timeit


def gen_logistic1(dim, initial, r):
    x = [r * initial * (1 - initial)]
    elements_size = dim * dim - 1
    for i in range(elements_size):
        x.append(r * x[-1] * (1 - x[-1]))
    return np.array(x).reshape(dim, dim)



@jit(nopython=True)
def gen_logistic2(dim, initial, r):
    x = [r * initial * (1 - initial)]
    elements_size = dim * dim - 1
    for i in range(elements_size):
        x.append(r * x[-1] * (1 - x[-1]))
    return np.array(x).reshape(dim, dim)


# "warm" the jit
gen_logistic2(1, 0.2, 3.92)

t1 = timeit(lambda: gen_logistic1(1000, 0.2, 3.92), number=1)
t2 = timeit(lambda: gen_logistic2(1000, 0.2, 3.92), number=1)

print(t1)
print(t2)

Prints on my computer (AMD 3700x/Python 3.9.7):

0.24606511206366122
0.007645457983016968

so ~35x speedup

Andrej Kesely
  • 168,389
  • 15
  • 48
  • 91
  • 1
    Nice(+1) @AndrejKesely. Thanks for your answer. Could you help me with [this optimization](https://stackoverflow.com/q/71969535/13355189) question also. – falamiw Apr 23 '22 at 15:16