Fill a multidimensional array efficiently, which has a lot if else

I want to populate a 4dim numpy array in a specific and efficient way. Since I don’t know better, I start writing code with if else, but it doesn’t look very good, maybe slower, and I also can’t be sure if I thought about each combination. Here is the code that I stopped writing:

sercnew2 = numpy.zeros((gn, gn, gn, gn))
for x1 in range(gn):
    for x2 in range(gn):
        for x3 in range(gn):
            for x4 in range(gn):
                if x1 == x2 == x3 == x4: 
                    sercnew2[x1, x2, x3, x4] = ewp[x1]
                elif x1 == x2 == x3 != x4:
                    sercnew2[x1, x2, x3, x4] = ewp[x1] * ewp[x4]
                elif x1 == x2 == x4 != x3:
                    sercnew2[x1, x2, x3, x4] = ewp[x1] * ewp[x3]
                elif x1 == x3 == x4 != x2:
                    sercnew2[x1, x2, x3, x4] = ewp[x1] * ewp[x2]
                elif x2 == x3 == x4 != x1:
                    sercnew2[x1, x2, x3, x4] = ewp[x2] * ewp[x1]
                elif x1 == x2 != x3 == x4:
                    sercnew2[x1, x2, x3, x4] = ewp[x1] * ewp[x3]
                elif ... many more combinations which have to be considered

So, basically, what should happen if all the variables (x1, x2, x3, x4) are different from each other, the record will be as follows:

sercnew2[x1, x2, x3, x4] = ewp[x1]* ewp[x2] * ewp[x3] * ewp[x4]

Now, if we say that the variables x2 and x4 are the same:

sercnew2[x1, x2, x3, x4] = ewp[x1]* ewp[x2] * ewp[x3]

. , , . , . , , , . , . , .

+4
3

, ! -

from itertools import product

n_dims = 4 # Number of dims

# Create 2D array of all possible combinations of X as rows
idx = np.sort(np.array(list(product(np.arange(gn), repeat=n_dims))),axis=1)

# Get all X indexed values from ewp array
vals = ewp[idx]

# Set the duplicates along each row as 1s. With the np.prod coming up next,
#these 1s would not affect the result, which is the expected pattern here.
vals[:,1:][idx[:,1:] == idx[:,:-1]] = 1

# Perform product along each row and reshape into multi-dim array
out = vals.prod(1).reshape([gn]*n_dims)
+3

, , , , , , , set().

from functools import reduce
from operator import mul
sercnew2 = numpy.zeros((gn, gn, gn, gn))
for x1 in range(gn):
    for x2 in range(x1, gn):
        for x3 in range(x2, gn):
            for x4 in range(x3, gn):
                set_ = [ewp[n] for n in set([x1, x2, x3, x4])]
                sercnew2[x1, x2, x3, x4] = reduce(mul, set_, 1)

, set(), , reduce set_, 1 ( ) reduce , set_. .

+3

. Divakar Trick , , , , 4d- sercnew2.

(. https://www.peterbe.com/plog/uniqifiers-benchmark) . sercnew2 , .

from itertools import product
import numpy as np

sercnew2 = np.ones((gn, gn, gn, gn))
n_dims=4
idx = list(product(np.arange(gn), repeat=n_dims))

for i,j,k,l in idx:
    unique_items = set((i,j,k,l))
    for ele in unique_items:
        sercnew2[i,j,k,l] *= ewp[ele]

EDIT: as suggested by @unutbu, we could also use the cartesian_product function from fooobar.com/questions/64380 / ... to speed up initializationidx

Edit2: If you are having difficulty understanding what it is doing productfrom itertools, it provides all permutations. For example, suppose the gn=2repetition size is 4, you get

[0, 0, 0, 0]
[0, 0, 0, 1]
[0, 0, 1, 0]
[0, 0, 1, 1]
[0, 1, 0, 0]
[0, 1, 0, 1]
[0, 1, 1, 0]
[0, 1, 1, 1]
[1, 0, 0, 0]
[1, 0, 0, 1]
[1, 0, 1, 0]
[1, 0, 1, 1]
[1, 1, 0, 0]
[1, 1, 0, 1]
[1, 1, 1, 0]
[1, 1, 1, 1]
+2
source

Source: https://habr.com/ru/post/1657873/


All Articles