Can this double-list understanding go straight to the array (is there an even more pythonic way?)

My goal is to write a function that performs multiplication modulo 2 of two arrays (multiplication = and, complement = xor). Here is the code that I have now. Any suggestions on how to improve this are gratefully received - in particular, should I / how can I understand that the list is understood in an array of the appropriate form?

import numpy as np import operator def m2mult(a,b): c = np.ndarray([reduce(operator.xor, np.logical_and(a[x,:],b[:,y])) for x in range(0,a.shape[0]) for y in range (0, b.shape[1])]) c.shape = (a.shape[0], b.shape[1]) return c 
+4
source share
2 answers

You should not do this at all:

 a = np.random.randint(0,2,(4,4)) b = np.random.randint(0,2,(4,4)) # Now note that this is true: # (I will let you figure that out, its a lot of neat broadcasting. # bT would be enough as well, because of it) np.multiply(a[:,None,:], bT[None,:,:]).sum(-1) == np.dot(a,b) # note also that .sum(-1) is the same as np.add.reduce(array, axis=-1) # now we can do the same thing for your logical operations: a = np.random.randint(0,2,(4,4)).astype(bool) b = np.random.randint(0,2,(4,4)).astype(bool) def m2mult(a, b): mult = np.logical_and(a[:,None,:], bT[None,:,:]) return np.logical_xor.reduce(mult, axis=-1) 

And its fully vectorized, much faster and just numpy!

+4
source

You can simply multiply the common matrix by int s and then reduce modulo-2 and then convert back to bool :

 np.mod(np.dot(a.astype('u1'), b), 2).astype('bool') 

It is faster than seberg solution and Jaime modification.

 +---------------+---------+-----------+----------+ | | 10x10 | 1000x1000 | 750x1250 | +---------------+---------+-----------+----------+ | m2mult_tz | 33 us | 7.27 s | 4.68 s | | m2mult_jaime | 56.7 us | 20.4 s | 14.2 s | | m2mult_seberg | 62.9 us | 20.5 s | 14.3 s | +---------------+---------+-----------+----------+ 

This can be a problem for really large arrays or if your program performs this operation a lot.
I timed this approach and seberg solutions and its modification proposed by Jaime.
This is how I implemented the various functions:

 import numpy as np def create_ab(n, m): a = np.random.randint(0, 2, (n, m)).astype(bool) b = np.random.randint(0, 2, (m, n)).astype(bool) return a, b def m2mult_tz(a, b): return np.mod(np.dot(a.astype('u1'), b), 2).astype(bool) def m2mult_seberg(a, b): return np.logical_xor.reduce( np.logical_and(a[:,None,:], bT[None,:,:]), axis=-1) def m2mult_jaime(a, b): return np.logical_xor.reduce( np.logical_and(a[:, :, None], b), axis=1) 

Here is a record of the 1000x1000 timings (I also checked that the results are the same in all cases):

 In [19]: a, b = create_ab(1000, 1000) In [20]: timeit m2mult_tz(a, b) 1 loops, best of 3: 7.27 s per loop In [21]: timeit m2mult_jaime(a, b) 1 loops, best of 3: 20.4 s per loop In [22]: timeit m2mult_seberg(a, b) 1 loops, best of 3: 20.5 s per loop In [23]: r_tz = m2mult_tz(a, b) In [24]: r_jaime = m2mult_jaime(a, b) In [25]: r_seberg = m2mult_seberg(a, b) In [26]: np.all(r_tz == r_jaime) Out[26]: True In [27]: np.all(r_tz == r_seberg) Out[27]: True 
+2
source

All Articles