sに対して一般的な行列乗算を実行しint
、続いて modulo-2 リダクションを行ってから、 に戻すことができbool
ます。
np.mod(np.dot(a.astype('u1'), b), 2).astype('bool')
これは、seberg のソリューションと Jaime の修正よりも高速です。
+---------------+---------+-----------+----------+
| | 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 |
+---------------+---------+-----------+----------+
これは、非常に大きな配列の場合、またはプログラムがこの操作を頻繁に行う場合に問題になる可能性があります。
私はこのアプローチとセバーグの解決策とハイメによって提案されたそれへの修正を計りました。
さまざまな機能を実装する方法は次のとおりです。
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,:], b.T[None,:,:]),
axis=-1)
def m2mult_jaime(a, b):
return np.logical_xor.reduce(
np.logical_and(a[:, :, None], b),
axis=1)
1000x1000 のタイミングの記録を次に示します (すべてのケースで結果が同じであることも確認しました)。
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